ladybird/Libraries/LibWeb/Painting/DisplayListCommand.cpp

229 lines
6.9 KiB
C++
Raw Permalink Normal View History

/*
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Painting/DisplayListCommand.h>
namespace Web::Painting {
Gfx::IntRect PaintOuterBoxShadow::bounding_rect() const
{
auto rect = shadow_rect;
rect.inflate(blur_radius * 2, blur_radius * 2, blur_radius * 2, blur_radius * 2);
return rect;
}
Gfx::IntRect PaintInnerBoxShadow::bounding_rect() const
{
return device_content_rect;
}
void DrawGlyphRun::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} translation={} color={}", rect, translation, color);
}
void FillRect::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} color={}", rect, color);
}
void DrawScaledDecodedImageFrame::dump(StringBuilder& builder) const
{
builder.appendff(" dst_rect={}", dst_rect);
}
void DrawRepeatedDecodedImageFrame::dump(StringBuilder& builder) const
{
builder.appendff(" dst_rect={} clip_rect={}", dst_rect, clip_rect);
}
void DrawCompositedContext::dump(StringBuilder& builder) const
{
builder.appendff(" dst_rect={}", dst_rect);
}
void DrawCanvas::dump(StringBuilder& builder) const
{
builder.appendff(" dst_rect={}", dst_rect);
}
void DrawVideoFrame::dump(StringBuilder& builder) const
{
builder.appendff(" dst_rect={}", dst_rect);
}
void Save::dump(StringBuilder&) const
{
}
void SaveLayer::dump(StringBuilder&) const
{
}
void Restore::dump(StringBuilder&) const
{
}
void Translate::dump(StringBuilder& builder) const
{
builder.appendff(" delta={}", delta);
}
void AddClipRect::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", rect);
}
void PaintLinearGradient::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", gradient_rect);
}
void PaintRadialGradient::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} center={} size={}", rect, center, size);
}
void PaintConicGradient::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} position={} angle={}", rect, position, start_angle);
}
void PaintOuterBoxShadow::dump(StringBuilder& builder) const
{
builder.appendff(" content_rect={} shadow_rect={} blur_radius={} color={}", device_content_rect, shadow_rect, blur_radius, color);
}
void PaintInnerBoxShadow::dump(StringBuilder& builder) const
{
builder.appendff(" content_rect={} outer_shadow_rect={} inner_shadow_rect={} blur_radius={} color={}", device_content_rect, outer_shadow_rect, inner_shadow_rect, blur_radius, color);
}
void PaintTextShadow::dump(StringBuilder& builder) const
{
builder.appendff(" shadow_rect={} text_rect={} draw_location={} blur_radius={} color={}", shadow_bounding_rect, text_rect, draw_location, blur_radius, color);
}
void FillRectWithRoundedCorners::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} color={}", rect, color);
}
void FillPath::dump(StringBuilder& builder) const
{
builder.appendff(" path_bounding_rect={}", path_bounding_rect);
}
void StrokePath::dump(StringBuilder&) const
{
}
void DrawEllipse::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} color={} thickness={}", rect, color, thickness);
}
void FillEllipse::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} color={}", rect, color);
}
void DrawLine::dump(StringBuilder& builder) const
{
builder.appendff(" from={} to={} color={} thickness={}", from, to, color, thickness);
}
void ApplyBackdropFilter::dump(StringBuilder& builder) const
{
builder.appendff(" backdrop_region={}", backdrop_region);
}
void DrawRect::dump(StringBuilder& builder) const
{
builder.appendff(" rect={} color={} rough={}", rect, color, rough);
}
void AddRoundedRectClip::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", border_rect);
}
void PaintNestedDisplayList::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", rect);
}
void CompositorScrollNode::dump(StringBuilder& builder) const
{
builder.appendff(" scroll_frame_index={} parent_scroll_frame_index={} scrollport_rect={} max_scroll_offset={} is_viewport={}",
scroll_frame_index, parent_scroll_frame_index, scrollport_rect, max_scroll_offset, is_viewport);
}
static void dump_optional_float(StringBuilder& builder, Optional<float> value)
{
if (value.has_value())
builder.appendff("{}", *value);
else
builder.append("none"sv);
}
void CompositorStickyArea::dump(StringBuilder& builder) const
{
builder.appendff(" scroll_frame_index={} parent_scroll_frame_index={} nearest_scrolling_ancestor_index={} position_relative_to_scroll_ancestor={} border_box_size={} scrollport_size={} containing_block_region={} needs_parent_offset_adjustment={} inset_top=",
scroll_frame_index, parent_scroll_frame_index, nearest_scrolling_ancestor_index, position_relative_to_scroll_ancestor, border_box_size, scrollport_size, containing_block_region, needs_parent_offset_adjustment);
dump_optional_float(builder, inset_top);
builder.append(" inset_right="sv);
dump_optional_float(builder, inset_right);
builder.append(" inset_bottom="sv);
dump_optional_float(builder, inset_bottom);
builder.append(" inset_left="sv);
dump_optional_float(builder, inset_left);
}
void CompositorBlockingWheelEventRegion::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", rect);
}
void CompositorWheelHitTestTarget::dump(StringBuilder& builder) const
{
builder.appendff(" target_scroll_frame_index={} rect={}", target_scroll_frame_index, rect);
}
void CompositorWheelHitTestTargetWithCornerRadii::dump(StringBuilder& builder) const
{
builder.appendff(" target_scroll_frame_index={} rect={}", target_scroll_frame_index, rect);
if (corner_radii.has_any_radius()) {
builder.appendff(" corner_radii=[{}x{},{}x{},{}x{},{}x{}]",
corner_radii.top_left.horizontal_radius, corner_radii.top_left.vertical_radius,
corner_radii.top_right.horizontal_radius, corner_radii.top_right.vertical_radius,
corner_radii.bottom_right.horizontal_radius, corner_radii.bottom_right.vertical_radius,
corner_radii.bottom_left.horizontal_radius, corner_radii.bottom_left.vertical_radius);
}
}
void CompositorMainThreadWheelEventRegion::dump(StringBuilder& builder) const
{
builder.appendff(" rect={}", rect);
}
void CompositorViewportScrollbar::dump(StringBuilder& builder) const
{
builder.appendff(" scroll_frame_index={} gutter_rect={} thumb_rect={} expanded_gutter_rect={} expanded_thumb_rect={} scroll_size={} expanded_scroll_size={} max_scroll_offset={} thumb_color={} track_color={} vertical={}",
scroll_frame_index, gutter_rect, thumb_rect, expanded_gutter_rect, expanded_thumb_rect, scroll_size, expanded_scroll_size, max_scroll_offset, thumb_color, track_color, vertical);
}
void PaintScrollBar::dump(StringBuilder&) const
{
}
LibWeb: Integrate AccumulatedVisualContext with display list Integrate AccumulatedVisualContext with display list recording and playback. This is the main commit of the refactoring that delivers the architectural improvements enabled by AccumulatedVisualContext. Recording changes: Each display list command now stores a single RefPtr<AccumulatedVisualContext> instead of separate scroll_frame_id and ClipFrame. The recorder simply captures the current accumulated context when appending commands. The before_paint()/after_paint() hooks that pushed/popped scroll frame IDs are replaced by directly setting accumulated_visual_context on the recorder before painting each element. Playback changes: The display list player now uses LCA (Lowest Common Ancestor) based traversal to switch between visual contexts efficiently. When transitioning from context A to context B: 1. Find the LCA of A and B in the context tree 2. Pop (restore) states back to the LCA depth 3. Push (save + apply) states from LCA down to B This approach minimizes redundant save/restore operations. For example, when rendering siblings that share a common scroll container, the player keeps that scroll state applied and only switches the divergent parts of their context chains. Key deletions: - Remove translate_by() from all 45 display list commands - commands are now immutable - Remove transform/perspective fields from PushStackingContext - transforms are tracked via AccumulatedVisualContext - Remove push_scroll_frame_id()/pop_scroll_frame_id() from DisplayListRecorder - Remove before_paint()/after_paint() hooks from Paintable - Merge ApplyOpacity, ApplyCompositeAndBlendingOperator, ApplyFilter into single ApplyEffects command Stacking context painting changes: The StackingContext::paint() method is significantly simplified. Instead of building a PushStackingContextParams struct with transform matrices and pushing/popping stacking contexts, it now: 1. Sets the accumulated visual context (which already contains transforms) 2. Applies effects (opacity, blend mode, filters) if needed 3. Applies clip path if needed 4. Paints the content 5. Restores state The visual state management that was interleaved throughout the painting code is now handled uniformly by the context tree.
2026-01-13 16:44:09 -03:00
void ApplyEffects::dump(StringBuilder& builder) const
{
builder.appendff(" opacity={} has_filter={}", opacity, has_filter);
}
}