diff --git a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp index a2d51fee3e..36bbe34e91 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ JS::GCPtr HTMLIFrameElement::create_layout_node(NonnullRefPtrdiscard(); - m_nested_browsing_context = nullptr; - } + // When an iframe element is removed from a document, the user agent must destroy the nested navigable of the element. + destroy_the_child_navigable(); } // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images @@ -126,8 +159,8 @@ void HTMLIFrameElement::apply_presentational_hints(CSS::StyleProperties& style) // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#iframe-load-event-steps void run_iframe_load_event_steps(HTML::HTMLIFrameElement& element) { - // FIXME: 1. Assert: element's nested browsing context is not null. - if (!element.nested_browsing_context()) { + // FIXME: 1. Assert: element's content navigable is not null. + if (!element.content_navigable()) { // 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; diff --git a/Userland/Libraries/LibWeb/HTML/NavigableContainer.cpp b/Userland/Libraries/LibWeb/HTML/NavigableContainer.cpp index c41de04086..d3ffa3ba6a 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigableContainer.cpp +++ b/Userland/Libraries/LibWeb/HTML/NavigableContainer.cpp @@ -44,7 +44,6 @@ NavigableContainer::~NavigableContainer() void NavigableContainer::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); - visitor.visit(m_nested_browsing_context); visitor.visit(m_content_navigable); } @@ -133,49 +132,15 @@ WebIDL::ExceptionOr NavigableContainer::create_new_child_navigable() return {}; } -// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-nested-browsing-context -void NavigableContainer::create_new_nested_browsing_context() -{ - // 1. Let group be element's node document's browsing context's top-level browsing context's group. - VERIFY(document().browsing_context()); - auto* group = document().browsing_context()->top_level_browsing_context().group(); - - // NOTE: The spec assumes that `group` is non-null here. - VERIFY(group); - VERIFY(group->page()); - - // 2. Let browsingContext be the result of creating a new browsing context with element's node document, element, and group. - // 3. Set element's nested browsing context to browsingContext. - m_nested_browsing_context = BrowsingContext::create_a_new_browsing_context(*group->page(), document(), *this, *group); - - document().browsing_context()->append_child(*m_nested_browsing_context); - m_nested_browsing_context->set_frame_nesting_levels(document().browsing_context()->frame_nesting_levels()); - m_nested_browsing_context->register_frame_nesting(document().url()); - - // 4. If element has a name attribute, then set browsingContext's name to the value of this attribute. - if (auto name = deprecated_attribute(HTML::AttributeNames::name); !name.is_empty()) - m_nested_browsing_context->set_name(String::from_deprecated_string(name).release_value_but_fixme_should_propagate_errors()); -} - // https://html.spec.whatwg.org/multipage/browsers.html#concept-bcc-content-document const DOM::Document* NavigableContainer::content_document() const { - // 1. If container's nested browsing context is null, then return null. - if (m_nested_browsing_context == nullptr) + // 1. If container's content navigable is null, then return null. + if (m_content_navigable == nullptr) return nullptr; - // 2. Let context be container's nested browsing context. - auto const& context = *m_nested_browsing_context; - - // 3. Let document be context's active document. - auto const* document = context.active_document(); - - // FIXME: This should not be here, as we're expected to have a document at this point. - if (!document) - return nullptr; - - VERIFY(document); - VERIFY(m_document); + // 2. Let document be container's content navigable's active document. + auto document = m_content_navigable->active_document(); // 4. If document's origin and container's node document's origin are not same origin-domain, then return null. if (!document->origin().is_same_origin_domain(m_document->origin())) @@ -187,9 +152,10 @@ const DOM::Document* NavigableContainer::content_document() const DOM::Document const* NavigableContainer::content_document_without_origin_check() const { - if (!m_nested_browsing_context) + if (!m_content_navigable) return nullptr; - return m_nested_browsing_context->active_document(); + + return m_content_navigable->active_document(); } // https://html.spec.whatwg.org/multipage/embedded-content-other.html#dom-media-getsvgdocument @@ -207,13 +173,13 @@ const DOM::Document* NavigableContainer::get_svg_document() const HTML::WindowProxy* NavigableContainer::content_window() { - if (!m_nested_browsing_context) + if (!m_content_navigable) return nullptr; - return m_nested_browsing_context->window_proxy(); + return m_content_navigable->active_window_proxy(); } // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements -void NavigableContainer::shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion) +Optional NavigableContainer::shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion) { // 1. Let url be the URL record about:blank. auto url = AK::URL("about:blank"); @@ -228,83 +194,45 @@ void NavigableContainer::shared_attribute_processing_steps_for_iframe_and_frame( url = parsed_src; } - // 3. If there exists an ancestor browsing context of element's nested browsing context - // whose active document's URL, ignoring fragments, is equal to url, then return. - if (m_nested_browsing_context) { - for (auto ancestor = m_nested_browsing_context->parent(); ancestor; ancestor = ancestor->parent()) { - VERIFY(ancestor->active_document()); - if (ancestor->active_document()->url().equals(url, AK::URL::ExcludeFragment::Yes)) - return; + // 3. If the inclusive ancestor navigables of element's node navigable contains a navigable + // whose active document's URL equals url with exclude fragments set to true, then return null. + if (m_content_navigable) { + for (auto const& navigable : document().inclusive_ancestor_navigables()) { + VERIFY(navigable->active_document()); + if (navigable->active_document()->url().equals(url, AK::URL::ExcludeFragment::Yes)) + return {}; } } - // 4. If url matches about:blank and initialInsertion is true, then: + // 4. If url matches about:blank and initialInsertion is true, then perform the URL and history update steps given element's content navigable's active document and url. if (url_matches_about_blank(url) && initial_insertion) { - // FIXME: 1. Perform the URL and history update steps given element's nested browsing context's active document and url. - - // 2. Run the iframe load event steps given element. - // FIXME: The spec doesn't check frame vs iframe here. Bug: https://github.com/whatwg/html/issues/8295 - if (is(*this)) { - run_iframe_load_event_steps(static_cast(*this)); - } - - // 3. Return. - return; + perform_url_and_history_update_steps(*m_content_navigable->active_document(), url); } - // 5. Let resource be a new request whose URL is url and whose referrer policy is the current state of element's referrerpolicy content attribute. - auto resource = Fetch::Infrastructure::Request::create(vm()); - resource->set_url(url); - // FIXME: Set the referrer policy. - - // AD-HOC: - if (url.scheme() == "file" && document().origin().scheme() != "file") { - dbgln("iframe failed to load URL: Security violation: {} may not load {}", document().url(), url); - return; - } - - // 6. If element is an iframe element, then set element's current navigation was lazy loaded boolean to false. - if (is(*this)) { - static_cast(*this).set_current_navigation_was_lazy_loaded(false); - } - - // 7. If element is an iframe element, and the will lazy load element steps given element return true, then: - if (is(*this) && static_cast(*this).will_lazy_load_element()) { - // FIXME: 1. Set element's lazy load resumption steps to the rest of this algorithm starting with the step labeled navigate to the resource. - // FIXME: 2. Set element's current navigation was lazy loaded boolean to true. - // FIXME: 3. Start intersection-observing a lazy loading element for element. - // FIXME: 4. Return. - } - - // 8. Navigate to the resource: navigate an iframe or frame given element and resource. - navigate_an_iframe_or_frame(resource); + // 5. Return url. + return url; } // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame -void NavigableContainer::navigate_an_iframe_or_frame(JS::NonnullGCPtr resource) +void NavigableContainer::navigate_an_iframe_or_frame(AK::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional srcdoc_string) { - // 1. Let historyHandling be "default". - auto history_handling = HistoryHandlingBehavior::Default; + // 1. Let historyHandling be "auto". + auto history_handling = Bindings::NavigationHistoryBehavior::Auto; - // 2. If element's nested browsing context's active document is not completely loaded, then set historyHandling to "replace". - VERIFY(m_nested_browsing_context); - VERIFY(m_nested_browsing_context->active_document()); - if (!m_nested_browsing_context->active_document()->is_completely_loaded()) { - history_handling = HistoryHandlingBehavior::Replace; + // 2. If element's content navigable's active document is not completely loaded, then set historyHandling to "replace". + if (m_content_navigable->active_document() && !m_content_navigable->active_document()->is_completely_loaded()) { + history_handling = Bindings::NavigationHistoryBehavior::Replace; } - // FIXME: 3. Let reportFrameTiming be the following step given response response: - // queue an element task on the networking task source - // given element's node document's relevant global object - // to finalize and report timing given response, element's node document's relevant global object, and element's local name. + // FIXME: 3. If element is an iframe, then set element's pending resource-timing start time to the current high resolution + // time given element's node document's relevant global object. - // 4. Navigate element's nested browsing context to resource, - // with historyHandling set to historyHandling, - // the source browsing context set to element's node document's browsing context, - // FIXME: and processResponseEndOfBody set to reportFrameTiming. - auto* source_browsing_context = document().browsing_context(); - VERIFY(source_browsing_context); - MUST(m_nested_browsing_context->navigate(resource, *source_browsing_context, false, history_handling)); + // 4. Navigate element's content navigable to url using element's node document, with historyHandling set to historyHandling, + // referrerPolicy set to referrerPolicy, and documentResource set to scrdocString. + Variant document_resource = Empty {}; + if (srcdoc_string.has_value()) + document_resource = srcdoc_string.value(); + MUST(m_content_navigable->navigate(url, document(), document_resource, nullptr, false, history_handling, {}, {}, referrer_policy)); } // https://html.spec.whatwg.org/multipage/document-sequences.html#destroy-a-child-navigable diff --git a/Userland/Libraries/LibWeb/HTML/NavigableContainer.h b/Userland/Libraries/LibWeb/HTML/NavigableContainer.h index bf15a16ce6..fce8b34941 100644 --- a/Userland/Libraries/LibWeb/HTML/NavigableContainer.h +++ b/Userland/Libraries/LibWeb/HTML/NavigableContainer.h @@ -7,6 +7,7 @@ #pragma once #include +#include namespace Web::HTML { @@ -23,8 +24,18 @@ public: JS::GCPtr content_navigable() { return m_content_navigable; } JS::GCPtr content_navigable() const { return m_content_navigable.ptr(); } - BrowsingContext* nested_browsing_context() { return m_nested_browsing_context; } - BrowsingContext const* nested_browsing_context() const { return m_nested_browsing_context; } + BrowsingContext* nested_browsing_context() + { + if (m_content_navigable) + return m_content_navigable->active_browsing_context(); + return nullptr; + } + BrowsingContext const* nested_browsing_context() const + { + if (m_content_navigable) + return m_content_navigable->active_browsing_context(); + return nullptr; + } const DOM::Document* content_document() const; DOM::Document const* content_document_without_origin_check() const; @@ -41,17 +52,13 @@ protected: virtual void visit_edges(Cell::Visitor&) override; // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements - void shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion); + Optional shared_attribute_processing_steps_for_iframe_and_frame(bool initial_insertion); // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame - void navigate_an_iframe_or_frame(JS::NonnullGCPtr); - - void create_new_nested_browsing_context(); + void navigate_an_iframe_or_frame(AK::URL url, ReferrerPolicy::ReferrerPolicy referrer_policy, Optional srcdoc_string = {}); WebIDL::ExceptionOr create_new_child_navigable(); - JS::GCPtr m_nested_browsing_context; - // https://html.spec.whatwg.org/multipage/document-sequences.html#content-navigable JS::GCPtr m_content_navigable { nullptr };