aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/htmliframeelement.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/htmliframeelement.rs')
-rw-r--r--components/script/dom/htmliframeelement.rs1000
1 files changed, 500 insertions, 500 deletions
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 599f2f69c36..6f5264999be 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -1,75 +1,68 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use document_loader::{LoadBlocker, LoadType};
-use dom::attr::Attr;
-use dom::bindings::cell::DOMRefCell;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementErrorEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementIconChangeEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementLocationChangeEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenTabEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenWindowEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementVisibilityChangeEventDetail;
-use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail;
-use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
-use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
-use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
-use dom::bindings::conversions::ToJSValConvertible;
-use dom::bindings::error::{Error, ErrorResult, Fallible};
-use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{LayoutJS, MutNullableJS, Root};
-use dom::bindings::refcounted::Trusted;
-use dom::bindings::reflector::DomObject;
-use dom::bindings::str::DOMString;
-use dom::browsingcontext::BrowsingContext;
-use dom::customevent::CustomEvent;
-use dom::document::Document;
-use dom::domtokenlist::DOMTokenList;
-use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
-use dom::event::Event;
-use dom::eventtarget::EventTarget;
-use dom::globalscope::GlobalScope;
-use dom::htmlelement::HTMLElement;
-use dom::node::{Node, NodeDamage, UnbindContext, document_from_node, window_from_node};
-use dom::virtualmethods::VirtualMethods;
-use dom::window::{ReflowReason, Window};
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::document_loader::{LoadBlocker, LoadType};
+use crate::dom::attr::Attr;
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
+use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::refcounted::Trusted;
+use crate::dom::bindings::reflector::DomObject;
+use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
+use crate::dom::bindings::str::{DOMString, USVString};
+use crate::dom::document::Document;
+use crate::dom::domtokenlist::DOMTokenList;
+use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers};
+use crate::dom::eventtarget::EventTarget;
+use crate::dom::globalscope::GlobalScope;
+use crate::dom::htmlelement::HTMLElement;
+use crate::dom::node::{
+ document_from_node, window_from_node, BindContext, Node, NodeDamage, UnbindContext,
+};
+use crate::dom::virtualmethods::VirtualMethods;
+use crate::dom::window::ReflowReason;
+use crate::dom::windowproxy::WindowProxy;
+use crate::script_thread::ScriptThread;
+use crate::task_source::TaskSource;
use dom_struct::dom_struct;
-use html5ever_atoms::LocalName;
+use html5ever::{LocalName, Prefix};
use ipc_channel::ipc;
-use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue};
-use js::jsval::{NullValue, UndefinedValue};
-use msg::constellation_msg::{FrameType, FrameId, PipelineId, TraversalDirection};
-use net_traits::response::HttpsState;
-use script_layout_interface::message::ReflowQueryType;
-use script_thread::{ScriptThread, Runnable};
-use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData};
-use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg};
+use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
+use profile_traits::ipc as ProfiledIpc;
+use script_layout_interface::message::ReflowGoal;
use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
+use script_traits::{
+ HistoryEntryReplacement, IFrameLoadInfo, IFrameLoadInfoWithData, JsEvalResult, LoadData,
+ LoadOrigin, UpdatePipelineIdReason, WindowSizeData,
+};
+use script_traits::{NewLayoutInfo, ScriptMsg};
use servo_atoms::Atom;
-use servo_config::prefs::PREFS;
-use servo_config::servo_version;
use servo_url::ServoUrl;
use std::cell::Cell;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
-use style::context::ReflowGoal;
-use task_source::TaskSource;
bitflags! {
- #[derive(JSTraceable, HeapSizeOf)]
- flags SandboxAllowance: u8 {
- const ALLOW_NOTHING = 0x00,
- const ALLOW_SAME_ORIGIN = 0x01,
- const ALLOW_TOP_NAVIGATION = 0x02,
- const ALLOW_FORMS = 0x04,
- const ALLOW_SCRIPTS = 0x08,
- const ALLOW_POINTER_LOCK = 0x10,
- const ALLOW_POPUPS = 0x20
+ #[derive(JSTraceable, MallocSizeOf)]
+ struct SandboxAllowance: u8 {
+ const ALLOW_NOTHING = 0x00;
+ const ALLOW_SAME_ORIGIN = 0x01;
+ const ALLOW_TOP_NAVIGATION = 0x02;
+ const ALLOW_FORMS = 0x04;
+ const ALLOW_SCRIPTS = 0x08;
+ const ALLOW_POINTER_LOCK = 0x10;
+ const ALLOW_POPUPS = 0x20;
}
}
#[derive(PartialEq)]
+pub enum NavigationType {
+ InitialAboutBlank,
+ Regular,
+}
+
+#[derive(PartialEq)]
enum ProcessingMode {
FirstTime,
NotFirstTime,
@@ -78,11 +71,14 @@ enum ProcessingMode {
#[dom_struct]
pub struct HTMLIFrameElement {
htmlelement: HTMLElement,
- frame_id: FrameId,
+ top_level_browsing_context_id: Cell<Option<TopLevelBrowsingContextId>>,
+ browsing_context_id: Cell<Option<BrowsingContextId>>,
pipeline_id: Cell<Option<PipelineId>>,
- sandbox: MutNullableJS<DOMTokenList>,
+ pending_pipeline_id: Cell<Option<PipelineId>>,
+ about_blank_pipeline_id: Cell<Option<PipelineId>>,
+ sandbox: MutNullableDom<DOMTokenList>,
sandbox_allowance: Cell<Option<SandboxAllowance>>,
- load_blocker: DOMRefCell<Option<LoadBlocker>>,
+ load_blocker: DomRefCell<Option<LoadBlocker>>,
visibility: Cell<bool>,
}
@@ -95,172 +91,348 @@ impl HTMLIFrameElement {
/// step 1.
fn get_url(&self) -> ServoUrl {
let element = self.upcast::<Element>();
- element.get_attribute(&ns!(), &local_name!("src")).and_then(|src| {
- let url = src.value();
- if url.is_empty() {
- None
- } else {
- document_from_node(self).base_url().join(&url).ok()
- }
- }).unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap())
- }
-
- pub fn generate_new_pipeline_id(&self) -> (Option<PipelineId>, PipelineId) {
- let old_pipeline_id = self.pipeline_id.get();
- let new_pipeline_id = PipelineId::new();
- self.pipeline_id.set(Some(new_pipeline_id));
- debug!("Frame {} created pipeline {}.", self.frame_id, new_pipeline_id);
- (old_pipeline_id, new_pipeline_id)
+ element
+ .get_attribute(&ns!(), &local_name!("src"))
+ .and_then(|src| {
+ let url = src.value();
+ if url.is_empty() {
+ None
+ } else {
+ document_from_node(self).base_url().join(&url).ok()
+ }
+ })
+ .unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap())
}
- pub fn navigate_or_reload_child_browsing_context(&self, load_data: Option<LoadData>, replace: bool) {
+ pub fn navigate_or_reload_child_browsing_context(
+ &self,
+ mut load_data: LoadData,
+ nav_type: NavigationType,
+ replace: HistoryEntryReplacement,
+ ) {
let sandboxed = if self.is_sandboxed() {
IFrameSandboxed
} else {
IFrameUnsandboxed
};
- let document = document_from_node(self);
+ let browsing_context_id = match self.browsing_context_id() {
+ None => return warn!("Navigating unattached iframe."),
+ Some(id) => id,
+ };
- let mut load_blocker = self.load_blocker.borrow_mut();
- // Any oustanding load is finished from the point of view of the blocked
- // document; the new navigation will continue blocking it.
- LoadBlocker::terminate(&mut load_blocker);
+ let top_level_browsing_context_id = match self.top_level_browsing_context_id() {
+ None => return warn!("Navigating unattached iframe."),
+ Some(id) => id,
+ };
+
+ let document = document_from_node(self);
- //TODO(#9592): Deal with the case where an iframe is being reloaded so url is None.
- // The iframe should always have access to the nested context's active
- // document URL through the browsing context.
- if let Some(ref load_data) = load_data {
- *load_blocker = Some(LoadBlocker::new(&*document, LoadType::Subframe(load_data.url.clone())));
+ {
+ let mut load_blocker = self.load_blocker.borrow_mut();
+ // Any oustanding load is finished from the point of view of the blocked
+ // document; the new navigation will continue blocking it.
+ LoadBlocker::terminate(&mut load_blocker);
+ }
+
+ if load_data.url.scheme() == "javascript" {
+ let window_proxy = self.GetContentWindow();
+ if let Some(window_proxy) = window_proxy {
+ // Important re security. See https://github.com/servo/servo/issues/23373
+ // TODO: check according to https://w3c.github.io/webappsec-csp/#should-block-navigation-request
+ if ScriptThread::check_load_origin(&load_data.load_origin, &document.url().origin())
+ {
+ ScriptThread::eval_js_url(&window_proxy.global(), &mut load_data);
+ }
+ }
}
+ match load_data.js_eval_result {
+ Some(JsEvalResult::NoContent) => (),
+ _ => {
+ let mut load_blocker = self.load_blocker.borrow_mut();
+ *load_blocker = Some(LoadBlocker::new(
+ &*document,
+ LoadType::Subframe(load_data.url.clone()),
+ ));
+ },
+ };
+
let window = window_from_node(self);
- let (old_pipeline_id, new_pipeline_id) = self.generate_new_pipeline_id();
- let private_iframe = self.privatebrowsing();
- let frame_type = if self.Mozbrowser() { FrameType::MozBrowserIFrame } else { FrameType::IFrame };
+ let old_pipeline_id = self.pipeline_id();
+ let new_pipeline_id = PipelineId::new();
+ self.pending_pipeline_id.set(Some(new_pipeline_id));
let global_scope = window.upcast::<GlobalScope>();
let load_info = IFrameLoadInfo {
parent_pipeline_id: global_scope.pipeline_id(),
- frame_id: self.frame_id,
+ browsing_context_id: browsing_context_id,
+ top_level_browsing_context_id: top_level_browsing_context_id,
new_pipeline_id: new_pipeline_id,
- is_private: private_iframe,
- frame_type: frame_type,
+ is_private: false, // FIXME
+ inherited_secure_context: load_data.inherited_secure_context,
replace: replace,
};
- if load_data.as_ref().map_or(false, |d| d.url.as_str() == "about:blank") {
- let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
-
- global_scope
- .constellation_chan()
- .send(ConstellationMsg::ScriptLoadedAboutBlankInIFrame(load_info, pipeline_sender))
- .unwrap();
-
- let new_layout_info = NewLayoutInfo {
- parent_info: Some((global_scope.pipeline_id(), frame_type)),
- new_pipeline_id: new_pipeline_id,
- frame_id: self.frame_id,
- load_data: load_data.unwrap(),
- pipeline_port: pipeline_receiver,
- content_process_shutdown_chan: None,
- window_size: None,
- layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
- };
-
- ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
- } else {
- let load_info = IFrameLoadInfoWithData {
- info: load_info,
- load_data: load_data,
- old_pipeline_id: old_pipeline_id,
- sandbox: sandboxed,
- };
- global_scope
- .constellation_chan()
- .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info))
- .unwrap();
- }
+ let window_size = WindowSizeData {
+ initial_viewport: window
+ .inner_window_dimensions_query(browsing_context_id)
+ .unwrap_or_default(),
+ device_pixel_ratio: window.device_pixel_ratio(),
+ };
- if PREFS.is_mozbrowser_enabled() {
- // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
- self.dispatch_mozbrowser_event(MozBrowserEvent::LoadStart);
+ match nav_type {
+ NavigationType::InitialAboutBlank => {
+ let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
+
+ self.about_blank_pipeline_id.set(Some(new_pipeline_id));
+
+ let load_info = IFrameLoadInfoWithData {
+ info: load_info,
+ load_data: load_data.clone(),
+ old_pipeline_id: old_pipeline_id,
+ sandbox: sandboxed,
+ window_size,
+ };
+ global_scope
+ .script_to_constellation_chan()
+ .send(ScriptMsg::ScriptNewIFrame(load_info, pipeline_sender))
+ .unwrap();
+
+ let new_layout_info = NewLayoutInfo {
+ parent_info: Some(global_scope.pipeline_id()),
+ new_pipeline_id: new_pipeline_id,
+ browsing_context_id: browsing_context_id,
+ top_level_browsing_context_id: top_level_browsing_context_id,
+ opener: None,
+ load_data: load_data,
+ pipeline_port: pipeline_receiver,
+ window_size,
+ };
+
+ self.pipeline_id.set(Some(new_pipeline_id));
+ ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
+ },
+ NavigationType::Regular => {
+ let load_info = IFrameLoadInfoWithData {
+ info: load_info,
+ load_data: load_data,
+ old_pipeline_id: old_pipeline_id,
+ sandbox: sandboxed,
+ window_size,
+ };
+ global_scope
+ .script_to_constellation_chan()
+ .send(ScriptMsg::ScriptLoadedURLInIFrame(load_info))
+ .unwrap();
+ },
}
}
- /// https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes
+ /// <https://html.spec.whatwg.org/multipage/#process-the-iframe-attributes>
fn process_the_iframe_attributes(&self, mode: ProcessingMode) {
- // TODO: srcdoc
-
- // https://github.com/whatwg/html/issues/490
- if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) {
+ if self
+ .upcast::<Element>()
+ .has_attribute(&local_name!("srcdoc"))
+ {
+ let url = ServoUrl::parse("about:srcdoc").unwrap();
+ let document = document_from_node(self);
let window = window_from_node(self);
- let event_loop = window.dom_manipulation_task_source();
- let _ = event_loop.queue(box IFrameLoadEventSteps::new(self),
- window.upcast());
+ let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
+ let mut load_data = LoadData::new(
+ LoadOrigin::Script(document.origin().immutable().clone()),
+ url,
+ pipeline_id,
+ window.upcast::<GlobalScope>().get_referrer(),
+ document.get_referrer_policy(),
+ Some(window.upcast::<GlobalScope>().is_secure_context()),
+ );
+ let element = self.upcast::<Element>();
+ load_data.srcdoc = String::from(element.get_string_attribute(&local_name!("srcdoc")));
+ self.navigate_or_reload_child_browsing_context(
+ load_data,
+ NavigationType::Regular,
+ HistoryEntryReplacement::Disabled,
+ );
return;
}
- let url = self.get_url();
+ let window = window_from_node(self);
- // TODO: check ancestor browsing contexts for same URL
+ // https://html.spec.whatwg.org/multipage/#attr-iframe-name
+ // Note: the spec says to set the name 'when the nested browsing context is created'.
+ // The current implementation sets the name on the window,
+ // when the iframe attributes are first processed.
+ if mode == ProcessingMode::FirstTime {
+ if let Some(window) = self.GetContentWindow() {
+ window.set_name(
+ self.upcast::<Element>()
+ .get_name()
+ .map_or(DOMString::from(""), |n| DOMString::from(&*n)),
+ );
+ }
+ }
- let document = document_from_node(self);
- self.navigate_or_reload_child_browsing_context(
- Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false);
- }
+ // https://github.com/whatwg/html/issues/490
+ if mode == ProcessingMode::FirstTime &&
+ !self.upcast::<Element>().has_attribute(&local_name!("src"))
+ {
+ let this = Trusted::new(self);
+ let pipeline_id = self.pipeline_id().unwrap();
+ // FIXME(nox): Why are errors silenced here?
+ let _ = window.task_manager().dom_manipulation_task_source().queue(
+ task!(iframe_load_event_steps: move || {
+ this.root().iframe_load_event_steps(pipeline_id);
+ }),
+ window.upcast(),
+ );
+ return;
+ }
- #[allow(unsafe_code)]
- pub fn dispatch_mozbrowser_event(&self, event: MozBrowserEvent) {
- assert!(PREFS.is_mozbrowser_enabled());
+ let url = self.get_url();
- if self.Mozbrowser() {
- let window = window_from_node(self);
- let custom_event = build_mozbrowser_custom_event(&window, event);
- custom_event.upcast::<Event>().fire(self.upcast());
+ // TODO(#25748):
+ // By spec, we return early if there's an ancestor browsing context
+ // "whose active document's url, ignoring fragments, is equal".
+ // However, asking about ancestor browsing contexts is more nuanced than
+ // it sounds and not implemented here.
+ // Within a single origin, we can do it by walking window proxies,
+ // and this check covers only that single-origin case, protecting
+ // against simple typo self-includes but nothing more elaborate.
+ let mut ancestor = window.GetParent();
+ while let Some(a) = ancestor {
+ if let Some(ancestor_url) = a.document().map(|d| d.url()) {
+ if ancestor_url.scheme() == url.scheme() &&
+ ancestor_url.username() == url.username() &&
+ ancestor_url.password() == url.password() &&
+ ancestor_url.host() == url.host() &&
+ ancestor_url.port() == url.port() &&
+ ancestor_url.path() == url.path() &&
+ ancestor_url.query() == url.query()
+ {
+ return;
+ }
+ }
+ ancestor = a.parent().map(|p| DomRoot::from_ref(p));
}
+
+ let creator_pipeline_id = if url.as_str() == "about:blank" {
+ Some(window.upcast::<GlobalScope>().pipeline_id())
+ } else {
+ None
+ };
+
+ let document = document_from_node(self);
+ let load_data = LoadData::new(
+ LoadOrigin::Script(document.origin().immutable().clone()),
+ url,
+ creator_pipeline_id,
+ window.upcast::<GlobalScope>().get_referrer(),
+ document.get_referrer_policy(),
+ Some(window.upcast::<GlobalScope>().is_secure_context()),
+ );
+
+ let pipeline_id = self.pipeline_id();
+ // If the initial `about:blank` page is the current page, load with replacement enabled,
+ // see https://html.spec.whatwg.org/multipage/#the-iframe-element:about:blank-3
+ let is_about_blank =
+ pipeline_id.is_some() && pipeline_id == self.about_blank_pipeline_id.get();
+ let replace = if is_about_blank {
+ HistoryEntryReplacement::Enabled
+ } else {
+ HistoryEntryReplacement::Disabled
+ };
+ self.navigate_or_reload_child_browsing_context(load_data, NavigationType::Regular, replace);
}
fn create_nested_browsing_context(&self) {
// Synchronously create a new context and navigate it to about:blank.
let url = ServoUrl::parse("about:blank").unwrap();
let document = document_from_node(self);
- let load_data = LoadData::new(url,
- document.get_referrer_policy(),
- Some(document.url().clone()));
- self.navigate_or_reload_child_browsing_context(Some(load_data), false);
+ let window = window_from_node(self);
+ let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id());
+ let load_data = LoadData::new(
+ LoadOrigin::Script(document.origin().immutable().clone()),
+ url,
+ pipeline_id,
+ window.upcast::<GlobalScope>().get_referrer(),
+ document.get_referrer_policy(),
+ Some(window.upcast::<GlobalScope>().is_secure_context()),
+ );
+ let browsing_context_id = BrowsingContextId::new();
+ let top_level_browsing_context_id = window.window_proxy().top_level_browsing_context_id();
+ self.pipeline_id.set(None);
+ self.pending_pipeline_id.set(None);
+ self.top_level_browsing_context_id
+ .set(Some(top_level_browsing_context_id));
+ self.browsing_context_id.set(Some(browsing_context_id));
+ self.navigate_or_reload_child_browsing_context(
+ load_data,
+ NavigationType::InitialAboutBlank,
+ HistoryEntryReplacement::Disabled,
+ );
}
- pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) {
+ fn destroy_nested_browsing_context(&self) {
+ self.pipeline_id.set(None);
+ self.pending_pipeline_id.set(None);
+ self.about_blank_pipeline_id.set(None);
+ self.top_level_browsing_context_id.set(None);
+ self.browsing_context_id.set(None);
+ }
+
+ pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId, reason: UpdatePipelineIdReason) {
+ if self.pending_pipeline_id.get() != Some(new_pipeline_id) &&
+ reason == UpdatePipelineIdReason::Navigation
+ {
+ return;
+ }
+
self.pipeline_id.set(Some(new_pipeline_id));
- let mut blocker = self.load_blocker.borrow_mut();
- LoadBlocker::terminate(&mut blocker);
+ // Only terminate the load blocker if the pipeline id was updated due to a traversal.
+ // The load blocker will be terminated for a navigation in iframe_load_event_steps.
+ if reason == UpdatePipelineIdReason::Traversal {
+ let mut blocker = self.load_blocker.borrow_mut();
+ LoadBlocker::terminate(&mut blocker);
+ }
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
+ let window = window_from_node(self);
+ window.reflow(ReflowGoal::Full, ReflowReason::FramedContentChanged);
}
- fn new_inherited(local_name: LocalName,
- prefix: Option<DOMString>,
- document: &Document) -> HTMLIFrameElement {
+ fn new_inherited(
+ local_name: LocalName,
+ prefix: Option<Prefix>,
+ document: &Document,
+ ) -> HTMLIFrameElement {
HTMLIFrameElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
- frame_id: FrameId::new(),
+ browsing_context_id: Cell::new(None),
+ top_level_browsing_context_id: Cell::new(None),
pipeline_id: Cell::new(None),
+ pending_pipeline_id: Cell::new(None),
+ about_blank_pipeline_id: Cell::new(None),
sandbox: Default::default(),
sandbox_allowance: Cell::new(None),
- load_blocker: DOMRefCell::new(None),
+ load_blocker: DomRefCell::new(None),
visibility: Cell::new(true),
}
}
#[allow(unrooted_must_root)]
- pub fn new(local_name: LocalName,
- prefix: Option<DOMString>,
- document: &Document) -> Root<HTMLIFrameElement> {
- Node::reflect_node(box HTMLIFrameElement::new_inherited(local_name, prefix, document),
- document,
- HTMLIFrameElementBinding::Wrap)
+ pub fn new(
+ local_name: LocalName,
+ prefix: Option<Prefix>,
+ document: &Document,
+ ) -> DomRoot<HTMLIFrameElement> {
+ Node::reflect_node(
+ Box::new(HTMLIFrameElement::new_inherited(
+ local_name, prefix, document,
+ )),
+ document,
+ )
}
#[inline]
@@ -269,26 +441,18 @@ impl HTMLIFrameElement {
}
#[inline]
- pub fn frame_id(&self) -> FrameId {
- self.frame_id
+ pub fn browsing_context_id(&self) -> Option<BrowsingContextId> {
+ self.browsing_context_id.get()
+ }
+
+ #[inline]
+ pub fn top_level_browsing_context_id(&self) -> Option<TopLevelBrowsingContextId> {
+ self.top_level_browsing_context_id.get()
}
pub fn change_visibility_status(&self, visibility: bool) {
if self.visibility.get() != visibility {
self.visibility.set(visibility);
-
- // Visibility changes are only exposed to Mozbrowser iframes
- if self.Mozbrowser() {
- self.dispatch_mozbrowser_event(MozBrowserEvent::VisibilityChange(visibility));
- }
- }
- }
-
- pub fn set_visible(&self, visible: bool) {
- if let Some(pipeline_id) = self.pipeline_id.get() {
- let window = window_from_node(self);
- let msg = ConstellationMsg::SetVisible(pipeline_id, visible);
- window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
}
}
@@ -296,7 +460,9 @@ impl HTMLIFrameElement {
pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) {
// TODO(#9592): assert that the load blocker is present at all times when we
// can guarantee that it's created for the case of iframe.reload().
- if Some(loaded_pipeline) != self.pipeline_id() { return; }
+ if Some(loaded_pipeline) != self.pending_pipeline_id.get() {
+ return;
+ }
// TODO A cross-origin child document would not be easily accessible
// from this script thread. It's unclear how to implement
@@ -313,211 +479,101 @@ impl HTMLIFrameElement {
// TODO Step 5 - unset child document `mut iframe load` flag
let window = window_from_node(self);
- window.reflow(ReflowGoal::ForDisplay,
- ReflowQueryType::NoQuery,
- ReflowReason::IFrameLoadEvent);
- }
-
- /// Check whether the iframe has the mozprivatebrowsing attribute set
- pub fn privatebrowsing(&self) -> bool {
- if self.Mozbrowser() {
- let element = self.upcast::<Element>();
- element.has_attribute(&LocalName::from("mozprivatebrowsing"))
- } else {
- false
- }
+ window.reflow(ReflowGoal::Full, ReflowReason::IFrameLoadEvent);
}
}
pub trait HTMLIFrameElementLayoutMethods {
fn pipeline_id(self) -> Option<PipelineId>;
- fn get_width(&self) -> LengthOrPercentageOrAuto;
- fn get_height(&self) -> LengthOrPercentageOrAuto;
+ fn browsing_context_id(self) -> Option<BrowsingContextId>;
+ fn get_width(self) -> LengthOrPercentageOrAuto;
+ fn get_height(self) -> LengthOrPercentageOrAuto;
}
-impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> {
+impl HTMLIFrameElementLayoutMethods for LayoutDom<'_, HTMLIFrameElement> {
#[inline]
#[allow(unsafe_code)]
fn pipeline_id(self) -> Option<PipelineId> {
- unsafe {
- (*self.unsafe_get()).pipeline_id.get()
- }
- }
-
- #[allow(unsafe_code)]
- fn get_width(&self) -> LengthOrPercentageOrAuto {
- unsafe {
- (*self.upcast::<Element>().unsafe_get())
- .get_attr_for_layout(&ns!(), &local_name!("width"))
- .map(AttrValue::as_dimension)
- .cloned()
- .unwrap_or(LengthOrPercentageOrAuto::Auto)
- }
+ unsafe { (*self.unsafe_get()).pipeline_id.get() }
}
+ #[inline]
#[allow(unsafe_code)]
- fn get_height(&self) -> LengthOrPercentageOrAuto {
- unsafe {
- (*self.upcast::<Element>().unsafe_get())
- .get_attr_for_layout(&ns!(), &local_name!("height"))
- .map(AttrValue::as_dimension)
- .cloned()
- .unwrap_or(LengthOrPercentageOrAuto::Auto)
- }
+ fn browsing_context_id(self) -> Option<BrowsingContextId> {
+ unsafe { (*self.unsafe_get()).browsing_context_id.get() }
}
-}
-
-#[allow(unsafe_code)]
-pub fn build_mozbrowser_custom_event(window: &Window, event: MozBrowserEvent) -> Root<CustomEvent> {
- // TODO(gw): Support mozbrowser event types that have detail which is not a string.
- // See https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API
- // for a list of mozbrowser events.
- let cx = window.get_cx();
- let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get());
- rooted!(in(cx) let mut detail = UndefinedValue());
- let event_name = Atom::from(event.name());
- unsafe { build_mozbrowser_event_detail(event, cx, detail.handle_mut()); }
- CustomEvent::new(window.upcast(),
- event_name,
- true,
- true,
- detail.handle())
-}
-#[allow(unsafe_code)]
-unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent,
- cx: *mut JSContext,
- rval: MutableHandleValue) {
- match event {
- MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu |
- MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
- MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch |
- MozBrowserEvent::UsernameAndPasswordRequired => {
- rval.set(NullValue());
- }
- MozBrowserEvent::Error(error_type, description, report) => {
- BrowserElementErrorEventDetail {
- type_: Some(DOMString::from(error_type.name())),
- description: Some(DOMString::from(description)),
- report: Some(DOMString::from(report)),
- version: Some(DOMString::from_string(servo_version())),
- }.to_jsval(cx, rval);
- },
- MozBrowserEvent::SecurityChange(https_state) => {
- BrowserElementSecurityChangeDetail {
- // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange
- state: Some(DOMString::from(match https_state {
- HttpsState::Modern => "secure",
- HttpsState::Deprecated => "broken",
- HttpsState::None => "insecure",
- }.to_owned())),
- // FIXME - Not supported yet:
- trackingContent: None,
- mixedContent: None,
- trackingState: None,
- extendedValidation: None,
- mixedState: None,
- }.to_jsval(cx, rval);
- }
- MozBrowserEvent::TitleChange(ref string) => {
- string.to_jsval(cx, rval);
- }
- MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => {
- BrowserElementLocationChangeEventDetail {
- url: Some(DOMString::from(url)),
- canGoBack: Some(can_go_back),
- canGoForward: Some(can_go_forward),
- }.to_jsval(cx, rval);
- }
- MozBrowserEvent::OpenTab(url) => {
- BrowserElementOpenTabEventDetail {
- url: Some(DOMString::from(url)),
- }.to_jsval(cx, rval);
- }
- MozBrowserEvent::OpenWindow(url, target, features) => {
- BrowserElementOpenWindowEventDetail {
- url: Some(DOMString::from(url)),
- target: target.map(DOMString::from),
- features: features.map(DOMString::from),
- }.to_jsval(cx, rval);
- }
- MozBrowserEvent::IconChange(rel, href, sizes) => {
- BrowserElementIconChangeEventDetail {
- rel: Some(DOMString::from(rel)),
- href: Some(DOMString::from(href)),
- sizes: Some(DOMString::from(sizes)),
- }.to_jsval(cx, rval);
- }
- MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value) => {
- BrowserShowModalPromptEventDetail {
- promptType: Some(DOMString::from(prompt_type)),
- title: Some(DOMString::from(title)),
- message: Some(DOMString::from(message)),
- returnValue: Some(DOMString::from(return_value)),
- }.to_jsval(cx, rval)
- }
- MozBrowserEvent::VisibilityChange(visibility) => {
- BrowserElementVisibilityChangeEventDetail {
- visible: Some(visibility),
- }.to_jsval(cx, rval);
- }
+ fn get_width(self) -> LengthOrPercentageOrAuto {
+ self.upcast::<Element>()
+ .get_attr_for_layout(&ns!(), &local_name!("width"))
+ .map(AttrValue::as_dimension)
+ .cloned()
+ .unwrap_or(LengthOrPercentageOrAuto::Auto)
}
-}
-pub fn Navigate(iframe: &HTMLIFrameElement, direction: TraversalDirection) -> ErrorResult {
- if iframe.Mozbrowser() {
- if iframe.upcast::<Node>().is_in_doc_with_browsing_context() {
- let window = window_from_node(iframe);
- let msg = ConstellationMsg::TraverseHistory(iframe.pipeline_id(), direction);
- window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
- }
-
- Ok(())
- } else {
- debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top",
- "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"));
- Err(Error::NotSupported)
+ fn get_height(self) -> LengthOrPercentageOrAuto {
+ self.upcast::<Element>()
+ .get_attr_for_layout(&ns!(), &local_name!("height"))
+ .map(AttrValue::as_dimension)
+ .cloned()
+ .unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}
impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#dom-iframe-src
- fn Src(&self) -> DOMString {
- self.upcast::<Element>().get_string_attribute(&local_name!("src"))
- }
+ make_url_getter!(Src, "src");
// https://html.spec.whatwg.org/multipage/#dom-iframe-src
- fn SetSrc(&self, src: DOMString) {
- self.upcast::<Element>().set_url_attribute(&local_name!("src"), src)
- }
+ make_url_setter!(SetSrc, "src");
+
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_getter!(Srcdoc, "srcdoc");
+
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-srcdoc
+ make_setter!(SetSrcdoc, "srcdoc");
// https://html.spec.whatwg.org/multipage/#dom-iframe-sandbox
- fn Sandbox(&self) -> Root<DOMTokenList> {
- self.sandbox.or_init(|| DOMTokenList::new(self.upcast::<Element>(), &local_name!("sandbox")))
+ fn Sandbox(&self) -> DomRoot<DOMTokenList> {
+ self.sandbox.or_init(|| {
+ DOMTokenList::new(
+ self.upcast::<Element>(),
+ &local_name!("sandbox"),
+ Some(vec![
+ Atom::from("allow-same-origin"),
+ Atom::from("allow-forms"),
+ Atom::from("allow-pointer-lock"),
+ Atom::from("allow-popups"),
+ Atom::from("allow-scripts"),
+ Atom::from("allow-top-navigation"),
+ ]),
+ )
+ })
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentwindow
- fn GetContentWindow(&self) -> Option<Root<BrowsingContext>> {
- self.pipeline_id.get().and_then(|_| ScriptThread::find_browsing_context(self.frame_id))
+ fn GetContentWindow(&self) -> Option<DomRoot<WindowProxy>> {
+ self.browsing_context_id
+ .get()
+ .and_then(|browsing_context_id| ScriptThread::find_window_proxy(browsing_context_id))
}
// https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument
// https://html.spec.whatwg.org/multipage/#concept-bcc-content-document
- fn GetContentDocument(&self) -> Option<Root<Document>> {
+ fn GetContentDocument(&self) -> Option<DomRoot<Document>> {
// Step 1.
- let pipeline_id = match self.pipeline_id.get() {
- None => return None,
- Some(pipeline_id) => pipeline_id,
- };
+ let pipeline_id = self.pipeline_id.get()?;
+
// Step 2-3.
// Note that this lookup will fail if the document is dissimilar-origin,
// so we should return None in that case.
- let document = match ScriptThread::find_document(pipeline_id) {
- None => return None,
- Some(document) => document,
- };
+ let document = ScriptThread::find_document(pipeline_id)?;
+
// Step 4.
- let current = GlobalScope::current().as_window().Document();
+ let current = GlobalScope::current()
+ .expect("No current global object")
+ .as_window()
+ .Document();
if !current.origin().same_origin_domain(document.origin()) {
return None;
}
@@ -525,83 +581,11 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
Some(document)
}
- // Experimental mozbrowser implementation is based on the webidl
- // present in the gecko source tree, and the documentation here:
- // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser
- fn Mozbrowser(&self) -> bool {
- if window_from_node(self).is_mozbrowser() {
- let element = self.upcast::<Element>();
- element.has_attribute(&local_name!("mozbrowser"))
- } else {
- false
- }
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser
- fn SetMozbrowser(&self, value: bool) {
- let element = self.upcast::<Element>();
- element.set_bool_attribute(&local_name!("mozbrowser"), value);
- }
-
// https://html.spec.whatwg.org/multipage/#attr-iframe-allowfullscreen
make_bool_getter!(AllowFullscreen, "allowfullscreen");
// https://html.spec.whatwg.org/multipage/#attr-iframe-allowfullscreen
make_bool_setter!(SetAllowFullscreen, "allowfullscreen");
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack
- fn GoBack(&self) -> ErrorResult {
- Navigate(self, TraversalDirection::Back(1))
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward
- fn GoForward(&self) -> ErrorResult {
- Navigate(self, TraversalDirection::Forward(1))
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload
- fn Reload(&self, _hard_reload: bool) -> ErrorResult {
- if self.Mozbrowser() {
- if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- self.navigate_or_reload_child_browsing_context(None, true);
- }
- Ok(())
- } else {
- debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top",
- "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"));
- Err(Error::NotSupported)
- }
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/setVisible
- fn SetVisible(&self, visible: bool) -> ErrorResult {
- if self.Mozbrowser() {
- self.set_visible(visible);
- Ok(())
- } else {
- debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top",
- "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"));
- Err(Error::NotSupported)
- }
- }
-
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/getVisible
- fn GetVisible(&self) -> Fallible<bool> {
- if self.Mozbrowser() {
- Ok(self.visibility.get())
- } else {
- debug!(concat!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top",
- "level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"));
- Err(Error::NotSupported)
- }
- }
-
-
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/stop
- fn Stop(&self) -> ErrorResult {
- Err(Error::NotSupported)
- }
-
// https://html.spec.whatwg.org/multipage/#dom-dim-width
make_getter!(Width, "width");
// https://html.spec.whatwg.org/multipage/#dom-dim-width
@@ -617,46 +601,58 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
// https://html.spec.whatwg.org/multipage/#other-elements,-attributes-and-apis:attr-iframe-frameborder
make_setter!(SetFrameBorder, "frameborder");
- // check-tidy: no specs after this line
- fn SetMozprivatebrowsing(&self, value: bool) {
- let element = self.upcast::<Element>();
- element.set_bool_attribute(&LocalName::from("mozprivatebrowsing"), value);
- }
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-name
+ // A child browsing context checks the name of its iframe only at the time
+ // it is created; subsequent name sets have no special effect.
+ make_atomic_setter!(SetName, "name");
- fn Mozprivatebrowsing(&self) -> bool {
- if window_from_node(self).is_mozbrowser() {
- let element = self.upcast::<Element>();
- element.has_attribute(&LocalName::from("mozprivatebrowsing"))
- } else {
- false
- }
- }
+ // https://html.spec.whatwg.org/multipage/#dom-iframe-name
+ // This is specified as reflecting the name content attribute of the
+ // element, not the name of the child browsing context.
+ make_getter!(Name, "name");
}
impl VirtualMethods for HTMLIFrameElement {
- fn super_type(&self) -> Option<&VirtualMethods> {
- Some(self.upcast::<HTMLElement>() as &VirtualMethods)
+ fn super_type(&self) -> Option<&dyn VirtualMethods> {
+ Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
match attr.local_name() {
&local_name!("sandbox") => {
- self.sandbox_allowance.set(mutation.new_value(attr).map(|value| {
- let mut modes = ALLOW_NOTHING;
- for token in value.as_tokens() {
- modes |= match &*token.to_ascii_lowercase() {
- "allow-same-origin" => ALLOW_SAME_ORIGIN,
- "allow-forms" => ALLOW_FORMS,
- "allow-pointer-lock" => ALLOW_POINTER_LOCK,
- "allow-popups" => ALLOW_POPUPS,
- "allow-scripts" => ALLOW_SCRIPTS,
- "allow-top-navigation" => ALLOW_TOP_NAVIGATION,
- _ => ALLOW_NOTHING
- };
- }
- modes
- }));
+ self.sandbox_allowance
+ .set(mutation.new_value(attr).map(|value| {
+ let mut modes = SandboxAllowance::ALLOW_NOTHING;
+ for token in value.as_tokens() {
+ modes |= match &*token.to_ascii_lowercase() {
+ "allow-same-origin" => SandboxAllowance::ALLOW_SAME_ORIGIN,
+ "allow-forms" => SandboxAllowance::ALLOW_FORMS,
+ "allow-pointer-lock" => SandboxAllowance::ALLOW_POINTER_LOCK,
+ "allow-popups" => SandboxAllowance::ALLOW_POPUPS,
+ "allow-scripts" => SandboxAllowance::ALLOW_SCRIPTS,
+ "allow-top-navigation" => SandboxAllowance::ALLOW_TOP_NAVIGATION,
+ _ => SandboxAllowance::ALLOW_NOTHING,
+ };
+ }
+ modes
+ }));
+ },
+ &local_name!("srcdoc") => {
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element:the-iframe-element-9
+ // "Whenever an iframe element with a non-null nested browsing context has its
+ // srcdoc attribute set, changed, or removed, the user agent must process the
+ // iframe attributes."
+ // but we can't check that directly, since the child browsing context
+ // may be in a different script thread. Instead, we check to see if the parent
+ // is in a document tree and has a browsing context, which is what causes
+ // the child browsing context to be created.
+
+ // trigger the processing of iframe attributes whenever "srcdoc" attribute is set, changed or removed
+ if self.upcast::<Node>().is_connected_with_browsing_context() {
+ debug!("iframe srcdoc modified while in browsing context.");
+ self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
+ }
},
&local_name!("src") => {
// https://html.spec.whatwg.org/multipage/#the-iframe-element
@@ -664,11 +660,11 @@ impl VirtualMethods for HTMLIFrameElement {
// but with no srcdoc attribute specified has its src attribute set, changed, or removed,
// the user agent must process the iframe attributes,"
// but we can't check that directly, since the child browsing context
- // may be in a different script thread. Instread, we check to see if the parent
+ // may be in a different script thread. Instead, we check to see if the parent
// is in a document tree and has a browsing context, which is what causes
// the child browsing context to be created.
- if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- debug!("iframe {} src set while in browsing context.", self.frame_id);
+ if self.upcast::<Node>().is_connected_with_browsing_context() {
+ debug!("iframe src set while in browsing context.");
self.process_the_iframe_attributes(ProcessingMode::NotFirstTime);
}
},
@@ -681,27 +677,35 @@ impl VirtualMethods for HTMLIFrameElement {
&local_name!("sandbox") => AttrValue::from_serialized_tokenlist(value.into()),
&local_name!("width") => AttrValue::from_dimension(value.into()),
&local_name!("height") => AttrValue::from_dimension(value.into()),
- _ => self.super_type().unwrap().parse_plain_attribute(name, value),
+ _ => self
+ .super_type()
+ .unwrap()
+ .parse_plain_attribute(name, value),
}
}
- fn bind_to_tree(&self, tree_in_doc: bool) {
+ fn bind_to_tree(&self, context: &BindContext) {
if let Some(ref s) = self.super_type() {
- s.bind_to_tree(tree_in_doc);
- }
-
- // https://html.spec.whatwg.org/multipage/#the-iframe-element
- // "When an iframe element is inserted into a document that has
- // a browsing context, the user agent must create a new
- // browsing context, set the element's nested browsing context
- // to the newly-created browsing context, and then process the
- // iframe attributes for the "first time"."
- if self.upcast::<Node>().is_in_doc_with_browsing_context() {
- debug!("iframe {} bound to browsing context.", self.frame_id);
- debug_assert!(tree_in_doc, "is_in_doc_with_bc, but not tree_in_doc");
- self.create_nested_browsing_context();
- self.process_the_iframe_attributes(ProcessingMode::FirstTime);
- }
+ s.bind_to_tree(context);
+ }
+
+ let tree_connected = context.tree_connected;
+ let iframe = Trusted::new(self);
+ document_from_node(self).add_delayed_task(task!(IFrameDelayedInitialize: move || {
+ let this = iframe.root();
+ // https://html.spec.whatwg.org/multipage/#the-iframe-element
+ // "When an iframe element is inserted into a document that has
+ // a browsing context, the user agent must create a new
+ // browsing context, set the element's nested browsing context
+ // to the newly-created browsing context, and then process the
+ // iframe attributes for the "first time"."
+ if this.upcast::<Node>().is_connected_with_browsing_context() {
+ debug!("iframe bound to browsing context.");
+ debug_assert!(tree_connected, "is_connected_with_bc, but not tree_connected");
+ this.create_nested_browsing_context();
+ this.process_the_iframe_attributes(ProcessingMode::FirstTime);
+ }
+ }));
}
fn unbind_from_tree(&self, context: &UnbindContext) {
@@ -711,24 +715,41 @@ impl VirtualMethods for HTMLIFrameElement {
LoadBlocker::terminate(&mut blocker);
// https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
- debug!("Unbinding frame {}.", self.frame_id);
let window = window_from_node(self);
- let (sender, receiver) = ipc::channel().unwrap();
+ let (sender, receiver) =
+ ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
// Ask the constellation to remove the iframe, and tell us the
// pipeline ids of the closed pipelines.
- let msg = ConstellationMsg::RemoveIFrame(self.frame_id, sender);
- window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
+ let browsing_context_id = match self.browsing_context_id() {
+ None => return warn!("Unbinding already unbound iframe."),
+ Some(id) => id,
+ };
+ debug!("Unbinding frame {}.", browsing_context_id);
+
+ let msg = ScriptMsg::RemoveIFrame(browsing_context_id, sender);
+ window
+ .upcast::<GlobalScope>()
+ .script_to_constellation_chan()
+ .send(msg)
+ .unwrap();
let exited_pipeline_ids = receiver.recv().unwrap();
// The spec for discarding is synchronous,
// so we need to discard the browsing contexts now, rather than
// when the `PipelineExit` message arrives.
for exited_pipeline_id in exited_pipeline_ids {
+ // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
if let Some(exited_document) = ScriptThread::find_document(exited_pipeline_id) {
- exited_document.window().browsing_context().discard();
+ debug!(
+ "Discarding browsing context for pipeline {}",
+ exited_pipeline_id
+ );
+ let exited_window = exited_document.window();
+ exited_window.discard_browsing_context();
for exited_iframe in exited_document.iter_iframes() {
- exited_iframe.pipeline_id.set(None);
+ debug!("Discarding nested browsing context");
+ exited_iframe.destroy_nested_browsing_context();
}
}
}
@@ -738,27 +759,6 @@ impl VirtualMethods for HTMLIFrameElement {
// the load doesn't think that it's a navigation, but instead
// a new iframe. Without this, the constellation gets very
// confused.
- self.pipeline_id.set(None);
- }
-}
-
-struct IFrameLoadEventSteps {
- frame_element: Trusted<HTMLIFrameElement>,
- pipeline_id: PipelineId,
-}
-
-impl IFrameLoadEventSteps {
- fn new(frame_element: &HTMLIFrameElement) -> IFrameLoadEventSteps {
- IFrameLoadEventSteps {
- frame_element: Trusted::new(frame_element),
- pipeline_id: frame_element.pipeline_id().unwrap(),
- }
- }
-}
-
-impl Runnable for IFrameLoadEventSteps {
- fn handler(self: Box<IFrameLoadEventSteps>) {
- let this = self.frame_element.root();
- this.iframe_load_event_steps(self.pipeline_id);
+ self.destroy_nested_browsing_context();
}
}