00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00032 #ifndef _GG_Font_h_
00033 #define _GG_Font_h_
00034
00035 #include <GG/AlignmentFlags.h>
00036 #include <GG/FontFwd.h>
00037 #include <GG/Texture.h>
00038 #include <GG/UnicodeCharsets.h>
00039
00040 #include <set>
00041 #include <stack>
00042
00043 #include <boost/unordered_map.hpp>
00044 #include <boost/serialization/access.hpp>
00045
00046
00047 struct FT_FaceRec_;
00048 typedef struct FT_FaceRec_* FT_Face;
00049 typedef int FT_Error;
00050
00051 namespace GG {
00052
00055 GG_API std::string RgbaTag(const Clr& c);
00056
00057
00123 class GG_API Font
00124 {
00125 public:
00131 class GG_API Substring
00132 {
00133 public:
00134 typedef std::pair<std::string::const_iterator, std::string::const_iterator> IterPair;
00135
00137 Substring();
00138
00140 Substring(const std::string& str_,
00141 std::string::const_iterator first_,
00142 std::string::const_iterator second_);
00143
00146 Substring(const std::string& str_, const IterPair& pair);
00147
00149 std::string::const_iterator begin() const;
00150
00152 std::string::const_iterator end() const;
00153
00155 bool empty() const;
00156
00158 std::size_t size() const;
00159
00161 operator std::string() const;
00162
00164 bool operator==(const std::string& rhs) const;
00165
00167 bool operator!=(const std::string& rhs) const;
00168
00172 Substring& operator+=(const IterPair& rhs);
00173
00174 private:
00175 const std::string* str;
00176 std::ptrdiff_t first;
00177 std::ptrdiff_t second;
00178
00179 static const std::string EMPTY_STRING;
00180
00181 friend class boost::serialization::access;
00182 template <class Archive>
00183 void serialize(Archive& ar, const unsigned int version);
00184 };
00185
00188 struct GG_API TextElement
00189 {
00192 enum TextElementType {
00193 OPEN_TAG,
00194 CLOSE_TAG,
00195 TEXT,
00196 WHITESPACE,
00197
00202 NEWLINE
00203 };
00204
00207 TextElement(bool ws, bool nl);
00208
00209 virtual ~TextElement();
00210
00212 virtual TextElementType Type() const;
00213
00215 X Width() const;
00216
00217
00218
00219 StrSize StringSize() const;
00220
00223 CPSize CodePointSize() const;
00224
00226 Substring text;
00227
00228 std::vector<X> widths;
00229 const bool whitespace;
00230 const bool newline;
00231
00232 protected:
00233 TextElement();
00234
00235 private:
00236 friend class boost::serialization::access;
00237 template <class Archive>
00238 void serialize(Archive& ar, const unsigned int version);
00239 };
00240
00243 struct GG_API FormattingTag : TextElement
00244 {
00247 FormattingTag(bool close);
00248
00249 virtual TextElementType Type() const;
00250
00253 std::vector<Substring> params;
00254
00256 Substring tag_name;
00257
00259 const bool close_tag;
00260
00261 private:
00262 FormattingTag();
00263 friend class boost::serialization::access;
00264 template <class Archive>
00265 void serialize(Archive& ar, const unsigned int version);
00266 };
00267
00273 struct GG_API LineData
00274 {
00275 LineData();
00276
00280 struct GG_API CharData
00281 {
00283 CharData();
00284
00286 CharData(X extent_, StrSize str_index, StrSize str_size, CPSize cp_index,
00287 const std::vector<boost::shared_ptr<TextElement> >& tags_);
00288
00291 X extent;
00292
00295 StrSize string_index;
00296
00299 StrSize string_size;
00300
00302 CPSize code_point_index;
00303
00306 std::vector<boost::shared_ptr<FormattingTag> > tags;
00307
00308 private:
00309 friend class boost::serialization::access;
00310 template <class Archive>
00311 void serialize(Archive& ar, const unsigned int version);
00312 };
00313
00314 X Width() const;
00315 bool Empty() const;
00316
00318 std::vector<CharData> char_data;
00319
00322 Alignment justification;
00323
00324 private:
00325 friend class boost::serialization::access;
00326 template <class Archive>
00327 void serialize(Archive& ar, const unsigned int version);
00328 };
00329
00335 struct GG_API RenderState
00336 {
00337 RenderState();
00338
00340 std::size_t use_italics;
00341
00343 std::size_t draw_underline;
00344
00346 std::stack<Clr> colors;
00347 };
00348
00350
00353 Font(const std::string& font_filename, unsigned int pts);
00354
00359 Font(const std::string& font_filename, unsigned int pts,
00360 const std::vector<unsigned char>& file_contents);
00361
00366 template <class CharSetIter>
00367 Font(const std::string& font_filename, unsigned int pts,
00368 CharSetIter first, CharSetIter last);
00369
00375 template <class CharSetIter>
00376 Font(const std::string& font_filename, unsigned int pts,
00377 const std::vector<unsigned char>& file_contents,
00378 CharSetIter first, CharSetIter last);
00379
00380 ~Font();
00381
00382
00384
00385 const std::string& FontName() const;
00386
00389 unsigned int PointSize() const;
00390
00392 const std::vector<UnicodeCharset>& UnicodeCharsets() const;
00393
00395 Y Ascent() const;
00396
00398 Y Descent() const;
00399
00401 Y Height() const;
00402
00405 Y Lineskip() const;
00406
00408 X SpaceWidth() const;
00409
00413 X RenderGlyph(const Pt& pt, char c) const;
00414
00416 X RenderGlyph(const Pt& pt, boost::uint32_t c) const;
00417
00420 X RenderText(const Pt& pt, const std::string& text) const;
00421
00423 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format,
00424 const std::vector<LineData>* line_data = 0, RenderState* render_state = 0) const;
00425
00430 void RenderText(const Pt& pt1, const Pt& pt2, const std::string& text, Flags<TextFormat>& format,
00431 const std::vector<LineData>& line_data, RenderState& render_state,
00432 std::size_t begin_line, CPSize begin_char,
00433 std::size_t end_line, CPSize end_char) const;
00434
00437 void ProcessTagsBefore(const std::vector<LineData>& line_data, RenderState& render_state,
00438 std::size_t begin_line, CPSize begin_char) const;
00439
00442 Pt DetermineLines(const std::string& text, Flags<TextFormat>& format, X box_width,
00443 std::vector<LineData>& line_data) const;
00444
00448 Pt TextExtent(const std::string& text, Flags<TextFormat> format = FORMAT_NONE,
00449 X box_width = X0) const;
00450
00452 Pt TextExtent(const std::string& text, const std::vector<LineData>& line_data) const;
00454
00458 static void RegisterKnownTag(const std::string& tag);
00459
00462 static void RemoveKnownTag(const std::string& tag);
00463
00466 static void ClearKnownTags();
00467
00469
00470 GG_ABSTRACT_EXCEPTION(Exception);
00471
00473 GG_CONCRETE_EXCEPTION(BadFile, GG::Font, Exception);
00474
00476 GG_CONCRETE_EXCEPTION(InvalidPointSize, GG::Font, Exception);
00477
00480 GG_CONCRETE_EXCEPTION(UnscalableFont, GG::Font, Exception);
00481
00484 GG_CONCRETE_EXCEPTION(BadFace, GG::Font, Exception);
00485
00488 GG_CONCRETE_EXCEPTION(BadPointSize, GG::Font, Exception);
00489
00492 GG_CONCRETE_EXCEPTION(BadGlyph, GG::Font, Exception);
00494
00499 static void ThrowBadGlyph(const std::string& format_str, boost::uint32_t c);
00500
00501 protected:
00503 Font();
00504
00505
00506 private:
00509 struct Glyph
00510 {
00511 Glyph();
00512 Glyph(const boost::shared_ptr<Texture>& texture, const Pt& ul, const Pt& lr,
00513 X lb, X adv);
00514
00515 SubTexture sub_texture;
00516 X left_bearing;
00517 X advance;
00518 X width;
00519 };
00520
00521 typedef boost::unordered_map<boost::uint32_t, Glyph> GlyphMap;
00522
00523 FT_Error GetFace(FT_Face& face);
00524 FT_Error GetFace(const std::vector<unsigned char>& file_contents, FT_Face& face);
00525 void CheckFace(FT_Face font, FT_Error error);
00526 void Init(FT_Face& font);
00527 bool GenerateGlyph(FT_Face font, boost::uint32_t ch);
00528 void ValidateFormat(Flags<TextFormat>& format) const;
00529 inline X RenderGlyph(const Pt& pt, const Glyph& glyph,
00530 const RenderState* render_state) const;
00531 void HandleTag(const boost::shared_ptr<FormattingTag>& tag, double* orig_color,
00532 RenderState& render_state) const;
00533 bool IsDefaultFont();
00534 boost::shared_ptr<Font>
00535 GetDefaultFont(unsigned int pts);
00536
00537 std::string m_font_filename;
00538 unsigned int m_pt_sz;
00539 std::vector<UnicodeCharset>
00540 m_charsets;
00541 Y m_ascent;
00542 Y m_descent;
00543 Y m_height;
00544 Y m_lineskip;
00545 double m_underline_offset;
00546 double m_underline_height;
00547 double m_italics_offset;
00548 X m_space_width;
00549 GlyphMap m_glyphs;
00550 std::vector<boost::shared_ptr<Texture> >
00551 m_textures;
00552
00553 static std::set<std::string> s_action_tags;
00554 static std::set<std::string> s_known_tags;
00555
00556 friend class boost::serialization::access;
00557 template <class Archive>
00558 void serialize(Archive& ar, const unsigned int version);
00559 };
00560
00562 GG_API std::ostream& operator<<(std::ostream& os, const Font::Substring& substr);
00563
00568 GG_API CPSize CodePointIndexOf(std::size_t line, CPSize index,
00569 const std::vector<Font::LineData>& line_data);
00570
00575 GG_API StrSize StringIndexOf(std::size_t line, CPSize index,
00576 const std::vector<Font::LineData>& line_data);
00577
00582 GG_API std::pair<std::size_t, CPSize>
00583 LinePositionOf(CPSize index, const std::vector<Font::LineData>& line_data);
00584
00585
00602 class GG_API FontManager
00603 {
00604 private:
00607 struct GG_API FontKey
00608 {
00609 FontKey(const std::string& str, unsigned int pts);
00610 bool operator<(const FontKey& rhs) const;
00611
00612 std::string filename;
00613 unsigned int points;
00614 };
00615
00616 public:
00618
00621 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts);
00622
00626 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
00627 const std::vector<unsigned char>& file_contents);
00628
00632 template <class CharSetIter>
00633 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
00634 CharSetIter first, CharSetIter last);
00635
00640 template <class CharSetIter>
00641 boost::shared_ptr<Font> GetFont(const std::string& font_filename, unsigned int pts,
00642 const std::vector<unsigned char>& file_contents,
00643 CharSetIter first, CharSetIter last);
00644
00647 void FreeFont(const std::string& font_filename, unsigned int pts);
00649
00650 private:
00651 FontManager();
00652 template <class CharSetIter>
00653 boost::shared_ptr<Font> GetFontImpl(const std::string& font_filename, unsigned int pts,
00654 const std::vector<unsigned char>* file_contents,
00655 CharSetIter first, CharSetIter last);
00656
00657 std::map<FontKey, boost::shared_ptr<Font> > m_rendered_fonts;
00658
00659 static const boost::shared_ptr<Font> EMPTY_FONT;
00660
00661 friend GG_API FontManager& GetFontManager();
00662 };
00663
00665 GG_API FontManager& GetFontManager();
00666
00668 GG_EXCEPTION(FailedFTLibraryInit);
00669
00670 namespace detail {
00671 template <class CharT, bool CharIsSigned = boost::is_signed<CharT>::value>
00672 struct ValidUTFChar;
00673
00674 template <class CharT>
00675 struct ValidUTFChar<CharT, true>
00676 {
00677 bool operator()(CharT c)
00678 { return 0x0 <= c; }
00679 };
00680
00681 template <class CharT>
00682 struct ValidUTFChar<CharT, false>
00683 {
00684 bool operator()(CharT c)
00685 { return c <= 0x7f; }
00686 };
00687
00688 struct SerializableString : public std::string
00689 {
00690 template <class Archive>
00691 void serialize(Archive& ar, const unsigned int version)
00692 { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(std::string); }
00693 };
00694
00695 struct GG_API FTFaceWrapper
00696 {
00697 FTFaceWrapper();
00698 ~FTFaceWrapper();
00699 FT_Face m_face;
00700 };
00701 }
00702
00703 }
00704
00705
00706
00707 template <class Archive>
00708 void GG::Font::Substring::serialize(Archive& ar, const unsigned int version)
00709 {
00710 detail::SerializableString* mutable_str =
00711 static_cast<detail::SerializableString*>(const_cast<std::string*>(str));
00712 ar & BOOST_SERIALIZATION_NVP(mutable_str)
00713 & BOOST_SERIALIZATION_NVP(first)
00714 & BOOST_SERIALIZATION_NVP(second);
00715 if (Archive::is_loading::value)
00716 str = mutable_str;
00717 }
00718
00719 template <class Archive>
00720 void GG::Font::TextElement::serialize(Archive& ar, const unsigned int version)
00721 {
00722 ar & BOOST_SERIALIZATION_NVP(text)
00723 & BOOST_SERIALIZATION_NVP(widths)
00724 & boost::serialization::make_nvp("whitespace", const_cast<bool&>(whitespace))
00725 & boost::serialization::make_nvp("newline", const_cast<bool&>(newline));
00726 }
00727
00728 template <class Archive>
00729 void GG::Font::FormattingTag::serialize(Archive& ar, const unsigned int version)
00730 {
00731 ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(TextElement)
00732 & BOOST_SERIALIZATION_NVP(params)
00733 & BOOST_SERIALIZATION_NVP(tag_name)
00734 & boost::serialization::make_nvp("close_tag", const_cast<bool&>(close_tag));
00735 }
00736
00737 template <class Archive>
00738 void GG::Font::LineData::CharData::serialize(Archive& ar, const unsigned int version)
00739 {
00740 ar & BOOST_SERIALIZATION_NVP(extent)
00741 & BOOST_SERIALIZATION_NVP(string_index)
00742 & BOOST_SERIALIZATION_NVP(string_size)
00743 & BOOST_SERIALIZATION_NVP(code_point_index)
00744 & BOOST_SERIALIZATION_NVP(tags);
00745 }
00746
00747 template <class Archive>
00748 void GG::Font::LineData::serialize(Archive& ar, const unsigned int version)
00749 {
00750 ar & BOOST_SERIALIZATION_NVP(char_data)
00751 & BOOST_SERIALIZATION_NVP(justification);
00752 }
00753
00754 template <class CharSetIter>
00755 GG::Font::Font(const std::string& font_filename, unsigned int pts,
00756 CharSetIter first, CharSetIter last) :
00757 m_font_filename(font_filename),
00758 m_pt_sz(pts),
00759 m_charsets(first, last),
00760 m_ascent(0),
00761 m_descent(0),
00762 m_height(0),
00763 m_lineskip(0),
00764 m_underline_offset(0.0),
00765 m_underline_height(0.0),
00766 m_italics_offset(0.0),
00767 m_space_width(0)
00768 {
00769 if (m_font_filename != "") {
00770 detail::FTFaceWrapper wrapper;
00771 FT_Error error = GetFace(wrapper.m_face);
00772 CheckFace(wrapper.m_face, error);
00773 Init(wrapper.m_face);
00774 }
00775 }
00776
00777 template <class CharSetIter>
00778 GG::Font::Font(const std::string& font_filename, unsigned int pts,
00779 const std::vector<unsigned char>& file_contents,
00780 CharSetIter first, CharSetIter last) :
00781 m_font_filename(font_filename),
00782 m_pt_sz(pts),
00783 m_charsets(first, last),
00784 m_ascent(0),
00785 m_descent(0),
00786 m_height(0),
00787 m_lineskip(0),
00788 m_underline_offset(0.0),
00789 m_underline_height(0.0),
00790 m_italics_offset(0.0),
00791 m_space_width(0)
00792 {
00793 assert(!file_contents.empty());
00794 detail::FTFaceWrapper wrapper;
00795 FT_Error error = GetFace(file_contents, wrapper.m_face);
00796 CheckFace(wrapper.m_face, error);
00797 Init(wrapper.m_face);
00798 }
00799
00800 template <class Archive>
00801 void GG::Font::serialize(Archive& ar, const unsigned int version)
00802 {
00803 ar & BOOST_SERIALIZATION_NVP(m_font_filename)
00804 & BOOST_SERIALIZATION_NVP(m_pt_sz)
00805 & BOOST_SERIALIZATION_NVP(m_charsets);
00806
00807 if (Archive::is_loading::value) {
00808 if (!m_font_filename.empty() && 0 < m_pt_sz) {
00809 try {
00810 if (IsDefaultFont()) {
00811 *this = *GetDefaultFont(m_pt_sz);
00812 } else if (m_font_filename != "") {
00813 detail::FTFaceWrapper wrapper;
00814 FT_Error error = GetFace(wrapper.m_face);
00815 CheckFace(wrapper.m_face, error);
00816 Init(wrapper.m_face);
00817 }
00818 } catch (const Exception& e) {
00819
00820 }
00821 }
00822 }
00823 }
00824
00825 template <class CharSetIter>
00826 boost::shared_ptr<GG::Font>
00827 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts,
00828 CharSetIter first, CharSetIter last)
00829 { return GetFontImpl(font_filename, pts, 0, first, last); }
00830
00831 template <class CharSetIter>
00832 boost::shared_ptr<GG::Font>
00833 GG::FontManager::GetFont(const std::string& font_filename, unsigned int pts,
00834 const std::vector<unsigned char>& file_contents,
00835 CharSetIter first, CharSetIter last)
00836 { return GetFontImpl(font_filename, pts, &file_contents, first, last); }
00837
00838
00839 template <class CharSetIter>
00840 boost::shared_ptr<GG::Font>
00841 GG::FontManager::GetFontImpl(const std::string& font_filename, unsigned int pts,
00842 const std::vector<unsigned char>* file_contents,
00843 CharSetIter first, CharSetIter last)
00844 {
00845 FontKey key(font_filename, pts);
00846 std::map<FontKey, boost::shared_ptr<Font> >::iterator it = m_rendered_fonts.find(key);
00847 if (it == m_rendered_fonts.end()) {
00848 if (font_filename == "") {
00849
00850
00851 return EMPTY_FONT;
00852 } else {
00853 boost::shared_ptr<Font> font(
00854 file_contents ?
00855 new Font(font_filename, pts, *file_contents, first, last) :
00856 new Font(font_filename, pts, first, last)
00857 );
00858 m_rendered_fonts[key] = font;
00859 return m_rendered_fonts[key];
00860 }
00861
00862
00863 } else {
00864 std::set<UnicodeCharset> requested_charsets(first, last);
00865 std::set<UnicodeCharset> found_charsets(it->second->UnicodeCharsets().begin(),
00866 it->second->UnicodeCharsets().end());
00867 if (requested_charsets != found_charsets) {
00868 std::vector<UnicodeCharset> united_charsets;
00869 std::set_union(requested_charsets.begin(), requested_charsets.end(),
00870 found_charsets.begin(), found_charsets.end(),
00871 std::back_inserter(united_charsets));
00872 m_rendered_fonts.erase(it);
00873 boost::shared_ptr<Font> font(
00874 file_contents ?
00875 new Font(font_filename, pts, *file_contents,
00876 united_charsets.begin(), united_charsets.end()) :
00877 new Font(font_filename, pts,
00878 united_charsets.begin(), united_charsets.end())
00879 );
00880 m_rendered_fonts[key] = font;
00881 return m_rendered_fonts[key];
00882 } else {
00883 return it->second;
00884 }
00885 }
00886 }
00887
00888 #endif // _GG_Font_h_