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