1 // Created on: 2013-01-29
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Font_TextFormatter.hxx>
20 typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
22 //! Auxiliary function to translate corners by the vector.
23 inline void move (NCollection_Vector< Vec2f >& theCorners,
24 const Vec2f& theMoveVec,
25 Standard_Integer theCharLower,
26 const Standard_Integer theCharUpper)
28 for(; theCharLower <= theCharUpper; ++theCharLower)
30 theCorners.ChangeValue (theCharLower) += theMoveVec;
34 //! Auxiliary function to translate corners in vertical direction.
35 inline void moveY (NCollection_Vector<Vec2f>& theCorners,
36 const Standard_ShortReal theMoveVec,
37 Standard_Integer theCharLower,
38 const Standard_Integer theCharUpper)
40 for(; theCharLower <= theCharUpper; ++theCharLower)
42 theCorners.ChangeValue (theCharLower).y() += theMoveVec;
48 // =======================================================================
49 // function : Font_TextFormatter
51 // =======================================================================
52 Font_TextFormatter::Font_TextFormatter()
53 : myAlignX (Graphic3d_HTA_LEFT),
54 myAlignY (Graphic3d_VTA_TOP),
61 myIsFormatted (false),
70 myMoveVec (0.0f, 0.0f)
75 // =======================================================================
76 // function : SetupAlignment
78 // =======================================================================
79 void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
80 const Graphic3d_VerticalTextAlignment theAlignY)
86 // =======================================================================
89 // =======================================================================
90 void Font_TextFormatter::Reset()
92 myIsFormatted = false;
94 myPen.x() = myPen.y() = 0.0f;
96 myLineSpacing = myAscender = 0.0f;
101 // =======================================================================
104 // =======================================================================
105 void Font_TextFormatter::Append (const NCollection_String& theString,
106 Font_FTFont& theFont)
108 if (theString.IsEmpty())
113 myAscender = Max (myAscender, theFont.Ascender());
114 myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
115 myString += theString;
117 int aSymbolsCounter = 0; // special counter to process tabulation symbols
119 // first pass - render all symbols using associated font on single ZERO baseline
120 for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
122 const Standard_Utf32Char aCharThis = *anIter;
123 const Standard_Utf32Char aCharNext = *++anIter;
125 if (aCharThis == '\x0D' // CR (carriage return)
126 || aCharThis == '\a' // BEL (alarm)
127 || aCharThis == '\f' // FF (form feed) NP (new page)
128 || aCharThis == '\b' // BS (backspace)
129 || aCharThis == '\v') // VT (vertical tab)
131 continue; // skip unsupported carriage control codes
133 else if (aCharThis == '\x0A') // LF (line feed, new line)
136 myNewLines.Append (myPen.x());
137 continue; // will be processed on second pass
139 else if (aCharThis == ' ')
142 myPen.x() += theFont.AdvanceX (' ', aCharNext);
145 else if (aCharThis == '\t')
147 const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
148 myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
149 aSymbolsCounter += aSpacesNum;
155 myCorners.Append (myPen);
157 myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
163 // =======================================================================
164 // function : newLine
166 // =======================================================================
167 void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
169 if (myRectLineStart >= myRectsNb)
172 myPenCurrLine -= myLineSpacing;
176 myMoveVec.y() = myPenCurrLine;
180 case Graphic3d_HTA_LEFT:
182 myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
185 case Graphic3d_HTA_RIGHT:
187 myMoveVec.x() = (myNewLineNb < myNewLines.Length())
188 ? -myNewLines.Value (myNewLineNb)
192 case Graphic3d_HTA_CENTER:
194 const Standard_ShortReal aFrom = (myNewLineNb > 0)
195 ? myNewLines.Value (myNewLineNb - 1)
197 const Standard_ShortReal aTo = (myNewLineNb < myNewLines.Length())
198 ? myNewLines.Value (myNewLineNb)
200 myMoveVec.x() = -0.5f * (aFrom + aTo);
205 move (myCorners, myMoveVec, myRectLineStart, theLastRect);
208 myPenCurrLine -= myLineSpacing;
209 myRectLineStart = myRectWordStart = theLastRect + 1;
212 // =======================================================================
215 // =======================================================================
216 void Font_TextFormatter::Format()
218 if (myRectsNb == 0 || myIsFormatted)
223 myIsFormatted = true;
224 myLinesNb = myRectLineStart = myRectWordStart = 0;
227 myMoveVec.x() = myMoveVec.y() = 0.0f;
229 // split text into lines and apply horizontal alignment
230 myPenCurrLine = -myAscender;
231 Standard_Integer aRectIter = 0;
233 Standard_ShortReal aMaxLineWidth = -1.0f;
234 for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
236 const Standard_Utf32Char aCharThis = *anIter;
237 if (aCharThis == '\x0D' // CR (carriage return)
238 || aCharThis == '\a' // BEL (alarm)
239 || aCharThis == '\f' // FF (form feed) NP (new page)
240 || aCharThis == '\b' // BS (backspace)
241 || aCharThis == '\v') // VT (vertical tab)
243 continue; // skip unsupported carriage control codes
245 else if (aCharThis == '\x0A') // LF (line feed, new line)
247 // calculate max line width
248 if (myNewLineNb == 0)
250 aMaxLineWidth = myNewLines.Value(0);
254 aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
257 const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
262 else if (aCharThis == ' '
263 || aCharThis == '\t')
265 myRectWordStart = aRectIter;
273 if (aMaxLineWidth < 0.0f)
275 aMaxLineWidth = myPen.x();
277 else // Consider last line
279 aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1));
282 myBndWidth = aMaxLineWidth;
285 newLine (myRectsNb - 1);
287 // apply vertical alignment style
288 if (myAlignY == Graphic3d_VTA_BOTTOM)
290 myBndTop = -myLineSpacing - myPenCurrLine;
292 else if (myAlignY == Graphic3d_VTA_CENTER)
294 myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
296 else if (myAlignY == Graphic3d_VTA_TOPFIRSTLINE)
298 myBndTop = myAscender;
301 if (myAlignY != Graphic3d_VTA_TOP)
303 moveY (myCorners, myBndTop, 0, myRectsNb - 1);