Font.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /* GG is a GUI for SDL and OpenGL.
00003    Copyright (C) 2003-2008 T. Zachary Laine
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public License
00007    as published by the Free Software Foundation; either version 2.1
00008    of the License, or (at your option) any later version.
00009    
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014     
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA
00019 
00020    If you do not wish to comply with the terms of the LGPL please
00021    contact the author as other terms are available for a fee.
00022     
00023    Zach Laine
00024    whatwasthataddress@gmail.com */
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         /* Returns the number of characters in the original string that the
00218            element represents. */
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 } // namespace GG
00704 
00705 
00706 // template implementations
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                 // take no action; the Font must have been uninitialized when saved
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()) { // if no such font has been created, create it now
00848         if (font_filename == "") {
00849             // keeps this function from throwing; "" is the only invalid font
00850             // filename that shouldn't throw
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     // if a font like this has been created, but it doesn't have all the right
00862     // glyphs, release it and create a new one
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 { // otherwise, the font we found works, so just return it
00883             return it->second;
00884         }
00885     }
00886 }
00887 
00888 #endif // _GG_Font_h_

Generated on Sat Mar 26 07:08:37 2011 for GG by  doxygen 1.5.9