mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 12:17:44 +00:00
LibGfx: Add Path::place_text_along(text, font)
This method returns a new path with the input text placed along the edge of the original path.
This commit is contained in:
parent
8713968165
commit
d327104910
2 changed files with 65 additions and 1 deletions
|
@ -184,6 +184,69 @@ void Path::text(Utf8View text, Font const& font)
|
||||||
IncludeLeftBearing::Yes);
|
IncludeLeftBearing::Yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path Path::place_text_along(Utf8View text, Font const& font) const
|
||||||
|
{
|
||||||
|
if (!is<ScaledFont>(font)) {
|
||||||
|
// FIXME: This API only accepts Gfx::Font for ease of use.
|
||||||
|
dbgln("Cannot path-ify bitmap fonts!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& lines = split_lines();
|
||||||
|
auto next_point_for_offset = [&, line_index = 0U, distance_along_path = 0.0f, last_line_length = 0.0f](float offset) mutable -> Optional<FloatPoint> {
|
||||||
|
while (line_index < lines.size() && offset > distance_along_path) {
|
||||||
|
last_line_length = lines[line_index++].length();
|
||||||
|
distance_along_path += last_line_length;
|
||||||
|
}
|
||||||
|
if (offset > distance_along_path)
|
||||||
|
return {};
|
||||||
|
if (last_line_length > 1) {
|
||||||
|
// If the last line segment was fairly long, compute the point in the line.
|
||||||
|
float p = (last_line_length + offset - distance_along_path) / last_line_length;
|
||||||
|
auto current_line = lines[line_index - 1];
|
||||||
|
return current_line.a() + (current_line.b() - current_line.a()).scaled(p);
|
||||||
|
}
|
||||||
|
if (line_index >= lines.size())
|
||||||
|
return {};
|
||||||
|
return lines[line_index].a();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto font_list = Gfx::FontCascadeList::create();
|
||||||
|
font_list->add(font);
|
||||||
|
auto& scaled_font = static_cast<Gfx::ScaledFont const&>(font);
|
||||||
|
|
||||||
|
Gfx::Path result_path;
|
||||||
|
Gfx::for_each_glyph_position(
|
||||||
|
{}, text, font_list, [&](Gfx::DrawGlyphOrEmoji glyph_or_emoji) {
|
||||||
|
auto* glyph = glyph_or_emoji.get_pointer<Gfx::DrawGlyph>();
|
||||||
|
if (!glyph)
|
||||||
|
return;
|
||||||
|
auto offset = glyph->position.x();
|
||||||
|
auto width = font.glyph_width(glyph->code_point);
|
||||||
|
auto start = next_point_for_offset(offset);
|
||||||
|
if (!start.has_value())
|
||||||
|
return;
|
||||||
|
auto end = next_point_for_offset(offset + width);
|
||||||
|
if (!end.has_value())
|
||||||
|
return;
|
||||||
|
// Find the angle between the start and end points on the path.
|
||||||
|
auto delta = *end - *start;
|
||||||
|
auto angle = AK::atan2(delta.y(), delta.x());
|
||||||
|
Gfx::Path glyph_path;
|
||||||
|
// Rotate the glyph then move it to start point.
|
||||||
|
auto glyph_id = scaled_font.glyph_id_for_code_point(glyph->code_point);
|
||||||
|
scaled_font.append_glyph_path_to(glyph_path, glyph_id);
|
||||||
|
auto transform = Gfx::AffineTransform {}
|
||||||
|
.translate(*start)
|
||||||
|
.multiply(Gfx::AffineTransform {}.rotate_radians(angle))
|
||||||
|
.multiply(Gfx::AffineTransform {}.translate({ 0, -scaled_font.pixel_metrics().ascent }));
|
||||||
|
glyph_path = glyph_path.copy_transformed(transform);
|
||||||
|
result_path.append_path(glyph_path);
|
||||||
|
},
|
||||||
|
Gfx::IncludeLeftBearing::Yes);
|
||||||
|
return result_path;
|
||||||
|
}
|
||||||
|
|
||||||
FloatPoint Path::last_point()
|
FloatPoint Path::last_point()
|
||||||
{
|
{
|
||||||
FloatPoint last_point { 0, 0 };
|
FloatPoint last_point { 0, 0 };
|
||||||
|
@ -400,7 +463,6 @@ void Path::ensure_subpath(FloatPoint point)
|
||||||
m_need_new_subpath = false;
|
m_need_new_subpath = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct RoundTrip {
|
struct RoundTrip {
|
||||||
RoundTrip(ReadonlySpan<T> span)
|
RoundTrip(ReadonlySpan<T> span)
|
||||||
|
|
|
@ -202,6 +202,8 @@ public:
|
||||||
|
|
||||||
Path stroke_to_fill(float thickness) const;
|
Path stroke_to_fill(float thickness) const;
|
||||||
|
|
||||||
|
Path place_text_along(Utf8View text, Font const&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void approximate_elliptical_arc_with_cubic_beziers(FloatPoint center, FloatSize radii, float x_axis_rotation, float theta, float theta_delta);
|
void approximate_elliptical_arc_with_cubic_beziers(FloatPoint center, FloatSize radii, float x_axis_rotation, float theta, float theta_delta);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue