add font-feature-settings

This commit is contained in:
Jiri Drbalek 2014-09-11 18:58:26 +00:00
parent cdf6cf6e99
commit 2dcfa9e4b7
14 changed files with 229 additions and 7 deletions

View file

@ -41,6 +41,7 @@
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/symbolizer_enumerations.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/util/dasharray_parser.hpp>
#include <mapnik/util/variant.hpp>
@ -104,7 +105,8 @@ using value_base_type = util::variant<value_bool,
text_placements_ptr,
dash_array,
raster_colorizer_ptr,
group_symbolizer_properties_ptr>;
group_symbolizer_properties_ptr,
font_feature_settings_ptr>;
struct strict_value : value_base_type
{
@ -173,7 +175,8 @@ enum class property_types : std::uint8_t
target_horizontal_alignment,
target_justify_alignment,
target_vertical_alignment,
target_upright
target_upright,
target_font_feature_settings
};
inline bool operator==(symbolizer_base const& lhs, symbolizer_base const& rhs)
@ -415,6 +418,20 @@ struct evaluate_expression_wrapper<mapnik::dash_array>
}
};
// mapnik::font_feature_settings_ptr
template <>
struct evaluate_expression_wrapper<mapnik::font_feature_settings_ptr>
{
template <typename T1, typename T2, typename T3>
mapnik::font_feature_settings_ptr operator() (T1 const& expr, T2 const& feature, T3 const& vars) const
{
mapnik::value_type val = util::apply_visitor(mapnik::evaluate<T2, mapnik::value_type, T3>(feature, vars), expr);
// FIXME - throw instead?
if (val.is_null()) return std::make_shared<mapnik::font_feature_settings>();
return std::make_shared<mapnik::font_feature_settings>(val.to_string());
}
};
template <typename T>
struct extract_value : public util::static_visitor<T>
{

View file

@ -91,6 +91,7 @@ enum class keys : std::uint8_t
vertical_alignment,
upright,
avoid_edges,
font_feature_settings,
MAX_SYMBOLIZER_KEY
};

View file

@ -0,0 +1,68 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_FONT_FEATURE_SETTINGS_HPP
#define MAPNIK_FONT_FEATURE_SETTINGS_HPP
// stl
#include <vector>
#include <memory>
#include <limits>
// harfbuzz
#include <harfbuzz/hb.h>
namespace mapnik
{
class font_feature_settings
{
public:
using font_feature = hb_feature_t;
using feature_vector = std::vector<font_feature>;
using feature_iterator = feature_vector::iterator;
font_feature_settings(std::string const& features = "");
void from_string(std::string const& features);
std::string to_string() const;
void append(std::string const& feature);
void append(font_feature const& feature) { features_.push_back(feature); }
const font_feature* get_features() const { return features_.data(); }
feature_vector::size_type count() const { return features_.size(); }
private:
feature_vector features_;
};
using font_feature_settings_ptr = std::shared_ptr<font_feature_settings>;
constexpr unsigned int font_feature_range_global_start = 0u;
constexpr unsigned int font_feature_range_global_end = std::numeric_limits<unsigned int>::max();
constexpr hb_feature_t font_feature_liga_off = { HB_TAG('l', 'i', 'g', 'a'), 0, font_feature_range_global_start, font_feature_range_global_end };
} // mapnik namespace
#endif // MAPNIK_FONT_FEATURE_SETTINGS_HPP

View file

@ -55,6 +55,7 @@ public:
boost::optional<symbolizer_base::value_type> fill;
boost::optional<symbolizer_base::value_type> halo_fill;
boost::optional<symbolizer_base::value_type> halo_radius;
boost::optional<symbolizer_base::value_type> font_feature_settings;
private:
node_ptr child_;

View file

@ -27,6 +27,8 @@
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
// stl
#include <list>
#include <type_traits>
@ -60,7 +62,7 @@ static void shape_text(text_line & line,
text_itemizer & itemizer,
std::map<unsigned,double> & width_map,
face_manager_freetype & font_manager,
double scale_factor )
double scale_factor)
{
unsigned start = line.first_char();
unsigned end = line.last_char();
@ -74,6 +76,8 @@ static void shape_text(text_line & line,
hb_buffer_pre_allocate(buffer.get(), length);
mapnik::value_unicode_string const& text = itemizer.text();
font_feature_settings_ptr features = list.front().format->font_feature_settings;
for (auto const& text_item : list)
{
face_set_ptr face_set = font_manager.get_face_set(text_item.format->face_name, text_item.format->fontset);
@ -89,7 +93,7 @@ static void shape_text(text_line & line,
hb_buffer_set_direction(buffer.get(), (text_item.rtl == UBIDI_RTL)?HB_DIRECTION_RTL:HB_DIRECTION_LTR);
hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
hb_shape(font, buffer.get(), nullptr, 0);
hb_shape(font, buffer.get(), features->get_features(), features->count());
hb_font_destroy(font);
unsigned num_glyphs = hb_buffer_get_length(buffer.get());

View file

@ -55,7 +55,8 @@ struct evaluated_format_properties
text_transform(NONE),
fill(0,0,0),
halo_fill(0,0,0),
halo_radius(0.0) {}
halo_radius(0.0),
font_feature_settings(std::make_shared<mapnik::font_feature_settings>()) {}
std::string face_name;
boost::optional<font_set> fontset;
double text_size;
@ -67,6 +68,7 @@ struct evaluated_format_properties
color fill;
color halo_fill;
double halo_radius;
font_feature_settings_ptr font_feature_settings;
};
}
@ -94,6 +96,7 @@ struct MAPNIK_DECL format_properties
symbolizer_base::value_type halo_fill;
symbolizer_base::value_type halo_radius;
symbolizer_base::value_type text_transform;
symbolizer_base::value_type font_feature_settings;
};

View file

@ -33,6 +33,7 @@
#include <mapnik/expression.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/text/font_feature_settings.hpp>
// boost
#include <boost/optional.hpp>
@ -200,6 +201,16 @@ struct do_xml_attribute_cast<mapnik::expression_ptr>
}
};
// specialization for mapnik::font_feature_settings_ptr
template <>
struct do_xml_attribute_cast<mapnik::font_feature_settings_ptr>
{
static inline boost::optional<mapnik::font_feature_settings_ptr> xml_attribute_cast_impl(xml_tree const& tree, std::string const& source)
{
return std::make_shared<font_feature_settings>(source);
}
};
} // end namespace detail
template <typename T>

View file

@ -211,6 +211,7 @@ source = Split(
text/renderer.cpp
text/symbolizer_helpers.cpp
text/text_properties.cpp
text/font_feature_settings.cpp
text/formatting/base.cpp
text/formatting/list.cpp
text/formatting/text.cpp

View file

@ -118,6 +118,7 @@ static const property_meta_type key_meta[const_max_key] =
{return enumeration<text_upright_enum,text_upright_enum_MAX>(text_upright_enum(e.value)).as_string();},
property_types::target_upright},
property_meta_type{ "avoid-edges",false, nullptr, property_types::target_bool },
property_meta_type{ "font-feature-settings", nullptr, nullptr, property_types::target_font_feature_settings },
};

View file

@ -0,0 +1,95 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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/font_feature_settings.hpp>
#include <mapnik/config_error.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
// stl
#include <algorithm>
#include <cctype>
#include <sstream>
namespace mapnik
{
font_feature_settings::font_feature_settings(std::string const& features)
{
from_string(features);
}
void font_feature_settings::from_string(std::string const& features)
{
features_.clear();
if (std::all_of(features.begin(), features.end(), isspace)) return;
namespace qi = boost::spirit::qi;
qi::char_type char_;
qi::as_string_type as_string;
auto app = [&](std::string const& s) { append(s); };
if (!qi::parse(features.begin(), features.end(), as_string[+(char_ - ',')][app] % ','))
{
throw config_error("failed to parse font-features: '" + features + "'");
}
}
std::string font_feature_settings::to_string() const
{
std::ostringstream output;
constexpr size_t buffsize = 128;
char buff[buffsize];
bool first = true;
for (auto feature : features_)
{
if (!first)
{
output << ", ";
first = false;
}
hb_feature_to_string(&feature, buff, buffsize);
output << buff;
}
return output.str();
}
void font_feature_settings::append(std::string const& feature)
{
features_.emplace_back();
feature_iterator current_feature = features_.end() - 1;
if (!hb_feature_from_string(feature.c_str(), feature.length(), &*current_feature))
{
features_.erase(current_feature);
throw config_error("failed to parse font-features: '" + feature + "'");
}
}
}

View file

@ -50,6 +50,7 @@ void format_node::to_xml(ptree & xml) const
if (halo_fill) serialize_property("halo-fill", *halo_fill, new_node);
if (halo_radius) serialize_property("halo-radius", *halo_radius, new_node);
if (text_transform) serialize_property("text-transform", *text_transform, new_node);
if (font_feature_settings) serialize_property("font-feature-settings", *font_feature_settings, new_node);
if (face_name) set_attr(new_node, "face-name", *face_name);
if (fontset) set_attr(new_node, "fontset-name", fontset->get_name());
@ -73,6 +74,7 @@ node_ptr format_node::from_xml(xml_node const& xml, fontset_map const& fontsets)
set_property_from_xml<color>(n->fill, "fill", xml);
set_property_from_xml<color>(n->halo_fill, "halo-fill", xml);
set_property_from_xml<text_transform_e>(n->text_transform, "text-transform", xml);
set_property_from_xml<font_feature_settings_ptr>(n->font_feature_settings, "font-feature-settings", xml);
boost::optional<std::string> face_name = xml.get_opt_attr<std::string>("face-name");
if (face_name)
@ -112,6 +114,7 @@ void format_node::apply(evaluated_format_properties_ptr p, feature_impl const& f
if (fill) new_properties->fill = util::apply_visitor(extract_value<color>(feature,attrs), *fill);
if (halo_fill) new_properties->halo_fill = util::apply_visitor(extract_value<color>(feature,attrs), *halo_fill);
if (text_transform) new_properties->text_transform = util::apply_visitor(extract_value<text_transform_enum>(feature,attrs), *text_transform);
if (font_feature_settings) new_properties->font_feature_settings = util::apply_visitor(extract_value<font_feature_settings_ptr>(feature,attrs), *font_feature_settings);
if (fontset)
{
@ -155,6 +158,7 @@ void format_node::add_expressions(expression_set & output) const
if (fill && is_expression(*fill)) output.insert(util::get<expression_ptr>(*fill));
if (halo_fill && is_expression(*halo_fill)) output.insert(util::get<expression_ptr>(*halo_fill));
if (text_transform && is_expression(*text_transform)) output.insert(util::get<expression_ptr>(*text_transform));
if (font_feature_settings && is_expression(*font_feature_settings)) output.insert(util::get<expression_ptr>(*font_feature_settings));
if (child_) child_->add_expressions(output);
}

View file

@ -22,6 +22,7 @@
#include <mapnik/text/properties_util.hpp>
#include <mapnik/expression_string.hpp>
#include <mapnik/text/font_feature_settings.hpp>
namespace mapnik { namespace detail {
@ -67,6 +68,12 @@ struct property_serializer : public util::static_visitor<>
node_.put("<xmlattr>." + name_, str);
}
void operator() (font_feature_settings_ptr const& val) const
{
std::string str = val->to_string();
node_.put("<xmlattr>." + name_, str);
}
template <typename T>
void operator() (T const& val) const
{

View file

@ -97,6 +97,8 @@ void text_symbolizer_properties::process(text_layout & output, feature_impl cons
format->face_name = format_defaults.face_name;
format->fontset = format_defaults.fontset;
format->font_feature_settings = util::apply_visitor(extract_value<font_feature_settings_ptr>(feature,attrs), format_defaults.font_feature_settings);
tree_->apply(format, feature, attrs, output);
}
else MAPNIK_LOG_WARN(text_properties) << "text_symbolizer_properties can't produce text: No formatting tree!";
@ -315,7 +317,8 @@ format_properties::format_properties()
fill(color(0,0,0)),
halo_fill(color(255,255,255)),
halo_radius(0.0),
text_transform(enumeration_wrapper(NONE)) {}
text_transform(enumeration_wrapper(NONE)),
font_feature_settings(std::make_shared<mapnik::font_feature_settings>()) {}
void format_properties::from_xml(xml_node const& node, fontset_map const& fontsets)
{
@ -328,6 +331,7 @@ void format_properties::from_xml(xml_node const& node, fontset_map const& fontse
set_property_from_xml<color>(fill, "fill", node);
set_property_from_xml<color>(halo_fill, "halo-fill", node);
set_property_from_xml<text_transform_e>(text_transform,"text-transform", node);
set_property_from_xml<font_feature_settings_ptr>(font_feature_settings, "font-feature-settings", node);
optional<std::string> face_name_ = node.get_opt_attr<std::string>("face-name");
if (face_name_) face_name = *face_name_;
@ -377,6 +381,7 @@ void format_properties::to_xml(boost::property_tree::ptree & node, bool explicit
if (!(fill == dfl.fill) || explicit_defaults) serialize_property("fill", fill, node);
if (!(halo_fill == dfl.halo_fill) || explicit_defaults) serialize_property("halo-fill", halo_fill, node);
if (!(text_transform == dfl.text_transform) || explicit_defaults) serialize_property("text-transform", text_transform, node);
if (!(font_feature_settings == dfl.font_feature_settings) || explicit_defaults) serialize_property("font-feature-settings", font_feature_settings, node);
}
void format_properties::add_expressions(expression_set & output) const
@ -390,6 +395,7 @@ void format_properties::add_expressions(expression_set & output) const
if (is_expression(fill)) output.insert(util::get<expression_ptr>(fill));
if (is_expression(halo_fill)) output.insert(util::get<expression_ptr>(halo_fill));
if (is_expression(text_transform)) output.insert(util::get<expression_ptr>(text_transform));
if (is_expression(font_feature_settings)) output.insert(util::get<expression_ptr>(font_feature_settings));
}

View file

@ -33,6 +33,7 @@
#include <mapnik/config_error.hpp>
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/text/font_feature_settings.hpp>
// stl
#include <type_traits>
@ -74,7 +75,8 @@ DEFINE_NAME_TRAIT( mapnik::value_integer, "int" )
#endif
DEFINE_NAME_TRAIT( std::string, "string" )
DEFINE_NAME_TRAIT( color, "color" )
DEFINE_NAME_TRAIT(expression_ptr, "expression_ptr" )
DEFINE_NAME_TRAIT( expression_ptr, "expression_ptr" )
DEFINE_NAME_TRAIT( font_feature_settings_ptr, "font-feature-settings" )
template <typename ENUM, int MAX>
struct name_trait< mapnik::enumeration<ENUM, MAX> >
@ -421,6 +423,7 @@ compile_get_opt_attr(justify_alignment_e);
compile_get_opt_attr(text_upright_e);
compile_get_opt_attr(halo_rasterizer_e);
compile_get_opt_attr(expression_ptr);
compile_get_opt_attr(font_feature_settings_ptr);
compile_get_attr(std::string);
compile_get_attr(filter_mode_e);
compile_get_attr(point_placement_e);