| 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 | | |
| 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 | | |
| | 120 | |
| 233 | | |
| 234 | | FT_Set_Transform(face, &matrix, &pen); |
| 235 | | |
| 236 | | error = FT_Load_Glyph (face, glyph_index, FT_LOAD_NO_HINTING); |
| | 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); |
| 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); |
| | 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); |
| 329 | | |
| | 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 | |
| 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 | | |
| 431 | | |
| 432 | | FT_Set_Transform(face, &matrix, &pen); |
| 433 | | |
| 434 | | error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_HINTING); |
| | 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); |