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