00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef FONT_ENGINE_FREETYPE_HPP
00026 #define FONT_ENGINE_FREETYPE_HPP
00027
00028 #include <mapnik/color.hpp>
00029 #include <mapnik/utils.hpp>
00030 #include <mapnik/ctrans.hpp>
00031 #include <mapnik/geometry.hpp>
00032 #include <mapnik/text_path.hpp>
00033 #include <mapnik/font_set.hpp>
00034
00035
00036 extern "C"
00037 {
00038 #include <ft2build.h>
00039 #include FT_FREETYPE_H
00040 #include FT_GLYPH_H
00041 }
00042
00043
00044 #include <boost/shared_ptr.hpp>
00045 #include <boost/utility.hpp>
00046 #include <boost/ptr_container/ptr_vector.hpp>
00047 #include <boost/thread/mutex.hpp>
00048 #include <boost/thread/mutex.hpp>
00049
00050
00051 #include <string>
00052 #include <vector>
00053 #include <map>
00054 #include <iostream>
00055
00056
00057 #include <unicode/ubidi.h>
00058 #include <unicode/ushape.h>
00059
00060 namespace mapnik
00061 {
00062 class font_face;
00063
00064 typedef boost::shared_ptr<font_face> face_ptr;
00065
00066 class MAPNIK_DECL font_glyph : private boost::noncopyable
00067 {
00068 public:
00069 font_glyph(face_ptr face, unsigned index)
00070 : face_(face), index_(index) {}
00071
00072 face_ptr get_face() const
00073 {
00074 return face_;
00075 }
00076
00077 unsigned get_index() const
00078 {
00079 return index_;
00080 }
00081 private:
00082 face_ptr face_;
00083 unsigned index_;
00084 };
00085
00086 typedef boost::shared_ptr<font_glyph> glyph_ptr;
00087
00088 class font_face : boost::noncopyable
00089 {
00090 public:
00091 font_face(FT_Face face)
00092 : face_(face) {}
00093
00094 std::string family_name() const
00095 {
00096 return std::string(face_->family_name);
00097 }
00098
00099 std::string style_name() const
00100 {
00101 return std::string(face_->style_name);
00102 }
00103
00104 FT_GlyphSlot glyph() const
00105 {
00106 return face_->glyph;
00107 }
00108
00109 FT_Face get_face() const
00110 {
00111 return face_;
00112 }
00113
00114 unsigned get_char(unsigned c) const
00115 {
00116 return FT_Get_Char_Index(face_, c);
00117 }
00118
00119 bool set_pixel_sizes(unsigned size)
00120 {
00121 if (! FT_Set_Pixel_Sizes( face_, 0, size ))
00122 return true;
00123
00124 return false;
00125 }
00126
00127 ~font_face()
00128 {
00129 #ifdef MAPNIK_DEBUG
00130 std::clog << "~font_face: Clean up face \"" << family_name()
00131 << " " << style_name() << "\"" << std::endl;
00132 #endif
00133 FT_Done_Face(face_);
00134 }
00135
00136 private:
00137 FT_Face face_;
00138 };
00139
00140 class MAPNIK_DECL font_face_set : private boost::noncopyable
00141 {
00142 public:
00143 typedef std::pair<unsigned,unsigned> dimension_t;
00144
00145 font_face_set(void)
00146 : faces_() {}
00147
00148 void add(face_ptr face)
00149 {
00150 faces_.push_back(face);
00151 }
00152
00153 unsigned size() const
00154 {
00155 return faces_.size();
00156 }
00157
00158 glyph_ptr get_glyph(unsigned c) const
00159 {
00160 for (std::vector<face_ptr>::const_iterator face = faces_.begin(); face != faces_.end(); ++face)
00161 {
00162 FT_UInt g = (*face)->get_char(c);
00163
00164 if (g) return glyph_ptr(new font_glyph(*face, g));
00165 }
00166
00167
00168 return glyph_ptr(new font_glyph(*faces_.begin(), 0));
00169 }
00170
00171 dimension_t character_dimensions(const unsigned c)
00172 {
00173 FT_Matrix matrix;
00174 FT_Vector pen;
00175 FT_Error error;
00176
00177 pen.x = 0;
00178 pen.y = 0;
00179
00180 FT_BBox glyph_bbox;
00181 FT_Glyph image;
00182
00183 glyph_ptr glyph = get_glyph(c);
00184 FT_Face face = glyph->get_face()->get_face();
00185
00186 matrix.xx = (FT_Fixed)( 1 * 0x10000L );
00187 matrix.xy = (FT_Fixed)( 0 * 0x10000L );
00188 matrix.yx = (FT_Fixed)( 0 * 0x10000L );
00189 matrix.yy = (FT_Fixed)( 1 * 0x10000L );
00190
00191 FT_Set_Transform(face, &matrix, &pen);
00192
00193 error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING);
00194 if ( error )
00195 return dimension_t(0, 0);
00196
00197 error = FT_Get_Glyph(face->glyph, &image);
00198 if ( error )
00199 return dimension_t(0, 0);
00200
00201 FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
00202 FT_Done_Glyph(image);
00203
00204 unsigned tempx = face->glyph->advance.x >> 6;
00205 unsigned tempy = glyph_bbox.yMax - glyph_bbox.yMin;
00206
00207
00208
00209 return dimension_t(tempx, tempy);
00210 }
00211
00212 void get_string_info(string_info & info)
00213 {
00214 unsigned width = 0;
00215 unsigned height = 0;
00216 UErrorCode err = U_ZERO_ERROR;
00217 UnicodeString const& ustr = info.get_string();
00218 const UChar * text = ustr.getBuffer();
00219 UBiDi * bidi = ubidi_openSized(ustr.length(),0,&err);
00220
00221 if (U_SUCCESS(err))
00222 {
00223 ubidi_setPara(bidi,text,ustr.length(), UBIDI_DEFAULT_LTR,0,&err);
00224
00225 if (U_SUCCESS(err))
00226 {
00227 int32_t count = ubidi_countRuns(bidi,&err);
00228 int32_t logicalStart;
00229 int32_t length;
00230
00231 for (int32_t i=0; i< count;++i)
00232 {
00233 if (UBIDI_LTR == ubidi_getVisualRun(bidi,i,&logicalStart,&length))
00234 {
00235 do {
00236 UChar ch = text[logicalStart++];
00237 dimension_t char_dim = character_dimensions(ch);
00238 info.add_info(ch, char_dim.first, char_dim.second);
00239 width += char_dim.first;
00240 height = char_dim.second > height ? char_dim.second : height;
00241
00242 } while (--length > 0);
00243 }
00244 else
00245 {
00246 logicalStart += length;
00247
00248 int32_t j=0,i=length;
00249 UnicodeString arabic;
00250 UChar * buf = arabic.getBuffer(length);
00251 do {
00252 UChar ch = text[--logicalStart];
00253 buf[j++] = ch;
00254 } while (--i > 0);
00255
00256 arabic.releaseBuffer(length);
00257 if ( *arabic.getBuffer() >= 0x0600 && *arabic.getBuffer() <= 0x06ff)
00258 {
00259 UnicodeString shaped;
00260 u_shapeArabic(arabic.getBuffer(),arabic.length(),shaped.getBuffer(arabic.length()),arabic.length(),
00261 U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
00262 U_SHAPE_TEXT_DIRECTION_VISUAL_LTR
00263 ,&err);
00264
00265 shaped.releaseBuffer(arabic.length());
00266
00267 if (U_SUCCESS(err))
00268 {
00269 for (int j=0;j<shaped.length();++j)
00270 {
00271 dimension_t char_dim = character_dimensions(shaped[j]);
00272 info.add_info(shaped[j], char_dim.first, char_dim.second);
00273 width += char_dim.first;
00274 height = char_dim.second > height ? char_dim.second : height;
00275 }
00276 }
00277 }
00278 }
00279 }
00280 }
00281 ubidi_close(bidi);
00282 }
00283
00284 info.set_dimensions(width, height);
00285 }
00286
00287 void set_pixel_sizes(unsigned size)
00288 {
00289 for (std::vector<face_ptr>::iterator face = faces_.begin(); face != faces_.end(); ++face)
00290 {
00291 (*face)->set_pixel_sizes(size);
00292 }
00293 }
00294 private:
00295 std::vector<face_ptr> faces_;
00296 };
00297
00298 typedef boost::shared_ptr<font_face_set> face_set_ptr;
00299
00300 class MAPNIK_DECL freetype_engine
00301
00302 {
00303
00304 public:
00305 static bool register_font(std::string const& file_name);
00306 static std::vector<std::string> face_names ();
00307 face_ptr create_face(std::string const& family_name);
00308 virtual ~freetype_engine();
00309 freetype_engine();
00310 private:
00311 FT_Library library_;
00312 static boost::mutex mutex_;
00313 static std::map<std::string,std::string> name2file_;
00314 };
00315
00316 template <typename T>
00317 class MAPNIK_DECL face_manager : private boost::noncopyable
00318 {
00319 typedef T font_engine_type;
00320 typedef std::map<std::string,face_ptr> faces;
00321
00322 public:
00323 face_manager(T & engine)
00324 : engine_(engine) {}
00325
00326 face_ptr get_face(std::string const& name)
00327 {
00328 typename faces::iterator itr;
00329 itr = faces_.find(name);
00330 if (itr != faces_.end())
00331 {
00332 return itr->second;
00333 }
00334 else
00335 {
00336 face_ptr face = engine_.create_face(name);
00337 if (face)
00338 {
00339 faces_.insert(make_pair(name,face));
00340 }
00341 return face;
00342 }
00343 }
00344
00345 face_set_ptr get_face_set(std::string const& name)
00346 {
00347 face_set_ptr face_set(new font_face_set);
00348 if (face_ptr face = get_face(name))
00349 {
00350 face_set->add(face);
00351 }
00352 return face_set;
00353 }
00354
00355 face_set_ptr get_face_set(FontSet const& fontset)
00356 {
00357 std::vector<std::string> const& names = fontset.get_face_names();
00358 face_set_ptr face_set(new font_face_set);
00359 for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name)
00360 {
00361 if (face_ptr face = get_face(*name))
00362 {
00363 face_set->add(face);
00364 }
00365 }
00366 return face_set;
00367 }
00368 private:
00369 faces faces_;
00370 font_engine_type & engine_;
00371 };
00372
00373 template <typename T>
00374 struct text_renderer : private boost::noncopyable
00375 {
00376 struct glyph_t : boost::noncopyable
00377 {
00378 FT_Glyph image;
00379 glyph_t(FT_Glyph image_) : image(image_) {}
00380 ~glyph_t () { FT_Done_Glyph(image);}
00381 };
00382
00383 typedef boost::ptr_vector<glyph_t> glyphs_t;
00384 typedef T pixmap_type;
00385
00386 text_renderer (pixmap_type & pixmap, face_set_ptr faces)
00387 : pixmap_(pixmap),
00388 faces_(faces),
00389 fill_(0,0,0),
00390 halo_fill_(255,255,255),
00391 halo_radius_(0) {}
00392
00393 void set_pixel_size(unsigned size)
00394 {
00395 faces_->set_pixel_sizes(size);
00396 }
00397
00398 void set_fill(mapnik::Color const& fill)
00399 {
00400 fill_=fill;
00401 }
00402
00403 void set_halo_fill(mapnik::Color const& halo)
00404 {
00405 halo_fill_=halo;
00406 }
00407
00408 void set_halo_radius( int radius=1)
00409 {
00410 halo_radius_=radius;
00411 }
00412
00413 Envelope<double> prepare_glyphs(text_path *path)
00414 {
00415
00416 glyphs_.clear();
00417
00418 FT_Matrix matrix;
00419 FT_Vector pen;
00420 FT_Error error;
00421
00422 FT_BBox bbox;
00423 bbox.xMin = bbox.yMin = 32000;
00424 bbox.xMax = bbox.yMax = -32000;
00425
00426 for (int i = 0; i < path->num_nodes(); i++)
00427 {
00428 int c;
00429 double x, y, angle;
00430
00431 path->vertex(&c, &x, &y, &angle);
00432
00433 #ifdef MAPNIK_DEBUG
00434
00435
00436
00437 #endif
00438
00439 FT_BBox glyph_bbox;
00440 FT_Glyph image;
00441
00442 pen.x = int(x * 64);
00443 pen.y = int(y * 64);
00444
00445 glyph_ptr glyph = faces_->get_glyph(unsigned(c));
00446 FT_Face face = glyph->get_face()->get_face();
00447
00448 matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
00449 matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
00450 matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
00451 matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
00452
00453 FT_Set_Transform(face, &matrix, &pen);
00454
00455 error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING);
00456 if ( error )
00457 continue;
00458
00459 error = FT_Get_Glyph(face->glyph, &image);
00460 if ( error )
00461 continue;
00462
00463 FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
00464 if (glyph_bbox.xMin < bbox.xMin)
00465 bbox.xMin = glyph_bbox.xMin;
00466 if (glyph_bbox.yMin < bbox.yMin)
00467 bbox.yMin = glyph_bbox.yMin;
00468 if (glyph_bbox.xMax > bbox.xMax)
00469 bbox.xMax = glyph_bbox.xMax;
00470 if (glyph_bbox.yMax > bbox.yMax)
00471 bbox.yMax = glyph_bbox.yMax;
00472
00473
00474 if ( bbox.xMin > bbox.xMax )
00475 {
00476 bbox.xMin = 0;
00477 bbox.yMin = 0;
00478 bbox.xMax = 0;
00479 bbox.yMax = 0;
00480 }
00481
00482
00483 glyphs_.push_back(new glyph_t(image));
00484 }
00485
00486 return Envelope<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);
00487 }
00488
00489 void render(double x0, double y0)
00490 {
00491 FT_Error error;
00492 FT_Vector start;
00493 unsigned height = pixmap_.height();
00494
00495 start.x = static_cast<FT_Pos>(x0 * (1 << 6));
00496 start.y = static_cast<FT_Pos>((height - y0) * (1 << 6));
00497
00498
00499 typename glyphs_t::iterator pos;
00500
00501
00502 if (halo_radius_ > 0 && halo_radius_ < 256)
00503 {
00504
00505 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00506 {
00507
00508 FT_Glyph_Transform(pos->image,0,&start);
00509
00510 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00511 if ( ! error )
00512 {
00513
00514 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00515 render_halo(&bit->bitmap, halo_fill_.rgba(),
00516 bit->left,
00517 height - bit->top,halo_radius_);
00518 }
00519 }
00520 }
00521
00522 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00523 {
00524
00525 FT_Glyph_Transform(pos->image,0,&start);
00526
00527 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00528 if ( ! error )
00529 {
00530
00531 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00532 render_bitmap(&bit->bitmap, fill_.rgba(),
00533 bit->left,
00534 height - bit->top);
00535 }
00536 }
00537 }
00538
00539 private:
00540
00541 void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius)
00542 {
00543 int x_max=x+bitmap->width;
00544 int y_max=y+bitmap->rows;
00545 int i,p,j,q;
00546
00547 for (i=x,p=0;i<x_max;++i,++p)
00548 {
00549 for (j=y,q=0;j<y_max;++j,++q)
00550 {
00551 int gray = bitmap->buffer[q*bitmap->width+p];
00552 if (gray)
00553 {
00554 for (int n=-halo_radius_; n <=halo_radius_; ++n)
00555 for (int m=-halo_radius_;m <= halo_radius_; ++m)
00556 pixmap_.blendPixel(i+m,j+n,rgba,gray);
00557 }
00558 }
00559 }
00560 }
00561
00562 void render_bitmap(FT_Bitmap *bitmap,unsigned rgba,int x,int y)
00563 {
00564 int x_max=x+bitmap->width;
00565 int y_max=y+bitmap->rows;
00566 int i,p,j,q;
00567
00568 for (i=x,p=0;i<x_max;++i,++p)
00569 {
00570 for (j=y,q=0;j<y_max;++j,++q)
00571 {
00572 int gray=bitmap->buffer[q*bitmap->width+p];
00573 if (gray)
00574 {
00575 pixmap_.blendPixel(i,j,rgba,gray);
00576 }
00577 }
00578 }
00579 }
00580
00581 pixmap_type & pixmap_;
00582 face_set_ptr faces_;
00583 mapnik::Color fill_;
00584 mapnik::Color halo_fill_;
00585 int halo_radius_;
00586 unsigned text_ratio_;
00587 unsigned wrap_width_;
00588 glyphs_t glyphs_;
00589 };
00590 }
00591
00592 #endif // FONT_ENGINE_FREETYPE_HPP