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

applied font fallback patch from Beau Gunderson

Files:
1 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