1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:37:46 +00:00

LibWeb: Implement text-shadow painting

We don't yet take the spread-distance parameter into account, since we
don't have a way to "inflate" the text shadow.

Also, I'm not sure if we need to inflate the shadow slightly anyway.
Blurred shadows of our pixel fonts seem very faint. Part of this is
that a blur of < 3px does nothing, see #13231, but even so we might
want to inflate it a little.
This commit is contained in:
Sam Atkins 2022-03-24 15:20:25 +00:00 committed by Andreas Kling
parent 03daa4653f
commit 5aad32b504
3 changed files with 81 additions and 0 deletions

View file

@ -407,6 +407,35 @@ void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
context.painter().translate(-scroll_offset.to_type<int>());
}
// Text shadows
// This is yet another loop, but done here because all shadows should appear under all text.
// So, we paint the shadows before painting any text.
// FIXME: Find a smarter way to do this?
if (phase == PaintPhase::Foreground) {
for (auto& line_box : m_line_boxes) {
for (auto& fragment : line_box.fragments()) {
if (is<Layout::TextNode>(fragment.layout_node())) {
auto& text_shadow = fragment.layout_node().computed_values().text_shadow();
if (!text_shadow.is_empty()) {
Vector<ShadowData> resolved_shadow_data;
resolved_shadow_data.ensure_capacity(text_shadow.size());
for (auto const& layer : text_shadow) {
resolved_shadow_data.empend(
layer.color,
static_cast<int>(layer.offset_x.to_px(layout_box())),
static_cast<int>(layer.offset_y.to_px(layout_box())),
static_cast<int>(layer.blur_radius.to_px(layout_box())),
static_cast<int>(layer.spread_distance.to_px(layout_box())),
ShadowPlacement::Outer);
}
context.painter().set_font(fragment.layout_node().font());
Painting::paint_text_shadow(context, fragment, resolved_shadow_data);
}
}
}
}
}
for (auto& line_box : m_line_boxes) {
for (auto& fragment : line_box.fragments()) {
if (context.should_show_line_box_borders())

View file

@ -8,6 +8,7 @@
#include <LibGfx/DisjointRectSet.h>
#include <LibGfx/Filters/FastBoxBlurFilter.h>
#include <LibGfx/Painter.h>
#include <LibWeb/Layout/LineBoxFragment.h>
#include <LibWeb/Painting/PaintContext.h>
#include <LibWeb/Painting/ShadowPainting.h>
@ -124,4 +125,53 @@ void paint_box_shadow(PaintContext& context, Gfx::IntRect const& content_rect, V
}
}
void paint_text_shadow(PaintContext& context, Layout::LineBoxFragment const& fragment, Vector<ShadowData> const& shadow_layers)
{
if (shadow_layers.is_empty())
return;
auto& painter = context.painter();
// Note: Box-shadow layers are ordered front-to-back, so we paint them in reverse
for (auto& layer : shadow_layers.in_reverse()) {
// Space around the painted text to allow it to blur.
// FIXME: Include spread in this once we use that.
auto margin = layer.blur_radius * 2;
Gfx::IntRect text_rect {
margin, margin,
static_cast<int>(ceilf(fragment.width())),
static_cast<int>(ceilf(fragment.height()))
};
Gfx::IntRect bounding_rect {
0, 0,
text_rect.width() + margin + margin,
text_rect.height() + margin + margin
};
// FIXME: Figure out the maximum bitmap size for all shadows and then allocate it once and reuse it?
auto maybe_shadow_bitmap = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, bounding_rect.size());
if (maybe_shadow_bitmap.is_error()) {
dbgln("Unable to allocate temporary bitmap for box-shadow rendering: {}", maybe_shadow_bitmap.error());
return;
}
auto shadow_bitmap = maybe_shadow_bitmap.release_value();
Gfx::Painter shadow_painter { *shadow_bitmap };
shadow_painter.set_font(context.painter().font());
// FIXME: "Spread" the shadow somehow.
shadow_painter.draw_text(text_rect, fragment.text(), Gfx::TextAlignment::TopLeft, layer.color);
// Blur
Gfx::FastBoxBlurFilter filter(*shadow_bitmap);
filter.apply_three_passes(layer.blur_radius);
auto draw_rect = Gfx::enclosing_int_rect(fragment.absolute_rect());
Gfx::IntPoint draw_location {
draw_rect.x() + layer.offset_x - margin,
draw_rect.y() + layer.offset_y - margin
};
painter.blit(draw_location, *shadow_bitmap, bounding_rect);
}
}
}

View file

@ -7,6 +7,7 @@
#pragma once
#include <LibGfx/Color.h>
#include <LibWeb/Forward.h>
#include <LibWeb/Painting/PaintContext.h>
namespace Web::Painting {
@ -26,5 +27,6 @@ struct ShadowData {
};
void paint_box_shadow(PaintContext&, Gfx::IntRect const&, Vector<ShadowData> const&);
void paint_text_shadow(PaintContext&, Layout::LineBoxFragment const&, Vector<ShadowData> const&);
}