From 63f8feb9a49ce809912a6490e586561f2d872d03 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 21 Jun 2024 07:50:48 +0200 Subject: [PATCH] LibWeb: Implement RecordingPainter::draw_text() via draw_text_run() To get away from the ancient (and buggy) text layout code in Gfx::Painter, we want to remove all the uses of Painter::draw_text(). As a first step towards this, we implement the draw_text() display list command in terms of the draw_text_run() command by performing the very simple necessary layout in draw_text() beforehand. --- .../LibWeb/Ref/reference/images/alt-frame.png | Bin 1629 -> 1629 bytes .../LibWeb/Painting/ImagePaintable.cpp | 2 +- .../LibWeb/Painting/RecordingPainter.cpp | 37 +++++++++++++----- .../LibWeb/Painting/RecordingPainter.h | 2 +- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Tests/LibWeb/Ref/reference/images/alt-frame.png b/Tests/LibWeb/Ref/reference/images/alt-frame.png index 8a3737269bbf63cc85f7faa6670a449d90be4eed..bae73ef195d623f633dc51457fb1794be21e2318 100644 GIT binary patch delta 629 zcmcc1bC+j=ZoTZ3tZIg155*4~$jHd>upd5Xz;pN@n9bjoDAD%tSnthhg&pkgEDQAK zzO1}<>&mbEitE3=axOiPf0RW*K!AgTg@uWUvGKrm4we6tHGke~tWafYY;bT;fJxrB zo$#m^F5hQZCX3N`O*Bz!^-u_Pg z^26!P%VnyBIQYd+=)BL}eR|2;f`7OA-dcT@o3wDRY`FgX?+$*pPgMlu^d|V;u2Xqy z=oxq0@7Y_U>vd-*rEHU~I=NE3@k2r5o+p)?jzx6?ISCQmP$=^cLZ+ZK;& zvc>OaY<8%q-{COHC;f8D8=Ko7Z7Q=q-_a|6XVkr|JE!XO((OOQy4|^-m~M`~U29Y_ zNo8_qer2AxW%rmWk1Gq--8v+K;0Ylb)fezW_qmpSr2v!q%5?CkF+Yj*y5W4ig9 z>hXQ*w?A9{d}DFDY)&rgp=Q=gkB{5)zn`D(uODxle#`Fpjks%@eI~7sD{qf0uhV$) zkm;xS;jMdlzx&JlzP|nK16?tupZeb!8#!1Sp|Jvqhaa<kbiJNZ4c3bTTM@Z|d}OBk6ZpJi5>e1|!D@&^_b zmIenOhRJ>`N|R$*8W}k!?`Bn+e2O(@ay*ORpuze`b=O{K6uxU Qfq{X+)78&qol`;+03p{O!~g&Q delta 664 zcmcc1bC+j=ZoOj9Ee4U}57j50@KO<~+*I`G$;ru6Jye7`*VuHfaZv&Z7YTiz|6^z*x6>4Fd}k6Juk8gM)&Czz>neEB2eb?8+7FIzfB^4h|Nu z^nrB#6pK2QlWX7a|M&6CJA+<_8KDaAud1C4DE(Pqc;#_T-Lsl~|Er#Dn(d}=Mr*=4 zGtZ*6R{t$t#eDU+YUpX?x8C%w2~%QNV@~!|mE@}v=J4M=ZMSpXt9je{PVR`my32pk z*D|R_gVhdYTYV;_U)7ACzIBDvr0=`ZS2*j1Ze5whck*-|Se`HRY|+LQtL&y{6~*hk zuUu{D{MNWWL(dUxBZ^V??ai@$EWzVx*FTcaz#X4YKMs=Vv3 zERZI8V&kh>D&1DgR%e;5-~HtDd51}FvL^45Una=0nd`~pYK7Cco}1j=pq?9h`MRF- z)fs!Ps_nFgNPhXtJz-gyWVWI0>)MsxeOu42d^KasRkg=CrC_HWE8}`nR{Lb|D)m1Z|hE_1X*vQDz8``LSPNGYN7q3Btl26g400Ss%UUKVWS?IgwRyaz3jFqv+(_tV)wl zvBpf+U=^IK#wyIrlEgZ>kXdDN0gK?|6|91j8<>PApJ5f8e2UeAxiNxqvNfyHWG`0p x$ptJP%nk}+lRvPULG{LxWtxn{gZ-a))te>+hwo@v&cMLH;OXk;vd$@?2>^1qA@=|P diff --git a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp index aed02007c59..e5be9444c09 100644 --- a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp @@ -66,7 +66,7 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const if (m_renders_as_alt_text) { auto enclosing_rect = context.enclosing_device_rect(absolute_rect()).to_type(); context.recording_painter().draw_rect(enclosing_rect, Gfx::Color::Black); - context.recording_painter().draw_text(enclosing_rect, m_alt_text, Platform::FontPlugin::the().default_font(), Gfx::TextAlignment::Center, computed_values().color(), Gfx::TextElision::Right); + context.recording_painter().draw_text(enclosing_rect, m_alt_text, Platform::FontPlugin::the().default_font(), Gfx::TextAlignment::Center, computed_values().color()); } else if (auto bitmap = m_image_provider.current_image_bitmap(image_rect.size().to_type())) { ScopedCornerRadiusClip corner_clip { context, image_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; auto image_int_rect = image_rect.to_type(); diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index 8a47223a9b8..b6cd84040ff 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -222,19 +222,36 @@ void RecordingPainter::draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color col }); } -void RecordingPainter::draw_text(Gfx::IntRect const& rect, String raw_text, Gfx::Font const& font, Gfx::TextAlignment alignment, Color color, Gfx::TextElision elision, Gfx::TextWrapping wrapping) +void RecordingPainter::draw_text(Gfx::IntRect const& rect, String raw_text, Gfx::Font const& font, Gfx::TextAlignment alignment, Color color) { if (rect.is_empty()) return; - append(DrawText { - .rect = state().translation.map(rect), - .raw_text = move(raw_text), - .alignment = alignment, - .color = color, - .elision = elision, - .wrapping = wrapping, - .font = font, - }); + + auto glyph_run = adopt_ref(*new Gfx::GlyphRun); + auto font_cascade_list = Gfx::FontCascadeList::create(); + font_cascade_list->add(font); + float glyph_run_width = 0; + Gfx::for_each_glyph_position( + { 0, 0 }, raw_text.code_points(), font_cascade_list, [&](Gfx::DrawGlyphOrEmoji const& glyph_or_emoji) { + glyph_run->append(glyph_or_emoji); + return IterationDecision::Continue; + }, + Gfx::IncludeLeftBearing::No, glyph_run_width); + + float baseline_x = 0; + if (alignment == Gfx::TextAlignment::CenterLeft) { + baseline_x = rect.x(); + } else if (alignment == Gfx::TextAlignment::Center) { + baseline_x = static_cast(rect.x()) + (static_cast(rect.width()) - glyph_run_width) / 2.0f; + } else if (alignment == Gfx::TextAlignment::CenterRight) { + baseline_x = static_cast(rect.right()) - glyph_run_width; + } else { + // Unimplemented alignment. + TODO(); + } + auto metrics = font.pixel_metrics(); + float baseline_y = static_cast(rect.y()) + metrics.ascent + (static_cast(rect.height()) - (metrics.ascent + metrics.descent)) / 2.0f; + draw_text_run(Gfx::IntPoint(roundf(baseline_x), roundf(baseline_y)), *glyph_run, color, rect, 1.0); } void RecordingPainter::draw_text_run(Gfx::IntPoint baseline_start, Gfx::GlyphRun const& glyph_run, Color color, Gfx::IntRect const& rect, double scale) diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index f7ee60173e5..77298f8adaa 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -95,7 +95,7 @@ public: void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::LineStyle style = Gfx::LineStyle::Solid, Color alternate_color = Color::Transparent); - void draw_text(Gfx::IntRect const&, String, Gfx::Font const&, Gfx::TextAlignment = Gfx::TextAlignment::TopLeft, Color = Color::Black, Gfx::TextElision = Gfx::TextElision::None, Gfx::TextWrapping = Gfx::TextWrapping::DontWrap); + void draw_text(Gfx::IntRect const&, String, Gfx::Font const&, Gfx::TextAlignment, Color); // Streamlined text drawing routine that does no wrapping/elision/alignment. void draw_text_run(Gfx::IntPoint baseline_start, Gfx::GlyphRun const& glyph_run, Color color, Gfx::IntRect const& rect, double scale);