| | 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 | |
| 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 | |
| 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); |
| 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); |
| 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 | |
| | 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 | |
| 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); |