0026780: Coding rules - eliminate warnings on Linux and Mac
[occt.git] / src / Font / Font_TextFormatter.cxx
1 // Created on: 2013-01-29
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Font_TextFormatter.hxx>
17
18 namespace
19 {
20   typedef NCollection_Vec2<Standard_ShortReal> Vec2f;
21
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)
27   {
28     for(; theCharLower <= theCharUpper; ++theCharLower)
29     {
30       theCorners.ChangeValue (theCharLower) += theMoveVec;
31     }
32   }
33
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)
39   {
40     for(; theCharLower <= theCharUpper; ++theCharLower)
41     {
42       theCorners.ChangeValue (theCharLower).y() += theMoveVec;
43     }
44   }
45
46 }
47
48 // =======================================================================
49 // function : Font_TextFormatter
50 // purpose  :
51 // =======================================================================
52 Font_TextFormatter::Font_TextFormatter()
53 : myAlignX (Graphic3d_HTA_LEFT),
54   myAlignY (Graphic3d_VTA_TOP),
55   myTabSize (8),
56   //
57   myPen (0.0f, 0.0f),
58   myRectsNb (0),
59   myLineSpacing (0.0f),
60   myAscender (0.0f),
61   myIsFormatted (false),
62   //
63   myLinesNb (0),
64   myRectLineStart (0),
65   myRectWordStart (0),
66   myNewLineNb(0),
67   myPenCurrLine (0.0f),
68   myBndTop   (0.0f),
69   myBndWidth (0.0f),
70   myMoveVec (0.0f, 0.0f)
71 {
72   //
73 }
74
75 // =======================================================================
76 // function : SetupAlignment
77 // purpose  :
78 // =======================================================================
79 void Font_TextFormatter::SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
80                                          const Graphic3d_VerticalTextAlignment   theAlignY)
81 {
82   myAlignX = theAlignX;
83   myAlignY = theAlignY;
84 }
85
86 // =======================================================================
87 // function : Reset
88 // purpose  :
89 // =======================================================================
90 void Font_TextFormatter::Reset()
91 {
92   myIsFormatted = false;
93   myString.Clear();
94   myPen.x() = myPen.y() = 0.0f;
95   myRectsNb = 0;
96   myLineSpacing = myAscender = 0.0f;
97   myCorners.Clear();
98   myNewLines.Clear();
99 }
100
101 // =======================================================================
102 // function : Append
103 // purpose  :
104 // =======================================================================
105 void Font_TextFormatter::Append (const NCollection_String& theString,
106                                  Font_FTFont&              theFont)
107 {
108   if (theString.IsEmpty())
109   {
110     return;
111   }
112
113   myAscender    = Max (myAscender,    theFont.Ascender());
114   myLineSpacing = Max (myLineSpacing, theFont.LineSpacing());
115   myString     += theString;
116
117   int aSymbolsCounter = 0; // special counter to process tabulation symbols
118
119   // first pass - render all symbols using associated font on single ZERO baseline
120   for (NCollection_Utf8Iter anIter = theString.Iterator(); *anIter != 0;)
121   {
122     const Standard_Utf32Char aCharThis =   *anIter;
123     const Standard_Utf32Char aCharNext = *++anIter;
124
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)
130     {
131       continue; // skip unsupported carriage control codes
132     }
133     else if (aCharThis == '\x0A') // LF (line feed, new line)
134     {
135       aSymbolsCounter = 0;
136       myNewLines.Append (myPen.x());
137       continue; // will be processed on second pass
138     }
139     else if (aCharThis == ' ')
140     {
141       ++aSymbolsCounter;
142       myPen.x() += theFont.AdvanceX (' ', aCharNext);
143       continue;
144     }
145     else if (aCharThis == '\t')
146     {
147       const Standard_Integer aSpacesNum = (myTabSize - (aSymbolsCounter - 1) % myTabSize);
148       myPen.x() += theFont.AdvanceX (' ', aCharNext) * Standard_ShortReal(aSpacesNum);
149       aSymbolsCounter += aSpacesNum;
150       continue;
151     }
152
153     ++aSymbolsCounter;
154
155     myCorners.Append (myPen);
156
157     myPen.x() += theFont.AdvanceX (aCharThis, aCharNext);
158
159     ++myRectsNb;
160   }
161 }
162
163 // =======================================================================
164 // function : newLine
165 // purpose  :
166 // =======================================================================
167 void Font_TextFormatter::newLine (const Standard_Integer theLastRect)
168 {
169   if (myRectLineStart >= myRectsNb)
170   {
171     ++myLinesNb;
172     myPenCurrLine -= myLineSpacing;
173     return;
174   }
175
176   myMoveVec.y() = myPenCurrLine;
177   switch (myAlignX)
178   {
179     default:
180     case Graphic3d_HTA_LEFT:
181     {
182       myMoveVec.x() = (myNewLineNb > 0) ? -myNewLines.Value (myNewLineNb - 1) : 0.0f;
183       break;
184     }
185     case Graphic3d_HTA_RIGHT:
186     {
187       myMoveVec.x() = (myNewLineNb < myNewLines.Length())
188                     ? -myNewLines.Value (myNewLineNb)
189                     : -myPen.x();
190       break;
191     }
192     case Graphic3d_HTA_CENTER:
193     {
194       const Standard_ShortReal aFrom = (myNewLineNb > 0)
195                                      ? myNewLines.Value (myNewLineNb - 1)
196                                      : 0.0f;
197       const Standard_ShortReal aTo   = (myNewLineNb < myNewLines.Length())
198                                      ? myNewLines.Value (myNewLineNb)
199                                      : myPen.x();
200       myMoveVec.x() = -0.5f * (aFrom + aTo);
201       break;
202     }
203   }
204
205   move (myCorners, myMoveVec, myRectLineStart, theLastRect);
206
207   ++myLinesNb;
208   myPenCurrLine -= myLineSpacing;
209   myRectLineStart = myRectWordStart = theLastRect + 1;
210 }
211
212 // =======================================================================
213 // function : Format
214 // purpose  :
215 // =======================================================================
216 void Font_TextFormatter::Format()
217 {
218   if (myRectsNb == 0 || myIsFormatted)
219   {
220     return;
221   }
222
223   myIsFormatted = true;
224   myLinesNb = myRectLineStart = myRectWordStart = 0;
225   myBndTop     = 0.0f;
226   myBndWidth   = 0.0f;
227   myMoveVec.x() = myMoveVec.y() = 0.0f;
228
229   // split text into lines and apply horizontal alignment
230   myPenCurrLine = -myAscender;
231   Standard_Integer aRectIter = 0;
232   myNewLineNb = 0;
233   Standard_ShortReal aMaxLineWidth = -1.0f;
234   for (NCollection_Utf8Iter anIter = myString.Iterator(); *anIter != 0; ++anIter)
235   {
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)
242     {
243       continue; // skip unsupported carriage control codes
244     }
245     else if (aCharThis == '\x0A') // LF (line feed, new line)
246     {
247       // calculate max line width
248       if (myNewLineNb == 0)
249       {
250         aMaxLineWidth = myNewLines.Value(0);
251       }
252       else
253       {
254         aMaxLineWidth = Max (aMaxLineWidth, myNewLines.Value (myNewLineNb) - myNewLines.Value (myNewLineNb - 1));
255       }
256
257       const Standard_Integer aLastRect = aRectIter - 1; // last rect on current line
258       newLine (aLastRect);
259       ++myNewLineNb;
260       continue;
261     }
262     else if (aCharThis == ' '
263           || aCharThis == '\t')
264     {
265       myRectWordStart = aRectIter;
266       continue;
267     }
268
269     ++aRectIter;
270   }
271
272   // If only one line
273   if (aMaxLineWidth < 0.0f)
274   {
275     aMaxLineWidth = myPen.x();
276   }
277   else // Consider last line
278   {
279     aMaxLineWidth = Max (aMaxLineWidth, myPen.x() - myNewLines.Value (myNewLineNb - 1));
280   }
281
282   myBndWidth = aMaxLineWidth;
283
284   // move last line
285   newLine (myRectsNb - 1);
286
287   // apply vertical alignment style
288   if (myAlignY == Graphic3d_VTA_BOTTOM)
289   {
290     myBndTop = -myLineSpacing - myPenCurrLine;
291   }
292   else if (myAlignY == Graphic3d_VTA_CENTER)
293   {
294     myBndTop = 0.5f * (myLineSpacing * Standard_ShortReal(myLinesNb));
295   }
296   else if (myAlignY == Graphic3d_VTA_TOPFIRSTLINE)
297   {
298     myBndTop = myAscender;
299   }
300
301   if (myAlignY != Graphic3d_VTA_TOP)
302   {
303     moveY (myCorners, myBndTop, 0, myRectsNb - 1);
304   }
305 }