1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     font_PackedFont.h
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: 25674 $
14  *---------------------------------------------------------------------------*/
15 
16 #ifndef NN_FONT_FONT_PACKED_FONT_H_
17 #define NN_FONT_FONT_PACKED_FONT_H_
18 
19 #include <nn/types.h>
20 #include <nn/font/font_ArchiveFontBase.h>
21 
22 namespace nn {
23 namespace font {
24 
25 
26 //---------------------------------------------------------------------------
27 //! @brief        圧縮されているフォントリソースをそのままメモリ上に持ち、
28 //!               グリフを要求された場合に、必要に応じて展開して使用するクラスです。
29 //---------------------------------------------------------------------------
30 class PackedFont : public ArchiveFontBase
31 {
32 public:
33     /* ------------------------------------------------------------------------
34             関数
35        ------------------------------------------------------------------------ */
36     //! @name コンストラクタ / デストラクタ
37     //@{
38 
39     //! コンストラクタです。
40                         PackedFont();
41 
42     //! デストラクタです。
43     virtual             ~PackedFont();
44 
45     //@}
46 
47     //! @name リソースの関連付け / 解除
48     //@{
49 
50     //! @brief      フォントを構築するのに必要なバッファのサイズを計算します。
51     //!
52     //! @param[in]  bfnt           メモリ上にロード済みのバイナリリソース(bfnt)先頭部分への
53     //!                            ポインタ。
54     //! @param[in]  numSheetCache  展開したシートをキャッシュする最大枚数。
55     //!
56     //! @return     Construct() 関数または InitStreamingConstruct() 関数で
57     //!             フォントを構築する場合に必要なバッファのサイズを返します。@n
58     //!             リソース @a bfnt が不正である等の理由でバッファサイズが
59     //!             計算できなかった場合は 0 を返します。
60     //!
GetRequireBufferSize(const void * bfnt,int numSheetCache)61     static u32      GetRequireBufferSize(
62                         const void* bfnt,
63                         int         numSheetCache
64     )
65     {
66         return GetRequireBufferSize(bfnt, LOAD_GLYPH_ALL, numSheetCache);
67     }
68 
69     //! @brief      フォントを構築するのに必要なバッファのサイズを計算します。
70     //!
71     //! @param[in]  bfnt            メモリ上にロード済みのバイナリリソース(bfnt)先頭部分への
72     //!                             ポインタ。
73     //! @param[in]  glyphGroups     ロードするグリフグループを指定する文字列。
74     //! @param[in]  numSheetCache   展開したシートをキャッシュする最大枚数。
75     //! @param[in]  rateSheetCache  展開したシートをキャッシュする最大枚数の、
76     //!                             シートの枚数に対する割合。
77     //!
78     //! @return     Construct() 関数または InitStreamingConstruct() 関数で
79     //!             フォントを構築する場合に必要なバッファのサイズを返します。@n
80     //!             リソース @a bfnt が不正である等の理由でバッファサイズが
81     //!             計算できなかった場合は 0 を返します。
82     //!
83     static u32      GetRequireBufferSize(
84                         const void* bfnt,
85                         const char* glyphGroups,
86                         int         numSheetCache);
87 
88     //! @brief      フォントを構築するのに必要なバッファのサイズを計算します。
89     //!
90     //! @param[in]  bfnt            メモリ上にロード済みのバイナリリソース(bfnt)先頭部分への
91     //!                             ポインタ。
92     //! @param[in]  rateSheetCache  展開したシートをキャッシュする最大枚数の、
93     //!                             シートの枚数に対する割合。
94     //!
95     //! @return     Construct() 関数または InitStreamingConstruct() 関数で
96     //!             フォントを構築する場合に必要なバッファのサイズを返します。@n
97     //!             リソース @a bfnt が不正である等の理由でバッファサイズが
98     //!             計算できなかった場合は 0 を返します。
99     //!
GetRequireBufferSize(const void * bfnt,f32 rateSheetCache)100     static u32      GetRequireBufferSize(
101                         const void* bfnt,
102                         f32         rateSheetCache
103     )
104     {
105         return GetRequireBufferSize(bfnt, LOAD_GLYPH_ALL, rateSheetCache);
106     }
107 
108     //! @brief      フォントを構築するのに必要なバッファのサイズを計算します。
109     //!
110     //! @param[in]  bfnt            メモリ上にロード済みのバイナリリソース(bfnt)先頭部分への
111     //!                             ポインタ。
112     //! @param[in]  glyphGroups     ロードするグリフグループを指定する文字列。
113     //! @param[in]  rateSheetCache  展開したシートをキャッシュする最大枚数の、
114     //!                             シートの枚数に対する割合。
115     //!
116     //! @return     Construct() 関数または InitStreamingConstruct() 関数で
117     //!             フォントを構築する場合に必要なバッファのサイズを返します。@n
118     //!             リソース @a bfnt が不正である等の理由でバッファサイズが
119     //!             計算できなかった場合は 0 を返します。
120     //!
121     static u32      GetRequireBufferSize(
122                         const void* bfnt,
123                         const char* glyphGroups,
124                         f32         rateSheetCache
125                     );
126 
127     //! @brief      アーカイブフォントからグリフグループを抽出しフォントを構築します。
128     //!
129     //! @param[out] pBuffer     このインスタンスに関連付けるバッファへのポインタ。
130     //!                         128byte アライメントされている必要があります。
131     //! @param[in]  bufferSize  @a pBuffer が指すバッファのサイズ。
132     //! @param[in]  bfnt        メモリ上にロード済みのバイナリリソース(bfnt) へのポインタ。
133     //! @param[in]  glyphGroups ロードするグリフグループを指定する文字列。
134     //!
135     //! @return     フォントの構築が成功したなら true を、そうでなければ false を返します。@n
136     //!             アーカイブフォント @a bfnt が不正であったり
137     //!             バッファサイズが小さすぎると失敗します。
138     //!
139     bool            Construct(
140                         void*               pBuffer,
141                         u32                 bufferSize,
142                         const void*         bfnt,
143                         const char*         glyphGroups = LOAD_GLYPH_ALL
144                     );
145 
146     //! @brief      アーカイブフォントから順次読み込みでグリフグループを抽出し、
147     //!             フォントを構築するための初期化を行います。
148     //!
149     //! @param[out] pContext    初期化するストリーミング構築コンテキストへのポインタ。
150     //! @param[out] pBuffer     このインスタンスに関連付けるバッファへのポインタ。
151     //!                         128byte アライメントされている必要があります。
152     //! @param[in]  bufferSize  @a pBuffer が指すバッファのサイズ。
153     //! @param[in]  glyphGroups ロードするグリフグループを指定する文字列。
154     //!
155     void            InitStreamingConstruct(
156                         ConstructContext*   pContext,
157                         void*               pBuffer,
158                         u32                 bufferSize,
159                         const char*         glyphGroups = LOAD_GLYPH_ALL
160                     );
161 
162     //! @brief      アーカイブフォントから順次読み込みでフォントを構築します。
163     //!
164     //! @param[out] pContext    InitStreamingConstruct() 関数で初期化した
165     //!                         ストリーミング構築コンテキストへのポインタ。
166     //! @param[in]  stream      アーカイブフォントの一部を格納したバッファへのポインタ。
167     //! @param[in]  streamSize  @a stream が指すバッファに格納されているデータのバイト数。
168     //!
169     //! @return     構築処理の経過状態を返します。
170     //!
171     ConstructResult StreamingConstruct(
172                         ConstructContext*   pContext,
173                         const void*         stream,
174                         u32                 streamSize);
175 
176     //! @brief      フォントを破棄します。
177     //!
178     //! @return     Construct() 関数または InitStreamingConstruct() 関数で、
179     //!             このインスタンスに割り当てたメモリ領域へのポインタを返します。
180     //!
181     void*           Destroy();
182 
183     //@}
184 
185 
186     //! @name キャッシュ管理
187     //@{
188 
189     //! @brief      キャッシュの数を取得します。
190     //!
191     //! @return     キャッシュの数を返します。
192     //!
GetNumCache()193     int             GetNumCache() const { return m_NumSheetCache; }
194 
195     //! @brief      シートをあらかじめキャッシュに読み込みます。
196     //!
197     //! @param[in]  c   ロードするシートに含まれるグリフを指す文字コード。
198     //!
199     //! @return     シートを新たにキャッシュした場合は true を、
200 	//!             既にキャッシュ済みだった場合は false を返します。
201     //!
202     bool            PreloadSheet(CharCode c);
203 
204     //! @brief      キャッシュ上のシートを破棄されないようにします。
205     //!
206     //! @param[in]  c   ロックするシートに含まれるグリフを指す文字コード。
207     //!
208     //! @return     ロックを行った場合は true を、
209     //!             ロックを行えなかった場合は false を返します。@n
210     //!             ロックできるシートの最大数を超える場合にはロックは行えません。
211     //!
212     bool            LockSheet(CharCode c);
213 
214     //! @brief      シートのロックを解除します。
215     //!
216     //! @param[in]  c       ロックを解除するシートに含まれるグリフを指す文字コード。
217     //! @param[in]  bUnload ロック解除後、さらにキャッシュを破棄するならば、true を指定します。
218     //!
219     //! @return     対象のシートがキャッシュ上に存在しなかった場合には false を返します。
220     //!
221     bool            UnlockSheet(
222                         CharCode    c,
223                         bool        bUnload = true
224                     );
225 
226     //! @brief      全てのシートのロックを解除します。
227     //!
228     void            UnlockSheetAll();
229 
230     //@}
231 
232 
233     //! @name 文字情報の取得
234     //@{
235 
236     //! @brief      グリフデータを取得します。
237     //!
238     //! @param[out] glyph   グリフデータを受け取るバッファへのポインタ。
239     //! @param[in]  c       グリフデータを取得する文字の文字コード。
240     //!
241     virtual void    GetGlyph(
242                         Glyph*      glyph,
243                         CharCode    c
244                     ) const;
245 
246     //@}
247 
248 
249 protected:
250 
251     //! @name シート情報の取得
252     //@{
253 
254     virtual int             GetActiveSheetNum() const;
255 
256     //@}
257 
258 
259 private:
260     /* ------------------------------------------------------------------------
261 262        ------------------------------------------------------------------------ */
263     // Leaset Recently Used 管理のためのクラス
264     class LRUManager
265     {
266     public:
267         struct OrderNode
268         {
269             u16 prevIndex;
270             u16 nextIndex;
271         };
272 
GetRequireBufferSize(int numNode)273         static u32          GetRequireBufferSize(int numNode)
274         {
275             return sizeof(OrderNode) * (numNode + 1);
276         }
277 
278         //! @brief      初期化します。
279         //!
280         //! @param[in]  buffer:       LRUManager に割り当てるバッファを指定します。
281         //! @param[in]  numOrderNode  LRU管理するオブジェクトの数を指定します。
282         //!
283         void                Init(
284                                 void*   buffer,
285                                 int     numOrderNode);
286 
287         //! @brief      Use されたことを記録します。
288         //!
289         //! @param[in]  index  Use されたオブジェクトの番号。
290         //!
291         void                Use(int index);
292 
293         //! @brief      最も最後に使用されたことにします。
294         //!
295         //! @param[in]  index  LRU にするブジェクトの番号。
296         //!
297         void                Unuse(int index);
298 
299         //! @brief      LRU 管理対象から除外します。
300         //!
301         //! @param[in]  index  ロックするオブジェクトの番号。
302         //!
303         void                Lock(int index);
304 
305         //! @brief      LRU 管理対象に戻します。
306         //!
307         //! @param[in]  index  ロック解除するオブジェクトの番号。
308         //!
309         void                Unlock(int index);
310 
GetLastIndex()311         int                 GetLastIndex() const    { return GetRootNode().prevIndex; }
312 
IsLocked(int index)313         bool                IsLocked(int index) const
314         {
315             const OrderNode& node = GetNode(index);
316             return IsLockedNode(node);
317         }
318 
GetNumLocked()319         int                 GetNumLocked() const    { return mNumLockedNode; }
320 
321     private:
IsLockedNode(const OrderNode & node)322         bool                IsLockedNode(const OrderNode& node) const
323         {
324             NN_ASSERT( ! (node.prevIndex == LOCKED_INDEX) ^ (node.nextIndex == LOCKED_INDEX) );
325             return (node.prevIndex == LOCKED_INDEX);
326         }
327 
MarkLocked(OrderNode & node)328         void                MarkLocked(OrderNode& node) const
329         {
330             node.prevIndex = LOCKED_INDEX;
331             node.nextIndex = LOCKED_INDEX;
332         }
333 
Unlink(OrderNode & node)334         void                Unlink(OrderNode& node)
335         {
336             OrderNode& prev = GetNode(node.prevIndex);
337             OrderNode& next = GetNode(node.nextIndex);
338             prev.nextIndex = node.nextIndex;
339             next.prevIndex = node.prevIndex;
340         }
341 
GetRootNode()342         OrderNode&          GetRootNode()           { return GetNode(mNumOrderNode); }
343 
GetRootNode()344         const OrderNode&    GetRootNode() const     { return GetNode(mNumOrderNode); }
345 
GetNode(int index)346         OrderNode& GetNode(int index)               { return mpOrderNodeArray[index]; }
347 
GetNode(int index)348         const OrderNode& GetNode(int index) const   { return mpOrderNodeArray[index]; }
349 
350     private:
351         static const u16    LOCKED_INDEX  = 0xFFFF;
352 
353         OrderNode*          mpOrderNodeArray;
354         u16                 mNumOrderNode;
355         u16                 mNumLockedNode;
356     };
357 
358 
359     /* ------------------------------------------------------------------------
360             定数
361        ------------------------------------------------------------------------ */
362     static const u16 SHEET_INDEX_NOT_LOADED = 0xFFFF;
363 
364 
365     /* ------------------------------------------------------------------------
366             関数
367        ------------------------------------------------------------------------ */
368     //---- グリフの取得
369 
370     //! @brief      Glyph 構造体にグリフの情報を格納します。
371     //!
372     //! @param[out] glyph:      情報の格納先となる構造体へのポインタ。
373     //! @param[in]  gindex:     情報を格納するグリフを指すグリフインデックス。
374     //! @param[in]  cacheIndex: gindex が指すグリフのグリフイメージが含まれた
375     //!                         シートが展開されているキャッシュ領域番号。
376     //!
377     void                MakeGlyph(
378                             Glyph*      glyph,
379                             GlyphIndex  gindex,
380                             int         cacheIndex
381                         ) const;
382 
383     //---- シートの解凍
384 
385     //! @brief      圧縮シートを展開してキャッシュします。
386     //!
387     //! @param[in]  compIndex  圧縮シート番号
388     //!
389     //! @return     展開したシートがキャッシュされたキャッシュ領域番号
390     //!
391     int                 LoadSheet(int compIndex) const;
392 
393     //! @brief      キャッシュされているシートを破棄します。
394     //!
395     //! @param[in]  compIndex  圧縮シート番号。
396     //!
397     void                UnloadSheet(int compIndex) const;
398 
399     //---- シート状態の管理
400 
401     //! @brief      文字コードからその文字コードが表すグリフを含むシートの
402     //!             番号を取得します。
403     //!
404     //! @param[in]  c  文字コード。
405     //!
406     //! @return     c で指定される文字コードが表すグリフが含まれるシートの番号。
407     //!
408     int                 GetSheetIndex(CharCode c) const;
409 
410     //! @brief      調整済みグリフインデックスからそのグリフが含まれる
411     //!             シート番号を計算します。
412     //!
413     //! @param[in]  index  グリフインデックス。
414     //!
415     //! @return     index で指定されるグリフが含まれるシートの番号。
416     //!
417     int                 CalcSheetIndex(GlyphIndex index) const;
418 
419     //! @brief      圧縮シートを展開したデータがキャッシュされている
420     //!             キャッシュ領域番号を取得します。
421     //!
422     //! @param[in]  compIndex  問い合わせる圧縮シート番号。
423     //!
424     //! @return     compIndex で指定される圧縮シートを展開したデータが
425     //!             キャッシュされているキャッシュ領域番号を返します。
426     //!             キャッシュが存在しない場合は SHEET_INDEX_NOT_LOADED を返します。
427     //!
428     int                 GetCacheIndex(int compIndex) const;
429 
430     //! @brief      あるキャッシュに格納されているデータがどの圧縮シートを
431     //!             展開した物かを取得します。
432     //!
433     //! @param[in]  cacheIndex  問い合わせるキャッシュ番号。
434     //!
435     //! @return     cacheIndex に格納されているデータの展開元圧縮シート番号を
436     //!             返します。
437     //!             格納されているデータが意味を持たない場合は
438     //!             SHEET_INDEX_NOT_LOADED を返します。
439     //!
440     int                 GetCacheUser(int cacheIndex) const;
441 
442     //! @brief      圧縮シートを展開したデータが格納されている
443     //!             キャッシュ番号を記録します。
444     //!
445     //! @param[in]  compIndex   圧縮シート番号。
446     //! @param[in]  cacheIndex  compIndex で指定される圧縮シートを展開したデータが
447     //!                         格納されているキャッシュ番号
448     //!
449     void                SetCacheUser(
450                             int compIndex,
451                             int cacheIndex
452                         ) const;
453 
454     //! @brief      圧縮シートとキャッシュの関係を消去します。
455     //!
456     //! @param[in]  compIndex   圧縮シート番号。
457     //! @param[in]  cacheIndex  compIndex で指定される圧縮シートを展開したデータが
458     //!                         格納されていたキャッシュ番号。
459     //!
460     void                ResetCacheUser(
461                             int compIndex,
462                             int cacheIndex
463                         ) const;
464 
465     //---- シートの取得
466 
467     //! @brief      展開済みシートキャッシュ先頭へのポインタを取得します。
468     //!
469     //! @param[in]  cacheIndex  キャッシュ番号。
470     //!
471     //! @return     cacheIndex で指定されるキャッシュの先頭へのポインタを返します。
472     //!
473     u8*                 GetLoadedSheet(int cacheIndex) const;
474 
475     //! @brief      圧縮シートの先頭へのポインタを取得します。
476     //!
477     //! @param[in]  compIndex  圧縮シート番号。
478     //!
479     //! @return     compIndex で指定される圧縮シートの先頭へのポインタを返します。
480     //!
481     const u8*           GetCompSheet(int compIndex) const;
482 
483     //---- メモリ割り当て
484 
485     //! @brief      バッファを分配し各メンバに割り当てます。
486     //!
487     //! @param      buffer:         割り当てるメモリ領域へのポインタ。
488     //! @param      bufferSize:     buffer のサイズ。
489     //! @param      numResSheet:    リソースに含まれるシートの総数。
490     //! @param      numLoadSheet:   メモリ上にロードするシートの枚数。
491     //! @param      sheetSize:      展開したシートサイズ。
492     //!
493     //! @return     buffer 上に割り当てたグリフインデックス調整テーブルへの
494     //!             ポインタを返します。
495     //!             buffer が小さすぎる場合は NULL を返します。
496     //!
497     u16*                AssignMemory(
498                             u8* buffer,
499                             u32 bufferSize,
500                             u32 numResSheet,
501                             u32 numLoadSheet,
502                             u32 sheetSize);
503 
504 
505     //---- 必要メモリサイズ計算
506 
507     //! @brief      フォントリソース格納領域に必要なバッファサイズを計算します。
508     //!
509     //! @param[in]  gg             GLGR ブロックアクセサ。
510     //! @param[in]  glyphGroups    ロードするグリフグループ。
511     //! @param[in]  pNumLoadSheet  ロードするシートの枚数を格納するバッファへの
512     //!                            ポインタ。
513     //!
514     //! @return     フォントリソース格納領域に必要なバッファサイズを返します。
515     //!
516     static u32          CalcCopySize(
517                             const FontGlyphGroupsAcs&   gg,
518                             const char*                 glyphGroups,
519                             int*                        pNumLoadSheet);
520 
521     //! @brief      キャッシュ領域に必要なバッファサイズを計算します。
522     //!
523     //! @param[in]  gg             GLGR ブロックアクセサ。
524     //! @param[in]  numSheetCache  確保するシートキャッシュの数。
525     //!
526     //! @return     キャッシュ領域に必要なバッファサイズを返します。
527     //!
528     static u32          CalcCacheSize(
529                             const FontGlyphGroupsAcs&   gg,
530                             int                         numSheetCache);
531 
532     //---- ストリーミング処理
533 
534     //! @brief      GLGR ブロックを処理します。
535     //!
536     //! @param      pContext  ストリーム構築コンテキスト。
537     //! @param      pStream   入力ストリーム。
538     //!
539     //! @return     処理状態を返します。
540     //!
541     ConstructResult     ConstructOpAnalyzeGLGRPacked(
542                             ConstructContext*   pContext,
543                             CachedStreamReader* pStream);
544 
545     //! @brief      シートのコピー処理をセットアップします。
546     //!
547     //! @param      pContext  ストリーム構築コンテキスト。
548     //! @param      pStream   入力ストリーム。
549     //!
550     //! @return     処理状態を返します。
551     //!
552     static ConstructResult
553                         ConstructOpPrepairCopyPackedSheet(
554                             ConstructContext*   pContext,
555                             CachedStreamReader* pStream);
556 
557     /* ------------------------------------------------------------------------
558             変数
559        ------------------------------------------------------------------------ */
560     //! 解凍済みシートのキャッシュ状態を管理するオブジェクト
561     mutable LRUManager  m_LRUMan;
562 
563     u16                 m_NumCompSheet;         //!< ロードしたシートの数
564     u16                 m_NumSheetCache;        //!< シートキャッシュの数
565 
566     //! シート番号から使用しているキャッシュ領域番号を引くためのテーブル
567     u16*                m_pCacheIndexArray;     // mNumLoadedSheet
568 
569     //! キャッシュ領域番号からキャッシュされているシート番号を引くためのテーブル
570     u16*                m_pCacheUserArray;      // m_NumSheetCache
571 
572     //! 圧縮済みシートへのポインタの配列
573     const u8**          m_pCompSheetArray;      // mNumLoadedSheet
574 
575     //! シートキャッシュ領域へのポインタ
576     u8*                 m_pSheetCache;          // sheetSize * m_NumSheetCache
577 };
578 
579 }   // namespace font
580 }   // namespace nn
581 
582 #endif //  NN_FONT_FONT_PACKED_FONT_H_
583