1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     font_TextWriterBase.cpp
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 #include "precompiled.h"
19 
20 #include <cstdarg>
21 #include <cstdio>
22 #include <nn/types.h>
23 #include <nn/assert.h>
24 #include <nw/font/font_TextWriterBase.h>
25 #include <nw/font/font_TagProcessorBase.h>
26 #include <nw/ut/ut_Inlines.h>
27 
28 #if defined(_MSC_VER) && _MSC_VER >= 1500
29     #include <malloc.h>
30 
31     #define GET_FORMAT_BUFFER()                                 \
32         reinterpret_cast<CharType*>((s_FormatBuffer != NULL) ?  \
33             s_FormatBuffer:                                     \
34             _alloca(s_FormatBufferSize))
35 #else
36     #include <alloca.h>
37 
38     #define GET_FORMAT_BUFFER()                                 \
39         reinterpret_cast<CharType*>((s_FormatBuffer != NULL) ?  \
40             s_FormatBuffer:                                     \
41             alloca(s_FormatBufferSize))
42 #endif
43 
44 
45 namespace nw {
46 namespace font {
47 
48 
49 /* ------------------------------------------------------------------------
50         クラス変数定義
51    ------------------------------------------------------------------------ */
52 
53 template <typename CharType>
54 CharType* TextWriterBase<CharType>::s_FormatBuffer = NULL;
55 
56 template <typename CharType>
57 std::size_t TextWriterBase<CharType>::s_FormatBufferSize = DEFAULT_FORMAT_BUFFER_SIZE;
58 
59 template <typename CharType>
60 TagProcessorBase<CharType> TextWriterBase<CharType>::s_DefaultTagProcessor;
61 
62 namespace
63 {
64 
65 /*!--------------------------------------------------------------------------*
66   @brief        基点が中央であるときのカーソル位置補正の値を求めます。
67                 半分の値が浮動小数点にならないように整数値に切り上げます。
68 
69   @param[in]    value  考慮する幅/高さ
70 
71   @return       基点が中央であるときのカーソル位置補正の値を返します。
72  *---------------------------------------------------------------------------*/
73 inline
74 f32
AdjustCenterValue(f32 value)75 AdjustCenterValue(f32 value)
76 {
77     return math::FCeil(value * 0.5f);
78 }
79 
80 }   // namespace
81 
82 
83 /* =======================================================================
84         public
85    ======================================================================== */
86 
87 /* ------------------------------------------------------------------------
88         コンストラクタ/デストラクタ
89    ------------------------------------------------------------------------ */
90 
91 template <typename CharType>
TextWriterBase()92 TextWriterBase<CharType>::TextWriterBase()
93 : CharWriter(),
94   m_WidthLimit(FLT_MAX),
95   m_CharSpace(0),
96   m_LineSpace(0),
97   m_TabWidth (4),
98   m_DrawFlag(DEFAULT_DRAWFLAG),
99   m_TagProcessor(&s_DefaultTagProcessor)
100 {
101 }
102 
103 template <typename CharType>
~TextWriterBase()104 TextWriterBase<CharType>::~TextWriterBase()
105 {
106 }
107 
108 
109 
110 
111 
112 /* ------------------------------------------------------------------------
113         行間/文字間/タブ幅
114    ------------------------------------------------------------------------ */
115 
116 template <typename CharType>
117 void
SetLineHeight(f32 height)118 TextWriterBase<CharType>::SetLineHeight(f32 height)
119 {
120     const Font* font = GetFont();
121     const int linefeed = font != NULL ? font->GetLineFeed(): 0;
122 
123     m_LineSpace = height - linefeed * GetScaleV();
124 }
125 
126 template <typename CharType>
127 f32
GetLineHeight() const128 TextWriterBase<CharType>::GetLineHeight() const
129 {
130     const Font* font = GetFont();
131     const int linefeed = font != NULL ? font->GetLineFeed(): 0;
132 
133     return linefeed * GetScaleV() + m_LineSpace;
134 }
135 
136 
137 
138 
139 
140 
141 /* ------------------------------------------------------------------------
142         文字列サイズ計算
143    ------------------------------------------------------------------------ */
144 
145 template <typename CharType>
146 f32
CalcFormatStringWidth(StreamType format,...) const147 TextWriterBase<CharType>::CalcFormatStringWidth(
148     StreamType  format,
149     ...
150 ) const
151 {
152     NN_POINTER_ASSERT(format);
153 
154     ut::Rect rect;
155     std::va_list vargs;
156     va_start(vargs, format);
157 
158     CalcVStringRect(&rect, format, vargs);
159 
160     va_end(vargs);
161     return rect.GetWidth();
162 }
163 
164 template <typename CharType>
165 f32
CalcFormatStringHeight(StreamType format,...) const166 TextWriterBase<CharType>::CalcFormatStringHeight(
167     StreamType  format,
168     ...
169 ) const
170 {
171     NN_POINTER_ASSERT(format);
172 
173     ut::Rect rect;
174     std::va_list vargs;
175     va_start(vargs, format);
176 
177     CalcVStringRect(&rect, format, vargs);
178 
179     va_end(vargs);
180     return rect.GetHeight();
181 }
182 
183 template <typename CharType>
184 void
CalcFormatStringRect(ut::Rect * pRect,StreamType format,...) const185 TextWriterBase<CharType>::CalcFormatStringRect(
186     ut::Rect*   pRect,
187     StreamType  format,
188     ...
189 ) const
190 {
191     NN_POINTER_ASSERT(pRect);
192     NN_POINTER_ASSERT(format);
193 
194     std::va_list vargs;
195     va_start(vargs, format);
196 
197     CalcVStringRect(pRect, format, vargs);
198 
199     va_end(vargs);
200 }
201 
202 template <typename CharType>
203 void
CalcVStringRect(ut::Rect * pRect,StreamType format,std::va_list args) const204 TextWriterBase<CharType>::CalcVStringRect(
205     ut::Rect*       pRect,
206     StreamType      format,
207     std::va_list    args
208 ) const
209 {
210     NN_POINTER_ASSERT(pRect);
211     NN_POINTER_ASSERT(format);
212 
213     CharType* buffer = GET_FORMAT_BUFFER();
214 
215     int length = VSNPrintf(buffer, s_FormatBufferSize, format, args);
216     length = math::Min(length, int(s_FormatBufferSize - 1));
217     CalcStringRect(pRect, buffer, length);
218 }
219 
220 template <typename CharType>
221 f32
CalcStringWidth(StreamType str,int length) const222 TextWriterBase<CharType>::CalcStringWidth(
223     StreamType  str,
224     int         length
225 ) const
226 {
227     NN_POINTER_ASSERT(str);
228     NW_FONT_MIN_ASSERT(length, 0);
229 
230     ut::Rect rect;
231 
232     CalcStringRect(&rect, str, length);
233 
234     return rect.GetWidth();
235 }
236 
237 template <typename CharType>
238 f32
CalcStringHeight(StreamType str,int length) const239 TextWriterBase<CharType>::CalcStringHeight(
240     StreamType  str,
241     int         length
242 ) const
243 {
244     NN_POINTER_ASSERT(str);
245     NW_FONT_MIN_ASSERT(length, 0);
246 
247     ut::Rect rect;
248 
249     CalcStringRect(&rect, str, length);
250 
251     return rect.GetHeight();
252 }
253 
254 template <typename CharType>
255 void
CalcStringRect(ut::Rect * pRect,StreamType str,int length) const256 TextWriterBase<CharType>::CalcStringRect(
257     ut::Rect*   pRect,
258     StreamType  str,
259     int         length
260 ) const
261 {
262     NN_POINTER_ASSERT(pRect);
263     NN_POINTER_ASSERT(str);
264     NW_FONT_MIN_ASSERT(length, 0);
265 
266     TextWriterBase<CharType> myCopy = *this;
267 
268     myCopy.CalcStringRectImpl(pRect, str, length);
269 
270     #if defined(NW_FONT_PROFILE)
271         this->CopyProfileData(myCopy);
272     #endif
273 }
274 
275 
276 
277 
278 
279 
280 /* ------------------------------------------------------------------------
281         文字列描画
282    ------------------------------------------------------------------------ */
283 
284 template <typename CharType>
285 f32
Printf(StreamType format,...)286 TextWriterBase<CharType>::Printf(
287     StreamType  format,
288     ...
289 )
290 {
291     NN_POINTER_ASSERT(format);
292 
293     std::va_list vargs;
294     va_start(vargs, format);
295 
296     f32 width = VPrintf(format, vargs);
297 
298     va_end(vargs);
299     return width;
300 }
301 
302 template <typename CharType>
303 f32
VPrintf(StreamType format,std::va_list args)304 TextWriterBase<CharType>::VPrintf(
305     StreamType      format,
306     std::va_list    args
307 )
308 {
309     NN_POINTER_ASSERT(format);
310 
311     CharType* buffer = GET_FORMAT_BUFFER();
312 
313     int length = VSNPrintf(buffer, s_FormatBufferSize, format, args);
314     length = math::Min(length, int(s_FormatBufferSize - 1));
315     f32 width = Print(buffer, length);
316 
317     return width;
318 }
319 
320 template <typename CharType>
321 f32
Print(StreamType str,int length)322 TextWriterBase<CharType>::Print(
323     StreamType  str,
324     int         length
325 )
326 {
327     NN_POINTER_ASSERT(str);
328     NW_FONT_MIN_ASSERT(length, 0);
329 
330     NW_FONT_COUNTUP(m_PrintTextCount);
331     NW_FONT_STOPWATCH_START(m_PrintTextSw);
332 
333     TextWriterBase<CharType> myCopy = *this;
334 
335     f32 width = myCopy.PrintImpl(str, length);
336 
337     SetCursor( myCopy.GetCursorX(), myCopy.GetCursorY() );
338 
339     #if defined(NW_FONT_PROFILE)
340         this->CopyProfileData(myCopy);
341     #endif
342     NW_FONT_STOPWATCH_STOP(m_PrintTextSw);
343 
344     return width;
345 }
346 
347 /* =======================================================================
348         private
349    ======================================================================== */
350 
351 /* ------------------------------------------------------------------------
352         文字列処理
353    ------------------------------------------------------------------------ */
354 
355 template <typename CharType>
356 f32
CalcLineWidth(StreamType str,int length)357 TextWriterBase<CharType>::CalcLineWidth(
358     StreamType  str,
359     int         length
360 )
361 {
362     NN_POINTER_ASSERT(str);
363     NW_FONT_MIN_ASSERT(length, 0);
364 
365     ut::Rect rect;
366     TextWriterBase<CharType> myCopy = *this;
367 
368     myCopy.SetCursor(0, 0);
369     myCopy.CalcLineRectImpl(&rect, &str, length);
370 
371     #if defined(NW_FONT_PROFILE)
372         this->CopyProfileData(myCopy);
373     #endif
374 
375     return rect.GetWidth();
376 }
377 
378 template <typename CharType>
379 bool
CalcLineRectImpl(ut::Rect * pRect,StreamType * pStr,int length)380 TextWriterBase<CharType>::CalcLineRectImpl(
381     ut::Rect*   pRect,
382     StreamType* pStr,
383     int         length
384 )
385 {
386     NN_POINTER_ASSERT(pRect);
387     NN_POINTER_ASSERT(pStr);
388     NN_POINTER_ASSERT(*pStr);
389     NW_FONT_MIN_ASSERT(length, 0);
390 
391     const StreamType str            = *pStr;
392     const StreamType end            = str + length;
393     const bool bUseLimit            = m_WidthLimit < FLT_MAX;
394     PrintContext<CharType> context(this, str, 0, 0, 0);
395     f32 limitLeft                   = 0;
396     f32 limitRight                  = 0;
397     bool bCharSpace                 = false;
398     bool bOverLimit                 = false;
399     StreamType prevStreamPos        = NULL;
400     ut::Rect prevRect;
401 
402     /*
403         文字列の途中でエンコーディングが変わる事は想定していない
404     */
405     NN_POINTER_ASSERT(GetFont());
406     CharStrmReader reader = GetFont()->GetCharStrmReader(CharType(0));
407 
408     // 1行の高さにはLineSpaceを含めない。
409     f32 lineFeed = GetLineHeight() - GetLineSpace();
410 
411     pRect->left     = 0;
412     pRect->right    = 0;
413     pRect->top      = math::Min(0.0f, lineFeed);
414     pRect->bottom   = math::Max(0.0f, lineFeed);
415     prevRect = *pRect;
416 
417     reader.Set(str);
418     prevStreamPos = NULL;
419 
420     for (
421         CharCode code = reader.Next();
422         reinterpret_cast<StreamType>(reader.GetCurrentPos()) <= end;
423     )
424     {
425         if (code < ' ')
426         {
427             //---- 制御文字(タグの開始)
428 
429             typename TagProcessor::Operation operation;
430             ut::Rect rect(limitRight, 0, 0, 0);
431 
432             context.str = reinterpret_cast<StreamType>(reader.GetCurrentPos());
433             context.flags = 0;
434             context.flags |= bCharSpace ? 0: CONTEXT_NO_CHAR_SPACE;
435             SetCursorX(limitRight);
436 
437             //---- 折り返しの判定
438             if ( bUseLimit
439               && code != '\n'
440               && prevStreamPos != NULL
441             )
442             {
443                 PrintContext<CharType> context2 = context;
444                 TextWriterBase<CharType> myCopy = *this;
445                 ut::Rect rect2;
446 
447                 context2.writer = &myCopy;
448                 operation = m_TagProcessor->CalcRect(&rect2, code, &context2);
449 
450                 #if defined(NW_FONT_PROFILE)
451                     this->CopyProfileData(myCopy);
452                 #endif
453 
454                 if ( rect2.GetWidth() > 0.0f
455                   && (myCopy.GetCursorX() - context.xOrigin > m_WidthLimit)
456                 )
457                 {
458                     bOverLimit = true;
459                     code       = '\n';
460                     reader.Set(prevStreamPos);
461                     continue;
462                 }
463             }
464 
465             //---- タグ処理
466             operation = m_TagProcessor->CalcRect(&rect, code, &context);
467 
468             NN_POINTER_ASSERT(context.str);
469             reader.Set(context.str);
470 
471             pRect->left     = math::Min(pRect->left,      rect.left);
472             pRect->top      = math::Min(pRect->top,       rect.top);
473             pRect->right    = math::Max(pRect->right,     rect.right);
474             pRect->bottom   = math::Max(pRect->bottom,    rect.bottom);
475             limitRight = GetCursorX();
476 
477             if (operation == TagProcessor::OPERATION_END_DRAW)
478             {
479                 //---- 全部読み進んだ事にする
480                 *pStr += length;
481                 return false;
482             }
483             else if (operation == TagProcessor::OPERATION_NO_CHAR_SPACE)
484             {
485                 bCharSpace = false;
486             }
487             else if (operation == TagProcessor::OPERATION_CHAR_SPACE)
488             {
489                 bCharSpace = true;
490             }
491             else if (operation == TagProcessor::OPERATION_NEXT_LINE)
492             {
493                 break;
494             }
495         }
496         else
497         {
498             //---- 通常の文字
499 
500             f32 crntRight = limitRight;
501 
502             if (bCharSpace)
503             {
504                 crntRight += GetCharSpace();
505             }
506 
507             if (IsWidthFixed())
508             {
509                 crntRight += GetFixedWidth();
510             }
511             else
512             {
513                 crntRight += GetFont()->GetCharWidth(code) * GetScaleH();
514             }
515 
516             //---- 折り返しの判定
517             if (bUseLimit && prevStreamPos != NULL)
518             {
519                 f32 width = crntRight - limitLeft;
520                 if (width > m_WidthLimit)
521                 {
522                     bOverLimit = true;
523                     code       = '\n';
524                     reader.Set(prevStreamPos);
525                     continue;
526                 }
527             }
528 
529             limitRight = crntRight;
530             pRect->left  = math::Min(pRect->left,  limitRight);
531             pRect->right = math::Max(pRect->right, limitRight);
532             bCharSpace = true;
533         }
534 
535         if (bUseLimit)
536         {
537             prevStreamPos = reinterpret_cast<StreamType>(reader.GetCurrentPos());
538         }
539 
540         code = reader.Next();
541     }
542 
543 
544     *pStr = reinterpret_cast<StreamType>(reader.GetCurrentPos());
545 
546     return bOverLimit;
547 }
548 
549 template <typename CharType>
550 void
CalcStringRectImpl(ut::Rect * pRect,StreamType str,int length)551 TextWriterBase<CharType>::CalcStringRectImpl(
552     ut::Rect*   pRect,
553     StreamType  str,
554     int         length
555 )
556 {
557     NN_POINTER_ASSERT(pRect);
558     NN_POINTER_ASSERT(str);
559     NW_FONT_MIN_ASSERT(length, 0);
560 
561     const StreamType end = str + length;
562     int remain = length;
563     StreamType pos = str;
564 
565     pRect->left     = 0;
566     pRect->right    = 0;
567     pRect->top      = 0;
568     pRect->bottom   = 0;
569 
570     SetCursor(0, 0);
571 
572     do
573     {
574         ut::Rect rect;
575         CalcLineRectImpl(&rect, &pos, remain);
576         remain   = (end - pos);
577 
578         pRect->left     = math::Min(pRect->left,      rect.left);
579         pRect->top      = math::Min(pRect->top,       rect.top);
580         pRect->right    = math::Max(pRect->right,     rect.right);
581         pRect->bottom   = math::Max(pRect->bottom,    rect.bottom);
582     } while (remain > 0);
583 }
584 
585 template <typename CharType>
586 f32
PrintImpl(StreamType str,int length)587 TextWriterBase<CharType>::PrintImpl(
588     StreamType  str,
589     int         length
590 )
591 {
592     NN_POINTER_ASSERT(str);
593     NN_POINTER_ASSERT(GetFont());
594     NW_FONT_MIN_ASSERT(length, 0);
595 
596     f32 xOrigin    = GetCursorX();
597     f32 yOrigin    = GetCursorY();
598     f32 limitLeft  = 0;
599     f32 limitRight = 0;
600     const bool bUseLimit = m_WidthLimit < FLT_MAX;
601     const f32 orgCursorY = yOrigin;
602     bool bCharSpace  = false;
603     StreamType prevStreamPos = str;
604     StreamType prevNewLinePos = str;
605 
606     f32 textWidth  = AdjustCursor(&xOrigin, &yOrigin, str, length);
607     f32 yCursorAdj = orgCursorY - GetCursorY();
608 
609     PrintContext<CharType> context(this, str, xOrigin, yOrigin, 0);
610     CharStrmReader reader = GetFont()->GetCharStrmReader(CharType(0));
611     reader.Set(str);
612 
613     for (
614         CharCode code = reader.Next();
615         reinterpret_cast<StreamType>(reader.GetCurrentPos()) - str <= length;
616     )
617     {
618         if (code < ' ')
619         {
620             //---- 制御文字(タグの開始)
621 
622             typename TagProcessor::Operation operation;
623             context.str = reinterpret_cast<StreamType>(reader.GetCurrentPos());
624             context.flags = 0;
625             context.flags |= bCharSpace ? 0: CONTEXT_NO_CHAR_SPACE;
626 
627             //---- 折り返しの判定
628             if ( bUseLimit
629               && code != '\n'
630               && prevStreamPos != prevNewLinePos
631             )
632             {
633                 PrintContext<CharType> context2 = context;
634                 TextWriterBase<CharType> myCopy = *this;
635                 ut::Rect rect;
636 
637                 context2.writer = &myCopy;
638                 operation = m_TagProcessor->CalcRect(&rect, code, &context2);
639 
640                 #if defined(NW_FONT_PROFILE)
641                     this->CopyProfileData(myCopy);
642                 #endif
643 
644                 if ( rect.GetWidth() > 0.0f
645                   && myCopy.GetCursorX() - context.xOrigin > m_WidthLimit
646                 )
647                 {
648                     code = '\n';
649                     reader.Set(prevStreamPos);
650                     continue;
651                 }
652             }
653 
654             //---- タグ処理
655             operation = m_TagProcessor->Process(code, &context);
656             limitRight = GetCursorX() - xOrigin;
657 
658             if (operation == TagProcessor::OPERATION_NEXT_LINE)
659             {
660                 NN_POINTER_ASSERT(context.str);
661 
662                 //---- 次行描画開始位置Xの補正
663                 if (IsDrawFlagSet(HORIZONTAL_ALIGN_MASK, HORIZONTAL_ALIGN_CENTER))
664                 {
665                     const int   remain  = length - (context.str - str);
666                     const f32   width   = CalcLineWidth( context.str, remain );
667                     const f32   offset  = AdjustCenterValue(textWidth) - AdjustCenterValue(width);
668                     SetCursorX( context.xOrigin + offset );
669                 }
670                 else if (IsDrawFlagSet(HORIZONTAL_ALIGN_MASK, HORIZONTAL_ALIGN_RIGHT))
671                 {
672                     const int   remain  = length - (context.str - str);
673                     const f32   width   = CalcLineWidth( context.str, remain );
674                     const f32   offset  = textWidth - width;
675                     SetCursorX( context.xOrigin + offset );
676                 }
677                 else
678                 {
679                     //---- 最大幅の更新
680                     const f32 width = GetCursorX() - context.xOrigin;
681                     textWidth = math::Max(textWidth, width);
682 
683                     SetCursorX( context.xOrigin );
684                 }
685 
686                 if (bUseLimit)
687                 {
688                     prevNewLinePos = reinterpret_cast<StreamType>(reader.GetCurrentPos());
689                 }
690                 bCharSpace = false;
691             }
692             else if (operation == TagProcessor::OPERATION_NO_CHAR_SPACE)
693             {
694                 bCharSpace = false;
695             }
696             else if (operation == TagProcessor::OPERATION_CHAR_SPACE)
697             {
698                 bCharSpace = true;
699             }
700             else if (operation == TagProcessor::OPERATION_END_DRAW)
701             {
702                 break;
703             }
704 
705             NN_POINTER_ASSERT(context.str);
706             reader.Set(context.str);
707         }
708         else
709         {
710             //---- 通常の文字
711 
712             const f32 baseY = GetCursorY();
713 
714             f32 crntRight = limitRight;
715 
716             if (bCharSpace)
717             {
718                 crntRight += GetCharSpace();
719             }
720 
721             if (IsWidthFixed())
722             {
723                 crntRight += GetFixedWidth();
724             }
725             else
726             {
727                 crntRight += GetFont()->GetCharWidth(code) * GetScaleH();
728             }
729 
730             //---- 折り返しの判定
731             if (bUseLimit && prevStreamPos != prevNewLinePos)
732             {
733                 f32 width = crntRight - limitLeft;
734                 if (width > m_WidthLimit)
735                 {
736                     code = '\n';
737                     reader.Set(prevStreamPos);
738                     continue;
739                 }
740             }
741 
742             limitRight = crntRight;
743 
744 
745             if (bCharSpace)
746             {
747                 MoveCursorX( GetCharSpace() );
748             }
749             bCharSpace = true;
750 
751 
752             //---- カーソルはベースラインにあるのでセル上端へ移動する
753             {
754                 const Font* pFont = GetFont();
755                 const f32 adj = - pFont->GetBaselinePos() * GetScaleV();
756                 MoveCursorY( adj );
757             }
758 
759             Print(code);
760 
761             // 戻す
762             SetCursorY( baseY );
763         }
764 
765         if (bUseLimit)
766         {
767             prevStreamPos = reinterpret_cast<StreamType>(reader.GetCurrentPos());
768         }
769 
770         code = reader.Next();
771     }
772 
773     //---- 最大幅の更新
774     {
775         const f32 width = GetCursorX() - context.xOrigin;
776         textWidth = math::Max(textWidth, width);
777     }
778 
779     //---- カーソル位置Yを描画フラグに従って移動
780     // AdjustCursorでベースライン上に移動したカーソル位置を元に戻す
781     if ( IsDrawFlagSet(VERTICAL_ORIGIN_MASK, VERTICAL_ORIGIN_MIDDLE)
782       || IsDrawFlagSet(VERTICAL_ORIGIN_MASK, VERTICAL_ORIGIN_BOTTOM)
783     )
784     {
785         SetCursorY(orgCursorY);
786     }
787     else
788     {
789         MoveCursorY(yCursorAdj);
790     }
791 
792     return textWidth;
793 }
794 
795 template <typename CharType>
796 f32
AdjustCursor(f32 * pXOrigin,f32 * pYOrigin,StreamType str,int length)797 TextWriterBase<CharType>::AdjustCursor(
798     f32*        pXOrigin,
799     f32*        pYOrigin,
800     StreamType  str,
801     int         length
802 )
803 {
804     f32 textWidth  = 0;
805     f32 textHeight = 0;
806 
807     {
808         u32 flagMask  = HORIZONTAL_ALIGN_MASK | HORIZONTAL_ORIGIN_MASK | VERTICAL_ORIGIN_MASK;
809         u32 blineFlag = HORIZONTAL_ALIGN_LEFT | HORIZONTAL_ORIGIN_LEFT | VERTICAL_ORIGIN_BASELINE;
810         u32 topFlag   = HORIZONTAL_ALIGN_LEFT | HORIZONTAL_ORIGIN_LEFT | VERTICAL_ORIGIN_TOP;
811 
812         if ( ! IsDrawFlagSet(flagMask, blineFlag)
813           && ! IsDrawFlagSet(flagMask, topFlag)
814         )
815         {
816             ut::Rect textRect;
817             CalcStringRect(&textRect, str, length);
818             textWidth  = textRect.left + textRect.right;
819             textHeight = textRect.top  + textRect.bottom;
820         }
821     }
822 
823     //---- 描画開始位置Xの補正
824     // 各々の位置から文字列の左端に統一
825     if (IsDrawFlagSet(HORIZONTAL_ORIGIN_MASK, HORIZONTAL_ORIGIN_CENTER))
826     {
827         *pXOrigin -= AdjustCenterValue(textWidth);
828     }
829     else if (IsDrawFlagSet(HORIZONTAL_ORIGIN_MASK, HORIZONTAL_ORIGIN_RIGHT))
830     {
831         *pXOrigin -= textWidth;
832     }
833 
834     //---- 描画開始位置Yの補正
835     // 各々の位置から 1 行目のアセンダラインに統一
836     if (IsDrawFlagSet(VERTICAL_ORIGIN_MASK, VERTICAL_ORIGIN_MIDDLE))
837     {
838         *pYOrigin -= AdjustCenterValue(textHeight);
839     }
840     else if (IsDrawFlagSet(VERTICAL_ORIGIN_MASK, VERTICAL_ORIGIN_BOTTOM))
841     {
842         *pYOrigin -= textHeight;
843     }
844 
845     //---- 1行目描画開始位置Xの補正
846     // 文字列の左端からそれぞれの寄せ位置へカーソルを移動
847     if (IsDrawFlagSet(HORIZONTAL_ALIGN_MASK, HORIZONTAL_ALIGN_CENTER))
848     {
849         const f32 width = CalcLineWidth(str, length);
850         const f32 offset = AdjustCenterValue(textWidth) - AdjustCenterValue(width);
851         SetCursorX( *pXOrigin + offset );
852     }
853     else if (IsDrawFlagSet(HORIZONTAL_ALIGN_MASK, HORIZONTAL_ALIGN_RIGHT))
854     {
855         const f32 width = CalcLineWidth(str, length);
856         const f32 offset = textWidth - width;
857         SetCursorX( *pXOrigin + offset );
858     }
859     else
860     {
861         SetCursorX( *pXOrigin );
862     }
863 
864     //---- 1行目描画開始位置Yの補正
865     // 1 行目のベースライン位置にカーソルを移動
866     if (IsDrawFlagSet(VERTICAL_ORIGIN_MASK, VERTICAL_ORIGIN_BASELINE))
867     {
868         // pYOrigin はベースラインであるのでそのままセット
869         SetCursorY( *pYOrigin );
870     }
871     else
872     {
873         // pYOrigin はアセンダラインであるのでベースラインにカーソルを移動
874         SetCursorY( *pYOrigin + GetFontAscent() );
875     }
876 
877     return textWidth;
878 }
879 
880 
881 #if defined(NW_FONT_PROFILE)
882 template <typename CharType>
883 void
PrintProfile()884 TextWriterBase<CharType>::PrintProfile()
885 {
886     using namespace nn::fnd;
887 
888     CharWriter::PrintProfile();
889 
890     TimeSpan timeSpan = m_PrintTextSw.GetElapsedTime();
891     NN_LOG("TextWriter Print time %d micros, count %d.\n", (int)timeSpan.GetMilliSeconds(), m_PrintTextCount);
892 }
893 
894 template <typename CharType>
895 void
CopyProfileData(const TextWriterBase<CharType> & other) const896 TextWriterBase<CharType>::CopyProfileData(const TextWriterBase<CharType>& other) const
897 {
898     CharWriter::CopyProfileData(other);
899 
900     m_PrintTextSw       = other.m_PrintTextSw;
901     m_PrintTextCount    = other.m_PrintTextCount;
902 }
903 #endif
904 
905 
906 /* =======================================================================
907         明示的実体化
908    ======================================================================== */
909 
910 template class TagProcessorBase<char>;
911 template class TagProcessorBase<wchar_t>;
912 template class TextWriterBase<char>;
913 template class TextWriterBase<wchar_t>;
914 
915 
916 
917 }   // namespace font
918 }   // namespace nw
919 
920