Browse Source

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 months ago
parent
commit
17f4ed6ea1

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

@@ -12,7 +12,7 @@
 
 
 namespace Gfx {
 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();
     hb_buffer_t* buffer = hb_buffer_create();
     ScopeGuard destroy_buffer = [&]() { hb_buffer_destroy(buffer); };
     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;
     u32 glyph_count;
     auto* glyph_info = hb_buffer_get_glyph_infos(buffer, &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 });
     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();
     auto* hb_font = font.harfbuzz_font();
     hb_shape(hb_font, buffer, nullptr, 0);
     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);
     glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
     auto* positions = hb_buffer_get_glyph_positions(buffer, &glyph_count);
     auto* positions = hb_buffer_get_glyph_positions(buffer, &glyph_count);
 
 
+    Vector<Gfx::DrawGlyph> glyph_run;
     FloatPoint point = baseline_start;
     FloatPoint point = baseline_start;
     for (size_t i = 0; i < glyph_count; ++i) {
     for (size_t i = 0; i < glyph_count; ++i) {
         auto position = point
         auto position = point
             - FloatPoint { 0, font.pixel_metrics().ascent }
             - FloatPoint { 0, font.pixel_metrics().ascent }
             + FloatPoint { positions[i].x_offset, positions[i].y_offset } / text_shaping_resolution;
             + 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;
         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 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,
         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_glyphs(move(glyphs))
         , m_font(move(font))
         , m_font(move(font))
         , m_text_type(text_type)
         , 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> const& glyphs() const { return m_glyphs; }
     [[nodiscard]] Vector<DrawGlyph>& glyphs() { return m_glyphs; }
     [[nodiscard]] Vector<DrawGlyph>& glyphs() { return m_glyphs; }
     [[nodiscard]] bool is_empty() const { return m_glyphs.is_empty(); }
     [[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); }
     void append(DrawGlyph glyph) { m_glyphs.append(glyph); }
 
 
@@ -59,9 +61,10 @@ private:
     Vector<DrawGlyph> m_glyphs;
     Vector<DrawGlyph> m_glyphs;
     NonnullRefPtr<Font> m_font;
     NonnullRefPtr<Font> m_font;
     TextType m_text_type;
     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);
 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 };
     Gfx::FloatPoint anchor { 0, 0 };
     auto physical_alignment = Gfx::TextAlignment::CenterLeft;
     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.
     // 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.
     // 9. Return result, physical alignment, and the inline box.
     return prepared_text;
     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.
         // NOTE: We never consider `content: ""` to be collapsible whitespace.
         bool is_generated_empty_string = text_node.is_generated() && chunk.length == 0;
         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 {
         Item item {
             .type = Item::Type::Text,
             .type = Item::Type::Text,
             .node = &text_node,
             .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,
             .offset_in_node = chunk.start,
             .length_in_node = chunk.length,
             .length_in_node = chunk.length,
             .width = chunk_width,
             .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())
     if (rect.is_empty())
         return;
         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;
     float baseline_x = 0;
     if (alignment == Gfx::TextAlignment::CenterLeft) {
     if (alignment == Gfx::TextAlignment::CenterLeft) {
         baseline_x = rect.x();
         baseline_x = rect.x();
     } else if (alignment == Gfx::TextAlignment::Center) {
     } 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) {
     } 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 {
     } else {
         // Unimplemented alignment.
         // Unimplemented alignment.
         TODO();
         TODO();