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/ctrans.hpp>
|
||||||
#include <mapnik/geometry.hpp>
|
#include <mapnik/geometry.hpp>
|
||||||
#include <mapnik/text_path.hpp>
|
#include <mapnik/text_path.hpp>
|
||||||
|
#include <mapnik/font_set.hpp>
|
||||||
|
|
||||||
// freetype2
|
// freetype2
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -61,8 +62,6 @@ namespace mapnik
|
||||||
class font_face : boost::noncopyable
|
class font_face : boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::pair<unsigned,unsigned> dimension_t;
|
|
||||||
|
|
||||||
font_face(FT_Face face)
|
font_face(FT_Face face)
|
||||||
: face_(face) {}
|
: face_(face) {}
|
||||||
|
|
||||||
|
@ -104,122 +103,11 @@ namespace mapnik
|
||||||
return false;
|
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()
|
~font_face()
|
||||||
{
|
{
|
||||||
#ifdef MAPNIK_DEBUG
|
#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
|
#endif
|
||||||
FT_Done_Face(face_);
|
FT_Done_Face(face_);
|
||||||
}
|
}
|
||||||
|
@ -229,6 +117,7 @@ namespace mapnik
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::shared_ptr<font_face> face_ptr;
|
typedef boost::shared_ptr<font_face> face_ptr;
|
||||||
|
|
||||||
class MAPNIK_DECL freetype_engine // : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>,
|
class MAPNIK_DECL freetype_engine // : public mapnik::singleton<freetype_engine,mapnik::CreateStatic>,
|
||||||
// private boost::noncopyable
|
// private boost::noncopyable
|
||||||
{
|
{
|
||||||
|
@ -281,6 +170,8 @@ namespace mapnik
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct text_renderer : private boost::noncopyable
|
struct text_renderer : private boost::noncopyable
|
||||||
{
|
{
|
||||||
|
typedef std::pair<unsigned,unsigned> dimension_t;
|
||||||
|
|
||||||
struct glyph_t : boost::noncopyable
|
struct glyph_t : boost::noncopyable
|
||||||
{
|
{
|
||||||
FT_Glyph image;
|
FT_Glyph image;
|
||||||
|
@ -291,16 +182,159 @@ namespace mapnik
|
||||||
typedef boost::ptr_vector<glyph_t> glyphs_t;
|
typedef boost::ptr_vector<glyph_t> glyphs_t;
|
||||||
typedef T pixmap_type;
|
typedef T pixmap_type;
|
||||||
|
|
||||||
text_renderer (pixmap_type & pixmap, face_ptr face)
|
text_renderer (pixmap_type & pixmap, std::vector<face_ptr> faces)
|
||||||
: pixmap_(pixmap),
|
: pixmap_(pixmap),
|
||||||
face_(face),
|
faces_(faces),
|
||||||
fill_(0,0,0),
|
fill_(0,0,0),
|
||||||
halo_fill_(255,255,255),
|
halo_fill_(255,255,255),
|
||||||
halo_radius_(0) {}
|
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)
|
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)
|
void set_fill(mapnik::Color const& fill)
|
||||||
|
@ -327,12 +361,11 @@ namespace mapnik
|
||||||
FT_Vector pen;
|
FT_Vector pen;
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
|
|
||||||
FT_Face face = face_->get_face();
|
|
||||||
// FT_GlyphSlot slot = face->glyph;
|
|
||||||
|
|
||||||
FT_BBox bbox;
|
FT_BBox bbox;
|
||||||
bbox.xMin = bbox.yMin = 32000;
|
bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we
|
||||||
bbox.xMax = bbox.yMax = -32000; //hmm??
|
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++)
|
for (int i = 0; i < path->num_nodes(); i++)
|
||||||
{
|
{
|
||||||
|
@ -340,8 +373,12 @@ namespace mapnik
|
||||||
double x, y, angle;
|
double x, y, angle;
|
||||||
|
|
||||||
path->vertex(&c, &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_BBox glyph_bbox;
|
||||||
FT_Glyph image;
|
FT_Glyph image;
|
||||||
|
@ -349,20 +386,56 @@ namespace mapnik
|
||||||
pen.x = int(x * 64);
|
pen.x = int(x * 64);
|
||||||
pen.y = int(y * 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.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
|
||||||
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
|
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
|
||||||
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
|
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
|
||||||
matrix.yy = (FT_Fixed)( cos( 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 )
|
if ( error )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
error = FT_Get_Glyph( face->glyph, &image);
|
error = FT_Get_Glyph(face->glyph, &image);
|
||||||
if ( error )
|
if ( error )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -376,6 +449,7 @@ namespace mapnik
|
||||||
if (glyph_bbox.yMax > bbox.yMax)
|
if (glyph_bbox.yMax > bbox.yMax)
|
||||||
bbox.yMax = glyph_bbox.yMax;
|
bbox.yMax = glyph_bbox.yMax;
|
||||||
|
|
||||||
|
// Check if we properly grew the bbox
|
||||||
if ( bbox.xMin > bbox.xMax )
|
if ( bbox.xMin > bbox.xMax )
|
||||||
{
|
{
|
||||||
bbox.xMin = 0;
|
bbox.xMin = 0;
|
||||||
|
@ -484,7 +558,7 @@ namespace mapnik
|
||||||
}
|
}
|
||||||
|
|
||||||
pixmap_type & pixmap_;
|
pixmap_type & pixmap_;
|
||||||
face_ptr face_;
|
std::vector<face_ptr> faces_;
|
||||||
mapnik::Color fill_;
|
mapnik::Color fill_;
|
||||||
mapnik::Color halo_fill_;
|
mapnik::Color halo_fill_;
|
||||||
int halo_radius_;
|
int halo_radius_;
|
||||||
|
@ -494,5 +568,4 @@ namespace mapnik
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // FONT_ENGINE_FREETYPE_HPP
|
#endif // FONT_ENGINE_FREETYPE_HPP
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace mapnik
|
||||||
std::string srs_;
|
std::string srs_;
|
||||||
boost::optional<Color> background_;
|
boost::optional<Color> background_;
|
||||||
std::map<std::string,feature_type_style> styles_;
|
std::map<std::string,feature_type_style> styles_;
|
||||||
|
std::map<std::string,FontSet> fontsets_;
|
||||||
std::vector<Layer> layers_;
|
std::vector<Layer> layers_;
|
||||||
Envelope<double> currentExtent_;
|
Envelope<double> currentExtent_;
|
||||||
|
|
||||||
|
@ -129,6 +130,20 @@ namespace mapnik
|
||||||
*/
|
*/
|
||||||
feature_type_style const& find_style(std::string const& name) const;
|
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.
|
/*! \brief Get number of all layers.
|
||||||
*/
|
*/
|
||||||
size_t layerCount() const;
|
size_t layerCount() const;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/enumeration.hpp>
|
#include <mapnik/enumeration.hpp>
|
||||||
#include <mapnik/color.hpp>
|
#include <mapnik/color.hpp>
|
||||||
|
#include <mapnik/font_set.hpp>
|
||||||
#include <mapnik/graphics.hpp>
|
#include <mapnik/graphics.hpp>
|
||||||
// boost
|
// boost
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
@ -49,6 +50,7 @@ namespace mapnik
|
||||||
{
|
{
|
||||||
text_symbolizer(std::string const& name,std::string const& face_name,
|
text_symbolizer(std::string const& name,std::string const& face_name,
|
||||||
unsigned size, Color const& fill);
|
unsigned size, Color const& fill);
|
||||||
|
text_symbolizer(std::string const& name, unsigned size, Color const& fill);
|
||||||
text_symbolizer(text_symbolizer const& rhs);
|
text_symbolizer(text_symbolizer const& rhs);
|
||||||
text_symbolizer& operator=(text_symbolizer const& rhs);
|
text_symbolizer& operator=(text_symbolizer const& rhs);
|
||||||
std::string const& get_name() const;
|
std::string const& get_name() const;
|
||||||
|
@ -66,6 +68,9 @@ namespace mapnik
|
||||||
void set_max_char_angle_delta(double angle);
|
void set_max_char_angle_delta(double angle);
|
||||||
unsigned get_text_size() const;
|
unsigned get_text_size() const;
|
||||||
std::string const& get_face_name() 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;
|
Color const& get_fill() const;
|
||||||
void set_halo_fill(Color const& fill);
|
void set_halo_fill(Color const& fill);
|
||||||
Color const& get_halo_fill() const;
|
Color const& get_halo_fill() const;
|
||||||
|
@ -86,6 +91,7 @@ namespace mapnik
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
std::string face_name_;
|
std::string face_name_;
|
||||||
|
FontSet fontset_;
|
||||||
unsigned size_;
|
unsigned size_;
|
||||||
unsigned text_ratio_;
|
unsigned text_ratio_;
|
||||||
unsigned wrap_width_;
|
unsigned wrap_width_;
|
||||||
|
|
|
@ -47,6 +47,7 @@ source = Split(
|
||||||
envelope.cpp
|
envelope.cpp
|
||||||
filter_factory.cpp
|
filter_factory.cpp
|
||||||
font_engine_freetype.cpp
|
font_engine_freetype.cpp
|
||||||
|
font_set.cpp
|
||||||
graphics.cpp
|
graphics.cpp
|
||||||
image_reader.cpp
|
image_reader.cpp
|
||||||
image_util.cpp
|
image_util.cpp
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <mapnik/markers_converter.hpp>
|
#include <mapnik/markers_converter.hpp>
|
||||||
#include <mapnik/arrow.hpp>
|
#include <mapnik/arrow.hpp>
|
||||||
#include <mapnik/config_error.hpp>
|
#include <mapnik/config_error.hpp>
|
||||||
|
#include <mapnik/font_set.hpp>
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
#define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
|
#define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
|
||||||
|
@ -280,7 +281,6 @@ namespace mapnik
|
||||||
|
|
||||||
frame->move_to(itr->get<0>(),itr->get<1>());
|
frame->move_to(itr->get<0>(),itr->get<1>());
|
||||||
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
frame->line_to(itr->get<0>(),itr->get<1>()+height);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geom.rewind(0);
|
geom.rewind(0);
|
||||||
|
@ -310,7 +310,6 @@ namespace mapnik
|
||||||
ras_ptr->add_path(roof_path);
|
ras_ptr->add_path(roof_path);
|
||||||
ren.color(agg::rgba8(r, g, b, int(255 * sym.get_opacity())));
|
ren.color(agg::rgba8(r, g, b, int(255 * sym.get_opacity())));
|
||||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -460,15 +459,20 @@ namespace mapnik
|
||||||
boost::shared_ptr<ImageData32> const& data = sym.get_image();
|
boost::shared_ptr<ImageData32> const& data = sym.get_image();
|
||||||
if (text.length() > 0 && data)
|
if (text.length() > 0 && data)
|
||||||
{
|
{
|
||||||
face_ptr face = font_manager_.get_face(sym.get_face_name());
|
std::vector<face_ptr> faces;
|
||||||
if (face)
|
|
||||||
|
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_pixel_size(sym.get_text_size());
|
||||||
ren.set_fill(sym.get_fill());
|
ren.set_fill(sym.get_fill());
|
||||||
|
|
||||||
string_info info(text);
|
string_info info(text);
|
||||||
face->get_string_info(info);
|
|
||||||
|
ren.get_string_info(info);
|
||||||
|
|
||||||
placement_finder<label_collision_detector4> finder(detector_);
|
placement_finder<label_collision_detector4> finder(detector_);
|
||||||
|
|
||||||
|
@ -670,10 +674,30 @@ namespace mapnik
|
||||||
if ( text.length() > 0 )
|
if ( text.length() > 0 )
|
||||||
{
|
{
|
||||||
Color const& fill = sym.get_fill();
|
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_pixel_size(sym.get_text_size());
|
||||||
ren.set_fill(fill);
|
ren.set_fill(fill);
|
||||||
ren.set_halo_fill(sym.get_halo_fill());
|
ren.set_halo_fill(sym.get_halo_fill());
|
||||||
|
@ -682,7 +706,8 @@ namespace mapnik
|
||||||
placement_finder<label_collision_detector4> finder(detector_);
|
placement_finder<label_collision_detector4> finder(detector_);
|
||||||
|
|
||||||
string_info info(text);
|
string_info info(text);
|
||||||
face->get_string_info(info);
|
|
||||||
|
ren.get_string_info(info);
|
||||||
unsigned num_geom = feature.num_geometries();
|
unsigned num_geom = feature.num_geometries();
|
||||||
for (unsigned i=0;i<num_geom;++i)
|
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/layer.hpp>
|
||||||
#include <mapnik/datasource_cache.hpp>
|
#include <mapnik/datasource_cache.hpp>
|
||||||
#include <mapnik/font_engine_freetype.hpp>
|
#include <mapnik/font_engine_freetype.hpp>
|
||||||
|
#include <mapnik/font_set.hpp>
|
||||||
|
|
||||||
#include <mapnik/ptree_helpers.hpp>
|
#include <mapnik/ptree_helpers.hpp>
|
||||||
#include <mapnik/libxml2_loader.hpp>
|
#include <mapnik/libxml2_loader.hpp>
|
||||||
|
@ -67,6 +68,9 @@ namespace mapnik
|
||||||
void parse_style( Map & map, ptree const & sty);
|
void parse_style( Map & map, ptree const & sty);
|
||||||
void parse_layer( Map & map, ptree const & lay);
|
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_rule( feature_type_style & style, ptree const & r);
|
||||||
|
|
||||||
void parse_point_symbolizer( rule_type & rule, ptree const & sym);
|
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_building_symbolizer( rule_type & rule, ptree const & sym );
|
||||||
void parse_markers_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_;
|
bool strict_;
|
||||||
std::map<std::string,parameters> datasource_templates_;
|
std::map<std::string,parameters> datasource_templates_;
|
||||||
freetype_engine font_engine_;
|
freetype_engine font_engine_;
|
||||||
face_manager<freetype_engine> font_manager_;
|
face_manager<freetype_engine> font_manager_;
|
||||||
std::map<std::string,std::string> file_sources_;
|
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)
|
void load_map(Map & map, std::string const& filename, bool strict)
|
||||||
|
@ -142,9 +147,12 @@ namespace mapnik
|
||||||
}
|
}
|
||||||
else if (v.first == "Layer")
|
else if (v.first == "Layer")
|
||||||
{
|
{
|
||||||
|
|
||||||
parse_layer(map, v.second );
|
parse_layer(map, v.second );
|
||||||
}
|
}
|
||||||
|
else if (v.first == "FontSet")
|
||||||
|
{
|
||||||
|
parse_fontset(map, v.second);
|
||||||
|
}
|
||||||
else if (v.first == "FileSource")
|
else if (v.first == "FileSource")
|
||||||
{
|
{
|
||||||
std::string name = get_attr<string>( v.second, "name");
|
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 )
|
void map_parser::parse_layer( Map & map, ptree const & lay )
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -603,12 +676,39 @@ namespace mapnik
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string name = get_attr<string>(sym, "name");
|
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));
|
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 dx = get_attr(sym, "dx", 0);
|
||||||
int dy = get_attr(sym, "dy", 0);
|
int dy = get_attr(sym, "dy", 0);
|
||||||
|
@ -683,7 +783,7 @@ namespace mapnik
|
||||||
|
|
||||||
if ( strict_ )
|
if ( strict_ )
|
||||||
{
|
{
|
||||||
ensure_font_face( text_symbol );
|
ensure_font_face( text_symbol.get_face_name() );
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.append(text_symbol);
|
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 '" +
|
throw config_error("Failed to find font face '" +
|
||||||
text_symbol.get_face_name() + "'");
|
face_name + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end of namespace mapnik
|
} // end of namespace mapnik
|
||||||
|
|
14
src/map.cpp
14
src/map.cpp
|
@ -102,6 +102,20 @@ namespace mapnik
|
||||||
styles_.erase(name);
|
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
|
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);
|
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 );
|
IMPLEMENT_ENUM( mapnik::label_placement_e, label_placement_strings );
|
||||||
|
|
||||||
namespace mapnik
|
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),
|
: name_(name),
|
||||||
face_name_(face_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),
|
size_(size),
|
||||||
text_ratio_(0),
|
text_ratio_(0),
|
||||||
wrap_width_(0),
|
wrap_width_(0),
|
||||||
|
@ -61,6 +83,7 @@ namespace mapnik
|
||||||
text_symbolizer::text_symbolizer(text_symbolizer const& rhs)
|
text_symbolizer::text_symbolizer(text_symbolizer const& rhs)
|
||||||
: name_(rhs.name_),
|
: name_(rhs.name_),
|
||||||
face_name_(rhs.face_name_),
|
face_name_(rhs.face_name_),
|
||||||
|
fontset_(rhs.fontset_),
|
||||||
size_(rhs.size_),
|
size_(rhs.size_),
|
||||||
text_ratio_(rhs.text_ratio_),
|
text_ratio_(rhs.text_ratio_),
|
||||||
wrap_width_(rhs.wrap_width_),
|
wrap_width_(rhs.wrap_width_),
|
||||||
|
@ -84,6 +107,7 @@ namespace mapnik
|
||||||
return *this;
|
return *this;
|
||||||
name_ = other.name_;
|
name_ = other.name_;
|
||||||
face_name_ = other.face_name_;
|
face_name_ = other.face_name_;
|
||||||
|
fontset_ = other.fontset_;
|
||||||
size_ = other.size_;
|
size_ = other.size_;
|
||||||
text_ratio_ = other.text_ratio_;
|
text_ratio_ = other.text_ratio_;
|
||||||
wrap_width_ = other.wrap_width_;
|
wrap_width_ = other.wrap_width_;
|
||||||
|
@ -114,6 +138,21 @@ namespace mapnik
|
||||||
return face_name_;
|
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
|
unsigned text_symbolizer::get_text_ratio() const
|
||||||
{
|
{
|
||||||
return text_ratio_;
|
return text_ratio_;
|
||||||
|
|
Loading…
Reference in a new issue