diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
index 882d4f9eec..84032ea058 100644
--- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
+++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -451,9 +452,10 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(De
auto& font = Platform::FontPlugin::the().default_font();
size_t width = 0;
size_t height = font.pixel_size();
- for (auto c : Utf8View { replaced_text }) {
- width += font.glyph_or_emoji_width(c);
- }
+
+ Utf8View replaced_text_view { replaced_text };
+ for (auto it = replaced_text_view.begin(); it != replaced_text_view.end(); ++it)
+ width += font.glyph_or_emoji_width(it);
// 6. If maxWidth was provided and the hypothetical width of the inline box in the hypothetical line box is greater than maxWidth CSS pixels, then change font to have a more condensed font (if one is available or if a reasonably readable one can be synthesized by applying a horizontal scale factor to the font) or a smaller font, and return to the previous step.
// FIXME: Record the font size used for this piece of text, and actually retry with a smaller size if needed.
@@ -478,11 +480,17 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(De
PreparedText prepared_text { {}, physical_alignment, { 0, 0, static_cast(width), static_cast(height) } };
prepared_text.glyphs.ensure_capacity(replaced_text.length());
- size_t offset = 0;
- for (auto c : Utf8View { replaced_text }) {
- prepared_text.glyphs.append({ c, { static_cast(offset), 0 } });
- offset += font.glyph_or_emoji_width(c);
- }
+ size_t previous_grapheme_boundary = 0;
+ Unicode::for_each_grapheme_segmentation_boundary(replaced_text_view, [&](auto boundary) {
+ if (boundary == 0)
+ return IterationDecision::Continue;
+
+ auto glyph_view = replaced_text_view.substring_view(previous_grapheme_boundary, boundary - previous_grapheme_boundary);
+ auto glyph = String::from_utf8(glyph_view.as_string()).release_value_but_fixme_should_propagate_errors();
+
+ prepared_text.glyphs.append({ move(glyph), { static_cast(boundary), 0 } });
+ return IterationDecision::Continue;
+ });
// 9. Return result, physical alignment, and the inline box.
return prepared_text;
diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h
index e73b42bd26..00fc7c003c 100644
--- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h
+++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h
@@ -7,6 +7,7 @@
#pragma once
+#include
#include
#include
#include
@@ -90,7 +91,7 @@ private:
virtual void visit_edges(Cell::Visitor&) override;
struct PreparedTextGlyph {
- unsigned int c;
+ String glyph;
Gfx::IntPoint position;
};