diff --git a/Libraries/LibGfx/TextLayout.cpp b/Libraries/LibGfx/TextLayout.cpp index 04ccf4a4f9b..56d36cb7832 100644 --- a/Libraries/LibGfx/TextLayout.cpp +++ b/Libraries/LibGfx/TextLayout.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, sin-ack + * Copyright (c) 2024-2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,6 +13,45 @@ namespace Gfx { +Vector> shape_text(FloatPoint baseline_start, Utf8View string, FontCascadeList const& font_cascade_list) +{ + if (string.length() == 0) + return {}; + + Vector> runs; + + auto it = string.begin(); + auto substring_begin_offset = string.iterator_offset(it); + Font const* last_font = &font_cascade_list.font_for_code_point(*it); + FloatPoint last_position = baseline_start; + + auto add_run = [&runs, &last_position](Utf8View string, Font const& font) { + auto run = shape_text(last_position, 0, string, font, GlyphRun::TextType::Common, {}); + last_position.translate_by(run->width(), 0); + runs.append(*run); + }; + + while (it != string.end()) { + auto code_point = *it; + auto const* font = &font_cascade_list.font_for_code_point(code_point); + if (font != last_font) { + auto substring = string.substring_view(substring_begin_offset, string.iterator_offset(it) - substring_begin_offset); + add_run(substring, *last_font); + last_font = font; + substring_begin_offset = string.iterator_offset(it); + } + ++it; + } + + auto end_offset = string.iterator_offset(it); + if (substring_begin_offset < end_offset) { + auto substring = string.substring_view(substring_begin_offset, end_offset - substring_begin_offset); + add_run(substring, *last_font); + } + + return runs; +} + RefPtr shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType text_type, ShapeFeatures const& features) { static hb_buffer_t* buffer = hb_buffer_create(); diff --git a/Libraries/LibGfx/TextLayout.h b/Libraries/LibGfx/TextLayout.h index 0c7f1ed98b6..0cf8e7818f9 100644 --- a/Libraries/LibGfx/TextLayout.h +++ b/Libraries/LibGfx/TextLayout.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, sin-ack + * Copyright (c) 2024-2025, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,6 +13,7 @@ #include #include #include +#include #include #include @@ -69,6 +71,7 @@ private: }; RefPtr shape_text(FloatPoint baseline_start, float letter_spacing, Utf8View string, Gfx::Font const& font, GlyphRun::TextType, ShapeFeatures const& features); +Vector> shape_text(FloatPoint baseline_start, Utf8View string, FontCascadeList const&); float measure_text_width(Utf8View const& string, Gfx::Font const& font, ShapeFeatures const& features); } diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 9a0e4331454..71b0a05f18f 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -232,11 +232,13 @@ Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y, auto& drawing_state = this->drawing_state(); - auto const& font = font_cascade_list()->first(); - + auto const& font_cascade_list = this->font_cascade_list(); + auto const& font = font_cascade_list->first(); + auto glyph_runs = Gfx::shape_text({ x, y }, Utf8View(text), *font_cascade_list); Gfx::Path path; - auto glyph_run = Gfx::shape_text({ x, y }, 0, Utf8View(text), font, Gfx::GlyphRun::TextType::Ltr, {}); - path.glyph_run(*glyph_run); + for (auto const& glyph_run : glyph_runs) { + path.glyph_run(glyph_run); + } auto text_width = path.bounding_box().width(); Gfx::AffineTransform transform = {};