mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 16:07:46 +00:00
LibWeb: Implement Document/BrowsingContext hookup according to spec
We now implement the browsing context's "set active document" algorithm from the spec, as well as the "discard" algorithm for browsing contexts and documents.
This commit is contained in:
parent
ab8432783e
commit
92deba7197
9 changed files with 189 additions and 70 deletions
|
@ -207,7 +207,7 @@ NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Pa
|
|||
document->append_child(html_node);
|
||||
|
||||
// 19. Set the active document of browsingContext to document.
|
||||
browsing_context->m_active_document = JS::make_handle(*document);
|
||||
browsing_context->set_active_document(*document);
|
||||
|
||||
// 20. If browsingContext's creator URL is non-null, then set document's referrer to the serialization of it.
|
||||
if (browsing_context->m_creator_url.has_value()) {
|
||||
|
@ -227,9 +227,6 @@ NonnullRefPtr<BrowsingContext> BrowsingContext::create_a_new_browsing_context(Pa
|
|||
.original_source_browsing_context = {},
|
||||
});
|
||||
|
||||
// Non-standard:
|
||||
document->attach_to_browsing_context({}, browsing_context);
|
||||
|
||||
// 23. Completely finish loading document.
|
||||
document->completely_finish_loading();
|
||||
|
||||
|
@ -286,36 +283,29 @@ bool BrowsingContext::is_focused_context() const
|
|||
return m_page && &m_page->focused_context() == this;
|
||||
}
|
||||
|
||||
void BrowsingContext::set_active_document(DOM::Document* document)
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#set-the-active-document
|
||||
void BrowsingContext::set_active_document(JS::NonnullGCPtr<DOM::Document> document)
|
||||
{
|
||||
if (m_active_document.ptr() == document)
|
||||
return;
|
||||
// 1. Let window be document's relevant global object.
|
||||
auto& window = verify_cast<HTML::Window>(relevant_global_object(document));
|
||||
|
||||
m_cursor_position = {};
|
||||
// 2. Set document's visibility state to browsingContext's top-level browsing context's system visibility state.
|
||||
document->set_visibility_state({}, top_level_browsing_context().system_visibility_state());
|
||||
|
||||
if (m_active_document)
|
||||
m_active_document->detach_from_browsing_context({}, *this);
|
||||
// 3. Set browsingContext's active window to window.
|
||||
m_active_window = window;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#resetBCName
|
||||
// FIXME: The rest of set_active_document does not follow the spec very closely, this just implements the
|
||||
// relevant steps for resetting the browsing context name and should be updated closer to the spec once
|
||||
// the other parts of history handling/navigating are implemented
|
||||
// 3. If newDocument's origin is not same origin with the current entry's document's origin, then:
|
||||
if (!document || !m_active_document || !document->origin().is_same_origin(m_active_document->origin())) {
|
||||
// 3. If the browsing context is a top-level browsing context, but not an auxiliary browsing context
|
||||
// whose disowned is false, then set the browsing context's name to the empty string.
|
||||
// FIXME: this is not checking the second part of the condition yet
|
||||
if (is_top_level())
|
||||
m_name = String::empty();
|
||||
}
|
||||
// 4. Set window's associated Document to document.
|
||||
window.set_associated_document(document);
|
||||
|
||||
m_active_document = JS::make_handle(document);
|
||||
// 5. Set window's relevant settings object's execution ready flag.
|
||||
relevant_settings_object(window).execution_ready = true;
|
||||
|
||||
if (m_active_document) {
|
||||
m_active_document->attach_to_browsing_context({}, *this);
|
||||
if (m_page && is_top_level())
|
||||
m_page->client().page_did_change_title(m_active_document->title());
|
||||
}
|
||||
// AD-HOC:
|
||||
document->set_browsing_context(this);
|
||||
|
||||
if (m_page && is_top_level())
|
||||
m_page->client().page_did_change_title(document->title());
|
||||
}
|
||||
|
||||
void BrowsingContext::set_viewport_rect(Gfx::IntRect const& rect)
|
||||
|
@ -792,22 +782,26 @@ bool BrowsingContext::still_on_its_initial_about_blank_document() const
|
|||
|
||||
DOM::Document const* BrowsingContext::active_document() const
|
||||
{
|
||||
return m_active_document.cell();
|
||||
if (!m_active_window)
|
||||
return nullptr;
|
||||
return &m_active_window->associated_document();
|
||||
}
|
||||
|
||||
DOM::Document* BrowsingContext::active_document()
|
||||
{
|
||||
return m_active_document.cell();
|
||||
if (!m_active_window)
|
||||
return nullptr;
|
||||
return &m_active_window->associated_document();
|
||||
}
|
||||
|
||||
HTML::Window* BrowsingContext::active_window()
|
||||
{
|
||||
return m_active_document ? &m_active_document->window() : nullptr;
|
||||
return m_active_window;
|
||||
}
|
||||
|
||||
HTML::Window const* BrowsingContext::active_window() const
|
||||
{
|
||||
return m_active_document ? &m_active_document->window() : nullptr;
|
||||
return m_active_window;
|
||||
}
|
||||
|
||||
void BrowsingContext::scroll_offset_did_change()
|
||||
|
@ -1087,7 +1081,7 @@ DOM::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_index,
|
|||
}
|
||||
|
||||
// 4. Set the active document of the browsing context to newDocument.
|
||||
set_active_document(new_document);
|
||||
set_active_document(*new_document);
|
||||
|
||||
// 5. If entry's browsing context name is not null, then:
|
||||
if (entry->browsing_context_name.has_value()) {
|
||||
|
@ -1299,4 +1293,27 @@ void BrowsingContext::set_system_visibility_state(VisibilityState visibility_sta
|
|||
});
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded
|
||||
void BrowsingContext::discard()
|
||||
{
|
||||
// 1. Discard all Document objects for all the entries in browsingContext's session history.
|
||||
for (auto& entry : m_session_history) {
|
||||
if (entry.document)
|
||||
entry.document->discard();
|
||||
}
|
||||
|
||||
// AD-HOC:
|
||||
// FIXME: This should be in the session history!
|
||||
if (auto* document = active_document())
|
||||
document->discard();
|
||||
|
||||
// 2. If browsingContext is a top-level browsing context, then remove browsingContext.
|
||||
if (is_top_level())
|
||||
remove();
|
||||
|
||||
// AD-HOC:
|
||||
if (parent())
|
||||
parent()->remove_child(*this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
DOM::Document const* active_document() const;
|
||||
DOM::Document* active_document();
|
||||
|
||||
void set_active_document(DOM::Document*);
|
||||
void set_active_document(JS::NonnullGCPtr<DOM::Document>);
|
||||
|
||||
HTML::Window* active_window();
|
||||
HTML::Window const* active_window() const;
|
||||
|
@ -165,6 +165,9 @@ public:
|
|||
VisibilityState system_visibility_state() const;
|
||||
void set_system_visibility_state(VisibilityState);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded
|
||||
void discard();
|
||||
|
||||
private:
|
||||
explicit BrowsingContext(Page&, HTML::BrowsingContextContainer*);
|
||||
|
||||
|
@ -195,7 +198,7 @@ private:
|
|||
Optional<HTML::Origin> m_creator_origin;
|
||||
|
||||
WeakPtr<HTML::BrowsingContextContainer> m_container;
|
||||
JS::Handle<DOM::Document> m_active_document;
|
||||
JS::Handle<HTML::Window> m_active_window;
|
||||
Gfx::IntSize m_size;
|
||||
Gfx::IntPoint m_viewport_scroll_offset;
|
||||
|
||||
|
|
|
@ -55,17 +55,6 @@ void BrowsingContextContainer::create_new_nested_browsing_context()
|
|||
m_nested_browsing_context->set_name(name);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#a-browsing-context-is-discarded
|
||||
void BrowsingContextContainer::discard_nested_browsing_context()
|
||||
{
|
||||
// 1. Discard all Document objects for all the entries in browsingContext's session history.
|
||||
if (m_nested_browsing_context && m_nested_browsing_context->parent())
|
||||
m_nested_browsing_context->parent()->remove_child(*m_nested_browsing_context);
|
||||
|
||||
// 2. If browsingContext is a top-level browsing context, then remove browsingContext.
|
||||
// NOTE: We skip this here because this is by definition a nested browsing context, not top-level.
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#concept-bcc-content-document
|
||||
const DOM::Document* BrowsingContextContainer::content_document() const
|
||||
{
|
||||
|
|
|
@ -38,7 +38,6 @@ protected:
|
|||
void navigate_an_iframe_or_frame(Fetch::Infrastructure::Request);
|
||||
|
||||
void create_new_nested_browsing_context();
|
||||
void discard_nested_browsing_context();
|
||||
|
||||
RefPtr<BrowsingContext> m_nested_browsing_context;
|
||||
|
||||
|
|
|
@ -95,7 +95,13 @@ void HTMLIFrameElement::process_the_iframe_attributes(bool initial_insertion)
|
|||
void HTMLIFrameElement::removed_from(DOM::Node* node)
|
||||
{
|
||||
HTMLElement::removed_from(node);
|
||||
discard_nested_browsing_context();
|
||||
|
||||
// When an iframe element is removed from a document, the user agent must discard the element's nested browsing context,
|
||||
// if it is not null, and then set the element's nested browsing context to null.
|
||||
if (m_nested_browsing_context) {
|
||||
m_nested_browsing_context->discard();
|
||||
m_nested_browsing_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLIFrameElement::load_src(String const& value)
|
||||
|
@ -123,8 +129,12 @@ void HTMLIFrameElement::load_src(String const& value)
|
|||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#iframe-load-event-steps
|
||||
void run_iframe_load_event_steps(HTML::HTMLIFrameElement& element)
|
||||
{
|
||||
// 1. Assert: element's nested browsing context is not null.
|
||||
VERIFY(element.nested_browsing_context());
|
||||
// FIXME: 1. Assert: element's nested browsing context is not null.
|
||||
if (!element.nested_browsing_context()) {
|
||||
// FIXME: For some reason, we sometimes end up here in the middle of SunSpider.
|
||||
dbgln("FIXME: run_iframe_load_event_steps called with null nested browsing context");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Let childDocument be the active document of element's nested browsing context.
|
||||
[[maybe_unused]] auto* child_document = element.nested_browsing_context()->active_document();
|
||||
|
|
|
@ -235,7 +235,7 @@ void HTMLObjectElement::run_object_representation_handler_steps(Optional<String>
|
|||
else if (resource_type.has_value() && resource_type->starts_with("image/"sv)) {
|
||||
// If the object element's nested browsing context is non-null, then it must be discarded and then set to null.
|
||||
if (m_nested_browsing_context) {
|
||||
discard_nested_browsing_context();
|
||||
m_nested_browsing_context->discard();
|
||||
m_nested_browsing_context = nullptr;
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ void HTMLObjectElement::run_object_representation_fallback_steps()
|
|||
{
|
||||
// 6. Fallback: The object element represents the element's children, ignoring any leading param element children. This is the element's fallback content. If the element has an instantiated plugin, then unload it. If the element's nested browsing context is non-null, then it must be discarded and then set to null.
|
||||
if (m_nested_browsing_context) {
|
||||
discard_nested_browsing_context();
|
||||
m_nested_browsing_context->discard();
|
||||
m_nested_browsing_context = nullptr;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue