You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
10 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2021 Ola Rinta-Koski
  5. * Copyright (C) 2021-2022 Kicad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * Font abstract base class
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #ifndef FONT_H_
  27. #define FONT_H_
  28. #include <iostream>
  29. #include <map>
  30. #include <algorithm>
  31. #include <wx/string.h>
  32. #include <font/glyph.h>
  33. #include <font/text_attributes.h>
  34. namespace KIGFX
  35. {
  36. class GAL;
  37. }
  38. enum TEXT_STYLE
  39. {
  40. BOLD = 1,
  41. ITALIC = 1 << 1,
  42. SUBSCRIPT = 1 << 2,
  43. SUPERSCRIPT = 1 << 3,
  44. OVERBAR = 1 << 4,
  45. UNDERLINE = 1 << 5
  46. };
  47. /**
  48. * Tilt factor for italic style (this is the scaling factor on dY relative coordinates to give
  49. * a tilted shape).
  50. * This is applied directly to stroke fonts, and is used as an estimate for outline fonts (which
  51. * have the actual tilt built in to their polygonal glyph outlines).
  52. */
  53. static constexpr double ITALIC_TILT = 1.0 / 8;
  54. using TEXT_STYLE_FLAGS = unsigned int;
  55. inline bool IsBold( TEXT_STYLE_FLAGS aFlags )
  56. {
  57. return aFlags & TEXT_STYLE::BOLD;
  58. }
  59. inline bool IsItalic( TEXT_STYLE_FLAGS aFlags )
  60. {
  61. return aFlags & TEXT_STYLE::ITALIC;
  62. }
  63. inline bool IsSuperscript( TEXT_STYLE_FLAGS aFlags )
  64. {
  65. return aFlags & TEXT_STYLE::SUPERSCRIPT;
  66. }
  67. inline bool IsSubscript( TEXT_STYLE_FLAGS aFlags )
  68. {
  69. return aFlags & TEXT_STYLE::SUBSCRIPT;
  70. }
  71. inline bool IsOverbar( TEXT_STYLE_FLAGS aFlags )
  72. {
  73. return aFlags & TEXT_STYLE::OVERBAR;
  74. }
  75. std::string TextStyleAsString( TEXT_STYLE_FLAGS aFlags );
  76. namespace KIFONT
  77. {
  78. /**
  79. * FONT is an abstract base class for both outline and stroke fonts
  80. */
  81. class FONT
  82. {
  83. public:
  84. explicit FONT();
  85. virtual ~FONT()
  86. { }
  87. virtual bool IsStroke() const { return false; }
  88. virtual bool IsOutline() const { return false; }
  89. virtual bool IsBold() const { return false; }
  90. virtual bool IsItalic() const { return false; }
  91. static FONT* GetFont( const wxString& aFontName = wxEmptyString, bool aBold = false,
  92. bool aItalic = false );
  93. static bool IsStroke( const wxString& aFontName );
  94. const wxString& GetName() const { return m_fontName; };
  95. inline const char* NameAsToken() const { return GetName().utf8_str().data(); }
  96. /**
  97. * Draw a string.
  98. *
  99. * @param aGal is the graphics context.
  100. * @param aText is the text to be drawn.
  101. * @param aPosition is the text position in world coordinates.
  102. * @param aCursor is the current text position (for multiple text blocks within a single text
  103. * object, such as a run of superscript characters)
  104. * @param aAttrs are the styling attributes of the text, including its rotation
  105. */
  106. void Draw( KIGFX::GAL* aGal, const wxString& aText, const VECTOR2I& aPosition,
  107. const VECTOR2I& aCursor, const TEXT_ATTRIBUTES& aAttrs ) const;
  108. void Draw( KIGFX::GAL* aGal, const wxString& aText, const VECTOR2I& aPosition,
  109. const TEXT_ATTRIBUTES& aAttributes ) const
  110. {
  111. Draw( aGal, aText, aPosition, VECTOR2I( 0, 0 ), aAttributes );
  112. }
  113. /**
  114. * Compute the boundary limits of aText (the bounding box of all shapes).
  115. *
  116. * @return a VECTOR2I giving the width and height of text.
  117. */
  118. VECTOR2I StringBoundaryLimits( const wxString& aText, const VECTOR2I& aSize, int aThickness,
  119. bool aBold, bool aItalic ) const;
  120. /**
  121. * Insert \n characters into text to ensure that no lines are wider than \a aColumnWidth.
  122. */
  123. void LinebreakText( wxString& aText, int aColumnWidth, const VECTOR2I& aGlyphSize,
  124. int aThickness, bool aBold, bool aItalic ) const;
  125. /**
  126. * Compute the vertical position of an overbar. This is the distance between the text
  127. * baseline and the overbar.
  128. */
  129. virtual double ComputeOverbarVerticalPosition( double aGlyphHeight ) const = 0;
  130. /**
  131. * Compute the vertical position of an underline. This is the distance between the text
  132. * baseline and the underline.
  133. */
  134. virtual double ComputeUnderlineVerticalPosition( double aGlyphHeight ) const = 0;
  135. /**
  136. * Compute the distance (interline) between 2 lines of text (for multiline texts). This is
  137. * the distance between baselines, not the space between line bounding boxes.
  138. */
  139. virtual double GetInterline( double aGlyphHeight, double aLineSpacing = 1.0 ) const = 0;
  140. /**
  141. * Convert text string to an array of GLYPHs.
  142. *
  143. * @param aBBox pointer to a BOX2I that will set to the bounding box, or nullptr
  144. * @param aGlyphs storage for the returned GLYPHs
  145. * @param aText text to convert to polygon/polyline
  146. * @param aSize is the cap-height and em-width of the text
  147. * @param aPosition position of text (cursor position before this text)
  148. * @param aAngle text angle
  149. * @param aMirror is true if text should be drawn mirrored, false otherwise.
  150. * @param aOrigin is the point around which the text should be rotated, mirrored, etc.
  151. * @param aTextStyle text style flags
  152. * @return text cursor position after this text
  153. */
  154. virtual VECTOR2I GetTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
  155. const wxString& aText, const VECTOR2I& aSize,
  156. const VECTOR2I& aPosition, const EDA_ANGLE& aAngle,
  157. bool aMirror, const VECTOR2I& aOrigin,
  158. TEXT_STYLE_FLAGS aTextStyle ) const = 0;
  159. protected:
  160. /**
  161. * Returns number of lines for a given text.
  162. *
  163. * @param aText is the text to be checked.
  164. * @return unsigned - The number of lines in aText.
  165. */
  166. inline unsigned linesCount( const wxString& aText ) const
  167. {
  168. if( aText.empty() )
  169. return 0; // std::count does not work well with empty strings
  170. else
  171. // aText.end() - 1 is to skip a newline character that is potentially at the end
  172. return std::count( aText.begin(), aText.end() - 1, '\n' ) + 1;
  173. }
  174. /**
  175. * Draws a single line of text. Multiline texts should be split before using the
  176. * function.
  177. *
  178. * @param aGal is a pointer to the graphics abstraction layer, or nullptr (nothing is drawn)
  179. * @param aBBox is an optional pointer to be filled with the bounding box.
  180. * @param aText is the text to be drawn.
  181. * @param aPosition is text position.
  182. * @param aSize is the cap-height and em-width of the text
  183. * @param aAngle is text angle.
  184. * @param aMirror is true if text should be drawn mirrored, false otherwise.
  185. * @param aOrigin is the point around which the text should be rotated, mirrored, etc.
  186. * @return new cursor position in non-rotated, non-mirrored coordinates
  187. */
  188. void drawSingleLineText( KIGFX::GAL* aGal, BOX2I* aBoundingBox, const wxString& aText,
  189. const VECTOR2I& aPosition, const VECTOR2I& aSize,
  190. const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
  191. bool aItalic, bool aUnderline ) const;
  192. /**
  193. * Computes the bounding box for a single line of text.
  194. * Multiline texts should be split before using the function.
  195. *
  196. * @param aBBox is an optional pointer to be filled with the bounding box.
  197. * @param aText is the text to be drawn.
  198. * @param aPosition is text position.
  199. * @param aSize is the cap-height and em-width of the text.
  200. * @return new cursor position
  201. */
  202. VECTOR2I boundingBoxSingleLine( BOX2I* aBBox, const wxString& aText, const VECTOR2I& aPosition,
  203. const VECTOR2I& aSize, bool aItalic ) const;
  204. void getLinePositions( const wxString& aText, const VECTOR2I& aPosition,
  205. wxArrayString& aTextLines, std::vector<VECTOR2I>& aPositions,
  206. std::vector<VECTOR2I>& aExtents, const TEXT_ATTRIBUTES& aAttrs ) const;
  207. VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs,
  208. const wxString& aText, const VECTOR2I& aPosition, const VECTOR2I& aSize,
  209. const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin,
  210. TEXT_STYLE_FLAGS aTextStyle ) const;
  211. void wordbreakMarkup( std::vector<std::pair<wxString, int>>* aWords, const wxString& aText,
  212. const VECTOR2I& aSize, TEXT_STYLE_FLAGS aTextStyle ) const;
  213. ///< Factor that determines the pitch between 2 lines.
  214. static constexpr double INTERLINE_PITCH_RATIO = 1.62; // The golden mean
  215. private:
  216. static FONT* getDefaultFont();
  217. protected:
  218. wxString m_fontName; ///< Font name
  219. wxString m_fontFileName; ///< Font file name
  220. private:
  221. static FONT* s_defaultFont;
  222. static std::map< std::tuple<wxString, bool, bool>, FONT* > s_fontMap;
  223. };
  224. } //namespace KIFONT
  225. inline std::ostream& operator<<(std::ostream& os, const KIFONT::FONT& aFont)
  226. {
  227. os << "[Font \"" << aFont.GetName() << "\"" << ( aFont.IsStroke() ? " stroke" : "" )
  228. << ( aFont.IsOutline() ? " outline" : "" ) << ( aFont.IsBold() ? " bold" : "" )
  229. << ( aFont.IsItalic() ? " italic" : "" ) << "]";
  230. return os;
  231. }
  232. inline std::ostream& operator<<(std::ostream& os, const KIFONT::FONT* aFont)
  233. {
  234. os << *aFont;
  235. return os;
  236. }
  237. #endif // FONT_H_