From f19b17e089f1d95aa44154fbbc6890fb6e745428 Mon Sep 17 00:00:00 2001 From: MacDue Date: Sun, 11 Feb 2024 17:18:55 +0000 Subject: [PATCH] LibWeb: Use paths for text in CRC2D (if possible) This allows for: * Transformed text (e.g. rotated text) * Stroked text * Filling/stroking text with PaintStyles (e.g. gradients) * Squashed/condensed text (via maxWidth parameter) Fixes part of #22817 --- Tests/LibWeb/Ref/canvas-text.html | 46 ++++++++++++ .../LibWeb/Ref/reference/canvas-text-ref.html | 9 +++ .../Ref/reference/images/canvas-text-ref.png | Bin 0 -> 20198 bytes .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 71 ++++++++++++++++-- .../LibWeb/HTML/CanvasRenderingContext2D.h | 3 + 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 Tests/LibWeb/Ref/canvas-text.html create mode 100644 Tests/LibWeb/Ref/reference/canvas-text-ref.html create mode 100644 Tests/LibWeb/Ref/reference/images/canvas-text-ref.png diff --git a/Tests/LibWeb/Ref/canvas-text.html b/Tests/LibWeb/Ref/canvas-text.html new file mode 100644 index 0000000000..d29efeffac --- /dev/null +++ b/Tests/LibWeb/Ref/canvas-text.html @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/Tests/LibWeb/Ref/reference/canvas-text-ref.html b/Tests/LibWeb/Ref/reference/canvas-text-ref.html new file mode 100644 index 0000000000..968b109850 --- /dev/null +++ b/Tests/LibWeb/Ref/reference/canvas-text-ref.html @@ -0,0 +1,9 @@ + + diff --git a/Tests/LibWeb/Ref/reference/images/canvas-text-ref.png b/Tests/LibWeb/Ref/reference/images/canvas-text-ref.png new file mode 100644 index 0000000000000000000000000000000000000000..0684ebcba58c5d34e060c513e9474493c0019afc GIT binary patch literal 20198 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 literal 0 HcmV?d00001 diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 7d769c20d0..229497a219 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -198,7 +198,7 @@ Optional CanvasRenderingContext2D::antialiased_painter return {}; } -void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Optional max_width) +void CanvasRenderingContext2D::bitmap_font_fill_text(StringView text, float x, float y, Optional max_width) { if (max_width.has_value() && max_width.value() <= 0) return; @@ -207,9 +207,8 @@ void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Opti auto& drawing_state = this->drawing_state(); auto& base_painter = painter.underlying_painter(); - auto font = current_font(); - // Create text rect from font + auto font = current_font(); auto text_rect = Gfx::FloatRect(x, y, max_width.has_value() ? static_cast(max_width.value()) : font->width(text), font->pixel_size()); // Apply text align to text_rect @@ -242,10 +241,72 @@ void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Opti }); } +Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y, Optional max_width) +{ + if (max_width.has_value() && max_width.value() <= 0) + return {}; + + auto& drawing_state = this->drawing_state(); + auto font = current_font(); + + Gfx::Path path; + path.move_to({ x, y }); + path.text(Utf8View { text }, *font); + + auto text_width = path.bounding_box().width(); + Gfx::AffineTransform transform = {}; + + // https://html.spec.whatwg.org/multipage/canvas.html#text-preparation-algorithm: + // 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. + if (max_width.has_value() && text_width > float(*max_width)) { + auto horizontal_scale = float(*max_width) / text_width; + transform = Gfx::AffineTransform {}.scale({ horizontal_scale, 1 }); + text_width *= horizontal_scale; + } + + // Apply text align + // FIXME: CanvasTextAlign::Start and CanvasTextAlign::End currently do not nothing for right-to-left languages: + // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-textalign-start + // Default alignment of draw_text is left so do nothing by CanvasTextAlign::Start and CanvasTextAlign::Left + if (drawing_state.text_align == Bindings::CanvasTextAlign::Center) { + transform = Gfx::AffineTransform {}.set_translation({ -text_width / 2, 0 }).multiply(transform); + } + if (drawing_state.text_align == Bindings::CanvasTextAlign::End || drawing_state.text_align == Bindings::CanvasTextAlign::Right) { + transform = Gfx::AffineTransform {}.set_translation({ -text_width, 0 }).multiply(transform); + } + + // Apply text baseline + // FIXME: Implement CanvasTextBasline::Hanging, Bindings::CanvasTextAlign::Alphabetic and Bindings::CanvasTextAlign::Ideographic for real + // right now they are just handled as textBaseline = top or bottom. + // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-textbaseline-hanging + // Default baseline of draw_text is top so do nothing by CanvasTextBaseline::Top and CanvasTextBasline::Hanging + if (drawing_state.text_baseline == Bindings::CanvasTextBaseline::Middle) { + transform = Gfx::AffineTransform {}.set_translation({ 0, font->pixel_size() / 2 }).multiply(transform); + } + if (drawing_state.text_baseline == Bindings::CanvasTextBaseline::Top || drawing_state.text_baseline == Bindings::CanvasTextBaseline::Hanging) { + transform = Gfx::AffineTransform {}.set_translation({ 0, font->pixel_size() }).multiply(transform); + } + + transform = Gfx::AffineTransform { drawing_state.transform }.multiply(transform); + path = path.copy_transformed(transform); + return path; +} + +void CanvasRenderingContext2D::fill_text(StringView text, float x, float y, Optional max_width) +{ + if (is(*current_font())) + return bitmap_font_fill_text(text, x, y, max_width); + fill_internal(text_path(text, x, y, max_width), Gfx::Painter::WindingRule::Nonzero); +} + void CanvasRenderingContext2D::stroke_text(StringView text, float x, float y, Optional max_width) { - // FIXME: Stroke the text instead of filling it. - fill_text(text, x, y, max_width); + if (is(*current_font())) + return bitmap_font_fill_text(text, x, y, max_width); + stroke_internal(text_path(text, x, y, max_width)); } void CanvasRenderingContext2D::begin_path() diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h index cce9f5a3f4..7bfc536a7b 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h @@ -145,6 +145,9 @@ private: Gfx::Path rect_path(float x, float y, float width, float height); + Gfx::Path text_path(StringView text, float x, float y, Optional max_width); + void bitmap_font_fill_text(StringView text, float x, float y, Optional max_width); + void stroke_internal(Gfx::Path const&); void fill_internal(Gfx::Path const&, Gfx::Painter::WindingRule); void clip_internal(Gfx::Path&, Gfx::Painter::WindingRule);