LibWeb: Remove InlinePaintable
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
It was replaced with PaintableWithLines.
This commit is contained in:
parent
6a549f6270
commit
c097f53875
Notes:
github-actions[bot]
2024-10-16 18:26:34 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/c097f538756 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1829
17 changed files with 1 additions and 513 deletions
|
@ -23,7 +23,6 @@ source_set("Painting") {
|
|||
"DisplayListRecorder.cpp",
|
||||
"GradientPainting.cpp",
|
||||
"ImagePaintable.cpp",
|
||||
"InlinePaintable.cpp",
|
||||
"LabelablePaintable.cpp",
|
||||
"MarkerPaintable.cpp",
|
||||
"MediaPaintable.cpp",
|
||||
|
|
|
@ -583,7 +583,6 @@ set(SOURCES
|
|||
Painting/DisplayListRecorder.cpp
|
||||
Painting/GradientPainting.cpp
|
||||
Painting/ImagePaintable.cpp
|
||||
Painting/InlinePaintable.cpp
|
||||
Painting/LabelablePaintable.cpp
|
||||
Painting/MarkerPaintable.cpp
|
||||
Painting/MediaPaintable.cpp
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
|
@ -1000,16 +999,6 @@ JS::NonnullGCPtr<Geometry::DOMRectList> Element::get_client_rects() const
|
|||
.translated(paintable_box->transform_origin())
|
||||
.translated(-scroll_offset);
|
||||
rects.append(Geometry::DOMRect::create(realm(), transformed_rect.to_type<float>()));
|
||||
} else if (paintable && is<Painting::InlinePaintable>(*paintable)) {
|
||||
auto const& inline_paintable = static_cast<Painting::InlinePaintable const&>(*paintable);
|
||||
|
||||
if (auto enclosing_scroll_offset = inline_paintable.enclosing_scroll_frame(); enclosing_scroll_offset) {
|
||||
scroll_offset.translate_by(-enclosing_scroll_offset->cumulative_offset());
|
||||
}
|
||||
|
||||
auto absolute_rect = inline_paintable.bounding_rect();
|
||||
absolute_rect.translate_by(-scroll_offset);
|
||||
rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type<float>())));
|
||||
} else if (paintable) {
|
||||
dbgln("FIXME: Failed to get client rects for element ({})", debug_description());
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Namespace.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||
|
||||
namespace Web::DOM {
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include <LibWeb/Layout/SVGBox.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWeb/Painting/TextPaintable.h>
|
||||
#include <LibWeb/SVG/SVGDecodedImageData.h>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <LibWeb/Layout/BlockContainer.h>
|
||||
#include <LibWeb/Layout/InlineFormattingContext.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/LayoutState.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/SVGPathPaintable.h>
|
||||
#include <LibWeb/Painting/SVGSVGPaintable.h>
|
||||
#include <LibWeb/Painting/TextPaintable.h>
|
||||
|
@ -126,17 +125,6 @@ static CSSPixelRect measure_scrollable_overflow(Box const& box)
|
|||
scrollable_overflow_rect.unite_vertically(child_scrollable_overflow);
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
} else {
|
||||
box.for_each_child([&scrollable_overflow_rect, &content_overflow_rect](Node const& child) {
|
||||
if (child.first_paintable() && child.first_paintable()->is_inline_paintable()) {
|
||||
for (auto const& fragment : static_cast<Painting::InlinePaintable const&>(*child.first_paintable()).fragments()) {
|
||||
scrollable_overflow_rect = scrollable_overflow_rect.united(fragment.absolute_rect());
|
||||
content_overflow_rect = content_overflow_rect.united(fragment.absolute_rect());
|
||||
}
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <LibWeb/Layout/TableWrapper.h>
|
||||
#include <LibWeb/Layout/TextNode.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Platform/FontPlugin.h>
|
||||
|
||||
namespace Web::Layout {
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <LibWeb/Layout/TextNode.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/BackgroundPainting.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
@ -42,12 +41,6 @@ static RefPtr<DisplayList> compute_text_clip_paths(PaintContext& context, Painta
|
|||
if (is<Layout::TextNode>(fragment.layout_node()))
|
||||
add_text_clip_path(fragment);
|
||||
}
|
||||
} else if (is<InlinePaintable>(paintable)) {
|
||||
auto const& inline_paintable = static_cast<InlinePaintable const&>(paintable);
|
||||
for (auto const& fragment : inline_paintable.fragments()) {
|
||||
if (is<Layout::TextNode>(fragment.layout_node()))
|
||||
add_text_clip_path(fragment);
|
||||
}
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
|
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/AntiAliasingPainter.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Range.h>
|
||||
#include <LibWeb/Layout/BlockContainer.h>
|
||||
#include <LibWeb/Painting/BackgroundPainting.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/TextPaintable.h>
|
||||
#include <LibWeb/Selection/Selection.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
JS_DEFINE_ALLOCATOR(InlinePaintable);
|
||||
|
||||
JS::NonnullGCPtr<InlinePaintable> InlinePaintable::create(Layout::InlineNode const& layout_node)
|
||||
{
|
||||
return layout_node.heap().allocate_without_realm<InlinePaintable>(layout_node);
|
||||
}
|
||||
|
||||
InlinePaintable::InlinePaintable(Layout::InlineNode const& layout_node)
|
||||
: Paintable(layout_node)
|
||||
{
|
||||
}
|
||||
|
||||
Layout::InlineNode const& InlinePaintable::layout_node() const
|
||||
{
|
||||
return static_cast<Layout::InlineNode const&>(Paintable::layout_node());
|
||||
}
|
||||
|
||||
void InlinePaintable::before_paint(PaintContext& context, PaintPhase) const
|
||||
{
|
||||
apply_clip(context);
|
||||
|
||||
if (scroll_frame_id().has_value()) {
|
||||
context.display_list_recorder().push_scroll_frame_id(scroll_frame_id().value());
|
||||
}
|
||||
}
|
||||
|
||||
void InlinePaintable::after_paint(PaintContext& context, PaintPhase) const
|
||||
{
|
||||
if (scroll_frame_id().has_value()) {
|
||||
context.display_list_recorder().pop_scroll_frame_id();
|
||||
}
|
||||
|
||||
restore_clip(context);
|
||||
}
|
||||
|
||||
void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||
{
|
||||
auto& display_list_recorder = context.display_list_recorder();
|
||||
|
||||
if (phase == PaintPhase::Background) {
|
||||
auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position();
|
||||
|
||||
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
||||
CSSPixelRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
||||
|
||||
if (is_first_fragment) {
|
||||
auto extra_start_width = box_model().padding.left;
|
||||
absolute_fragment_rect.translate_by(-extra_start_width, 0);
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_start_width);
|
||||
}
|
||||
|
||||
if (is_last_fragment) {
|
||||
auto extra_end_width = box_model().padding.right;
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width);
|
||||
}
|
||||
|
||||
absolute_fragment_rect.translate_by(0, -box_model().padding.top);
|
||||
absolute_fragment_rect.set_height(absolute_fragment_rect.height() + box_model().padding.top + box_model().padding.bottom);
|
||||
|
||||
auto const& border_radii_data = fragment.border_radii_data();
|
||||
paint_background(context, layout_node(), computed_values().image_rendering(), fragment.resolved_background(), border_radii_data);
|
||||
|
||||
if (!box_shadow_data().is_empty()) {
|
||||
auto borders_data = BordersData {
|
||||
.top = computed_values().border_top(),
|
||||
.right = computed_values().border_right(),
|
||||
.bottom = computed_values().border_bottom(),
|
||||
.left = computed_values().border_left(),
|
||||
};
|
||||
auto absolute_fragment_rect_bordered = absolute_fragment_rect.inflated(
|
||||
borders_data.top.width, borders_data.right.width,
|
||||
borders_data.bottom.width, borders_data.left.width);
|
||||
paint_box_shadow(context, absolute_fragment_rect_bordered, absolute_fragment_rect,
|
||||
borders_data, border_radii_data, box_shadow_data());
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
auto paint_border_or_outline = [&](Optional<BordersData> outline_data = {}, CSSPixels outline_offset = 0) {
|
||||
auto borders_data = BordersData {
|
||||
.top = computed_values().border_top(),
|
||||
.right = computed_values().border_right(),
|
||||
.bottom = computed_values().border_bottom(),
|
||||
.left = computed_values().border_left(),
|
||||
};
|
||||
|
||||
auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position();
|
||||
|
||||
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
||||
CSSPixelRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
||||
|
||||
if (is_first_fragment) {
|
||||
auto extra_start_width = box_model().padding.left;
|
||||
absolute_fragment_rect.translate_by(-extra_start_width, 0);
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_start_width);
|
||||
}
|
||||
|
||||
if (is_last_fragment) {
|
||||
auto extra_end_width = box_model().padding.right;
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width);
|
||||
}
|
||||
|
||||
absolute_fragment_rect.translate_by(0, -box_model().padding.top);
|
||||
absolute_fragment_rect.set_height(absolute_fragment_rect.height() + box_model().padding.top + box_model().padding.bottom);
|
||||
|
||||
auto borders_rect = absolute_fragment_rect.inflated(borders_data.top.width, borders_data.right.width, borders_data.bottom.width, borders_data.left.width);
|
||||
auto border_radii_data = fragment.border_radii_data();
|
||||
|
||||
if (outline_data.has_value()) {
|
||||
auto outline_offset_x = outline_offset;
|
||||
auto outline_offset_y = outline_offset;
|
||||
// "Both the height and the width of the outside of the shape drawn by the outline should not
|
||||
// become smaller than twice the computed value of the outline-width property to make sure
|
||||
// that an outline can be rendered even with large negative values."
|
||||
// https://www.w3.org/TR/css-ui-4/#outline-offset
|
||||
// So, if the horizontal outline offset is > half the borders_rect's width then we set it to that.
|
||||
// (And the same for y)
|
||||
if ((borders_rect.width() / 2) + outline_offset_x < 0)
|
||||
outline_offset_x = -borders_rect.width() / 2;
|
||||
if ((borders_rect.height() / 2) + outline_offset_y < 0)
|
||||
outline_offset_y = -borders_rect.height() / 2;
|
||||
|
||||
border_radii_data.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
borders_rect.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(borders_rect), border_radii_data.as_corners(context), outline_data->to_device_pixels(context));
|
||||
} else {
|
||||
paint_all_borders(context.display_list_recorder(), context.rounded_device_rect(borders_rect), border_radii_data.as_corners(context), borders_data.to_device_pixels(context));
|
||||
}
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
};
|
||||
|
||||
if (phase == PaintPhase::Border) {
|
||||
paint_border_or_outline();
|
||||
}
|
||||
|
||||
if (phase == PaintPhase::Outline) {
|
||||
auto maybe_outline_data = this->outline_data();
|
||||
if (maybe_outline_data.has_value())
|
||||
paint_border_or_outline(maybe_outline_data.value(), computed_values().outline_offset().to_px(layout_node()));
|
||||
}
|
||||
|
||||
if (phase == PaintPhase::Foreground) {
|
||||
for_each_fragment([&](auto const& fragment, bool, bool) {
|
||||
if (is<TextPaintable>(fragment.paintable()))
|
||||
paint_text_fragment(context, static_cast<TextPaintable const&>(fragment.paintable()), fragment, phase);
|
||||
});
|
||||
}
|
||||
|
||||
if (phase == PaintPhase::Overlay && layout_node().document().inspected_layout_node() == &layout_node()) {
|
||||
// FIXME: This paints a double-thick border between adjacent fragments, where ideally there
|
||||
// would be none. Once we implement non-rectangular outlines for the `outline` CSS
|
||||
// property, we can use that here instead.
|
||||
for_each_fragment([&](auto const& fragment, bool, bool) {
|
||||
display_list_recorder.draw_rect(context.enclosing_device_rect(fragment.absolute_rect()).template to_type<int>(), Color::Magenta);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
void InlinePaintable::for_each_fragment(Callback callback) const
|
||||
{
|
||||
for (size_t i = 0; i < m_fragments.size(); ++i) {
|
||||
auto const& fragment = m_fragments[i];
|
||||
callback(fragment, i == 0, i == m_fragments.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
TraversalDecision InlinePaintable::hit_test(CSSPixelPoint position, HitTestType type, Function<TraversalDecision(HitTestResult)> const& callback) const
|
||||
{
|
||||
if (clip_rect_for_hit_testing().has_value() && !clip_rect_for_hit_testing().value().contains(position))
|
||||
return TraversalDecision::Continue;
|
||||
|
||||
auto position_adjusted_by_scroll_offset = position;
|
||||
position_adjusted_by_scroll_offset.translate_by(-cumulative_offset_of_enclosing_scroll_frame());
|
||||
|
||||
for (auto const& fragment : m_fragments) {
|
||||
if (fragment.paintable().stacking_context())
|
||||
continue;
|
||||
auto fragment_absolute_rect = fragment.absolute_rect();
|
||||
if (fragment_absolute_rect.contains(position_adjusted_by_scroll_offset)) {
|
||||
if (fragment.paintable().hit_test(position, type, callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
auto hit_test_result = HitTestResult { const_cast<Paintable&>(fragment.paintable()), fragment.text_index_at(position_adjusted_by_scroll_offset.x()) };
|
||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
} else if (type == HitTestType::TextCursor) {
|
||||
auto const* common_ancestor_parent = [&]() -> DOM::Node const* {
|
||||
auto selection = document().get_selection();
|
||||
if (!selection)
|
||||
return nullptr;
|
||||
auto range = selection->range();
|
||||
if (!range)
|
||||
return nullptr;
|
||||
auto common_ancestor = range->common_ancestor_container();
|
||||
if (common_ancestor->parent())
|
||||
return common_ancestor->parent();
|
||||
return common_ancestor;
|
||||
}();
|
||||
|
||||
auto const* fragment_dom_node = fragment.layout_node().dom_node();
|
||||
if (common_ancestor_parent && fragment_dom_node && common_ancestor_parent->is_ancestor_of(*fragment_dom_node)) {
|
||||
// If we reached this point, the position is not within the fragment. However, the fragment start or end might be
|
||||
// the place to place the cursor. To determine the best place, we first find the closest fragment horizontally to
|
||||
// the cursor. If we could not find one, then find for the closest vertically above the cursor.
|
||||
// If we knew the direction of selection, we would look above if selecting upward.
|
||||
if (fragment_absolute_rect.bottom() - 1 <= position_adjusted_by_scroll_offset.y()) { // fully below the fragment
|
||||
HitTestResult hit_test_result {
|
||||
.paintable = const_cast<Paintable&>(fragment.paintable()),
|
||||
.index_in_node = fragment.start() + fragment.length(),
|
||||
.vertical_distance = position_adjusted_by_scroll_offset.y() - fragment_absolute_rect.bottom(),
|
||||
};
|
||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
} else if (fragment_absolute_rect.top() <= position_adjusted_by_scroll_offset.y()) { // vertically within the fragment
|
||||
if (position_adjusted_by_scroll_offset.x() < fragment_absolute_rect.left()) {
|
||||
HitTestResult hit_test_result {
|
||||
.paintable = const_cast<Paintable&>(fragment.paintable()),
|
||||
.index_in_node = fragment.start(),
|
||||
.vertical_distance = 0,
|
||||
.horizontal_distance = fragment_absolute_rect.left() - position_adjusted_by_scroll_offset.x(),
|
||||
};
|
||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
} else if (position_adjusted_by_scroll_offset.x() > fragment_absolute_rect.right()) {
|
||||
HitTestResult hit_test_result {
|
||||
.paintable = const_cast<Paintable&>(fragment.paintable()),
|
||||
.index_in_node = fragment.start() + fragment.length(),
|
||||
.vertical_distance = 0,
|
||||
.horizontal_distance = position_adjusted_by_scroll_offset.x() - fragment_absolute_rect.right(),
|
||||
};
|
||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool should_exit = false;
|
||||
for_each_child([&](Paintable const& child) {
|
||||
if (child.stacking_context())
|
||||
return IterationDecision::Continue;
|
||||
if (child.hit_test(position, type, callback) == TraversalDecision::Break) {
|
||||
should_exit = true;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
if (should_exit)
|
||||
return TraversalDecision::Break;
|
||||
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
CSSPixelRect InlinePaintable::bounding_rect() const
|
||||
{
|
||||
CSSPixelRect bounding_rect;
|
||||
for_each_fragment([&](auto const& fragment, bool, bool) {
|
||||
auto fragment_absolute_rect = fragment.absolute_rect();
|
||||
bounding_rect = bounding_rect.united(fragment_absolute_rect);
|
||||
});
|
||||
|
||||
if (bounding_rect.is_empty()) {
|
||||
// FIXME: This is adhoc, and we should return rect of empty fragment instead.
|
||||
auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position();
|
||||
return { containing_block_position_in_absolute_coordinates, { 0, 0 } };
|
||||
}
|
||||
return bounding_rect;
|
||||
}
|
||||
|
||||
void InlinePaintable::resolve_paint_properties()
|
||||
{
|
||||
auto const& computed_values = this->computed_values();
|
||||
auto const& layout_node = this->layout_node();
|
||||
auto& fragments = this->fragments();
|
||||
|
||||
// Border radii and background layers
|
||||
auto const& top_left_border_radius = computed_values.border_top_left_radius();
|
||||
auto const& top_right_border_radius = computed_values.border_top_right_radius();
|
||||
auto const& bottom_right_border_radius = computed_values.border_bottom_right_radius();
|
||||
auto const& bottom_left_border_radius = computed_values.border_bottom_left_radius();
|
||||
auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position();
|
||||
for (size_t i = 0; i < fragments.size(); ++i) {
|
||||
auto is_first_fragment = i == 0;
|
||||
auto is_last_fragment = i == fragments.size() - 1;
|
||||
auto& fragment = fragments[i];
|
||||
CSSPixelRect absolute_fragment_rect {
|
||||
containing_block_position_in_absolute_coordinates.translated(fragment.offset()),
|
||||
fragment.size()
|
||||
};
|
||||
if (is_first_fragment) {
|
||||
auto extra_start_width = box_model().padding.left;
|
||||
absolute_fragment_rect.translate_by(-extra_start_width, 0);
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_start_width);
|
||||
}
|
||||
if (is_last_fragment) {
|
||||
auto extra_end_width = box_model().padding.right;
|
||||
absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width);
|
||||
}
|
||||
auto border_radii_data = normalize_border_radii_data(layout_node,
|
||||
absolute_fragment_rect, top_left_border_radius,
|
||||
top_right_border_radius,
|
||||
bottom_right_border_radius,
|
||||
bottom_left_border_radius);
|
||||
fragment.set_border_radii_data(border_radii_data);
|
||||
|
||||
absolute_fragment_rect.translate_by(0, -box_model().padding.top);
|
||||
absolute_fragment_rect.set_height(absolute_fragment_rect.height() + box_model().padding.top + box_model().padding.bottom);
|
||||
|
||||
auto resolved_background = resolve_background_layers(computed_values.background_layers(), layout_node, computed_values.background_color(), absolute_fragment_rect, border_radii_data);
|
||||
fragment.set_resolved_background(move(resolved_background));
|
||||
}
|
||||
|
||||
auto const& box_shadow_data = computed_values.box_shadow();
|
||||
Vector<Painting::ShadowData> resolved_box_shadow_data;
|
||||
resolved_box_shadow_data.ensure_capacity(box_shadow_data.size());
|
||||
for (auto const& layer : box_shadow_data) {
|
||||
resolved_box_shadow_data.empend(
|
||||
layer.color,
|
||||
layer.offset_x.to_px(layout_node),
|
||||
layer.offset_y.to_px(layout_node),
|
||||
layer.blur_radius.to_px(layout_node),
|
||||
layer.spread_distance.to_px(layout_node),
|
||||
layer.placement == CSS::ShadowPlacement::Outer ? Painting::ShadowPlacement::Outer
|
||||
: Painting::ShadowPlacement::Inner);
|
||||
}
|
||||
set_box_shadow_data(move(resolved_box_shadow_data));
|
||||
|
||||
for (auto const& fragment : fragments) {
|
||||
auto const& text_shadow = fragment.m_layout_node->computed_values().text_shadow();
|
||||
if (!text_shadow.is_empty()) {
|
||||
Vector<Painting::ShadowData> resolved_shadow_data;
|
||||
resolved_shadow_data.ensure_capacity(text_shadow.size());
|
||||
for (auto const& layer : text_shadow) {
|
||||
resolved_shadow_data.empend(
|
||||
layer.color,
|
||||
layer.offset_x.to_px(layout_node),
|
||||
layer.offset_y.to_px(layout_node),
|
||||
layer.blur_radius.to_px(layout_node),
|
||||
layer.spread_distance.to_px(layout_node),
|
||||
Painting::ShadowPlacement::Outer);
|
||||
}
|
||||
const_cast<Painting::PaintableFragment&>(fragment).set_shadows(move(resolved_shadow_data));
|
||||
}
|
||||
}
|
||||
|
||||
// Outlines
|
||||
auto outline_width = computed_values.outline_width().to_px(layout_node);
|
||||
auto outline_data = borders_data_for_outline(layout_node, computed_values.outline_color(), computed_values.outline_style(), outline_width);
|
||||
auto outline_offset = computed_values.outline_offset().to_px(layout_node);
|
||||
set_outline_data(outline_data);
|
||||
set_outline_offset(outline_offset);
|
||||
|
||||
auto combined_transform = compute_combined_css_transform();
|
||||
set_combined_css_transform(combined_transform);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Painting/BackgroundPainting.h>
|
||||
#include <LibWeb/Painting/ClippableAndScrollable.h>
|
||||
#include <LibWeb/Painting/Paintable.h>
|
||||
#include <LibWeb/Painting/PaintableFragment.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
class InlinePaintable final : public Paintable
|
||||
, public ClippableAndScrollable {
|
||||
JS_CELL(InlinePaintable, Paintable);
|
||||
JS_DECLARE_ALLOCATOR(InlinePaintable);
|
||||
|
||||
public:
|
||||
static JS::NonnullGCPtr<InlinePaintable> create(Layout::InlineNode const&);
|
||||
|
||||
virtual void paint(PaintContext&, PaintPhase) const override;
|
||||
|
||||
virtual void before_paint(PaintContext& context, PaintPhase) const override;
|
||||
virtual void after_paint(PaintContext& context, PaintPhase) const override;
|
||||
|
||||
Layout::InlineNode const& layout_node() const;
|
||||
auto const& box_model() const { return layout_node().box_model(); }
|
||||
|
||||
CSSPixelRect bounding_rect() const;
|
||||
Vector<PaintableFragment> const& fragments() const { return m_fragments; }
|
||||
Vector<PaintableFragment>& fragments() { return m_fragments; }
|
||||
|
||||
virtual bool is_inline_paintable() const override { return true; }
|
||||
|
||||
virtual TraversalDecision hit_test(CSSPixelPoint, HitTestType, Function<TraversalDecision(HitTestResult)> const& callback) const override;
|
||||
|
||||
void set_box_shadow_data(Vector<ShadowData>&& box_shadow_data) { m_box_shadow_data = move(box_shadow_data); }
|
||||
Vector<ShadowData> const& box_shadow_data() const { return m_box_shadow_data; }
|
||||
|
||||
void set_outline_data(Optional<BordersData> outline_data) { m_outline_data = outline_data; }
|
||||
Optional<BordersData> const& outline_data() const { return m_outline_data; }
|
||||
|
||||
void set_outline_offset(CSSPixels outline_offset) { m_outline_offset = outline_offset; }
|
||||
CSSPixels outline_offset() const { return m_outline_offset; }
|
||||
|
||||
virtual void resolve_paint_properties() override;
|
||||
|
||||
private:
|
||||
InlinePaintable(Layout::InlineNode const&);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_fragment(Callback) const;
|
||||
|
||||
Vector<ShadowData> m_box_shadow_data;
|
||||
Optional<BordersData> m_outline_data;
|
||||
CSSPixels m_outline_offset { 0 };
|
||||
Vector<PaintableFragment> m_fragments;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool Paintable::fast_is<InlinePaintable>() const { return is_inline_paintable(); }
|
||||
|
||||
}
|
|
@ -158,13 +158,6 @@ void Paintable::set_needs_display(InvalidateDisplayList should_invalidate_displa
|
|||
if (!containing_block)
|
||||
return;
|
||||
|
||||
if (is<Painting::InlinePaintable>(*this)) {
|
||||
auto const& fragments = static_cast<Painting::InlinePaintable const*>(this)->fragments();
|
||||
for (auto const& fragment : fragments) {
|
||||
document.set_needs_display(fragment.absolute_rect(), InvalidateDisplayList::No);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is<Painting::PaintableWithLines>(*containing_block))
|
||||
return;
|
||||
static_cast<Painting::PaintableWithLines const&>(*containing_block).for_each_fragment([&](auto& fragment) {
|
||||
|
@ -179,12 +172,6 @@ CSSPixelPoint Paintable::box_type_agnostic_position() const
|
|||
return static_cast<PaintableBox const*>(this)->absolute_position();
|
||||
|
||||
VERIFY(is_inline());
|
||||
if (is_inline_paintable()) {
|
||||
auto const& inline_paintable = static_cast<Painting::InlinePaintable const&>(*this);
|
||||
if (!inline_paintable.fragments().is_empty())
|
||||
return inline_paintable.fragments().first().absolute_rect().location();
|
||||
return inline_paintable.bounding_rect().location();
|
||||
}
|
||||
|
||||
CSSPixelPoint position;
|
||||
if (auto const* block = containing_block(); block && is<Painting::PaintableWithLines>(*block)) {
|
||||
|
|
|
@ -210,7 +210,6 @@ public:
|
|||
|
||||
[[nodiscard]] virtual bool is_paintable_box() const { return false; }
|
||||
[[nodiscard]] virtual bool is_paintable_with_lines() const { return false; }
|
||||
[[nodiscard]] virtual bool is_inline_paintable() const { return false; }
|
||||
[[nodiscard]] virtual bool is_svg_paintable() const { return false; }
|
||||
[[nodiscard]] virtual bool is_text_paintable() const { return false; }
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <LibWeb/HTML/HTMLHtmlElement.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Layout/BlockContainer.h>
|
||||
#include <LibWeb/Layout/InlineNode.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Painting/BackgroundPainting.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
|
|
|
@ -298,8 +298,6 @@ void StackingContext::paint(PaintContext& context) const
|
|||
Gfx::IntRect source_paintable_rect;
|
||||
if (paintable().is_paintable_box()) {
|
||||
source_paintable_rect = context.enclosing_device_rect(paintable_box().absolute_paint_rect()).to_type<int>();
|
||||
} else if (paintable().is_inline()) {
|
||||
source_paintable_rect = context.enclosing_device_rect(inline_paintable().bounding_rect()).to_type<int>();
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
@ -445,9 +443,6 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType
|
|||
if (is<PaintableBox>(paintable())) {
|
||||
auto const& paintable_box = static_cast<PaintableBox const&>(paintable());
|
||||
enclosing_scroll_offset = paintable_box.cumulative_offset_of_enclosing_scroll_frame();
|
||||
} else if (is<InlinePaintable>(paintable())) {
|
||||
auto const& inline_paintable = static_cast<InlinePaintable const&>(paintable());
|
||||
enclosing_scroll_offset = inline_paintable.cumulative_offset_of_enclosing_scroll_frame();
|
||||
}
|
||||
|
||||
auto position_adjusted_by_scroll_offset = transformed_position;
|
||||
|
@ -473,8 +468,6 @@ void StackingContext::dump(int indent) const
|
|||
CSSPixelRect rect;
|
||||
if (paintable().is_paintable_box()) {
|
||||
rect = paintable_box().absolute_rect();
|
||||
} else if (paintable().is_inline_paintable()) {
|
||||
rect = inline_paintable().bounding_rect();
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/Matrix4x4.h>
|
||||
#include <LibWeb/Painting/InlinePaintable.h>
|
||||
#include <LibWeb/Painting/Paintable.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
@ -24,7 +23,6 @@ public:
|
|||
|
||||
Paintable const& paintable() const { return *m_paintable; }
|
||||
PaintableBox const& paintable_box() const { return verify_cast<PaintableBox>(*m_paintable); }
|
||||
InlinePaintable const& inline_paintable() const { return verify_cast<InlinePaintable>(*m_paintable); }
|
||||
|
||||
enum class StackingContextPaintPhase {
|
||||
BackgroundAndBorders,
|
||||
|
|
|
@ -108,9 +108,6 @@ void ViewportPaintable::assign_scroll_frames()
|
|||
if (paintable.is_paintable_box()) {
|
||||
auto const& paintable_box = static_cast<PaintableBox const&>(paintable);
|
||||
const_cast<PaintableBox&>(paintable_box).set_enclosing_scroll_frame(*scroll_frame);
|
||||
} else if (paintable.is_inline_paintable()) {
|
||||
auto const& inline_paintable = static_cast<InlinePaintable const&>(paintable);
|
||||
const_cast<InlinePaintable&>(inline_paintable).set_enclosing_scroll_frame(*scroll_frame);
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
@ -141,9 +138,6 @@ void ViewportPaintable::assign_clip_frames()
|
|||
if (paintable.is_paintable_box()) {
|
||||
auto const& paintable_box = static_cast<PaintableBox const&>(paintable);
|
||||
const_cast<PaintableBox&>(paintable_box).set_enclosing_clip_frame(clip_frame.value());
|
||||
} else if (paintable.is_inline_paintable()) {
|
||||
auto const& inline_paintable = static_cast<InlinePaintable const&>(paintable);
|
||||
const_cast<InlinePaintable&>(inline_paintable).set_enclosing_clip_frame(clip_frame.value());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue