diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index 560e0d404..5bcd345c5 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -174,7 +174,7 @@ public: char_info character_dimensions(const unsigned c); - void get_string_info(string_info & info); + void get_string_info(string_info & info, UnicodeString const& ustr, char_properties *format); void set_pixel_sizes(unsigned size) { @@ -306,6 +306,18 @@ public: return face_set; } + face_set_ptr get_face_set(std::string const& name, font_set const& fset) + { + if (fset.size() > 0) + { + return get_face_set(fset); + } + else + { + return get_face_set(name); + } + } + stroker_ptr get_stroker() { return stroker_; @@ -323,21 +335,18 @@ struct text_renderer : private boost::noncopyable struct glyph_t : boost::noncopyable { FT_Glyph image; - glyph_t(FT_Glyph image_) : image(image_) {} + char_properties *properties; + glyph_t(FT_Glyph image_, char_properties *properties_) : image(image_), properties(properties_) {} ~glyph_t () { FT_Done_Glyph(image);} }; typedef boost::ptr_vector glyphs_t; typedef T pixmap_type; - text_renderer (pixmap_type & pixmap, face_set_ptr faces, stroker & s) - : pixmap_(pixmap), - faces_(faces), - stroker_(s), - fill_(0,0,0), - halo_fill_(255,255,255), - halo_radius_(0.0), - opacity_(1.0) {} + text_renderer (pixmap_type & pixmap, face_set_ptr faces, stroker & s); + box2d prepare_glyphs(text_path *path); + void render(double x0, double y0); + void render_id(int feature_id,double x0, double y0, double min_radius=1.0); void set_pixel_size(unsigned size) @@ -370,200 +379,8 @@ struct text_renderer : private boost::noncopyable opacity_=opacity; } - box2d prepare_glyphs(text_path *path) - { - //clear glyphs - glyphs_.clear(); - - FT_Matrix matrix; - FT_Vector pen; - FT_Error error; - - FT_BBox bbox; - bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we - bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later - - for (int i = 0; i < path->num_nodes(); i++) - { - int c; - double x, y, angle; - - path->vertex(&c, &x, &y, &angle); - -#ifdef MAPNIK_DEBUG - // TODO Enable when we have support for setting verbosity - //std::clog << "prepare_glyphs: " << c << "," << x << - // "," << y << "," << angle << std::endl; -#endif - - FT_BBox glyph_bbox; - FT_Glyph image; - - pen.x = int(x * 64); - pen.y = int(y * 64); - - glyph_ptr glyph = faces_->get_glyph(unsigned(c)); - FT_Face face = glyph->get_face()->get_face(); - - matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); - matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); - matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); - matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); - - FT_Set_Transform(face, &matrix, &pen); - - error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING); - if ( error ) - continue; - - error = FT_Get_Glyph(face->glyph, &image); - if ( error ) - continue; - - FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox); - if (glyph_bbox.xMin < bbox.xMin) - bbox.xMin = glyph_bbox.xMin; - if (glyph_bbox.yMin < bbox.yMin) - bbox.yMin = glyph_bbox.yMin; - if (glyph_bbox.xMax > bbox.xMax) - bbox.xMax = glyph_bbox.xMax; - if (glyph_bbox.yMax > bbox.yMax) - bbox.yMax = glyph_bbox.yMax; - - // Check if we properly grew the bbox - if ( bbox.xMin > bbox.xMax ) - { - bbox.xMin = 0; - bbox.yMin = 0; - bbox.xMax = 0; - bbox.yMax = 0; - } - - // take ownership of the glyph - glyphs_.push_back(new glyph_t(image)); - } - - return box2d(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax); - } - - void render(double x0, double y0) - { - FT_Error error; - FT_Vector start; - unsigned height = pixmap_.height(); - - start.x = static_cast(x0 * (1 << 6)); - start.y = static_cast((height - y0) * (1 << 6)); - - // now render transformed glyphs - typename glyphs_t::iterator pos; - - //make sure we've got reasonable values. - if (halo_radius_ > 0.0 && halo_radius_ < 1024.0) - { - stroker_.init(halo_radius_); - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) - { - FT_Glyph g; - error = FT_Glyph_Copy(pos->image, &g); - if (!error) - { - FT_Glyph_Transform(g,0,&start); - FT_Glyph_Stroke(&g,stroker_.get(),1); - error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); - if ( ! error ) - { - - FT_BitmapGlyph bit = (FT_BitmapGlyph)g; - render_bitmap(&bit->bitmap, halo_fill_.rgba(), - bit->left, - height - bit->top); - } - } - FT_Done_Glyph(g); - } - } - //render actual text - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) - { - - FT_Glyph_Transform(pos->image,0,&start); - - error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1); - if ( ! error ) - { - - FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image; - render_bitmap(&bit->bitmap, fill_.rgba(), - bit->left, - height - bit->top); - } - } - } - - void render_id(int feature_id,double x0, double y0, double min_radius=1.0) - { - FT_Error error; - FT_Vector start; - unsigned height = pixmap_.height(); - - start.x = static_cast(x0 * (1 << 6)); - start.y = static_cast((height - y0) * (1 << 6)); - - // now render transformed glyphs - typename glyphs_t::iterator pos; - - stroker_.init(std::max(halo_radius_,min_radius)); - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) - { - FT_Glyph g; - error = FT_Glyph_Copy(pos->image, &g); - if (!error) - { - FT_Glyph_Transform(g,0,&start); - FT_Glyph_Stroke(&g,stroker_.get(),1); - error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); - //error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_MONO,0,1); - if ( ! error ) - { - - FT_BitmapGlyph bit = (FT_BitmapGlyph)g; - render_bitmap_id(&bit->bitmap, feature_id, - bit->left, - height - bit->top); - } - } - FT_Done_Glyph(g); - } - } - private: - - // unused currently, stroker is the new method for drawing halos - /* - void render_halo(FT_Bitmap *bitmap,unsigned rgba,int x,int y,int radius) - { - int x_max=x+bitmap->width; - int y_max=y+bitmap->rows; - int i,p,j,q; - - for (i=x,p=0;ibuffer[q*bitmap->width+p]; - if (gray) - { - for (int n=-halo_radius_; n <=halo_radius_; ++n) - for (int m=-halo_radius_;m <= halo_radius_; ++m) - pixmap_.blendPixel2(i+m,j+n,rgba,gray,opacity_); - } - } - } - } - */ - - void render_bitmap(FT_Bitmap *bitmap,unsigned rgba,int x,int y) + void render_bitmap(FT_Bitmap *bitmap, unsigned rgba, int x, int y, double opacity) { int x_max=x+bitmap->width; int y_max=y+bitmap->rows; @@ -576,7 +393,7 @@ private: int gray=bitmap->buffer[q*bitmap->width+p]; if (gray) { - pixmap_.blendPixel2(i,j,rgba,gray,opacity_); + pixmap_.blendPixel2(i, j, rgba, gray, opacity); } } } @@ -611,6 +428,7 @@ private: glyphs_t glyphs_; double opacity_; }; +typedef face_manager face_manager_freetype; } #endif // MAPNIK_FONT_ENGINE_FREETYPE_HPP diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 7d2c02741..55265ff2b 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -139,7 +139,7 @@ void agg_renderer::process(shield_symbolizer const& sym, string_info info(text); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); metawriter_with_properties writer = sym.get_metawriter(); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index e460fa322..677c40af6 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -116,7 +116,7 @@ void agg_renderer::process(text_symbolizer const& sym, string_info info(text); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); metawriter_with_properties writer = sym.get_metawriter(); BOOST_FOREACH( geometry_type * geom, geometries_to_process ) diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 6bc2f88a6..37f29423d 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1146,7 +1146,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, placement_finder finder(detector_); faces->set_character_sizes(placement_options->text_size); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); int w = (*marker)->width(); int h = (*marker)->height(); @@ -1508,7 +1508,7 @@ void cairo_renderer_base::process(text_symbolizer const& sym, string_info info(text); faces->set_character_sizes(placement_options->text_size); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); placement_finder finder(detector_); diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 7b8a76fd9..d03f9995b 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -22,6 +22,9 @@ // mapnik #include +#include +#include +#include // boost #include @@ -232,12 +235,13 @@ char_info font_face_set::character_dimensions(const unsigned c) FT_Done_Glyph(image); unsigned tempx = face->glyph->advance.x >> 6; + char_info dim(c, tempx, glyph_bbox.yMax, glyph_bbox.yMin, face->size->metrics.height/64.0 /* >> 6 */); dimension_cache_.insert(std::pair(c, dim)); return dim; } -void font_face_set::get_string_info(string_info & info) +void font_face_set::get_string_info(string_info & info, UnicodeString const& ustr_unused, char_properties *format_unused) { unsigned width = 0; unsigned height = 0; @@ -286,8 +290,199 @@ void font_face_set::get_string_info(string_info & info) info.set_dimensions(width, height); } +template +text_renderer::text_renderer (pixmap_type & pixmap, face_set_ptr faces, stroker & s) + : pixmap_(pixmap), + faces_(faces), + stroker_(s), + fill_(0,0,0), + halo_fill_(255,255,255), + halo_radius_(0.0), + opacity_(1.0) +{ + +} + +template +box2d text_renderer::prepare_glyphs(text_path *path) +{ + //clear glyphs + glyphs_.clear(); + + FT_Matrix matrix; + FT_Vector pen; + FT_Error error; + + FT_BBox bbox; + bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we + bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later + + for (int i = 0; i < path->num_nodes(); i++) + { + int c; + double x, y, angle; + + path->vertex(&c, &x, &y, &angle); + +#ifdef MAPNIK_DEBUG + // TODO Enable when we have support for setting verbosity + //std::clog << "prepare_glyphs: " << c << "," << x << + // "," << y << "," << angle << std::endl; +#endif + + FT_BBox glyph_bbox; + FT_Glyph image; + + pen.x = int(x * 64); + pen.y = int(y * 64); + + glyph_ptr glyph = faces_->get_glyph(unsigned(c)); + FT_Face face = glyph->get_face()->get_face(); + + matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); + matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); + matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); + matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); + + FT_Set_Transform(face, &matrix, &pen); + + error = FT_Load_Glyph(face, glyph->get_index(), FT_LOAD_NO_HINTING); + if ( error ) + continue; + + error = FT_Get_Glyph(face->glyph, &image); + if ( error ) + continue; + + FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox); + if (glyph_bbox.xMin < bbox.xMin) + bbox.xMin = glyph_bbox.xMin; + if (glyph_bbox.yMin < bbox.yMin) + bbox.yMin = glyph_bbox.yMin; + if (glyph_bbox.xMax > bbox.xMax) + bbox.xMax = glyph_bbox.xMax; + if (glyph_bbox.yMax > bbox.yMax) + bbox.yMax = glyph_bbox.yMax; + + // Check if we properly grew the bbox + if ( bbox.xMin > bbox.xMax ) + { + bbox.xMin = 0; + bbox.yMin = 0; + bbox.xMax = 0; + bbox.yMax = 0; + } + + // take ownership of the glyph + glyphs_.push_back(new glyph_t(image, 0)); + } + + return box2d(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax); +} + +template +void text_renderer::render(double x0, double y0) +{ + FT_Error error; + FT_Vector start; + unsigned height = pixmap_.height(); + + start.x = static_cast(x0 * (1 << 6)); + start.y = static_cast((height - y0) * (1 << 6)); + + // now render transformed glyphs + typename glyphs_t::iterator pos; + + //make sure we've got reasonable values. + if (halo_radius_ > 0.0 && halo_radius_ < 1024.0) + { + stroker_.init(halo_radius_); + for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + { + FT_Glyph g; + error = FT_Glyph_Copy(pos->image, &g); + if (!error) + { + FT_Glyph_Transform(g,0,&start); + FT_Glyph_Stroke(&g,stroker_.get(),1); + error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); + if ( ! error ) + { + + FT_BitmapGlyph bit = (FT_BitmapGlyph)g; + render_bitmap(&bit->bitmap, halo_fill_.rgba(), + bit->left, + height - bit->top, opacity_); + } + } + FT_Done_Glyph(g); + } + } + //render actual text + for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + { + + FT_Glyph_Transform(pos->image,0,&start); + + error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1); + if ( ! error ) + { + + FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image; + render_bitmap(&bit->bitmap, fill_.rgba(), + bit->left, + height - bit->top, opacity_); + } + } +} + + +template +void text_renderer::render_id(int feature_id,double x0, double y0, double min_radius) +{ + FT_Error error; + FT_Vector start; + unsigned height = pixmap_.height(); + + start.x = static_cast(x0 * (1 << 6)); + start.y = static_cast((height - y0) * (1 << 6)); + + // now render transformed glyphs + typename glyphs_t::iterator pos; + + stroker_.init(std::max(halo_radius_,min_radius)); + for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + { + FT_Glyph g; + error = FT_Glyph_Copy(pos->image, &g); + if (!error) + { + FT_Glyph_Transform(g,0,&start); + FT_Glyph_Stroke(&g,stroker_.get(),1); + error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_NORMAL,0,1); + //error = FT_Glyph_To_Bitmap( &g,FT_RENDER_MODE_MONO,0,1); + if ( ! error ) + { + + FT_BitmapGlyph bit = (FT_BitmapGlyph)g; + render_bitmap_id(&bit->bitmap, feature_id, + bit->left, + height - bit->top); + } + } + FT_Done_Glyph(g); + } +} + #ifdef MAPNIK_THREADSAFE boost::mutex freetype_engine::mutex_; #endif std::map > freetype_engine::name2file_; +template void text_renderer::render(double, double); +template text_renderer::text_renderer(image_32&, face_set_ptr, stroker&); +template box2dtext_renderer::prepare_glyphs(text_path*); + +template void text_renderer::render_id(int, double, double, double); +template text_renderer::text_renderer(grid&, face_set_ptr, stroker&); +template box2dtext_renderer::prepare_glyphs(text_path*); } diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index d0f61cd67..fdc2f7b15 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -120,7 +120,7 @@ void grid_renderer::process(shield_symbolizer const& sym, string_info info(text); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); // TODO- clamp to at least 4 px otherwise interactivity is too small int w = (*marker)->width()/pixmap_.get_resolution(); diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index e88aed6c5..1cf6abd53 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -89,7 +89,7 @@ void grid_renderer::process(text_symbolizer const& sym, string_info info(text); - faces->get_string_info(info); + faces->get_string_info(info, text, 0); unsigned num_geom = feature.num_geometries(); for (unsigned i=0; i