Fix label bounding box calculation to include glyph descenders [WIP] (ref #4308)

This commit is contained in:
Artem Pavlenko 2022-04-25 15:44:32 +01:00
parent 1ba1278b42
commit d26346f335
7 changed files with 29 additions and 17 deletions

View file

@ -360,7 +360,8 @@ struct harfbuzz_shaper
// Try next font in fontset
continue;
}
double max_glyph_height = 0;
double ymin = 0;
double ymax = 0;
for (auto const& c_id : clusters)
{
auto const& c = glyphinfos[c_id];
@ -382,19 +383,18 @@ struct harfbuzz_shaper
// Overwrite default advance with better value provided by HarfBuzz
g.unscaled_advance = gpos.x_advance;
g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
double tmp_height = g.height();
ymin = std::min(ymin, g.ymin());
ymax = std::max(ymax, g.ymax());
if (g.face->is_color())
{
tmp_height = g.ymax();
ymin = 0.0;
}
if (tmp_height > max_glyph_height)
max_glyph_height = tmp_height;
width_map[char_index] += g.advance();
line.add_glyph(std::move(g), scale_factor);
}
}
}
line.update_max_char_height(max_glyph_height);
line.update_max_char_height(ymin, ymax);
break; // When we reach this point the current font had all glyphs.
}
}

View file

@ -93,7 +93,8 @@ struct icu_shaper
std::size_t num_chars = static_cast<std::size_t>(num_char);
shaped.releaseBuffer(length);
bool shaped_status = true;
double max_glyph_height = 0;
double ymin = 0;
double ymax = 0;
if (U_SUCCESS(err) && (num_chars == length))
{
unsigned char_index = 0;
@ -113,9 +114,8 @@ struct icu_shaper
{
g.face = face;
g.scale_multiplier = size / face->get_face()->units_per_EM;
double tmp_height = g.height();
if (tmp_height > max_glyph_height)
max_glyph_height = tmp_height;
ymin = std::min(ymin, g.ymin());
ymax = std::max(ymax, g.ymax());
width_map[char_index++] += g.advance();
line.add_glyph(std::move(g), scale_factor);
}
@ -123,7 +123,7 @@ struct icu_shaper
}
if (!shaped_status)
continue;
line.update_max_char_height(max_glyph_height);
line.update_max_char_height(ymin, ymax);
return;
}
}

View file

@ -117,6 +117,7 @@ class text_layout
inline rotation const& orientation() const { return orientation_; }
inline pixel_position const& displacement() const { return displacement_; }
inline double base_ajustment() const { return baseline_adjustment_; }
inline box2d<double> const& bounds() const { return bounds_; }
inline horizontal_alignment_e horizontal_alignment() const { return halign_; }
pixel_position alignment_offset() const;
@ -173,6 +174,7 @@ class text_layout
bool repeat_wrap_char_ = false;
bool rotate_displacement_ = false;
double text_ratio_ = 0.0;
double baseline_adjustment_ = 0.0;
pixel_position displacement_ = {0, 0};
box2d<double> bounds_ = {0, 0, 0, 0};

View file

@ -65,7 +65,11 @@ class MAPNIK_DECL text_line : util::noncopyable
double max_char_height() const { return max_char_height_; }
// Called for each font/style to update the maximum height of this line.
void update_max_char_height(double max_char_height);
void update_max_char_height(double ymin, double ymax);
// Verticall adjustment
double baseline_adjustment() const { return baseline_adjustment_;}
// Line height including line spacing.
double line_height() const { return line_height_; }
@ -88,6 +92,7 @@ class MAPNIK_DECL text_line : util::noncopyable
glyph_vector glyphs_;
double line_height_; // Includes line spacing (returned by freetype)
double max_char_height_; // Max height of any glyphs in line - calculated by shaper
double baseline_adjustment_; // Adjustment to (0,0) origin
double width_;
double glyphs_width_;
unsigned first_char_;

View file

@ -172,7 +172,6 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
// Find text origin.
pixel_position layout_center = pos + layout.displacement();
if (!base_point_set)
{
glyphs->set_base_point(layout_center);
@ -180,9 +179,10 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
}
box2d<double> bbox = layout.bounds();
bbox.re_center(layout_center.x, layout_center.y);
/* For point placements it is faster to just check the bounding box. */
bbox.re_center(layout_center.x, layout_center.y - layout.base_ajustment());
// For point placements it is faster to just check the bounding box.
if (collision(bbox, layouts_.text(), false))
return false;

View file

@ -210,6 +210,7 @@ void text_layout::layout()
displacement_ = scale_factor_ * displacement_ + alignment_offset();
if (rotate_displacement_)
displacement_ = displacement_.rotate(!orientation_);
// Find layout bounds, expanded for rotation
rotated_box2d(bounds_, orientation_, displacement_, width_, height_);
}
@ -436,6 +437,7 @@ void text_layout::add_line(text_line&& line)
line.set_first_line(true);
}
height_ += line.height();
baseline_adjustment_ = line.baseline_adjustment();
glyphs_count_ += line.size();
width_ = std::max(width_, line.width());
lines_.emplace_back(std::move(line));

View file

@ -30,6 +30,7 @@ text_line::text_line(unsigned first_char, unsigned last_char)
: glyphs_()
, line_height_(0.0)
, max_char_height_(0.0)
, baseline_adjustment_(0.0)
, width_(0.0)
, glyphs_width_(0.0)
, first_char_(first_char)
@ -42,6 +43,7 @@ text_line::text_line(text_line&& rhs)
: glyphs_(std::move(rhs.glyphs_))
, line_height_(std::move(rhs.line_height_))
, max_char_height_(std::move(rhs.max_char_height_))
, baseline_adjustment_(std::move(baseline_adjustment_))
, width_(std::move(rhs.width_))
, glyphs_width_(std::move(rhs.glyphs_width_))
, first_char_(std::move(rhs.first_char_))
@ -92,9 +94,10 @@ double text_line::height() const
return line_height_;
}
void text_line::update_max_char_height(double max_char_height)
void text_line::update_max_char_height(double ymin, double ymax)
{
max_char_height_ = std::max(max_char_height_, max_char_height);
max_char_height_ = std::max(max_char_height_, ymax - ymin);
baseline_adjustment_ = ymin;
}
void text_line::set_first_line(bool first_line)