mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-29 05:38:24 +00:00
LibGfx: Support UTF-16 SVG text placement
This commit is contained in:
parent
2dc0a3b3ce
commit
d893d3234d
Notes:
github-actions[bot]
2025-08-05 13:15:00 +00:00
Author: https://github.com/trflynn89
Commit: d893d3234d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5720
Reviewed-by: https://github.com/gmta ✅
3 changed files with 62 additions and 20 deletions
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGfx/AffineTransform.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Point.h>
|
||||
|
@ -32,7 +31,8 @@ public:
|
|||
virtual void arc_to(FloatPoint point, float radius, bool large_arc, bool sweep) = 0;
|
||||
virtual void quadratic_bezier_curve_to(FloatPoint through, FloatPoint point) = 0;
|
||||
virtual void cubic_bezier_curve_to(FloatPoint c1, FloatPoint c2, FloatPoint p2) = 0;
|
||||
virtual void text(Utf8View, Font const&) = 0;
|
||||
virtual void text(Utf8View const&, Font const&) = 0;
|
||||
virtual void text(Utf16View const&, Font const&) = 0;
|
||||
virtual void glyph_run(GlyphRun const&) = 0;
|
||||
virtual void offset(Gfx::FloatPoint const&) = 0;
|
||||
|
||||
|
@ -47,7 +47,8 @@ public:
|
|||
|
||||
virtual NonnullOwnPtr<PathImpl> clone() const = 0;
|
||||
virtual NonnullOwnPtr<PathImpl> copy_transformed(Gfx::AffineTransform const&) const = 0;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf8View text, Font const&) const = 0;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf8View const& text, Font const&) const = 0;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf16View const& text, Font const&) const = 0;
|
||||
};
|
||||
|
||||
class Path {
|
||||
|
@ -91,7 +92,8 @@ public:
|
|||
void arc_to(FloatPoint point, float radius, bool large_arc, bool sweep) { impl().arc_to(point, radius, large_arc, sweep); }
|
||||
void quadratic_bezier_curve_to(FloatPoint through, FloatPoint point) { impl().quadratic_bezier_curve_to(through, point); }
|
||||
void cubic_bezier_curve_to(FloatPoint c1, FloatPoint c2, FloatPoint p2) { impl().cubic_bezier_curve_to(c1, c2, p2); }
|
||||
void text(Utf8View text, Font const& font) { impl().text(text, font); }
|
||||
void text(Utf8View const& text, Font const& font) { impl().text(text, font); }
|
||||
void text(Utf16View const& text, Font const& font) { impl().text(text, font); }
|
||||
void glyph_run(GlyphRun const& glyph_run) { impl().glyph_run(glyph_run); }
|
||||
void offset(Gfx::FloatPoint const& offset) { impl().offset(offset); }
|
||||
|
||||
|
@ -109,7 +111,8 @@ public:
|
|||
|
||||
Gfx::Path clone() const { return Gfx::Path { impl().clone() }; }
|
||||
Gfx::Path copy_transformed(Gfx::AffineTransform const& transform) const { return Gfx::Path { impl().copy_transformed(transform) }; }
|
||||
Gfx::Path place_text_along(Utf8View text, Font const& font) const { return Gfx::Path { impl().place_text_along(text, font) }; }
|
||||
Gfx::Path place_text_along(Utf8View const& text, Font const& font) const { return Gfx::Path { impl().place_text_along(text, font) }; }
|
||||
Gfx::Path place_text_along(Utf16View const& text, Font const& font) const { return Gfx::Path { impl().place_text_along(text, font) }; }
|
||||
|
||||
void transform(Gfx::AffineTransform const& transform) { m_impl = impl().copy_transformed(transform); }
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#define AK_DONT_REPLACE_STD
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibGfx/Font/Font.h>
|
||||
#include <LibGfx/PathSkia.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
|
@ -136,11 +138,21 @@ void PathImplSkia::cubic_bezier_curve_to(FloatPoint c1, FloatPoint c2, FloatPoin
|
|||
m_path->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), p2.x(), p2.y());
|
||||
}
|
||||
|
||||
void PathImplSkia::text(Utf8View string, Font const& font)
|
||||
void PathImplSkia::text(Utf8View const& string, Font const& font)
|
||||
{
|
||||
SkTextUtils::GetPath(string.as_string().characters_without_null_termination(), string.as_string().length(), SkTextEncoding::kUTF8, last_point().x(), last_point().y(), font.skia_font(1), m_path.ptr());
|
||||
}
|
||||
|
||||
void PathImplSkia::text(Utf16View const& string, Font const& font)
|
||||
{
|
||||
if (string.has_ascii_storage()) {
|
||||
text(Utf8View { string.bytes() }, font);
|
||||
return;
|
||||
}
|
||||
|
||||
SkTextUtils::GetPath(string.utf16_span().data(), string.length_in_code_units() * sizeof(char16_t), SkTextEncoding::kUTF16, last_point().x(), last_point().y(), font.skia_font(1), m_path.ptr());
|
||||
}
|
||||
|
||||
void PathImplSkia::glyph_run(GlyphRun const& glyph_run)
|
||||
{
|
||||
auto sk_font = glyph_run.font().skia_font(1);
|
||||
|
@ -160,37 +172,41 @@ void PathImplSkia::offset(Gfx::FloatPoint const& offset)
|
|||
m_path->offset(offset.x(), offset.y());
|
||||
}
|
||||
|
||||
NonnullOwnPtr<PathImpl> PathImplSkia::place_text_along(Utf8View text, Font const& font) const
|
||||
template<typename TextToGlyphs>
|
||||
static NonnullOwnPtr<PathImpl> place_text_along_impl(SkPath const& path, Font const& font, size_t length_in_code_points, TextToGlyphs&& text_to_glyphs)
|
||||
{
|
||||
auto sk_font = font.skia_font(1);
|
||||
size_t const text_length = text.length();
|
||||
SkScalar x = 0;
|
||||
SkScalar y = 0;
|
||||
|
||||
SkTextBlobBuilder builder;
|
||||
SkTextBlobBuilder::RunBuffer runBuffer = builder.allocRun(sk_font, text_length, x, y, nullptr);
|
||||
sk_font.textToGlyphs(text.as_string().characters_without_null_termination(), text.as_string().length(), SkTextEncoding::kUTF8, runBuffer.glyphs, text_length);
|
||||
SkPathMeasure pathMeasure(*m_path, false);
|
||||
auto const& run_buffer = builder.allocRun(sk_font, static_cast<int>(length_in_code_points), x, y, nullptr);
|
||||
text_to_glyphs(sk_font, run_buffer);
|
||||
|
||||
SkPathMeasure path_measure(path, false);
|
||||
SkScalar accumulated_distance = 0;
|
||||
|
||||
auto output_path = PathImplSkia::create();
|
||||
for (size_t i = 0; i < text_length; ++i) {
|
||||
SkGlyphID glyph = runBuffer.glyphs[i];
|
||||
SkPath glyphPath;
|
||||
sk_font.getPath(glyph, &glyphPath);
|
||||
|
||||
for (size_t i = 0; i < length_in_code_points; ++i) {
|
||||
SkGlyphID glyph = run_buffer.glyphs[i];
|
||||
SkPath glyph_path;
|
||||
sk_font.getPath(glyph, &glyph_path);
|
||||
|
||||
SkScalar advance;
|
||||
sk_font.getWidths(&glyph, 1, &advance);
|
||||
|
||||
SkPoint position;
|
||||
SkVector tangent;
|
||||
if (!pathMeasure.getPosTan(accumulated_distance, &position, &tangent))
|
||||
if (!path_measure.getPosTan(accumulated_distance, &position, &tangent))
|
||||
continue;
|
||||
|
||||
SkMatrix matrix;
|
||||
matrix.setTranslate(position.x(), position.y());
|
||||
matrix.preRotate(SkRadiansToDegrees(std::atan2(tangent.y(), tangent.x())));
|
||||
|
||||
glyphPath.transform(matrix);
|
||||
output_path->sk_path().addPath(glyphPath);
|
||||
glyph_path.transform(matrix);
|
||||
output_path->sk_path().addPath(glyph_path);
|
||||
|
||||
accumulated_distance += advance;
|
||||
}
|
||||
|
@ -198,6 +214,27 @@ NonnullOwnPtr<PathImpl> PathImplSkia::place_text_along(Utf8View text, Font const
|
|||
return output_path;
|
||||
}
|
||||
|
||||
NonnullOwnPtr<PathImpl> PathImplSkia::place_text_along(Utf8View const& text, Font const& font) const
|
||||
{
|
||||
auto length_in_code_points = text.length();
|
||||
|
||||
return place_text_along_impl(*m_path, font, length_in_code_points, [&](auto const& sk_font, auto const& run_buffer) {
|
||||
sk_font.textToGlyphs(text.as_string().characters_without_null_termination(), text.as_string().length(), SkTextEncoding::kUTF8, run_buffer.glyphs, length_in_code_points);
|
||||
});
|
||||
}
|
||||
|
||||
NonnullOwnPtr<PathImpl> PathImplSkia::place_text_along(Utf16View const& text, Font const& font) const
|
||||
{
|
||||
if (text.has_ascii_storage())
|
||||
return place_text_along(Utf8View { text.bytes() }, font);
|
||||
|
||||
auto length_in_code_points = text.length_in_code_points();
|
||||
|
||||
return place_text_along_impl(*m_path, font, length_in_code_points, [&](auto const& sk_font, auto const& run_buffer) {
|
||||
sk_font.textToGlyphs(text.utf16_span().data(), text.length_in_code_units() * sizeof(char16_t), SkTextEncoding::kUTF16, run_buffer.glyphs, length_in_code_points);
|
||||
});
|
||||
}
|
||||
|
||||
void PathImplSkia::append_path(Gfx::Path const& other)
|
||||
{
|
||||
m_path->addPath(static_cast<PathImplSkia const&>(other.impl()).sk_path());
|
||||
|
|
|
@ -27,7 +27,8 @@ public:
|
|||
virtual void arc_to(FloatPoint point, float radius, bool large_arc, bool sweep) override;
|
||||
virtual void quadratic_bezier_curve_to(FloatPoint through, FloatPoint point) override;
|
||||
virtual void cubic_bezier_curve_to(FloatPoint c1, FloatPoint c2, FloatPoint p2) override;
|
||||
virtual void text(Utf8View, Font const&) override;
|
||||
virtual void text(Utf8View const&, Font const&) override;
|
||||
virtual void text(Utf16View const&, Font const&) override;
|
||||
virtual void glyph_run(GlyphRun const&) override;
|
||||
virtual void offset(Gfx::FloatPoint const&) override;
|
||||
|
||||
|
@ -42,7 +43,8 @@ public:
|
|||
|
||||
virtual NonnullOwnPtr<PathImpl> clone() const override;
|
||||
virtual NonnullOwnPtr<PathImpl> copy_transformed(Gfx::AffineTransform const&) const override;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf8View text, Font const&) const override;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf8View const& text, Font const&) const override;
|
||||
virtual NonnullOwnPtr<PathImpl> place_text_along(Utf16View const& text, Font const&) const override;
|
||||
|
||||
SkPath const& sk_path() const { return *m_path; }
|
||||
SkPath& sk_path() { return *m_path; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue