GG: Font.h Source File

GG

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

Font.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /* GG is a GUI for SDL and 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
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 <set>
41 #include <stack>
42
43 #include <boost/unordered_map.hpp>
44
45
46 struct FT_FaceRec_;
47 typedef struct FT_FaceRec_* FT_Face;
48 typedef int FT_Error;
49
50 namespace GG {
51
54 GG_API std::string RgbaTag(const Clr& c);
55
56
122 class GG_API Font
123 {
124 public:
127 class GG_API Substring
128 {
129 public:
130 typedef std::pair<std::string::const_iterator, std::string::const_iterator> IterPair;
131
133 Substring();
134
136 Substring(const std::string& str_,
137 std::string::const_iterator first_,
138 std::string::const_iterator second_);
139
142 Substring(const std::string& str_, const IterPair& pair);
143
145 std::string::const_iterator begin() const;
146
148 std::string::const_iterator end() const;
149
151 bool empty() const;
152
154 std::size_t size() const;
155
157 operator std::string() const;
158
160 bool operator==(const std::string& rhs) const;
161
163 bool operator!=(const std::string& rhs) const;
164
168 Substring& operator+=(const IterPair& rhs);
169
170 private:
171 const std::string* str;
172 std::ptrdiff_t first;
173 std::ptrdiff_t second;
174
175 static const std::string EMPTY_STRING;
176 };
177
180 struct GG_API TextElement
181 {
184 enum TextElementType {
185 OPEN_TAG,
186 CLOSE_TAG,
187 TEXT,
188 WHITESPACE,
189
194 NEWLINE
195 };
196
199 TextElement(bool ws, bool nl);
200
201 virtual ~TextElement();
202
204 virtual TextElementType Type() const;
205
207 X Width() const;
208
209 /* Returns the number of characters in the original string that the
210 element represents. */
211 StrSize StringSize() const;
212
215 CPSize CodePointSize() const;
216
218 Substring text;
219
220 std::vector<X> widths;
221 const bool whitespace;
222 const bool newline;
223
224 protected:
225 TextElement();
226
227 private:
228 mutable X cached_width;
229 };
230
233 struct GG_API FormattingTag : TextElement
234 {
237 FormattingTag(bool close);
238
239 virtual TextElementType Type() const;
240
243 std::vector<Substring> params;
244
246 Substring tag_name;
247
249 const bool close_tag;
250
251 private:
252 FormattingTag();
253 };
254
260 struct GG_API LineData
261 {
262 LineData();
263
267 struct GG_API CharData
268 {
270 CharData();
271
273 CharData(X extent_, StrSize str_index, StrSize str_size, CPSize cp_index,
274 const std::vector<boost::shared_ptr<TextElement> >& tags_);
275
278 X extent;
279
282 StrSize string_index;
283
286 StrSize string_size;
287
289 CPSize code_point_index;
290
293 std::vector<boost::shared_ptr<FormattingTag> > tags;
294 };
295
296 X Width() const;
297 bool Empty() const;
298
300 std::vector<CharData> char_data;
301
304 Alignment justification;
305 };
306
312 struct GG_API RenderState
313 {
314 RenderState();
315
317 std::size_t use_italics;
318
320 std::size_t draw_underline;
321
323 std::stack<Clr> colors;
324 };
325
327
330 Font(const std::string& font_filename, unsigned int pts);
331
336 Font(const std::string& font_filename, unsigned int pts,
337 const std::vector<unsigned char>& file_contents);
338
343 template <class CharSetIter>
344 Font(const std::string& font_filename, unsigned int pts,
345 CharSetIter first, CharSetIter last);
346
352 template <class CharSetIter>
353 Font(const std::string& font_filename, unsigned int pts,
354 const std::vector<unsigned char>& file_contents,
355 CharSetIter first, CharSetIter last);
356
357 ~Font();
358
359
361
362 const std::string& FontName() const;
363
366 unsigned int PointSize() const;
367
369 const std::vector<UnicodeCharset>& UnicodeCharsets() const;
370
372 Y Ascent() const;
373
375 Y Descent() const;
376
378 Y Height() const;
379
382 Y Lineskip() const;
383
385 X SpaceWidth() const;
386
390 X RenderGlyph(const Pt& pt, char c) const;
391
393 X RenderGlyph(const Pt& pt, boost::uint32_t c) const;
394
397 X RenderText(const Pt& pt, const std::string& text) const;
398
400 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format,
401 const std::vector<LineData>* line_data = 0, RenderState* render_state = 0) const;
402
407 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format,
408 const std::vector<LineData>& line_data, RenderState& render_state,
409 std::size_t begin_line, CPSize begin_char,
410 std::size_t end_line, CPSize end_char) const;
411
414 void ProcessTagsBefore(const std::vector<LineData>& line_data, RenderState& render_state,
415 std::size_t begin_line, CPSize begin_char) const;
416
419 Pt DetermineLines(const std::string& text, Flags<TextFormat>& format, X box_width,
420 std::vector<LineData>& line_data) const;
421
425 Pt DetermineLines(const std::string& text, Flags<TextFormat>& format, X box_width,
426 std::vector<LineData>& line_data,
427 std::vector<boost::shared_ptr<TextElement> >& text_elements) const;
428
434 Pt DetermineLines(const std::string& text, Flags<TextFormat>& format, X box_width,
435 const std::vector<boost::shared_ptr<TextElement> >& text_elements,
436 std::vector<LineData>& line_data) const;
437
441 Pt TextExtent(const std::string& text, Flags<TextFormat> format = FORMAT_NONE,
442 X box_width = X0) const;
443
445 Pt TextExtent(const std::string& text, const std::vector<LineData>& line_data) const;
447
451 static void RegisterKnownTag(const std::string& tag);
452
455 static void RemoveKnownTag(const std::string& tag);
456
459 static void ClearKnownTags();
460
462
463 GG_ABSTRACT_EXCEPTION(Exception);
464
466 GG_CONCRETE_EXCEPTION(BadFile, GG::Font, Exception);
467
469 GG_CONCRETE_EXCEPTION(InvalidPointSize, GG::Font, Exception);
470
473 GG_CONCRETE_EXCEPTION(UnscalableFont, GG::Font, Exception);
474
477 GG_CONCRETE_EXCEPTION(BadFace, GG::Font, Exception);
478
481 GG_CONCRETE_EXCEPTION(BadPointSize, GG::Font, Exception);
482
485 GG_CONCRETE_EXCEPTION(BadGlyph, GG::Font, Exception);
487
492 static void ThrowBadGlyph(const std::string& format_str, boost::uint32_t c);
493
494 protected:
496 Font();
497
498
499 private:
502 struct Glyph
503 {
504 Glyph();
505 Glyph(const boost::shared_ptr<Texture>& texture, const Pt& ul, const Pt& lr, Y y_ofs,
506 X lb, X adv);
507
508 SubTexture sub_texture;
509 Y y_offset;
510 X left_bearing;
511 X advance;
512 X width;
513 };
514
515 typedef boost::unordered_map<boost::uint32_t, Glyph> GlyphMap;
516
517 Pt DetermineLinesImpl(const std::string& text,
518 Flags<TextFormat>& format,
519 X box_width,
520 std::vector<LineData>& line_data,
521 std::vector<boost::shared_ptr<TextElement> >* text_elements_ptr) const;
522
523 FT_Error GetFace(FT_Face& face);
524 FT_Error GetFace(const std::vector<unsigned char>& file_contents, FT_Face& face);
525 void CheckFace(FT_Face font, FT_Error error);
526 void Init(FT_Face& font);
527 bool GenerateGlyph(FT_Face font, boost::uint32_t ch);
528 void ValidateFormat(Flags<TextFormat>& format) const;
529 inline X RenderGlyph(const Pt& pt, const Glyph& glyph,
530 const RenderState* render_state) const;
531 void HandleTag(const boost::shared_ptr<FormattingTag>& tag, double* orig_color,
532 RenderState& render_state) const;
533 bool IsDefaultFont();
534 boost::shared_ptr<Font>
535 GetDefaultFont(unsigned int pts);
536
537 std::string m_font_filename;
538 unsigned int m_pt_sz;
539 std::vector<UnicodeCharset>
540 m_charsets;
541 Y m_ascent;
542 Y m_descent;
543 Y m_height;
544 Y m_lineskip;
545 double m_underline_offset;
546 double m_underline_height;
547 double m_italics_offset;
548 X m_space_width;
549 GlyphMap m_glyphs;
550 std::vector<boost::shared_ptr<Texture> >
551 m_textures;
552
553 static std::set<std::string> s_action_tags;
554 static std::set<std::string> s_known_tags;
555 };
556
558 GG_API std::ostream& operator<<(std::ostream& os, const Font::Substring& substr);
559
564 GG_API CPSize CodePointIndexOf(std::size_t line, CPSize index,
565 const std::vector<Font::LineData>& line_data);
566
571 GG_API StrSize StringIndexOf(std::size_t line, CPSize index,
572 const std::vector<Font::LineData>& line_data);
573
578 GG_API std::pair<std::size_t, CPSize>
579 LinePositionOf(CPSize index, const std::vector<Font::LineData>& line_data);
580
581
598 class GG_API FontManager
599 {
600 private:
603 struct GG_API FontKey
604 {
605 FontKey(const std::string& str, unsigned int pts);
606 bool operator<(const FontKey& rhs) const;
607
608 std::string filename;
609 unsigned int points;
610 };
611
612 public:
614
616 bool HasFont(const std::string& font_filename, unsigned int pts) const;
617
620 template <class CharSetIter>
621 bool HasFont(const std::string& font_filename, unsigned int pts,
622 CharSetIter first, CharSetIter last) const;
624
626
629 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts);
630
634 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
635 const std::vector<unsigned char>& file_contents);
636
640 template <class CharSetIter>
641 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
642 CharSetIter first, CharSetIter last);
643
648 template <class CharSetIter>
649 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
650 const std::vector<unsigned char>& file_contents,
651 CharSetIter first, CharSetIter last);
652
655 void FreeFont(const std::string& font_filename, unsigned int pts);
657
658 private:
659 FontManager();
660 template <class CharSetIter>
661 boost::shared_ptr<Font> GetFontImpl(const std::string& font_filename, unsigned int pts,
662 const std::vector<unsigned char>* file_contents,
663 CharSetIter first, CharSetIter last);
664
665 std::map<FontKey, boost::shared_ptr<Font> > m_rendered_fonts;
666
667 static const boost::shared_ptr<Font> EMPTY_FONT;
668
669 friend GG_API FontManager& GetFontManager();
670 };
671
673 GG_API FontManager& GetFontManager();
674
676 GG_EXCEPTION(FailedFTLibraryInit);
677
678 namespace detail {
679 template <class CharT, bool CharIsSigned = boost::is_signed<CharT>::value>
680 struct ValidUTFChar;
681
682 template <class CharT>
683 struct ValidUTFChar<CharT, true>
684 {
685 bool operator()(CharT c)
686 { return 0x0 <= c; }
687 };
688
689 template <class CharT>
690 struct ValidUTFChar<CharT, false>
691 {
692 bool operator()(CharT c)
693 { return c <= 0x7f; }
694 };
695
696 struct GG_API FTFaceWrapper
697 {
698 FTFaceWrapper();
699 ~FTFaceWrapper();
700 FT_Face m_face;
701 };
702 }
703
704 } // namespace GG
705
706
707 // template implementations
708 template <class CharSetIter>
709 GG::Font::Font(const std::string& font_filename, unsigned int pts,
710 CharSetIter first, CharSetIter last) :
711 m_font_filename(font_filename),
712 m_pt_sz(pts),
713 m_charsets(first, last),
714 m_ascent(0),
715 m_descent(0),
716 m_height(0),
717 m_lineskip(0),
718 m_underline_offset(0.0),
719 m_underline_height(0.0),
720 m_italics_offset(0.0),
721 m_space_width(0)
722 {
723 if (m_font_filename != "") {
724 detail::FTFaceWrapper wrapper;
725 FT_Error error = GetFace(wrapper.m_face);
726 CheckFace(wrapper.m_face, error);
727 Init(wrapper.m_face);
728 }
729 }
730
731 template <class CharSetIter>
732 GG::Font::Font(const std::string& font_filename, unsigned int pts,
733 const std::vector<unsigned char>& file_contents,
734 CharSetIter first, CharSetIter last) :
735 m_font_filename(font_filename),
736 m_pt_sz(pts),
737 m_charsets(first, last),
738 m_ascent(0),
739 m_descent(0),
740 m_height(0),
741 m_lineskip(0),
742 m_underline_offset(0.0),
743 m_underline_height(0.0),
744 m_italics_offset(0.0),
745 m_space_width(0)
746 {
747 assert(!file_contents.empty());
748 detail::FTFaceWrapper wrapper;
749 FT_Error error = GetFace(file_contents, wrapper.m_face);
750 CheckFace(wrapper.m_face, error);
751 Init(wrapper.m_face);
752 }
753
754 template <class CharSetIter>
755 bool GG::FontManager::HasFont(const std::string& font_filename, unsigned int pts,
756 CharSetIter first, CharSetIter last) const
757 {
758 bool retval = false;
759 FontKey key(font_filename, pts);
760 std::map<FontKey, boost::shared_ptr<Font> >::const_iterator it = m_rendered_fonts.find(key);
761 if (it != m_rendered_fonts.end()) {
762 std::set<UnicodeCharset> requested_charsets(first, last);
763 std::set<UnicodeCharset> found_charsets(it->second->UnicodeCharsets().begin(),
764 it->second->UnicodeCharsets().end());
765 retval = requested_charsets == found_charsets;
766 }
767 return retval;
768 }
769
770 template <class CharSetIter>
771 boost::shared_ptr<GG::Font>
772 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts,
773 CharSetIter first, CharSetIter last)
774 { return GetFontImpl(font_filename, pts, 0, first, last); }
775
776 template <class CharSetIter>
777 boost::shared_ptr<GG::Font>
778 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts,
779 const std::vector<unsigned char>& file_contents,
780 CharSetIter first, CharSetIter last)
781 { return GetFontImpl(font_filename, pts, &file_contents, first, last); }
782
783
784 template <class CharSetIter>
785 boost::shared_ptr<GG::Font>
786 GG::FontManager::GetFontImpl(const std::string& font_filename, unsigned int pts,
787 const std::vector<unsigned char>* file_contents,
788 CharSetIter first, CharSetIter last)
789 {
790 FontKey key(font_filename, pts);
791 std::map<FontKey, boost::shared_ptr<Font> >::iterator it = m_rendered_fonts.find(key);
792 if (it == m_rendered_fonts.end()) { // if no such font has been created, create it now
793 if (font_filename == "") {
794 // keeps this function from throwing; "" is the only invalid font
795 // filename that shouldn't throw
796 return EMPTY_FONT;
797 } else {
798 boost::shared_ptr<Font> font(
799 file_contents ?
800 new Font(font_filename, pts, *file_contents, first, last) :
801 new Font(font_filename, pts, first, last)
802 );
803 m_rendered_fonts[key] = font;
804 return m_rendered_fonts[key];
805 }
806 // if a font like this has been created, but it doesn't have all the right
807 // glyphs, release it and create a new one
808 } else {
809 std::set<UnicodeCharset> requested_charsets(first, last);
810 std::set<UnicodeCharset> found_charsets(it->second->UnicodeCharsets().begin(),
811 it->second->UnicodeCharsets().end());
812 if (requested_charsets != found_charsets) {
813 std::vector<UnicodeCharset> united_charsets;
814 std::set_union(requested_charsets.begin(), requested_charsets.end(),
815 found_charsets.begin(), found_charsets.end(),
816 std::back_inserter(united_charsets));
817 m_rendered_fonts.erase(it);
818 boost::shared_ptr<Font> font(
819 file_contents ?
820 new Font(font_filename, pts, *file_contents,
821 united_charsets.begin(), united_charsets.end()) :
822 new Font(font_filename, pts,
823 united_charsets.begin(), united_charsets.end())
824 );
825 m_rendered_fonts[key] = font;
826 return m_rendered_fonts[key];
827 } else { // otherwise, the font we found works, so just return it
828 return it->second;
829 }
830 }
831 }
832
833 #endif