applied font fallback patch from Beau Gunderson
This commit is contained in:
parent
3f9127b5d0
commit
1b47afde07
8 changed files with 444 additions and 171 deletions
|
@ -30,6 +30,7 @@
|
|||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/text_path.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
|
||||
// freetype2
|
||||
extern "C"
|
||||
|
@ -61,8 +62,6 @@ namespace mapnik
|
|||
class font_face : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef std::pair<unsigned,unsigned> dimension_t;
|
||||
|
||||
font_face(FT_Face face)
|
||||
: face_(face) {}
|
||||
|
||||
|
@ -104,122 +103,11 @@ namespace mapnik
|
|||
return false;
|
||||
}
|
||||
|
||||
dimension_t character_dimensions(const unsigned c)
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
FT_Vector pen;
|
||||
FT_Error error;
|
||||
|
||||
FT_GlyphSlot slot = face_->glyph;
|
||||
|
||||
pen.x = 0;
|
||||
pen.y = 0;
|
||||
|
||||
FT_BBox glyph_bbox;
|
||||
FT_Glyph image;
|
||||
|
||||
matrix.xx = (FT_Fixed)( 1 * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yy = (FT_Fixed)( 1 * 0x10000L );
|
||||
|
||||
FT_Set_Transform (face_,&matrix,&pen);
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face_, c);
|
||||
|
||||
error = FT_Load_Glyph (face_,glyph_index,FT_LOAD_NO_HINTING);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
error = FT_Get_Glyph( face_->glyph, &image);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
|
||||
FT_Done_Glyph(image);
|
||||
return dimension_t(slot->advance.x >> 6, glyph_bbox.yMax - glyph_bbox.yMin);
|
||||
}
|
||||
|
||||
void get_string_info(string_info & info)
|
||||
{
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
UnicodeString const& ustr = info.get_string();
|
||||
const UChar * text = ustr.getBuffer();
|
||||
UBiDi * bidi = ubidi_openSized(ustr.length(),0,&err);
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
ubidi_setPara(bidi,text,ustr.length(), UBIDI_DEFAULT_LTR,0,&err);
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
int32_t count = ubidi_countRuns(bidi,&err);
|
||||
int32_t logicalStart;
|
||||
int32_t length;
|
||||
|
||||
for (int32_t i=0; i< count;++i)
|
||||
{
|
||||
if (UBIDI_LTR == ubidi_getVisualRun(bidi,i,&logicalStart,&length))
|
||||
{
|
||||
do {
|
||||
UChar ch = text[logicalStart++];
|
||||
dimension_t char_dim = character_dimensions(ch);
|
||||
info.add_info(ch, char_dim.first, char_dim.second);
|
||||
width += char_dim.first;
|
||||
height = char_dim.second > height ? char_dim.second : height;
|
||||
|
||||
} while (--length > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
logicalStart += length;
|
||||
|
||||
int32_t j=0,i=length;
|
||||
UnicodeString arabic;
|
||||
UChar * buf = arabic.getBuffer(length);
|
||||
do {
|
||||
UChar ch = text[--logicalStart];
|
||||
buf[j++] = ch;
|
||||
} while (--i > 0);
|
||||
|
||||
arabic.releaseBuffer(length);
|
||||
if ( *arabic.getBuffer() >= 0x0600 && *arabic.getBuffer() <= 0x06ff)
|
||||
{
|
||||
|
||||
UnicodeString shaped;
|
||||
u_shapeArabic(arabic.getBuffer(),arabic.length(),shaped.getBuffer(arabic.length()),arabic.length(),
|
||||
U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
|
||||
U_SHAPE_TEXT_DIRECTION_VISUAL_LTR
|
||||
,&err);
|
||||
|
||||
shaped.releaseBuffer(arabic.length());
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
for (int j=0;j<shaped.length();++j)
|
||||
{
|
||||
dimension_t char_dim = character_dimensions(shaped[j]);
|
||||
info.add_info(shaped[j], char_dim.first, char_dim.second);
|
||||
width += char_dim.first;
|
||||
height = char_dim.second > height ? char_dim.second : height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ubidi_close(bidi);
|
||||
}
|
||||
|
||||
info.set_dimensions(width, height);
|
||||
}
|
||||
|
||||
~font_face()
|
||||
{
|
||||
#ifdef MAPNIK_DEBUG
|
||||
std::clog << "clean up face:" << family_name()<<":" << style_name() << std::endl;
|
||||
std::clog << "~font_face: Clean up face \"" << family_name()
|
||||
<< " " << style_name() << "\"" << std::endl;
|
||||
#endif
|
||||
FT_Done_Face(face_);
|
||||
}
|
||||
|
@ -229,6 +117,7 @@ namespace mapnik
|
|||
};
|
||||
|
||||
typedef boost::shared_ptr<font_face> face_ptr;
|
||||
|
||||
class MAPNIK_DECL freetype_engine // : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>,
|
||||
// private boost::noncopyable
|
||||
{
|
||||
|
@ -281,6 +170,8 @@ namespace mapnik
|
|||
template <typename T>
|
||||
struct text_renderer : private boost::noncopyable
|
||||
{
|
||||
typedef std::pair<unsigned,unsigned> dimension_t;
|
||||
|
||||
struct glyph_t : boost::noncopyable
|
||||
{
|
||||
FT_Glyph image;
|
||||
|
@ -291,16 +182,159 @@ namespace mapnik
|
|||
typedef boost::ptr_vector<glyph_t> glyphs_t;
|
||||
typedef T pixmap_type;
|
||||
|
||||
text_renderer (pixmap_type & pixmap, face_ptr face)
|
||||
text_renderer (pixmap_type & pixmap, std::vector<face_ptr> faces)
|
||||
: pixmap_(pixmap),
|
||||
face_(face),
|
||||
faces_(faces),
|
||||
fill_(0,0,0),
|
||||
halo_fill_(255,255,255),
|
||||
halo_radius_(0) {}
|
||||
|
||||
dimension_t character_dimensions(const unsigned c)
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
FT_Vector pen;
|
||||
FT_Error error;
|
||||
|
||||
pen.x = 0;
|
||||
pen.y = 0;
|
||||
|
||||
FT_BBox glyph_bbox;
|
||||
FT_Glyph image;
|
||||
|
||||
FT_Face face = (*faces_.begin())->get_face();
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(face, c);
|
||||
|
||||
// If there's no glyph_index we loop through the remaining fonts
|
||||
// in the fontset looking for one.
|
||||
if (!glyph_index) {
|
||||
std::vector<face_ptr>::iterator itr = faces_.begin();
|
||||
std::vector<face_ptr>::iterator end = faces_.end();
|
||||
|
||||
++itr; // Skip the first one, we already tried it.
|
||||
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
FT_Face f = (*itr)->get_face();
|
||||
|
||||
glyph_index = FT_Get_Char_Index(f, c);
|
||||
|
||||
if (glyph_index) {
|
||||
face = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix.xx = (FT_Fixed)( 1 * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yy = (FT_Fixed)( 1 * 0x10000L );
|
||||
|
||||
FT_Set_Transform(face, &matrix, &pen);
|
||||
|
||||
error = FT_Load_Glyph (face, glyph_index, FT_LOAD_NO_HINTING);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
error = FT_Get_Glyph(face->glyph, &image);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
|
||||
FT_Done_Glyph(image);
|
||||
|
||||
unsigned tempx = face->glyph->advance.x >> 6;
|
||||
unsigned tempy = glyph_bbox.yMax - glyph_bbox.yMin;
|
||||
|
||||
//std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl;
|
||||
|
||||
return dimension_t(tempx, tempy);
|
||||
}
|
||||
|
||||
void get_string_info(string_info & info)
|
||||
{
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
UnicodeString const& ustr = info.get_string();
|
||||
const UChar * text = ustr.getBuffer();
|
||||
UBiDi * bidi = ubidi_openSized(ustr.length(),0,&err);
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
ubidi_setPara(bidi,text,ustr.length(), UBIDI_DEFAULT_LTR,0,&err);
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
int32_t count = ubidi_countRuns(bidi,&err);
|
||||
int32_t logicalStart;
|
||||
int32_t length;
|
||||
|
||||
for (int32_t i=0; i< count;++i)
|
||||
{
|
||||
if (UBIDI_LTR == ubidi_getVisualRun(bidi,i,&logicalStart,&length))
|
||||
{
|
||||
do {
|
||||
UChar ch = text[logicalStart++];
|
||||
dimension_t char_dim = character_dimensions(ch);
|
||||
info.add_info(ch, char_dim.first, char_dim.second);
|
||||
width += char_dim.first;
|
||||
height = char_dim.second > height ? char_dim.second : height;
|
||||
|
||||
} while (--length > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
logicalStart += length;
|
||||
|
||||
int32_t j=0,i=length;
|
||||
UnicodeString arabic;
|
||||
UChar * buf = arabic.getBuffer(length);
|
||||
do {
|
||||
UChar ch = text[--logicalStart];
|
||||
buf[j++] = ch;
|
||||
} while (--i > 0);
|
||||
|
||||
arabic.releaseBuffer(length);
|
||||
if ( *arabic.getBuffer() >= 0x0600 && *arabic.getBuffer() <= 0x06ff)
|
||||
{
|
||||
UnicodeString shaped;
|
||||
u_shapeArabic(arabic.getBuffer(),arabic.length(),shaped.getBuffer(arabic.length()),arabic.length(),
|
||||
U_SHAPE_LETTERS_SHAPE|U_SHAPE_LENGTH_FIXED_SPACES_NEAR|
|
||||
U_SHAPE_TEXT_DIRECTION_VISUAL_LTR
|
||||
,&err);
|
||||
|
||||
shaped.releaseBuffer(arabic.length());
|
||||
|
||||
if (U_SUCCESS(err))
|
||||
{
|
||||
for (int j=0;j<shaped.length();++j)
|
||||
{
|
||||
dimension_t char_dim = character_dimensions(shaped[j]);
|
||||
info.add_info(shaped[j], char_dim.first, char_dim.second);
|
||||
width += char_dim.first;
|
||||
height = char_dim.second > height ? char_dim.second : height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ubidi_close(bidi);
|
||||
}
|
||||
|
||||
info.set_dimensions(width, height);
|
||||
}
|
||||
|
||||
void set_pixel_size(unsigned size)
|
||||
{
|
||||
face_->set_pixel_sizes(size);
|
||||
std::vector<face_ptr>::iterator itr = faces_.begin();
|
||||
std::vector<face_ptr>::iterator end = faces_.end();
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
(*itr)->set_pixel_sizes(size);
|
||||
}
|
||||
}
|
||||
|
||||
void set_fill(mapnik::Color const& fill)
|
||||
|
@ -327,12 +361,11 @@ namespace mapnik
|
|||
FT_Vector pen;
|
||||
FT_Error error;
|
||||
|
||||
FT_Face face = face_->get_face();
|
||||
// FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
FT_BBox bbox;
|
||||
bbox.xMin = bbox.yMin = 32000;
|
||||
bbox.xMax = bbox.yMax = -32000; //hmm??
|
||||
bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we
|
||||
bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later
|
||||
|
||||
std::vector<face_ptr>::iterator end = faces_.end();
|
||||
|
||||
for (int i = 0; i < path->num_nodes(); i++)
|
||||
{
|
||||
|
@ -340,8 +373,12 @@ namespace mapnik
|
|||
double x, y, angle;
|
||||
|
||||
path->vertex(&c, &x, &y, &angle);
|
||||
// std::clog << " prepare_glyph: " << (unsigned char)c << "," << x << "," << y << "," << angle << std::endl;
|
||||
|
||||
#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;
|
||||
|
@ -349,20 +386,56 @@ namespace mapnik
|
|||
pen.x = int(x * 64);
|
||||
pen.y = int(y * 64);
|
||||
|
||||
FT_Face face = (*faces_.begin())->get_face();
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(face, unsigned(c));
|
||||
|
||||
// If there's no glyph_index we loop through the remaining fonts
|
||||
// in the fontset looking for one.
|
||||
if (!glyph_index) {
|
||||
std::vector<face_ptr>::iterator itr = faces_.begin();
|
||||
++itr; // Skip the first one, we already tried it.
|
||||
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
#ifdef MAPNIK_DEBUG
|
||||
// TODO Enable when we have support for setting verbosity
|
||||
//std::clog << "prepare_glyphs: Falling back to font named \""
|
||||
// << (*itr)->family_name() << " " << (*itr)->style_name()
|
||||
// << "\"" << std::endl;
|
||||
#endif
|
||||
|
||||
FT_Face f = (*itr)->get_face();
|
||||
|
||||
glyph_index = FT_Get_Char_Index(f, unsigned(c));
|
||||
|
||||
if (glyph_index) {
|
||||
face = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAPNIK_DEBUG
|
||||
// TODO Enable when we have support for setting verbosity
|
||||
//if (!glyph_index) {
|
||||
// std::clog << "prepare_glyphs: Failed to fall back, glyph "
|
||||
// << c << " not found in any font." << std::endl;
|
||||
//}
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
FT_Set_Transform(face, &matrix, &pen);
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(c));
|
||||
|
||||
error = FT_Load_Glyph (face,glyph_index, FT_LOAD_NO_HINTING);
|
||||
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_HINTING);
|
||||
if ( error )
|
||||
continue;
|
||||
|
||||
error = FT_Get_Glyph( face->glyph, &image);
|
||||
error = FT_Get_Glyph(face->glyph, &image);
|
||||
if ( error )
|
||||
continue;
|
||||
|
||||
|
@ -376,6 +449,7 @@ namespace mapnik
|
|||
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;
|
||||
|
@ -484,7 +558,7 @@ namespace mapnik
|
|||
}
|
||||
|
||||
pixmap_type & pixmap_;
|
||||
face_ptr face_;
|
||||
std::vector<face_ptr> faces_;
|
||||
mapnik::Color fill_;
|
||||
mapnik::Color halo_fill_;
|
||||
int halo_radius_;
|
||||
|
@ -494,5 +568,4 @@ namespace mapnik
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // FONT_ENGINE_FREETYPE_HPP
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace mapnik
|
|||
std::string srs_;
|
||||
boost::optional<Color> background_;
|
||||
std::map<std::string,feature_type_style> styles_;
|
||||
std::map<std::string,FontSet> fontsets_;
|
||||
std::vector<Layer> layers_;
|
||||
Envelope<double> currentExtent_;
|
||||
|
||||
|
@ -129,6 +130,20 @@ namespace mapnik
|
|||
*/
|
||||
feature_type_style const& find_style(std::string const& name) const;
|
||||
|
||||
/*! \brief Insert a fontset into the map.
|
||||
* @param name The name of the fontset.
|
||||
* @param style The fontset to insert.
|
||||
* @return true If success.
|
||||
* @return false If failure.
|
||||
*/
|
||||
bool insert_fontset(std::string const& name, FontSet const& fontset);
|
||||
|
||||
/*! \brief Find a fontset.
|
||||
* @param name The name of the fontset.
|
||||
* @return The fontset if found. If not found return the default map fontset.
|
||||
*/
|
||||
FontSet const& find_fontset(std::string const& name) const;
|
||||
|
||||
/*! \brief Get number of all layers.
|
||||
*/
|
||||
size_t layerCount() const;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
// mapnik
|
||||
#include <mapnik/enumeration.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
// boost
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
@ -49,6 +50,7 @@ namespace mapnik
|
|||
{
|
||||
text_symbolizer(std::string const& name,std::string const& face_name,
|
||||
unsigned size, Color const& fill);
|
||||
text_symbolizer(std::string const& name, unsigned size, Color const& fill);
|
||||
text_symbolizer(text_symbolizer const& rhs);
|
||||
text_symbolizer& operator=(text_symbolizer const& rhs);
|
||||
std::string const& get_name() const;
|
||||
|
@ -66,6 +68,9 @@ namespace mapnik
|
|||
void set_max_char_angle_delta(double angle);
|
||||
unsigned get_text_size() const;
|
||||
std::string const& get_face_name() const;
|
||||
void set_face_name(std::string face_name);
|
||||
FontSet const& get_fontset() const;
|
||||
void set_fontset(FontSet fontset);
|
||||
Color const& get_fill() const;
|
||||
void set_halo_fill(Color const& fill);
|
||||
Color const& get_halo_fill() const;
|
||||
|
@ -86,6 +91,7 @@ namespace mapnik
|
|||
private:
|
||||
std::string name_;
|
||||
std::string face_name_;
|
||||
FontSet fontset_;
|
||||
unsigned size_;
|
||||
unsigned text_ratio_;
|
||||
unsigned wrap_width_;
|
||||
|
|
|
@ -47,6 +47,7 @@ source = Split(
|
|||
envelope.cpp
|
||||
filter_factory.cpp
|
||||
font_engine_freetype.cpp
|
||||
font_set.cpp
|
||||
graphics.cpp
|
||||
image_reader.cpp
|
||||
image_util.cpp
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <mapnik/markers_converter.hpp>
|
||||
#include <mapnik/arrow.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
|
||||
// agg
|
||||
#define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
|
||||
|
@ -280,7 +281,6 @@ namespace mapnik
|
|||
|
||||
frame->move_to(itr->get<0>(),itr->get<1>());
|
||||
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
||||
|
||||
}
|
||||
|
||||
geom.rewind(0);
|
||||
|
@ -310,7 +310,6 @@ namespace mapnik
|
|||
ras_ptr->add_path(roof_path);
|
||||
ren.color(agg::rgba8(r, g, b, int(255 * sym.get_opacity())));
|
||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,15 +459,20 @@ namespace mapnik
|
|||
boost::shared_ptr<ImageData32> const& data = sym.get_image();
|
||||
if (text.length() > 0 && data)
|
||||
{
|
||||
face_ptr face = font_manager_.get_face(sym.get_face_name());
|
||||
if (face)
|
||||
std::vector<face_ptr> faces;
|
||||
|
||||
faces.push_back(font_manager_.get_face(sym.get_face_name()));
|
||||
|
||||
if (faces.size() > 0)
|
||||
{
|
||||
text_renderer<mapnik::Image32> ren(pixmap_,face);
|
||||
text_renderer<mapnik::Image32> ren(pixmap_, faces);
|
||||
|
||||
ren.set_pixel_size(sym.get_text_size());
|
||||
ren.set_fill(sym.get_fill());
|
||||
|
||||
string_info info(text);
|
||||
face->get_string_info(info);
|
||||
|
||||
ren.get_string_info(info);
|
||||
|
||||
placement_finder<label_collision_detector4> finder(detector_);
|
||||
|
||||
|
@ -670,10 +674,30 @@ namespace mapnik
|
|||
if ( text.length() > 0 )
|
||||
{
|
||||
Color const& fill = sym.get_fill();
|
||||
face_ptr face = font_manager_.get_face(sym.get_face_name());
|
||||
if (face)
|
||||
|
||||
std::vector<face_ptr> faces;
|
||||
|
||||
FontSet fontset = sym.get_fontset();
|
||||
std::vector<std::string> face_names = fontset.get_face_names();
|
||||
|
||||
if (face_names.size() > 0)
|
||||
{
|
||||
text_renderer<mapnik::Image32> ren(pixmap_,face);
|
||||
std::vector<std::string>::iterator itr = face_names.begin();
|
||||
std::vector<std::string>::iterator end = face_names.end();
|
||||
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
faces.push_back(font_manager_.get_face(*itr));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
faces.push_back(font_manager_.get_face(sym.get_face_name()));
|
||||
}
|
||||
|
||||
if (faces.size() > 0)
|
||||
{
|
||||
text_renderer<mapnik::Image32> ren(pixmap_, faces);
|
||||
ren.set_pixel_size(sym.get_text_size());
|
||||
ren.set_fill(fill);
|
||||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
|
@ -682,7 +706,8 @@ namespace mapnik
|
|||
placement_finder<label_collision_detector4> finder(detector_);
|
||||
|
||||
string_info info(text);
|
||||
face->get_string_info(info);
|
||||
|
||||
ren.get_string_info(info);
|
||||
unsigned num_geom = feature.num_geometries();
|
||||
for (unsigned i=0;i<num_geom;++i)
|
||||
{
|
||||
|
|
118
src/load_map.cpp
118
src/load_map.cpp
|
@ -29,6 +29,7 @@
|
|||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
|
||||
#include <mapnik/ptree_helpers.hpp>
|
||||
#include <mapnik/libxml2_loader.hpp>
|
||||
|
@ -67,6 +68,9 @@ namespace mapnik
|
|||
void parse_style( Map & map, ptree const & sty);
|
||||
void parse_layer( Map & map, ptree const & lay);
|
||||
|
||||
void parse_fontset(Map & map, ptree const & fset);
|
||||
void parse_font(FontSet & fset, ptree const & f);
|
||||
|
||||
void parse_rule( feature_type_style & style, ptree const & r);
|
||||
|
||||
void parse_point_symbolizer( rule_type & rule, ptree const & sym);
|
||||
|
@ -79,13 +83,14 @@ namespace mapnik
|
|||
void parse_building_symbolizer( rule_type & rule, ptree const & sym );
|
||||
void parse_markers_symbolizer( rule_type & rule, ptree const & sym );
|
||||
|
||||
void ensure_font_face( const text_symbolizer & text_symbol );
|
||||
void ensure_font_face( const std::string & face_name );
|
||||
|
||||
bool strict_;
|
||||
std::map<std::string,parameters> datasource_templates_;
|
||||
freetype_engine font_engine_;
|
||||
face_manager<freetype_engine> font_manager_;
|
||||
std::map<std::string,std::string> file_sources_;
|
||||
std::map<std::string,FontSet> fontsets_;
|
||||
};
|
||||
|
||||
void load_map(Map & map, std::string const& filename, bool strict)
|
||||
|
@ -142,9 +147,12 @@ namespace mapnik
|
|||
}
|
||||
else if (v.first == "Layer")
|
||||
{
|
||||
|
||||
parse_layer(map, v.second );
|
||||
}
|
||||
else if (v.first == "FontSet")
|
||||
{
|
||||
parse_fontset(map, v.second);
|
||||
}
|
||||
else if (v.first == "FileSource")
|
||||
{
|
||||
std::string name = get_attr<string>( v.second, "name");
|
||||
|
@ -227,6 +235,71 @@ namespace mapnik
|
|||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_fontset( Map & map, ptree const & fset )
|
||||
{
|
||||
string name("<missing name>");
|
||||
try
|
||||
{
|
||||
name = get_attr<string>(fset, "name");
|
||||
FontSet fontset(name);
|
||||
|
||||
ptree::const_iterator itr = fset.begin();
|
||||
ptree::const_iterator end = fset.end();
|
||||
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
ptree::value_type const& font_tag = *itr;
|
||||
|
||||
if (font_tag.first == "Font")
|
||||
{
|
||||
parse_font(fontset, font_tag.second);
|
||||
}
|
||||
else if (font_tag.first != "<xmlcomment>" &&
|
||||
font_tag.first != "<xmlattr>" )
|
||||
{
|
||||
throw config_error(std::string("Unknown child node in 'FontSet'.") +
|
||||
"Expected 'Font' but got '" + font_tag.first + "'");
|
||||
}
|
||||
}
|
||||
|
||||
map.insert_fontset(name, fontset);
|
||||
|
||||
// XXX Hack because map object isn't accessible by text_symbolizer
|
||||
// when it's parsed
|
||||
fontsets_.insert(pair<std::string, FontSet>(name, fontset));
|
||||
} catch (const config_error & ex) {
|
||||
if ( ! name.empty() ) {
|
||||
ex.append_context(string("in FontSet '") + name + "'");
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void map_parser::parse_font(FontSet & fset, ptree const & f)
|
||||
{
|
||||
std::string face_name;
|
||||
|
||||
try
|
||||
{
|
||||
face_name = get_attr(f, "face_name", string());
|
||||
|
||||
if ( strict_ )
|
||||
{
|
||||
ensure_font_face( face_name );
|
||||
}
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
{
|
||||
if (!face_name.empty())
|
||||
{
|
||||
ex.append_context(string("in Font '") + face_name + "'");
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
fset.add_face_name(face_name);
|
||||
}
|
||||
|
||||
void map_parser::parse_layer( Map & map, ptree const & lay )
|
||||
{
|
||||
std::string name;
|
||||
|
@ -603,12 +676,39 @@ namespace mapnik
|
|||
try
|
||||
{
|
||||
std::string name = get_attr<string>(sym, "name");
|
||||
std::string face_name = get_attr<string>(sym, "face_name");
|
||||
unsigned size = get_attr(sym, "size", 10U );
|
||||
|
||||
optional<std::string> face_name =
|
||||
get_opt_attr<std::string>(sym, "face_name");
|
||||
|
||||
optional<std::string> fontset_name =
|
||||
get_opt_attr<std::string>(sym, "fontset_name");
|
||||
|
||||
unsigned size = get_attr(sym, "size", 10U);
|
||||
|
||||
Color c = get_attr(sym, "fill", Color(0,0,0));
|
||||
|
||||
text_symbolizer text_symbol(name, face_name, size, c);
|
||||
text_symbolizer text_symbol = text_symbolizer(name, size, c);
|
||||
|
||||
if (fontset_name && face_name)
|
||||
{
|
||||
throw config_error(std::string("Can't have both face_name and fontset_name"));
|
||||
}
|
||||
else if (fontset_name)
|
||||
{
|
||||
std::map<std::string,FontSet>::const_iterator itr = fontsets_.find(*fontset_name);
|
||||
if (itr != fontsets_.end())
|
||||
{
|
||||
text_symbol.set_fontset(itr->second);
|
||||
}
|
||||
}
|
||||
else if (face_name)
|
||||
{
|
||||
text_symbol.set_face_name(*face_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw config_error(std::string("Must have face_name or fontset_name"));
|
||||
}
|
||||
|
||||
int dx = get_attr(sym, "dx", 0);
|
||||
int dy = get_attr(sym, "dy", 0);
|
||||
|
@ -683,7 +783,7 @@ namespace mapnik
|
|||
|
||||
if ( strict_ )
|
||||
{
|
||||
ensure_font_face( text_symbol );
|
||||
ensure_font_face( text_symbol.get_face_name() );
|
||||
}
|
||||
|
||||
rule.append(text_symbol);
|
||||
|
@ -913,12 +1013,12 @@ namespace mapnik
|
|||
}
|
||||
}
|
||||
|
||||
void map_parser::ensure_font_face( const text_symbolizer & text_symbol )
|
||||
void map_parser::ensure_font_face( const std::string & face_name )
|
||||
{
|
||||
if ( ! font_manager_.get_face( text_symbol.get_face_name() ) )
|
||||
if ( ! font_manager_.get_face( face_name ) )
|
||||
{
|
||||
throw config_error("Failed to find font face '" +
|
||||
text_symbol.get_face_name() + "'");
|
||||
face_name + "'");
|
||||
}
|
||||
}
|
||||
} // end of namespace mapnik
|
||||
|
|
14
src/map.cpp
14
src/map.cpp
|
@ -102,6 +102,20 @@ namespace mapnik
|
|||
styles_.erase(name);
|
||||
}
|
||||
|
||||
bool Map::insert_fontset(std::string const& name, FontSet const& fontset)
|
||||
{
|
||||
return fontsets_.insert(make_pair(name, fontset)).second;
|
||||
}
|
||||
|
||||
FontSet const& Map::find_fontset(std::string const& name) const
|
||||
{
|
||||
std::map<std::string,FontSet>::const_iterator itr = fontsets_.find(name);
|
||||
if (itr!=fontsets_.end())
|
||||
return itr->second;
|
||||
static FontSet default_fontset;
|
||||
return default_fontset;
|
||||
}
|
||||
|
||||
feature_type_style const& Map::find_style(std::string const& name) const
|
||||
{
|
||||
std::map<std::string,feature_type_style>::const_iterator itr = styles_.find(name);
|
||||
|
|
|
@ -35,13 +35,35 @@ static const char * label_placement_strings[] = {
|
|||
""
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_ENUM( mapnik::label_placement_e, label_placement_strings );
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size,Color const& fill)
|
||||
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size, Color const& fill)
|
||||
: name_(name),
|
||||
face_name_(face_name),
|
||||
//fontset_(default_fontset),
|
||||
size_(size),
|
||||
text_ratio_(0),
|
||||
wrap_width_(0),
|
||||
label_spacing_(0),
|
||||
label_position_tolerance_(0),
|
||||
force_odd_labels_(false),
|
||||
max_char_angle_delta_(0),
|
||||
fill_(fill),
|
||||
halo_fill_(Color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(POINT_PLACEMENT),
|
||||
anchor_(0.0,0.5),
|
||||
displacement_(0.0,0.0),
|
||||
avoid_edges_(false),
|
||||
minimum_distance_(0.0),
|
||||
overlap_(false) {}
|
||||
text_symbolizer::text_symbolizer(std::string const& name, unsigned size, Color const& fill)
|
||||
: name_(name),
|
||||
//face_name_(""),
|
||||
//fontset_(default_fontset),
|
||||
size_(size),
|
||||
text_ratio_(0),
|
||||
wrap_width_(0),
|
||||
|
@ -61,6 +83,7 @@ namespace mapnik
|
|||
text_symbolizer::text_symbolizer(text_symbolizer const& rhs)
|
||||
: name_(rhs.name_),
|
||||
face_name_(rhs.face_name_),
|
||||
fontset_(rhs.fontset_),
|
||||
size_(rhs.size_),
|
||||
text_ratio_(rhs.text_ratio_),
|
||||
wrap_width_(rhs.wrap_width_),
|
||||
|
@ -84,6 +107,7 @@ namespace mapnik
|
|||
return *this;
|
||||
name_ = other.name_;
|
||||
face_name_ = other.face_name_;
|
||||
fontset_ = other.fontset_;
|
||||
size_ = other.size_;
|
||||
text_ratio_ = other.text_ratio_;
|
||||
wrap_width_ = other.wrap_width_;
|
||||
|
@ -114,6 +138,21 @@ namespace mapnik
|
|||
return face_name_;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_face_name(std::string face_name)
|
||||
{
|
||||
face_name_ = face_name;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_fontset(FontSet fontset)
|
||||
{
|
||||
fontset_ = fontset;
|
||||
}
|
||||
|
||||
FontSet const& text_symbolizer::get_fontset() const
|
||||
{
|
||||
return fontset_;
|
||||
}
|
||||
|
||||
unsigned text_symbolizer::get_text_ratio() const
|
||||
{
|
||||
return text_ratio_;
|
||||
|
|
Loading…
Reference in a new issue