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;
46 //! Apply floor to vector components.
47 //! @param theVec - vector to change (by reference!)
48 //! @return modified vector
49 inline Vec2f& floor (Vec2f& theVec)
51 theVec.x() = std::floor (theVec.x());
52 theVec.y() = std::floor (theVec.y());
58 // =======================================================================
59 // function : Font_TextFormatter
61 // =======================================================================
62 Font_TextFormatter::Font_TextFormatter()
63 : myAlignX (Graphic3d_HTA_LEFT),
64 myAlignY (Graphic3d_VTA_TOP),
71 myIsFormatted (false),
80 myMoveVec (0.0f, 0.0f)
85 // =======================================================================
86 // function : SetupAlignment
88 // =======================================================================
89 void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
90 const Graphic3d_VerticalTextAlignment theAlignY)
96 // =======================================================================
99 // =======================================================================
100 void Font_TextFormatter::Reset()
102 myIsFormatted = false;
104 myPen.x() = myPen.y() = 0.0f;
106 myLineSpacing = myAscender = 0.0f;
111 // =======================================================================
114 // =======================================================================
115 void Font_TextFormatter::Append (const NCollection_String& theString,
116 Font_FTFont& theFont)
118 if (theString.IsEmpty())
123 myAscender = Max (myAscender, theFont.Ascender());
124 myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
125 myString += theString;
127 int aSymbolsCounter = 0; // special counter to process tabulation symbols
129 // first pass - render all symbols using associated font on single ZERO baseline
130 for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
132 const Standard_Utf32Char aCharThis = *anIter;
133 const Standard_Utf32Char aCharNext = *++anIter;
135 if (aCharThis == '\x0D' // CR (carriage return)
136 || aCharThis == '\a' // BEL (alarm)
137 || aCharThis == '\f' // FF (form feed) NP (new page)
138 || aCharThis == '\b' // BS (backspace)
139 || aCharThis == '\v') // VT (vertical tab)
141 continue; // skip unsupported carriage control codes
143 else if (aCharThis == '\x0A') // LF (line feed, new line)
146 myNewLines.Append (myPen.x());
147 continue; // will be processed on second pass
149 else if (aCharThis == ' ')
152 myPen.x() += theFont.AdvanceX (' ', aCharNext);
155 else if (aCharThis == '\t')
157 const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
158 myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
159 aSymbolsCounter += aSpacesNum;
165 myCorners.Append (myPen);
167 myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
173 // =======================================================================
174 // function : newLine
176 // =======================================================================
177 void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
179 if (myRectLineStart >= myRectsNb)
182 myPenCurrLine -= myLineSpacing;
186 myMoveVec.y() = myPenCurrLine;
190 case Graphic3d_HTA_LEFT:
192 myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
195 case Graphic3d_HTA_RIGHT:
197 myMoveVec.x() = (myNewLineNb < myNewLines.Length())
198 ? -myNewLines.Value (myNewLineNb)
202 case Graphic3d_HTA_CENTER:
204 const Standard_ShortReal aFrom = (myNewLineNb > 0)
205 ? myNewLines.Value (myNewLineNb - 1)
207 const Standard_ShortReal aTo = (myNewLineNb < myNewLines.Length())
208 ? myNewLines.Value (myNewLineNb)
210 myMoveVec.x() = -0.5f * (aFrom + aTo);
215 move (myCorners, myMoveVec, myRectLineStart, theLastRect);
218 myPenCurrLine -= myLineSpacing;
219 myRectLineStart = myRectWordStart = theLastRect + 1;
222 // =======================================================================
225 // =======================================================================
226 void Font_TextFormatter::Format()
228 if (myRectsNb == 0 || myIsFormatted)
233 myIsFormatted = true;
234 myLinesNb = myRectLineStart = myRectWordStart = 0;
237 myMoveVec.x() = myMoveVec.y() = 0.0f;
239 // split text into lines and apply horizontal alignment
240 myPenCurrLine = -myAscender;
241 Standard_Integer aRectIter = 0;
243 Standard_ShortReal aMaxLineWidth = -1.0f;
244 for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
246 const Standard_Utf32Char aCharThis = *anIter;
247 if (aCharThis == '\x0D' // CR (carriage return)
248 || aCharThis == '\a' // BEL (alarm)
249 || aCharThis == '\f' // FF (form feed) NP (new page)
250 || aCharThis == '\b' // BS (backspace)
251 || aCharThis == '\v') // VT (vertical tab)
253 continue; // skip unsupported carriage control codes
255 else if (aCharThis == '\x0A') // LF (line feed, new line)
257 // calculate max line width
258 if (myNewLineNb == 0)
260 aMaxLineWidth = myNewLines.Value(0);
264 aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
267 const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
272 else if (aCharThis == ' '
273 || aCharThis == '\t')
275 myRectWordStart = aRectIter;
283 if (aMaxLineWidth < 0.0f)
285 aMaxLineWidth = myPen.x();
287 else // Consider last line
289 aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1));
292 myBndWidth = aMaxLineWidth;
295 newLine (myRectsNb - 1);
297 // apply vertical alignment style
298 if (myAlignY == Graphic3d_VTA_BOTTOM)
300 myBndTop = -myLineSpacing - myPenCurrLine;
301 moveY (myCorners, myBndTop, 0, myRectsNb - 1);
303 else if (myAlignY == Graphic3d_VTA_CENTER)
305 myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
306 moveY (myCorners, myBndTop, 0, myRectsNb - 1);