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