Changeset 704

Show
Ignore:
Timestamp:
06/29/08 06:58:48 (8 weeks ago)
Author:
artem
Message:

applied font fallback patch from Beau Gunderson

Location:
trunk
Files:
8 modified

Legend:

Unmodified
Added
Removed
  • trunk/include/mapnik/font_engine_freetype.hpp

    r702 r704  
    3131#include <mapnik/geometry.hpp> 
    3232#include <mapnik/text_path.hpp> 
     33#include <mapnik/font_set.hpp> 
    3334 
    3435// freetype2 
     
    6263    { 
    6364    public: 
    64         typedef std::pair<unsigned,unsigned> dimension_t; 
    65  
    66         font_face(FT_Face face) 
     65        font_face(FT_Face face) 
    6766            : face_(face) {} 
    6867         
     
    105104        } 
    106105               
     106        ~font_face() 
     107        { 
     108#ifdef MAPNIK_DEBUG 
     109            std::clog << "~font_face: Clean up face \"" << family_name() 
     110                << " " << style_name() << "\"" << std::endl; 
     111#endif 
     112            FT_Done_Face(face_); 
     113        } 
     114         
     115    private: 
     116        FT_Face face_; 
     117    }; 
     118     
     119    typedef boost::shared_ptr<font_face> face_ptr; 
     120    
     121    class MAPNIK_DECL freetype_engine  // : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>, 
     122         // private boost::noncopyable 
     123    { 
     124       // friend class mapnik::CreateStatic<freetype_engine>; 
     125      public: 
     126        static bool register_font(std::string const& file_name); 
     127        static std::vector<std::string> face_names (); 
     128        face_ptr create_face(std::string const& family_name); 
     129        virtual ~freetype_engine(); 
     130        freetype_engine(); 
     131      private: 
     132        FT_Library library_; 
     133        static boost::mutex mutex_; 
     134        static std::map<std::string,std::string> name2file_; 
     135    };  
     136     
     137    template <typename T> 
     138    class MAPNIK_DECL face_manager : private boost::noncopyable 
     139    { 
     140        typedef T font_engine_type; 
     141        typedef std::map<std::string,face_ptr> faces; 
     142         
     143    public: 
     144        face_manager(T & engine) 
     145           : engine_(engine) {} 
     146         
     147        face_ptr get_face(std::string const& name) 
     148        { 
     149            typename faces::iterator itr; 
     150            itr = faces_.find(name); 
     151            if (itr != faces_.end()) 
     152            { 
     153                return itr->second; 
     154            } 
     155            else 
     156            { 
     157                face_ptr face = engine_.create_face(name); 
     158                if (face) 
     159                { 
     160                    faces_.insert(make_pair(name,face)); 
     161                } 
     162                return face;     
     163            } 
     164        } 
     165    private: 
     166        faces faces_; 
     167        font_engine_type & engine_; 
     168    }; 
     169         
     170    template <typename T> 
     171    struct text_renderer : private boost::noncopyable 
     172    { 
     173        typedef std::pair<unsigned,unsigned> dimension_t; 
     174         
     175        struct glyph_t : boost::noncopyable 
     176        { 
     177            FT_Glyph image; 
     178            glyph_t(FT_Glyph image_) : image(image_) {} 
     179            ~glyph_t () { FT_Done_Glyph(image);} 
     180        }; 
     181         
     182        typedef boost::ptr_vector<glyph_t> glyphs_t; 
     183        typedef T pixmap_type; 
     184         
     185        text_renderer (pixmap_type & pixmap, std::vector<face_ptr> faces) 
     186            : pixmap_(pixmap), 
     187              faces_(faces), 
     188              fill_(0,0,0),  
     189              halo_fill_(255,255,255), 
     190              halo_radius_(0) {} 
     191 
    107192        dimension_t character_dimensions(const unsigned c) 
    108193        { 
     
    111196            FT_Error  error; 
    112197             
    113             FT_GlyphSlot slot = face_->glyph; 
    114              
    115198            pen.x = 0; 
    116199            pen.y = 0; 
     
    118201            FT_BBox glyph_bbox;  
    119202            FT_Glyph image; 
    120              
     203                     
     204            FT_Face face = (*faces_.begin())->get_face(); 
     205             
     206            FT_UInt glyph_index = FT_Get_Char_Index(face, c); 
     207                  
     208            // If there's no glyph_index we loop through the remaining fonts 
     209            // in the fontset looking for one. 
     210            if (!glyph_index) { 
     211                std::vector<face_ptr>::iterator itr = faces_.begin(); 
     212                std::vector<face_ptr>::iterator end = faces_.end(); 
     213                 
     214                ++itr; // Skip the first one, we already tried it. 
     215                 
     216                for (; itr != end; ++itr) 
     217                { 
     218                    FT_Face f = (*itr)->get_face(); 
     219                     
     220                    glyph_index = FT_Get_Char_Index(f, c); 
     221 
     222                    if (glyph_index) { 
     223                        face = f; 
     224                        break; 
     225                    } 
     226                } 
     227            } 
     228 
    121229            matrix.xx = (FT_Fixed)( 1 * 0x10000L );  
    122230            matrix.xy = (FT_Fixed)( 0 * 0x10000L );  
    123231            matrix.yx = (FT_Fixed)( 0 * 0x10000L );  
    124232            matrix.yy = (FT_Fixed)( 1 * 0x10000L ); 
    125                      
    126             FT_Set_Transform (face_,&matrix,&pen); 
    127              
    128             FT_UInt glyph_index = FT_Get_Char_Index( face_, c); 
    129              
    130             error = FT_Load_Glyph (face_,glyph_index,FT_LOAD_NO_HINTING);  
     233             
     234            FT_Set_Transform(face, &matrix, &pen); 
     235 
     236            error = FT_Load_Glyph (face, glyph_index, FT_LOAD_NO_HINTING);  
    131237            if ( error ) 
    132238                return dimension_t(0, 0); 
    133239             
    134             error = FT_Get_Glyph( face_->glyph, &image); 
     240            error = FT_Get_Glyph(face->glyph, &image); 
    135241            if ( error ) 
    136242                return dimension_t(0, 0); 
    137              
    138             FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);  
    139             FT_Done_Glyph(image);  
    140             return dimension_t(slot->advance.x >> 6, glyph_bbox.yMax - glyph_bbox.yMin); 
     243 
     244            FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);  
     245            FT_Done_Glyph(image); 
     246 
     247            unsigned tempx = face->glyph->advance.x >> 6; 
     248            unsigned tempy = glyph_bbox.yMax - glyph_bbox.yMin; 
     249 
     250            //std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl; 
     251 
     252            return dimension_t(tempx, tempy); 
    141253        } 
    142254         
     
    188300                        if ( *arabic.getBuffer() >= 0x0600 && *arabic.getBuffer() <= 0x06ff) 
    189301                        { 
    190                              
    191302                           UnicodeString shaped; 
    192303                           u_shapeArabic(arabic.getBuffer(),arabic.length(),shaped.getBuffer(arabic.length()),arabic.length(), 
     
    216327            info.set_dimensions(width, height); 
    217328        } 
    218          
    219         ~font_face() 
    220         { 
    221 #ifdef MAPNIK_DEBUG 
    222             std::clog << "clean up face:" << family_name()<<":" << style_name() << std::endl; 
    223 #endif 
    224             FT_Done_Face(face_); 
    225         } 
    226          
    227     private: 
    228         FT_Face face_; 
    229     }; 
    230      
    231    typedef boost::shared_ptr<font_face> face_ptr; 
    232    class MAPNIK_DECL freetype_engine  // : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>, 
    233          // private boost::noncopyable 
    234     { 
    235        // friend class mapnik::CreateStatic<freetype_engine>; 
    236       public: 
    237         static bool register_font(std::string const& file_name); 
    238         static std::vector<std::string> face_names (); 
    239         face_ptr create_face(std::string const& family_name); 
    240         virtual ~freetype_engine(); 
    241         freetype_engine(); 
    242       private: 
    243         FT_Library library_; 
    244         static boost::mutex mutex_; 
    245         static std::map<std::string,std::string> name2file_; 
    246     };  
    247      
    248     template <typename T> 
    249     class MAPNIK_DECL face_manager : private boost::noncopyable 
    250     { 
    251         typedef T font_engine_type; 
    252         typedef std::map<std::string,face_ptr> faces; 
    253          
    254     public: 
    255         face_manager(T & engine) 
    256            : engine_(engine) {} 
    257          
    258         face_ptr get_face(std::string const& name) 
    259         { 
    260             typename faces::iterator itr; 
    261             itr = faces_.find(name); 
    262             if (itr != faces_.end()) 
    263             { 
    264                 return itr->second; 
    265             } 
    266             else 
    267             { 
    268                 face_ptr face = engine_.create_face(name); 
    269                 if (face) 
    270                 { 
    271                     faces_.insert(make_pair(name,face)); 
    272                 } 
    273                 return face;     
    274             } 
    275         } 
    276     private: 
    277         faces faces_; 
    278         font_engine_type & engine_; 
    279     }; 
    280          
    281     template <typename T> 
    282     struct text_renderer : private boost::noncopyable 
    283     { 
    284         struct glyph_t : boost::noncopyable 
    285         { 
    286             FT_Glyph image; 
    287             glyph_t(FT_Glyph image_) : image(image_) {} 
    288             ~glyph_t () { FT_Done_Glyph(image);} 
    289         }; 
    290          
    291         typedef boost::ptr_vector<glyph_t> glyphs_t; 
    292         typedef T pixmap_type; 
    293          
    294         text_renderer (pixmap_type & pixmap, face_ptr face) 
    295             : pixmap_(pixmap), 
    296               face_(face), 
    297               fill_(0,0,0),  
    298               halo_fill_(255,255,255), 
    299               halo_radius_(0) {} 
    300      
     329 
    301330        void set_pixel_size(unsigned size) 
    302331        { 
    303             face_->set_pixel_sizes(size); 
     332            std::vector<face_ptr>::iterator itr = faces_.begin(); 
     333            std::vector<face_ptr>::iterator end = faces_.end(); 
     334            for (; itr != end; ++itr) 
     335            { 
     336                (*itr)->set_pixel_sizes(size); 
     337            } 
    304338        } 
    305339     
     
    327361            FT_Vector pen; 
    328362            FT_Error  error; 
    329              
    330             FT_Face face = face_->get_face(); 
    331             //            FT_GlyphSlot slot = face->glyph; 
    332              
     363 
    333364            FT_BBox bbox;    
    334             bbox.xMin = bbox.yMin = 32000;  
    335             bbox.xMax = bbox.yMax = -32000; //hmm??  
    336              
     365            bbox.xMin = bbox.yMin = 32000;  // Initialize these so we can tell if we 
     366            bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later 
     367             
     368            std::vector<face_ptr>::iterator end = faces_.end(); 
     369             
    337370            for (int i = 0; i < path->num_nodes(); i++)  
    338371            { 
    339372                int c; 
    340373                double x, y, angle; 
    341                  
     374 
    342375                path->vertex(&c, &x, &y, &angle); 
    343 //                std::clog << "   prepare_glyph: " << (unsigned char)c << "," << x << "," << y << "," << angle << std::endl; 
    344  
     376 
     377#ifdef MAPNIK_DEBUG 
     378                // TODO Enable when we have support for setting verbosity 
     379                //std::clog << "prepare_glyphs: " << c << "," << x <<  
     380                //    "," << y << "," << angle << std::endl; 
     381#endif 
    345382 
    346383                FT_BBox glyph_bbox;  
     
    350387                pen.y = int(y * 64); 
    351388                         
     389                FT_Face face = (*faces_.begin())->get_face(); 
     390 
     391                FT_UInt glyph_index = FT_Get_Char_Index(face, unsigned(c)); 
     392                      
     393                // If there's no glyph_index we loop through the remaining fonts 
     394                // in the fontset looking for one. 
     395                if (!glyph_index) { 
     396                    std::vector<face_ptr>::iterator itr = faces_.begin(); 
     397                    ++itr; // Skip the first one, we already tried it. 
     398                     
     399                    for (; itr != end; ++itr) 
     400                    { 
     401#ifdef MAPNIK_DEBUG 
     402                        // TODO Enable when we have support for setting verbosity 
     403                        //std::clog << "prepare_glyphs: Falling back to font named \"" 
     404                        //    << (*itr)->family_name() << " " << (*itr)->style_name() 
     405                        //    << "\"" << std::endl; 
     406#endif 
     407 
     408                        FT_Face f = (*itr)->get_face(); 
     409                         
     410                        glyph_index = FT_Get_Char_Index(f, unsigned(c)); 
     411 
     412                        if (glyph_index) { 
     413                            face = f; 
     414                            break; 
     415                        } 
     416                    } 
     417 
     418#ifdef MAPNIK_DEBUG 
     419                    // TODO Enable when we have support for setting verbosity 
     420                    //if (!glyph_index) { 
     421                    //    std::clog << "prepare_glyphs: Failed to fall back, glyph " 
     422                    //        << c << " not found in any font." << std::endl; 
     423                    //} 
     424#endif 
     425                } 
     426 
    352427                matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );  
    353428                matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );  
    354429                matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );  
    355430                matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); 
    356                  
    357                 FT_Set_Transform (face,&matrix,&pen); 
    358                  
    359                 FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(c)); 
    360                  
    361                 error = FT_Load_Glyph (face,glyph_index, FT_LOAD_NO_HINTING);  
     431 
     432                FT_Set_Transform(face, &matrix, &pen); 
     433 
     434                error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_HINTING);  
    362435                if ( error ) 
    363436                    continue; 
    364                  
    365                 error = FT_Get_Glyph( face->glyph, &image); 
     437 
     438                error = FT_Get_Glyph(face->glyph, &image); 
    366439                if ( error ) 
    367440                    continue; 
    368                  
     441 
    369442                FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);  
    370443                if (glyph_bbox.xMin < bbox.xMin)  
     
    376449                if (glyph_bbox.yMax > bbox.yMax)  
    377450                    bbox.yMax = glyph_bbox.yMax; 
    378                  
     451         
     452                // Check if we properly grew the bbox 
    379453                if ( bbox.xMin > bbox.xMax ) 
    380454                { 
     
    485559     
    486560        pixmap_type & pixmap_; 
    487         face_ptr face_; 
     561        std::vector<face_ptr> faces_; 
    488562        mapnik::Color fill_; 
    489563        mapnik::Color halo_fill_; 
     
    495569} 
    496570 
    497  
    498571#endif // FONT_ENGINE_FREETYPE_HPP 
  • trunk/include/mapnik/map.hpp

    r702 r704  
    4545        boost::optional<Color> background_; 
    4646        std::map<std::string,feature_type_style> styles_; 
     47        std::map<std::string,FontSet> fontsets_; 
    4748        std::vector<Layer> layers_; 
    4849        Envelope<double> currentExtent_; 
     
    129130         */ 
    130131        feature_type_style const& find_style(std::string const& name) const; 
     132 
     133        /*! \brief Insert a fontset into the map. 
     134         *  @param name The name of the fontset. 
     135         *  @param style The fontset to insert. 
     136         *  @return true If success. 
     137         *  @return false If failure. 
     138         */ 
     139        bool insert_fontset(std::string const& name, FontSet const& fontset); 
     140        
     141        /*! \brief Find a fontset. 
     142         *  @param name The name of the fontset. 
     143         *  @return The fontset if found. If not found return the default map fontset. 
     144         */ 
     145        FontSet const& find_fontset(std::string const& name) const; 
    131146 
    132147        /*! \brief Get number of all layers. 
  • trunk/include/mapnik/text_symbolizer.hpp

    r702 r704  
    2828#include <mapnik/enumeration.hpp> 
    2929#include <mapnik/color.hpp> 
    30 #include <mapnik/graphics.hpp>  
     30#include <mapnik/font_set.hpp> 
     31#include <mapnik/graphics.hpp> 
    3132// boost 
    3233#include <boost/tuple/tuple.hpp> 
     
    5051         text_symbolizer(std::string const& name,std::string const& face_name,  
    5152                         unsigned size, Color const& fill);      
     53         text_symbolizer(std::string const& name, unsigned size, Color const& fill);     
    5254         text_symbolizer(text_symbolizer const& rhs); 
    5355         text_symbolizer& operator=(text_symbolizer const& rhs); 
     
    6769         unsigned get_text_size() const; 
    6870         std::string const& get_face_name() const; 
     71         void set_face_name(std::string face_name); 
     72         FontSet const& get_fontset() const; 
     73         void set_fontset(FontSet fontset); 
    6974         Color const& get_fill() const; 
    7075         void set_halo_fill(Color const& fill); 
     
    8792         std::string name_; 
    8893         std::string face_name_; 
     94         FontSet fontset_; 
    8995         unsigned size_; 
    9096         unsigned text_ratio_; 
  • trunk/src/SConscript

    r702 r704  
    4848    filter_factory.cpp 
    4949    font_engine_freetype.cpp 
     50    font_set.cpp 
    5051    graphics.cpp 
    5152    image_reader.cpp 
  • trunk/src/agg_renderer.cpp

    r703 r704  
    3030#include <mapnik/arrow.hpp> 
    3131#include <mapnik/config_error.hpp> 
     32#include <mapnik/font_set.hpp> 
    3233 
    3334// agg 
     
    281282               frame->move_to(itr->get<0>(),itr->get<1>()); 
    282283               frame->line_to(itr->get<0>(),itr->get<1>()+height);    
    283                 
    284284            } 
    285285             
     
    311311            ren.color(agg::rgba8(r, g, b, int(255 * sym.get_opacity()))); 
    312312            agg::render_scanlines(*ras_ptr, sl, ren); 
    313              
    314313         } 
    315314      } 
     
    461460      if (text.length() > 0 && data) 
    462461      { 
    463          face_ptr face = font_manager_.get_face(sym.get_face_name()); 
    464          if (face) 
    465          { 
    466             text_renderer<mapnik::Image32> ren(pixmap_,face); 
     462         std::vector<face_ptr> faces; 
     463                         
     464         faces.push_back(font_manager_.get_face(sym.get_face_name())); 
     465          
     466         if (faces.size() > 0) 
     467         { 
     468            text_renderer<mapnik::Image32> ren(pixmap_, faces); 
     469             
    467470            ren.set_pixel_size(sym.get_text_size()); 
    468471            ren.set_fill(sym.get_fill()); 
    469472             
    470473            string_info info(text); 
    471             face->get_string_info(info); 
     474 
     475            ren.get_string_info(info); 
    472476             
    473477            placement_finder<label_collision_detector4> finder(detector_); 
     
    670674      if ( text.length() > 0 ) 
    671675      { 
    672          Color const& fill  = sym.get_fill(); 
    673          face_ptr face = font_manager_.get_face(sym.get_face_name()); 
    674          if (face) 
    675          { 
    676             text_renderer<mapnik::Image32> ren(pixmap_,face); 
     676         Color const& fill = sym.get_fill(); 
     677 
     678         std::vector<face_ptr> faces; 
     679     
     680         FontSet fontset = sym.get_fontset(); 
     681         std::vector<std::string> face_names = fontset.get_face_names(); 
     682     
     683         if (face_names.size() > 0) 
     684         { 
     685            std::vector<std::string>::iterator itr = face_names.begin(); 
     686            std::vector<std::string>::iterator end = face_names.end(); 
     687 
     688            for (; itr != end; ++itr) 
     689            { 
     690               faces.push_back(font_manager_.get_face(*itr)); 
     691            } 
     692         } 
     693         else  
     694         { 
     695            faces.push_back(font_manager_.get_face(sym.get_face_name())); 
     696         } 
     697      
     698         if (faces.size() > 0) 
     699         { 
     700            text_renderer<mapnik::Image32> ren(pixmap_, faces); 
    677701            ren.set_pixel_size(sym.get_text_size()); 
    678702            ren.set_fill(fill); 
     
    683707            
    684708            string_info info(text); 
    685             face->get_string_info(info); 
     709             
     710            ren.get_string_info(info); 
    686711            unsigned num_geom = feature.num_geometries(); 
    687712            for (unsigned i=0;i<num_geom;++i) 
  • trunk/src/load_map.cpp

    r703 r704  
    3030#include <mapnik/datasource_cache.hpp> 
    3131#include <mapnik/font_engine_freetype.hpp> 
     32#include <mapnik/font_set.hpp> 
    3233 
    3334#include <mapnik/ptree_helpers.hpp> 
     
    6768         void parse_style( Map & map, ptree const & sty); 
    6869         void parse_layer( Map & map, ptree const & lay); 
    69           
     70         
     71         void parse_fontset(Map & map, ptree const & fset); 
     72         void parse_font(FontSet & fset, ptree const & f); 
     73      
    7074         void parse_rule( feature_type_style & style, ptree const & r); 
    7175          
     
    8084         void parse_markers_symbolizer( rule_type & rule, ptree const & sym ); 
    8185          
    82          void ensure_font_face( const text_symbolizer & text_symbol ); 
     86         void ensure_font_face( const std::string & face_name ); 
    8387          
    8488         bool strict_; 
     
    8791         face_manager<freetype_engine> font_manager_; 
    8892         std::map<std::string,std::string> file_sources_; 
     93         std::map<std::string,FontSet> fontsets_; 
    8994    }; 
    9095 
     
    143148                else if (v.first == "Layer") 
    144149                { 
    145  
    146150                    parse_layer(map, v.second ); 
     151                } 
     152                else if (v.first == "FontSet") 
     153                { 
     154                    parse_fontset(map, v.second); 
    147155                } 
    148156                else if (v.first == "FileSource") 
     
    227235        } 
    228236    } 
     237 
     238    void map_parser::parse_fontset( Map & map, ptree const & fset ) 
     239    { 
     240        string name("<missing name>"); 
     241        try 
     242