1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 06:44:58 +00:00
serenity/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp
Aliaksandr Kalenik 33294aea86 LibWeb: Apply shadow root style sheets in StyleComputer
Now, if an element belongs to a shadow tree, we use only the style
sheets from the corresponding shadow root during style computation,
instead of using all available style sheets as was the case
previously.

The only exception is the user agent style sheets, which are still
taken into account for all elements.

Tests/LibWeb/Layout/input/input-element-with-display-inline.html
is affected because style of document no longer affects shadow tree
of input element, like it is supposed to be.

Co-authored-by: Simon Wanner <simon+git@skyrising.xyz>
2024-03-09 16:13:32 +01:00

120 lines
3.3 KiB
C++

/*
* Copyright (c) 2020, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/DOM/AdoptedStyleSheets.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/DOMParsing/InnerHTML.h>
#include <LibWeb/Layout/BlockContainer.h>
namespace Web::DOM {
JS_DEFINE_ALLOCATOR(ShadowRoot);
ShadowRoot::ShadowRoot(Document& document, Element& host, Bindings::ShadowRootMode mode)
: DocumentFragment(document)
, m_mode(mode)
{
document.register_shadow_root({}, *this);
set_host(&host);
}
void ShadowRoot::finalize()
{
Base::finalize();
document().unregister_shadow_root({}, *this);
}
void ShadowRoot::initialize(JS::Realm& realm)
{
Base::initialize(realm);
set_prototype(&Bindings::ensure_web_prototype<Bindings::ShadowRootPrototype>(realm, "ShadowRoot"_fly_string));
}
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
EventTarget* ShadowRoot::get_parent(Event const& event)
{
if (!event.composed()) {
auto& events_first_invocation_target = verify_cast<Node>(*event.path().first().invocation_target);
if (&events_first_invocation_target.root() == this)
return nullptr;
}
return host();
}
// https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml
WebIDL::ExceptionOr<String> ShadowRoot::inner_html() const
{
return serialize_fragment(DOMParsing::RequireWellFormed::Yes);
}
// https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml
WebIDL::ExceptionOr<void> ShadowRoot::set_inner_html(StringView markup)
{
TRY(DOMParsing::inner_html_setter(*this, markup));
set_needs_style_update(true);
return {};
}
CSS::StyleSheetList& ShadowRoot::style_sheets()
{
if (!m_style_sheets)
m_style_sheets = CSS::StyleSheetList::create(document());
return *m_style_sheets;
}
CSS::StyleSheetList const& ShadowRoot::style_sheets() const
{
return const_cast<ShadowRoot*>(this)->style_sheets();
}
void ShadowRoot::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_style_sheets);
visitor.visit(m_adopted_style_sheets);
}
JS::NonnullGCPtr<WebIDL::ObservableArray> ShadowRoot::adopted_style_sheets() const
{
if (!m_adopted_style_sheets)
m_adopted_style_sheets = create_adopted_style_sheets_list(const_cast<Document&>(document()));
return *m_adopted_style_sheets;
}
WebIDL::ExceptionOr<void> ShadowRoot::set_adopted_style_sheets(JS::Value new_value)
{
if (!m_adopted_style_sheets)
m_adopted_style_sheets = create_adopted_style_sheets_list(const_cast<Document&>(document()));
m_adopted_style_sheets->clear();
auto iterator_record = TRY(get_iterator(vm(), new_value, JS::IteratorHint::Sync));
while (true) {
auto next = TRY(iterator_step_value(vm(), iterator_record));
if (!next.has_value())
break;
TRY(m_adopted_style_sheets->append(*next));
}
return {};
}
void ShadowRoot::for_each_css_style_sheet(Function<void(CSS::CSSStyleSheet&)>&& callback) const
{
for (auto& style_sheet : style_sheets().sheets())
callback(*style_sheet);
if (m_adopted_style_sheets) {
m_adopted_style_sheets->for_each<CSS::CSSStyleSheet>([&](auto& style_sheet) {
callback(style_sheet);
});
}
}
}