Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-23 09:17:21

0001 // Created on: 2013-01-29
0002 // Created by: Kirill GAVRILOV
0003 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef Font_TextFormatter_Header
0017 #define Font_TextFormatter_Header
0018 
0019 #include <Font_Rect.hxx>
0020 #include <Graphic3d_HorizontalTextAlignment.hxx>
0021 #include <Graphic3d_VerticalTextAlignment.hxx>
0022 #include <NCollection_DataMap.hxx>
0023 #include <NCollection_DynamicArray.hxx>
0024 #include <NCollection_String.hxx>
0025 
0026 class Font_FTFont;
0027 
0028 //! This class is intended to prepare formatted text by using:
0029 //! - font to string combination,
0030 //! - alignment,
0031 //! - wrapping.
0032 //!
0033 //! After text formatting, each symbol of formatted text is placed in some position.
0034 //! Further work with the formatter is using an iterator.
0035 //! The iterator gives an access to each symbol inside the initial row.
0036 //! Also it's possible to get only significant/writable symbols of the text.
0037 //! Formatter gives an access to geometrical position of a symbol by the symbol index in the
0038 //! text. Example of correspondence of some text symbol to an index in "row_1\n\nrow_2\n":
0039 //! "row_1\n"  - 0-5 indices;
0040 //! "\n"       - 6 index;
0041 //! "\n"       - 7 index;
0042 //! "row_2\n"  - 8-13 indices.
0043 //! Pay attention that fonts should have the same LineSpacing value for correct formatting.
0044 //! Example of the formatter using:
0045 //! @code
0046 //!   occ::handle<Font_TextFormatter> aFormatter = new Font_TextFormatter();
0047 //!   aFormatter->Append(text_1, aFont1);
0048 //!   aFormatter->Append(text_2, aFont2);
0049 //!   // setting of additional properties such as wrapping or alignment
0050 //!   aFormatter->Format();
0051 //! @endcode
0052 class Font_TextFormatter : public Standard_Transient
0053 {
0054 public:
0055   //! Iteration filter flags. Command symbols are skipped with any filter.
0056   enum IterationFilter
0057   {
0058     IterationFilter_None             = 0x0000, //!< no filter
0059     IterationFilter_ExcludeInvisible = 0x0002, //!< exclude ' ', '\t', '\n'
0060   };
0061 
0062   //! Iterator through formatted symbols.
0063   //! It's possible to filter returned symbols to have only significant ones.
0064   class Iterator
0065   {
0066   public:
0067     //! Constructor with initialization.
0068     Iterator(const Font_TextFormatter& theFormatter,
0069              IterationFilter           theFilter = IterationFilter_None)
0070         : myFilter(theFilter),
0071           myIter(theFormatter.myString.Iterator()),
0072           mySymbolChar(0),
0073           mySymbolCharNext(0)
0074     {
0075       mySymbolPosition = readNextSymbol(-1, mySymbolChar);
0076       mySymbolNext     = readNextSymbol(mySymbolPosition, mySymbolCharNext);
0077     }
0078 
0079     //! Returns TRUE if iterator points to a valid item.
0080     bool More() const { return mySymbolPosition >= 0; }
0081 
0082     //! Returns TRUE if next item exists
0083     bool HasNext() const { return mySymbolNext >= 0; }
0084 
0085     //! Returns current symbol.
0086     char32_t Symbol() const { return mySymbolChar; }
0087 
0088     //! Returns the next symbol if exists.
0089     char32_t SymbolNext() const { return mySymbolCharNext; }
0090 
0091     //! Returns current symbol position.
0092     int SymbolPosition() const { return mySymbolPosition; }
0093 
0094     //! Returns the next symbol position.
0095     int SymbolPositionNext() const { return mySymbolNext; }
0096 
0097     //! Moves to the next item.
0098     void Next()
0099     {
0100       mySymbolPosition = mySymbolNext;
0101       mySymbolChar     = mySymbolCharNext;
0102       mySymbolNext     = readNextSymbol(mySymbolPosition, mySymbolCharNext);
0103     }
0104 
0105   protected:
0106     //! Finds index of the next symbol
0107     int readNextSymbol(const int theSymbolStartingFrom, char32_t& theSymbolChar)
0108     {
0109       int aNextSymbol = theSymbolStartingFrom;
0110       for (; *myIter != 0; ++myIter)
0111       {
0112         const char32_t aCharCurr = *myIter;
0113         if (Font_TextFormatter::IsCommandSymbol(aCharCurr))
0114         {
0115           continue; // skip unsupported carriage control codes
0116         }
0117         aNextSymbol++;
0118         if ((myFilter & IterationFilter_ExcludeInvisible) != 0)
0119         {
0120           if (aCharCurr == '\x0A' || // LF (line feed, new line)
0121               aCharCurr == ' ' || aCharCurr == '\t')
0122           {
0123             continue;
0124           }
0125         }
0126         ++myIter;
0127         theSymbolChar = aCharCurr;
0128         return aNextSymbol; // found the first next, not command and not filtered symbol
0129       }
0130       return -1; // the next symbol is not found
0131     }
0132 
0133   protected:
0134     IterationFilter myFilter;  //!< possibility to filter not-necessary symbols
0135                                // clang-format off
0136     NCollection_UtfIterator<char> myIter; //!< the next symbol iterator value over the text formatter string
0137     int     mySymbolPosition; //!< the current position
0138     char32_t   mySymbolChar; //!< the current symbol
0139     int     mySymbolNext; //!< position of the next symbol in iterator, if zero, the iterator is finished
0140                                // clang-format on
0141     char32_t mySymbolCharNext; //!< the current symbol
0142   };
0143 
0144   //! Default constructor.
0145   Standard_EXPORT Font_TextFormatter();
0146 
0147   //! Setup alignment style.
0148   Standard_EXPORT void SetupAlignment(const Graphic3d_HorizontalTextAlignment theAlignX,
0149                                       const Graphic3d_VerticalTextAlignment   theAlignY);
0150 
0151   //! Reset current progress.
0152   Standard_EXPORT void Reset();
0153 
0154   //! Render specified text to inner buffer.
0155   Standard_EXPORT void Append(const NCollection_String& theString, Font_FTFont& theFont);
0156 
0157   //! Perform formatting on the buffered text.
0158   //! Should not be called more than once after initialization!
0159   Standard_EXPORT void Format();
0160 
0161   Standard_DEPRECATED("BottomLeft should be used instead")
0162   const NCollection_Vec2<float>& TopLeft(const int theIndex) const { return BottomLeft(theIndex); }
0163 
0164   //! Returns specific glyph rectangle.
0165   const NCollection_Vec2<float>& BottomLeft(const int theIndex) const
0166   {
0167     return myCorners.Value(theIndex);
0168   }
0169 
0170   //! Returns current rendering string.
0171   inline const NCollection_String& String() const { return myString; }
0172 
0173   //! Returns symbol bounding box
0174   //! @param bounding box.
0175   Standard_EXPORT bool GlyphBoundingBox(const int theIndex, Font_Rect& theBndBox) const;
0176 
0177   //! Returns the line height
0178   //! @param theIndex a line index, obtained by LineIndex()
0179   float LineHeight(const int theIndex) const { return theIndex == 0 ? myAscender : myLineSpacing; }
0180 
0181   //! Returns width of a line
0182   Standard_EXPORT float LineWidth(const int theIndex) const;
0183 
0184   //! Returns true if the symbol by the index is '\n'. The width of the symbol is zero.
0185   Standard_EXPORT bool IsLFSymbol(const int theIndex) const;
0186 
0187   //! Returns position of the first symbol in a line using alignment
0188   Standard_EXPORT float FirstPosition() const;
0189 
0190   //! Returns column index of the corner index in the current line
0191   Standard_EXPORT int LinePositionIndex(const int theIndex) const;
0192 
0193   //! Returns row index of the corner index among text lines
0194   Standard_EXPORT int LineIndex(const int theIndex) const;
0195 
0196   //! Returns tab size.
0197   inline int TabSize() const { return myTabSize; }
0198 
0199   //! Returns horizontal alignment style
0200   Graphic3d_HorizontalTextAlignment HorizontalTextAlignment() const { return myAlignX; }
0201 
0202   //! Returns vertical alignment style
0203   Graphic3d_VerticalTextAlignment VerticalTextAlignment() const { return myAlignY; }
0204 
0205   //! Sets text wrapping width, zero means that the text is not bounded by width
0206   void SetWrapping(const float theWidth) { myWrappingWidth = theWidth; }
0207 
0208   //! Returns text maximum width, zero means that the text is not bounded by width
0209   bool HasWrapping() const { return myWrappingWidth > 0; }
0210 
0211   //! Returns text maximum width, zero means that the text is not bounded by width
0212   float Wrapping() const { return myWrappingWidth; }
0213 
0214   //! returns TRUE when trying not to break words when wrapping text
0215   bool WordWrapping() const { return myIsWordWrapping; }
0216 
0217   //! returns TRUE when trying not to break words when wrapping text
0218   void SetWordWrapping(const bool theIsWordWrapping) { myIsWordWrapping = theIsWordWrapping; }
0219 
0220   //! @return width of formatted text.
0221   inline float ResultWidth() const { return myBndWidth; }
0222 
0223   //! @return height of formatted text.
0224   inline float ResultHeight() const { return myLineSpacing * float(myLinesNb); }
0225 
0226   //! @return maximum width of the text symbol
0227   float MaximumSymbolWidth() const { return myMaxSymbolWidth; }
0228 
0229   //! @param bounding box.
0230   inline void BndBox(Font_Rect& theBndBox) const
0231   {
0232     theBndBox.Left = 0.0f;
0233     switch (myAlignX)
0234     {
0235       default:
0236       case Graphic3d_HTA_LEFT:
0237         theBndBox.Right = myBndWidth;
0238         break;
0239       case Graphic3d_HTA_RIGHT:
0240         theBndBox.Right = -myBndWidth;
0241         break;
0242       case Graphic3d_HTA_CENTER: {
0243         theBndBox.Left  = -0.5f * myBndWidth;
0244         theBndBox.Right = 0.5f * myBndWidth;
0245         break;
0246       }
0247     }
0248     theBndBox.Top    = myBndTop;
0249     theBndBox.Bottom = theBndBox.Top - myLineSpacing * float(myLinesNb);
0250   }
0251 
0252   //! Returns internal container of the top left corners of a formatted rectangles.
0253   const NCollection_DynamicArray<NCollection_Vec2<float>>& Corners() const { return myCorners; }
0254 
0255   //! Returns container of each line position at LF in formatted text
0256   const NCollection_DynamicArray<float>& NewLines() const { return myNewLines; }
0257 
0258   //! Returns true if the symbol is CR, BEL, FF, NP, BS or VT
0259   static inline bool IsCommandSymbol(const char32_t& theSymbol)
0260   {
0261     return (theSymbol == '\x0D'    // CR  (carriage return)
0262             || theSymbol == '\a'   // BEL (alarm)
0263             || theSymbol == '\f'   // FF  (form feed) NP (new page)
0264             || theSymbol == '\b'   // BS  (backspace)
0265             || theSymbol == '\v'); // VT  (vertical tab)
0266   }
0267 
0268   //! Returns true if the symbol separates words when wrapping is enabled
0269   static bool IsSeparatorSymbol(const char32_t& theSymbol)
0270   {
0271     return theSymbol == '\x0A'     // new line
0272            || theSymbol == ' '     // space
0273            || theSymbol == '\x09'; // tab
0274   }
0275 
0276   DEFINE_STANDARD_RTTIEXT(Font_TextFormatter, Standard_Transient)
0277 
0278 protected: //! @name class auxiliary methods
0279   //! Move glyphs on the current line to correct position.
0280   Standard_EXPORT void newLine(const int theLastRect, const float theMaxLineWidth);
0281 
0282 protected:                                    //! @name configuration
0283   Graphic3d_HorizontalTextAlignment myAlignX; //!< horizontal alignment style
0284   Graphic3d_VerticalTextAlignment   myAlignY; //!< vertical   alignment style
0285   // clang-format off
0286   int                  myTabSize; //!< horizontal tabulation width (number of space symbols)
0287   float                myWrappingWidth; //!< text is wrapped by the width if defined (more 0)
0288   bool                  myIsWordWrapping;  //!< if TRUE try not to break words when wrapping text (true by default)
0289   float                myLastSymbolWidth; //!< width of the last symbol
0290   float                myMaxSymbolWidth; //!< maximum symbol width of the formatter string
0291   // clang-format on
0292 
0293 protected:                          //! @name input data
0294   NCollection_String      myString; //!< currently rendered text
0295   NCollection_Vec2<float> myPen;    //!< current pen position
0296   NCollection_DynamicArray<NCollection_Vec2<float>>
0297                                   myCorners; //!< The bottom left corners of a formatted rectangles.
0298   NCollection_DynamicArray<float> myNewLines; //!< position at LF
0299                                               // clang-format off
0300   float myLineSpacing;   //!< line spacing (computed as maximum of all fonts involved in text formatting)
0301   float myAscender;      //!< line spacing for the first line
0302   bool               myIsFormatted;   //!< formatting state
0303 
0304 protected: //! @name temporary variables for formatting routines
0305 
0306   int   myLinesNb;       //!< overall (new)lines number (including splitting by width limit)
0307                                               // clang-format on
0308   int myRectLineStart;                        //!< id of first rectangle on the current line
0309   int myNewLineNb;
0310 
0311   float                   myPenCurrLine; //!< current baseline position
0312   float                   myBndTop;
0313   float                   myBndWidth;
0314   NCollection_Vec2<float> myMoveVec; //!< local variable
0315 };
0316 
0317 #endif // Font_TextFormatter_Header