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