0031875: Draw Harness, ViewerTest - command vaspects -mostContinuity lacks g1 and...
[occt.git] / src / Font / Font_TextFormatter.hxx
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 #ifndef Font_TextFormatter_Header
17 #define Font_TextFormatter_Header
18
19 #include <Font_Rect.hxx>
20 #include <Graphic3d_HorizontalTextAlignment.hxx>
21 #include <Graphic3d_VerticalTextAlignment.hxx>
22 #include <NCollection_DataMap.hxx>
23 #include <NCollection_Vector.hxx>
24 #include <NCollection_String.hxx>
25
26 class Font_FTFont;
27
28 DEFINE_STANDARD_HANDLE(Font_TextFormatter, Standard_Transient)
29
30 //! This class is intended to prepare formatted text by using:<br>
31 //! - font to string combination,<br>
32 //! - alignment,<br>
33 //! - wrapping.<br>
34 //!
35 //! After text formatting, each symbol of formatted text is placed in some position.
36 //! Further work with the formatter is using an iterator.
37 //! The iterator gives an access to each symbol inside the initial row.
38 //! Also it's possible to get only significant/writable symbols of the text.<br>
39 //! Formatter gives an access to geometrical position of a symbol by the symbol index in the text.<br>
40 //! Example of correspondence of some text symbol to an index in "row_1\n\nrow_2\n":<br>
41 //! "row_1\n"  - 0-5 indices;<br>
42 //! "\n"       - 6 index;<br>
43 //! "\n"       - 7 index;<br>
44 //! "row_2\n"  - 8-13 indices.<br>
45 //! Pay attention that fonts should have the same LineSpacing value for correct formatting.<br>
46 //! Example of the formatter using:
47 //! @code
48 //!   Handle(Font_TextFormatter) aFormatter = new Font_TextFormatter();
49 //!   aFormatter->Append(text_1, aFont1);
50 //!   aFormatter->Append(text_2, aFont2);
51 //!   // setting of additional properties such as wrapping or alignment
52 //!   aFormatter->Format();
53 //! @endcode
54 class Font_TextFormatter : public Standard_Transient
55 {
56 public:
57   //! Iteration filter flags. Command symbols are skipped with any filter.
58   enum IterationFilter
59   {
60     IterationFilter_None             = 0x0000, //!< no filter
61     IterationFilter_ExcludeInvisible = 0x0002, //!< exclude ' ', '\t', '\n'
62   };
63
64   //! Iterator through formatted symbols.
65   //! It's possible to filter returned symbols to have only significant ones.
66   class Iterator
67   {
68   public:
69     //! Constructor with initialization.
70     Iterator (const Font_TextFormatter& theFormatter,
71               IterationFilter theFilter = IterationFilter_None)
72     : myFilter (theFilter), myIter (theFormatter.myString.Iterator()), mySymbolChar (0), mySymbolCharNext (0)
73     {
74       mySymbolPosition = readNextSymbol (-1, mySymbolChar);
75       mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
76     }
77
78     //! Returns TRUE if iterator points to a valid item.
79     Standard_Boolean More() const { return mySymbolPosition >= 0; }
80
81     //! Returns TRUE if next item exists
82     Standard_Boolean HasNext() const { return mySymbolNext >= 0; }
83
84     //! Returns current symbol.
85     Standard_Utf32Char Symbol() const { return mySymbolChar; }
86
87     //! Returns the next symbol if exists.
88     Standard_Utf32Char SymbolNext() const { return mySymbolCharNext; }
89
90     //! Returns current symbol position.
91     Standard_Integer SymbolPosition() const { return mySymbolPosition; }
92
93     //! Returns the next symbol position.
94     Standard_Integer SymbolPositionNext() const { return mySymbolNext; }
95
96     //! Moves to the next item.
97     void Next()
98     {
99       mySymbolPosition = mySymbolNext;
100       mySymbolChar = mySymbolCharNext;
101       mySymbolNext = readNextSymbol (mySymbolPosition, mySymbolCharNext);
102     }
103
104   protected:
105     //! Finds index of the next symbol
106     Standard_Integer readNextSymbol (const Standard_Integer theSymbolStartingFrom,
107                                      Standard_Utf32Char& theSymbolChar)
108     {
109       Standard_Integer aNextSymbol = theSymbolStartingFrom;
110       for (; *myIter != 0; ++myIter)
111       {
112         const Standard_Utf32Char aCharCurr = *myIter;
113         if (Font_TextFormatter::IsCommandSymbol (aCharCurr))
114         {
115           continue; // skip unsupported carriage control codes
116         }
117         aNextSymbol++;
118         if ((myFilter & IterationFilter_ExcludeInvisible) != 0)
119         {
120           if (aCharCurr == '\x0A'|| // LF (line feed, new line)
121               aCharCurr == ' ' ||
122               aCharCurr == '\t')
123           {
124             continue;
125           }
126         }
127         ++myIter;
128         theSymbolChar = aCharCurr;
129         return aNextSymbol; // found the first next, not command and not filtered symbol
130       }
131       return -1; // the next symbol is not found
132     }
133
134   protected:
135     IterationFilter      myFilter; //!< possibility to filter not-necessary symbols
136     NCollection_Utf8Iter myIter; //!< the next symbol iterator value over the text formatter string
137     Standard_Integer     mySymbolPosition; //!< the current position
138     Standard_Utf32Char   mySymbolChar; //!< the current symbol
139     Standard_Integer     mySymbolNext; //!< position of the next symbol in iterator, if zero, the iterator is finished
140     Standard_Utf32Char   mySymbolCharNext; //!< the current symbol
141   };
142
143   //! Default constructor.
144   Standard_EXPORT Font_TextFormatter();
145
146   //! Setup alignment style.
147   Standard_EXPORT void SetupAlignment (const Graphic3d_HorizontalTextAlignment theAlignX,
148                                        const Graphic3d_VerticalTextAlignment   theAlignY);
149
150   //! Reset current progress.
151   Standard_EXPORT void Reset();
152
153   //! Render specified text to inner buffer.
154   Standard_EXPORT void Append (const NCollection_String& theString,
155                                Font_FTFont&              theFont);
156
157   //! Perform formatting on the buffered text.
158   //! Should not be called more than once after initialization!
159   Standard_EXPORT void Format();
160
161   Standard_DEPRECATED("BottomLeft should be used instead")
162   const NCollection_Vec2<Standard_ShortReal>& TopLeft (const Standard_Integer theIndex) const
163   {
164     return BottomLeft (theIndex);
165   }
166
167   //! Returns specific glyph rectangle.
168   const NCollection_Vec2<Standard_ShortReal>& BottomLeft (const Standard_Integer theIndex) const
169   { return myCorners.Value (theIndex); }
170
171   //! Returns current rendering string.
172   inline const NCollection_String& String() const
173   {
174     return myString;
175   }
176
177   //! Returns symbol bounding box
178   //! @param bounding box.
179   Standard_EXPORT Standard_Boolean GlyphBoundingBox (const Standard_Integer theIndex,
180                                                      Font_Rect& theBndBox) const;
181
182   //! Returns the line height
183   //! @param theIndex a line index, obtained by LineIndex()
184   Standard_ShortReal LineHeight (const Standard_Integer theIndex) const
185   { return theIndex == 0 ? myAscender : myLineSpacing; }
186
187   //! Returns width of a line
188   Standard_EXPORT Standard_ShortReal LineWidth (const Standard_Integer theIndex) const;
189
190   //! Returns true if the symbol by the index is '\n'. The width of the symbol is zero.
191   Standard_EXPORT Standard_Boolean IsLFSymbol (const Standard_Integer theIndex) const;
192
193   //! Returns position of the first symbol in a line using alignment
194   Standard_EXPORT Standard_ShortReal FirstPosition() const;
195
196   //! Returns column index of the corner index in the current line
197   Standard_EXPORT Standard_Integer LinePositionIndex (const Standard_Integer theIndex) const;
198
199   //! Returns row index of the corner index among text lines
200   Standard_EXPORT Standard_Integer LineIndex (const Standard_Integer theIndex) const;
201
202   //! Returns tab size.
203   inline Standard_Integer TabSize() const
204   {
205     return myTabSize;
206   }
207
208   //! Returns horizontal alignment style
209   Graphic3d_HorizontalTextAlignment HorizontalTextAlignment() const { return myAlignX; }
210
211   //! Returns vertical   alignment style
212   Graphic3d_VerticalTextAlignment VerticalTextAlignment() const { return myAlignY; }
213
214   //! Sets text wrapping width, zero means that the text is not bounded by width
215   void SetWrapping (const Standard_ShortReal theWidth) { myWrappingWidth = theWidth; }
216
217   //! Returns text maximum width, zero means that the text is not bounded by width
218   Standard_Boolean HasWrapping() const { return myWrappingWidth > 0; }
219
220   //! Returns text maximum width, zero means that the text is not bounded by width
221   Standard_ShortReal Wrapping() const { return myWrappingWidth; }
222
223   //! @return width of formatted text.
224   inline Standard_ShortReal ResultWidth() const
225   {
226     return myBndWidth;
227   }
228
229   //! @return height of formatted text.
230   inline Standard_ShortReal ResultHeight() const
231   {
232     return myLineSpacing * Standard_ShortReal(myLinesNb);
233   }
234
235   //! @return maximum width of the text symbol
236   Standard_ShortReal MaximumSymbolWidth() const { return myMaxSymbolWidth; }
237
238   //! @param bounding box.
239   inline void BndBox (Font_Rect& theBndBox) const
240   {
241     theBndBox.Left = 0.0f;
242     switch (myAlignX)
243     {
244       default:
245       case Graphic3d_HTA_LEFT:  theBndBox.Right  =  myBndWidth; break;
246       case Graphic3d_HTA_RIGHT: theBndBox.Right  = -myBndWidth; break;
247       case Graphic3d_HTA_CENTER:
248       {
249         theBndBox.Left  = -0.5f * myBndWidth;
250         theBndBox.Right =  0.5f * myBndWidth;
251         break;
252       }
253     }
254     theBndBox.Top    = myBndTop;
255     theBndBox.Bottom = theBndBox.Top - myLineSpacing * Standard_ShortReal(myLinesNb);
256   }
257
258   //! Returns internal container of the top left corners of a formatted rectangles.
259   const NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >& Corners() const { return myCorners; }
260
261   //! Returns container of each line position at LF in formatted text
262   const NCollection_Vector<Standard_ShortReal>& NewLines() const { return myNewLines; }
263
264   //! Returns true if the symbol is CR, BEL, FF, NP, BS or VT
265   static inline Standard_Boolean IsCommandSymbol (const Standard_Utf32Char& theSymbol)
266   {
267     if (theSymbol == '\x0D' // CR  (carriage return)
268      || theSymbol == '\a'   // BEL (alarm)
269      || theSymbol == '\f'   // FF  (form feed) NP (new page)
270      || theSymbol == '\b'   // BS  (backspace)
271      || theSymbol == '\v')  // VT  (vertical tab)
272       return Standard_True;
273
274     return Standard_False;
275   }
276
277   DEFINE_STANDARD_RTTIEXT (Font_TextFormatter, Standard_Transient)
278
279 protected: //! @name class auxiliary methods
280
281   //! Move glyphs on the current line to correct position.
282   Standard_EXPORT void newLine (const Standard_Integer theLastRect,
283                                 const Standard_ShortReal theMaxLineWidth);
284
285 protected: //! @name configuration
286
287   Graphic3d_HorizontalTextAlignment myAlignX;  //!< horizontal alignment style
288   Graphic3d_VerticalTextAlignment   myAlignY;  //!< vertical   alignment style
289   Standard_Integer                  myTabSize; //!< horizontal tabulation width (number of space symbols)
290   Standard_ShortReal                myWrappingWidth; //!< text is wrapped by the width if defined (more 0)
291   Standard_ShortReal                myLastSymbolWidth; //!< width of the last symbol
292   Standard_ShortReal                myMaxSymbolWidth; //!< maximum symbol width of the formatter string
293
294 protected: //! @name input data
295
296   NCollection_String myString;        //!< currently rendered text
297   NCollection_Vec2<Standard_ShortReal>
298                      myPen;           //!< current pen position
299   NCollection_Vector < NCollection_Vec2<Standard_ShortReal> >
300                      myCorners;       //!< The bottom left corners of a formatted rectangles.
301   NCollection_Vector<Standard_ShortReal>
302                      myNewLines;      //!< position at LF
303   Standard_ShortReal myLineSpacing;   //!< line spacing (computed as maximum of all fonts involved in text formatting)
304   Standard_ShortReal myAscender;      //!< line spacing for the first line
305   bool               myIsFormatted;   //!< formatting state
306
307 protected: //! @name temporary variables for formatting routines
308
309   Standard_Integer   myLinesNb;       //!< overall (new)lines number (including splitting by width limit)
310   Standard_Integer   myRectLineStart; //!< id of first rectangle on the current line
311   Standard_Integer   myNewLineNb;
312
313   Standard_ShortReal myPenCurrLine;   //!< current baseline position
314   Standard_ShortReal myBndTop;
315   Standard_ShortReal myBndWidth;
316   NCollection_Vec2<Standard_ShortReal>
317                      myMoveVec;       //!< local variable
318 };
319
320 #endif // Font_TextFormatter_Header