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