2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2018-2023, Andreas Kling <andreas@ladybird.org>
|
2021-02-21 13:45:26 +02:00
|
|
|
* Copyright (c) 2021, the SerenityOS developers.
|
LibWeb/CSS: Merge style declaration subclasses into CSSStyleProperties
We previously had PropertyOwningCSSStyleDeclaration and
ResolvedCSSStyleDeclaration, representing the current style properties
and resolved style respectively. Both of these were the
CSSStyleDeclaration type in the CSSOM. (We also had
ElementInlineCSSStyleDeclaration but I removed that in a previous
commit.)
In the meantime, the spec has changed so that these should now be a new
CSSStyleProperties type in the CSSOM. Also, we need to subclass
CSSStyleDeclaration for things like CSSFontFaceRule's list of
descriptors, which means it wouldn't hold style properties.
So, this commit does the fairly messy work of combining these two types
into a new CSSStyleProperties class. A lot of what previously was done
as separate methods in the two classes, now follows the spec steps of
"if the readonly flag is set, do X" instead, which is hopefully easier
to follow too.
There is still some functionality in CSSStyleDeclaration that belongs in
CSSStyleProperties, but I'll do that next. To avoid a huge diff for
"CSSStyleDeclaration-all-supported-properties-and-default-values.txt"
both here and in the following commit, we don't apply the (currently
empty) CSSStyleProperties prototype yet.
2025-03-17 17:50:49 +00:00
|
|
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
|
2020-06-14 18:47:21 +02:00
|
|
|
#include <AK/QuickSort.h>
|
2020-05-23 21:05:26 +02:00
|
|
|
#include <AK/StringBuilder.h>
|
2019-10-03 15:20:13 +02:00
|
|
|
#include <AK/Utf8View.h>
|
2025-05-08 14:37:25 +01:00
|
|
|
#include <LibWeb/CSS/CSSDescriptors.h>
|
2022-03-28 20:30:26 +01:00
|
|
|
#include <LibWeb/CSS/CSSFontFaceRule.h>
|
2021-02-21 18:36:34 +02:00
|
|
|
#include <LibWeb/CSS/CSSImportRule.h>
|
2025-05-08 12:11:52 +01:00
|
|
|
#include <LibWeb/CSS/CSSKeyframeRule.h>
|
|
|
|
|
#include <LibWeb/CSS/CSSKeyframesRule.h>
|
2024-09-02 16:45:25 +01:00
|
|
|
#include <LibWeb/CSS/CSSLayerBlockRule.h>
|
|
|
|
|
#include <LibWeb/CSS/CSSLayerStatementRule.h>
|
2025-05-15 11:48:56 +01:00
|
|
|
#include <LibWeb/CSS/CSSMarginRule.h>
|
2021-09-29 12:48:04 +01:00
|
|
|
#include <LibWeb/CSS/CSSMediaRule.h>
|
2025-05-08 14:37:25 +01:00
|
|
|
#include <LibWeb/CSS/CSSNamespaceRule.h>
|
2024-10-15 15:59:31 +01:00
|
|
|
#include <LibWeb/CSS/CSSNestedDeclarations.h>
|
2025-05-13 12:17:41 +01:00
|
|
|
#include <LibWeb/CSS/CSSPageRule.h>
|
2024-10-17 23:28:09 +01:00
|
|
|
#include <LibWeb/CSS/CSSPropertyRule.h>
|
2021-02-21 13:45:26 +02:00
|
|
|
#include <LibWeb/CSS/CSSRule.h>
|
LibWeb/CSS: Merge style declaration subclasses into CSSStyleProperties
We previously had PropertyOwningCSSStyleDeclaration and
ResolvedCSSStyleDeclaration, representing the current style properties
and resolved style respectively. Both of these were the
CSSStyleDeclaration type in the CSSOM. (We also had
ElementInlineCSSStyleDeclaration but I removed that in a previous
commit.)
In the meantime, the spec has changed so that these should now be a new
CSSStyleProperties type in the CSSOM. Also, we need to subclass
CSSStyleDeclaration for things like CSSFontFaceRule's list of
descriptors, which means it wouldn't hold style properties.
So, this commit does the fairly messy work of combining these two types
into a new CSSStyleProperties class. A lot of what previously was done
as separate methods in the two classes, now follows the spec steps of
"if the readonly flag is set, do X" instead, which is hopefully easier
to follow too.
There is still some functionality in CSSStyleDeclaration that belongs in
CSSStyleProperties, but I'll do that next. To avoid a huge diff for
"CSSStyleDeclaration-all-supported-properties-and-default-values.txt"
both here and in the following commit, we don't apply the (currently
empty) CSSStyleProperties prototype yet.
2025-03-17 17:50:49 +00:00
|
|
|
#include <LibWeb/CSS/CSSStyleProperties.h>
|
2021-03-07 15:00:02 +01:00
|
|
|
#include <LibWeb/CSS/CSSStyleRule.h>
|
2021-03-07 16:14:04 +01:00
|
|
|
#include <LibWeb/CSS/CSSStyleSheet.h>
|
2021-10-08 17:48:14 +01:00
|
|
|
#include <LibWeb/CSS/CSSSupportsRule.h>
|
2025-02-18 09:19:56 +01:00
|
|
|
#include <LibWeb/CSS/ComputedProperties.h>
|
2020-03-07 10:32:51 +01:00
|
|
|
#include <LibWeb/CSS/PropertyID.h>
|
2023-08-11 21:26:04 +01:00
|
|
|
#include <LibWeb/CSS/PseudoClass.h>
|
2020-03-07 10:32:51 +01:00
|
|
|
#include <LibWeb/DOM/Document.h>
|
|
|
|
|
#include <LibWeb/DOM/Element.h>
|
2021-02-10 18:25:05 +01:00
|
|
|
#include <LibWeb/DOM/ShadowRoot.h>
|
2020-03-07 10:32:51 +01:00
|
|
|
#include <LibWeb/DOM/Text.h>
|
|
|
|
|
#include <LibWeb/Dump.h>
|
2023-08-14 20:19:41 +02:00
|
|
|
#include <LibWeb/HTML/DocumentState.h>
|
2023-05-21 07:02:41 +02:00
|
|
|
#include <LibWeb/HTML/HTMLImageElement.h>
|
2020-08-19 22:30:33 +01:00
|
|
|
#include <LibWeb/HTML/HTMLTemplateElement.h>
|
2023-05-21 07:02:41 +02:00
|
|
|
#include <LibWeb/HTML/ImageRequest.h>
|
2023-08-14 20:19:41 +02:00
|
|
|
#include <LibWeb/HTML/TraversableNavigable.h>
|
2021-10-06 20:02:41 +02:00
|
|
|
#include <LibWeb/Layout/BlockContainer.h>
|
2023-05-03 10:32:23 +02:00
|
|
|
#include <LibWeb/Layout/FormattingContext.h>
|
2024-01-13 13:11:31 +01:00
|
|
|
#include <LibWeb/Layout/InlineNode.h>
|
2024-11-26 12:00:15 +01:00
|
|
|
#include <LibWeb/Layout/NavigableContainerViewport.h>
|
2020-11-22 15:53:01 +01:00
|
|
|
#include <LibWeb/Layout/Node.h>
|
2021-09-17 23:03:36 +02:00
|
|
|
#include <LibWeb/Layout/SVGBox.h>
|
2020-11-22 15:53:01 +01:00
|
|
|
#include <LibWeb/Layout/TextNode.h>
|
2023-05-21 07:02:41 +02:00
|
|
|
#include <LibWeb/Layout/Viewport.h>
|
2025-07-18 10:03:08 +02:00
|
|
|
#include <LibWeb/Namespace.h>
|
2022-03-10 23:13:37 +01:00
|
|
|
#include <LibWeb/Painting/PaintableBox.h>
|
2023-03-18 20:22:58 +01:00
|
|
|
#include <LibWeb/Painting/TextPaintable.h>
|
2023-05-21 07:02:41 +02:00
|
|
|
#include <LibWeb/SVG/SVGDecodedImageData.h>
|
2019-06-15 18:55:47 +02:00
|
|
|
|
2020-03-07 10:27:02 +01:00
|
|
|
namespace Web {
|
|
|
|
|
|
2024-10-15 11:35:01 +01:00
|
|
|
static void dump_session_history_entry(StringBuilder& builder, HTML::SessionHistoryEntry const& session_history_entry, int indent_levels)
|
2023-08-14 20:19:41 +02:00
|
|
|
{
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2024-03-27 16:14:52 +01:00
|
|
|
auto const& document = session_history_entry.document();
|
2024-10-15 11:35:01 +01:00
|
|
|
builder.appendff("step=({}) url=({}) is-active=({})\n", session_history_entry.step().get<int>(), session_history_entry.url(), document && document->is_active());
|
2024-03-27 15:59:12 +01:00
|
|
|
for (auto const& nested_history : session_history_entry.document_state()->nested_histories()) {
|
2023-08-14 20:19:41 +02:00
|
|
|
for (auto const& nested_she : nested_history.entries) {
|
2024-10-15 11:35:01 +01:00
|
|
|
dump_session_history_entry(builder, *nested_she, indent_levels + 1);
|
2023-08-14 20:19:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dump_tree(HTML::TraversableNavigable& traversable)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder builder;
|
|
|
|
|
for (auto const& she : traversable.session_history_entries()) {
|
2024-10-15 11:35:01 +01:00
|
|
|
dump_session_history_entry(builder, *she, 0);
|
2023-08-14 20:19:41 +02:00
|
|
|
}
|
|
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 14:13:29 +01:00
|
|
|
void dump_tree(DOM::Node const& node)
|
2021-02-17 15:59:13 +01:00
|
|
|
{
|
|
|
|
|
StringBuilder builder;
|
|
|
|
|
dump_tree(builder, node);
|
|
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 14:13:29 +01:00
|
|
|
void dump_tree(StringBuilder& builder, DOM::Node const& node)
|
2019-06-15 18:55:47 +02:00
|
|
|
{
|
|
|
|
|
static int indent = 0;
|
|
|
|
|
for (int i = 0; i < indent; ++i)
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(" "sv);
|
2025-07-18 10:03:08 +02:00
|
|
|
if (auto const* element = as_if<DOM::Element>(node)) {
|
2025-07-18 10:07:03 +02:00
|
|
|
auto namespace_prefix = [&] -> FlyString {
|
2025-07-18 10:03:08 +02:00
|
|
|
auto const& namespace_uri = element->namespace_uri();
|
2025-07-18 10:07:03 +02:00
|
|
|
if (!namespace_uri.has_value() || node.document().is_default_namespace(namespace_uri.value().to_string()))
|
|
|
|
|
return ""_fly_string;
|
2025-07-18 10:03:08 +02:00
|
|
|
if (namespace_uri == Namespace::HTML)
|
2025-07-18 10:07:03 +02:00
|
|
|
return "html:"_fly_string;
|
2025-07-18 10:03:08 +02:00
|
|
|
if (namespace_uri == Namespace::SVG)
|
2025-07-18 10:07:03 +02:00
|
|
|
return "svg:"_fly_string;
|
2025-07-18 10:03:08 +02:00
|
|
|
if (namespace_uri == Namespace::MathML)
|
2025-07-18 10:07:03 +02:00
|
|
|
return "mathml:"_fly_string;
|
2025-07-06 17:28:27 +02:00
|
|
|
return *namespace_uri;
|
|
|
|
|
}();
|
|
|
|
|
|
2025-07-18 10:07:03 +02:00
|
|
|
builder.appendff("<{}{}", namespace_prefix, element->local_name());
|
2025-07-18 10:03:08 +02:00
|
|
|
element->for_each_attribute([&](auto& name, auto& value) {
|
2021-02-17 15:59:13 +01:00
|
|
|
builder.appendff(" {}={}", name, value);
|
2019-06-15 21:08:36 +02:00
|
|
|
});
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(">\n"sv);
|
2025-07-18 10:03:08 +02:00
|
|
|
if (element->use_pseudo_element().has_value()) {
|
2024-08-20 14:37:05 +02:00
|
|
|
for (int i = 0; i < indent; ++i)
|
|
|
|
|
builder.append(" "sv);
|
2025-07-18 10:03:08 +02:00
|
|
|
builder.appendff(" (pseudo-element: {})\n", CSS::pseudo_element_name(element->use_pseudo_element().value()));
|
2024-08-20 14:37:05 +02:00
|
|
|
}
|
2025-07-18 10:03:08 +02:00
|
|
|
} else if (auto const* text = as_if<DOM::Text>(node)) {
|
|
|
|
|
builder.appendff("\"{}\"\n", text->data());
|
2021-02-10 17:13:08 +01:00
|
|
|
} else {
|
2021-02-17 15:59:13 +01:00
|
|
|
builder.appendff("{}\n", node.node_name());
|
2019-06-15 18:55:47 +02:00
|
|
|
}
|
|
|
|
|
++indent;
|
2025-07-18 10:03:08 +02:00
|
|
|
if (auto const* element = as_if<DOM::Element>(node); element && element->shadow_root())
|
|
|
|
|
dump_tree(builder, *element->shadow_root());
|
|
|
|
|
if (auto const* image = as_if<HTML::HTMLImageElement>(node)) {
|
|
|
|
|
if (auto const* svg_data = as_if<SVG::SVGDecodedImageData>(image->current_request().image_data().ptr())) {
|
|
|
|
|
++indent;
|
|
|
|
|
for (int i = 0; i < indent; ++i)
|
|
|
|
|
builder.append(" "sv);
|
|
|
|
|
builder.append("(SVG-as-image isolated context)\n"sv);
|
|
|
|
|
dump_tree(builder, svg_data->svg_document());
|
|
|
|
|
--indent;
|
2023-05-21 07:02:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-07-18 10:03:08 +02:00
|
|
|
if (auto const* template_element = as_if<HTML::HTMLTemplateElement>(node)) {
|
2025-04-25 09:35:30 +02:00
|
|
|
for (int i = 0; i < indent; ++i)
|
|
|
|
|
builder.append(" "sv);
|
|
|
|
|
builder.append("(template content)\n"sv);
|
2025-07-18 10:03:08 +02:00
|
|
|
dump_tree(builder, template_element->content());
|
2025-04-25 09:35:30 +02:00
|
|
|
builder.append("(template normal subtree)\n"sv);
|
|
|
|
|
}
|
2025-07-18 10:03:08 +02:00
|
|
|
if (auto const* parent_node = as_if<DOM::ParentNode>(node)) {
|
|
|
|
|
parent_node->for_each_child([&](auto const& child) {
|
2025-04-25 09:35:30 +02:00
|
|
|
dump_tree(builder, child);
|
|
|
|
|
return IterationDecision::Continue;
|
|
|
|
|
});
|
2019-06-15 18:55:47 +02:00
|
|
|
}
|
|
|
|
|
--indent;
|
|
|
|
|
}
|
2019-06-15 22:49:44 +02:00
|
|
|
|
2025-08-27 11:25:04 +02:00
|
|
|
void dump_tree(Layout::Node const& layout_node, bool show_cascaded_properties)
|
2020-12-08 22:11:02 +01:00
|
|
|
{
|
|
|
|
|
StringBuilder builder;
|
2025-08-27 11:25:04 +02:00
|
|
|
dump_tree(builder, layout_node, show_cascaded_properties, true);
|
2021-02-17 15:59:13 +01:00
|
|
|
dbgln("{}", builder.string_view());
|
2020-12-08 22:11:02 +01:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 11:25:04 +02:00
|
|
|
void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool show_cascaded_properties, bool interactive)
|
2019-06-15 22:49:44 +02:00
|
|
|
{
|
2020-02-25 14:49:47 +01:00
|
|
|
static size_t indent = 0;
|
2025-08-27 11:27:12 +02:00
|
|
|
builder.append_repeated(" "sv, indent);
|
2019-06-16 11:28:47 +02:00
|
|
|
|
2023-10-08 12:42:48 +13:00
|
|
|
FlyString tag_name;
|
2019-06-16 11:28:47 +02:00
|
|
|
if (layout_node.is_anonymous())
|
2023-10-08 12:42:48 +13:00
|
|
|
tag_name = "(anonymous)"_fly_string;
|
2020-11-22 14:46:36 +01:00
|
|
|
else if (is<DOM::Element>(layout_node.dom_node()))
|
2025-01-21 09:12:05 -05:00
|
|
|
tag_name = as<DOM::Element>(*layout_node.dom_node()).local_name();
|
2019-06-16 11:28:47 +02:00
|
|
|
else
|
2023-10-08 12:42:48 +13:00
|
|
|
tag_name = layout_node.dom_node()->node_name();
|
2019-06-16 11:28:47 +02:00
|
|
|
|
2023-11-20 23:17:14 +13:00
|
|
|
String identifier;
|
2020-11-22 14:46:36 +01:00
|
|
|
if (layout_node.dom_node() && is<DOM::Element>(*layout_node.dom_node())) {
|
2025-01-21 09:12:05 -05:00
|
|
|
auto& element = as<DOM::Element>(*layout_node.dom_node());
|
2025-08-27 11:28:04 +02:00
|
|
|
StringBuilder identifier_builder;
|
2024-01-13 20:12:25 +13:00
|
|
|
if (element.id().has_value() && !element.id()->is_empty()) {
|
2025-08-27 11:28:04 +02:00
|
|
|
identifier_builder.append('#');
|
|
|
|
|
identifier_builder.append(*element.id());
|
2020-05-23 21:05:26 +02:00
|
|
|
}
|
2020-06-12 13:23:07 +02:00
|
|
|
for (auto& class_name : element.class_names()) {
|
2025-08-27 11:28:04 +02:00
|
|
|
identifier_builder.append('.');
|
|
|
|
|
identifier_builder.append(class_name);
|
2020-06-12 13:23:07 +02:00
|
|
|
}
|
2025-08-27 11:28:04 +02:00
|
|
|
identifier = MUST(identifier_builder.to_string());
|
2020-05-23 21:05:26 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-11 17:32:29 +00:00
|
|
|
StringView nonbox_color_on = ""sv;
|
|
|
|
|
StringView box_color_on = ""sv;
|
|
|
|
|
StringView svg_box_color_on = ""sv;
|
|
|
|
|
StringView positioned_color_on = ""sv;
|
|
|
|
|
StringView floating_color_on = ""sv;
|
2023-01-16 13:51:49 +01:00
|
|
|
StringView inline_color_on = ""sv;
|
2022-07-11 17:32:29 +00:00
|
|
|
StringView fragment_color_on = ""sv;
|
|
|
|
|
StringView flex_color_on = ""sv;
|
2023-05-29 17:40:58 +03:00
|
|
|
StringView table_color_on = ""sv;
|
2023-05-03 10:32:23 +02:00
|
|
|
StringView formatting_context_color_on = ""sv;
|
2022-07-11 17:32:29 +00:00
|
|
|
StringView color_off = ""sv;
|
2020-12-08 22:11:02 +01:00
|
|
|
|
|
|
|
|
if (interactive) {
|
2022-07-11 17:32:29 +00:00
|
|
|
nonbox_color_on = "\033[33m"sv;
|
|
|
|
|
box_color_on = "\033[34m"sv;
|
|
|
|
|
svg_box_color_on = "\033[31m"sv;
|
|
|
|
|
positioned_color_on = "\033[31;1m"sv;
|
|
|
|
|
floating_color_on = "\033[32;1m"sv;
|
2023-01-16 13:51:49 +01:00
|
|
|
inline_color_on = "\033[36;1m"sv;
|
2022-07-11 17:32:29 +00:00
|
|
|
fragment_color_on = "\033[35;1m"sv;
|
|
|
|
|
flex_color_on = "\033[34;1m"sv;
|
2023-05-29 17:40:58 +03:00
|
|
|
table_color_on = "\033[91;1m"sv;
|
2023-05-03 10:32:23 +02:00
|
|
|
formatting_context_color_on = "\033[37;1m"sv;
|
2022-07-11 17:32:29 +00:00
|
|
|
color_off = "\033[0m"sv;
|
2020-12-08 22:11:02 +01:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 11:32:19 +02:00
|
|
|
auto dump_position = [&] {
|
|
|
|
|
if (auto* paintable_box = as_if<Painting::PaintableBox>(layout_node.first_paintable()))
|
|
|
|
|
builder.appendff("at {}", paintable_box->absolute_rect().location());
|
|
|
|
|
else
|
|
|
|
|
builder.appendff("(not painted)");
|
|
|
|
|
};
|
2025-02-17 13:54:36 +01:00
|
|
|
auto dump_box_model = [&] {
|
2025-08-27 11:32:19 +02:00
|
|
|
if (auto const* paintable_box = as_if<Painting::PaintableBox>(layout_node.first_paintable())) {
|
|
|
|
|
auto const& box_model = paintable_box->box_model();
|
2025-02-17 13:54:36 +01:00
|
|
|
// Dump the horizontal box properties
|
|
|
|
|
builder.appendff(" [{}+{}+{} {} {}+{}+{}]",
|
|
|
|
|
box_model.margin.left,
|
|
|
|
|
box_model.border.left,
|
|
|
|
|
box_model.padding.left,
|
2025-08-27 11:32:19 +02:00
|
|
|
paintable_box->content_width(),
|
2025-02-17 13:54:36 +01:00
|
|
|
box_model.padding.right,
|
|
|
|
|
box_model.border.right,
|
|
|
|
|
box_model.margin.right);
|
|
|
|
|
|
|
|
|
|
// And the vertical box properties
|
|
|
|
|
builder.appendff(" [{}+{}+{} {} {}+{}+{}]",
|
|
|
|
|
box_model.margin.top,
|
|
|
|
|
box_model.border.top,
|
|
|
|
|
box_model.padding.top,
|
2025-08-27 11:32:19 +02:00
|
|
|
paintable_box->content_height(),
|
2025-02-17 13:54:36 +01:00
|
|
|
box_model.padding.bottom,
|
|
|
|
|
box_model.border.bottom,
|
|
|
|
|
box_model.margin.bottom);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-01 18:55:47 +01:00
|
|
|
if (!is<Layout::Box>(layout_node)) {
|
2025-08-27 11:32:19 +02:00
|
|
|
builder.appendff("{}{}{} <{}{}{}{}> ",
|
2020-12-08 22:11:02 +01:00
|
|
|
nonbox_color_on,
|
2022-10-20 16:06:26 +02:00
|
|
|
layout_node.class_name(),
|
2020-12-08 22:11:02 +01:00
|
|
|
color_off,
|
|
|
|
|
tag_name,
|
|
|
|
|
nonbox_color_on,
|
|
|
|
|
identifier,
|
|
|
|
|
color_off);
|
2025-02-17 13:54:36 +01:00
|
|
|
|
2025-08-27 11:32:19 +02:00
|
|
|
dump_position();
|
2025-02-17 13:54:36 +01:00
|
|
|
dump_box_model();
|
2019-10-15 16:48:38 +02:00
|
|
|
} else {
|
2025-01-21 09:12:05 -05:00
|
|
|
auto& box = as<Layout::Box>(layout_node);
|
2021-09-17 23:03:36 +02:00
|
|
|
StringView color_on = is<Layout::SVGBox>(box) ? svg_box_color_on : box_color_on;
|
|
|
|
|
|
2020-12-08 22:11:02 +01:00
|
|
|
builder.appendff("{}{}{} <{}{}{}{}> ",
|
2021-09-17 23:03:36 +02:00
|
|
|
color_on,
|
2022-10-20 16:06:26 +02:00
|
|
|
box.class_name(),
|
2020-12-08 22:11:02 +01:00
|
|
|
color_off,
|
2021-09-17 23:03:36 +02:00
|
|
|
color_on,
|
2020-12-08 22:11:02 +01:00
|
|
|
tag_name,
|
|
|
|
|
color_off,
|
2023-11-20 23:17:14 +13:00
|
|
|
identifier);
|
2020-12-08 22:11:02 +01:00
|
|
|
|
2025-08-27 11:32:19 +02:00
|
|
|
dump_position();
|
2020-12-07 19:36:13 +01:00
|
|
|
|
|
|
|
|
if (box.is_positioned())
|
2020-12-08 22:11:02 +01:00
|
|
|
builder.appendff(" {}positioned{}", positioned_color_on, color_off);
|
2020-12-07 19:36:13 +01:00
|
|
|
if (box.is_floating())
|
2020-12-08 22:11:02 +01:00
|
|
|
builder.appendff(" {}floating{}", floating_color_on, color_off);
|
|
|
|
|
if (box.is_inline_block())
|
2023-01-16 13:51:49 +01:00
|
|
|
builder.appendff(" {}inline-block{}", inline_color_on, color_off);
|
|
|
|
|
if (box.is_inline_table())
|
|
|
|
|
builder.appendff(" {}inline-table{}", inline_color_on, color_off);
|
2022-10-06 16:02:53 +02:00
|
|
|
if (box.display().is_flex_inside()) {
|
2021-10-21 00:29:31 +02:00
|
|
|
StringView direction;
|
|
|
|
|
switch (box.computed_values().flex_direction()) {
|
|
|
|
|
case CSS::FlexDirection::Column:
|
|
|
|
|
direction = "column"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::FlexDirection::ColumnReverse:
|
|
|
|
|
direction = "column-reverse"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::FlexDirection::Row:
|
|
|
|
|
direction = "row"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::FlexDirection::RowReverse:
|
|
|
|
|
direction = "row-reverse"sv;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
builder.appendff(" {}flex-container({}){}", flex_color_on, direction, color_off);
|
|
|
|
|
}
|
2021-05-29 22:36:15 +02:00
|
|
|
if (box.is_flex_item())
|
|
|
|
|
builder.appendff(" {}flex-item{}", flex_color_on, color_off);
|
2023-05-29 17:40:58 +03:00
|
|
|
if (box.display().is_table_inside())
|
|
|
|
|
builder.appendff(" {}table-box{}", table_color_on, color_off);
|
|
|
|
|
if (box.display().is_table_row_group())
|
|
|
|
|
builder.appendff(" {}table-row-group{}", table_color_on, color_off);
|
2023-06-04 14:20:19 +00:00
|
|
|
if (box.display().is_table_column_group())
|
|
|
|
|
builder.appendff(" {}table-column-group{}", table_color_on, color_off);
|
2023-05-29 17:40:58 +03:00
|
|
|
if (box.display().is_table_header_group())
|
|
|
|
|
builder.appendff(" {}table-header-group{}", table_color_on, color_off);
|
|
|
|
|
if (box.display().is_table_footer_group())
|
|
|
|
|
builder.appendff(" {}table-footer-group{}", table_color_on, color_off);
|
|
|
|
|
if (box.display().is_table_row())
|
|
|
|
|
builder.appendff(" {}table-row{}", table_color_on, color_off);
|
|
|
|
|
if (box.display().is_table_cell())
|
|
|
|
|
builder.appendff(" {}table-cell{}", table_color_on, color_off);
|
2020-12-07 19:36:13 +01:00
|
|
|
|
2025-02-17 13:54:36 +01:00
|
|
|
dump_box_model();
|
2019-08-18 08:09:56 +02:00
|
|
|
|
2023-05-03 10:32:23 +02:00
|
|
|
if (auto formatting_context_type = Layout::FormattingContext::formatting_context_type_created_by_box(box); formatting_context_type.has_value()) {
|
|
|
|
|
switch (formatting_context_type.value()) {
|
|
|
|
|
case Layout::FormattingContext::Type::Block:
|
|
|
|
|
builder.appendff(" [{}BFC{}]", formatting_context_color_on, color_off);
|
|
|
|
|
break;
|
|
|
|
|
case Layout::FormattingContext::Type::Flex:
|
|
|
|
|
builder.appendff(" [{}FFC{}]", formatting_context_color_on, color_off);
|
|
|
|
|
break;
|
|
|
|
|
case Layout::FormattingContext::Type::Grid:
|
|
|
|
|
builder.appendff(" [{}GFC{}]", formatting_context_color_on, color_off);
|
|
|
|
|
break;
|
|
|
|
|
case Layout::FormattingContext::Type::Table:
|
|
|
|
|
builder.appendff(" [{}TFC{}]", formatting_context_color_on, color_off);
|
|
|
|
|
break;
|
|
|
|
|
case Layout::FormattingContext::Type::SVG:
|
|
|
|
|
builder.appendff(" [{}SVG{}]", formatting_context_color_on, color_off);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-26 00:10:36 +01:00
|
|
|
builder.appendff(" children: {}", box.children_are_inline() ? "inline" : "not-inline");
|
|
|
|
|
|
2024-11-26 12:00:15 +01:00
|
|
|
if (is<Layout::NavigableContainerViewport>(box)) {
|
|
|
|
|
auto const& frame_box = static_cast<Layout::NavigableContainerViewport const&>(box);
|
2024-11-03 17:22:22 +01:00
|
|
|
if (auto const* document = frame_box.dom_node().content_document_without_origin_check()) {
|
|
|
|
|
builder.appendff(" (url: {})", document->url());
|
2025-02-22 14:51:34 +01:00
|
|
|
builder.append("\n"sv);
|
2024-11-26 12:29:41 +01:00
|
|
|
if (auto const* nested_layout_root = document->layout_node()) {
|
|
|
|
|
++indent;
|
2025-08-27 11:25:04 +02:00
|
|
|
dump_tree(builder, *nested_layout_root, show_cascaded_properties, interactive);
|
2024-11-26 12:29:41 +01:00
|
|
|
--indent;
|
|
|
|
|
}
|
2022-08-05 00:16:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-10-15 16:48:38 +02:00
|
|
|
}
|
2019-06-21 20:54:13 +02:00
|
|
|
|
2025-08-27 11:29:46 +02:00
|
|
|
if (auto const* potential_continuation_node = as_if<Layout::NodeWithStyleAndBoxModelMetrics>(layout_node);
|
|
|
|
|
potential_continuation_node && potential_continuation_node->continuation_of_node())
|
2025-01-15 16:37:30 +01:00
|
|
|
builder.append(" continuation"sv);
|
|
|
|
|
|
|
|
|
|
builder.append("\n"sv);
|
|
|
|
|
|
2023-05-21 07:02:41 +02:00
|
|
|
if (layout_node.dom_node() && is<HTML::HTMLImageElement>(*layout_node.dom_node())) {
|
|
|
|
|
if (auto image_data = static_cast<HTML::HTMLImageElement const&>(*layout_node.dom_node()).current_request().image_data()) {
|
|
|
|
|
if (is<SVG::SVGDecodedImageData>(*image_data)) {
|
2025-01-21 09:12:05 -05:00
|
|
|
auto& svg_data = as<SVG::SVGDecodedImageData>(*image_data);
|
2023-05-21 07:02:41 +02:00
|
|
|
if (svg_data.svg_document().layout_node()) {
|
|
|
|
|
++indent;
|
|
|
|
|
for (size_t i = 0; i < indent; ++i)
|
|
|
|
|
builder.append(" "sv);
|
|
|
|
|
builder.append("(SVG-as-image isolated context)\n"sv);
|
|
|
|
|
|
2025-08-27 11:25:04 +02:00
|
|
|
dump_tree(builder, *svg_data.svg_document().layout_node(), show_cascaded_properties, interactive);
|
2023-05-21 07:02:41 +02:00
|
|
|
--indent;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-13 13:11:31 +01:00
|
|
|
auto dump_fragment = [&](auto& fragment, size_t fragment_index) {
|
2025-08-27 11:27:12 +02:00
|
|
|
builder.append_repeated(" "sv, indent);
|
2024-01-13 13:11:31 +01:00
|
|
|
builder.appendff(" {}frag {}{} from {} ",
|
|
|
|
|
fragment_color_on,
|
|
|
|
|
fragment_index,
|
|
|
|
|
color_off,
|
|
|
|
|
fragment.layout_node().class_name());
|
|
|
|
|
builder.appendff("start: {}, length: {}, rect: {} baseline: {}\n",
|
2025-07-25 09:34:41 -04:00
|
|
|
fragment.start_offset(),
|
|
|
|
|
fragment.length_in_code_units(),
|
2024-01-13 13:11:31 +01:00
|
|
|
fragment.absolute_rect(),
|
|
|
|
|
fragment.baseline());
|
2025-09-12 10:06:27 +02:00
|
|
|
if (fragment.length_in_code_units() > 0) {
|
2025-08-27 11:27:12 +02:00
|
|
|
builder.append_repeated(" "sv, indent);
|
2025-09-12 10:06:27 +02:00
|
|
|
builder.appendff(" \"{}\"\n", fragment.text());
|
2024-01-13 13:11:31 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-12 10:06:27 +02:00
|
|
|
if (auto const* block_container = as_if<Layout::BlockContainer>(layout_node);
|
|
|
|
|
block_container && block_container->children_are_inline() && block_container->paintable_with_lines()) {
|
|
|
|
|
size_t fragment_index = 0;
|
|
|
|
|
for (auto const& fragment : block_container->paintable_with_lines()->fragments())
|
|
|
|
|
dump_fragment(fragment, fragment_index++);
|
2024-01-13 13:11:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-16 15:19:32 +02:00
|
|
|
if (is<Layout::InlineNode>(layout_node) && layout_node.first_paintable()) {
|
2024-01-13 13:11:31 +01:00
|
|
|
auto const& inline_node = static_cast<Layout::InlineNode const&>(layout_node);
|
2024-10-13 21:29:47 +02:00
|
|
|
for (auto const& paintable : inline_node.paintables()) {
|
|
|
|
|
auto const& paintable_with_lines = static_cast<Painting::PaintableWithLines const&>(paintable);
|
|
|
|
|
auto const& fragments = paintable_with_lines.fragments();
|
|
|
|
|
for (size_t fragment_index = 0; fragment_index < fragments.size(); ++fragment_index) {
|
|
|
|
|
auto const& fragment = fragments[fragment_index];
|
|
|
|
|
dump_fragment(fragment, fragment_index);
|
|
|
|
|
}
|
2019-10-03 15:20:13 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-21 09:12:05 -05:00
|
|
|
if (show_cascaded_properties && layout_node.dom_node() && layout_node.dom_node()->is_element() && as<DOM::Element>(layout_node.dom_node())->computed_properties()) {
|
2020-12-07 19:36:13 +01:00
|
|
|
struct NameAndValue {
|
2024-03-15 20:32:45 +01:00
|
|
|
FlyString name;
|
2023-11-20 23:17:14 +13:00
|
|
|
String value;
|
2020-12-07 19:36:13 +01:00
|
|
|
};
|
|
|
|
|
Vector<NameAndValue> properties;
|
2025-01-21 09:12:05 -05:00
|
|
|
as<DOM::Element>(*layout_node.dom_node()).computed_properties()->for_each_property([&](auto property_id, auto& value) {
|
2025-05-16 19:20:24 +01:00
|
|
|
properties.append({ CSS::string_from_property_id(property_id), value.to_string(CSS::SerializationMode::Normal) });
|
2020-12-07 19:36:13 +01:00
|
|
|
});
|
|
|
|
|
quick_sort(properties, [](auto& a, auto& b) { return a.name < b.name; });
|
2020-06-14 18:47:21 +02:00
|
|
|
|
2020-12-07 19:36:13 +01:00
|
|
|
for (auto& property : properties) {
|
2025-08-27 11:27:12 +02:00
|
|
|
builder.append_repeated(" "sv, indent);
|
2021-05-07 20:47:25 +02:00
|
|
|
builder.appendff(" ({}: {})\n", property.name, property.value);
|
2020-12-07 19:36:13 +01:00
|
|
|
}
|
2020-06-14 18:47:21 +02:00
|
|
|
}
|
2019-09-21 15:32:17 +03:00
|
|
|
|
2019-06-28 21:17:34 +02:00
|
|
|
++indent;
|
2020-12-08 22:11:02 +01:00
|
|
|
layout_node.for_each_child([&](auto& child) {
|
2025-08-27 11:25:04 +02:00
|
|
|
dump_tree(builder, child, show_cascaded_properties, interactive);
|
2024-05-04 14:59:52 +01:00
|
|
|
return IterationDecision::Continue;
|
2019-06-28 21:17:34 +02:00
|
|
|
});
|
|
|
|
|
--indent;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-12 14:13:29 +01:00
|
|
|
void dump_selector(CSS::Selector const& selector)
|
2019-06-27 20:40:21 +02:00
|
|
|
{
|
2021-02-17 15:59:13 +01:00
|
|
|
StringBuilder builder;
|
|
|
|
|
dump_selector(builder, selector);
|
|
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-08 16:19:20 +01:00
|
|
|
static void dump_qualified_name(StringBuilder& builder, CSS::Selector::SimpleSelector::QualifiedName const& qualified_name)
|
|
|
|
|
{
|
|
|
|
|
StringView namespace_type;
|
|
|
|
|
switch (qualified_name.namespace_type) {
|
|
|
|
|
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Default:
|
|
|
|
|
namespace_type = "Default"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::None:
|
|
|
|
|
namespace_type = "None"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Any:
|
|
|
|
|
namespace_type = "Any"sv;
|
|
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Named:
|
|
|
|
|
namespace_type = "Named"sv;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
builder.appendff("NamespaceType={}, Namespace='{}', Name='{}'", namespace_type, qualified_name.namespace_, qualified_name.name.name);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 15:12:34 +01:00
|
|
|
void dump_selector(StringBuilder& builder, CSS::Selector const& selector, int indent_levels)
|
2021-02-17 15:59:13 +01:00
|
|
|
{
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2024-10-15 15:12:34 +01:00
|
|
|
builder.append("CSS::Selector:\n"sv);
|
2019-11-27 20:37:36 +01:00
|
|
|
|
2021-07-23 15:24:33 +01:00
|
|
|
for (auto& relative_selector : selector.compound_selectors()) {
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels + 1);
|
2020-03-29 22:24:23 +02:00
|
|
|
|
2021-07-12 14:13:29 +01:00
|
|
|
char const* relation_description = "";
|
2021-07-23 15:24:33 +01:00
|
|
|
switch (relative_selector.combinator) {
|
|
|
|
|
case CSS::Selector::Combinator::None:
|
2020-03-29 22:45:38 +02:00
|
|
|
relation_description = "None";
|
2020-03-29 22:24:23 +02:00
|
|
|
break;
|
2021-07-23 15:24:33 +01:00
|
|
|
case CSS::Selector::Combinator::ImmediateChild:
|
2020-03-29 22:24:23 +02:00
|
|
|
relation_description = "ImmediateChild";
|
|
|
|
|
break;
|
2021-07-23 15:24:33 +01:00
|
|
|
case CSS::Selector::Combinator::Descendant:
|
2020-03-29 22:24:23 +02:00
|
|
|
relation_description = "Descendant";
|
|
|
|
|
break;
|
2021-07-23 15:24:33 +01:00
|
|
|
case CSS::Selector::Combinator::NextSibling:
|
2020-03-29 22:24:23 +02:00
|
|
|
relation_description = "AdjacentSibling";
|
|
|
|
|
break;
|
2021-07-23 15:24:33 +01:00
|
|
|
case CSS::Selector::Combinator::SubsequentSibling:
|
2020-03-29 22:24:23 +02:00
|
|
|
relation_description = "GeneralSibling";
|
|
|
|
|
break;
|
2021-07-23 15:24:33 +01:00
|
|
|
case CSS::Selector::Combinator::Column:
|
2021-04-29 21:16:28 +02:00
|
|
|
relation_description = "Column";
|
|
|
|
|
break;
|
2020-03-29 22:24:23 +02:00
|
|
|
}
|
2019-11-27 20:37:36 +01:00
|
|
|
|
2020-03-29 22:24:23 +02:00
|
|
|
if (*relation_description)
|
2021-02-17 15:59:13 +01:00
|
|
|
builder.appendff("{{{}}} ", relation_description);
|
2020-03-29 22:24:23 +02:00
|
|
|
|
2021-07-23 15:24:33 +01:00
|
|
|
for (size_t i = 0; i < relative_selector.simple_selectors.size(); ++i) {
|
|
|
|
|
auto& simple_selector = relative_selector.simple_selectors[i];
|
2021-07-12 14:13:29 +01:00
|
|
|
char const* type_description = "Unknown";
|
2020-03-29 22:24:23 +02:00
|
|
|
switch (simple_selector.type) {
|
2020-07-26 20:01:35 +02:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Universal:
|
2020-03-29 22:24:23 +02:00
|
|
|
type_description = "Universal";
|
2019-10-06 09:28:10 +02:00
|
|
|
break;
|
2020-07-26 20:01:35 +02:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Id:
|
2020-03-29 22:24:23 +02:00
|
|
|
type_description = "Id";
|
2019-10-06 11:05:57 +02:00
|
|
|
break;
|
2020-07-26 20:01:35 +02:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Class:
|
2020-03-29 22:24:23 +02:00
|
|
|
type_description = "Class";
|
2019-10-06 19:59:07 +02:00
|
|
|
break;
|
2020-07-26 20:01:35 +02:00
|
|
|
case CSS::Selector::SimpleSelector::Type::TagName:
|
2020-03-29 22:24:23 +02:00
|
|
|
type_description = "TagName";
|
|
|
|
|
break;
|
2021-07-12 14:58:03 +01:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Attribute:
|
|
|
|
|
type_description = "Attribute";
|
2021-04-29 21:16:28 +02:00
|
|
|
break;
|
2021-07-12 16:18:00 +01:00
|
|
|
case CSS::Selector::SimpleSelector::Type::PseudoClass:
|
2023-08-11 21:26:04 +01:00
|
|
|
type_description = "PseudoClassSelector";
|
2021-05-23 20:59:26 +02:00
|
|
|
break;
|
2021-07-12 16:34:18 +01:00
|
|
|
case CSS::Selector::SimpleSelector::Type::PseudoElement:
|
|
|
|
|
type_description = "PseudoElement";
|
|
|
|
|
break;
|
2024-10-15 12:00:29 +01:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Nesting:
|
|
|
|
|
type_description = "Nesting";
|
|
|
|
|
break;
|
2024-11-13 15:49:43 +00:00
|
|
|
case CSS::Selector::SimpleSelector::Type::Invalid:
|
|
|
|
|
type_description = "INVALID";
|
|
|
|
|
break;
|
2020-06-13 00:43:06 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-21 15:43:59 +00:00
|
|
|
builder.appendff("{}:", type_description);
|
2023-08-08 16:19:20 +01:00
|
|
|
|
2022-03-21 15:43:59 +00:00
|
|
|
// FIXME: This is goofy
|
2023-08-08 15:11:48 +01:00
|
|
|
if (simple_selector.value.has<CSS::Selector::SimpleSelector::Name>()) {
|
2022-03-21 15:43:59 +00:00
|
|
|
builder.append(simple_selector.name());
|
2023-08-08 15:11:48 +01:00
|
|
|
} else if (simple_selector.value.has<CSS::Selector::SimpleSelector::QualifiedName>()) {
|
2023-08-08 16:19:20 +01:00
|
|
|
dump_qualified_name(builder, simple_selector.qualified_name());
|
2023-08-08 15:11:48 +01:00
|
|
|
}
|
2021-07-12 16:18:00 +01:00
|
|
|
|
|
|
|
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) {
|
2022-03-21 15:43:59 +00:00
|
|
|
auto const& pseudo_class = simple_selector.pseudo_class();
|
2021-07-12 16:18:00 +01:00
|
|
|
|
2023-08-11 21:26:04 +01:00
|
|
|
builder.appendff(" pseudo_class={}", CSS::pseudo_class_name(pseudo_class.type));
|
|
|
|
|
auto pseudo_class_metadata = CSS::pseudo_class_metadata(pseudo_class.type);
|
2021-07-12 16:18:00 +01:00
|
|
|
|
2023-08-11 21:26:04 +01:00
|
|
|
switch (pseudo_class_metadata.parameter_type) {
|
|
|
|
|
case CSS::PseudoClassMetadata::ParameterType::None:
|
|
|
|
|
break;
|
|
|
|
|
case CSS::PseudoClassMetadata::ParameterType::ANPlusB:
|
|
|
|
|
case CSS::PseudoClassMetadata::ParameterType::ANPlusBOf: {
|
2025-08-28 10:44:17 +01:00
|
|
|
builder.appendff("(step={}, offset={}", pseudo_class.an_plus_b_pattern.step_size, pseudo_class.an_plus_b_pattern.offset);
|
2022-03-17 19:13:51 +00:00
|
|
|
if (!pseudo_class.argument_selector_list.is_empty()) {
|
2024-10-15 15:12:34 +01:00
|
|
|
builder.append(", selectors=[\n"sv);
|
2022-03-17 19:13:51 +00:00
|
|
|
for (auto const& child_selector : pseudo_class.argument_selector_list)
|
2024-10-15 15:12:34 +01:00
|
|
|
dump_selector(builder, child_selector, indent_levels + 2);
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels + 1);
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append("]"sv);
|
2022-03-17 19:13:51 +00:00
|
|
|
}
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(")"sv);
|
2023-08-11 21:26:04 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2023-08-12 13:47:45 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::CompoundSelector:
|
2023-08-11 21:26:04 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::ForgivingSelectorList:
|
2024-07-13 09:19:30 -07:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::ForgivingRelativeSelectorList:
|
2024-11-14 11:22:46 +00:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::RelativeSelectorList:
|
2023-08-11 21:26:04 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::SelectorList: {
|
2024-10-15 15:12:34 +01:00
|
|
|
builder.append("([\n"sv);
|
|
|
|
|
for (auto& child_selector : pseudo_class.argument_selector_list)
|
|
|
|
|
dump_selector(builder, child_selector, indent_levels + 2);
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels + 1);
|
2023-08-11 21:26:04 +01:00
|
|
|
builder.append("])"sv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-08-12 18:11:50 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::Ident:
|
2025-05-16 14:57:18 +01:00
|
|
|
builder.appendff("(ident={})", pseudo_class.ident->string_value);
|
2023-08-12 18:11:50 +01:00
|
|
|
break;
|
2023-08-11 21:26:04 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::LanguageRanges: {
|
|
|
|
|
builder.append('(');
|
|
|
|
|
builder.join(',', pseudo_class.languages);
|
|
|
|
|
builder.append(')');
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-08-28 10:29:57 +01:00
|
|
|
case CSS::PseudoClassMetadata::ParameterType::LevelList: {
|
|
|
|
|
builder.append('(');
|
|
|
|
|
builder.join(',', pseudo_class.levels);
|
|
|
|
|
builder.append(')');
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-07-12 16:18:00 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-12 14:58:03 +01:00
|
|
|
|
2021-07-12 16:34:18 +01:00
|
|
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoElement) {
|
2025-03-24 13:56:24 +00:00
|
|
|
auto const& pseudo_element = simple_selector.pseudo_element();
|
2025-05-08 11:48:34 +01:00
|
|
|
builder.appendff(" pseudo_element={}", pseudo_element.serialize());
|
2025-03-24 13:56:24 +00:00
|
|
|
auto pseudo_element_metadata = CSS::pseudo_element_metadata(pseudo_element.type());
|
|
|
|
|
|
|
|
|
|
switch (pseudo_element_metadata.parameter_type) {
|
|
|
|
|
case CSS::PseudoElementMetadata::ParameterType::None:
|
2025-07-12 16:15:06 +12:00
|
|
|
case CSS::PseudoElementMetadata::ParameterType::CompoundSelector:
|
2025-03-24 13:56:24 +00:00
|
|
|
break;
|
|
|
|
|
case CSS::PseudoElementMetadata::ParameterType::PTNameSelector: {
|
|
|
|
|
auto const& [is_universal, value] = pseudo_element.pt_name_selector();
|
|
|
|
|
builder.appendff("(is_universal={}, value='{}')", is_universal, value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-12 16:34:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-07-12 14:58:03 +01:00
|
|
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Attribute) {
|
2022-03-21 15:43:59 +00:00
|
|
|
auto const& attribute = simple_selector.attribute();
|
2021-07-12 14:58:03 +01:00
|
|
|
char const* attribute_match_type_description = "";
|
|
|
|
|
|
2022-03-21 15:43:59 +00:00
|
|
|
switch (attribute.match_type) {
|
2021-07-12 14:58:03 +01:00
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::HasAttribute:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "HasAttribute";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "ExactValueMatch";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::ContainsWord:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "ContainsWord";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::ContainsString:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "ContainsString";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::StartsWithSegment:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "StartsWithSegment";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::StartsWithString:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "StartsWithString";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
case CSS::Selector::SimpleSelector::Attribute::MatchType::EndsWithString:
|
2021-07-24 13:28:45 +01:00
|
|
|
attribute_match_type_description = "EndsWithString";
|
2021-07-12 14:58:03 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-08 16:19:20 +01:00
|
|
|
builder.appendff(" [{}, ", attribute_match_type_description);
|
|
|
|
|
dump_qualified_name(builder, attribute.qualified_name);
|
|
|
|
|
builder.appendff(", value='{}']", attribute.value);
|
2019-11-21 20:07:43 +01:00
|
|
|
}
|
2020-03-29 22:24:23 +02:00
|
|
|
|
2024-11-13 15:49:43 +00:00
|
|
|
if (simple_selector.type == CSS::Selector::SimpleSelector::Type::Invalid) {
|
|
|
|
|
auto invalid = simple_selector.value.get<CSS::Selector::SimpleSelector::Invalid>();
|
|
|
|
|
builder.append(" '"sv);
|
|
|
|
|
for (auto const& component_value : invalid.component_values)
|
|
|
|
|
builder.append(component_value.to_string());
|
|
|
|
|
builder.append("'"sv);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 15:24:33 +01:00
|
|
|
if (i != relative_selector.simple_selectors.size() - 1)
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(", "sv);
|
2019-06-27 20:40:21 +02:00
|
|
|
}
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append("\n"sv);
|
2020-03-29 22:24:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 11:35:01 +01:00
|
|
|
void dump_rule(CSS::CSSRule const& rule)
|
2020-03-29 22:24:23 +02:00
|
|
|
{
|
2021-02-17 15:59:13 +01:00
|
|
|
StringBuilder builder;
|
2024-10-15 11:35:01 +01:00
|
|
|
dump_rule(builder, rule);
|
2021-02-17 15:59:13 +01:00
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 11:35:01 +01:00
|
|
|
void dump_rule(StringBuilder& builder, CSS::CSSRule const& rule, int indent_levels)
|
2021-02-21 13:45:26 +02:00
|
|
|
{
|
2025-12-04 12:03:01 +00:00
|
|
|
rule.dump(builder, indent_levels);
|
2024-10-15 20:41:04 +01:00
|
|
|
}
|
|
|
|
|
|
LibWeb/CSS: Merge style declaration subclasses into CSSStyleProperties
We previously had PropertyOwningCSSStyleDeclaration and
ResolvedCSSStyleDeclaration, representing the current style properties
and resolved style respectively. Both of these were the
CSSStyleDeclaration type in the CSSOM. (We also had
ElementInlineCSSStyleDeclaration but I removed that in a previous
commit.)
In the meantime, the spec has changed so that these should now be a new
CSSStyleProperties type in the CSSOM. Also, we need to subclass
CSSStyleDeclaration for things like CSSFontFaceRule's list of
descriptors, which means it wouldn't hold style properties.
So, this commit does the fairly messy work of combining these two types
into a new CSSStyleProperties class. A lot of what previously was done
as separate methods in the two classes, now follows the spec steps of
"if the readonly flag is set, do X" instead, which is hopefully easier
to follow too.
There is still some functionality in CSSStyleDeclaration that belongs in
CSSStyleProperties, but I'll do that next. To avoid a huge diff for
"CSSStyleDeclaration-all-supported-properties-and-default-values.txt"
both here and in the following commit, we don't apply the (currently
empty) CSSStyleProperties prototype yet.
2025-03-17 17:50:49 +00:00
|
|
|
void dump_style_properties(StringBuilder& builder, CSS::CSSStyleProperties const& declaration, int indent_levels)
|
2021-02-17 15:59:13 +01:00
|
|
|
{
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2024-10-15 15:59:31 +01:00
|
|
|
builder.appendff("Declarations ({}):\n", declaration.length());
|
|
|
|
|
for (auto& property : declaration.properties()) {
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2025-05-16 19:20:24 +01:00
|
|
|
builder.appendff(" {}: '{}'", CSS::string_from_property_id(property.property_id), property.value->to_string(CSS::SerializationMode::Normal));
|
2022-02-12 14:53:59 +00:00
|
|
|
if (property.important == CSS::Important::Yes)
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(" \033[31;1m!important\033[0m"sv);
|
2021-09-21 11:29:44 +02:00
|
|
|
builder.append('\n');
|
2019-06-27 20:40:21 +02:00
|
|
|
}
|
2024-10-15 15:59:31 +01:00
|
|
|
for (auto& property : declaration.custom_properties()) {
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2025-05-16 19:20:24 +01:00
|
|
|
builder.appendff(" {}: '{}'", property.key, property.value.value->to_string(CSS::SerializationMode::Normal));
|
2022-02-12 14:53:59 +00:00
|
|
|
if (property.value.important == CSS::Important::Yes)
|
2022-07-11 17:32:29 +00:00
|
|
|
builder.append(" \033[31;1m!important\033[0m"sv);
|
2021-11-30 16:23:35 +00:00
|
|
|
builder.append('\n');
|
|
|
|
|
}
|
2019-06-27 20:40:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 14:37:25 +01:00
|
|
|
void dump_descriptors(StringBuilder& builder, CSS::CSSDescriptors const& descriptors, int indent_levels)
|
|
|
|
|
{
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2025-05-08 14:37:25 +01:00
|
|
|
builder.appendff("Declarations ({}):\n", descriptors.length());
|
|
|
|
|
for (auto const& descriptor : descriptors.descriptors()) {
|
2025-12-04 11:25:11 +00:00
|
|
|
dump_indent(builder, indent_levels);
|
2025-05-16 19:20:24 +01:00
|
|
|
builder.appendff(" {}: '{}'", CSS::to_string(descriptor.descriptor_id), descriptor.value->to_string(CSS::SerializationMode::Normal));
|
2025-05-08 14:37:25 +01:00
|
|
|
builder.append('\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 11:35:01 +01:00
|
|
|
void dump_sheet(CSS::StyleSheet const& sheet)
|
2019-06-21 20:54:13 +02:00
|
|
|
{
|
2021-02-17 15:59:13 +01:00
|
|
|
StringBuilder builder;
|
2024-10-15 11:35:01 +01:00
|
|
|
dump_sheet(builder, sheet);
|
2021-02-17 15:59:13 +01:00
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-15 11:35:01 +01:00
|
|
|
void dump_sheet(StringBuilder& builder, CSS::StyleSheet const& sheet)
|
2021-02-17 15:59:13 +01:00
|
|
|
{
|
2025-01-21 09:12:05 -05:00
|
|
|
auto& css_stylesheet = as<CSS::CSSStyleSheet>(sheet);
|
2019-06-25 06:31:47 +02:00
|
|
|
|
2021-09-28 16:18:20 +01:00
|
|
|
builder.appendff("CSSStyleSheet{{{}}}: {} rule(s)\n", &sheet, css_stylesheet.rules().length());
|
2021-03-07 16:14:04 +01:00
|
|
|
|
2023-01-13 20:10:00 +01:00
|
|
|
for (auto& rule : css_stylesheet.rules())
|
2024-10-15 11:35:01 +01:00
|
|
|
dump_rule(builder, rule);
|
2019-06-21 20:54:13 +02:00
|
|
|
}
|
2020-03-07 10:27:02 +01:00
|
|
|
|
2023-03-18 20:22:58 +01:00
|
|
|
void dump_tree(Painting::Paintable const& paintable)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder builder;
|
|
|
|
|
dump_tree(builder, paintable, true);
|
|
|
|
|
dbgln("{}", builder.string_view());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dump_tree(StringBuilder& builder, Painting::Paintable const& paintable, bool colorize, int indent)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < indent; ++i)
|
|
|
|
|
builder.append(" "sv);
|
|
|
|
|
|
|
|
|
|
StringView paintable_with_lines_color_on = ""sv;
|
|
|
|
|
StringView paintable_box_color_on = ""sv;
|
|
|
|
|
StringView text_paintable_color_on = ""sv;
|
|
|
|
|
StringView paintable_color_on = ""sv;
|
|
|
|
|
StringView color_off = ""sv;
|
|
|
|
|
|
|
|
|
|
if (colorize) {
|
|
|
|
|
paintable_with_lines_color_on = "\033[34m"sv;
|
|
|
|
|
paintable_box_color_on = "\033[33m"sv;
|
|
|
|
|
text_paintable_color_on = "\033[35m"sv;
|
|
|
|
|
paintable_color_on = "\033[32m"sv;
|
|
|
|
|
color_off = "\033[0m"sv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is<Painting::PaintableWithLines>(paintable))
|
|
|
|
|
builder.append(paintable_with_lines_color_on);
|
|
|
|
|
else if (is<Painting::PaintableBox>(paintable))
|
|
|
|
|
builder.append(paintable_box_color_on);
|
|
|
|
|
else if (is<Painting::TextPaintable>(paintable))
|
|
|
|
|
builder.append(text_paintable_color_on);
|
|
|
|
|
else
|
|
|
|
|
builder.append(paintable_color_on);
|
|
|
|
|
|
|
|
|
|
builder.appendff("{}{} ({})", paintable.class_name(), color_off, paintable.layout_node().debug_description());
|
|
|
|
|
|
2025-07-03 14:39:57 +02:00
|
|
|
if (auto const* paintable_box = as_if<Painting::PaintableBox>(paintable)) {
|
|
|
|
|
builder.appendff(" {}", paintable_box->absolute_border_box_rect());
|
2023-05-29 07:23:23 +02:00
|
|
|
|
2025-07-03 14:39:57 +02:00
|
|
|
if (paintable_box->has_scrollable_overflow())
|
|
|
|
|
builder.appendff(" overflow: {}", paintable_box->scrollable_overflow_rect());
|
2023-08-06 21:34:07 +02:00
|
|
|
|
2025-07-03 14:39:57 +02:00
|
|
|
if (!paintable_box->scroll_offset().is_zero())
|
|
|
|
|
builder.appendff(" scroll-offset: {}", paintable_box->scroll_offset());
|
2023-03-18 20:22:58 +01:00
|
|
|
}
|
|
|
|
|
builder.append("\n"sv);
|
|
|
|
|
for (auto const* child = paintable.first_child(); child; child = child->next_sibling()) {
|
|
|
|
|
dump_tree(builder, *child, colorize, indent + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-07 10:27:02 +01:00
|
|
|
}
|