瀏覽代碼

LibGfx+LibWeb: Simplify text shaping API by removing per glyph callback

All places where text shaping happens, the callback is used to simply
append a glyph into the end of glyphs vector. This change removes the
callback parameter and makes the text shaping function return a glyph
run.
Aliaksandr Kalenik 9 月之前
父節點
當前提交
17f4ed6ea1

+ 6 - 12
Userland/Libraries/LibGfx/TextLayout.cpp

@@ -12,7 +12,7 @@
 
 namespace Gfx {
 
-void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, Function<void(DrawGlyph const&)> callback, Optional<float&> width)
+RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, GlyphRun::TextType text_type)
 {
     hb_buffer_t* buffer = hb_buffer_create();
     ScopeGuard destroy_buffer = [&]() { hb_buffer_destroy(buffer); };
@@ -22,8 +22,6 @@ void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Fo
     u32 glyph_count;
     auto* glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
     Vector<hb_glyph_info_t> const input_glyph_info({ glyph_info, glyph_count });
-    if (input_glyph_info.is_empty())
-        return;
 
     auto* hb_font = font.harfbuzz_font();
     hb_shape(hb_font, buffer, nullptr, 0);
@@ -31,27 +29,23 @@ void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Fo
     glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
     auto* positions = hb_buffer_get_glyph_positions(buffer, &glyph_count);
 
+    Vector<Gfx::DrawGlyph> glyph_run;
     FloatPoint point = baseline_start;
     for (size_t i = 0; i < glyph_count; ++i) {
         auto position = point
             - FloatPoint { 0, font.pixel_metrics().ascent }
             + FloatPoint { positions[i].x_offset, positions[i].y_offset } / text_shaping_resolution;
-        callback(DrawGlyph {
-            .position = position,
-            .glyph_id = glyph_info[i].codepoint,
-        });
+        glyph_run.append({ position, glyph_info[i].codepoint });
         point += FloatPoint { positions[i].x_advance, positions[i].y_advance } / text_shaping_resolution;
     }
 
-    if (width.has_value())
-        *width = point.x();
+    return adopt_ref(*new Gfx::GlyphRun(move(glyph_run), font, text_type, point.x()));
 }
 
 float measure_text_width(Utf8View const& string, Gfx::Font const& font)
 {
-    float width = 0;
-    for_each_glyph_position({}, string, font, [&](DrawGlyph const&) {}, width);
-    return width;
+    auto glyph_run = shape_text({}, string, font, GlyphRun::TextType::Common);
+    return glyph_run->width();
 }
 
 }

+ 5 - 2
Userland/Libraries/LibGfx/TextLayout.h

@@ -40,10 +40,11 @@ public:
         Rtl,
     };
 
-    GlyphRun(Vector<DrawGlyph>&& glyphs, NonnullRefPtr<Font> font, TextType text_type)
+    GlyphRun(Vector<DrawGlyph>&& glyphs, NonnullRefPtr<Font> font, TextType text_type, float width)
         : m_glyphs(move(glyphs))
         , m_font(move(font))
         , m_text_type(text_type)
+        , m_width(width)
     {
     }
 
@@ -52,6 +53,7 @@ public:
     [[nodiscard]] Vector<DrawGlyph> const& glyphs() const { return m_glyphs; }
     [[nodiscard]] Vector<DrawGlyph>& glyphs() { return m_glyphs; }
     [[nodiscard]] bool is_empty() const { return m_glyphs.is_empty(); }
+    [[nodiscard]] float width() const { return m_width; }
 
     void append(DrawGlyph glyph) { m_glyphs.append(glyph); }
 
@@ -59,9 +61,10 @@ private:
     Vector<DrawGlyph> m_glyphs;
     NonnullRefPtr<Font> m_font;
     TextType m_text_type;
+    float m_width { 0 };
 };
 
-void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, Function<void(DrawGlyph const&)> callback, Optional<float&> width = {});
+RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, GlyphRun::TextType);
 float measure_text_width(Utf8View const& string, Gfx::Font const& font);
 
 }

+ 2 - 8
Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp

@@ -513,16 +513,10 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
     Gfx::FloatPoint anchor { 0, 0 };
     auto physical_alignment = Gfx::TextAlignment::CenterLeft;
 
-    auto glyph_run = adopt_ref(*new Gfx::GlyphRun({}, *font, Gfx::GlyphRun::TextType::Ltr));
-    float glyph_run_width = 0;
-    Gfx::for_each_glyph_position(
-        anchor, replaced_text.code_points(), *font, [&](Gfx::DrawGlyph const& glyph) {
-            glyph_run->append(glyph);
-        },
-        glyph_run_width);
+    auto glyph_run = Gfx::shape_text(anchor, replaced_text.code_points(), *font, Gfx::GlyphRun::TextType::Ltr);
 
     // 8. Let result be an array constructed by iterating over each glyph in the inline box from left to right (if any), adding to the array, for each glyph, the shape of the glyph as it is in the inline box, positioned on a coordinate space using CSS pixels with its origin is at the anchor point.
-    PreparedText prepared_text { glyph_run, physical_alignment, { 0, 0, static_cast<int>(glyph_run_width), static_cast<int>(height) } };
+    PreparedText prepared_text { glyph_run, physical_alignment, { 0, 0, static_cast<int>(glyph_run->width()), static_cast<int>(height) } };
 
     // 9. Return result, physical alignment, and the inline box.
     return prepared_text;

+ 3 - 10
Userland/Libraries/LibWeb/Layout/InlineLevelIterator.cpp

@@ -239,15 +239,8 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
             };
         }
 
-        Vector<Gfx::DrawGlyph> glyph_run;
-        float glyph_run_width = 0;
-        Gfx::for_each_glyph_position(
-            { 0, 0 }, chunk.view, chunk.font, [&](Gfx::DrawGlyph const& glyph) {
-                glyph_run.append(glyph);
-            },
-            glyph_run_width);
-
-        CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run_width);
+        auto glyph_run = Gfx::shape_text({ 0, 0 }, chunk.view, chunk.font, text_type);
+        CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run->width());
 
         // NOTE: We never consider `content: ""` to be collapsible whitespace.
         bool is_generated_empty_string = text_node.is_generated() && chunk.length == 0;
@@ -255,7 +248,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
         Item item {
             .type = Item::Type::Text,
             .node = &text_node,
-            .glyph_run = adopt_ref(*new Gfx::GlyphRun(move(glyph_run), chunk.font, text_type)),
+            .glyph_run = move(glyph_run),
             .offset_in_node = chunk.start,
             .length_in_node = chunk.length,
             .width = chunk_width,

+ 3 - 10
Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp

@@ -233,21 +233,14 @@ void DisplayListRecorder::draw_text(Gfx::IntRect const& rect, String raw_text, G
     if (rect.is_empty())
         return;
 
-    auto glyph_run = adopt_ref(*new Gfx::GlyphRun({}, font, Gfx::GlyphRun::TextType::Ltr));
-    float glyph_run_width = 0;
-    Gfx::for_each_glyph_position(
-        { 0, 0 }, raw_text.code_points(), font, [&](Gfx::DrawGlyph const& glyph) {
-            glyph_run->append(glyph);
-        },
-        glyph_run_width);
-
+    auto glyph_run = Gfx::shape_text({}, raw_text.code_points(), font, Gfx::GlyphRun::TextType::Ltr);
     float baseline_x = 0;
     if (alignment == Gfx::TextAlignment::CenterLeft) {
         baseline_x = rect.x();
     } else if (alignment == Gfx::TextAlignment::Center) {
-        baseline_x = static_cast<float>(rect.x()) + (static_cast<float>(rect.width()) - glyph_run_width) / 2.0f;
+        baseline_x = static_cast<float>(rect.x()) + (static_cast<float>(rect.width()) - glyph_run->width()) / 2.0f;
     } else if (alignment == Gfx::TextAlignment::CenterRight) {
-        baseline_x = static_cast<float>(rect.right()) - glyph_run_width;
+        baseline_x = static_cast<float>(rect.right()) - glyph_run->width();
     } else {
         // Unimplemented alignment.
         TODO();