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