1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     font_TextWriterBase.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_CTR_FONT_TEXT_WRITER_BASE_H_
17 #define NN_FONT_CTR_FONT_TEXT_WRITER_BASE_H_
18 
19 #include <cstddef>
20 #include <cwchar>
21 #include <cstdio>
22 #include <cstring>
23 #include <cfloat>
24 #include <nn/types.h>
25 #include <nn/font/font_Font.h>
26 #include <nn/font/CTR/font_TagProcessorBase.h>
27 #include <nn/font/CTR/font_CharWriter.h>
28 #include <nn/util/util_Rect.h>
29 
30 
31 namespace nn {
32 namespace font {
33 namespace CTR {
34 
35 
36 //---------------------------------------------------------------------------
37 //! @brief        nw::font::Font クラスを用いて文字列の描画を行うためのクラスです。
38 //!
39 //! @tparam       CharType 文字の型。
40 //---------------------------------------------------------------------------
41 template <typename CharType>
42 class TextWriterBase: public CharWriter
43 {
44 public:
45     /* ------------------------------------------------------------------------
46 47        ------------------------------------------------------------------------ */
48 
49     //! SetDrawFlag() 関数で使用する文字列の配置を行う文字列描画フラグです。
50     enum PositionFlag
51     {
52         //水平方向の寄せ
53         HORIZONTAL_ALIGN_LEFT       = 0x0,      //!< 複数行文字列を左寄せする。
54         HORIZONTAL_ALIGN_CENTER     = 0x1,      //!< 複数行文字列を中央寄せする。
55         HORIZONTAL_ALIGN_RIGHT      = 0x2,      //!< 複数行文字列を右寄せする。
56         HORIZONTAL_ALIGN_MASK       = 0x3,
57 
58         // 原点の水平方向位置
59         HORIZONTAL_ORIGIN_LEFT      = 0x00,     //!< 原点を文字列の左端に置く。
60         HORIZONTAL_ORIGIN_CENTER    = 0x10,     //!< 原点を文字列の水平方向中央に置く。
61         HORIZONTAL_ORIGIN_RIGHT     = 0x20,     //!< 原点を文字列の右端に置く。
62         HORIZONTAL_ORIGIN_MASK      = 0x30,
63 
64         // 原点の垂直方向位置
65         VERTICAL_ORIGIN_TOP         = 0x000,    //!< 原点を文字列の上端に置く。
66         VERTICAL_ORIGIN_MIDDLE      = 0x100,    //!< 原点を文字列の垂直方向中央に置く。
67         VERTICAL_ORIGIN_BOTTOM      = 0x200,    //!< 原点を文字列の 1 行目ベースラインに置く。
68         VERTICAL_ORIGIN_BASELINE    = 0x300,    //!< 原点を文字列の下端に置く。
69         VERTICAL_ORIGIN_MASK        = 0x300
70     };
71 
72     enum ContextFlag
73     {
74         //! 前の文字との間に文字間が開けられていないことを示します
75         CONTEXT_NO_CHAR_SPACE       = 0x1
76     };
77 
78     /* ------------------------------------------------------------------------
79             変数
80        ------------------------------------------------------------------------ */
81     //! コンストラクタで設定されるデフォルトの描画フラグです。
82     static const u32 DEFAULT_DRAWFLAG =
83         HORIZONTAL_ALIGN_LEFT | HORIZONTAL_ORIGIN_LEFT | VERTICAL_ORIGIN_TOP;
84 
85 
86     /* ------------------------------------------------------------------------
87             関数
88        ------------------------------------------------------------------------ */
89 
90     //! @name コンストラクタ / デストラクタ
91     //@{
92 
93     //! コンストラクタです。
94                         TextWriterBase();
95 
96     //! デストラクタです。
97                         ~TextWriterBase();
98 
99     //@}
100 
101     //! @name 文字間 / 行間 / タブ幅
102     //@{
103 
104     //! @brief      行間を設定します。
105     //!
106     //! @param[in]  space   新しい行間。
107     //!
SetLineSpace(f32 space)108     void                SetLineSpace(f32 space)     { m_LineSpace = space; }
109 
110     //! @brief      行間を取得します。
111     //!
112     //! @return     行間を返します。
113     //!
GetLineSpace()114     f32                 GetLineSpace() const        { return m_LineSpace; }
115 
116     //! @brief      1 行の高さを設定します。
117     //!
118     //! @param[in]  height  新しい行の高さ。
119     //!
120     void                SetLineHeight(f32 height);
121 
122     //! @brief      1 行の高さを取得します。
123     //!
124     //! @return     1 行の高さを返します。
125     //!
126     f32                 GetLineHeight() const;
127 
128     //! @brief      文字間を設定します。
129     //!
130     //! @param[in]  space   新しい文字間。
131     //!
SetCharSpace(f32 space)132     void                SetCharSpace(f32 space)     { m_CharSpace = space; }
133 
134     //! @brief      文字間を取得します。
135     //!
136 	//! @return     文字間を返します。
137     //!
GetCharSpace()138     f32                 GetCharSpace() const        { return m_CharSpace; }
139 
140     //! @brief      タブ幅を指定します。
141     //!
142     //! @param[in]  tabWidth    文字数換算のタブ幅。
143     //!
SetTabWidth(int tabWidth)144     void                SetTabWidth(int tabWidth)   { m_TabWidth = tabWidth; }
145 
146     //! @brief      タブ幅を取得します。
147     //!
148     //! @return     文字数換算のタブ幅を返します。
149     //!
GetTabWidth()150     int                 GetTabWidth() const         { return m_TabWidth; }
151 
152     //@}
153 
154     //! @name 文字列の自動折り返し
155     //@{
156 
157     //! @brief      自動的に折り返す幅を指定します。
158     //!
159     //! @param[in]  limit   自動的に折り返す幅。
160     //!
SetWidthLimit(f32 limit)161     void                SetWidthLimit(f32 limit)    { m_WidthLimit  = limit; }
162 
163     //! @brief      設定されている折り返し幅を取得します。
164     //!
165     //! @return     設定されている折り返し幅を返します。@n
166     //!             折り返し幅が無効に設定されているときは正の無限大を返します。
167     //!
GetWidthLimit()168     f32                 GetWidthLimit() const       { return m_WidthLimit; }
169 
170     //! 自動折り返し機能を無効に設定します。
ResetWidthLimit()171     void                ResetWidthLimit()           { SetWidthLimit(FLT_MAX); }
172 
173     //@}
174 
175 
176     //! @name 文字列描画フラグ設定 / 取得
177     //@{
178 
179 	//! @brief      文字列描画フラグを設定します。
180     //!
181     //! @param[in]  flags   新しい文字列描画フラグ
182     //!
SetDrawFlag(u32 flags)183     void                SetDrawFlag(u32 flags)      { m_DrawFlag = flags; }
184 
185     //! @brief      文字列描画フラグを取得します。
186     //!
187     //! @return     文字列描画フラグを返します。
188     //!
GetDrawFlag()189     u32                 GetDrawFlag() const         { return m_DrawFlag; }
190 
191     //@}
192 
193 
194     //! @name タグプロセッサ設定 / 取得
195     //@{
196 
197     //! @brief      タグプロセッサを設定します。
198     //!
199     //! @param[in]  tagProcessor    新しいタグプロセッサへのポインタ。
200     //!
SetTagProcessor(TagProcessorBase<CharType> * tagProcessor)201     void                SetTagProcessor(TagProcessorBase<CharType>* tagProcessor)
202     {
203         NN_POINTER_ASSERT(tagProcessor);
204 
205         m_TagProcessor = tagProcessor;
206     }
207 
208     //! @brief      タグプロセッサを取得します。
209     //!
210     //! @return     タグプロセッサのリファレンスを返します。
211     //!
212     TagProcessorBase<CharType>&
GetTagProcessor()213                         GetTagProcessor() const     { return *m_TagProcessor; }
214 
215     //! タグプロセッサをデフォルトに戻します。
ResetTagProcessor()216     void                ResetTagProcessor()         { m_TagProcessor = &s_DefaultTagProcessor; }
217 
218     //@}
219 
220 
221     //! @name 文字列の描画サイズ計算
222     //@{
223 
224     //! @brief      文字列の幅を計算します。
225     //!
226     //! @param[in]  format  書式文字列。
227     //! @param[in]  ...     文字列パラメータ。
228     //!
229     //! @return     文字列の幅を返します。
230     //!
231     f32                 CalcFormatStringWidth(
232                             const CharType* format,
233                             ...
234                         ) const;
235 
236     //! @brief      文字列の幅を計算します。
237     //!
238     //! @param[in]  str     文字列。
239     //!
240     //! @return     文字列の幅を返します。
241     //!
CalcStringWidth(const CharType * str)242     f32                 CalcStringWidth(
243                             const CharType* str
244                         ) const
245     {
246         NN_POINTER_ASSERT(str);
247 
248         return CalcStringWidth(str, StrLen(str));
249     }
250 
251     //! @brief      文字列の幅を計算します。
252     //!
253     //! @param[in]  str     文字列。
254     //! @param[in]  length  文字列長。
255     //!
256     //! @return     文字列の幅を返します。
257     //!
258     f32                 CalcStringWidth(
259                             const CharType* str,
260                             int             length
261                         ) const;
262 
263 
264     //! @brief      文字列の高さを計算します。
265     //!
266     //! @param[in]  format  書式文字列。
267     //! @param[in]  ...     文字列パラメータ。
268     //! @param[in]  str     文字列。
269     //! @param[in]  length  文字列長。
270     //!
271     //! @return     文字列の高さを返します。
272     //!
273     f32                 CalcFormatStringHeight(
274                             const CharType* format,
275                             ...
276                         ) const;
277 
278     //! @brief      文字列の高さを計算します。
279     //!
280     //! @param[in]  str     文字列。
281     //!
282     //! @return     文字列の高さを返します。
283     //!
CalcStringHeight(const CharType * str)284     f32                 CalcStringHeight(
285                             const CharType* str
286                         ) const
287     {
288         NN_POINTER_ASSERT(str);
289 
290         return CalcStringHeight(str, StrLen(str));
291     }
292 
293     //! @brief      文字列の高さを計算します。
294     //!
295     //! @param[in]  str     文字列。
296     //! @param[in]  length  文字列長。
297     //!
298     //! @return     文字列の高さを返します。
299     //!
300     f32                 CalcStringHeight(
301                             const CharType* str,
302                             int             length
303                         ) const;
304 
305     //! @brief      文字列の描画矩形を計算します。
306     //!
307     //! @param[out] pRect   文字列描画矩形を受け取るバッファへのポインタ。
308     //! @param[in]  format  書式文字列。
309     //! @param[in]  ...     文字列パラメータ。
310     //!
311     void                CalcFormatStringRect(
312                             util::Rect*     pRect,
313                             const CharType* format,
314                             ...
315                         ) const;
316 
317 
318     //! @brief      文字列の描画矩形を計算します。
319     //!
320     //! @param[out] pRect   文字列描画矩形を受け取るバッファへのポインタ。
321     //! @param[in]  format  書式文字列。
322     //! @param[in]  args    文字列パラメータ。
323     //!
324     void                CalcVStringRect(
325                             util::Rect*     pRect,
326                             const CharType* format,
327                             std::va_list    args
328                         ) const;
329 
330 
331     //! @brief      文字列の描画矩形を計算します。
332     //!
333     //! @param[out] pRect   文字列描画矩形を受け取るバッファへのポインタ。
334     //! @param[in]  str     文字列。
335     //!
CalcStringRect(util::Rect * pRect,const CharType * str)336     void                CalcStringRect(
337                             util::Rect*     pRect,
338                             const CharType* str
339                         ) const
340     {
341         NN_POINTER_ASSERT(pRect);
342         NN_POINTER_ASSERT(str);
343 
344         CalcStringRect(pRect, str, StrLen(str));
345     }
346 
347     //! @brief      文字列の描画矩形を計算します。
348     //!
349     //! @param[out] pRect   文字列描画矩形を受け取るバッファへのポインタ。
350     //! @param[in]  str     文字列。
351     //! @param[in]  length  文字列長。
352     //!
353     void                CalcStringRect(
354                             util::Rect*     pRect,
355                             const CharType* str,
356                             int             length
357                         ) const;
358 
359     //@}
360 
361 
362     //! @name 文字列描画
363     //@{
364 
365     //! @brief      文字列を描画します。
366     //!
367     //! @param[in]  format  書式文字列。
368     //! @param[in]  ...     文字列パラメータ
369     //!
370     //! @return     文字列の幅を返します。
371     //!
372     f32                 Printf(
373                             const CharType* format,
374                             ... );
375 
376     //! @brief      文字列を描画します。
377     //!
378     //! @param[in]  format  書式文字列。
379     //! @param[in]  args    文字列パラメータ。
380     //!
381     //! @return     文字列の幅を返します。
382     //!
383     f32                 VPrintf(
384                             const CharType* format,
385                             std::va_list    args);
386 
387     //! @brief      文字列を描画します。
388     //!
389     //! @param[in]  str     文字列。
390     //!
391     //! @return     文字列の幅を返します。
392     //!
Print(const CharType * str)393     f32                 Print(
394                             const CharType* str
395                         )
396     {
397         NN_POINTER_ASSERT(str);
398 
399         return Print(str, StrLen(str));
400     }
401 
402     //! @brief      文字列を描画します。
403     //!
404     //! @param[in]  str     文字列。
405     //! @param[in]  length  文字列長。
406     //!
407     //! @return     文字列の幅を返します。
408     //!
409     f32                 Print(
410                             const CharType* str,
411                             int             length);
412 
413     //@}
414 
415     //! @name 書式展開バッファ
416     //@{
417 
418     //! @brief      	書式文字列展開用のバッファを割り当てます。
419     //!
420     //! @param[in]      size    バッファサイズ。
421     //!
422     //! @return         以前に TextWriter に割り当てられたバッファが存在する場合には
423     //!                 そのバッファへのポインタを返します。
424     //!                 割り当てられたバッファが存在しない場合には NULL を返します。
425     //!
SetBuffer(std::size_t size)426     static void*        SetBuffer(
427                             std::size_t size
428                         )
429     {
430         NN_FONT_MIN_ASSERT(size, 1);
431         void* oldBuffer = s_FormatBuffer;
432 
433         s_FormatBuffer       = NULL;
434         s_FormatBufferSize   = size;
435 
436         return oldBuffer;
437     }
438 
439     //! @brief      	書式文字列展開用のバッファを割り当てます。
440     //!
441     //! @param[in]      buffer  TextWriter に割り当てるバッファへのポインタ。
442     //! @param[in]      size    バッファサイズ。
443     //!
444     //! @return         以前に TextWriter に割り当てられたバッファが存在する場合には
445     //!                 そのバッファへのポインタを返します。
446     //!                 割り当てられたバッファが存在しない場合には NULL を返します。
447     //!
SetBuffer(CharType * buffer,std::size_t size)448     static void*        SetBuffer(
449                             CharType*   buffer,
450                             std::size_t size
451                         )
452     {
453         NN_POINTER_ASSERT(buffer);
454         NN_FONT_MIN_ASSERT(size, 1);
455         void* oldBuffer = s_FormatBuffer;
456 
457         s_FormatBuffer       = buffer;
458         s_FormatBufferSize   = size;
459 
460         return oldBuffer;
461     }
462 
463     //! @brief      書式文字列展開用のバッファへのポインタを取得します。
464     //!
465     //! @return     書式文字列展開用のバッファへのポインタを返します。
466     //!
GetBuffer()467     static const void*  GetBuffer()
468     {
469         return s_FormatBuffer;
470     }
471 
472     //! @brief      書式文字列展開用のバッファサイズを取得します。
473     //!
474     //! @return     書式文字列展開用のバッファのサイズを返します。
475     //!
GetBufferSize()476     static std::size_t  GetBufferSize()
477     {
478         return s_FormatBufferSize;
479     }
480 
481     //@}
482 
483 
484     //---- vsnprintf の 分岐
VSNPrintf(char * buffer,std::size_t count,const char * format,std::va_list arg)485     static int          VSNPrintf(
486                             char*           buffer,
487                             std::size_t     count,
488                             const char*     format,
489                             std::va_list    arg
490                         )
491     {
492         #if ! defined(_MSC_VER)
493             using namespace std;
494         #endif
495 
496         return vsnprintf(buffer, count, format, arg);
497     }
498 
VSNPrintf(wchar_t * buffer,std::size_t count,const wchar_t * format,std::va_list arg)499     static int          VSNPrintf(
500                             wchar_t*        buffer,
501                             std::size_t     count,
502                             const wchar_t*  format,
503                             std::va_list    arg
504                         )
505     {
506         #if ! defined(_MSC_VER)
507             using namespace std;
508         #endif
509 
510         return vswprintf(buffer, count, format, arg);
511     }
512 
StrLen(const char * str)513     static int          StrLen(const char* str)
514     {
515         return static_cast<int>(std::strlen(str));
516     }
517 
StrLen(const wchar_t * str)518     static int          StrLen(const wchar_t* str)
519     {
520         return static_cast<int>(std::wcslen(str));
521     }
522 
523 
524     using CharWriter::Print;
525 
526     #if defined(NN_FONT_PROFILE)
527         void                PrintProfile();
528     #endif
529 
530 protected:
531     #if defined(NN_FONT_PROFILE)
532         void                CopyProfileData(const TextWriterBase<CharType>& other) const;
533     #endif
534 
535 
536 private:
537     /* ------------------------------------------------------------------------
538 539        ------------------------------------------------------------------------ */
540     typedef TagProcessorBase<CharType>  TagProcessor;
541     typedef const CharType*             StreamType;
542 
543     /* ------------------------------------------------------------------------
544             定数
545        ------------------------------------------------------------------------ */
546     static const int DEFAULT_FORMAT_BUFFER_SIZE = 256;
547 
548     /* ------------------------------------------------------------------------
549             関数
550        ------------------------------------------------------------------------ */
551 
552     //! @brief      1行の長さを計算します。
553     //!
554     //! @param[in]  str     文字列
555     //! @param[in]  length  文字列長(sizeof(CharType)単位)
556     //!
557     f32                 CalcLineWidth(
558                             StreamType  str,
559                             int         length);
560 
561     //! @brief      1行分の描画矩形を計算します。
562     //!
563     //! @param[out]     pRect   描画矩形を格納するバッファへのポインタ。
564     //! @param[in,out]  pStr    文字列へのポインタを格納するバッファへのポインタ。
565     //! @param[in]      length  文字列長(sizeof(CharType)単位)
566     //!
567     //! @return     WidthLimit を超えたら true を、超えなければ false を返します。
568     //!
569     bool                CalcLineRectImpl(
570                             util::Rect* pRect,
571                             StreamType* pStr,
572                             int         length);
573 
574     //! @brief      文字列の描画矩形を計算します。
575     //!
576     //! @param[out] pRect   描画矩形を格納するバッファへのポインタ。
577     //! @param[in]  str     文字列
578     //! @param[in]  length  文字列長(sizeof(CharType)単位)
579     //!
580     void                CalcStringRectImpl(
581                             util::Rect* pRect,
582                             StreamType  str,
583                             int         length);
584 
585     //! @brief      文字列を描画します。
586     //!
587     //! @param[in]  str         文字列
588     //! @param[in]  length      文字列長(sizeof(CharType)単位)
589     //!
590     f32                 PrintImpl(
591                             StreamType  str,
592                             int         length);
593 
594 
595     //! @brief      文字列を描画フラグに従って描画するときの1文字目の
596     //!             描画開始位置にカーソルを移動します。
597     //!
598     //! @param[in,out]  pXOrigin  描画基準座標を格納したバッファへのポインタ。
599     //!                           補正後の描画基準座標が格納されて返る。
600     //! @param[in,out]  pYOrigin  描画基準座標を格納したバッファへのポインタ。
601     //!                           補正後の描画基準座標が格納されて返る。
602     //! @param[in]      str       文字列
603     //! @param[in]      length    文字列長(sizeof(CharType)単位)
604     //!
605     //! @return     文字列の幅を返します。
606     //!
607     f32                 AdjustCursor(
608                             f32*        pXOrigin,
609                             f32*        pYOrigin,
610                             StreamType  str,
611                             int         length);
612 
613     //! @brief      描画フラグが設定されているか判定します。
614     //!
615     //! @param[in]  mask    描画フラグのマスク値。
616     //! @param[in]  flag    判定する描画フラグ。
617     //!
618     //! @return     指定された描画フラグが設定されている場合は真を返します。
619     //!
IsDrawFlagSet(u32 mask,u32 flag)620     bool                IsDrawFlagSet(
621                             u32 mask,
622                             u32 flag
623                         ) const
624     {
625         return (m_DrawFlag & mask) == flag;
626     }
627 
628     /* ------------------------------------------------------------------------
629             変数
630        ------------------------------------------------------------------------ */
631 
632     static CharType*        s_FormatBuffer;         //!< sprintfバッファへのポインタ
633     static std::size_t      s_FormatBufferSize;     //!< sprintfバッファのサイズ
634 
635     //! デフォルトタグプロセッサ
636     static TagProcessor     s_DefaultTagProcessor;
637 
638     f32                     m_WidthLimit;           //!< 描画幅制限
639     f32                     m_CharSpace;            //!< 文字間
640     f32                     m_LineSpace;            //!< 行間
641     int                     m_TabWidth;             //!< タブ幅
642     u32                     m_DrawFlag;             //!< 描画フラグ
643     TagProcessor*           m_TagProcessor;         //!< タグ処理機
644 
645     #if defined(NN_FONT_PROFILE)
646         mutable Stopwatch           m_PrintTextSw;
647         mutable u32                 m_PrintTextCount;
648     #endif
649 };
650 
651 }   // namespace CTR
652 }   // namespace font
653 }   // namespace nn
654 
655 #endif //  NN_FONT_CTR_FONT_TEXT_WRITER_BASE_H_
656