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