1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_ArchiveFont.cpp
4 
5   Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Revision: 24154 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "precompiled.h"
17 
18 #include <nw/font/font_ArchiveFont.h>
19 #include <nw/ut/ut_Inlines.h>
20 #include <nw/assert.h>
21 #include <nw/math/math_Arithmetic.h>
22 
23 #include <cstring>
24 
25 namespace nw {
26 namespace font {
27 
28 
29 
30 
31 /* ------------------------------------------------------------------------
32         コンストラクタ/デストラクタ
33    ------------------------------------------------------------------------ */
34 
ArchiveFont()35 ArchiveFont::ArchiveFont()
36 {
37 }
38 
~ArchiveFont()39 ArchiveFont::~ArchiveFont()
40 {
41     Destroy();
42 }
43 
44 
45 
46 /* ------------------------------------------------------------------------
47         構築/破棄
48    ------------------------------------------------------------------------ */
49 
50 u32
GetRequireBufferSize(const void * bfnt,const char * glyphGroups)51 ArchiveFont::GetRequireBufferSize(
52     const void* bfnt,
53     const char* glyphGroups
54 )
55 {
56     NN_POINTER_ASSERT(bfnt);
57     NN_POINTER_ASSERT(glyphGroups);
58 
59     // 妥当性のチェック
60     if (! IsValidResource(bfnt, HEADER_SIZE))
61     {
62         return 0;
63     }
64 
65     FontGlyphGroupsAcs gg(bfnt);
66     u32 numRequireSheets    = 0;
67     u32 sizeSumCWDH         = 0;
68     u32 sizeSumCMAP         = 0;
69 
70     // ロードするシートの枚数を計算
71     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumSheet(); ++flagSetNo)
72     {
73         u32 useSheets = 0x0;
74 
75         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
76         {
77             const char* setName = gg.GetSetName(setNo);
78 
79             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
80             {
81                 useSheets |= gg.GetUseSheetFlags(setNo, flagSetNo);
82             }
83         }
84 
85         numRequireSheets += math::CntBit1(useSheets);
86     }
87 
88     // CWDH ブロック用に必要なバッファサイズを計算
89     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCWDH(); ++flagSetNo)
90     {
91         u32 useCWDH   = 0x0;
92 
93         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
94         {
95             const char* setName = gg.GetSetName(setNo);
96 
97             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
98             {
99                 useCWDH   |= gg.GetUseCWDHFlags(setNo, flagSetNo);
100             }
101         }
102 
103         for (int b = 0; b < 32; ++b)
104         {
105             if (((useCWDH << b) & (1u << 31)) != 0)
106             {
107                 sizeSumCWDH += gg.GetSizeCWDH(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
108             }
109         }
110     }
111 
112     // CMAP ブロック用に必要なバッファサイズを計算
113     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCMAP(); ++flagSetNo)
114     {
115         u32 useCMAP   = 0x0;
116 
117         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
118         {
119             const char* setName = gg.GetSetName(setNo);
120 
121             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
122             {
123                 useCMAP   |= gg.GetUseCMAPFlags(setNo, flagSetNo);
124             }
125         }
126 
127         for (int b = 0; b < 32; ++b)
128         {
129             if (((useCMAP << b) & (1u << 31)) != 0)
130             {
131                 sizeSumCMAP += gg.GetSizeCMAP(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
132             }
133         }
134     }
135 
136     //---- 必要バッファサイズの計算
137     const u32 sizeTable    = math::RoundUp(sizeof(u16) * gg.GetNumSheet(),       4);
138     const u32 sizeFINF     = math::RoundUp(sizeof(FontInformation),              4);
139     const u32 sizeTGLP     = math::RoundUp(sizeof(FontTextureGlyph),             4);
140     const u32 sizeSumSheet = math::RoundUp(gg.GetSheetSize() * numRequireSheets, 4);
141 
142     // シート領域以降はシート展開時に圧縮データのストリーム展開用コンテキストとして使用するので
143     // ある程度以上のサイズを確保する。
144     // 通常はシート領域以降がこのサイズを下回ることは無いのでサイズ的な追加コストは発生しない。
145     const u32 sizeForContext = static_cast<u32>(sizeof(nn::cx::UncompContextHuffman));
146     const u32 sizeAfterSheet = math::Max(static_cast<u32>(sizeSumCWDH + sizeSumCMAP), sizeForContext);
147 
148     // math::RoundUp の中に入るのはバッファ上でシートより前に配置されるもの
149     u32 totalSize =
150           math::RoundUp(sizeTable + sizeFINF + sizeTGLP, GlyphDataAlignment)
151         + sizeSumSheet
152         + sizeAfterSheet;
153 
154     totalSize = math::RoundUp(totalSize, 4);
155     totalSize += sizeof(internal::TextureObject) * numRequireSheets;
156 
157     return totalSize;
158 }
159 
160 void
InitStreamingConstruct(ArchiveFont::ConstructContext * pContext,void * pBuffer,u32 bufferSize,const char * glyphGroups)161 ArchiveFont::InitStreamingConstruct(
162     ArchiveFont::ConstructContext*  pContext,
163     void*                           pBuffer,
164     u32                             bufferSize,
165     const char*                     glyphGroups
166 )
167 {
168     NN_POINTER_ASSERT(pContext);
169     NN_POINTER_ASSERT(pBuffer);
170     NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment);
171     NW_FONT_BUFFERSIZE_ASSERT(bufferSize);
172     NN_POINTER_ASSERT(glyphGroups);
173 
174     pContext->Init( pBuffer, bufferSize, glyphGroups );
175     pContext->op = ConstructContext::ANALYZE_FILE_HEADER;
176 }
177 
178 ArchiveFont::ConstructResult
StreamingConstruct(ArchiveFont::ConstructContext * pContext,const void * stream,u32 streamSize)179 ArchiveFont::StreamingConstruct(
180     ArchiveFont::ConstructContext*  pContext,
181     const void*                     stream,
182     u32                             streamSize
183 )
184 {
185     NN_POINTER_ASSERT(pContext);
186     NN_POINTER_ASSERT(stream);
187     NW_FONT_BUFFERSIZE_ASSERT(streamSize);
188 
189     //---- 既に構築済みなら失敗とする
190     if (GetFINF() != NULL)
191     {
192         // ただし CONSTRUCT_FINISH を返した後であるなら
193         // エラーではなく CONSTRUCT_FINISH とする。
194         return pContext->HasMoreBlock() ? CONSTRUCT_ERROR: CONSTRUCT_FINISH;
195     }
196 
197     ArchiveFont::ConstructResult ret = CONSTRUCT_CONTINUE;
198     CachedStreamReader& s = pContext->GetStreamReader();
199     s.Attach(stream, streamSize);
200 
201     while (ret == CONSTRUCT_CONTINUE)
202     {
203         switch (pContext->op)
204         {
205         case ConstructContext::DISPATCH:              ret = ConstructOpDispatch(pContext, &s);  break;
206         case ConstructContext::ANALYZE_FILE_HEADER:   ret = ConstructOpAnalyzeFileHeader(pContext, &s);  break;
207         case ConstructContext::ANALYZE_GLGR:          ret = ConstructOpAnalyzeGLGR(pContext, &s);  break;
208         case ConstructContext::ANALYZE_FINF:          ret = ConstructOpAnalyzeFINF(pContext, &s);  break;
209         case ConstructContext::ANALYZE_CMAP:          ret = ConstructOpAnalyzeCMAP(pContext, &s);  break;
210         case ConstructContext::ANALYZE_CWDH:          ret = ConstructOpAnalyzeCWDH(pContext, &s);  break;
211         case ConstructContext::ANALYZE_TGLP:          ret = ConstructOpAnalyzeTGLP(pContext, &s);  break;
212         case ConstructContext::PREPAIR_COPY_SHEET:    ret = ConstructOpPrepairCopySheet(pContext, &s);  break;
213         case ConstructContext::PREPAIR_EXPAND_SHEET:  ret = ConstructOpPrepairExpandSheet(pContext, &s);  break;
214         case ConstructContext::COPY:                  ret = ConstructOpCopy(pContext, &s);  break;
215         case ConstructContext::SKIP:                  ret = ConstructOpSkip(pContext, &s);  break;
216         case ConstructContext::EXPAND:                ret = ConstructOpExpand(pContext, &s);  break;
217         case ConstructContext::FATAL_ERROR:           ret = ConstructOpFatalError(pContext, &s); break;
218         default:
219             NN_ASSERTMSG(false, "invalid operation(%d)", pContext->op);
220             pContext->op = ArchiveFont::ConstructContext::FATAL_ERROR;
221             ret = CONSTRUCT_ERROR;
222             break;
223         }
224     }
225 
226     //---- フォントリソースに対する処理終了時
227     if (ret == CONSTRUCT_FINISH && GetFINF() == NULL)
228     {
229         pContext->Align(sizeof(GLuint));
230         u32 texNamesSize = pContext->pFINF->pGlyph->sheetNum * sizeof(internal::TextureObject);
231         if (pContext->GetRemain() < texNamesSize)
232         {
233             // 出力先バッファのサイズが足らなかった
234             NN_LOG("buffer size too small");
235             return CONSTRUCT_ERROR;
236         }
237         SetTextureObjectsBufferPtr(pContext->GetCurrentPtr<internal::TextureObject*>());
238         pContext->Advance(texNamesSize);
239 
240         void* pUserBuffer;
241         FontInformation* pFontInfo;
242         u16* pAdjustArray;
243         pContext->Finish(&pUserBuffer, &pFontInfo, &pAdjustArray);
244         SetResourceBuffer(pUserBuffer, pFontInfo, pAdjustArray);
245 
246         if (AdjustIndex(GetFINF()->alterCharIndex) == GLYPH_INDEX_NOT_FOUND)
247         {
248             GetFINF()->alterCharIndex = 0;
249         }
250     }
251 
252     return ret;
253 }
254 
255 bool
Construct(void * pBuffer,u32 bufferSize,const void * bfnt,const char * glyphGroups)256 ArchiveFont::Construct(
257     void*       pBuffer,
258     u32         bufferSize,
259     const void* bfnt,
260     const char* glyphGroups
261 )
262 {
263     NN_POINTER_ASSERT(pBuffer);
264     NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment);
265     NW_FONT_BUFFERSIZE_ASSERT( bufferSize );
266     NN_POINTER_ASSERT(bfnt);
267     NN_POINTER_ASSERT(glyphGroups);
268 
269     const u32 fileSize = reinterpret_cast<const ut::BinaryFileHeader*>(bfnt)->fileSize;
270     NW_FONT_BUFFERSIZE_ASSERT(fileSize);
271 
272     ArchiveFont::ConstructContext context;
273     InitStreamingConstruct(&context, pBuffer, bufferSize, glyphGroups);
274     ArchiveFont::ConstructResult ret = StreamingConstruct(&context, bfnt, fileSize);
275 
276     return ret == CONSTRUCT_FINISH;
277 }
278 
279 void*
Destroy()280 ArchiveFont::Destroy()
281 {
282     if (IsManaging(NULL))
283     {
284         return 0;
285     }
286 
287     return RemoveResourceBuffer();
288 }
289 
290 
291 
292 /* ------------------------------------------------------------------------
293         文字単体情報アクセサ
294    ------------------------------------------------------------------------ */
295 
296 void
GetGlyph(Glyph * glyph,CharCode c) const297 ArchiveFont::GetGlyph(
298     Glyph*      glyph,
299     CharCode    c
300 ) const
301 {
302     GlyphIndex index = GetGlyphIndex(c);
303     GetGlyphFromIndex(glyph, index);
304 }
305 
306 
307 
308 /* ------------------------------------------------------------------------
309         グリフインデックス
310    ------------------------------------------------------------------------ */
311 
312 void
GetGlyphFromIndex(Glyph * glyph,GlyphIndex index) const313 ArchiveFont::GetGlyphFromIndex(
314     Glyph*      glyph,
315     GlyphIndex  index
316 ) const
317 {
318     NN_POINTER_ASSERT(GetFINF());
319     const FontTextureGlyph& tg = *GetFINF()->pGlyph;
320     u16 adjustedIndex = AdjustIndex(index);
321 
322     if (adjustedIndex == GLYPH_INDEX_NOT_FOUND)
323     {
324         index = GetFINF()->alterCharIndex;
325         adjustedIndex = AdjustIndex(index);
326     }
327     NN_ASSERT(adjustedIndex != GLYPH_INDEX_NOT_FOUND);
328 
329     const u32 cellsInASheet = internal::GetCellsInASheet(tg);
330     const u32 sheetNo       = adjustedIndex / cellsInASheet;
331     const u32 offsetBytes   = sheetNo * tg.sheetSize;
332     const void* pSheet      = tg.sheetImage + offsetBytes;
333 
334     glyph->pTexture         = pSheet;
335     glyph->widths           = GetCharWidthsFromIndex(index);
336     glyph->pTextureObject   = GetTextureObject(sheetNo);
337     SetGlyphMember(glyph, adjustedIndex, tg);
338 }
339 
340 }   // namespace font
341 }   // namespace nw
342