1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_PackedFont.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 <GLES2/gl2.h>
21 #include <GLES2/gl2ext.h>
22 #include <nn/gx.h>
23 #include <nw/font/font_PackedFont.h>
24 #include <nw/ut/ut_Inlines.h>
25 #include <nw/assert.h>
26 #include <nw/math/math_Arithmetic.h>
27 
28 #include <cstring>
29 #include <algorithm>
30 
31 namespace nw {
32 namespace font {
33 
34 namespace
35 {
36 
37 #ifdef NW_PLATFORM_CTR
38 /*!--------------------------------------------------------------------------*
39     @brief      蓄積された3Dコマンドを順次実行開始し、
40                 それらが終了するまで待機します。
41 
42                 予約されたコマンドリストオブジェクト0がバインドされている場合は
43                 何も行われません。
44  *---------------------------------------------------------------------------*/
45 void
RunCmdlistDone()46 RunCmdlistDone()
47 {
48     // 3Dコマンドを区切り、実行を開始します。
49     nngxSplitDrawCmdlist();
50     nngxRunCmdlist();
51     nngxWaitCmdlistDone();
52 }
53 #endif
54 
55 // PODでどのようになるか未定
56 void
GXDrawDone()57 GXDrawDone()
58 {
59 #ifdef NW_PLATFORM_CTR
60     RunCmdlistDone();
61 #endif
62 }
63 
64 }   // namespace
65 
66 /* =======================================================================
67         PackedFont public
68    ======================================================================== */
69 
70 /* ------------------------------------------------------------------------
71         コンストラクタ/デストラクタ
72    ------------------------------------------------------------------------ */
73 
PackedFont()74 PackedFont::PackedFont()
75 : m_NumCompSheet(0),
76   m_NumSheetCache(0),
77   m_pCacheIndexArray(NULL),
78   m_pCacheUserArray(NULL),
79   m_pCompSheetArray(NULL),
80   m_pSheetCache(NULL)
81 {
82 }
83 
~PackedFont()84 PackedFont::~PackedFont()
85 {
86     Destroy();
87 }
88 
89 
90 
91 /* ------------------------------------------------------------------------
92         バッファサイズ計算
93    ------------------------------------------------------------------------ */
94 
95 u32
GetRequireBufferSize(const void * bfnt,const char * glyphGroups,int numSheetCache)96 PackedFont::GetRequireBufferSize(
97     const void*   bfnt,
98     const char*   glyphGroups,
99     int           numSheetCache
100 )
101 {
102     NN_POINTER_ASSERT(bfnt);
103     NN_POINTER_ASSERT(glyphGroups);
104 
105     //---- 妥当性のチェック
106     if (! IsValidResource(bfnt, 16*1024))
107     {
108         return 0;
109     }
110 
111     FontGlyphGroupsAcs gg(bfnt);
112 
113     u32 copySize  = CalcCopySize (gg, glyphGroups, NULL);
114     u32 cacheSize = CalcCacheSize(gg, numSheetCache);
115 
116     return copySize + cacheSize;
117 }
118 
119 u32
GetRequireBufferSize(const void * bfnt,const char * glyphGroups,f32 rateSheetCache)120 PackedFont::GetRequireBufferSize(
121     const void*   bfnt,
122     const char*   glyphGroups,
123     f32           rateSheetCache
124 )
125 {
126     NN_POINTER_ASSERT(bfnt);
127     NN_POINTER_ASSERT(glyphGroups);
128     NW_FONT_FLOAT_ASSERT(rateSheetCache);
129 
130     //---- 妥当性のチェック
131     if (! IsValidResource(bfnt, 16*1024))
132     {
133         return 0;
134     }
135 
136     FontGlyphGroupsAcs gg(bfnt);
137 
138     int numLoadSheet;
139 
140     u32 copySize        = CalcCopySize (gg, glyphGroups, &numLoadSheet);
141     int numSheetCache   = static_cast<int>(numLoadSheet * rateSheetCache);
142      u32 cacheSize      = CalcCacheSize(gg, numSheetCache);
143 
144     return copySize + cacheSize;
145 }
146 
147 
148 
149 /* ------------------------------------------------------------------------
150         構築/破棄
151    ------------------------------------------------------------------------ */
152 
153 void
InitStreamingConstruct(PackedFont::ConstructContext * pContext,void * outBuffer,u32 outBufferSize,const char * glyphGroups)154 PackedFont::InitStreamingConstruct(
155     PackedFont::ConstructContext*   pContext,
156     void*                           outBuffer,
157     u32                             outBufferSize,
158     const char*                     glyphGroups
159 )
160 {
161     NN_POINTER_ASSERT(pContext);
162     NN_POINTER_ASSERT(outBuffer);
163     NN_ALIGN_ASSERT(outBuffer, GlyphDataAlignment);
164     NW_FONT_BUFFERSIZE_ASSERT(outBufferSize);
165     NN_POINTER_ASSERT(glyphGroups);
166 
167     pContext->Init( outBuffer, outBufferSize, glyphGroups );
168     pContext->op = ConstructContext::ANALYZE_FILE_HEADER;
169 }
170 
171 PackedFont::ConstructResult
StreamingConstruct(PackedFont::ConstructContext * pContext,const void * stream,u32 streamSize)172 PackedFont::StreamingConstruct(
173     PackedFont::ConstructContext*   pContext,
174     const void*                     stream,
175     u32                             streamSize
176 )
177 {
178     NN_POINTER_ASSERT(pContext);
179     NN_POINTER_ASSERT(stream);
180     NW_FONT_BUFFERSIZE_ASSERT(streamSize);
181 
182     //---- 既に構築済みなら失敗とする
183     if (GetFINF() != NULL)
184     {
185         // ただし CONSTRUCT_FINISH を返した後であるなら
186         // エラーではなく CONSTRUCT_FINISH とする。
187         return pContext->HasMoreBlock() ? CONSTRUCT_ERROR: CONSTRUCT_FINISH;
188     }
189 
190     PackedFont::ConstructResult ret = CONSTRUCT_CONTINUE;
191     CachedStreamReader& s = pContext->GetStreamReader();
192     s.Attach(stream, streamSize);
193 
194     while (ret == CONSTRUCT_CONTINUE)
195     {
196         switch (pContext->op)
197         {
198         case ConstructContext::DISPATCH:            ret = ConstructOpDispatch(pContext, &s);  break;
199         case ConstructContext::ANALYZE_FILE_HEADER: ret = ConstructOpAnalyzeFileHeader(pContext, &s);  break;
200         case ConstructContext::ANALYZE_GLGR:        ret = ConstructOpAnalyzeGLGRPacked(pContext, &s);  break;
201         case ConstructContext::ANALYZE_FINF:        ret = ConstructOpAnalyzeFINF(pContext, &s);  break;
202         case ConstructContext::ANALYZE_CMAP:        ret = ConstructOpAnalyzeCMAP(pContext, &s);  break;
203         case ConstructContext::ANALYZE_CWDH:        ret = ConstructOpAnalyzeCWDH(pContext, &s);  break;
204         case ConstructContext::COPY:                ret = ConstructOpCopy(pContext, &s);  break;
205         case ConstructContext::SKIP:                ret = ConstructOpSkip(pContext, &s);  break;
206         case ConstructContext::FATAL_ERROR:         ret = ConstructOpFatalError(pContext, &s); break;
207         case ConstructContext::ANALYZE_TGLP:        ret = ConstructOpAnalyzeTGLP(pContext, &s);  break;
208         case ConstructContext::PREPAIR_EXPAND_SHEET:
209             {
210                 ret = ConstructOpPrepairCopyPackedSheet(pContext, &s);
211                 if (pContext->op == PackedFont::ConstructContext::COPY)
212                 {
213                     // 圧縮シートデータ先頭へのポインタを収集する
214                     m_pCompSheetArray[m_NumCompSheet] = pContext->GetCurrentPtr<u8*>();
215                     m_NumCompSheet++;
216                 }
217             }
218             break;
219 
220         case ConstructContext::PREPAIR_COPY_SHEET:
221             NN_LOG("PackedFont: specified font is not compressed.");
222             pContext->op = ConstructContext::FATAL_ERROR;
223             return CONSTRUCT_ERROR;
224 
225         default:
226             NN_ASSERTMSG(false, "NW FONT Internal error\n" "invalid operation(%d)", pContext->op);
227             pContext->op = ConstructContext::FATAL_ERROR;
228             return CONSTRUCT_ERROR;
229         }
230     }
231 
232     //---- フォントリソースに対する処理終了時
233     if (ret == CONSTRUCT_FINISH && GetFINF() == NULL)
234     {
235         void* pUserBuffer;
236         FontInformation* pFontInfo;
237         u16* pAdjustArray;
238 
239         pContext->Finish(&pUserBuffer, &pFontInfo, &pAdjustArray);
240         SetResourceBuffer(pUserBuffer, pFontInfo, pAdjustArray);
241 
242         if (AdjustIndex(GetFINF()->alterCharIndex) == GLYPH_INDEX_NOT_FOUND)
243         {
244             GetFINF()->alterCharIndex = 0;
245         }
246 
247         // 全てのシートを未ロードとする
248         for (int i = 0; i < m_NumCompSheet; ++i)
249         {
250             m_pCacheIndexArray[i] = SHEET_INDEX_NOT_LOADED;
251         }
252 
253         // 全てのシートを未ロードとする
254         for (int i = 0; i < m_NumSheetCache; ++i)
255         {
256             m_pCacheUserArray[i] = SHEET_INDEX_NOT_LOADED;
257         }
258 
259     }
260 
261     return ret;
262 }
263 
264 bool
Construct(void * pBuffer,u32 bufferSize,const void * bfnt,const char * glyphGroups)265 PackedFont::Construct(
266     void*       pBuffer,
267     u32         bufferSize,
268     const void* bfnt,
269     const char* glyphGroups
270 )
271 {
272     NN_POINTER_ASSERT(pBuffer);
273     NN_ALIGN_ASSERT(pBuffer, GlyphDataAlignment);
274     NW_FONT_BUFFERSIZE_ASSERT(bufferSize);
275     NN_POINTER_ASSERT(bfnt);
276     NN_POINTER_ASSERT(glyphGroups);
277 
278     PackedFont::ConstructResult ret;
279     PackedFont::ConstructContext context;
280     const u32 fileSize = reinterpret_cast<const ut::BinaryFileHeader*>(bfnt)->fileSize;
281     NW_FONT_BUFFERSIZE_ASSERT(fileSize);
282 
283     InitStreamingConstruct(&context, pBuffer, bufferSize, glyphGroups);
284     ret = StreamingConstruct(&context, bfnt, fileSize);
285 
286     return ret == CONSTRUCT_FINISH;
287 }
288 
289 void*
Destroy()290 PackedFont::Destroy()
291 {
292     if (IsManaging(NULL))
293     {
294         return 0;
295     }
296 
297     // テクスチャ名を削除する際に m_NumSheetCache を
298     // 参照するため、m_NumSheetCacheを初期化する前に呼び出す。
299     void *const buffer = RemoveResourceBuffer();
300 
301     m_NumSheetCache      = 0;
302     m_pCacheIndexArray   = NULL;
303     m_pCacheUserArray    = NULL;
304     m_pCompSheetArray    = NULL;
305     m_pSheetCache        = NULL;
306 
307     return buffer;
308 }
309 
310 
311 
312 /* ------------------------------------------------------------------------
313         Fontクラスオーバーライド
314    ------------------------------------------------------------------------ */
315 
316 void
GetGlyph(Glyph * pGlyph,CharCode c) const317 PackedFont::GetGlyph(
318     Glyph*      pGlyph,
319     CharCode    c
320 ) const
321 {
322     NN_POINTER_ASSERT(pGlyph);
323     NN_POINTER_ASSERT(GetFINF());
324     GlyphIndex index = GetGlyphIndex(c);
325     u16 adjustedIndex = AdjustIndex(index);
326 
327     if (adjustedIndex == GLYPH_INDEX_NOT_FOUND)
328     {
329         index = GetFINF()->alterCharIndex;
330         adjustedIndex = AdjustIndex(index);
331     }
332     NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND );
333 
334     int compIndex  = CalcSheetIndex(adjustedIndex);
335     int cacheIndex = GetCacheIndex(compIndex);
336 
337     if (cacheIndex == SHEET_INDEX_NOT_LOADED)
338     {
339         cacheIndex = LoadSheet(compIndex);
340         pGlyph->isSheetUpdated = true;
341     }
342     m_LRUMan.Use(cacheIndex);
343 
344     MakeGlyph(pGlyph, index, cacheIndex);
345 }
346 
347 
348 int
GetActiveSheetNum() const349 PackedFont::GetActiveSheetNum() const
350 {
351     return m_NumSheetCache;
352 }
353 
354 
355 
356 /* ------------------------------------------------------------------------
357         シート管理
358    ------------------------------------------------------------------------ */
359 
360 bool
PreloadSheet(CharCode c)361 PackedFont::PreloadSheet(CharCode c)
362 {
363     NN_POINTER_ASSERT(GetFINF());
364     bool bCacheNow = false;
365 
366     int compIndex  = GetSheetIndex(c);
367     int cacheIndex = GetCacheIndex(compIndex);
368 
369     if (cacheIndex == SHEET_INDEX_NOT_LOADED)
370     {
371         cacheIndex = LoadSheet(compIndex);
372         bCacheNow = true;
373     }
374     NN_ASSERT( cacheIndex != SHEET_INDEX_NOT_LOADED );
375     m_LRUMan.Use(cacheIndex);
376 
377     return bCacheNow;
378 }
379 
380 bool
LockSheet(CharCode c)381 PackedFont::LockSheet(CharCode c)
382 {
383     NN_POINTER_ASSERT(GetFINF());
384     int compIndex  = GetSheetIndex(c);
385     int cacheIndex = GetCacheIndex(compIndex);
386 
387     //---- キャッシュされていないならキャッシュする
388     if (cacheIndex == SHEET_INDEX_NOT_LOADED)
389     {
390         if (m_LRUMan.GetNumLocked() >= m_NumSheetCache - 1)
391         {
392             return false;
393         }
394 
395         cacheIndex = LoadSheet(compIndex);
396     }
397 
398     //---- ロック
399     m_LRUMan.Lock(cacheIndex);
400     return true;
401 }
402 
403 bool
UnlockSheet(CharCode c,bool bUnload)404 PackedFont::UnlockSheet(
405     CharCode    c,
406     bool        bUnload
407 )
408 {
409     int compIndex  = GetSheetIndex(c);
410     int cacheIndex = GetCacheIndex(compIndex);
411 
412     //---- キャッシュ上に存在しなければならない
413     if (cacheIndex == SHEET_INDEX_NOT_LOADED)
414     {
415         return false;
416     }
417 
418     //---- ロック解除
419     m_LRUMan.Unlock(cacheIndex);
420 
421     if (bUnload)
422     {
423         //---- キャッシュ破棄
424         UnloadSheet(compIndex);
425         m_LRUMan.Unuse(cacheIndex);
426     }
427 
428     return true;
429 }
430 
431 void
UnlockSheetAll()432 PackedFont::UnlockSheetAll()
433 {
434     for (int i = 0; i < m_NumSheetCache; ++i)
435     {
436         m_LRUMan.Unlock(i);
437     }
438 }
439 
440 
441 
442 /* =======================================================================
443         PackedFont private
444    ======================================================================== */
445 
446 /* ------------------------------------------------------------------------
447         バッファサイズ計算
448    ------------------------------------------------------------------------ */
449 
450 u32
CalcCopySize(const FontGlyphGroupsAcs & gg,const char * glyphGroups,int * pNumLoadSheet)451 PackedFont::CalcCopySize(
452     const FontGlyphGroupsAcs&   gg,
453     const char*                 glyphGroups,
454     int*                        pNumLoadSheet
455 )
456 {
457     NN_POINTER_ASSERT(glyphGroups);
458 
459     u32 sizeSumSheet    = 0;
460     u32 sizeSumCWDH     = 0;
461     u32 sizeSumCMAP     = 0;
462     int numLoadSheet    = 0;
463 
464     // ロードするシートのサイズを計算
465     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumSheet(); ++flagSetNo)
466     {
467         u32 useSheets = 0x0;
468 
469         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
470         {
471             const char* setName = gg.GetSetName(setNo);
472 
473             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
474             {
475                 useSheets |= gg.GetUseSheetFlags(setNo, flagSetNo);
476             }
477         }
478 
479         for (int b = 0; b < 32; ++b)
480         {
481             if (((useSheets << b) & (1u << 31)) != 0)
482             {
483                 sizeSumSheet += gg.GetSizeCompSheet(flagSetNo * 32 + b);
484                 numLoadSheet++;
485             }
486         }
487     }
488 
489     // CWDH ブロック用に必要なバッファサイズを計算
490     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCWDH(); ++flagSetNo)
491     {
492         u32 useCWDH   = 0x0;
493 
494         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
495         {
496             const char* setName = gg.GetSetName(setNo);
497 
498             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
499             {
500                 useCWDH   |= gg.GetUseCWDHFlags(setNo, flagSetNo);
501             }
502         }
503 
504         for (int b = 0; b < 32; ++b)
505         {
506             if (((useCWDH << b) & (1u << 31)) != 0)
507             {
508                 sizeSumCWDH += gg.GetSizeCWDH(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
509             }
510         }
511     }
512 
513     // CMAP ブロック用に必要なバッファサイズを計算
514     for (int flagSetNo = 0; flagSetNo * 32 < gg.GetNumCMAP(); ++flagSetNo)
515     {
516         u32 useCMAP   = 0x0;
517 
518         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
519         {
520             const char* setName = gg.GetSetName(setNo);
521 
522             if (IsNullString(glyphGroups) || IncludeName(glyphGroups, setName))
523             {
524                 useCMAP   |= gg.GetUseCMAPFlags(setNo, flagSetNo);
525             }
526         }
527 
528         for (int b = 0; b < 32; ++b)
529         {
530             if ( ((useCMAP << b) & (1u << 31)) != 0)
531             {
532                 sizeSumCMAP += gg.GetSizeCMAP(flagSetNo * 32 + b) - sizeof(ut::BinaryBlockHeader);
533             }
534         }
535     }
536 
537 
538     if (pNumLoadSheet != NULL)
539     {
540         *pNumLoadSheet = numLoadSheet;
541     }
542 
543     //---- 必要バッファサイズの計算
544     const u32 sizeFINF  = math::RoundUp(sizeof(FontInformation),  4);
545     const u32 sizeTGLP  = math::RoundUp(sizeof(FontTextureGlyph), 4);
546 
547     // GLGR ブロックの処理に必要なテンポラリバッファのサイズ
548     // バッファサイズはこの値以上になるようにする
549     // 通常、このサイズより小さくなる事は無い
550     const u32 glgrSize  = (sizeof(ut::BinaryFileHeader) + gg.GetGLGRSize()) * 2;
551 
552     // 圧縮されたシートにアライメントは不要だが処理の都合上アライメントを入れる
553     const u32 loadResSize = math::RoundUp(sizeFINF + sizeTGLP, GlyphDataAlignment)
554         + sizeSumSheet + sizeSumCWDH + sizeSumCMAP;
555 
556     return math::Max(loadResSize, glgrSize);
557 }
558 
559 u32
CalcCacheSize(const FontGlyphGroupsAcs & gg,int numSheetCache)560 PackedFont::CalcCacheSize(
561     const FontGlyphGroupsAcs&   gg,
562     int                         numSheetCache
563 )
564 {
565     const u32 numResSheet = gg.GetNumSheet();
566     numSheetCache = math::Clamp(numSheetCache, 1, static_cast<int>(numResSheet));
567 
568     u32 sizeLRUBuffer               = LRUManager::GetRequireBufferSize(numSheetCache);
569     u32 sizeCompSheetArray          = sizeof(u8*) * numResSheet;
570     u32 sizeResSheetIndexArray      = sizeof(u16) * numSheetCache;
571     u32 sizeSheetCached             = gg.GetSheetSize() * numSheetCache;
572     u32 sizeTextureNamesArray       = sizeof(internal::TextureObject) * numSheetCache;
573 
574     u32 offsetLRUBuffer             = 0;
575     u32 offsetCompSheetArray        = math::RoundUp(offsetLRUBuffer           + sizeLRUBuffer,            4);
576     u32 offsetSheetIndexArray       = math::RoundUp(offsetCompSheetArray      + sizeCompSheetArray,       2);
577     u32 offsetResSheetIndexArray    = math::RoundUp(offsetSheetIndexArray     + sizeCompSheetArray,       2);
578     u32 offsetSheetCached           = math::RoundUp(offsetResSheetIndexArray  + sizeResSheetIndexArray,   GlyphDataAlignment);
579     u32 size                        = math::RoundUp(offsetSheetCached         + sizeSheetCached,          4);
580     size                            = math::RoundUp(size                      + sizeTextureNamesArray,    4);
581 
582     return size;
583 }
584 
585 
586 
587 /* ------------------------------------------------------------------------
588         構築/破棄
589    ------------------------------------------------------------------------ */
590 
591 u16*
AssignMemory(u8 * buffer,u32 bufferSize,u32 numResSheet,u32 numLoadSheet,u32 sheetSize)592 PackedFont::AssignMemory(
593     u8* buffer,
594     u32 bufferSize,
595     u32 numResSheet,
596     u32 numLoadSheet,
597     u32 sheetSize
598 )
599 {
600     NN_POINTER_ASSERT(buffer);
601     NW_FONT_BUFFERSIZE_ASSERT(bufferSize);
602     NN_ASSERT( numLoadSheet <= numResSheet );
603     u16* pGlyphIndexAdjustArray;
604 
605     // シートキャッシュ数計算
606     u32 sizeGlyphIndexAdjustArray   = math::RoundUp(sizeof(u16) * numResSheet,  2);
607     u32 sizeCacheIndexArray         = math::RoundUp(sizeof(u16) * numLoadSheet, 2);
608     u32 sizeCompSheetArray          = math::RoundUp(sizeof(u8*) * numLoadSheet, 4);
609 
610     u32 varibaleAreaSize        = bufferSize - sizeGlyphIndexAdjustArray
611                                              - sizeCacheIndexArray
612                                              - sizeCompSheetArray
613                                              - sizeof(LRUManager::OrderNode);
614     if (varibaleAreaSize > bufferSize)
615     {
616         // varibaleAreaSize が負になった
617         return NULL;
618     }
619 
620     int numSheetCache           = static_cast<int>(varibaleAreaSize
621                                     / (sheetSize + sizeof(LRUManager::OrderNode)
622                                        + sizeof(u16) + sizeof(internal::TextureObject)
623                                       )
624                                   );
625 
626     u32 sizeLRUBuffer           = LRUManager::GetRequireBufferSize(numSheetCache);
627     u32 sizeCacheUserArray      = sizeof(u16) * numSheetCache;
628     u32 sizeSheetCached         = sheetSize * numSheetCache;
629 
630     // バッファ割り当て計算
631     u32 offsetLRUBuffer             = 0;
632     u32 offsetGlyphIndexAdjustArray = math::RoundUp(offsetLRUBuffer               + sizeLRUBuffer,                2);
633     u32 offsetCacheIndexArray       = math::RoundUp(offsetGlyphIndexAdjustArray   + sizeGlyphIndexAdjustArray,    2);
634     u32 offsetCacheUserArray        = math::RoundUp(offsetCacheIndexArray         + sizeCacheIndexArray,          2);
635     u32 offsetCompSheetArray        = math::RoundUp(offsetCacheUserArray          + sizeCacheUserArray,           4);
636     u32 offsetSheetCache            = math::RoundUp(offsetCompSheetArray          + sizeCompSheetArray,           GlyphDataAlignment);
637     u32 offsetTextureObjectsArray   = math::RoundUp(offsetSheetCache              + sizeSheetCached,              4);
638 
639 
640     // バッファ割り当て
641     m_LRUMan.Init(buffer + offsetLRUBuffer, numSheetCache);
642     m_NumCompSheet          = 0;    // ConstructContext::PREPAIR_EXPAND_SHEET で設定される
643     m_NumSheetCache         = static_cast<u16>(numSheetCache);
644     pGlyphIndexAdjustArray  = reinterpret_cast<u16*>      (buffer + offsetGlyphIndexAdjustArray);
645     m_pCacheIndexArray      = reinterpret_cast<u16*>      (buffer + offsetCacheIndexArray);
646     m_pCacheUserArray       = reinterpret_cast<u16*>      (buffer + offsetCacheUserArray);
647     m_pCompSheetArray       = reinterpret_cast<const u8**>(buffer + offsetCompSheetArray);
648     m_pSheetCache           = reinterpret_cast<u8*>       (buffer + offsetSheetCache);
649     SetTextureObjectsBufferPtr(buffer + offsetTextureObjectsArray);
650 
651     return pGlyphIndexAdjustArray;
652 }
653 
654 
655 
656 /* ------------------------------------------------------------------------
657         グリフ取得/シート管理
658    ------------------------------------------------------------------------ */
659 
660 void
MakeGlyph(Glyph * glyph,GlyphIndex gindex,int cacheIndex) const661 PackedFont::MakeGlyph(
662     Glyph*      glyph,
663     GlyphIndex  gindex,
664     int         cacheIndex
665 ) const
666 {
667     const FontTextureGlyph& tg = *GetFINF()->pGlyph;
668 
669     glyph->pTexture         = GetLoadedSheet(cacheIndex);
670     glyph->widths           = GetCharWidthsFromIndex(gindex);
671     glyph->pTextureObject   = GetTextureObject(cacheIndex);
672     SetGlyphMember(glyph, gindex, tg);
673 }
674 
675 int
LoadSheet(int compIndex) const676 PackedFont::LoadSheet(int compIndex) const
677 {
678     int nextCacheIndex = m_LRUMan.GetLastIndex();
679     int oldCacheUser    = GetCacheUser(nextCacheIndex);
680 
681     u8* pSheetDst  = GetLoadedSheet(nextCacheIndex);
682     const u8* pCompSheet = GetCompSheet(compIndex);
683 
684     if (oldCacheUser != SHEET_INDEX_NOT_LOADED)
685     {
686         GXDrawDone();
687         UnloadSheet(oldCacheUser);
688     }
689     nn::cx::UncompressHuffman(pCompSheet, pSheetDst);
690     SetCacheUser(compIndex, nextCacheIndex);
691 
692     return nextCacheIndex;
693 }
694 
695 void
UnloadSheet(int compIndex) const696 PackedFont::UnloadSheet(int compIndex) const
697 {
698     int cacheIndex = GetCacheIndex(compIndex);
699     ResetCacheUser(compIndex, cacheIndex);
700 }
701 
702 int
GetSheetIndex(CharCode c) const703 PackedFont::GetSheetIndex(CharCode c) const
704 {
705     NN_POINTER_ASSERT(GetFINF());
706     GlyphIndex index = GetGlyphIndex(c);
707     u16 adjustedIndex = AdjustIndex(index);
708 
709     if (adjustedIndex == GLYPH_INDEX_NOT_FOUND)
710     {
711         index = GetFINF()->alterCharIndex;
712         adjustedIndex = AdjustIndex(index);
713     }
714     NN_ASSERT( adjustedIndex != GLYPH_INDEX_NOT_FOUND );
715 
716     return  CalcSheetIndex(adjustedIndex);
717 }
718 
719 int
CalcSheetIndex(GlyphIndex index) const720 PackedFont::CalcSheetIndex(GlyphIndex index) const
721 {
722     const FontTextureGlyph& tg = *GetFINF()->pGlyph;
723     const int cellsInASheet = internal::GetCellsInASheet(tg);
724     return index / cellsInASheet;
725 }
726 
727 int
GetCacheIndex(int compIndex) const728 PackedFont::GetCacheIndex(int compIndex) const
729 {
730     NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
731     return m_pCacheIndexArray[compIndex];
732 }
733 
734 int
GetCacheUser(int cacheIndex) const735 PackedFont::GetCacheUser(int cacheIndex) const
736 {
737     NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
738     return m_pCacheUserArray[cacheIndex];
739 }
740 
741 void
SetCacheUser(int compIndex,int cacheIndex) const742 PackedFont::SetCacheUser(
743     int compIndex,
744     int cacheIndex
745 ) const
746 {
747     NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
748     NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
749     m_pCacheIndexArray[compIndex] = static_cast<u16>(cacheIndex);
750     m_pCacheUserArray[cacheIndex] = static_cast<u16>(compIndex);
751 }
752 
753 void
ResetCacheUser(int compIndex,int cacheIndex) const754 PackedFont::ResetCacheUser(
755     int compIndex,
756     int cacheIndex
757 ) const
758 {
759     NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
760     NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
761     NN_ASSERT( m_pCacheIndexArray[compIndex] == cacheIndex );
762     NN_ASSERT( m_pCacheUserArray[cacheIndex] == compIndex );
763     m_pCacheIndexArray[compIndex] = SHEET_INDEX_NOT_LOADED;
764     m_pCacheUserArray[cacheIndex] = SHEET_INDEX_NOT_LOADED;
765 }
766 
767 
768 u8*
GetLoadedSheet(int cacheIndex) const769 PackedFont::GetLoadedSheet(int cacheIndex) const
770 {
771     NW_FONT_MINMAX_ASSERT( cacheIndex, 0, m_NumSheetCache - 1 );
772     const u32 offsetBytes = cacheIndex * GetFINF()->pGlyph->sheetSize;
773     return m_pSheetCache + offsetBytes;
774 }
775 
776 const u8*
GetCompSheet(int compIndex) const777 PackedFont::GetCompSheet(int compIndex) const
778 {
779     NW_FONT_MINMAX_ASSERT( compIndex, 0, m_NumCompSheet - 1 );
780     return m_pCompSheetArray[compIndex];
781 }
782 
783 
784 
785 /* ------------------------------------------------------------------------
786         構築処理置き換え
787    ------------------------------------------------------------------------ */
788 
789 PackedFont::ConstructResult
ConstructOpAnalyzeGLGRPacked(PackedFont::ConstructContext * pContext,PackedFont::CachedStreamReader * pStream)790 PackedFont::ConstructOpAnalyzeGLGRPacked(
791     PackedFont::ConstructContext*   pContext,
792     PackedFont::CachedStreamReader* pStream
793 )
794 {
795     NN_POINTER_ASSERT(pContext);
796     NN_POINTER_ASSERT(pStream);
797     u8* pTempFileHead;
798     u8* pTempGLGRTail;
799 
800     // GLGR ブロックの確保
801     {
802         const ut::BinaryFileHeader& header = *pContext->GetCurrentPtr<const ut::BinaryFileHeader*>();
803         const u32 requireSize = pContext->header.size - sizeof(ut::BinaryBlockHeader);
804         const u32 infoSize = sizeof(ut::BinaryFileHeader) + pContext->header.size;
805 
806         if (header.signature != BINFILE_SIG_FONTA)
807         {
808             // バイナリファイルヘッダがロードされていない or これはフォントリソースではない
809             NN_LOG("invalid font binary file.");
810             return CONSTRUCT_ERROR;
811         }
812         if (pStream->GetRemain() < requireSize)
813         {
814             return RequestData(pContext, pStream, requireSize);
815         }
816         if (pContext->GetRemain() < infoSize)
817         {
818             // 出力先バッファのサイズが足らなかった
819             NN_LOG("buffer size too small");
820             return CONSTRUCT_ERROR;
821         }
822 
823         // GLGR ブロックを一時的にコピー
824         // CopyTo(pContext, ...) だとバッファ位置が進んでしまうので CopyTo(void*, ...) を使う
825         pTempFileHead      = pContext->GetCurrentPtr<u8*>();
826         u8* blockHeaderPos = pTempFileHead + sizeof(ut::BinaryFileHeader);
827         u8* blockBodyPos   = blockHeaderPos + sizeof(ut::BinaryBlockHeader);
828         pTempGLGRTail      = blockHeaderPos + pContext->header.size;
829         std::memcpy(blockHeaderPos, &pContext->header, sizeof(ut::BinaryBlockHeader));
830         pStream->CopyTo(blockBodyPos, requireSize);
831 
832         //---- 妥当性のチェック
833         if (! IsValidResource(pTempFileHead, infoSize))
834         {
835             return CONSTRUCT_ERROR;
836         }
837     }
838 
839     const u32 bufferSize = pContext->GetRemain();
840     u16 numResSheet;
841     u32 numLoadSheet;
842     u16 numGlyphsPerSheet;
843     u32 numBlock;
844     u32 sheetSize;
845     u16* pTempAdjustArray;
846     u32 sizeAdjustTable;
847     u32 sizeResLoadBuffer;
848 
849     //---- グリフインデックス調整テーブルの構築
850     {
851         FontGlyphGroupsAcs gg(pTempFileHead);
852 
853         numResSheet       = gg.GetNumSheet();
854         numLoadSheet      = 0;
855         numGlyphsPerSheet = gg.GetNumGlyphsPerSheet();
856         numBlock          = gg.GetNumBlock();
857         sheetSize         = gg.GetSheetSize();
858 
859         sizeAdjustTable = math::RoundUp(numResSheet * sizeof(u16), 4);   // 4 バイトアライメント
860         pTempAdjustArray = reinterpret_cast<u16*>(math::RoundDown(
861             reinterpret_cast<uptr>(pTempFileHead + bufferSize - sizeAdjustTable), 2));
862         if (bufferSize < (pTempGLGRTail - pTempFileHead) + sizeAdjustTable)
863         {
864             // 出力先バッファのサイズが足らなかった
865             NN_LOG("buffer size too small");
866             return CONSTRUCT_ERROR;
867         }
868 
869         // 以下 AdjustTable を一時的にフラグ配列として使う。
870         // フラグを全て落とす。
871         for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
872         {
873             pTempAdjustArray[sheetNo] = 0;
874         }
875 
876         // 使用するシートに対応するフラグを立てていく。
877         for (int setNo = 0; setNo < gg.GetNumSet(); ++setNo)
878         {
879             const char* setName = gg.GetSetName(setNo);
880 
881             if (IsNullString(pContext->GetGlyphGroups()) || IncludeName(pContext->GetGlyphGroups(), setName))
882             {
883                 for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
884                 {
885                     if (gg.IsUseSheet(setNo, sheetNo))
886                     {
887                         pTempAdjustArray[sheetNo] = 1;
888                     }
889                 }
890             }
891         }
892 
893         // フラグを元に AdjustTable を構築する。
894         u16 adjust = 0;
895         for (int sheetNo = 0; sheetNo < numResSheet; ++sheetNo)
896         {
897             u16 &entry = pTempAdjustArray[sheetNo];
898 
899             if (entry == 1)
900             {
901                 entry = adjust;
902                 numLoadSheet++;
903             }
904             else
905             {
906                 entry = 0xFFFF;
907                 adjust += gg.GetNumGlyphsPerSheet();
908             }
909         }
910 
911         sizeResLoadBuffer = CalcCopySize(gg, pContext->GetGlyphGroups(), NULL);
912     }
913 
914     // 以下では一時的にコピーした GLGR ブロックを破壊するので以降アクセスする事はできない。
915 
916     // メモリの配分
917     {
918         const u32 sizeValiableBuffer   = math::RoundDown(bufferSize - sizeResLoadBuffer, 4);
919         const u32 offsetValiableBuffer = 0;
920         const u32 offsetResLoadBuffer  = offsetValiableBuffer + sizeValiableBuffer;
921         if (sizeResLoadBuffer >= bufferSize)
922         {
923             // 出力先バッファのサイズが足らなかった
924             NN_LOG("buffer size too small");
925             return CONSTRUCT_ERROR;
926         }
927 
928         u8* const pValiableBuffer      = pTempFileHead + offsetValiableBuffer;
929         u16* pTrueAdjustArray          = AssignMemory(pValiableBuffer, sizeValiableBuffer, numResSheet, numLoadSheet, sheetSize);
930         if (pTrueAdjustArray == NULL)
931         {
932             // 出力先バッファのサイズが足らなかった
933             NN_LOG("buffer size too small");
934             return CONSTRUCT_ERROR;
935         }
936 
937 
938         std::copy(pTempAdjustArray, pTempAdjustArray + numResSheet,
939                   NW_CHECKED_ARRAY_ITERATOR(pTrueAdjustArray, numResSheet));
940 
941         pContext->SetGLGR( pTrueAdjustArray,
942                            numResSheet,
943                            numGlyphsPerSheet,
944                            numBlock );
945 
946         pContext->Advance(offsetResLoadBuffer); // 既に確保した分
947         pContext->op = ConstructContext::DISPATCH;
948     }
949 
950     return CONSTRUCT_CONTINUE;
951 }
952 
953 PackedFont::ConstructResult
ConstructOpPrepairCopyPackedSheet(PackedFont::ConstructContext * pContext,PackedFont::CachedStreamReader * pStream)954 PackedFont::ConstructOpPrepairCopyPackedSheet(
955     PackedFont::ConstructContext*   pContext,
956     PackedFont::CachedStreamReader* pStream
957 )
958 {
959     NN_POINTER_ASSERT(pContext);
960     NN_POINTER_ASSERT(pStream);
961     // 全てのシートに対して処理が終わっているか?
962     if (! pContext->HasMoreSheet())
963     {
964         pContext->op = ConstructContext::DISPATCH;
965         return CONSTRUCT_CONTINUE;
966     }
967 
968     u32 compSize;
969     const u32 requireSize = sizeof(compSize);
970 
971     if (pStream->GetRemain() < requireSize)
972     {
973         return RequestData(pContext, pStream, requireSize);
974     }
975 
976     // 圧縮データサイズを読み込む
977     pStream->CopyTo(&compSize, sizeof(compSize));
978 
979     const u32 srcSize = compSize;
980 
981     // ロードしなければならないシートか?
982     if (pContext->IsRequireSheet())
983     {
984         // ロードする
985 
986         if (pContext->GetRemain() < srcSize)
987         {
988             NN_LOG("buffer size too small");
989             return CONSTRUCT_ERROR;
990         }
991 
992         // CXヘッダ + CXデータをコピー
993         pContext->SetupCopyTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
994     }
995     else
996     {
997         // CXヘッダ + CXデータをスキップ
998         pContext->SetupSkipTask(srcSize, ConstructContext::PREPAIR_EXPAND_SHEET);
999     }
1000 
1001     // カレントシート番号を更新
1002     pContext->NextSheet();
1003 
1004     return CONSTRUCT_CONTINUE;
1005 }
1006 
1007 
1008 
1009 
1010 
1011 /* =======================================================================
1012         LRUManager
1013    ======================================================================== */
1014 
1015 void
Init(void * buffer,int numOrderNode)1016 PackedFont::LRUManager::Init(
1017     void*   buffer,
1018     int     numOrderNode
1019 )
1020 {
1021     mpOrderNodeArray = reinterpret_cast<OrderNode*>(buffer);
1022     mNumOrderNode  = static_cast<u16>(numOrderNode);
1023     mNumLockedNode = 0;
1024 
1025     // index = numOrderNode をルートとして双方向循環リストを構成する
1026     // index=0 が LRU となる
1027     int i = 0;
1028     for ( ; i < numOrderNode; ++i)
1029     {
1030         OrderNode& node = GetNode(i);
1031         node.prevIndex = static_cast<u16>(i + 1);
1032         node.nextIndex = static_cast<u16>((i <= 0) ? numOrderNode: i - 1);
1033     }
1034 
1035     OrderNode& root = GetRootNode();
1036     root.prevIndex = 0;
1037     root.nextIndex = static_cast<u16>(numOrderNode - 1);
1038 }
1039 
1040 void
Use(int index)1041 PackedFont::LRUManager::Use(int index)
1042 {
1043     NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1044     OrderNode& target = GetNode(index);
1045 
1046     if (! IsLockedNode(target))
1047     {
1048         // target をリンクリストからはずす
1049         Unlink(target);
1050 
1051         // target を先頭に挿入
1052         OrderNode& root     = GetRootNode();
1053         OrderNode& first    = GetNode(root.nextIndex);
1054         target.nextIndex    = root.nextIndex;
1055         target.prevIndex    = first.prevIndex;
1056         root.nextIndex      = static_cast<u16>(index);
1057         first.prevIndex     = static_cast<u16>(index);
1058     }
1059 }
1060 
1061 void
Unuse(int index)1062 PackedFont::LRUManager::Unuse(int index)
1063 {
1064     NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1065     OrderNode& target = GetNode(index);
1066 
1067     if (! IsLockedNode(target))
1068     {
1069         // target をリンクリストからはずす
1070         Unlink(target);
1071     }
1072 
1073     // target を最後に挿入
1074     OrderNode& root     = GetRootNode();
1075     OrderNode& last     = GetNode(root.prevIndex);
1076     target.prevIndex    = root.prevIndex;
1077     target.nextIndex    = last.nextIndex;
1078     root.prevIndex      = static_cast<u16>(index);
1079     last.nextIndex      = static_cast<u16>(index);
1080 }
1081 
1082 void
Lock(int index)1083 PackedFont::LRUManager::Lock(int index)
1084 {
1085     NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1086     OrderNode& target = GetNode(index);
1087 
1088     if (! IsLockedNode(target))
1089     {
1090         // target をリンクリストからはずす
1091         Unlink(target);
1092 
1093         // ロック状態にする
1094         MarkLocked(target);
1095         mNumLockedNode++;
1096     }
1097 }
1098 
1099 void
Unlock(int index)1100 PackedFont::LRUManager::Unlock(int index)
1101 {
1102     NW_FONT_MINMAX_ASSERT( index, 0, mNumOrderNode - 1 );
1103     OrderNode& target = GetNode(index);
1104 
1105     if (IsLockedNode(target))
1106     {
1107         mNumLockedNode--;
1108 
1109         // target を先頭に挿入
1110         OrderNode& root     = GetRootNode();
1111         OrderNode& first    = GetNode(root.nextIndex);
1112         target.nextIndex    = root.nextIndex;
1113         target.prevIndex    = first.prevIndex;
1114         root.nextIndex      = static_cast<u16>(index);
1115         first.prevIndex     = static_cast<u16>(index);
1116     }
1117 }
1118 
1119 
1120 
1121 
1122 }   // namespace font
1123 }   // namespace nw
1124