1 // -*- C++ -*- 2 /* GG is a GUI for OpenGL. 3 Copyright (C) 2003-2008 T. Zachary Laine 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public License 7 as published by the Free Software Foundation; either version 2.1 8 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free 17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 02111-1307 USA 19 20 If you do not wish to comply with the terms of the LGPL please 21 contact the author as other terms are available for a fee. 22 23 Zach Laine 24 whatwasthataddress@gmail.com */ 25 26 /** \file Font.h \brief Contains the Font class, a class that encapsulates the 27 rendering of a single FreeType-compatible font in italics, with 28 underlining, left-, right-, or center- justified, etc., and the 29 FontManager class which provides application-wide management of Font 30 objects. */ 31 32 #ifndef _GG_Font_h_ 33 #define _GG_Font_h_ 34 35 #include <GG/AlignmentFlags.h> 36 #include <GG/FontFwd.h> 37 #include <GG/Texture.h> 38 #include <GG/UnicodeCharsets.h> 39 40 #include <boost/graph/graph_concepts.hpp> 41 42 #include <memory> 43 #include <set> 44 #include <stack> 45 #include <unordered_map> 46 47 48 struct FT_FaceRec_; 49 typedef struct FT_FaceRec_* FT_Face; 50 typedef int FT_Error; 51 52 namespace GG { 53 54 class GLRGBAColorBuffer; 55 class GLTexCoordBuffer; 56 class GL2DVertexBuffer; 57 58 /** Returns a string of the form "<rgba r g b a>" from a Clr object with color 59 channels r, b, g, a. */ 60 GG_API std::string RgbaTag(const Clr& c); 61 62 63 /** \brief A bitmapped font rendering class. 64 65 Font creates one or more 16-bits-per-pixel OpenGL textures that contain 66 rendered glyphs from a requested font file at the requested point size, 67 including only the requested ranges of code points. Once the textures 68 have been created, text is rendered to the display by rendering quads 69 textured with portions of the glyph textures. The glyphs are rendered to 70 the textures in white, with alpha blending used for antialiasing. The 71 user should set the desired text color with a call to glColor*() before 72 any call to RenderText(). When text is rendered, DetermineLines() is 73 called to determine where the line breaks are, so that text can be 74 rendered centered, right-justified, or whatever. To cut down on this 75 computation, when the text is not changing very rapidly (ie not every 76 frame), DetermineLines() can be called by the user once, and the result 77 supplied to RenderText() repeatedly. When this is done, the iteration 78 through the text to determine line breaks is not necessary at render time. 79 The user is responsible for ensuring that the line data applies to the 80 text string supplied to RenderText(). See UnicodeCharsets.h for the 81 ranges of code points available, including a function that allow one to 82 determine which ranges are necessary for rendering a certain string. 83 Point sizes above 250 are not supported. Note that users should not 84 normally need to use Font directly. Users should instead use TextControl, 85 Edit, or MultiEdit. 86 87 <h3>Text Formatting Tags</h3> 88 89 GG::Font supports a few text formatting tags for convenience. These tags 90 are similar to HTML or XML tags; there is an opening version "<tag>" and a 91 closing version "</tag>" of each tag. Tags can be nested. For instance, 92 consider the use of the italics tag \<i> here: 93 94 \verbatim 95 <i>some text <i>and </i>some more </i>text \endverbatim 96 97 In this example, everything is italicized except for "text". Each \<i> 98 tag establishes that italics should be used for all further text until the 99 next \a matching \</i> tag. The first \<i> tag matches the second \</i> 100 tag, and the two inner tags are matched. Note that unmatched close-tags 101 (e.g. \</i>) are ignored by the text parser Font uses to find tags -- they 102 will appear as regular text. The text justification tags are used on a 103 per-line basis, since it makes no sense to, for instance, right-justify 104 only a part of a line and center the rest. When more than one 105 justification tag appears on a line, the last one is used. A 106 justification close-tag indicates that a line is to be the last one with 107 that justification, and only applies if that justification is active. 108 109 <br>The supported tags are: 110 - \verbatim<i></i> \endverbatim Italics 111 - \verbatim<u></u> \endverbatim Underline 112 - \verbatim<s></s> \endverbatim Shadow 113 - \verbatim<rgba r g b a></rgba> \endverbatim Color. Sets current rendering color to that specified by parameters. Parameters may be either floating point values in the range [0.0, 1.0], or integer values in the range [0, 255]. All parameters must be in one format or the other. The \</rgba> tag restores the previously set \<rgba> color, or restores the default color used to render the text when there are no other \<rgba> tags in effect. Example tag: \<rgba 0.4 0.5 0.6 0.7>. 114 - \verbatim<left></left> \endverbatim Left-justified text. 115 - \verbatim<center></center> \endverbatim Centered text. 116 - \verbatim<right></right> \endverbatim Right-justified text. 117 - \verbatim<pre></pre> \endverbatim Preformatted. Similar to HTML \<pre> tag, except this one only causes all tags to be ignored until a subsequent \</pre> tag is seen. Note that due to their semantics, \<pre> tags cannot be nested. 118 119 <p>Users of Font may wish to create their own tags as well. Though Font 120 will know nothing about the semantics of the new tags, it is possible to 121 let Font know about them, in order for Font to render them invisible as it 122 does with the tags listed above. See the static methods 123 RegisterKnownTag(), RemoveKnownTag(), and ClearKnownTags() for details. 124 It is not possible to remove the built-in tags using these methods. If 125 you wish not to use tags at all, call DetermineLines() and RenderText() 126 with the format parameter containing FORMAT_IGNORETAGS, or include a 127 \<pre> tag at the beginning of the text to be rendered. 128 */ 129 class GG_API Font 130 { 131 public: 132 /** \brief A range of iterators into a std::string that defines a 133 substring found in a string being rendered by Font. 134 135 Substring is bound to a particular instance of a std::string. If 136 that particular std::string goes out of scope or is deleted then 137 behavior is undefined, but may seg fault with the next access. */ 138 class GG_API Substring 139 { 140 public: 141 typedef std::pair<std::string::const_iterator, std::string::const_iterator> IterPair; 142 143 Substring(); 144 145 /** Ctor. \a first_ must be <= \a second_. */ 146 Substring(const std::string& str_, 147 std::string::const_iterator first_, 148 std::string::const_iterator second_); 149 150 /** Construction from base. \a pair.first must be <= \a 151 pair.second. */ 152 Substring(const std::string& str_, const IterPair& pair); 153 154 /** Attach this Substring to \p str_. 155 156 This changes the iterators from pointing into the previous 157 std::string to pointing into \p str_. 158 */ 159 void Bind(const std::string& str_); 160 161 /** Returns an iterator to the beginning of the substring. */ 162 std::string::const_iterator begin() const; 163 164 /** Returns an iterator to one-past-the-end of the substring. */ 165 std::string::const_iterator end() const; 166 167 /** True iff .first == .second. */ 168 bool empty() const; 169 170 /** Length, in original string chars, of the substring. */ 171 std::size_t size() const; 172 173 /** Implicit conversion to std::string. */ 174 operator std::string() const; 175 176 /** Comparison with std::string. */ 177 bool operator==(const std::string& rhs) const; 178 179 /** Comparison with std::string. */ 180 bool operator!=(const std::string& rhs) const; 181 182 /** Concatenation with base. \a rhs.first must be <= \a rhs.second. 183 .second must be equal to \a rhs.first (*this and \a rhs must be 184 contiguous). */ 185 Substring& operator+=(const IterPair& rhs); 186 187 private: 188 const std::string* str; 189 std::ptrdiff_t first; 190 std::ptrdiff_t second; 191 192 static const std::string EMPTY_STRING; 193 }; 194 195 /** \brief Used to encapsulate a token-like piece of text to be rendered 196 using GG::Font. */ 197 struct GG_API TextElement 198 { 199 /** The types of token-like entities that can be represented by a 200 TextElement. */ 201 enum TextElementType { 202 OPEN_TAG, ///< An opening text formatting tag (e.g. "<rgba 0 0 0 255>"). 203 CLOSE_TAG, ///< A closing text formatting tag (e.g. "</rgba>"). 204 TEXT, ///< Some non-whitespace text (e.g. "The"). 205 WHITESPACE, ///< Some whitespace text (e.g. " \n"). 206 207 /** A newline. Newline TextElements represent the newline code 208 point when it is encountered in a rendered string, though they 209 do not contain the actual newline character -- their \a text 210 members are always ""). */ 211 NEWLINE 212 }; 213 214 /** Ctor. \a ws indicates that the element contains only whitespace; 215 \a nl indicates that it is a newline element. */ 216 TextElement(bool ws, bool nl); 217 218 virtual ~TextElement(); 219 220 /** Attach this TextElement to the string \p whole_text, by 221 attaching the SubString data member text to \p whole_text. 222 223 Binding to a new \p whole_text is very fast compared to 224 re-parsing the entire \p whole_text and allows TextElements of 225 TextElementType TEXT to be changed quickly if it is known that 226 the parse would be the same. 227 228 It is efficient when you want to do a text parse or layout 229 once, and then create several different controls that have the 230 same text layout and text contents, but each of them needs to 231 keep there own internal copy of the text. So, while the pointer 232 diffs are all the same, since the text contents are the same, 233 the pointer to the string in each TextElement (and its 234 contained Substring) needs to be set to the appropriate copy of 235 the string. 236 237 This is used in TextControl and its derived classes to re-use 238 entire vectors of TextElement with different std::strings 239 without re-parsing the std::string. 240 */ 241 virtual void Bind(const std::string& whole_text); 242 243 /** Returns the TextElementType of the element. */ 244 virtual TextElementType Type() const; 245 246 /** Returns the width of the element. */ 247 X Width() const; 248 249 /* Returns the number of characters in the original string that the 250 element represents. */ 251 StrSize StringSize() const; 252 253 /** Returns the number of code points in the original string that the 254 element represents. */ 255 CPSize CodePointSize() const; 256 257 virtual bool operator==(const TextElement &rhs) const; 258 259 /** The text from the original string represented by the element. */ 260 Substring text; 261 262 std::vector<X> widths; ///< The widths of the glyphs in \a text. 263 const bool whitespace; ///< True iff this is a whitespace element. 264 const bool newline; ///< True iff this is a newline element. 265 266 protected: 267 TextElement(); 268 269 private: 270 mutable X cached_width; 271 }; 272 273 /** \brief TextAndElementsAssembler is used to assemble a matched pair of text and a vector of 274 TextElement, without incurring the computational cost of parsing the text with 275 ExpensiveParseFromTextToTextElements(). 276 277 The pair of string and vector returned by Text() and Elements() are consistent with each 278 other and can be used with the fast constructor or the fast SetText variant of TextControl. 279 */ 280 class GG_API TextAndElementsAssembler 281 { 282 public: 283 TextAndElementsAssembler(const Font& font); 284 ~TextAndElementsAssembler(); 285 286 /** Return the constructed text.*/ 287 const std::string& Text(); 288 /** Return the constructed TextElements.*/ 289 const std::vector<std::shared_ptr<TextElement>>& Elements(); 290 291 /** Add an open tag iff it exists as a recognized tag.*/ 292 TextAndElementsAssembler& AddOpenTag(const std::string& tag); 293 /** Add an open tag iff it exists as a recognized tag.*/ 294 TextAndElementsAssembler& AddOpenTag(const std::string& tag, const std::vector<std::string>& params); 295 /** Add a close tag iff it exists as a recognized tag.*/ 296 TextAndElementsAssembler& AddCloseTag(const std::string& tag); 297 /** Add a text element. Any whitespace in this text element will be non-breaking.*/ 298 TextAndElementsAssembler& AddText(const std::string& text); 299 /** Add a white space element.*/ 300 TextAndElementsAssembler& AddWhitespace(const std::string& whitespace); 301 /** Add a new line element.*/ 302 TextAndElementsAssembler& AddNewline(); 303 304 /** Add an open Clr tag.*/ 305 TextAndElementsAssembler& AddOpenTag(const Clr& color); 306 307 private: 308 class Impl; 309 std::unique_ptr<Impl> const m_impl; 310 }; 311 312 /** \brief The type of TextElement that represents a text formatting 313 tag. */ 314 struct GG_API FormattingTag : TextElement 315 { 316 /** Ctor. \a close indicates that the tag is a close-tag 317 (e.g. "</rgba>"). */ 318 FormattingTag(bool close); 319 320 /** Attach to \p whole_text by binding all Substring data members, 321 both the base class and the data member tag_name to the string 322 \p whole_text.*/ 323 void Bind(const std::string& whole_text) override; 324 325 TextElementType Type() const override; 326 327 bool operator==(const TextElement &rhs) const override; 328 329 /** The parameter strings within the tag, e.g. "0", "0", "0", and "255" 330 for the tag "<rgba 0 0 0 255>". */ 331 std::vector<Substring> params; 332 333 /** The name of the tag (e.g. for the tag "<i>", tag_name is "i"). */ 334 Substring tag_name; 335 336 /** True iff this is a close-tag. */ 337 const bool close_tag; 338 339 private: 340 FormattingTag(); 341 }; 342 343 /** \brief Holds the essential data on each line that a string occupies when 344 rendered with given format flags. 345 346 \a char_data contains the visible glyphs for each line, plus any text 347 formatting tags present on that line as well. */ 348 struct GG_API LineData 349 { 350 LineData(); 351 352 /** \brief Contains the extent, the index into the original string, 353 and the text formatting tags that should be applied before 354 rendering of a visible glyph. */ 355 struct GG_API CharData 356 { 357 CharData(); 358 359 CharData(X extent_, StrSize str_index, StrSize str_size, CPSize cp_index, 360 const std::vector<std::shared_ptr<TextElement>>& tags_); 361 362 /** The furthest-right extent of this glyph as it appears on the 363 line. */ 364 X extent; 365 366 /** The position in the original string of the first character of 367 this glyph. */ 368 StrSize string_index; 369 370 /** The size in the original string of the characters that make up 371 this glyph. */ 372 StrSize string_size; 373 374 /** The code point index of this glyph. */ 375 CPSize code_point_index; 376 377 /** The text formatting tags that should be applied before 378 rendering this glyph. */ 379 std::vector<std::shared_ptr<FormattingTag>> tags; 380 }; 381 382 X Width() const; ///< Returns the width of the line. 383 bool Empty() const; ///< Returns true iff char_data has size 0. 384 385 /** Data on each individual glyph. */ 386 std::vector<CharData> char_data; 387 388 /** FORMAT_LEFT, FORMAT_CENTER, or FORMAT_RIGHT; derived from text 389 format flags and/or formatting tags in the text. */ 390 Alignment justification; 391 }; 392 393 /** \brief Holds the state of tags during rendering of text. 394 395 By keeping track of this state across multiple calls to RenderText(), 396 the user can preserve the functionality of the text formatting tags, 397 if present. */ 398 struct GG_API RenderState 399 { 400 RenderState(); 401 402 RenderState(Clr color); //< Takes default text color as parameter 403 404 /** The count of open \<i> tags seen since the last \</i> seen. */ 405 std::size_t use_italics; 406 407 /** The count of open \<s> tags seen since the last \</s> seen. */ 408 std::size_t use_shadow; 409 410 /** The count of open \<u> tags seen since the last \</u> seen. */ 411 std::size_t draw_underline; 412 413 /** The count of open \<super> (positive) minus \<sub> tags seen. */ 414 int super_sub_shift; 415 416 /** The stack of text color indexes (as set by previous tags). */ 417 std::stack<int> color_index_stack; 418 419 /** All colors that have been used. **/ 420 std::vector<Clr> used_colors; 421 422 /// Add color to stack and remember it has been used 423 void PushColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a); 424 425 /// Return to the previous used color, or remain as default 426 void PopColor(); 427 428 /// Return the index of the current color in used_colors 429 int CurrentIndex() const; 430 431 const Clr& CurrentColor() const; 432 433 /// Return true if there are no more colors to pop. 434 bool ColorsEmpty() const; 435 }; 436 437 /** \brief Holds precomputed glyph position information for rendering. 438 */ 439 struct RenderCache 440 { 441 std::unique_ptr<GL2DVertexBuffer> vertices; 442 std::unique_ptr<GLTexCoordBuffer> coordinates; 443 std::unique_ptr<GLRGBAColorBuffer> colors; 444 445 std::unique_ptr<GL2DVertexBuffer> underline_vertices; 446 std::unique_ptr<GLRGBAColorBuffer> underline_colors; 447 448 RenderCache(); 449 450 ~RenderCache(); 451 }; 452 453 /** \name Structors */ ///@{ 454 /** Ctor. Construct a font using only the printable ASCII characters. 455 \throw Font::Exception Throws a subclass of Font::Exception if the 456 condition specified for the subclass is met. */ 457 Font(const std::string& font_filename, unsigned int pts); 458 459 /** Ctor. Construct a font using only the printable ASCII characters, 460 from the in-memory contents \a file_contents. \throw Font::Exception 461 Throws a subclass of Font::Exception if the condition specified for 462 the subclass is met. */ 463 Font(const std::string& font_filename, unsigned int pts, 464 const std::vector<unsigned char>& file_contents); 465 466 /** Ctor. Construct a font using all the code points in the 467 UnicodeCharsets in the range [first, last). \throw Font::Exception 468 Throws a subclass of Font::Exception if the condition specified for 469 the subclass is met. */ 470 template <typename CharSetIter> 471 Font(const std::string& font_filename, unsigned int pts, 472 CharSetIter first, CharSetIter last); 473 474 /** Ctor. Construct a font using all the code points in the 475 UnicodeCharsets in the range [first, last), from the in-memory 476 contents \a file_contents. \throw Font::Exception Throws a subclass 477 of Font::Exception if the condition specified for the subclass is 478 met. */ 479 template <typename CharSetIter> 480 Font(const std::string& font_filename, unsigned int pts, 481 const std::vector<unsigned char>& file_contents, 482 CharSetIter first, CharSetIter last); 483 484 ~Font(); ///< Dtor. 485 //@} 486 487 /** \name Accessors */ ///@{ 488 /** Returns the name of the file from which this font was created. */ 489 const std::string& FontName() const; 490 491 /** Returns the point size in which the characters in the font object are 492 rendered. */ 493 unsigned int PointSize() const; 494 GetTexture()495 const std::shared_ptr<Texture> GetTexture() const 496 { return m_texture; } 497 498 /** Returns the range(s) of code points rendered in the font */ 499 const std::vector<UnicodeCharset>& UnicodeCharsets() const; 500 501 /** Returns the maximum amount above the baseline the text can go. */ 502 Y Ascent() const; 503 504 /** Returns the maximum amount below the baseline the text can go. */ 505 Y Descent() const; 506 507 /** Returns (Ascent() - Descent()). */ 508 Y Height() const; 509 510 /** Returns the distance that should be placed between lines. This is 511 usually not equal to Height(). */ 512 Y Lineskip() const; 513 514 /** Returns the width of the glyph for the space character. */ 515 X SpaceWidth() const; 516 517 /** Unformatted text rendering; repeatedly calls RenderGlyph, then returns 518 advance of entire string. */ 519 X RenderText(const Pt& pt, const std::string& text) const; 520 521 /** Formatted text rendering. */ 522 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format, 523 const std::vector<LineData>& line_data, RenderState* render_state = nullptr) const; 524 525 /** Formatted text rendering over a subset of lines and code points. The 526 glyphs rendered are in the range [CodePointIndexOf(<i>begin_line</i>, 527 <i>begin_char</i>, <i>line_data</i>), CodePointIndexOf(<i>end_line</i> - 528 1, <i>end_char</i>, <i>line_data</i>)). */ 529 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format, 530 const std::vector<LineData>& line_data, RenderState& render_state, 531 std::size_t begin_line, CPSize begin_char, 532 std::size_t end_line, CPSize end_char) const; 533 534 /** Wrapper around PreRenderText that provides dummy values for line start and end values.*/ 535 void PreRenderText(const Pt& ul, const Pt& lr, const std::string& text, Flags<TextFormat>& format, 536 RenderCache& cache, const std::vector<LineData>& line_data, 537 RenderState* render_state = nullptr) const; 538 539 /** Fill the \p cache with glyphs corresponding to the passed in \p text and \p line_data.*/ 540 void PreRenderText(const Pt& pt1, const Pt& pt2, const std::string& text, 541 Flags<TextFormat>& format, const std::vector<LineData>& line_data, 542 RenderState& render_state, std::size_t begin_line, CPSize begin_char, 543 std::size_t end_line, CPSize end_char, RenderCache& cache) const; 544 545 /** Render the glyphs from the \p cache.*/ 546 void RenderCachedText(RenderCache& cache) const; 547 548 /** Sets \a render_state as if all the text before (<i>begin_line</i>, 549 <i>begin_char</i>) had just been rendered. */ 550 void ProcessTagsBefore(const std::vector<LineData>& line_data, RenderState& render_state, 551 std::size_t begin_line, CPSize begin_char) const; 552 553 /** Return a vector of TextElements parsed from \p text, using the 554 FORMAT_IGNORETAGS bit in \p format to determine if all KnownTags() 555 are ignored. 556 557 This function is costly even on single character texts. Do not call 558 it from tight loops. Do not call it from within Render(). Do not 559 call it repeatedly on a known text. 560 */ 561 std::vector<std::shared_ptr<Font::TextElement>> ExpensiveParseFromTextToTextElements(const std::string& text, 562 const Flags<TextFormat>& format) const; 563 564 /** Fill \p text_elements with the font widths of characters from \p text starting from \p 565 starting_from. */ 566 void FillTemplatedText(const std::string& text, 567 std::vector<std::shared_ptr<TextElement>>& text_elements, 568 std::vector<std::shared_ptr<TextElement>>::iterator starting_from) const; 569 570 /** Change \p text_elements and \p text to replace the text of the TextElement at 571 \p targ_offset with \p new_text. 572 573 This replaces the entire text of the TextElement at offset \p targ_offset and adjusts the 574 string \p text to be consistent even if the \p new_text is longer/shorter than the original 575 TEXT type TextElement. 576 577 This does not recompute the text_elements. It is faster than 578 ExpensiveParseFromTextToTextElements on a new string. It will not find white space in the 579 inserted text. 580 581 \p text and \p text_elements are assumed to be consistent with each other and both will be 582 changed to remain consistent. 583 584 \p targ_offset is the zero based offset of the TextElements of type TEXT. It ignores 585 other types of TextElements such as TAGS, WHITESPACE and NEWLINE, when determining the 586 offset. 587 588 Here is an example of changing a ship name from "oldname" to "New Ship Name": 589 590 original text: "<i>Ship:<\i> oldname ID:" 591 orignal text_elements: [<OPEN_TAG i>, <TEXT "Ship:">, <CLOSE_TAG i>, <WHITESPACE>, <TEXT oldname>, <WHITESPACE>, <TEXT ID:>] 592 593 ChangeTemplatedText(text, text_elements, "New Ship Name", 1); 594 595 changed text: "<i>Ship:<\i> New Ship Name ID:" 596 changed text_elements: [<OPEN_TAG i>, <TEXT "Ship:">, <CLOSE_TAG i>, <WHITESPACE>, <TEXT New Ship Name>, <WHITESPACE>, <TEXT ID:>] 597 598 */ 599 void ChangeTemplatedText(std::string& text, 600 std::vector<std::shared_ptr<TextElement>>& text_elements, 601 const std::string& new_text, 602 size_t targ_offset) const; 603 604 /** DetermineLines() returns the \p line_data resulting from adding the necessary line 605 breaks, to the \p text formatted with \p format and parsed into \p text_elements, to fit 606 the \p text into a box of width \p box_width. 607 608 It accounts for alignment, wrapping and justification of the \p text. 609 610 A \p box_width of X0 will add a line break at every whitespace element in \p text_elements. 611 612 Supplying a \p text and \p text_elements that are incompatible will result in undefined 613 behavior. \p text_elements contains internal pointers to the \p text to which it is 614 bound. Compatible means the exact same \p text object, not the same text content. 615 */ 616 std::vector<LineData> DetermineLines(const std::string& text, Flags<TextFormat>& format, X box_width, 617 const std::vector<std::shared_ptr<TextElement>>& text_elements) const; 618 619 /** Returns the maximum dimensions of the text in x and y. */ 620 Pt TextExtent(const std::vector<LineData>& line_data) const; 621 //@} 622 623 /** Adds \a tag to the list of embedded tags that Font should not print 624 when rendering text. Passing "foo" will cause Font to treat "<foo>", 625 "<foo [arg1 [arg2 ...]]>", and "</foo>" as tags. */ 626 static void RegisterKnownTag(const std::string& tag); 627 628 /** Removes \a tag from the known tag list. Does not remove the built in 629 tags: \<i>, \<u>, \<rgba r g b a>, and \<pre>. */ 630 static void RemoveKnownTag(const std::string& tag); 631 632 /** Removes all tags from the known tag list. Does not remove the built 633 in tags: \<i>, \<u>, \<rgba r g b a>, and \<pre>. */ 634 static void ClearKnownTags(); 635 636 /** Returns the input \a text, stripped of any formatting tags. */ 637 static std::string StripTags(const std::string& text, bool strip_unpaired_tags = true); 638 639 /** \name Exceptions */ ///@{ 640 /** The base class for Font exceptions. */ 641 GG_ABSTRACT_EXCEPTION(Exception); 642 643 /** Thrown when valid font data cannot be read from a file. */ 644 GG_CONCRETE_EXCEPTION(BadFile, GG::Font, Exception); 645 646 /** Thrown when a 0 font size is requested. */ 647 GG_CONCRETE_EXCEPTION(InvalidPointSize, GG::Font, Exception); 648 649 /** Thrown when a FreeType font could be loaded, but the resulting font is 650 not scalable, making it unusable by GG. */ 651 GG_CONCRETE_EXCEPTION(UnscalableFont, GG::Font, Exception); 652 653 /** Thrown when an attempt is made to create a glyph from null font face 654 object. */ 655 GG_CONCRETE_EXCEPTION(BadFace, GG::Font, Exception); 656 657 /** Thrown when an attempt to set the size of a FreeType font face 658 fails. */ 659 GG_CONCRETE_EXCEPTION(BadPointSize, GG::Font, Exception); 660 661 /** Thrown when FreeType is unable to fulfill a request to load or render 662 a glpyh. */ 663 GG_CONCRETE_EXCEPTION(BadGlyph, GG::Font, Exception); 664 //@} 665 666 /** Throws a BadGlyph exception, with \a c converted to a printable ASCII 667 character (if possible), or as a Unicode code point. \a format_str 668 should contain the Boost.Format positional notation formatting tag 669 "%1%" where the code point should appear. */ 670 static void ThrowBadGlyph(const std::string& format_str, std::uint32_t c); 671 672 protected: 673 /** \name Structors */ ///@{ 674 Font(); 675 //@} 676 677 private: 678 /** \brief This just holds the essential data necessary to render a glyph 679 from the OpenGL texture(s) created at GG::Font creation time. */ 680 struct Glyph 681 { 682 Glyph(); 683 684 Glyph(const std::shared_ptr<Texture>& texture, const Pt& ul, const Pt& lr, Y y_ofs, 685 X lb, X adv); ///< Ctor 686 687 SubTexture sub_texture; ///< The subtexture containing just this glyph 688 Y y_offset; ///< The vertical offset to draw this glyph (may be negative!) 689 X left_bearing; ///< The space that should remain before the glyph 690 X advance; ///< The amount of space the glyph should occupy, including glyph graphic and inter-glyph spacing 691 X width; ///< The width of the glyph only 692 }; 693 694 typedef std::unordered_map<std::uint32_t, Glyph> GlyphMap; 695 696 FT_Error GetFace(FT_Face& face); 697 FT_Error GetFace(const std::vector<unsigned char>& file_contents, FT_Face& face); 698 void CheckFace(FT_Face font, FT_Error error); 699 void Init(FT_Face& font); 700 701 bool GenerateGlyph(FT_Face font, std::uint32_t ch); 702 703 void ValidateFormat(Flags<TextFormat>& format) const; 704 705 X StoreGlyph(const Pt& pt, const Glyph& glyph, const RenderState* render_state, 706 RenderCache& cache) const; 707 void StoreGlyphImpl(RenderCache& cache, GG::Clr color, const Pt& pt, 708 const Glyph& glyph, int x_top_offset, 709 int y_shift) const; 710 void StoreUnderlineImpl(RenderCache& cache, GG::Clr color, const Pt& pt, 711 const Glyph& glyph, Y descent, Y height, 712 Y underline_height, Y underline_offset) const; 713 714 void HandleTag(const std::shared_ptr<FormattingTag>& tag, double* orig_color, 715 RenderState& render_state) const; 716 bool IsDefaultFont(); 717 718 std::shared_ptr<Font> GetDefaultFont(unsigned int pts); 719 720 std::string m_font_filename; 721 unsigned int m_pt_sz; 722 std::vector<UnicodeCharset> 723 m_charsets; ///< The sets of glyphs that are covered by this font object 724 Y m_ascent; ///< Maximum amount above the baseline the text can go 725 Y m_descent; ///< Maximum amount below the baseline the text can go 726 Y m_height; ///< Ascent - descent 727 Y m_lineskip; ///< Distance that should be placed between lines 728 double m_underline_offset; ///< Amount below the baseline that the underline sits 729 double m_underline_height; ///< Height (thickness) of underline 730 double m_italics_offset; ///< Amount that the top of an italicized glyph is left of the bottom 731 double m_super_sub_offset; ///< Ammount to shift super or subscript text 732 double m_shadow_offset; ///< Amount that shadows rendered under texts are displaced from the text 733 X m_space_width; ///< The width of the glyph for the space character 734 GlyphMap m_glyphs; ///< The locations of the images of each glyph within the textures 735 736 /** The OpenGL texture object in which the glyphs can be found. */ 737 std::shared_ptr<Texture> m_texture; 738 }; 739 740 /** Stream output operator for Font::Substring. */ 741 GG_API std::ostream& operator<<(std::ostream& os, const Font::Substring& substr); 742 743 /** Returns the code point index of the <i>index</i>-th code point on line \a 744 line within the text represented by \a line_data. Returns the index of 745 the code point one past the end of the text if \a line or \a index are out 746 of bounds. */ 747 GG_API CPSize CodePointIndexOf(std::size_t line, CPSize index, 748 const std::vector<Font::LineData>& line_data); 749 750 /** Returns the string index of the <i>index</i>-th code point on line \a line 751 within the text represented by \a line_data. Returns the index of the 752 character one past the end of the text if \a line or \a index are out of 753 bounds. */ 754 GG_API StrSize StringIndexOf(std::size_t line, CPSize index, 755 const std::vector<Font::LineData>& line_data); 756 757 /** Returns the line L and the code point index within L of the 758 <i>index</i>-th code point within the text represented by \a line_data. 759 Returns (std::numeric_limits<std::size_t>::max(), INVALID_CP_SIZE) if \a 760 index is out of bounds. */ 761 GG_API std::pair<std::size_t, CPSize> 762 LinePositionOf(CPSize index, const std::vector<Font::LineData>& line_data); 763 764 765 /** \brief A singleton that loads and stores fonts for use by GG. 766 767 This class is essentially a very thin wrapper around a map of 768 Font smart pointers, keyed on font filename/point size pairs. The user 769 need only request a font through GetFont(); if the font at the requested 770 size needs to be created, the font is created at the requestd size, a 771 shared_ptr to it is kept, and a copy of the shared_ptr is returned. If 772 the font has been created at the desired size, but the request includes 773 code point range(s) not already created, the font at the requested size is 774 created with the union of the reqested and existing ranges, stored, and 775 returned as above; the only difference is that the original shared_ptr is 776 released. Due to the shared_ptr semantics, the object pointed to by the 777 shared_ptr is deleted if and only if the last shared_ptr that refers to it 778 is deleted. So any requested font can be used as long as the caller 779 desires, even when another caller tells the FontManager to free the 780 font. */ 781 class GG_API FontManager 782 { 783 private: 784 /** \brief This GG::FontManager-private struct is used as a key type for 785 the map of rendered fonts. */ 786 struct GG_API FontKey 787 { 788 FontKey(const std::string& str, unsigned int pts); ///< Ctor. 789 bool operator<(const FontKey& rhs) const; ///< Lexocograhpical ordering on filename then points. 790 791 std::string filename; ///< The name of the file from which this font was created. 792 unsigned int points; ///< The point size in which this font was rendered. 793 }; 794 795 public: 796 /** \name Accessors */ ///@{ 797 /** Returns true iff this manager contains a font with the given filename 798 and point size, regardless of charsets. */ 799 bool HasFont(const std::string& font_filename, unsigned int pts) const; 800 801 /** Returns true iff this manager contains a font with the given filename 802 and point size, containing the given charsets. */ 803 template <typename CharSetIter> 804 bool HasFont(const std::string& font_filename, unsigned int pts, 805 CharSetIter first, CharSetIter last) const; 806 //@} 807 808 /** \name Mutators */ ///@{ 809 /** Returns a shared_ptr to the requested font, supporting all printable 810 ASCII characters. \note May load font if unavailable at time of 811 request. */ 812 std::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts); 813 814 /** Returns a shared_ptr to the requested font, supporting all printable 815 ASCII characters, from the in-memory contents \a file_contents. \note 816 May load font if unavailable at time of request. */ 817 std::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts, 818 const std::vector<unsigned char>& file_contents); 819 820 /** Returns a shared_ptr to the requested font, supporting all the 821 code points in the UnicodeCharsets in the range [first, last). \note 822 May load font if unavailable at time of request. */ 823 template <typename CharSetIter> 824 std::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts, 825 CharSetIter first, CharSetIter last); 826 827 /** Returns a shared_ptr to the requested font, supporting all the code 828 points in the UnicodeCharsets in the range [first, last), from the 829 in-memory contents \a file_contents. \note May load font if 830 unavailable at time of request. */ 831 template <typename CharSetIter> 832 std::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts, 833 const std::vector<unsigned char>& file_contents, 834 CharSetIter first, CharSetIter last); 835 836 /** Removes the indicated font from the font manager. Due to shared_ptr 837 semantics, the font may not be deleted until much later. */ 838 void FreeFont(const std::string& font_filename, unsigned int pts); 839 //@} 840 841 private: 842 FontManager(); 843 template <typename CharSetIter> 844 std::shared_ptr<Font> GetFontImpl(const std::string& font_filename, unsigned int pts, 845 const std::vector<unsigned char>* file_contents, 846 CharSetIter first, CharSetIter last); 847 848 std::map<FontKey, std::shared_ptr<Font>> m_rendered_fonts; 849 850 static const std::shared_ptr<Font> EMPTY_FONT; 851 852 friend GG_API FontManager& GetFontManager(); 853 }; 854 855 /** Returns the singleton FontManager instance. */ 856 GG_API FontManager& GetFontManager(); 857 858 /** Thrown when initialization of the FreeType library fails. */ 859 GG_EXCEPTION(FailedFTLibraryInit); 860 861 namespace detail { 862 template <typename CharT, bool CharIsSigned = boost::is_signed<CharT>::value> 863 struct ValidUTFChar; 864 865 template <typename CharT> 866 struct ValidUTFChar<CharT, true> 867 { 868 bool operator()(CharT c) 869 { return 0x0 <= c; } 870 }; 871 872 template <typename CharT> 873 struct ValidUTFChar<CharT, false> 874 { 875 bool operator()(CharT c) 876 { return c <= 0x7f; } 877 }; 878 879 struct GG_API FTFaceWrapper 880 { 881 FTFaceWrapper(); 882 ~FTFaceWrapper(); 883 FT_Face m_face = nullptr; 884 }; 885 } 886 887 } // namespace GG 888 889 890 // template implementations 891 template <typename CharSetIter> 892 GG::Font::Font(const std::string& font_filename, unsigned int pts, 893 CharSetIter first, CharSetIter last) : 894 m_font_filename(font_filename), 895 m_pt_sz(pts), 896 m_charsets(first, last), 897 m_ascent(0), 898 m_descent(0), 899 m_height(0), 900 m_lineskip(0), 901 m_underline_offset(0.0), 902 m_underline_height(0.0), 903 m_italics_offset(0.0), 904 m_super_sub_offset(0.0), 905 m_shadow_offset(0.0), 906 m_space_width(0) 907 { 908 if (!m_font_filename.empty()) { 909 detail::FTFaceWrapper wrapper; 910 FT_Error error = GetFace(wrapper.m_face); 911 CheckFace(wrapper.m_face, error); 912 Init(wrapper.m_face); 913 } 914 } 915 916 template <typename CharSetIter> 917 GG::Font::Font(const std::string& font_filename, unsigned int pts, 918 const std::vector<unsigned char>& file_contents, 919 CharSetIter first, CharSetIter last) : 920 m_font_filename(font_filename), 921 m_pt_sz(pts), 922 m_charsets(first, last), 923 m_ascent(0), 924 m_descent(0), 925 m_height(0), 926 m_lineskip(0), 927 m_underline_offset(0.0), 928 m_underline_height(0.0), 929 m_italics_offset(0.0), 930 m_super_sub_offset(0.0), 931 m_shadow_offset(0.0), 932 m_space_width(0) 933 { 934 assert(!file_contents.empty()); 935 detail::FTFaceWrapper wrapper; 936 FT_Error error = GetFace(file_contents, wrapper.m_face); 937 CheckFace(wrapper.m_face, error); 938 Init(wrapper.m_face); 939 } 940 941 template <typename CharSetIter> 942 bool GG::FontManager::HasFont(const std::string& font_filename, unsigned int pts, 943 CharSetIter first, CharSetIter last) const 944 { 945 bool retval = false; 946 FontKey key(font_filename, pts); 947 auto it = m_rendered_fonts.find(key); 948 if (it != m_rendered_fonts.end()) { 949 std::set<UnicodeCharset> requested_charsets(first, last); 950 std::set<UnicodeCharset> found_charsets(it->second->UnicodeCharsets().begin(), 951 it->second->UnicodeCharsets().end()); 952 retval = requested_charsets == found_charsets; 953 } 954 return retval; 955 } 956 957 template <typename CharSetIter> 958 std::shared_ptr<GG::Font> 959 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts, 960 CharSetIter first, CharSetIter last) 961 { return GetFontImpl(font_filename, pts, nullptr, first, last); } 962 963 template <typename CharSetIter> 964 std::shared_ptr<GG::Font> 965 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts, 966 const std::vector<unsigned char>& file_contents, 967 CharSetIter first, CharSetIter last) 968 { return GetFontImpl(font_filename, pts, &file_contents, first, last); } 969 970 971 template <typename CharSetIter> 972 std::shared_ptr<GG::Font> 973 GG::FontManager::GetFontImpl(const std::string& font_filename, unsigned int pts, 974 const std::vector<unsigned char>* file_contents, 975 CharSetIter first, CharSetIter last) 976 { 977 FontKey key(font_filename, pts); 978 auto it = m_rendered_fonts.find(key); 979 if (it == m_rendered_fonts.end()) { // if no such font has been created, create it now 980 if (font_filename.empty()) { 981 // keeps this function from throwing; "" is the only invalid font 982 // filename that shouldn't throw 983 return EMPTY_FONT; 984 } else { 985 std::shared_ptr<Font> font( 986 file_contents ? 987 new Font(font_filename, pts, *file_contents, first, last) : 988 new Font(font_filename, pts, first, last) 989 ); 990 m_rendered_fonts[key] = font; 991 return m_rendered_fonts[key]; 992 } 993 // if a font like this has been created, but it doesn't have all the right 994 // glyphs, release it and create a new one 995 } else { 996 std::set<UnicodeCharset> requested_charsets(first, last); 997 std::set<UnicodeCharset> found_charsets(it->second->UnicodeCharsets().begin(), 998 it->second->UnicodeCharsets().end()); 999 if (requested_charsets != found_charsets) { 1000 std::vector<UnicodeCharset> united_charsets; 1001 std::set_union(requested_charsets.begin(), requested_charsets.end(), 1002 found_charsets.begin(), found_charsets.end(), 1003 std::back_inserter(united_charsets)); 1004 m_rendered_fonts.erase(it); 1005 std::shared_ptr<Font> font( 1006 file_contents ? 1007 new Font(font_filename, pts, *file_contents, 1008 united_charsets.begin(), united_charsets.end()) : 1009 new Font(font_filename, pts, 1010 united_charsets.begin(), united_charsets.end()) 1011 ); 1012 m_rendered_fonts[key] = font; 1013 return m_rendered_fonts[key]; 1014 } else { // otherwise, the font we found works, so just return it 1015 return it->second; 1016 } 1017 } 1018 } 1019 1020 #endif 1021