ladybird/Libraries/LibWeb/DOM/AbstractElement.h
Andreas Kling d17f666a8c
Some checks are pending
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / 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
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
LibWeb: Better CSS inheritance for nodes that represent a pseudo-element
When we compute style for elements inside a UA-internal shadow tree that
represent a pseudo-element (e.g ::placeholder), we actually run the
StyleComputer machinery for (host element :: pseudo-element).

While that lets us match the correct selectors, it was incorrectly
applying CSS inheritance, since we'd also then inherit from whatever was
above the host element in the tree.

This patch fixes the issue by introducing an inheritance override in
AbstractElement and then using that to force inheritance from whatever
is actually directly above in the DOM for these elements instead of
jumping all the way up past the host.

This fixes an issue where `text-align: center` on input type=text
elements would render the main text centered but placeholder text was
still left-aligned.
2025-10-21 16:42:00 +02:00

80 lines
2.8 KiB
C++

/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibGC/Cell.h>
#include <LibWeb/CSS/PseudoElement.h>
#include <LibWeb/CSS/StyleProperty.h>
#include <LibWeb/Forward.h>
namespace Web::DOM {
// Either an Element or a PseudoElement
class WEB_API AbstractElement {
public:
AbstractElement(GC::Ref<Element>, Optional<CSS::PseudoElement> = {});
Document& document() const;
Element& element() { return m_element; }
Element const& element() const { return m_element; }
Optional<CSS::PseudoElement> pseudo_element() const { return m_pseudo_element; }
GC::Ptr<Layout::NodeWithStyle> layout_node();
GC::Ptr<Layout::NodeWithStyle const> layout_node() const { return const_cast<AbstractElement*>(this)->layout_node(); }
CSS::TreeCountingFunctionResolutionContext tree_counting_function_resolution_context() const;
GC::Ptr<Element const> parent_element() const;
Optional<AbstractElement> element_to_inherit_style_from() const;
Optional<AbstractElement> previous_in_tree_order() { return walk_layout_tree(WalkMethod::Previous); }
Optional<AbstractElement> previous_sibling_in_tree_order() { return walk_layout_tree(WalkMethod::PreviousSibling); }
bool is_before(AbstractElement const&) const;
void set_inheritance_override(GC::Ref<Element> element) { m_inheritance_override = element; }
GC::Ptr<CSS::ComputedProperties const> computed_properties() const;
void set_custom_properties(OrderedHashMap<FlyString, CSS::StyleProperty>&& custom_properties);
[[nodiscard]] OrderedHashMap<FlyString, CSS::StyleProperty> const& custom_properties() const;
RefPtr<CSS::StyleValue const> get_custom_property(FlyString const& name) const;
GC::Ptr<CSS::CascadedProperties> cascaded_properties() const;
void set_cascaded_properties(GC::Ptr<CSS::CascadedProperties>);
bool has_non_empty_counters_set() const;
Optional<CSS::CountersSet const&> counters_set() const;
CSS::CountersSet& ensure_counters_set();
void set_counters_set(OwnPtr<CSS::CountersSet>&&);
void visit(GC::Cell::Visitor& visitor) const;
String debug_description() const;
bool operator==(AbstractElement const&) const = default;
private:
enum class WalkMethod : u8 {
Previous,
PreviousSibling,
};
Optional<AbstractElement> walk_layout_tree(WalkMethod);
GC::Ref<Element> m_element;
Optional<CSS::PseudoElement> m_pseudo_element;
GC::Ptr<Element> m_inheritance_override;
};
}
template<>
struct AK::Traits<Web::DOM::AbstractElement> : public DefaultTraits<Web::DOM::AbstractElement> {
static unsigned hash(Web::DOM::AbstractElement const& key)
{
return pair_int_hash(ptr_hash(&key.element()), key.pseudo_element().has_value() ? to_underlying(key.pseudo_element().value()) : -1);
}
};