add text attribute horizontal-alignment="adjust"

This commit is contained in:
Jiri Drbalek 2014-09-22 14:34:57 +00:00
parent d59529d22f
commit 31607cb3f4
8 changed files with 92 additions and 4 deletions

View file

@ -158,6 +158,7 @@ enum horizontal_alignment_enum
H_MIDDLE,
H_RIGHT,
H_AUTO,
H_ADJUST,
horizontal_alignment_enum_MAX
};

View file

@ -67,6 +67,8 @@ bool placement_finder::find_line_placements(T & path, bool points)
{
continue;
}
layouts_.adjust(pp.length(), scale_factor_);
}
double spacing = get_spacing(pp.length(), points ? 0. : layouts_.width());
@ -74,7 +76,7 @@ bool placement_finder::find_line_placements(T & path, bool points)
//horizontal_alignment_e halign = layouts_.back()->horizontal_alignment();
// halign == H_LEFT -> don't move
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO)
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO || horizontal_alignment_ == H_ADJUST)
{
if (!pp.forward(spacing / 2.0)) continue;
}

View file

@ -110,6 +110,10 @@ public:
void evaluate_properties(feature_impl const& feature, attributes const& attr);
text_line const& longest_line() const;
void set_character_spacing(double spacing, double scale_factor);
private:
void break_line(text_line & line, double wrap_width, unsigned text_ratio, bool wrap_before);
void break_line(text_line & line, char wrap_char,
@ -186,6 +190,8 @@ public:
inline double width() const { return bounds_.width(); }
inline double height() const { return bounds_.height(); }
void adjust(double width, double scale_factor);
private:
text_layout_vector layouts_;

View file

@ -52,6 +52,8 @@ public:
// Iterator beyond last glyph.
const_iterator end() const;
// Width of all glyphs without character spacing.
double glyphs_width() const { return glyphs_width_; }
// Width of all glyphs including character spacing.
double width() const { return width_; }
// Real line height. For first line: max_char_height(), for all others: line_height().
@ -75,14 +77,21 @@ public:
// Number of glyphs.
unsigned size() const;
unsigned space_count() const { return space_count_; }
void set_character_spacing(double character_spacing, double scale_factor);
private:
glyph_vector glyphs_;
double line_height_; // Includes line spacing (returned by freetype)
double max_char_height_; // Height of 'X' character of the largest font in this run. //TODO: Initialize this!
double width_;
double glyphs_width_;
unsigned first_char_;
unsigned last_char_;
bool first_line_;
unsigned space_count_;
};
} //namespace mapnik

View file

@ -137,6 +137,7 @@ static const char * horizontal_alignment_strings[] = {
"middle",
"right",
"auto",
"adjust",
""
};

View file

@ -36,6 +36,7 @@
// stl
#include <vector>
#include <functional>
namespace mapnik
{
@ -192,6 +193,7 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or
pixel_position const& layout_displacement = layout.displacement();
double sign = (real_orientation == UPRIGHT_LEFT) ? -1 : 1;
double offset = layout_displacement.y + 0.5 * sign * layout.height();
bool move_by_length = layout.horizontal_alignment() == H_ADJUST;
for (auto const& line : layout)
{
@ -209,12 +211,14 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or
double angle;
rotation rot;
double last_glyph_spacing = 0.;
std::function<bool(double)> glyph_move_method = std::bind(
move_by_length ? &vertex_cache::move : &vertex_cache::move_to_distance, &off_pp, std::placeholders::_1);
for (auto const& glyph : line)
{
if (current_cluster != static_cast<int>(glyph.char_index))
{
if (!off_pp.move_to_distance(sign * (layout.cluster_width(current_cluster) + last_glyph_spacing)))
if (!glyph_move_method(sign * (layout.cluster_width(current_cluster) + last_glyph_spacing)))
{
return false;
}

View file

@ -415,6 +415,31 @@ double text_layout::jalign_offset(double line_width) const
return 0;
}
text_line const& text_layout::longest_line() const
{
if (lines_.empty())
{
throw std::runtime_error("longest_line: Text layout has no lines.");
}
text_layout::const_iterator longest = lines_.begin();
for (text_layout::const_iterator line = longest + 1; line != lines_.end(); ++line)
{
if (line->glyphs_width() > longest->glyphs_width())
{
longest = line;
}
}
return *longest;
}
void text_layout::set_character_spacing(double spacing, double scale_factor)
{
for (auto & line : lines_)
{
line.set_character_spacing(spacing, scale_factor);
}
}
void layout_container::add(text_layout_ptr layout)
{
text_ += layout->text();
@ -461,5 +486,20 @@ void layout_container::clear()
line_count_ = 0;
}
void layout_container::adjust(double width, double scale_factor)
{
for (auto & layout_ptr : layouts_)
{
text_layout & layout = *layout_ptr;
if (layout.horizontal_alignment() == H_ADJUST)
{
text_line const& longest_line = layout.longest_line();
double character_spacing = ((width - longest_line.glyphs_width()) / longest_line.space_count()) / scale_factor;
if (character_spacing >= .0)
{
layout.set_character_spacing(character_spacing, scale_factor);
}
}
}
}
} //ns mapnik

View file

@ -31,9 +31,11 @@ text_line::text_line(unsigned first_char, unsigned last_char)
line_height_(0.0),
max_char_height_(0.0),
width_(0.0),
glyphs_width_(0.0),
first_char_(first_char),
last_char_(last_char),
first_line_(false)
first_line_(false),
space_count_(0)
{}
void text_line::add_glyph(glyph_info const& glyph, double scale_factor_)
@ -43,11 +45,15 @@ void text_line::add_glyph(glyph_info const& glyph, double scale_factor_)
if (glyphs_.empty())
{
width_ = advance;
glyphs_width_ = advance;
space_count_ = 0;
}
else if (advance)
{
// Only add character spacing if the character is not a zero-width part of a cluster.
width_ += advance + glyphs_.back().format->character_spacing * scale_factor_;
glyphs_width_ += advance;
space_count_++;
}
glyphs_.push_back(glyph);
}
@ -99,4 +105,23 @@ unsigned text_line::size() const
return glyphs_.size();
}
void text_line::set_character_spacing(double character_spacing, double scale_factor)
{
bool first = true;
for (auto const& glyph : glyphs_)
{
glyph.format->character_spacing = character_spacing;
double advance = glyph.advance();
if (first)
{
width_ = advance;
first = false;
}
else if (advance)
{
width_ += advance + character_spacing * scale_factor;
}
}
}
} // end namespace mapnik