Large manual merge. A lot of the changes could not be applied directly
as a different solution was used in the new branch. Merge commit '6cbceafc45eda71ae379a3dfd7c52712ebe8422b' into harfbuzz Conflicts: include/mapnik/font_engine_freetype.hpp src/font_engine_freetype.cpp src/grid/process_text_symbolizer.cpp
This commit is contained in:
commit
290c2b4a26
15 changed files with 366 additions and 295 deletions
|
@ -73,23 +73,9 @@ void check_object_status_and_throw_exception(const T& object)
|
||||||
class cairo_face : private mapnik::noncopyable
|
class cairo_face : private mapnik::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cairo_face(boost::shared_ptr<freetype_engine> const& engine, face_ptr const& face)
|
cairo_face(boost::shared_ptr<freetype_engine> const& engine, face_ptr const& face);
|
||||||
: face_(face)
|
~cairo_face();
|
||||||
{
|
cairo_font_face_t * face() const;
|
||||||
static cairo_user_data_key_t key;
|
|
||||||
c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING);
|
|
||||||
cairo_font_face_set_user_data(c_face_, &key, new handle(engine, face), destroy);
|
|
||||||
}
|
|
||||||
~cairo_face()
|
|
||||||
{
|
|
||||||
if (c_face_) cairo_font_face_destroy(c_face_);
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_font_face_t * face() const
|
|
||||||
{
|
|
||||||
return c_face_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class handle
|
class handle
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,21 +27,11 @@
|
||||||
#include <mapnik/config.hpp>
|
#include <mapnik/config.hpp>
|
||||||
#include <mapnik/box2d.hpp>
|
#include <mapnik/box2d.hpp>
|
||||||
#include <mapnik/font_set.hpp>
|
#include <mapnik/font_set.hpp>
|
||||||
#include <mapnik/text/face.hpp>
|
|
||||||
#include <mapnik/text_symbolizer.hpp>
|
#include <mapnik/text_symbolizer.hpp>
|
||||||
#include <mapnik/noncopyable.hpp>
|
#include <mapnik/noncopyable.hpp>
|
||||||
#include <mapnik/value_types.hpp>
|
#include <mapnik/value_types.hpp>
|
||||||
#include <mapnik/pixel_position.hpp>
|
#include <mapnik/pixel_position.hpp>
|
||||||
|
|
||||||
// freetype2
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include FT_GLYPH_H
|
|
||||||
#include FT_STROKER_H
|
|
||||||
}
|
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/ptr_container/ptr_vector.hpp>
|
#include <boost/ptr_container/ptr_vector.hpp>
|
||||||
|
@ -53,27 +43,20 @@ extern "C"
|
||||||
//// stl
|
//// stl
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
struct FT_LibraryRec_;
|
||||||
|
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
{
|
{
|
||||||
struct char_properties;
|
//struct char_properties;
|
||||||
typedef std::vector<face_ptr> container_type;
|
// typedef std::vector<face_ptr> container_type;
|
||||||
typedef container_type::size_type size_type;
|
// typedef container_type::size_type size_type;
|
||||||
|
|
||||||
|
class stroker;
|
||||||
// FT_Stroker wrapper
|
|
||||||
class stroker : mapnik::noncopyable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit stroker(FT_Stroker s)
|
|
||||||
: s_(s) {}
|
|
||||||
~stroker();
|
|
||||||
|
|
||||||
void init(double radius);
|
|
||||||
FT_Stroker const& get() const { return s_; }
|
|
||||||
private:
|
|
||||||
FT_Stroker s_;
|
|
||||||
};
|
|
||||||
typedef boost::shared_ptr<stroker> stroker_ptr;
|
typedef boost::shared_ptr<stroker> stroker_ptr;
|
||||||
|
class font_face_set;
|
||||||
|
typedef boost::shared_ptr<font_face_set> face_set_ptr;
|
||||||
|
class font_face;
|
||||||
|
typedef boost::shared_ptr<font_face> face_ptr;
|
||||||
|
|
||||||
|
|
||||||
class MAPNIK_DECL freetype_engine
|
class MAPNIK_DECL freetype_engine
|
||||||
|
@ -98,7 +81,7 @@ public:
|
||||||
virtual ~freetype_engine();
|
virtual ~freetype_engine();
|
||||||
freetype_engine();
|
freetype_engine();
|
||||||
private:
|
private:
|
||||||
FT_Library library_;
|
FT_LibraryRec_ *library_;
|
||||||
#ifdef MAPNIK_THREADSAFE
|
#ifdef MAPNIK_THREADSAFE
|
||||||
static boost::mutex mutex_;
|
static boost::mutex mutex_;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,9 +30,6 @@
|
||||||
#include <mapnik/gradient.hpp>
|
#include <mapnik/gradient.hpp>
|
||||||
#include <mapnik/noncopyable.hpp>
|
#include <mapnik/noncopyable.hpp>
|
||||||
|
|
||||||
// boost
|
|
||||||
#include <libxml/xmlreader.h>
|
|
||||||
|
|
||||||
// stl
|
// stl
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
@ -45,34 +42,13 @@ namespace mapnik { namespace svg {
|
||||||
~svg_parser();
|
~svg_parser();
|
||||||
void parse(std::string const& filename);
|
void parse(std::string const& filename);
|
||||||
void parse_from_string(std::string const& svg);
|
void parse_from_string(std::string const& svg);
|
||||||
private:
|
|
||||||
bool parse_reader(xmlTextReaderPtr reader);
|
|
||||||
void process_node(xmlTextReaderPtr reader);
|
|
||||||
void start_element(xmlTextReaderPtr reader);
|
|
||||||
void end_element(xmlTextReaderPtr reader);
|
|
||||||
void parse_path(xmlTextReaderPtr reader);
|
|
||||||
void parse_dimensions(xmlTextReaderPtr reader);
|
|
||||||
void parse_polygon(xmlTextReaderPtr reader);
|
|
||||||
void parse_polyline(xmlTextReaderPtr reader);
|
|
||||||
void parse_line(xmlTextReaderPtr reader);
|
|
||||||
void parse_rect(xmlTextReaderPtr reader);
|
|
||||||
void parse_circle(xmlTextReaderPtr reader);
|
|
||||||
void parse_ellipse(xmlTextReaderPtr reader);
|
|
||||||
void parse_linear_gradient(xmlTextReaderPtr reader);
|
|
||||||
void parse_radial_gradient(xmlTextReaderPtr reader);
|
|
||||||
bool parse_common_gradient(xmlTextReaderPtr reader);
|
|
||||||
void parse_gradient_stop(xmlTextReaderPtr reader);
|
|
||||||
void parse_pattern(xmlTextReaderPtr reader);
|
|
||||||
void parse_attr(xmlTextReaderPtr reader);
|
|
||||||
void parse_attr(const xmlChar * name, const xmlChar * value );
|
|
||||||
private:
|
|
||||||
svg_converter_type & path_;
|
svg_converter_type & path_;
|
||||||
bool is_defs_;
|
bool is_defs_;
|
||||||
std::map<std::string, gradient> gradient_map_;
|
std::map<std::string, gradient> gradient_map_;
|
||||||
std::pair<std::string, gradient> temporary_gradient_;
|
std::pair<std::string, gradient> temporary_gradient_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
#endif // MAPNIK_SVG_PARSER_HPP
|
#endif // MAPNIK_SVG_PARSER_HPP
|
||||||
|
|
|
@ -25,16 +25,17 @@
|
||||||
//mapnik
|
//mapnik
|
||||||
#include <mapnik/text/glyph_info.hpp>
|
#include <mapnik/text/glyph_info.hpp>
|
||||||
#include <mapnik/config.hpp>
|
#include <mapnik/config.hpp>
|
||||||
|
#include <mapnik/noncopyable.hpp>
|
||||||
|
|
||||||
// freetype2
|
// freetype2
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_STROKER_H
|
||||||
}
|
}
|
||||||
|
|
||||||
//boost
|
//boost
|
||||||
#include <boost/utility.hpp>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
//stl
|
//stl
|
||||||
|
@ -45,7 +46,7 @@ extern "C"
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
{
|
{
|
||||||
|
|
||||||
class font_face : boost::noncopyable
|
class font_face : mapnik::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
font_face(FT_Face face);
|
font_face(FT_Face face);
|
||||||
|
@ -78,10 +79,10 @@ private:
|
||||||
mutable std::map<glyph_index_t, glyph_info> dimension_cache_;
|
mutable std::map<glyph_index_t, glyph_info> dimension_cache_;
|
||||||
mutable double char_height_;
|
mutable double char_height_;
|
||||||
};
|
};
|
||||||
|
typedef boost::shared_ptr<font_face> face_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
class MAPNIK_DECL font_face_set : private mapnik::noncopyable
|
||||||
class MAPNIK_DECL font_face_set : private boost::noncopyable
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::vector<face_ptr>::iterator iterator;
|
typedef std::vector<face_ptr>::iterator iterator;
|
||||||
|
@ -99,6 +100,20 @@ private:
|
||||||
typedef boost::shared_ptr<font_face_set> face_set_ptr;
|
typedef boost::shared_ptr<font_face_set> face_set_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
// FT_Stroker wrapper
|
||||||
|
class stroker : mapnik::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit stroker(FT_Stroker s)
|
||||||
|
: s_(s) {}
|
||||||
|
~stroker();
|
||||||
|
|
||||||
|
void init(double radius);
|
||||||
|
FT_Stroker const& get() const { return s_; }
|
||||||
|
private:
|
||||||
|
FT_Stroker s_;
|
||||||
|
};
|
||||||
|
|
||||||
} //ns mapnik
|
} //ns mapnik
|
||||||
|
|
||||||
#endif // FACE_HPP
|
#endif // FACE_HPP
|
||||||
|
|
|
@ -1,3 +1,25 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Artem Pavlenko
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
#ifndef MAPNIK_TEXT_RENDERER_HPP
|
#ifndef MAPNIK_TEXT_RENDERER_HPP
|
||||||
#define MAPNIK_TEXT_RENDERER_HPP
|
#define MAPNIK_TEXT_RENDERER_HPP
|
||||||
|
|
||||||
|
@ -10,43 +32,27 @@
|
||||||
|
|
||||||
//boost
|
//boost
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
struct FT_Bitmap_;
|
||||||
// freetype2
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include FT_GLYPH_H
|
|
||||||
#include FT_STROKER_H
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct glyph_t;
|
||||||
|
|
||||||
class text_renderer : private boost::noncopyable
|
class text_renderer : private boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
text_renderer (halo_rasterizer_e rasterizer, composite_mode_e comp_op = src_over, double scale_factor=1.0, stroker_ptr stroker=stroker_ptr());
|
text_renderer (halo_rasterizer_e rasterizer, composite_mode_e comp_op = src_over, double scale_factor=1.0, stroker_ptr stroker=stroker_ptr());
|
||||||
protected:
|
protected:
|
||||||
struct glyph_t : boost::noncopyable
|
typedef boost::ptr_vector<glyph_t> glyph_vector;
|
||||||
{
|
|
||||||
FT_Glyph image;
|
|
||||||
char_properties_ptr properties;
|
|
||||||
|
|
||||||
glyph_t(FT_Glyph image_, char_properties_ptr properties_)
|
|
||||||
: image(image_), properties(properties_) {}
|
|
||||||
|
|
||||||
~glyph_t () { FT_Done_Glyph(image);}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void prepare_glyphs(glyph_positions_ptr pos);
|
void prepare_glyphs(glyph_positions_ptr pos);
|
||||||
|
|
||||||
halo_rasterizer_e rasterizer_;
|
halo_rasterizer_e rasterizer_;
|
||||||
composite_mode_e comp_op_;
|
composite_mode_e comp_op_;
|
||||||
double scale_factor_;
|
double scale_factor_;
|
||||||
boost::ptr_vector<glyph_t> glyphs_;
|
boost::shared_ptr<glyph_vector> glyphs_;
|
||||||
stroker_ptr stroker_;
|
stroker_ptr stroker_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -63,7 +69,7 @@ public:
|
||||||
void render(glyph_positions_ptr pos);
|
void render(glyph_positions_ptr pos);
|
||||||
private:
|
private:
|
||||||
pixmap_type & pixmap_;
|
pixmap_type & pixmap_;
|
||||||
void render_halo(FT_Bitmap *bitmap, unsigned rgba, int x, int y,
|
void render_halo(FT_Bitmap_ *bitmap, unsigned rgba, int x, int y,
|
||||||
int halo_radius, double opacity,
|
int halo_radius, double opacity,
|
||||||
composite_mode_e comp_op);
|
composite_mode_e comp_op);
|
||||||
};
|
};
|
||||||
|
@ -78,7 +84,7 @@ public:
|
||||||
void render(glyph_positions_ptr pos, value_integer feature_id);
|
void render(glyph_positions_ptr pos, value_integer feature_id);
|
||||||
private:
|
private:
|
||||||
pixmap_type & pixmap_;
|
pixmap_type & pixmap_;
|
||||||
void render_halo_id(FT_Bitmap *bitmap, mapnik::value_integer feature_id, int x, int y, int halo_radius);
|
void render_halo_id(FT_Bitmap_ *bitmap, mapnik::value_integer feature_id, int x, int y, int halo_radius);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,10 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/feature.hpp>
|
|
||||||
#include <mapnik/agg_renderer.hpp>
|
#include <mapnik/agg_renderer.hpp>
|
||||||
#include <mapnik/graphics.hpp>
|
#include <mapnik/graphics.hpp>
|
||||||
#include <mapnik/text/symbolizer_helpers.hpp>
|
#include <mapnik/text/symbolizer_helpers.hpp>
|
||||||
#include <mapnik/text/renderer.hpp>
|
#include <mapnik/text/renderer.hpp>
|
||||||
#include <mapnik/pixel_position.hpp>
|
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/feature.hpp>
|
|
||||||
#include <mapnik/agg_renderer.hpp>
|
#include <mapnik/agg_renderer.hpp>
|
||||||
|
#include <mapnik/graphics.hpp>
|
||||||
#include <mapnik/text/symbolizer_helpers.hpp>
|
#include <mapnik/text/symbolizer_helpers.hpp>
|
||||||
#include <mapnik/text/renderer.hpp>
|
#include <mapnik/text/renderer.hpp>
|
||||||
|
|
||||||
|
// boost
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <mapnik/graphics.hpp>
|
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,28 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include <mapnik/cairo_context.hpp>
|
#include <mapnik/cairo_context.hpp>
|
||||||
|
#include <mapnik/text/face.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
|
cairo_face::cairo_face(boost::shared_ptr<freetype_engine> const& engine, face_ptr const& face)
|
||||||
|
: face_(face)
|
||||||
|
{
|
||||||
|
static cairo_user_data_key_t key;
|
||||||
|
c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING);
|
||||||
|
cairo_font_face_set_user_data(c_face_, &key, new handle(engine, face), destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_face::~cairo_face()
|
||||||
|
{
|
||||||
|
if (c_face_) cairo_font_face_destroy(c_face_);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_font_face_t * cairo_face::face() const
|
||||||
|
{
|
||||||
|
return c_face_;
|
||||||
|
}
|
||||||
|
|
||||||
cairo_context::cairo_context(cairo_ptr const& cairo)
|
cairo_context::cairo_context(cairo_ptr const& cairo)
|
||||||
: cairo_(cairo)
|
: cairo_(cairo)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <mapnik/debug.hpp>
|
#include <mapnik/debug.hpp>
|
||||||
#include <mapnik/font_engine_freetype.hpp>
|
#include <mapnik/font_engine_freetype.hpp>
|
||||||
#include <mapnik/pixel_position.hpp>
|
#include <mapnik/pixel_position.hpp>
|
||||||
|
#include <mapnik/text/face.hpp>
|
||||||
|
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
|
@ -34,9 +35,20 @@
|
||||||
// stl
|
// stl
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
// freetype2
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_STROKER_H
|
||||||
|
}
|
||||||
|
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
{
|
{
|
||||||
freetype_engine::freetype_engine()
|
|
||||||
|
freetype_engine::freetype_engine() :
|
||||||
|
library_(NULL)
|
||||||
|
|
||||||
{
|
{
|
||||||
FT_Error error = FT_Init_FreeType( &library_ );
|
FT_Error error = FT_Init_FreeType( &library_ );
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -211,6 +223,7 @@ face_ptr freetype_engine::create_face(std::string const& family_name)
|
||||||
return face_ptr();
|
return face_ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stroker_ptr freetype_engine::create_stroker()
|
stroker_ptr freetype_engine::create_stroker()
|
||||||
{
|
{
|
||||||
FT_Stroker s;
|
FT_Stroker s;
|
||||||
|
@ -295,20 +308,6 @@ boost::mutex freetype_engine::mutex_;
|
||||||
#endif
|
#endif
|
||||||
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
|
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
|
||||||
|
|
||||||
void stroker::init(double radius)
|
|
||||||
{
|
|
||||||
FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)),
|
|
||||||
FT_STROKER_LINECAP_ROUND,
|
|
||||||
FT_STROKER_LINEJOIN_ROUND,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
stroker::~stroker()
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_DEBUG(font_engine_freetype) << "stroker: Destroy stroker=" << s_;
|
|
||||||
|
|
||||||
FT_Stroker_Done(s_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template class face_manager<freetype_engine>;
|
template class face_manager<freetype_engine>;
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,9 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/feature.hpp>
|
|
||||||
#include <mapnik/grid/grid_renderer.hpp>
|
#include <mapnik/grid/grid_renderer.hpp>
|
||||||
#include <mapnik/grid/grid_renderer_base.hpp>
|
|
||||||
#include <mapnik/text/symbolizer_helpers.hpp>
|
#include <mapnik/text/symbolizer_helpers.hpp>
|
||||||
#include <mapnik/text/renderer.hpp>
|
#include <mapnik/text/renderer.hpp>
|
||||||
#include <mapnik/pixel_position.hpp>
|
|
||||||
|
|
||||||
// agg
|
// agg
|
||||||
#include "agg_trans_affine.h"
|
#include "agg_trans_affine.h"
|
||||||
|
|
|
@ -21,10 +21,11 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
// mapnik
|
// mapnik
|
||||||
#include <mapnik/feature.hpp>
|
|
||||||
#include <mapnik/grid/grid_renderer.hpp>
|
#include <mapnik/grid/grid_renderer.hpp>
|
||||||
#include <mapnik/text/symbolizer_helpers.hpp>
|
#include <mapnik/text/symbolizer_helpers.hpp>
|
||||||
#include <mapnik/text/renderer.hpp>
|
#include <mapnik/text/renderer.hpp>
|
||||||
|
|
||||||
|
// boost
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
|
@ -42,8 +42,31 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
// xml2
|
||||||
|
#include <libxml/xmlreader.h>
|
||||||
|
|
||||||
|
|
||||||
namespace mapnik { namespace svg {
|
namespace mapnik { namespace svg {
|
||||||
|
|
||||||
|
bool parse_reader(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void process_node(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void start_element(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void end_element(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_path(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_dimensions(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_polygon(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_polyline(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_line(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_rect(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_circle(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_ellipse(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_linear_gradient(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_radial_gradient(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
bool parse_common_gradient(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_gradient_stop(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_pattern(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_attr(svg_parser & parser,xmlTextReaderPtr reader);
|
||||||
|
void parse_attr(svg_parser & parser,const xmlChar * name, const xmlChar * value );
|
||||||
|
|
||||||
typedef std::vector<std::pair<double, agg::rgba8> > color_lookup_type;
|
typedef std::vector<std::pair<double, agg::rgba8> > color_lookup_type;
|
||||||
|
|
||||||
|
@ -124,48 +147,13 @@ bool parse_style (const char* str, pairs_type & v)
|
||||||
return phrase_parse(str, str + std::strlen(str), kv_parser, skip_type(), v);
|
return phrase_parse(str, str + std::strlen(str), kv_parser, skip_type(), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
svg_parser::svg_parser(svg_converter<svg_path_adapter,
|
bool parse_reader(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
agg::pod_bvector<mapnik::svg::path_attributes> > & path)
|
|
||||||
: path_(path),
|
|
||||||
is_defs_(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
svg_parser::~svg_parser() {}
|
|
||||||
|
|
||||||
void svg_parser::parse(std::string const& filename)
|
|
||||||
{
|
|
||||||
xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str());
|
|
||||||
if (reader == NULL)
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'";
|
|
||||||
}
|
|
||||||
else if (!parse_reader(reader))
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void svg_parser::parse_from_string(std::string const& svg)
|
|
||||||
{
|
|
||||||
xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL,
|
|
||||||
(XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));
|
|
||||||
if (reader == NULL)
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'";
|
|
||||||
}
|
|
||||||
else if (!parse_reader(reader))
|
|
||||||
{
|
|
||||||
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool svg_parser::parse_reader(xmlTextReaderPtr reader)
|
|
||||||
{
|
{
|
||||||
int ret = xmlTextReaderRead(reader);
|
int ret = xmlTextReaderRead(reader);
|
||||||
try {
|
try {
|
||||||
while (ret == 1)
|
while (ret == 1)
|
||||||
{
|
{
|
||||||
process_node(reader);
|
process_node(parser,reader);
|
||||||
ret = xmlTextReaderRead(reader);
|
ret = xmlTextReaderRead(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,23 +171,8 @@ bool svg_parser::parse_reader(xmlTextReaderPtr reader)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::process_node(xmlTextReaderPtr reader)
|
|
||||||
{
|
|
||||||
int node_type = xmlTextReaderNodeType(reader);
|
|
||||||
switch (node_type)
|
|
||||||
{
|
|
||||||
case 1: //start element
|
|
||||||
start_element(reader);
|
|
||||||
break;
|
|
||||||
case 15:// end element
|
|
||||||
end_element(reader);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void svg_parser::start_element(xmlTextReaderPtr reader)
|
void start_element(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
const xmlChar *name;
|
const xmlChar *name;
|
||||||
name = xmlTextReaderConstName(reader);
|
name = xmlTextReaderConstName(reader);
|
||||||
|
@ -207,67 +180,67 @@ void svg_parser::start_element(xmlTextReaderPtr reader)
|
||||||
if (xmlStrEqual(name, BAD_CAST "defs"))
|
if (xmlStrEqual(name, BAD_CAST "defs"))
|
||||||
{
|
{
|
||||||
if (xmlTextReaderIsEmptyElement(reader) == 0)
|
if (xmlTextReaderIsEmptyElement(reader) == 0)
|
||||||
is_defs_ = true;
|
parser.is_defs_ = true;
|
||||||
}
|
}
|
||||||
// the gradient tags *should* be in defs, but illustrator seems not to put them in there so
|
// the gradient tags *should* be in defs, but illustrator seems not to put them in there so
|
||||||
// accept them anywhere
|
// accept them anywhere
|
||||||
else if (xmlStrEqual(name, BAD_CAST "linearGradient"))
|
else if (xmlStrEqual(name, BAD_CAST "linearGradient"))
|
||||||
{
|
{
|
||||||
parse_linear_gradient(reader);
|
parse_linear_gradient(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "radialGradient"))
|
else if (xmlStrEqual(name, BAD_CAST "radialGradient"))
|
||||||
{
|
{
|
||||||
parse_radial_gradient(reader);
|
parse_radial_gradient(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "stop"))
|
else if (xmlStrEqual(name, BAD_CAST "stop"))
|
||||||
{
|
{
|
||||||
parse_gradient_stop(reader);
|
parse_gradient_stop(parser,reader);
|
||||||
}
|
}
|
||||||
if ( !is_defs_ )
|
if ( !parser.is_defs_ )
|
||||||
{
|
{
|
||||||
|
|
||||||
if (xmlStrEqual(name, BAD_CAST "g"))
|
if (xmlStrEqual(name, BAD_CAST "g"))
|
||||||
{
|
{
|
||||||
path_.push_attr();
|
parser.path_.push_attr();
|
||||||
parse_attr(reader);
|
parse_attr(parser,reader);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path_.push_attr();
|
parser.path_.push_attr();
|
||||||
parse_attr(reader);
|
parse_attr(parser,reader);
|
||||||
if (path_.display())
|
if (parser.path_.display())
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(name, BAD_CAST "path"))
|
if (xmlStrEqual(name, BAD_CAST "path"))
|
||||||
{
|
{
|
||||||
parse_path(reader);
|
parse_path(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "polygon") )
|
else if (xmlStrEqual(name, BAD_CAST "polygon") )
|
||||||
{
|
{
|
||||||
parse_polygon(reader);
|
parse_polygon(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "polyline"))
|
else if (xmlStrEqual(name, BAD_CAST "polyline"))
|
||||||
{
|
{
|
||||||
parse_polyline(reader);
|
parse_polyline(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "line"))
|
else if (xmlStrEqual(name, BAD_CAST "line"))
|
||||||
{
|
{
|
||||||
parse_line(reader);
|
parse_line(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "rect"))
|
else if (xmlStrEqual(name, BAD_CAST "rect"))
|
||||||
{
|
{
|
||||||
parse_rect(reader);
|
parse_rect(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "circle"))
|
else if (xmlStrEqual(name, BAD_CAST "circle"))
|
||||||
{
|
{
|
||||||
parse_circle(reader);
|
parse_circle(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "ellipse"))
|
else if (xmlStrEqual(name, BAD_CAST "ellipse"))
|
||||||
{
|
{
|
||||||
parse_ellipse(reader);
|
parse_ellipse(parser,reader);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "svg"))
|
else if (xmlStrEqual(name, BAD_CAST "svg"))
|
||||||
{
|
{
|
||||||
parse_dimensions(reader);
|
parse_dimensions(parser,reader);
|
||||||
}
|
}
|
||||||
#ifdef MAPNIK_LOG
|
#ifdef MAPNIK_LOG
|
||||||
else if (!xmlStrEqual(name, BAD_CAST "svg"))
|
else if (!xmlStrEqual(name, BAD_CAST "svg"))
|
||||||
|
@ -276,45 +249,61 @@ void svg_parser::start_element(xmlTextReaderPtr reader)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
path_.pop_attr();
|
parser.path_.pop_attr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::end_element(xmlTextReaderPtr reader)
|
void end_element(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
const xmlChar *name;
|
const xmlChar *name;
|
||||||
name = xmlTextReaderConstName(reader);
|
name = xmlTextReaderConstName(reader);
|
||||||
|
|
||||||
|
|
||||||
if (!is_defs_ && xmlStrEqual(name, BAD_CAST "g"))
|
if (!parser.is_defs_ && xmlStrEqual(name, BAD_CAST "g"))
|
||||||
{
|
{
|
||||||
path_.pop_attr();
|
parser.path_.pop_attr();
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "defs"))
|
else if (xmlStrEqual(name, BAD_CAST "defs"))
|
||||||
{
|
{
|
||||||
is_defs_ = false;
|
parser.is_defs_ = false;
|
||||||
}
|
}
|
||||||
else if ((xmlStrEqual(name, BAD_CAST "linearGradient")) || (xmlStrEqual(name, BAD_CAST "radialGradient")))
|
else if ((xmlStrEqual(name, BAD_CAST "linearGradient")) || (xmlStrEqual(name, BAD_CAST "radialGradient")))
|
||||||
{
|
{
|
||||||
gradient_map_[temporary_gradient_.first] = temporary_gradient_.second;
|
parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
|
void process_node(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
|
{
|
||||||
|
int node_type = xmlTextReaderNodeType(reader);
|
||||||
|
switch (node_type)
|
||||||
|
{
|
||||||
|
case 1: //start element
|
||||||
|
start_element(parser,reader);
|
||||||
|
break;
|
||||||
|
case 15:// end element
|
||||||
|
end_element(parser,reader);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_attr(svg_parser & parser, const xmlChar * name, const xmlChar * value )
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(name, BAD_CAST "transform"))
|
if (xmlStrEqual(name, BAD_CAST "transform"))
|
||||||
{
|
{
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
mapnik::svg::parse_transform((const char*) value,tr);
|
mapnik::svg::parse_transform((const char*) value,tr);
|
||||||
path_.transform().premultiply(tr);
|
parser.path_.transform().premultiply(tr);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "fill"))
|
else if (xmlStrEqual(name, BAD_CAST "fill"))
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(value, BAD_CAST "none"))
|
if (xmlStrEqual(value, BAD_CAST "none"))
|
||||||
{
|
{
|
||||||
path_.fill_none();
|
parser.path_.fill_none();
|
||||||
}
|
}
|
||||||
else if (boost::starts_with((const char*)value, "url(#"))
|
else if (boost::starts_with((const char*)value, "url(#"))
|
||||||
{
|
{
|
||||||
|
@ -322,9 +311,9 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
|
||||||
std::string id = std::string((const char*)&value[5]);
|
std::string id = std::string((const char*)&value[5]);
|
||||||
// get rid of the trailing )
|
// get rid of the trailing )
|
||||||
id.erase(id.end()-1);
|
id.erase(id.end()-1);
|
||||||
if (gradient_map_.count(id) > 0)
|
if (parser.gradient_map_.count(id) > 0)
|
||||||
{
|
{
|
||||||
path_.add_fill_gradient(gradient_map_[id]);
|
parser.path_.add_fill_gradient(parser.gradient_map_[id]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -333,25 +322,25 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path_.fill(parse_color((const char*) value));
|
parser.path_.fill(parse_color((const char*) value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "fill-opacity"))
|
else if (xmlStrEqual(name, BAD_CAST "fill-opacity"))
|
||||||
{
|
{
|
||||||
path_.fill_opacity(parse_double((const char*) value));
|
parser.path_.fill_opacity(parse_double((const char*) value));
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "fill-rule"))
|
else if (xmlStrEqual(name, BAD_CAST "fill-rule"))
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(value, BAD_CAST "evenodd"))
|
if (xmlStrEqual(value, BAD_CAST "evenodd"))
|
||||||
{
|
{
|
||||||
path_.even_odd(true);
|
parser.path_.even_odd(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "stroke"))
|
else if (xmlStrEqual(name, BAD_CAST "stroke"))
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(value, BAD_CAST "none"))
|
if (xmlStrEqual(value, BAD_CAST "none"))
|
||||||
{
|
{
|
||||||
path_.stroke_none();
|
parser.path_.stroke_none();
|
||||||
}
|
}
|
||||||
else if (boost::starts_with((const char*)value, "url(#"))
|
else if (boost::starts_with((const char*)value, "url(#"))
|
||||||
{
|
{
|
||||||
|
@ -359,9 +348,9 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
|
||||||
std::string id = std::string((const char*)&value[5]);
|
std::string id = std::string((const char*)&value[5]);
|
||||||
// get rid of the trailing )
|
// get rid of the trailing )
|
||||||
id.erase(id.end()-1);
|
id.erase(id.end()-1);
|
||||||
if (gradient_map_.count(id) > 0)
|
if (parser.gradient_map_.count(id) > 0)
|
||||||
{
|
{
|
||||||
path_.add_stroke_gradient(gradient_map_[id]);
|
parser.path_.add_stroke_gradient(parser.gradient_map_[id]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -370,61 +359,61 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path_.stroke(parse_color((const char*) value));
|
parser.path_.stroke(parse_color((const char*) value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "stroke-width"))
|
else if (xmlStrEqual(name, BAD_CAST "stroke-width"))
|
||||||
{
|
{
|
||||||
path_.stroke_width(parse_double((const char*)value));
|
parser.path_.stroke_width(parse_double((const char*)value));
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "stroke-opacity"))
|
else if (xmlStrEqual(name, BAD_CAST "stroke-opacity"))
|
||||||
{
|
{
|
||||||
path_.stroke_opacity(parse_double((const char*)value));
|
parser.path_.stroke_opacity(parse_double((const char*)value));
|
||||||
}
|
}
|
||||||
else if(xmlStrEqual(name,BAD_CAST "stroke-width"))
|
else if(xmlStrEqual(name,BAD_CAST "stroke-width"))
|
||||||
{
|
{
|
||||||
path_.stroke_width(parse_double((const char*) value));
|
parser.path_.stroke_width(parse_double((const char*) value));
|
||||||
}
|
}
|
||||||
else if(xmlStrEqual(name,BAD_CAST "stroke-linecap"))
|
else if(xmlStrEqual(name,BAD_CAST "stroke-linecap"))
|
||||||
{
|
{
|
||||||
if(xmlStrEqual(value,BAD_CAST "butt"))
|
if(xmlStrEqual(value,BAD_CAST "butt"))
|
||||||
path_.line_cap(agg::butt_cap);
|
parser.path_.line_cap(agg::butt_cap);
|
||||||
else if(xmlStrEqual(value,BAD_CAST "round"))
|
else if(xmlStrEqual(value,BAD_CAST "round"))
|
||||||
path_.line_cap(agg::round_cap);
|
parser.path_.line_cap(agg::round_cap);
|
||||||
else if(xmlStrEqual(value,BAD_CAST "square"))
|
else if(xmlStrEqual(value,BAD_CAST "square"))
|
||||||
path_.line_cap(agg::square_cap);
|
parser.path_.line_cap(agg::square_cap);
|
||||||
}
|
}
|
||||||
else if(xmlStrEqual(name,BAD_CAST "stroke-linejoin"))
|
else if(xmlStrEqual(name,BAD_CAST "stroke-linejoin"))
|
||||||
{
|
{
|
||||||
if(xmlStrEqual(value,BAD_CAST "miter"))
|
if(xmlStrEqual(value,BAD_CAST "miter"))
|
||||||
path_.line_join(agg::miter_join);
|
parser.path_.line_join(agg::miter_join);
|
||||||
else if(xmlStrEqual(value,BAD_CAST "round"))
|
else if(xmlStrEqual(value,BAD_CAST "round"))
|
||||||
path_.line_join(agg::round_join);
|
parser.path_.line_join(agg::round_join);
|
||||||
else if(xmlStrEqual(value,BAD_CAST "bevel"))
|
else if(xmlStrEqual(value,BAD_CAST "bevel"))
|
||||||
path_.line_join(agg::bevel_join);
|
parser.path_.line_join(agg::bevel_join);
|
||||||
}
|
}
|
||||||
else if(xmlStrEqual(name,BAD_CAST "stroke-miterlimit"))
|
else if(xmlStrEqual(name,BAD_CAST "stroke-miterlimit"))
|
||||||
{
|
{
|
||||||
path_.miter_limit(parse_double((const char*)value));
|
parser.path_.miter_limit(parse_double((const char*)value));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(xmlStrEqual(name, BAD_CAST "opacity"))
|
else if(xmlStrEqual(name, BAD_CAST "opacity"))
|
||||||
{
|
{
|
||||||
double opacity = parse_double((const char*)value);
|
double opacity = parse_double((const char*)value);
|
||||||
path_.opacity(opacity);
|
parser.path_.opacity(opacity);
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "visibility"))
|
else if (xmlStrEqual(name, BAD_CAST "visibility"))
|
||||||
{
|
{
|
||||||
path_.visibility(!xmlStrEqual(value, BAD_CAST "hidden"));
|
parser.path_.visibility(!xmlStrEqual(value, BAD_CAST "hidden"));
|
||||||
}
|
}
|
||||||
else if (xmlStrEqual(name, BAD_CAST "display") && xmlStrEqual(value, BAD_CAST "none"))
|
else if (xmlStrEqual(name, BAD_CAST "display") && xmlStrEqual(value, BAD_CAST "none"))
|
||||||
{
|
{
|
||||||
path_.display(false);
|
parser.path_.display(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void svg_parser::parse_attr(xmlTextReaderPtr reader)
|
void parse_attr(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
const xmlChar *name, *value;
|
const xmlChar *name, *value;
|
||||||
|
|
||||||
|
@ -443,19 +432,19 @@ void svg_parser::parse_attr(xmlTextReaderPtr reader)
|
||||||
parse_style((const char*)value, vec);
|
parse_style((const char*)value, vec);
|
||||||
BOOST_FOREACH(value_type kv , vec )
|
BOOST_FOREACH(value_type kv , vec )
|
||||||
{
|
{
|
||||||
parse_attr(BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str());
|
parse_attr(parser,BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parse_attr(name,value);
|
parse_attr(parser,name,value);
|
||||||
}
|
}
|
||||||
} while(xmlTextReaderMoveToNextAttribute(reader) == 1);
|
} while(xmlTextReaderMoveToNextAttribute(reader) == 1);
|
||||||
}
|
}
|
||||||
xmlTextReaderMoveToElement(reader);
|
xmlTextReaderMoveToElement(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_dimensions(xmlTextReaderPtr reader)
|
void parse_dimensions(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
double width = 0;
|
double width = 0;
|
||||||
|
@ -473,10 +462,10 @@ void svg_parser::parse_dimensions(xmlTextReaderPtr reader)
|
||||||
height = parse_double((const char*)value2);
|
height = parse_double((const char*)value2);
|
||||||
xmlFree(value2);
|
xmlFree(value2);
|
||||||
}
|
}
|
||||||
path_.set_dimensions(width,height);
|
parser.path_.set_dimensions(width,height);
|
||||||
|
|
||||||
}
|
}
|
||||||
void svg_parser::parse_path(xmlTextReaderPtr reader)
|
void parse_path(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
|
||||||
|
@ -490,9 +479,9 @@ void svg_parser::parse_path(xmlTextReaderPtr reader)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
|
|
||||||
if (!mapnik::svg::parse_path((const char*) value, path_))
|
if (!mapnik::svg::parse_path((const char*) value, parser.path_))
|
||||||
{
|
{
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
xmlChar *id_value;
|
xmlChar *id_value;
|
||||||
|
@ -508,51 +497,51 @@ void svg_parser::parse_path(xmlTextReaderPtr reader)
|
||||||
throw std::runtime_error("unable to parse invalid svg <path>");
|
throw std::runtime_error("unable to parse invalid svg <path>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_polygon(xmlTextReaderPtr reader)
|
void parse_polygon(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
|
||||||
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
|
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
if (!mapnik::svg::parse_points((const char*) value, path_))
|
if (!mapnik::svg::parse_points((const char*) value, parser.path_))
|
||||||
{
|
{
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
throw std::runtime_error("Failed to parse <polygon>");
|
throw std::runtime_error("Failed to parse <polygon>");
|
||||||
}
|
}
|
||||||
path_.close_subpath();
|
parser.path_.close_subpath();
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_polyline(xmlTextReaderPtr reader)
|
void parse_polyline(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
|
||||||
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
|
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
if (!mapnik::svg::parse_points((const char*) value, path_))
|
if (!mapnik::svg::parse_points((const char*) value, parser.path_))
|
||||||
{
|
{
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
throw std::runtime_error("Failed to parse <polygon>");
|
throw std::runtime_error("Failed to parse <polygon>");
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_line(xmlTextReaderPtr reader)
|
void parse_line(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
double x1 = 0.0;
|
double x1 = 0.0;
|
||||||
|
@ -588,14 +577,14 @@ void svg_parser::parse_line(xmlTextReaderPtr reader)
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
path_.move_to(x1, y1);
|
parser.path_.move_to(x1, y1);
|
||||||
path_.line_to(x2, y2);
|
parser.path_.line_to(x2, y2);
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_circle(xmlTextReaderPtr reader)
|
void parse_circle(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
double cx = 0.0;
|
double cx = 0.0;
|
||||||
|
@ -622,19 +611,19 @@ void svg_parser::parse_circle(xmlTextReaderPtr reader)
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
|
|
||||||
if(r != 0.0)
|
if(r != 0.0)
|
||||||
{
|
{
|
||||||
if(r < 0.0) throw std::runtime_error("parse_circle: Invalid radius");
|
if(r < 0.0) throw std::runtime_error("parse_circle: Invalid radius");
|
||||||
agg::ellipse c(cx, cy, r, r);
|
agg::ellipse c(cx, cy, r, r);
|
||||||
path_.storage().concat_path(c);
|
parser.path_.storage().concat_path(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_ellipse(xmlTextReaderPtr reader)
|
void parse_ellipse(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
double cx = 0.0;
|
double cx = 0.0;
|
||||||
|
@ -670,21 +659,21 @@ void svg_parser::parse_ellipse(xmlTextReaderPtr reader)
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
|
|
||||||
if(rx != 0.0 && ry != 0.0)
|
if(rx != 0.0 && ry != 0.0)
|
||||||
{
|
{
|
||||||
if(rx < 0.0) throw std::runtime_error("parse_ellipse: Invalid rx");
|
if(rx < 0.0) throw std::runtime_error("parse_ellipse: Invalid rx");
|
||||||
if(ry < 0.0) throw std::runtime_error("parse_ellipse: Invalid ry");
|
if(ry < 0.0) throw std::runtime_error("parse_ellipse: Invalid ry");
|
||||||
agg::ellipse c(cx, cy, rx, ry);
|
agg::ellipse c(cx, cy, rx, ry);
|
||||||
path_.storage().concat_path(c);
|
parser.path_.storage().concat_path(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_rect(xmlTextReaderPtr reader)
|
void parse_rect(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
double x = 0.0;
|
double x = 0.0;
|
||||||
|
@ -752,24 +741,24 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
|
||||||
if(h < 0.0) throw std::runtime_error("parse_rect: Invalid height");
|
if(h < 0.0) throw std::runtime_error("parse_rect: Invalid height");
|
||||||
if(rx < 0.0) throw std::runtime_error("parse_rect: Invalid rx");
|
if(rx < 0.0) throw std::runtime_error("parse_rect: Invalid rx");
|
||||||
if(ry < 0.0) throw std::runtime_error("parse_rect: Invalid ry");
|
if(ry < 0.0) throw std::runtime_error("parse_rect: Invalid ry");
|
||||||
path_.begin_path();
|
parser.path_.begin_path();
|
||||||
|
|
||||||
if(rounded)
|
if(rounded)
|
||||||
{
|
{
|
||||||
agg::rounded_rect r;
|
agg::rounded_rect r;
|
||||||
r.rect(x,y,x+w,y+h);
|
r.rect(x,y,x+w,y+h);
|
||||||
r.radius(rx,ry);
|
r.radius(rx,ry);
|
||||||
path_.storage().concat_path(r);
|
parser.path_.storage().concat_path(r);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
path_.move_to(x, y);
|
parser.path_.move_to(x, y);
|
||||||
path_.line_to(x + w, y);
|
parser.path_.line_to(x + w, y);
|
||||||
path_.line_to(x + w, y + h);
|
parser.path_.line_to(x + w, y + h);
|
||||||
path_.line_to(x, y + h);
|
parser.path_.line_to(x, y + h);
|
||||||
path_.close_subpath();
|
parser.path_.close_subpath();
|
||||||
}
|
}
|
||||||
path_.end_path();
|
parser.path_.end_path();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,7 +769,7 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
|
||||||
offset="1"
|
offset="1"
|
||||||
id="stop3763" />
|
id="stop3763" />
|
||||||
*/
|
*/
|
||||||
void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
|
void parse_gradient_stop(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
|
||||||
|
@ -848,7 +837,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
|
||||||
|
|
||||||
stop_color.set_alpha(opacity*255);
|
stop_color.set_alpha(opacity*255);
|
||||||
|
|
||||||
temporary_gradient_.second.add_stop(offset, stop_color);
|
parser.temporary_gradient_.second.add_stop(offset, stop_color);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MAPNIK_LOG_DEBUG(svg_parser) << "\tFound Stop: " << offset << " "
|
MAPNIK_LOG_DEBUG(svg_parser) << "\tFound Stop: " << offset << " "
|
||||||
|
@ -859,7 +848,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
bool parse_common_gradient(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
|
||||||
|
@ -870,7 +859,7 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
||||||
// start a new gradient
|
// start a new gradient
|
||||||
gradient new_grad;
|
gradient new_grad;
|
||||||
id = std::string((const char *) value);
|
id = std::string((const char *) value);
|
||||||
temporary_gradient_ = std::make_pair(id, new_grad);
|
parser.temporary_gradient_ = std::make_pair(id, new_grad);
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -886,9 +875,9 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
||||||
if (value[0] == '#')
|
if (value[0] == '#')
|
||||||
{
|
{
|
||||||
std::string linkid = (const char *) &value[1];
|
std::string linkid = (const char *) &value[1];
|
||||||
if (gradient_map_.count(linkid))
|
if (parser.gradient_map_.count(linkid))
|
||||||
{
|
{
|
||||||
temporary_gradient_.second = gradient_map_[linkid];
|
parser.temporary_gradient_.second = parser.gradient_map_[linkid];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -903,11 +892,11 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
if (xmlStrEqual(value, BAD_CAST "userSpaceOnUse"))
|
if (xmlStrEqual(value, BAD_CAST "userSpaceOnUse"))
|
||||||
{
|
{
|
||||||
temporary_gradient_.second.set_units(USER_SPACE_ON_USE);
|
parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX);
|
parser.temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX);
|
||||||
}
|
}
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
|
@ -917,7 +906,7 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
agg::trans_affine tr;
|
agg::trans_affine tr;
|
||||||
mapnik::svg::parse_transform((const char*) value,tr);
|
mapnik::svg::parse_transform((const char*) value,tr);
|
||||||
temporary_gradient_.second.set_transform(tr);
|
parser.temporary_gradient_.second.set_transform(tr);
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -936,9 +925,9 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
|
||||||
r="5.1999998"
|
r="5.1999998"
|
||||||
gradientUnits="userSpaceOnUse" />
|
gradientUnits="userSpaceOnUse" />
|
||||||
*/
|
*/
|
||||||
void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader)
|
void parse_radial_gradient(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
if (!parse_common_gradient(reader))
|
if (!parse_common_gradient(parser,reader))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
@ -988,22 +977,22 @@ void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader)
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
// this logic for detecting %'s will not support mixed coordinates.
|
// this logic for detecting %'s will not support mixed coordinates.
|
||||||
if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
|
if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
|
||||||
{
|
{
|
||||||
temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
temporary_gradient_.second.set_gradient_type(RADIAL);
|
parser.temporary_gradient_.second.set_gradient_type(RADIAL);
|
||||||
temporary_gradient_.second.set_control_points(fx,fy,cx,cy,r);
|
parser.temporary_gradient_.second.set_control_points(fx,fy,cx,cy,r);
|
||||||
// add this here in case we have no end tag, will be replaced if we do
|
// add this here in case we have no end tag, will be replaced if we do
|
||||||
gradient_map_[temporary_gradient_.first] = temporary_gradient_.second;
|
parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second;
|
||||||
|
|
||||||
//MAPNIK_LOG_DEBUG(svg_parser) << "Found Radial Gradient: " << " " << cx << " " << cy << " " << fx << " " << fy << " " << r;
|
//MAPNIK_LOG_DEBUG(svg_parser) << "Found Radial Gradient: " << " " << cx << " " << cy << " " << fx << " " << fy << " " << r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader)
|
void parse_linear_gradient(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
if (!parse_common_gradient(reader))
|
if (!parse_common_gradient(parser,reader))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xmlChar *value;
|
xmlChar *value;
|
||||||
|
@ -1041,22 +1030,57 @@ void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader)
|
||||||
xmlFree(value);
|
xmlFree(value);
|
||||||
}
|
}
|
||||||
// this logic for detecting %'s will not support mixed coordinates.
|
// this logic for detecting %'s will not support mixed coordinates.
|
||||||
if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
|
if (has_percent && parser.temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
|
||||||
{
|
{
|
||||||
temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
parser.temporary_gradient_.second.set_units(USER_SPACE_ON_USE_BOUNDING_BOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
temporary_gradient_.second.set_gradient_type(LINEAR);
|
parser.temporary_gradient_.second.set_gradient_type(LINEAR);
|
||||||
temporary_gradient_.second.set_control_points(x1,y1,x2,y2);
|
parser.temporary_gradient_.second.set_control_points(x1,y1,x2,y2);
|
||||||
// add this here in case we have no end tag, will be replaced if we do
|
// add this here in case we have no end tag, will be replaced if we do
|
||||||
gradient_map_[temporary_gradient_.first] = temporary_gradient_.second;
|
parser.gradient_map_[parser.temporary_gradient_.first] = parser.temporary_gradient_.second;
|
||||||
|
|
||||||
//MAPNIK_LOG_DEBUG(svg_parser) << "Found Linear Gradient: " << "(" << x1 << " " << y1 << "),(" << x2 << " " << y2 << ")";
|
//MAPNIK_LOG_DEBUG(svg_parser) << "Found Linear Gradient: " << "(" << x1 << " " << y1 << "),(" << x2 << " " << y2 << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_parser::parse_pattern(xmlTextReaderPtr reader)
|
void parse_pattern(svg_parser & parser, xmlTextReaderPtr reader)
|
||||||
{
|
{
|
||||||
//const xmlChar *value;
|
//const xmlChar *value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
svg_parser::svg_parser(svg_converter<svg_path_adapter,
|
||||||
|
agg::pod_bvector<mapnik::svg::path_attributes> > & path)
|
||||||
|
: path_(path),
|
||||||
|
is_defs_(false) {}
|
||||||
|
|
||||||
|
svg_parser::~svg_parser() {}
|
||||||
|
|
||||||
|
void svg_parser::parse(std::string const& filename)
|
||||||
|
{
|
||||||
|
xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str());
|
||||||
|
if (reader == NULL)
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'";
|
||||||
|
}
|
||||||
|
else if (!parse_reader(*this,reader))
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void svg_parser::parse_from_string(std::string const& svg)
|
||||||
|
{
|
||||||
|
xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL,
|
||||||
|
(XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING));
|
||||||
|
if (reader == NULL)
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'";
|
||||||
|
}
|
||||||
|
else if (!parse_reader(*this,reader))
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -119,4 +119,21 @@ void font_face_set::set_character_sizes(double size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void stroker::init(double radius)
|
||||||
|
{
|
||||||
|
FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)),
|
||||||
|
FT_STROKER_LINECAP_ROUND,
|
||||||
|
FT_STROKER_LINEJOIN_ROUND,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
stroker::~stroker()
|
||||||
|
{
|
||||||
|
MAPNIK_LOG_DEBUG(font_engine_freetype) << "stroker: Destroy stroker=" << s_;
|
||||||
|
|
||||||
|
FT_Stroker_Done(s_);
|
||||||
|
}
|
||||||
|
|
||||||
}//ns mapnik
|
}//ns mapnik
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <mapnik/text/layout.hpp>
|
#include <mapnik/text/layout.hpp>
|
||||||
#include <mapnik/text/shaping.hpp>
|
#include <mapnik/text/shaping.hpp>
|
||||||
#include <mapnik/text/text_properties.hpp>
|
#include <mapnik/text/text_properties.hpp>
|
||||||
|
#include <mapnik/text/face.hpp>
|
||||||
|
|
||||||
//stl
|
//stl
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
|
@ -1,16 +1,64 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* This file is part of Mapnik (c++ mapping toolkit)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Artem Pavlenko
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
// mapnik
|
||||||
#include <mapnik/text/renderer.hpp>
|
#include <mapnik/text/renderer.hpp>
|
||||||
#include <mapnik/graphics.hpp>
|
#include <mapnik/graphics.hpp>
|
||||||
#include <mapnik/grid/grid.hpp>
|
#include <mapnik/grid/grid.hpp>
|
||||||
#include <mapnik/text/text_properties.hpp>
|
#include <mapnik/text/text_properties.hpp>
|
||||||
#include <mapnik/font_engine_freetype.hpp>
|
#include <mapnik/font_engine_freetype.hpp>
|
||||||
|
#include <mapnik/text/face.hpp>
|
||||||
|
|
||||||
|
// boost
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
|
||||||
|
// freetype2
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include FT_STROKER_H
|
||||||
|
}
|
||||||
|
|
||||||
namespace mapnik
|
namespace mapnik
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct glyph_t : boost::noncopyable
|
||||||
|
{
|
||||||
|
FT_Glyph image;
|
||||||
|
char_properties_ptr properties;
|
||||||
|
|
||||||
|
glyph_t(FT_Glyph image_, char_properties_ptr properties_)
|
||||||
|
: image(image_), properties(properties_) {}
|
||||||
|
|
||||||
|
~glyph_t () { FT_Done_Glyph(image);}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
text_renderer::text_renderer (halo_rasterizer_e rasterizer, composite_mode_e comp_op, double scale_factor, stroker_ptr stroker)
|
text_renderer::text_renderer (halo_rasterizer_e rasterizer, composite_mode_e comp_op, double scale_factor, stroker_ptr stroker)
|
||||||
: rasterizer_(rasterizer),
|
: rasterizer_(rasterizer),
|
||||||
comp_op_(comp_op),
|
comp_op_(comp_op),
|
||||||
scale_factor_(scale_factor),
|
scale_factor_(scale_factor),
|
||||||
|
glyphs_(boost::make_shared<glyph_vector>()),
|
||||||
stroker_(stroker)
|
stroker_(stroker)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -18,7 +66,7 @@ text_renderer::text_renderer (halo_rasterizer_e rasterizer, composite_mode_e com
|
||||||
void text_renderer::prepare_glyphs(glyph_positions_ptr pos)
|
void text_renderer::prepare_glyphs(glyph_positions_ptr pos)
|
||||||
{
|
{
|
||||||
//clear glyphs
|
//clear glyphs
|
||||||
glyphs_.clear();
|
glyphs_->clear();
|
||||||
|
|
||||||
FT_Matrix matrix;
|
FT_Matrix matrix;
|
||||||
FT_Vector pen;
|
FT_Vector pen;
|
||||||
|
@ -50,7 +98,7 @@ void text_renderer::prepare_glyphs(glyph_positions_ptr pos)
|
||||||
if (error) continue;
|
if (error) continue;
|
||||||
|
|
||||||
// take ownership of the glyph
|
// take ownership of the glyph
|
||||||
glyphs_.push_back(new glyph_t(image, glyph.format));
|
glyphs_->push_back(new glyph_t(image, glyph.format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +136,7 @@ agg_text_renderer<T>::agg_text_renderer (pixmap_type & pixmap,
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void agg_text_renderer<T>::render(glyph_positions_ptr pos)
|
void agg_text_renderer<T>::render(glyph_positions_ptr pos)
|
||||||
{
|
{
|
||||||
glyphs_.clear();
|
glyphs_->clear();
|
||||||
prepare_glyphs(pos);
|
prepare_glyphs(pos);
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
FT_Vector start;
|
FT_Vector start;
|
||||||
|
@ -99,10 +147,10 @@ void agg_text_renderer<T>::render(glyph_positions_ptr pos)
|
||||||
start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6));
|
start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6));
|
||||||
|
|
||||||
//render halo
|
//render halo
|
||||||
typename boost::ptr_vector<glyph_t>::iterator itr, end = glyphs_.end();
|
typename glyph_vector::iterator itr, end = glyphs_->end();
|
||||||
double halo_radius = 0;
|
double halo_radius = 0;
|
||||||
char_properties_ptr format;
|
char_properties_ptr format;
|
||||||
for (itr = glyphs_.begin(); itr != end; ++itr)
|
for (itr = glyphs_->begin(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
if (itr->properties)
|
if (itr->properties)
|
||||||
{
|
{
|
||||||
|
@ -155,7 +203,7 @@ void agg_text_renderer<T>::render(glyph_positions_ptr pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
//render actual text
|
//render actual text
|
||||||
for (itr = glyphs_.begin(); itr != end; ++itr)
|
for (itr = glyphs_->begin(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
if (itr->properties)
|
if (itr->properties)
|
||||||
{
|
{
|
||||||
|
@ -190,9 +238,9 @@ void grid_text_renderer<T>::render(glyph_positions_ptr pos, value_integer featur
|
||||||
start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6));
|
start.y = static_cast<FT_Pos>((height - base_point.y) * (1 << 6));
|
||||||
|
|
||||||
// now render transformed glyphs
|
// now render transformed glyphs
|
||||||
typename boost::ptr_vector<glyph_t>::iterator itr, end = glyphs_.end();
|
typename glyph_vector::iterator itr, end = glyphs_->end();
|
||||||
double halo_radius = 0.;
|
double halo_radius = 0.;
|
||||||
for (itr = glyphs_.begin(); itr != end; ++itr)
|
for (itr = glyphs_->begin(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
if (itr->properties)
|
if (itr->properties)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue