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