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 } else {
00278
00279 for (int j=0;j<arabic.length();++j)
00280 {
00281 dimension_t char_dim = character_dimensions(arabic[j]);
00282 info.add_info(arabic[j], char_dim.first, char_dim.second);
00283 width += char_dim.first;
00284 height = char_dim.second > height ? char_dim.second : height;
00285 }
00286 }
00287 }
00288 }
00289 }
00290 ubidi_close(bidi);
00291 }
00292
00293 info.set_dimensions(width, height);
00294 }
00295
00296 void set_pixel_sizes(unsigned size)
00297 {
00298 for (std::vector<face_ptr>::iterator face = faces_.begin(); face != faces_.end(); ++face)
00299 {
00300 (*face)->set_pixel_sizes(size);
00301 }
00302 }
00303 private:
00304 std::vector<face_ptr> faces_;
00305 };
00306
00307 typedef boost::shared_ptr<font_face_set> face_set_ptr;
00308
00309 class MAPNIK_DECL freetype_engine
00310
00311 {
00312
00313 public:
00314 static bool register_font(std::string const& file_name);
00315 static std::vector<std::string> face_names ();
00316 face_ptr create_face(std::string const& family_name);
00317 virtual ~freetype_engine();
00318 freetype_engine();
00319 private:
00320 FT_Library library_;
00321 static boost::mutex mutex_;
00322 static std::map<std::string,std::string> name2file_;
00323 };
00324
00325 template <typename T>
00326 class MAPNIK_DECL face_manager : private boost::noncopyable
00327 {
00328 typedef T font_engine_type;
00329 typedef std::map<std::string,face_ptr> faces;
00330
00331 public:
00332 face_manager(T & engine)
00333 : engine_(engine) {}
00334
00335 face_ptr get_face(std::string const& name)
00336 {
00337 typename faces::iterator itr;
00338 itr = faces_.find(name);
00339 if (itr != faces_.end())
00340 {
00341 return itr->second;
00342 }
00343 else
00344 {
00345 face_ptr face = engine_.create_face(name);
00346 if (face)
00347 {
00348 faces_.insert(make_pair(name,face));
00349 }
00350 return face;
00351 }
00352 }
00353
00354 face_set_ptr get_face_set(std::string const& name)
00355 {
00356 face_set_ptr face_set(new font_face_set);
00357 if (face_ptr face = get_face(name))
00358 {
00359 face_set->add(face);
00360 }
00361 return face_set;
00362 }
00363
00364 face_set_ptr get_face_set(FontSet const& fontset)
00365 {
00366 std::vector<std::string> const& names = fontset.get_face_names();
00367 face_set_ptr face_set(new font_face_set);
00368 for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name)
00369 {
00370 if (face_ptr face = get_face(*name))
00371 {
00372 face_set->add(face);
00373 }
00374 }
00375 return face_set;
00376 }
00377 private:
00378 faces faces_;
00379 font_engine_type & engine_;
00380 };
00381
00382 template <typename T>
00383 struct text_renderer : private boost::noncopyable
00384 {
00385 struct glyph_t : boost::noncopyable
00386 {
00387 FT_Glyph image;
00388 glyph_t(FT_Glyph image_) : image(image_) {}
00389 ~glyph_t () { FT_Done_Glyph(image);}
00390 };
00391
00392 typedef boost::ptr_vector<glyph_t> glyphs_t;
00393 typedef T pixmap_type;
00394
00395 text_renderer (pixmap_type & pixmap, face_set_ptr faces)
00396 : pixmap_(pixmap),
00397 faces_(faces),
00398 fill_(0,0,0),
00399 halo_fill_(255,255,255),
00400 halo_radius_(0) {}
00401
00402 void set_pixel_size(unsigned size)
00403 {
00404 faces_->set_pixel_sizes(size);
00405 }
00406
00407 void set_fill(mapnik::Color const& fill)
00408 {
00409 fill_=fill;
00410 }
00411
00412 void set_halo_fill(mapnik::Color const& halo)
00413 {
00414 halo_fill_=halo;
00415 }
00416
00417 void set_halo_radius( int radius=1)
00418 {
00419 halo_radius_=radius;
00420 }
00421
00422 Envelope<double> prepare_glyphs(text_path *path)
00423 {
00424
00425 glyphs_.clear();
00426
00427 FT_Matrix matrix;
00428 FT_Vector pen;
00429 FT_Error error;
00430
00431 FT_BBox bbox;
00432 bbox.xMin = bbox.yMin = 32000;
00433 bbox.xMax = bbox.yMax = -32000;
00434
00435 for (int i = 0; i < path->num_nodes(); i++)
00436 {
00437 int c;
00438 double x, y, angle;
00439
00440 path->vertex(&c, &x, &y, &angle);
00441
00442 #ifdef MAPNIK_DEBUG
00443
00444
00445
00446 #endif
00447
00448 FT_BBox glyph_bbox;
00449 FT_Glyph image;
00450
00451 pen.x = int(x * 64);
00452 pen.y = int(y * 64);
00453
00454 glyph_ptr glyph = faces_->get_glyph(unsigned(c));
00455 FT_Face face = glyph->get_face()->get_face();
00456
00457 matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
00458 matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
00459 matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
00460 matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
00461
00462 FT_Set_Transform(face, &matrix, &pen);
00463
00464 error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING);
00465 if ( error )
00466 continue;
00467
00468 error = FT_Get_Glyph(face->glyph, &image);
00469 if ( error )
00470 continue;
00471
00472 FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
00473 if (glyph_bbox.xMin < bbox.xMin)
00474 bbox.xMin = glyph_bbox.xMin;
00475 if (glyph_bbox.yMin < bbox.yMin)
00476 bbox.yMin = glyph_bbox.yMin;
00477 if (glyph_bbox.xMax > bbox.xMax)
00478 bbox.xMax = glyph_bbox.xMax;
00479 if (glyph_bbox.yMax > bbox.yMax)
00480 bbox.yMax = glyph_bbox.yMax;
00481
00482
00483 if ( bbox.xMin > bbox.xMax )
00484 {
00485 bbox.xMin = 0;
00486 bbox.yMin = 0;
00487 bbox.xMax = 0;
00488 bbox.yMax = 0;
00489 }
00490
00491
00492 glyphs_.push_back(new glyph_t(image));
00493 }
00494
00495 return Envelope<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);
00496 }
00497
00498 void render(double x0, double y0)
00499 {
00500 FT_Error error;
00501 FT_Vector start;
00502 unsigned height = pixmap_.height();
00503
00504 start.x = static_cast<FT_Pos>(x0 * (1 << 6));
00505 start.y = static_cast<FT_Pos>((height - y0) * (1 << 6));
00506
00507
00508 typename glyphs_t::iterator pos;
00509
00510
00511 if (halo_radius_ > 0 && halo_radius_ < 256)
00512 {
00513
00514 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00515 {
00516
00517 FT_Glyph_Transform(pos->image,0,&start);
00518
00519 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00520 if ( ! error )
00521 {
00522
00523 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00524 render_halo(&bit->bitmap, halo_fill_.rgba(),
00525 bit->left,
00526 height - bit->top,halo_radius_);
00527 }
00528 }
00529 }
00530
00531 for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
00532 {
00533
00534 FT_Glyph_Transform(pos->image,0,&start);
00535
00536 error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
00537 if ( ! error )
00538 {
00539
00540 FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
00541 render_bitmap(&bit->bitmap, fill_.rgba(),
00542 bit->left,
00543 height - bit->top);
00544 }
00545 }
00546 }
00547
00548 private:
00549
00550 void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius)
00551 {
00552 int x_max=x+bitmap->width;
00553 int y_max=y+bitmap->rows;
00554 int i,p,j,q;
00555
00556 for (i=x,p=0;i<x_max;++i,++p)
00557 {
00558 for (j=y,q=0;j<y_max;++j,++q)
00559 {
00560 int gray = bitmap->buffer[q*bitmap->width+p];
00561 if (gray)
00562 {
00563 for (int n=-halo_radius_; n <=halo_radius_; ++n)
00564 for (int m=-halo_radius_;m <= halo_radius_; ++m)
00565 pixmap_.blendPixel(i+m,j+n,rgba,gray);
00566 }
00567 }
00568 }
00569 }
00570
00571 void render_bitmap(FT_Bitmap *bitmap,unsigned rgba,int x,int y)
00572 {
00573 int x_max=x+bitmap->width;
00574 int y_max=y+bitmap->rows;
00575 int i,p,j,q;
00576
00577 for (i=x,p=0;i<x_max;++i,++p)
00578 {
00579 for (j=y,q=0;j<y_max;++j,++q)
00580 {
00581 int gray=bitmap->buffer[q*bitmap->width+p];
00582 if (gray)
00583 {
00584 pixmap_.blendPixel(i,j,rgba,gray);
00585 }
00586 }
00587 }
00588 }
00589
00590 pixmap_type & pixmap_;
00591 face_set_ptr faces_;
00592 mapnik::Color fill_;
00593 mapnik::Color halo_fill_;
00594 int halo_radius_;
00595 unsigned text_ratio_;
00596 unsigned wrap_width_;
00597 glyphs_t glyphs_;
00598 };
00599 }
00600
00601 #endif // FONT_ENGINE_FREETYPE_HPP