2021-04-03 12:43:08 +03:00
/*
2022-09-19 14:34:36 +03:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2022-02-15 01:03:16 +03:00
* Copyright ( c ) 2022 , Linus Groh < linusg @ serenityos . org >
2023-11-24 18:52:56 +03:00
* Copyright ( c ) 2023 , Sam Atkins < atkinssj @ serenityos . org >
2021-04-03 12:43:08 +03:00
*
2021-04-22 11:24:48 +03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-04-03 12:43:08 +03:00
*/
2023-07-10 22:08:57 +03:00
# include <LibWeb/Bindings/MainThreadVM.h>
2021-04-03 12:43:08 +03:00
# include <LibWeb/DOM/Document.h>
# include <LibWeb/DOM/Event.h>
2022-09-19 14:34:36 +03:00
# include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
2021-11-18 17:01:28 +03:00
# include <LibWeb/HTML/BrowsingContext.h>
2022-09-19 13:28:46 +03:00
# include <LibWeb/HTML/BrowsingContextGroup.h>
2022-12-17 01:28:12 +03:00
# include <LibWeb/HTML/DocumentState.h>
2022-09-19 14:34:36 +03:00
# include <LibWeb/HTML/HTMLIFrameElement.h>
2023-07-10 22:08:57 +03:00
# include <LibWeb/HTML/Navigable.h>
2022-12-12 14:20:02 +03:00
# include <LibWeb/HTML/NavigableContainer.h>
2022-09-19 14:34:36 +03:00
# include <LibWeb/HTML/NavigationParams.h>
2022-07-12 22:37:43 +03:00
# include <LibWeb/HTML/Origin.h>
2023-07-10 22:08:57 +03:00
# include <LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h>
2022-12-17 01:28:12 +03:00
# include <LibWeb/HTML/TraversableNavigable.h>
2024-04-01 00:42:51 +03:00
# include <LibWeb/HTML/Window.h>
2023-07-10 22:08:57 +03:00
# include <LibWeb/HighResolutionTime/TimeOrigin.h>
2021-09-12 03:10:43 +03:00
# include <LibWeb/Page/Page.h>
2021-04-03 12:43:08 +03:00
namespace Web : : HTML {
2022-12-12 14:20:02 +03:00
HashTable < NavigableContainer * > & NavigableContainer : : all_instances ( )
2022-09-19 21:50:33 +03:00
{
2022-12-12 14:20:02 +03:00
static HashTable < NavigableContainer * > set ;
2022-09-19 21:50:33 +03:00
return set ;
}
2022-12-12 14:20:02 +03:00
NavigableContainer : : NavigableContainer ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-04-03 12:43:08 +03:00
: HTMLElement ( document , move ( qualified_name ) )
{
2023-04-23 17:50:08 +03:00
all_instances ( ) . set ( this ) ;
2021-04-03 12:43:08 +03:00
}
2023-04-23 17:50:08 +03:00
NavigableContainer : : ~ NavigableContainer ( )
{
all_instances ( ) . remove ( this ) ;
}
2021-04-03 12:43:08 +03:00
2022-12-12 14:20:02 +03:00
void NavigableContainer : : visit_edges ( Cell : : Visitor & visitor )
2022-10-17 12:06:50 +03:00
{
Base : : visit_edges ( visitor ) ;
2023-08-14 15:43:50 +03:00
visitor . visit ( m_content_navigable ) ;
2022-10-17 12:06:50 +03: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 22:08:57 +03:00
// https://html.spec.whatwg.org/multipage/document-sequences.html#create-a-new-child-navigable
2024-04-04 19:49:40 +03:00
WebIDL : : ExceptionOr < void > NavigableContainer : : create_new_child_navigable ( JS : : SafeFunction < void ( ) > afterSessionHistoryUpdate )
2023-07-10 22:08:57 +03:00
{
// 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 ( ) ) ;
2023-09-04 16:33:08 +03:00
auto group = document ( ) . browsing_context ( ) - > top_level_browsing_context ( ) - > group ( ) ;
2023-07-10 22:08:57 +03:00
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.
2023-12-15 17:41:28 +03:00
auto & page = document ( ) . page ( ) ;
auto [ browsing_context , document ] = TRY ( BrowsingContext : : create_a_new_browsing_context_and_document ( page , this - > document ( ) , * this , * group ) ) ;
2023-07-10 22:08:57 +03:00
// 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.
2024-01-13 10:12:25 +03:00
if ( name ( ) . has_value ( ) )
target_name = name ( ) . value ( ) . to_string ( ) ;
2023-07-10 22:08:57 +03:00
// 6. Let documentState be a new document state, with
2023-09-23 02:31:25 +03:00
// - document: document
// - initiator origin: document's origin
// - origin: document's origin
// - navigable target name: targetName
// - about base URL: document's about base URL
2023-07-10 22:08:57 +03:00
JS : : NonnullGCPtr < DocumentState > document_state = * heap ( ) . allocate_without_realm < HTML : : DocumentState > ( ) ;
document_state - > set_document ( document ) ;
2023-09-23 02:31:25 +03:00
document_state - > set_initiator_origin ( document - > origin ( ) ) ;
document_state - > set_origin ( document - > origin ( ) ) ;
2023-07-10 22:08:57 +03:00
if ( target_name . has_value ( ) )
document_state - > set_navigable_target_name ( * target_name ) ;
2023-09-23 02:31:25 +03:00
document_state - > set_about_base_url ( document - > about_base_url ( ) ) ;
2023-07-10 22:08:57 +03:00
// 7. Let navigable be a new navigable.
2024-04-26 17:59:04 +03:00
JS : : NonnullGCPtr < Navigable > navigable = * heap ( ) . allocate_without_realm < Navigable > ( page ) ;
2023-07-10 22:08:57 +03:00
// 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 02:22:57 +03:00
// 12. Append the following session history traversal steps to traversable:
2024-04-04 19:49:40 +03:00
traversable - > append_session_history_traversal_steps ( [ traversable , navigable , parent_navigable , history_entry , afterSessionHistoryUpdate = move ( afterSessionHistoryUpdate ) ] {
2023-07-25 02:22:57 +03:00
// 1. Let parentDocState be parentNavigable's active session history entry's document state.
2024-03-27 17:59:12 +03:00
auto parent_doc_state = parent_navigable - > active_session_history_entry ( ) - > document_state ( ) ;
2023-07-10 22:08:57 +03:00
2024-01-02 22:57:26 +03:00
// 2. Let parentNavigableEntries be the result of getting session history entries for parentNavigable.
auto parent_navigable_entries = parent_navigable - > get_session_history_entries ( ) ;
// 3. Let targetStepSHE be the first session history entry in parentNavigableEntries whose document state equals parentDocState.
auto target_step_she = * parent_navigable_entries . find_if ( [ parent_doc_state ] ( auto & entry ) {
2024-03-27 17:59:12 +03:00
return entry - > document_state ( ) = = parent_doc_state ;
2024-01-02 22:57:26 +03:00
} ) ;
2023-07-10 22:08:57 +03:00
2024-01-02 22:57:26 +03:00
// 4. Set historyEntry's step to targetStepSHE's step.
2024-03-27 17:59:12 +03:00
history_entry - > set_step ( target_step_she - > step ( ) ) ;
2023-07-10 22:08:57 +03:00
2024-01-02 22:57:26 +03:00
// 5. Let nestedHistory be a new nested history whose id is navigable's id and entries list is « historyEntry ».
2023-07-25 02:22:57 +03:00
DocumentState : : NestedHistory nested_history {
. id = navigable - > id ( ) ,
. entries { * history_entry } ,
} ;
2023-07-10 22:08:57 +03:00
2024-04-06 21:48:06 +03:00
// 6. Append nestedHistory to parentDocState's nested histories.
2023-07-25 02:22:57 +03:00
parent_doc_state - > nested_histories ( ) . append ( move ( nested_history ) ) ;
2023-07-10 22:08:57 +03:00
2024-04-06 21:48:06 +03:00
// 7. Update for navigable creation/destruction given traversable
2023-09-03 23:20:32 +03:00
traversable - > update_for_navigable_creation_or_destruction ( ) ;
2024-04-04 19:49:40 +03:00
if ( afterSessionHistoryUpdate ) {
afterSessionHistoryUpdate ( ) ;
}
2023-07-25 02:22:57 +03:00
} ) ;
2023-07-10 22:08:57 +03:00
return { } ;
}
2022-02-15 01:03:16 +03:00
// https://html.spec.whatwg.org/multipage/browsers.html#concept-bcc-content-document
2022-12-12 14:20:02 +03:00
const DOM : : Document * NavigableContainer : : content_document ( ) const
2021-04-03 12:43:08 +03: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-15 01:03:16 +03:00
return nullptr ;
2021-04-03 12:43:08 +03: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-15 01:03:16 +03: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 12:43:08 +03:00
}
2022-12-12 14:20:02 +03:00
DOM : : Document const * NavigableContainer : : content_document_without_origin_check ( ) const
2022-02-17 01:51:25 +03:00
{
2023-04-13 18:50:09 +03:00
if ( ! m_content_navigable )
2022-02-17 01:51:25 +03:00
return nullptr ;
2023-04-13 18:50:09 +03:00
return m_content_navigable - > active_document ( ) ;
2022-02-17 01:51:25 +03:00
}
2022-03-24 23:08:06 +03:00
// https://html.spec.whatwg.org/multipage/embedded-content-other.html#dom-media-getsvgdocument
2022-12-12 14:20:02 +03:00
const DOM : : Document * NavigableContainer : : get_svg_document ( ) const
2022-03-24 23:08:06 +03: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 14:20:02 +03:00
HTML : : WindowProxy * NavigableContainer : : content_window ( )
2022-08-04 21:13:52 +03:00
{
2023-04-13 18:50:09 +03:00
if ( ! m_content_navigable )
2022-08-04 21:13:52 +03:00
return nullptr ;
2023-04-13 18:50:09 +03:00
return m_content_navigable - > active_window_proxy ( ) ;
2022-08-04 21:13:52 +03:00
}
2022-09-19 14:34:36 +03:00
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements
2024-03-18 06:22:27 +03:00
Optional < URL : : URL > NavigableContainer : : shared_attribute_processing_steps_for_iframe_and_frame ( bool initial_insertion )
2022-09-19 14:34:36 +03:00
{
// 1. Let url be the URL record about:blank.
2024-03-18 06:22:27 +03:00
auto url = URL : : URL ( " about:blank " ) ;
2022-09-19 14:34:36 +03:00
// 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.
2024-01-16 21:04:45 +03:00
auto src_attribute_value = get_attribute_value ( HTML : : AttributeNames : : src ) ;
2023-10-10 14:30:58 +03:00
if ( ! src_attribute_value . is_empty ( ) ) {
2022-09-19 14:34:36 +03:00
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 ( ) ) ;
2024-02-11 10:15:39 +03:00
if ( navigable - > active_document ( ) - > url ( ) . equals ( url , URL : : ExcludeFragment : : Yes ) )
2023-04-13 18:50:09 +03:00
return { } ;
2022-09-19 14:34:36 +03: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 14:34:36 +03:00
if ( url_matches_about_blank ( url ) & & initial_insertion ) {
2024-04-08 19:22:06 +03:00
auto & document = * m_content_navigable - > active_document ( ) ;
perform_url_and_history_update_steps ( document , url ) ;
2022-09-19 14:34:36 +03:00
}
2023-04-13 18:50:09 +03:00
// 5. Return url.
return url ;
2022-09-19 14:34:36 +03:00
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#navigate-an-iframe-or-frame
2024-03-18 06:22:27 +03:00
void NavigableContainer : : navigate_an_iframe_or_frame ( URL : : URL url , ReferrerPolicy : : ReferrerPolicy referrer_policy , Optional < String > srcdoc_string )
2022-09-19 14:34:36 +03: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 14:34:36 +03: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 ( ) ;
2023-10-10 17:05:38 +03:00
MUST ( m_content_navigable - > navigate ( { . url = url ,
. source_document = document ( ) ,
. document_resource = document_resource ,
. history_handling = history_handling ,
. referrer_policy = referrer_policy } ) ) ;
2022-09-19 14:34:36 +03:00
}
2022-12-17 01:28:12 +03: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 ;
2024-04-02 18:10:35 +03:00
// Not in the spec:
// Setting container's content navigable makes document *not* be "fully active".
// Therefore, it is moved to run in afterAllDestruction callback of "destroy a document and its descendants"
// when all queued tasks are done.
// "Has been destroyed" flag is used instead to check whether navigable is already destroyed.
if ( navigable - > has_been_destroyed ( ) )
return ;
navigable - > set_has_been_destroyed ( ) ;
2022-12-17 01:28:12 +03:00
2023-11-04 04:16:52 +03:00
// FIXME: 4. Inform the navigation API about child navigable destruction given navigable.
2024-04-01 00:42:51 +03:00
// 5. Destroy a document and its descendants given navigable's active document.
2024-04-16 23:04:01 +03:00
navigable - > active_document ( ) - > destroy_a_document_and_its_descendants ( JS : : create_heap_function ( heap ( ) , [ this , navigable ] {
2024-04-02 18:10:35 +03:00
// 3. Set container's content navigable to null.
m_content_navigable = nullptr ;
2022-12-17 01:28:12 +03:00
2024-04-03 20:19:40 +03:00
// Not in the spec:
HTML : : all_navigables ( ) . remove ( navigable ) ;
2022-12-17 01:28:12 +03:00
2024-04-03 20:19:40 +03:00
// 6. 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 ( ) ;
// 7. 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 ;
} ) ;
2022-12-17 01:28:12 +03:00
2024-04-03 20:19:40 +03:00
// 8. Let traversable be container's node navigable's traversable navigable.
auto traversable = this - > navigable ( ) - > traversable_navigable ( ) ;
2022-12-17 01:28:12 +03:00
2024-04-03 20:19:40 +03:00
// 9. Append the following session history traversal steps to traversable:
traversable - > append_session_history_traversal_steps ( [ traversable ] {
// 1. Update for navigable creation/destruction given traversable.
traversable - > update_for_navigable_creation_or_destruction ( ) ;
} ) ;
2024-04-16 23:04:01 +03:00
} ) ) ;
2022-12-17 01:28:12 +03:00
}
2023-11-24 18:52:56 +03:00
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#potentially-delays-the-load-event
bool NavigableContainer : : currently_delays_the_load_event ( ) const
{
2024-04-04 19:49:40 +03:00
if ( ! m_content_navigable_initialized )
return true ;
2023-11-24 18:52:56 +03:00
if ( ! m_potentially_delays_the_load_event )
return false ;
// If an element type potentially delays the load event, then for each element element of that type,
// the user agent must delay the load event of element's node document if element's content navigable is non-null
// and any of the following are true:
if ( ! m_content_navigable )
return false ;
// - element's content navigable's active document is not ready for post-load tasks;
if ( ! m_content_navigable - > active_document ( ) - > ready_for_post_load_tasks ( ) )
return true ;
// - element's content navigable's is delaying load events is true; or
if ( m_content_navigable - > is_delaying_load_events ( ) )
return true ;
// - anything is delaying the load event of element's content navigable's active document.
if ( m_content_navigable - > active_document ( ) - > anything_is_delaying_the_load_event ( ) )
return true ;
return false ;
}
2021-04-03 12:43:08 +03:00
}