diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-05-12 15:08:45 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-12 15:08:45 -0500 |
commit | dc8cf694eddca6529bf4b3ac1066764473775192 (patch) | |
tree | 0eb9fd8d4c7dc1c001ea1c2c39653d74304052d1 /components/script/dom | |
parent | 875b07b4ec64d9ef01bafb81ecf01496c0b9fa4b (diff) | |
parent | 727e5b41f5cdb9fb9e7613d2a523aaec0e5692c5 (diff) | |
download | servo-dc8cf694eddca6529bf4b3ac1066764473775192.tar.gz servo-dc8cf694eddca6529bf4b3ac1066764473775192.zip |
Auto merge of #16506 - cbrewster:about_chaos, r=asajeffrey
Make non-initial about:blank loads async
<!-- Please describe your changes on the following line: -->
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #14856 (github issue number if applicable).
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16506)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom')
-rwxr-xr-x | components/script/dom/htmlformelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 134 | ||||
-rw-r--r-- | components/script/dom/node.rs | 9 | ||||
-rw-r--r-- | components/script/dom/window.rs | 6 |
4 files changed, 101 insertions, 50 deletions
diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 4397364f68f..53867c755f8 100755 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -345,7 +345,7 @@ impl HTMLFormElement { let _target = submitter.target(); // TODO: Handle browsing contexts, partially loaded documents (step 16-17) - let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url())); + let mut load_data = LoadData::new(action_components, None, doc.get_referrer_policy(), Some(doc.url())); // Step 18 match (&*scheme, method) { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index e1a7fb7c672..554dc82f7d3 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -44,7 +44,7 @@ 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::{IFrameLoadInfo, IFrameLoadInfoWithData, LoadData, UpdatePipelineIdReason}; use script_traits::{MozBrowserEvent, NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use servo_atoms::Atom; @@ -70,6 +70,12 @@ bitflags! { } #[derive(PartialEq)] +pub enum NavigationType { + InitialAboutBlank, + Regular, +} + +#[derive(PartialEq)] enum ProcessingMode { FirstTime, NotFirstTime, @@ -80,6 +86,7 @@ pub struct HTMLIFrameElement { htmlelement: HTMLElement, frame_id: FrameId, pipeline_id: Cell<Option<PipelineId>>, + pending_pipeline_id: Cell<Option<PipelineId>>, sandbox: MutNullableJS<DOMTokenList>, sandbox_allowance: Cell<Option<SandboxAllowance>>, load_blocker: DOMRefCell<Option<LoadBlocker>>, @@ -108,12 +115,14 @@ impl HTMLIFrameElement { 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) } - pub fn navigate_or_reload_child_browsing_context(&self, load_data: Option<LoadData>, replace: bool) { + pub fn navigate_or_reload_child_browsing_context(&self, + load_data: Option<LoadData>, + nav_type: NavigationType, + replace: bool) { let sandboxed = if self.is_sandboxed() { IFrameSandboxed } else { @@ -136,6 +145,7 @@ impl HTMLIFrameElement { let window = window_from_node(self); let (old_pipeline_id, new_pipeline_id) = self.generate_new_pipeline_id(); + self.pending_pipeline_id.set(Some(new_pipeline_id)); let private_iframe = self.privatebrowsing(); let frame_type = if self.Mozbrowser() { FrameType::MozBrowserIFrame } else { FrameType::IFrame }; @@ -149,37 +159,41 @@ impl HTMLIFrameElement { 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 + match nav_type { + NavigationType::InitialAboutBlank => { + let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap(); + + global_scope + .constellation_chan() + .send(ConstellationMsg::ScriptNewIFrame(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, + }; + + 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, + }; + global_scope .constellation_chan() .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) .unwrap(); + } } if PREFS.is_mozbrowser_enabled() { @@ -192,9 +206,10 @@ impl HTMLIFrameElement { fn process_the_iframe_attributes(&self, mode: ProcessingMode) { // TODO: srcdoc + let window = window_from_node(self); + // https://github.com/whatwg/html/issues/490 if mode == ProcessingMode::FirstTime && !self.upcast::<Element>().has_attribute(&local_name!("src")) { - let window = window_from_node(self); let event_loop = window.dom_manipulation_task_source(); let _ = event_loop.queue(box IFrameLoadEventSteps::new(self), window.upcast()); @@ -205,9 +220,15 @@ impl HTMLIFrameElement { // TODO: check ancestor browsing contexts for same URL + let creator_pipeline_id = if url.as_str() == "about:blank" { + Some(window.upcast::<GlobalScope>().pipeline_id()) + } else { + None + }; + 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); + let load_data = LoadData::new(url, creator_pipeline_id, document.get_referrer_policy(), Some(document.url())); + self.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::Regular, false); } #[allow(unsafe_code)] @@ -225,19 +246,30 @@ impl HTMLIFrameElement { // 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 pipeline_id = Some(window_from_node(self).upcast::<GlobalScope>().pipeline_id()); + let load_data = LoadData::new(url, pipeline_id, document.get_referrer_policy(), Some(document.url().clone())); + self.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::InitialAboutBlank, false); } - pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId) { + 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::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::FramedContentChanged); } fn new_inherited(local_name: LocalName, @@ -247,6 +279,7 @@ impl HTMLIFrameElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), frame_id: FrameId::new(), pipeline_id: Cell::new(None), + pending_pipeline_id: Cell::new(None), sandbox: Default::default(), sandbox_allowance: Cell::new(None), load_blocker: DOMRefCell::new(None), @@ -296,7 +329,7 @@ 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 @@ -330,7 +363,8 @@ impl HTMLIFrameElement { } pub trait HTMLIFrameElementLayoutMethods { - fn pipeline_id(self) -> Option<PipelineId>; + fn pipeline_id(&self) -> Option<PipelineId>; + fn frame_id(&self) -> FrameId; fn get_width(&self) -> LengthOrPercentageOrAuto; fn get_height(&self) -> LengthOrPercentageOrAuto; } @@ -338,12 +372,21 @@ pub trait HTMLIFrameElementLayoutMethods { impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> { #[inline] #[allow(unsafe_code)] - fn pipeline_id(self) -> Option<PipelineId> { + fn pipeline_id(&self) -> Option<PipelineId> { unsafe { (*self.unsafe_get()).pipeline_id.get() } } + #[inline] + #[allow(unsafe_code)] + fn frame_id(&self) -> FrameId { + unsafe { + (*self.unsafe_get()).frame_id + } + } + + #[allow(unsafe_code)] fn get_width(&self) -> LengthOrPercentageOrAuto { unsafe { @@ -563,7 +606,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { 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); + self.navigate_or_reload_child_browsing_context(None, NavigationType::Regular, true); } Ok(()) } else { @@ -739,6 +782,7 @@ impl VirtualMethods for HTMLIFrameElement { // a new iframe. Without this, the constellation gets very // confused. self.pipeline_id.set(None); + self.pending_pipeline_id.set(None); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 31e48b5b695..81a06850757 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -61,7 +61,7 @@ use heapsize::{HeapSizeOf, heap_size_of}; use html5ever::{Prefix, Namespace, QualName}; use js::jsapi::{JSContext, JSObject, JSRuntime}; use libc::{self, c_void, uintptr_t}; -use msg::constellation_msg::PipelineId; +use msg::constellation_msg::{FrameId, PipelineId}; use ref_slice::ref_slice; use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData}; use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress}; @@ -970,6 +970,7 @@ pub trait LayoutNodeHelpers { fn image_url(&self) -> Option<ServoUrl>; fn canvas_data(&self) -> Option<HTMLCanvasData>; fn svg_data(&self) -> Option<SVGSVGData>; + fn iframe_frame_id(&self) -> FrameId; fn iframe_pipeline_id(&self) -> PipelineId; fn opaque(&self) -> OpaqueNode; } @@ -1120,6 +1121,12 @@ impl LayoutNodeHelpers for LayoutJS<Node> { .map(|svg| svg.data()) } + fn iframe_frame_id(&self) -> FrameId { + let iframe_element = self.downcast::<HTMLIFrameElement>() + .expect("not an iframe element!"); + iframe_element.frame_id() + } + fn iframe_pipeline_id(&self) -> PipelineId { let iframe_element = self.downcast::<HTMLIFrameElement>() .expect("not an iframe element!"); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index a2af04ad1cc..b7f5881df83 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1537,10 +1537,10 @@ impl Window { } } + let pipeline_id = self.upcast::<GlobalScope>().pipeline_id(); self.main_thread_script_chan().send( - MainThreadScriptMsg::Navigate(self.upcast::<GlobalScope>().pipeline_id(), - LoadData::new(url, referrer_policy, Some(doc.url())), - replace)).unwrap(); + MainThreadScriptMsg::Navigate(pipeline_id, + LoadData::new(url, Some(pipeline_id), referrer_policy, Some(doc.url())), replace)).unwrap(); } pub fn handle_fire_timer(&self, timer_id: TimerEventId) { |