2021-04-03 11:43:08 +02:00
/*
2022-09-19 13:34:36 +02:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2022-02-14 22:03:16 +00:00
* Copyright ( c ) 2022 , Linus Groh < linusg @ serenityos . org >
2021-04-03 11:43:08 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-04-03 11:43:08 +02:00
*/
2023-07-10 21:08:57 +02:00
# include <LibWeb/Bindings/MainThreadVM.h>
2021-04-03 11:43:08 +02:00
# include <LibWeb/DOM/Document.h>
# include <LibWeb/DOM/Event.h>
2022-09-19 13:34:36 +02:00
# include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
2021-11-18 15:01:28 +01:00
# include <LibWeb/HTML/BrowsingContext.h>
2022-09-19 12:28:46 +02:00
# include <LibWeb/HTML/BrowsingContextGroup.h>
2022-12-16 23:28:12 +01:00
# include <LibWeb/HTML/DocumentState.h>
2022-09-19 13:34:36 +02:00
# include <LibWeb/HTML/HTMLIFrameElement.h>
2023-07-10 21:08:57 +02:00
# include <LibWeb/HTML/Navigable.h>
2022-12-12 12:20:02 +01:00
# include <LibWeb/HTML/NavigableContainer.h>
2022-09-19 13:34:36 +02:00
# include <LibWeb/HTML/NavigationParams.h>
2022-07-12 20:37:43 +01:00
# include <LibWeb/HTML/Origin.h>
2023-07-10 21:08:57 +02:00
# include <LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h>
2022-12-16 23:28:12 +01:00
# include <LibWeb/HTML/TraversableNavigable.h>
2023-07-10 21:08:57 +02:00
# include <LibWeb/HighResolutionTime/TimeOrigin.h>
2021-09-12 02:10:43 +02:00
# include <LibWeb/Page/Page.h>
2021-04-03 11:43:08 +02:00
namespace Web : : HTML {
2022-12-12 12:20:02 +01:00
HashTable < NavigableContainer * > & NavigableContainer : : all_instances ( )
2022-09-19 20:50:33 +02:00
{
2022-12-12 12:20:02 +01:00
static HashTable < NavigableContainer * > set ;
2022-09-19 20:50:33 +02:00
return set ;
}
2022-12-12 12:20:02 +01:00
NavigableContainer : : NavigableContainer ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-04-03 11:43:08 +02:00
: HTMLElement ( document , move ( qualified_name ) )
{
2023-04-23 17:50:08 +03:00
all_instances ( ) . set ( this ) ;
2021-04-03 11:43:08 +02:00
}
2023-04-23 17:50:08 +03:00
NavigableContainer : : ~ NavigableContainer ( )
{
all_instances ( ) . remove ( this ) ;
}
2021-04-03 11:43:08 +02:00
2022-12-12 12:20:02 +01:00
void NavigableContainer : : visit_edges ( Cell : : Visitor & visitor )
2022-10-17 11:06:50 +02:00
{
Base : : visit_edges ( visitor ) ;
2023-08-14 14:43:50 +02:00
visitor . visit ( m_content_navigable ) ;
2022-10-17 11:06:50 +02:00
}
2023-04-23 17:50:08 +03:00
JS : : GCPtr < NavigableContainer > NavigableContainer : : navigable_container_with_content_navigable ( JS : : NonnullGCPtr < Navigable > navigable )
{
for ( auto * navigable_container : all_instances ( ) ) {
if ( navigable_container - > content_navigable ( ) = = navigable )
return navigable_container ;
}
return nullptr ;
}
2023-07-10 21:08:57 +02:00
// https://html.spec.whatwg.org/multipage/document-sequences.html#create-a-new-child-navigable
WebIDL : : ExceptionOr < void > NavigableContainer : : create_new_child_navigable ( )
{
// 1. Let parentNavigable be element's node navigable.
auto parent_navigable = navigable ( ) ;
// 2. 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 ( ) ;
VERIFY ( group ) ;
// 3. Let browsingContext and document be the result of creating a new browsing context and document given element's node document, element, and group.
auto * page = document ( ) . page ( ) ;
VERIFY ( page ) ;
auto [ browsing_context , document ] = TRY ( BrowsingContext : : create_a_new_browsing_context_and_document ( * page , this - > document ( ) , * this , * group ) ) ;
// 4. Let targetName be null.
Optional < String > target_name ;
// 5. If element has a name content attribute, then set targetName to the value of that attribute.
2023-09-03 14:58:18 +12:00
if ( auto value = deprecated_attribute ( HTML : : AttributeNames : : name ) ; ! value . is_null ( ) )
2023-07-10 21:08:57 +02:00
target_name = String : : from_deprecated_string ( value ) . release_value_but_fixme_should_propagate_errors ( ) ;
// 6. Let documentState be a new document state, with
// document: document
// navigable target name: targetName
JS : : NonnullGCPtr < DocumentState > document_state = * heap ( ) . allocate_without_realm < HTML : : DocumentState > ( ) ;
document_state - > set_document ( document ) ;
if ( target_name . has_value ( ) )
document_state - > set_navigable_target_name ( * target_name ) ;
// 7. Let navigable be a new navigable.
JS : : NonnullGCPtr < Navigable > navigable = * heap ( ) . allocate_without_realm < Navigable > ( ) ;
// 8. Initialize the navigable navigable given documentState and parentNavigable.
TRY_OR_THROW_OOM ( vm ( ) , navigable - > initialize_navigable ( document_state , parent_navigable ) ) ;
// 9. Set element's content navigable to navigable.
m_content_navigable = navigable ;
// 10. Let historyEntry be navigable's active session history entry.
auto history_entry = navigable - > active_session_history_entry ( ) ;
// 11. Let traversable be parentNavigable's traversable navigable.
auto traversable = parent_navigable - > traversable_navigable ( ) ;
2023-07-25 01:22:57 +02:00
// 12. Append the following session history traversal steps to traversable:
traversable - > append_session_history_traversal_steps ( [ traversable , navigable , parent_navigable , history_entry ] {
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
2023-07-10 21:08:57 +02:00
2023-07-25 01:22:57 +02:00
auto parent_doc_state = parent_navigable - > active_session_history_entry ( ) - > document_state ;
2023-07-10 21:08:57 +02:00
2023-07-25 01:22:57 +02:00
// 2. Let targetStepSHE be the first session history entry in traversable's session history entries whose document state equals parentDocState.
auto target_step_she = * ( traversable - > session_history_entries ( ) . find_if ( [ parent_doc_state ] ( auto & entry ) {
return entry - > document_state = = parent_doc_state ;
} ) ) ;
2023-07-10 21:08:57 +02:00
2023-07-25 01:22:57 +02:00
// 3. Set historyEntry's step to targetStepSHE's step.
history_entry - > step = target_step_she - > step ;
2023-07-10 21:08:57 +02:00
2023-07-25 01:22:57 +02:00
// 4. Let nestedHistory be a new nested history whose id is navigable's id and entries list is « historyEntry ».
DocumentState : : NestedHistory nested_history {
. id = navigable - > id ( ) ,
. entries { * history_entry } ,
} ;
2023-07-10 21:08:57 +02:00
2023-07-25 01:22:57 +02:00
// 5. Append nestedHistory to parentDocState's nested histories.
parent_doc_state - > nested_histories ( ) . append ( move ( nested_history ) ) ;
2023-07-10 21:08:57 +02:00
2023-09-03 22:20:32 +02:00
// 6. Update for navigable creation/destruction given traversable
traversable - > update_for_navigable_creation_or_destruction ( ) ;
2023-07-25 01:22:57 +02:00
} ) ;
2023-07-10 21:08:57 +02:00
return { } ;
}
2022-02-14 22:03:16 +00:00
// https://html.spec.whatwg.org/multipage/browsers.html#concept-bcc-content-document
2022-12-12 12:20:02 +01:00
const DOM : : Document * NavigableContainer : : content_document ( ) const
2021-04-03 11:43:08 +02:00
{
2023-04-13 18:50:09 +03:00
// 1. If container's content navigable is null, then return null.
if ( m_content_navigable = = nullptr )
2022-02-14 22:03:16 +00:00
return nullptr ;
2021-04-03 11:43:08 +02:00
2023-04-13 18:50:09 +03:00
// 2. Let document be container's content navigable's active document.
auto document = m_content_navigable - > active_document ( ) ;
2022-02-14 22:03:16 +00:00
// 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 ( ) ) )
return nullptr ;
// 5. Return document.
return document ;
2021-04-03 11:43:08 +02:00
}
2022-12-12 12:20:02 +01:00
DOM : : Document const * NavigableContainer : : content_document_without_origin_check ( ) const
2022-02-16 22:51:25 +00:00
{
2023-04-13 18:50:09 +03:00
if ( ! m_content_navigable )
2022-02-16 22:51:25 +00:00
return nullptr ;
2023-04-13 18:50:09 +03:00
return m_content_navigable - > active_document ( ) ;
2022-02-16 22:51:25 +00:00
}
2022-03-24 22:08:06 +02:00
// https://html.spec.whatwg.org/multipage/embedded-content-other.html#dom-media-getsvgdocument
2022-12-12 12:20:02 +01:00
const DOM : : Document * NavigableContainer : : get_svg_document ( ) const
2022-03-24 22:08:06 +02:00
{
// 1. Let document be this element's content document.
auto const * document = content_document ( ) ;
// 2. If document is non-null and was created by the page load processing model for XML files section because the computed type of the resource in the navigate algorithm was image/svg+xml, then return document.
if ( document & & document - > content_type ( ) = = " image/svg+xml " sv )
return document ;
// 3. Return null.
return nullptr ;
}
2022-12-12 12:20:02 +01:00
HTML : : WindowProxy * NavigableContainer : : content_window ( )
2022-08-04 20:13:52 +02:00
{
2023-04-13 18:50:09 +03:00
if ( ! m_content_navigable )
2022-08-04 20:13:52 +02:00
return nullptr ;
2023-04-13 18:50:09 +03:00
return m_content_navigable - > active_window_proxy ( ) ;
2022-08-04 20:13:52 +02:00
}
2022-09-19 13:34:36 +02:00
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements
2023-04-13 18:50:09 +03:00
Optional < AK : : URL > NavigableContainer : : shared_attribute_processing_steps_for_iframe_and_frame ( bool initial_insertion )
2022-09-19 13:34:36 +02:00
{
// 1. Let url be the URL record about:blank.
auto url = AK : : URL ( " about:blank " ) ;
// 2. If element has a src attribute specified, and its value is not the empty string,
// then parse the value of that attribute relative to element's node document.
// If this is successful, then set url to the resulting URL record.
2023-09-03 14:58:18 +12:00
auto src_attribute_value = deprecated_attribute ( HTML : : AttributeNames : : src ) ;
2022-09-19 13:34:36 +02:00
if ( ! src_attribute_value . is_null ( ) & & ! src_attribute_value . is_empty ( ) ) {
auto parsed_src = document ( ) . parse_url ( src_attribute_value ) ;
if ( parsed_src . is_valid ( ) )
url = parsed_src ;
}
2023-04-13 18:50:09 +03:00
// 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 { } ;
2022-09-19 13:34:36 +02:00
}
}
2023-04-13 18:50:09 +03:00
// 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.
2022-09-19 13:34:36 +02:00
if ( url_matches_about_blank ( url ) & & initial_insertion ) {
2023-04-13 18:50:09 +03:00
perform_url_and_history_update_steps ( * m_content_navigable - > active_document ( ) , url ) ;
2022-09-19 13:34:36 +02:00
}
2023-04-13 18:50:09 +03:00
// 5. Return url.
return url ;
2022-09-19 13:34:36 +02:00
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
2023-04-13 18:50:09 +03:00
void NavigableContainer : : navigate_an_iframe_or_frame ( AK : : URL url , ReferrerPolicy : : ReferrerPolicy referrer_policy , Optional < String > srcdoc_string )
2022-09-19 13:34:36 +02:00
{
2023-04-13 18:50:09 +03:00
// 1. Let historyHandling be "auto".
auto history_handling = Bindings : : NavigationHistoryBehavior : : Auto ;
// 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 ;
2022-09-19 13:34:36 +02:00
}
2023-04-13 18:50:09 +03:00
// 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 content navigable to url using element's node document, with historyHandling set to historyHandling,
// referrerPolicy set to referrerPolicy, and documentResource set to scrdocString.
Variant < Empty , String , POSTResource > 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 ) ) ;
2022-09-19 13:34:36 +02:00
}
2022-12-16 23:28:12 +01:00
// https://html.spec.whatwg.org/multipage/document-sequences.html#destroy-a-child-navigable
void NavigableContainer : : destroy_the_child_navigable ( )
{
// 1. Let navigable be container's content navigable.
auto navigable = content_navigable ( ) ;
// 2. If navigable is null, then return.
if ( ! navigable )
return ;
// 3. Set container's content navigable to null.
m_content_navigable = nullptr ;
// 4. Destroy navigable's active document.
navigable - > active_document ( ) - > destroy ( ) ;
// 5. Let parentDocState be container's node navigable's active session history entry's document state.
auto parent_doc_state = this - > navigable ( ) - > active_session_history_entry ( ) - > document_state ;
// 6. Remove the nested history from parentDocState's nested histories whose id equals navigable's id.
parent_doc_state - > nested_histories ( ) . remove_all_matching ( [ & ] ( auto & nested_history ) {
return navigable - > id ( ) = = nested_history . id ;
} ) ;
// 7. Let traversable be container's node navigable's traversable navigable.
auto traversable = this - > navigable ( ) - > traversable_navigable ( ) ;
2023-09-05 23:36:20 +02:00
// Not in the spec
navigable - > set_has_been_destroyed ( ) ;
HTML : : all_navigables ( ) . remove ( navigable ) ;
2023-07-25 01:22:57 +02:00
// 8. Append the following session history traversal steps to traversable:
traversable - > append_session_history_traversal_steps ( [ traversable ] {
// 1. Apply pending history changes to traversable.
2023-09-03 22:20:32 +02:00
traversable - > update_for_navigable_creation_or_destruction ( ) ;
2023-07-25 01:22:57 +02:00
} ) ;
2022-12-16 23:28:12 +01:00
}
2021-04-03 11:43:08 +02:00
}