diff --git a/Tests/LibWeb/Ref/reference/images/text-shadow-ref.png b/Tests/LibWeb/Ref/reference/images/text-shadow-ref.png index 9edd4e3757..19fc3a74cd 100644 Binary files a/Tests/LibWeb/Ref/reference/images/text-shadow-ref.png and b/Tests/LibWeb/Ref/reference/images/text-shadow-ref.png differ diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp index d93a48c9d0..5382e7830a 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp @@ -225,7 +225,7 @@ CommandResult PaintingCommandExecutorCPU::paint_inner_box_shadow(PaintOuterBoxSh return CommandResult::Continue; } -CommandResult PaintingCommandExecutorCPU::paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, String const& text, Gfx::Font const& font, Color const& color, int fragment_baseline, Gfx::IntPoint const& draw_location) +CommandResult PaintingCommandExecutorCPU::paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span glyph_run, Color const& color, int fragment_baseline, Gfx::IntPoint const& draw_location) { // FIXME: Figure out the maximum bitmap size for all shadows and then allocate it once and reuse it? auto maybe_shadow_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, shadow_bounding_rect.size()); @@ -237,8 +237,17 @@ CommandResult PaintingCommandExecutorCPU::paint_text_shadow(int blur_radius, Gfx Gfx::Painter shadow_painter { *shadow_bitmap }; // FIXME: "Spread" the shadow somehow. - Gfx::IntPoint baseline_start(text_rect.x(), text_rect.y() + fragment_baseline); - shadow_painter.draw_text_run(baseline_start, Utf8View(text), font, color); + Gfx::IntPoint const baseline_start(text_rect.x(), text_rect.y() + fragment_baseline); + shadow_painter.translate(baseline_start); + for (auto const& glyph_or_emoji : glyph_run) { + if (glyph_or_emoji.has()) { + auto const& glyph = glyph_or_emoji.get(); + shadow_painter.draw_glyph(glyph.position, glyph.code_point, *glyph.font, color); + } else { + auto const& emoji = glyph_or_emoji.get(); + shadow_painter.draw_emoji(emoji.position.to_type(), *emoji.emoji, *emoji.font); + } + } // Blur Gfx::StackBlurFilter filter(*shadow_bitmap); diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h index d5d5f6d5dd..5746600f9e 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h @@ -26,7 +26,7 @@ public: CommandResult paint_linear_gradient(Gfx::IntRect const&, Web::Painting::LinearGradientData const&) override; CommandResult paint_outer_box_shadow(PaintOuterBoxShadowParams const&) override; CommandResult paint_inner_box_shadow(PaintOuterBoxShadowParams const&) override; - CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, String const& text, Gfx::Font const&, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) override; + CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) override; CommandResult fill_rect_with_rounded_corners(Gfx::IntRect const&, Color const&, Gfx::AntiAliasingPainter::CornerRadius const& top_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& top_right_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_right_radius, Optional const& aa_translation) override; CommandResult fill_path_using_color(Gfx::Path const&, Color const&, Gfx::Painter::WindingRule winding_rule, Optional const& aa_translation) override; CommandResult fill_path_using_paint_style(Gfx::Path const&, Gfx::PaintStyle const& paint_style, Gfx::Painter::WindingRule winding_rule, float opacity, Optional const& aa_translation) override; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp index cc3cfb78e4..eaf435ff58 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp @@ -165,7 +165,7 @@ CommandResult PaintingCommandExecutorGPU::paint_inner_box_shadow(PaintOuterBoxSh return CommandResult::Continue; } -CommandResult PaintingCommandExecutorGPU::paint_text_shadow(int, Gfx::IntRect const&, Gfx::IntRect const&, String const&, Gfx::Font const&, Color const&, int, Gfx::IntPoint const&) +CommandResult PaintingCommandExecutorGPU::paint_text_shadow(int, Gfx::IntRect const&, Gfx::IntRect const&, Span, Color const&, int, Gfx::IntPoint const&) { // FIXME return CommandResult::Continue; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h index 3f1dd2ce4c..fb7d418efe 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h @@ -27,7 +27,7 @@ public: CommandResult paint_linear_gradient(Gfx::IntRect const&, Web::Painting::LinearGradientData const&) override; CommandResult paint_outer_box_shadow(PaintOuterBoxShadowParams const&) override; CommandResult paint_inner_box_shadow(PaintOuterBoxShadowParams const&) override; - CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, String const& text, Gfx::Font const&, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) override; + CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) override; CommandResult fill_rect_with_rounded_corners(Gfx::IntRect const&, Color const&, Gfx::AntiAliasingPainter::CornerRadius const& top_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& top_right_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_right_radius, Optional const& aa_translation) override; CommandResult fill_path_using_color(Gfx::Path const&, Color const&, Gfx::Painter::WindingRule winding_rule, Optional const& aa_translation) override; CommandResult fill_path_using_paint_style(Gfx::Path const&, Gfx::PaintStyle const& paint_style, Gfx::Painter::WindingRule winding_rule, float opacity, Optional const& aa_translation) override; diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index 360134dd2b..8a5cf9c7e6 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -344,14 +344,13 @@ void RecordingPainter::paint_inner_box_shadow_params(PaintOuterBoxShadowParams p }); } -void RecordingPainter::paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Utf8View text, Gfx::Font const& font, Color color, int fragment_baseline, Gfx::IntPoint draw_location) +void RecordingPainter::paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Span glyph_run, Color color, int fragment_baseline, Gfx::IntPoint draw_location) { push_command(PaintTextShadow { .blur_radius = blur_radius, .shadow_bounding_rect = bounding_rect, .text_rect = text_rect, - .text = String::from_utf8(text.as_string()).release_value_but_fixme_should_propagate_errors(), - .font = font, + .glyph_run = Vector { glyph_run }, .color = color, .fragment_baseline = fragment_baseline, .draw_location = state().translation.map(draw_location) }); @@ -497,7 +496,7 @@ void RecordingPainter::execute(PaintingCommandExecutor& executor) return executor.paint_inner_box_shadow(command.outer_box_shadow_params); }, [&](PaintTextShadow const& command) { - return executor.paint_text_shadow(command.blur_radius, command.shadow_bounding_rect, command.text_rect, command.text, command.font, command.color, command.fragment_baseline, command.draw_location); + return executor.paint_text_shadow(command.blur_radius, command.shadow_bounding_rect, command.text_rect, command.glyph_run, command.color, command.fragment_baseline, command.draw_location); }, [&](FillRectWithRoundedCorners const& command) { return executor.fill_rect_with_rounded_corners(command.rect, command.color, command.top_left_radius, command.top_right_radius, command.bottom_left_radius, command.bottom_right_radius, command.aa_translation); diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index ef2dfe3a43..def49bd2c3 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -141,8 +141,7 @@ struct PaintTextShadow { int blur_radius; Gfx::IntRect shadow_bounding_rect; Gfx::IntRect text_rect; - String text; - NonnullRefPtr font; + Vector glyph_run; Color color; int fragment_baseline; Gfx::IntPoint draw_location; @@ -373,7 +372,7 @@ public: virtual CommandResult paint_conic_gradient(Gfx::IntRect const& rect, ConicGradientData const&, Gfx::IntPoint const& position) = 0; virtual CommandResult paint_outer_box_shadow(PaintOuterBoxShadowParams const&) = 0; virtual CommandResult paint_inner_box_shadow(PaintOuterBoxShadowParams const&) = 0; - virtual CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, String const&, Gfx::Font const&, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) = 0; + virtual CommandResult paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span, Color const&, int fragment_baseline, Gfx::IntPoint const& draw_location) = 0; virtual CommandResult fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color const& color, Gfx::AntiAliasingPainter::CornerRadius const& top_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& top_right_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_right_radius, Optional const& aa_translation) = 0; virtual CommandResult fill_path_using_color(Gfx::Path const&, Color const& color, Gfx::Painter::WindingRule, Optional const& aa_translation) = 0; virtual CommandResult fill_path_using_paint_style(Gfx::Path const&, Gfx::PaintStyle const& paint_style, Gfx::Painter::WindingRule winding_rule, float opacity, Optional const& aa_translation) = 0; @@ -493,7 +492,7 @@ public: void paint_outer_box_shadow_params(PaintOuterBoxShadowParams params); void paint_inner_box_shadow_params(PaintOuterBoxShadowParams params); - void paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Utf8View text, Gfx::Font const& font, Color color, int fragment_baseline, Gfx::IntPoint draw_location); + void paint_text_shadow(int blur_radius, Gfx::IntRect bounding_rect, Gfx::IntRect text_rect, Span glyph_run, Color color, int fragment_baseline, Gfx::IntPoint draw_location); void fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color color, Gfx::AntiAliasingPainter::CornerRadius top_left_radius, Gfx::AntiAliasingPainter::CornerRadius top_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_right_radius, Gfx::AntiAliasingPainter::CornerRadius bottom_left_radius); void fill_rect_with_rounded_corners(Gfx::IntRect const& a_rect, Color color, int radius); diff --git a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp index 55ca61284e..d021612f04 100644 --- a/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/ShadowPainting.cpp @@ -586,10 +586,19 @@ void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fra auto fragment_width = context.enclosing_device_pixels(fragment.width()).value(); auto fragment_height = context.enclosing_device_pixels(fragment.height()).value(); auto draw_rect = context.enclosing_device_rect(fragment.absolute_rect()).to_type(); - auto text = Utf8View(fragment.text()); - auto& font = fragment.layout_node().scaled_font(context); + auto const& scaled_font = fragment.layout_node().scaled_font(context); auto fragment_baseline = context.rounded_device_pixels(fragment.baseline()).value(); + Vector scaled_glyph_run; + scaled_glyph_run.ensure_capacity(fragment.glyph_run().size()); + for (auto glyph : fragment.glyph_run()) { + glyph.visit([&](auto& glyph) { + glyph.font = &scaled_font; + glyph.position = glyph.position.scaled(context.device_pixels_per_css_pixel()); + }); + scaled_glyph_run.append(move(glyph)); + } + // Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse for (auto& layer : shadow_layers.in_reverse()) { int offset_x = context.rounded_device_pixels(layer.offset_x).value(); @@ -613,7 +622,7 @@ void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fra draw_rect.y() + offset_y - margin }; - context.recording_painter().paint_text_shadow(blur_radius, bounding_rect, text_rect, text, font, layer.color, fragment_baseline, draw_location); + context.recording_painter().paint_text_shadow(blur_radius, bounding_rect, text_rect, scaled_glyph_run, layer.color, fragment_baseline, draw_location); } }