mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Implement browsing context discarding.
This commit is contained in:
parent
143dfc879e
commit
7c2de62124
12 changed files with 196 additions and 160 deletions
|
@ -95,7 +95,7 @@ use profile_traits::mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use rand::{Rng, SeedableRng, StdRng, random};
|
use rand::{Rng, SeedableRng, StdRng, random};
|
||||||
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
||||||
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg};
|
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
|
||||||
use script_traits::{DocumentState, LayoutControlMsg, LoadData};
|
use script_traits::{DocumentState, LayoutControlMsg, LoadData};
|
||||||
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
|
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
|
||||||
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
||||||
|
@ -975,13 +975,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
debug!("constellation got set visibility change complete message");
|
debug!("constellation got set visibility change complete message");
|
||||||
self.handle_visibility_change_complete(pipeline_id, visible);
|
self.handle_visibility_change_complete(pipeline_id, visible);
|
||||||
}
|
}
|
||||||
FromScriptMsg::RemoveIFrame(pipeline_id, sender) => {
|
FromScriptMsg::RemoveIFrame(frame_id, sender) => {
|
||||||
debug!("constellation got remove iframe message");
|
debug!("constellation got remove iframe message");
|
||||||
self.handle_remove_iframe_msg(pipeline_id);
|
let removed_pipeline_ids = self.handle_remove_iframe_msg(frame_id);
|
||||||
if let Some(sender) = sender {
|
if let Err(e) = sender.send(removed_pipeline_ids) {
|
||||||
if let Err(e) = sender.send(()) {
|
warn!("Error replying to remove iframe ({})", e);
|
||||||
warn!("Error replying to remove iframe ({})", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FromScriptMsg::NewFavicon(url) => {
|
FromScriptMsg::NewFavicon(url) => {
|
||||||
|
@ -1126,7 +1124,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
debug!("Removing pending frame {}.", pending.frame_id);
|
debug!("Removing pending frame {}.", pending.frame_id);
|
||||||
self.close_frame(pending.frame_id, ExitPipelineMode::Normal);
|
self.close_frame(pending.frame_id, ExitPipelineMode::Normal);
|
||||||
debug!("Removing pending pipeline {}.", pending.new_pipeline_id);
|
debug!("Removing pending pipeline {}.", pending.new_pipeline_id);
|
||||||
self.close_pipeline(pending.new_pipeline_id, ExitPipelineMode::Normal);
|
self.close_pipeline(pending.new_pipeline_id, DiscardBrowsingContext::Yes, ExitPipelineMode::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case there are frames which weren't attached to the frame tree, we close them.
|
// In case there are frames which weren't attached to the frame tree, we close them.
|
||||||
|
@ -1140,7 +1138,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
let pipeline_ids: Vec<PipelineId> = self.pipelines.keys().cloned().collect();
|
let pipeline_ids: Vec<PipelineId> = self.pipelines.keys().cloned().collect();
|
||||||
for pipeline_id in pipeline_ids {
|
for pipeline_id in pipeline_ids {
|
||||||
debug!("Removing detached pipeline {}.", pipeline_id);
|
debug!("Removing detached pipeline {}.", pipeline_id);
|
||||||
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal);
|
self.close_pipeline(pipeline_id, DiscardBrowsingContext::Yes, ExitPipelineMode::Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1234,7 +1232,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
let parent_info = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.parent_info));
|
let parent_info = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.parent_info));
|
||||||
let window_size = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.size));
|
let window_size = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.size));
|
||||||
|
|
||||||
self.close_frame_children(top_level_frame_id, ExitPipelineMode::Force);
|
self.close_frame_children(top_level_frame_id, DiscardBrowsingContext::No, ExitPipelineMode::Force);
|
||||||
|
|
||||||
let failure_url = ServoUrl::parse("about:failure").expect("infallible");
|
let failure_url = ServoUrl::parse("about:failure").expect("infallible");
|
||||||
|
|
||||||
|
@ -1805,20 +1803,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.focus_parent_pipeline(pipeline_id);
|
self.focus_parent_pipeline(pipeline_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_remove_iframe_msg(&mut self, pipeline_id: PipelineId) {
|
fn handle_remove_iframe_msg(&mut self, frame_id: FrameId) -> Vec<PipelineId> {
|
||||||
let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
|
let result = self.full_frame_tree_iter(frame_id)
|
||||||
match frame_id {
|
.flat_map(|frame| frame.next.iter().chain(frame.prev.iter())
|
||||||
Some(frame_id) => {
|
.filter_map(|entry| entry.pipeline_id)
|
||||||
// This iframe has already loaded and been added to the frame tree.
|
.chain(once(frame.pipeline_id)))
|
||||||
self.close_frame(frame_id, ExitPipelineMode::Normal);
|
.collect();
|
||||||
}
|
self.close_frame(frame_id, ExitPipelineMode::Normal);
|
||||||
None => {
|
result
|
||||||
// This iframe is currently loading / painting for the first time.
|
|
||||||
// In this case, it doesn't exist in the frame tree, but the pipeline
|
|
||||||
// still needs to be shut down.
|
|
||||||
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) {
|
fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) {
|
||||||
|
@ -2118,7 +2110,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(evicted_id) = evicted_id {
|
if let Some(evicted_id) = evicted_id {
|
||||||
self.close_pipeline(evicted_id, ExitPipelineMode::Normal);
|
self.close_pipeline(evicted_id, DiscardBrowsingContext::No, ExitPipelineMode::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_frame {
|
if new_frame {
|
||||||
|
@ -2344,7 +2336,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
};
|
};
|
||||||
for entry in evicted {
|
for entry in evicted {
|
||||||
if let Some(pipeline_id) = entry.pipeline_id {
|
if let Some(pipeline_id) = entry.pipeline_id {
|
||||||
self.close_pipeline(pipeline_id, ExitPipelineMode::Normal);
|
self.close_pipeline(pipeline_id, DiscardBrowsingContext::No, ExitPipelineMode::Normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2357,7 +2349,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
.and_then(|frame| self.pipelines.get(&frame.pipeline_id))
|
.and_then(|frame| self.pipelines.get(&frame.pipeline_id))
|
||||||
.and_then(|pipeline| pipeline.parent_info);
|
.and_then(|pipeline| pipeline.parent_info);
|
||||||
|
|
||||||
self.close_frame_children(frame_id, exit_mode);
|
self.close_frame_children(frame_id, DiscardBrowsingContext::Yes, exit_mode);
|
||||||
|
|
||||||
self.event_loops.remove(&frame_id);
|
self.event_loops.remove(&frame_id);
|
||||||
if self.frames.remove(&frame_id).is_none() {
|
if self.frames.remove(&frame_id).is_none() {
|
||||||
|
@ -2375,7 +2367,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the children of a frame
|
// Close the children of a frame
|
||||||
fn close_frame_children(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
|
fn close_frame_children(&mut self, frame_id: FrameId, dbc: DiscardBrowsingContext, exit_mode: ExitPipelineMode) {
|
||||||
debug!("Closing frame children {}.", frame_id);
|
debug!("Closing frame children {}.", frame_id);
|
||||||
// Store information about the pipelines to be closed. Then close the
|
// Store information about the pipelines to be closed. Then close the
|
||||||
// pipelines, before removing ourself from the frames hash map. This
|
// pipelines, before removing ourself from the frames hash map. This
|
||||||
|
@ -2393,18 +2385,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
|
|
||||||
for pipeline_id in pipelines_to_close {
|
for pipeline_id in pipelines_to_close {
|
||||||
self.close_pipeline(pipeline_id, exit_mode);
|
self.close_pipeline(pipeline_id, dbc, exit_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Closed frame children {}.", frame_id);
|
debug!("Closed frame children {}.", frame_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close all pipelines at and beneath a given frame
|
// Close all pipelines at and beneath a given frame
|
||||||
fn close_pipeline(&mut self, pipeline_id: PipelineId, exit_mode: ExitPipelineMode) {
|
fn close_pipeline(&mut self, pipeline_id: PipelineId, dbc: DiscardBrowsingContext, exit_mode: ExitPipelineMode) {
|
||||||
debug!("Closing pipeline {:?}.", pipeline_id);
|
debug!("Closing pipeline {:?}.", pipeline_id);
|
||||||
// Store information about the frames to be closed. Then close the
|
// Store information about the frames to be closed. Then close the
|
||||||
// frames, before removing ourself from the pipelines hash map. This
|
// frames, before removing ourself from the pipelines hash map. This
|
||||||
// ordering is vital - so that if close_frames() ends up closing
|
// ordering is vital - so that if close_frame() ends up closing
|
||||||
// any child pipelines, they can be removed from the parent pipeline correctly.
|
// any child pipelines, they can be removed from the parent pipeline correctly.
|
||||||
let frames_to_close = {
|
let frames_to_close = {
|
||||||
let mut frames_to_close = vec!();
|
let mut frames_to_close = vec!();
|
||||||
|
@ -2438,8 +2430,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
|
|
||||||
// Inform script, compositor that this pipeline has exited.
|
// Inform script, compositor that this pipeline has exited.
|
||||||
match exit_mode {
|
match exit_mode {
|
||||||
ExitPipelineMode::Normal => pipeline.exit(),
|
ExitPipelineMode::Normal => pipeline.exit(dbc),
|
||||||
ExitPipelineMode::Force => pipeline.force_exit(),
|
ExitPipelineMode::Force => pipeline.force_exit(dbc),
|
||||||
}
|
}
|
||||||
debug!("Closed pipeline {:?}.", pipeline_id);
|
debug!("Closed pipeline {:?}.", pipeline_id);
|
||||||
}
|
}
|
||||||
|
@ -2463,7 +2455,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
// Note that we deliberately do not do any of the tidying up
|
// Note that we deliberately do not do any of the tidying up
|
||||||
// associated with closing a pipeline. The constellation should cope!
|
// associated with closing a pipeline. The constellation should cope!
|
||||||
warn!("Randomly closing pipeline {}.", pipeline_id);
|
warn!("Randomly closing pipeline {}.", pipeline_id);
|
||||||
pipeline.force_exit();
|
pipeline.force_exit(DiscardBrowsingContext::No);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use net_traits::{IpcSend, ResourceThreads};
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use profile_traits::mem as profile_mem;
|
use profile_traits::mem as profile_mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{ConstellationControlMsg, InitialScriptState};
|
use script_traits::{ConstellationControlMsg, DiscardBrowsingContext, InitialScriptState};
|
||||||
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
|
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
|
||||||
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
|
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
|
||||||
use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
|
use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
|
||||||
|
@ -328,7 +328,7 @@ impl Pipeline {
|
||||||
|
|
||||||
/// A normal exit of the pipeline, which waits for the compositor,
|
/// A normal exit of the pipeline, which waits for the compositor,
|
||||||
/// and delegates layout shutdown to the script thread.
|
/// and delegates layout shutdown to the script thread.
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self, discard_bc: DiscardBrowsingContext) {
|
||||||
debug!("pipeline {:?} exiting", self.id);
|
debug!("pipeline {:?} exiting", self.id);
|
||||||
|
|
||||||
// The compositor wants to know when pipelines shut down too.
|
// The compositor wants to know when pipelines shut down too.
|
||||||
|
@ -345,15 +345,17 @@ impl Pipeline {
|
||||||
|
|
||||||
// Script thread handles shutting down layout, and layout handles shutting down the painter.
|
// Script thread handles shutting down layout, and layout handles shutting down the painter.
|
||||||
// For now, if the script thread has failed, we give up on clean shutdown.
|
// For now, if the script thread has failed, we give up on clean shutdown.
|
||||||
if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) {
|
let msg = ConstellationControlMsg::ExitPipeline(self.id, discard_bc);
|
||||||
|
if let Err(e) = self.event_loop.send(msg) {
|
||||||
warn!("Sending script exit message failed ({}).", e);
|
warn!("Sending script exit message failed ({}).", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A forced exit of the shutdown, which does not wait for the compositor,
|
/// A forced exit of the shutdown, which does not wait for the compositor,
|
||||||
/// or for the script thread to shut down layout.
|
/// or for the script thread to shut down layout.
|
||||||
pub fn force_exit(&self) {
|
pub fn force_exit(&self, discard_bc: DiscardBrowsingContext) {
|
||||||
if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) {
|
let msg = ConstellationControlMsg::ExitPipeline(self.id, discard_bc);
|
||||||
|
if let Err(e) = self.event_loop.send(msg) {
|
||||||
warn!("Sending script exit message failed ({}).", e);
|
warn!("Sending script exit message failed ({}).", e);
|
||||||
}
|
}
|
||||||
if let Err(e) = self.layout_chan.send(LayoutControlMsg::ExitNow) {
|
if let Err(e) = self.layout_chan.send(LayoutControlMsg::ExitNow) {
|
||||||
|
|
|
@ -3,16 +3,13 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
|
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
|
||||||
use dom::bindings::inheritance::Castable;
|
use dom::bindings::js::{JS, Root, RootedReference};
|
||||||
use dom::bindings::js::{JS, MutNullableJS, Root, RootedReference};
|
|
||||||
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
|
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
|
||||||
use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
|
use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
|
||||||
use dom::bindings::trace::JSTraceable;
|
use dom::bindings::trace::JSTraceable;
|
||||||
use dom::bindings::utils::WindowProxyHandler;
|
use dom::bindings::utils::WindowProxyHandler;
|
||||||
use dom::bindings::utils::get_array_index_from_id;
|
use dom::bindings::utils::get_array_index_from_id;
|
||||||
use dom::document::Document;
|
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::globalscope::GlobalScope;
|
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use js::JSCLASS_IS_GLOBAL;
|
use js::JSCLASS_IS_GLOBAL;
|
||||||
use js::glue::{CreateWrapperProxyHandler, ProxyTraps, NewWindowProxy};
|
use js::glue::{CreateWrapperProxyHandler, ProxyTraps, NewWindowProxy};
|
||||||
|
@ -26,7 +23,6 @@ use js::jsapi::{MutableHandle, MutableHandleObject, MutableHandleValue};
|
||||||
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
|
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
|
||||||
use js::jsval::{UndefinedValue, PrivateValue};
|
use js::jsval::{UndefinedValue, PrivateValue};
|
||||||
use js::rust::get_object_class;
|
use js::rust::get_object_class;
|
||||||
use msg::constellation_msg::PipelineId;
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -40,10 +36,8 @@ pub struct BrowsingContext {
|
||||||
/// Indicates if reflow is required when reloading.
|
/// Indicates if reflow is required when reloading.
|
||||||
needs_reflow: Cell<bool>,
|
needs_reflow: Cell<bool>,
|
||||||
|
|
||||||
/// The current active document.
|
/// Has this browsing context been discarded?
|
||||||
/// Note that the session history is stored in the constellation,
|
discarded: Cell<bool>,
|
||||||
/// in the script thread we just track the current active document.
|
|
||||||
active_document: MutNullableJS<Document>,
|
|
||||||
|
|
||||||
/// The containing iframe element, if this is a same-origin iframe
|
/// The containing iframe element, if this is a same-origin iframe
|
||||||
frame_element: Option<JS<Element>>,
|
frame_element: Option<JS<Element>>,
|
||||||
|
@ -54,7 +48,7 @@ impl BrowsingContext {
|
||||||
BrowsingContext {
|
BrowsingContext {
|
||||||
reflector: Reflector::new(),
|
reflector: Reflector::new(),
|
||||||
needs_reflow: Cell::new(true),
|
needs_reflow: Cell::new(true),
|
||||||
active_document: Default::default(),
|
discarded: Cell::new(false),
|
||||||
frame_element: frame_element.map(JS::from_ref),
|
frame_element: frame_element.map(JS::from_ref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,20 +78,12 @@ impl BrowsingContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_active_document(&self, document: &Document) {
|
pub fn discard(&self) {
|
||||||
self.active_document.set(Some(document))
|
self.discarded.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_document(&self) -> Root<Document> {
|
pub fn is_discarded(&self) -> bool {
|
||||||
self.active_document.get().expect("No active document.")
|
self.discarded.get()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maybe_active_document(&self) -> Option<Root<Document>> {
|
|
||||||
self.active_document.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn active_window(&self) -> Root<Window> {
|
|
||||||
Root::from_ref(self.active_document().window())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame_element(&self) -> Option<&Element> {
|
pub fn frame_element(&self) -> Option<&Element> {
|
||||||
|
@ -115,15 +101,6 @@ impl BrowsingContext {
|
||||||
self.needs_reflow.set(status);
|
self.needs_reflow.set(status);
|
||||||
old
|
old
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_pipeline_id(&self) -> Option<PipelineId> {
|
|
||||||
self.active_document.get()
|
|
||||||
.map(|doc| doc.window().upcast::<GlobalScope>().pipeline_id())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unset_active_document(&self) {
|
|
||||||
self.active_document.set(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
|
@ -190,6 +190,7 @@ pub struct Document {
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
encoding: Cell<EncodingRef>,
|
encoding: Cell<EncodingRef>,
|
||||||
is_html_document: bool,
|
is_html_document: bool,
|
||||||
|
is_fully_active: Cell<bool>,
|
||||||
url: DOMRefCell<ServoUrl>,
|
url: DOMRefCell<ServoUrl>,
|
||||||
quirks_mode: Cell<QuirksMode>,
|
quirks_mode: Cell<QuirksMode>,
|
||||||
/// Caches for the getElement methods
|
/// Caches for the getElement methods
|
||||||
|
@ -385,20 +386,17 @@ impl Document {
|
||||||
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
|
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#active-document
|
|
||||||
pub fn is_active(&self) -> bool {
|
|
||||||
self.browsing_context().map_or(false, |context| {
|
|
||||||
self == &*context.active_document()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#fully-active
|
// https://html.spec.whatwg.org/multipage/#fully-active
|
||||||
pub fn is_fully_active(&self) -> bool {
|
pub fn is_fully_active(&self) -> bool {
|
||||||
if !self.is_active() {
|
self.is_fully_active.get()
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
// FIXME: It should also check whether the browser context is top-level or not
|
pub fn fully_activate(&self) {
|
||||||
true
|
self.is_fully_active.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fully_deactivate(&self) {
|
||||||
|
self.is_fully_active.set(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn origin(&self) -> &Origin {
|
pub fn origin(&self) -> &Origin {
|
||||||
|
@ -1693,11 +1691,16 @@ impl Document {
|
||||||
self.current_parser.get()
|
self.current_parser.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find an iframe element in the document.
|
/// Iterate over all iframes in the document.
|
||||||
pub fn find_iframe(&self, frame_id: FrameId) -> Option<Root<HTMLIFrameElement>> {
|
pub fn iter_iframes(&self) -> impl Iterator<Item=Root<HTMLIFrameElement>> {
|
||||||
self.upcast::<Node>()
|
self.upcast::<Node>()
|
||||||
.traverse_preorder()
|
.traverse_preorder()
|
||||||
.filter_map(Root::downcast::<HTMLIFrameElement>)
|
.filter_map(Root::downcast::<HTMLIFrameElement>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find an iframe element in the document.
|
||||||
|
pub fn find_iframe(&self, frame_id: FrameId) -> Option<Root<HTMLIFrameElement>> {
|
||||||
|
self.iter_iframes()
|
||||||
.find(|node| node.frame_id() == frame_id)
|
.find(|node| node.frame_id() == frame_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1864,6 +1867,7 @@ impl Document {
|
||||||
// https://dom.spec.whatwg.org/#concept-document-encoding
|
// https://dom.spec.whatwg.org/#concept-document-encoding
|
||||||
encoding: Cell::new(UTF_8),
|
encoding: Cell::new(UTF_8),
|
||||||
is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
|
is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
|
||||||
|
is_fully_active: Cell::new(false),
|
||||||
id_map: DOMRefCell::new(HashMap::new()),
|
id_map: DOMRefCell::new(HashMap::new()),
|
||||||
tag_map: DOMRefCell::new(HashMap::new()),
|
tag_map: DOMRefCell::new(HashMap::new()),
|
||||||
tagns_map: DOMRefCell::new(HashMap::new()),
|
tagns_map: DOMRefCell::new(HashMap::new()),
|
||||||
|
@ -2261,19 +2265,12 @@ impl DocumentMethods for Document {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-document-hasfocus
|
// https://html.spec.whatwg.org/multipage/#dom-document-hasfocus
|
||||||
fn HasFocus(&self) -> bool {
|
fn HasFocus(&self) -> bool {
|
||||||
match self.browsing_context() {
|
// Step 1-2.
|
||||||
Some(browsing_context) => {
|
if self.window().parent_info().is_none() && self.is_fully_active() {
|
||||||
// Step 2.
|
return true;
|
||||||
let candidate = browsing_context.active_document();
|
|
||||||
// Step 3.
|
|
||||||
if &*candidate == self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false //TODO Step 4.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
}
|
||||||
|
// TODO Step 3.
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#relaxing-the-same-origin-restriction
|
// https://html.spec.whatwg.org/multipage/#relaxing-the-same-origin-restriction
|
||||||
|
@ -3190,8 +3187,8 @@ impl DocumentMethods for Document {
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
// TODO: handle throw-on-dynamic-markup-insertion counter.
|
// TODO: handle throw-on-dynamic-markup-insertion counter.
|
||||||
|
// FIXME: this should check for being active rather than fully active
|
||||||
if !self.is_active() {
|
if !self.is_fully_active() {
|
||||||
// Step 3.
|
// Step 3.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ use dom::eventtarget::EventTarget;
|
||||||
use dom::globalscope::GlobalScope;
|
use dom::globalscope::GlobalScope;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, NodeDamage, UnbindContext, document_from_node, window_from_node};
|
use dom::node::{Node, NodeDamage, UnbindContext, document_from_node, window_from_node};
|
||||||
use dom::urlhelper::UrlHelper;
|
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use dom::window::{ReflowReason, Window};
|
use dom::window::{ReflowReason, Window};
|
||||||
use html5ever_atoms::LocalName;
|
use html5ever_atoms::LocalName;
|
||||||
|
@ -709,42 +708,34 @@ impl VirtualMethods for HTMLIFrameElement {
|
||||||
LoadBlocker::terminate(&mut blocker);
|
LoadBlocker::terminate(&mut blocker);
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
|
// https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded
|
||||||
if let Some(pipeline_id) = self.pipeline_id.get() {
|
debug!("Unbinding frame {}.", self.frame_id);
|
||||||
debug!("Unbinding pipeline {} from frame {}.", pipeline_id, self.frame_id);
|
let window = window_from_node(self);
|
||||||
let window = window_from_node(self);
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
// The only reason we're waiting for the iframe to be totally
|
// Ask the constellation to remove the iframe, and tell us the
|
||||||
// removed is to ensure the script thread can't add iframes faster
|
// pipeline ids of the closed pipelines.
|
||||||
// than the compositor can remove them.
|
let msg = ConstellationMsg::RemoveIFrame(self.frame_id, sender);
|
||||||
//
|
window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
|
||||||
// Since most of this cleanup doesn't happen on same-origin
|
let exited_pipeline_ids = receiver.recv().unwrap();
|
||||||
// iframes, and since that would cause a deadlock, don't do it.
|
|
||||||
let same_origin = {
|
// The spec for discarding is synchronous,
|
||||||
// FIXME(#10968): this should probably match the origin check in
|
// so we need to discard the browsing contexts now, rather than
|
||||||
// HTMLIFrameElement::contentDocument.
|
// when the `PipelineExit` message arrives.
|
||||||
let self_url = self.get_url();
|
for exited_pipeline_id in exited_pipeline_ids {
|
||||||
let win_url = window_from_node(self).get_url();
|
if let Some(exited_document) = ScriptThread::find_document(exited_pipeline_id) {
|
||||||
UrlHelper::SameOrigin(&self_url, &win_url) || self_url.as_str() == "about:blank"
|
exited_document.window().browsing_context().discard();
|
||||||
};
|
for exited_iframe in exited_document.iter_iframes() {
|
||||||
let (sender, receiver) = if same_origin {
|
exited_iframe.pipeline_id.set(None);
|
||||||
(None, None)
|
}
|
||||||
} else {
|
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
|
||||||
(Some(sender), Some(receiver))
|
|
||||||
};
|
|
||||||
let msg = ConstellationMsg::RemoveIFrame(pipeline_id, sender);
|
|
||||||
window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap();
|
|
||||||
if let Some(receiver) = receiver {
|
|
||||||
receiver.recv().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resetting the pipeline_id to None is required here so that
|
|
||||||
// if this iframe is subsequently re-added to the document
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resetting the pipeline_id to None is required here so that
|
||||||
|
// if this iframe is subsequently re-added to the document
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,13 @@
|
||||||
// other browsing contexts
|
// other browsing contexts
|
||||||
[Replaceable] readonly attribute WindowProxy frames;
|
[Replaceable] readonly attribute WindowProxy frames;
|
||||||
//[Replaceable] readonly attribute unsigned long length;
|
//[Replaceable] readonly attribute unsigned long length;
|
||||||
[Unforgeable] readonly attribute WindowProxy top;
|
// Note that this can return null in the case that the browsing context has been discarded.
|
||||||
|
// https://github.com/whatwg/html/issues/2115
|
||||||
|
[Unforgeable] readonly attribute WindowProxy? top;
|
||||||
// attribute any opener;
|
// attribute any opener;
|
||||||
readonly attribute WindowProxy parent;
|
// Note that this can return null in the case that the browsing context has been discarded.
|
||||||
|
// https://github.com/whatwg/html/issues/2115
|
||||||
|
readonly attribute WindowProxy? parent;
|
||||||
readonly attribute Element? frameElement;
|
readonly attribute Element? frameElement;
|
||||||
//WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank",
|
//WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank",
|
||||||
// optional DOMString features = "", optional boolean replace = false);
|
// optional DOMString features = "", optional boolean replace = false);
|
||||||
|
|
|
@ -163,6 +163,7 @@ pub struct Window {
|
||||||
#[ignore_heap_size_of = "channels are hard"]
|
#[ignore_heap_size_of = "channels are hard"]
|
||||||
image_cache_chan: ImageCacheChan,
|
image_cache_chan: ImageCacheChan,
|
||||||
browsing_context: MutNullableJS<BrowsingContext>,
|
browsing_context: MutNullableJS<BrowsingContext>,
|
||||||
|
document: MutNullableJS<Document>,
|
||||||
history: MutNullableJS<History>,
|
history: MutNullableJS<History>,
|
||||||
performance: MutNullableJS<Performance>,
|
performance: MutNullableJS<Performance>,
|
||||||
navigation_start: u64,
|
navigation_start: u64,
|
||||||
|
@ -443,7 +444,7 @@ impl WindowMethods for Window {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-document-2
|
// https://html.spec.whatwg.org/multipage/#dom-document-2
|
||||||
fn Document(&self) -> Root<Document> {
|
fn Document(&self) -> Root<Document> {
|
||||||
self.browsing_context().active_document()
|
self.document.get().expect("Document accessed before initialization.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-history
|
// https://html.spec.whatwg.org/multipage/#dom-history
|
||||||
|
@ -551,21 +552,32 @@ impl WindowMethods for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-parent
|
// https://html.spec.whatwg.org/multipage/#dom-parent
|
||||||
fn Parent(&self) -> Root<BrowsingContext> {
|
fn GetParent(&self) -> Option<Root<BrowsingContext>> {
|
||||||
match self.parent() {
|
// Steps 1. and 2.
|
||||||
Some(window) => window.browsing_context(),
|
if self.browsing_context().is_discarded() {
|
||||||
None => self.Window()
|
return None;
|
||||||
}
|
}
|
||||||
}
|
match self.parent() {
|
||||||
|
// Step 4.
|
||||||
|
Some(parent) => Some(parent.Window()),
|
||||||
|
// Step 5.
|
||||||
|
None => Some(self.Window())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-top
|
// https://html.spec.whatwg.org/multipage/#dom-top
|
||||||
fn Top(&self) -> Root<BrowsingContext> {
|
fn GetTop(&self) -> Option<Root<BrowsingContext>> {
|
||||||
|
// Steps 1. and 2.
|
||||||
|
if self.browsing_context().is_discarded() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Step 5.
|
||||||
let mut window = Root::from_ref(self);
|
let mut window = Root::from_ref(self);
|
||||||
while let Some(parent) = window.parent() {
|
while let Some(parent) = window.parent() {
|
||||||
window = parent;
|
window = parent;
|
||||||
}
|
}
|
||||||
window.browsing_context()
|
Some(window.Window())
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/
|
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/
|
||||||
// NavigationTiming/Overview.html#sec-window.performance-attribute
|
// NavigationTiming/Overview.html#sec-window.performance-attribute
|
||||||
|
@ -1351,6 +1363,13 @@ impl Window {
|
||||||
unsafe { SetWindowProxy(cx, window, browsing_context.reflector().get_jsobject()); }
|
unsafe { SetWindowProxy(cx, window, browsing_context.reflector().get_jsobject()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
pub fn init_document(&self, document: &Document) {
|
||||||
|
assert!(self.document.get().is_none());
|
||||||
|
assert!(document.window() == self);
|
||||||
|
self.document.set(Some(&document));
|
||||||
|
}
|
||||||
|
|
||||||
/// Commence a new URL load which will either replace this window or scroll to a fragment.
|
/// Commence a new URL load which will either replace this window or scroll to a fragment.
|
||||||
pub fn load_url(&self, url: ServoUrl, replace: bool, force_reload: bool,
|
pub fn load_url(&self, url: ServoUrl, replace: bool, force_reload: bool,
|
||||||
referrer_policy: Option<ReferrerPolicy>) {
|
referrer_policy: Option<ReferrerPolicy>) {
|
||||||
|
@ -1518,13 +1537,8 @@ impl Window {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let browsing_context = self.browsing_context();
|
self.browsing_context().frame_element()
|
||||||
|
.map(|frame_element| window_from_node(frame_element))
|
||||||
browsing_context.frame_element().map(|frame_element| {
|
|
||||||
let window = window_from_node(frame_element);
|
|
||||||
let context = window.browsing_context();
|
|
||||||
context.active_window()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this window is mozbrowser.
|
/// Returns whether this window is mozbrowser.
|
||||||
|
@ -1610,6 +1624,7 @@ impl Window {
|
||||||
image_cache_thread: image_cache_thread,
|
image_cache_thread: image_cache_thread,
|
||||||
history: Default::default(),
|
history: Default::default(),
|
||||||
browsing_context: Default::default(),
|
browsing_context: Default::default(),
|
||||||
|
document: Default::default(),
|
||||||
performance: Default::default(),
|
performance: Default::default(),
|
||||||
navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64,
|
navigation_start: (current_time.sec * 1000 + current_time.nsec as i64 / 1000000) as u64,
|
||||||
navigation_start_precise: time::precise_time_ns() as f64,
|
navigation_start_precise: time::precise_time_ns() as f64,
|
||||||
|
|
|
@ -83,7 +83,7 @@ use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
||||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
|
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
|
||||||
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
|
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
|
||||||
use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult};
|
use script_traits::{CompositorEvent, ConstellationControlMsg, DiscardBrowsingContext, EventResult};
|
||||||
use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
|
use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
|
||||||
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
||||||
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
||||||
|
@ -1007,8 +1007,8 @@ impl ScriptThread {
|
||||||
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
|
self.handle_css_error_reporting(pipeline_id, filename, line, column, msg),
|
||||||
ConstellationControlMsg::Reload(pipeline_id) =>
|
ConstellationControlMsg::Reload(pipeline_id) =>
|
||||||
self.handle_reload(pipeline_id),
|
self.handle_reload(pipeline_id),
|
||||||
ConstellationControlMsg::ExitPipeline(pipeline_id) =>
|
ConstellationControlMsg::ExitPipeline(pipeline_id, discard_browsing_context) =>
|
||||||
self.handle_exit_pipeline_msg(pipeline_id),
|
self.handle_exit_pipeline_msg(pipeline_id, discard_browsing_context),
|
||||||
msg @ ConstellationControlMsg::AttachLayout(..) |
|
msg @ ConstellationControlMsg::AttachLayout(..) |
|
||||||
msg @ ConstellationControlMsg::Viewport(..) |
|
msg @ ConstellationControlMsg::Viewport(..) |
|
||||||
msg @ ConstellationControlMsg::SetScrollState(..) |
|
msg @ ConstellationControlMsg::SetScrollState(..) |
|
||||||
|
@ -1368,6 +1368,7 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.window().thaw();
|
document.window().thaw();
|
||||||
|
document.fully_activate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut loads = self.incomplete_loads.borrow_mut();
|
let mut loads = self.incomplete_loads.borrow_mut();
|
||||||
|
@ -1565,7 +1566,7 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a request to exit a pipeline and shut down layout.
|
/// Handles a request to exit a pipeline and shut down layout.
|
||||||
fn handle_exit_pipeline_msg(&self, id: PipelineId) {
|
fn handle_exit_pipeline_msg(&self, id: PipelineId, discard_bc: DiscardBrowsingContext) {
|
||||||
debug!("Exiting pipeline {}.", id);
|
debug!("Exiting pipeline {}.", id);
|
||||||
|
|
||||||
self.closed_pipelines.borrow_mut().insert(id);
|
self.closed_pipelines.borrow_mut().insert(id);
|
||||||
|
@ -1591,6 +1592,11 @@ impl ScriptThread {
|
||||||
|
|
||||||
if let Some(document) = self.documents.borrow_mut().remove(id) {
|
if let Some(document) = self.documents.borrow_mut().remove(id) {
|
||||||
shut_down_layout(document.window());
|
shut_down_layout(document.window());
|
||||||
|
if discard_bc == DiscardBrowsingContext::Yes {
|
||||||
|
if let Some(context) = document.browsing_context() {
|
||||||
|
context.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
let _ = self.constellation_chan.send(ConstellationMsg::PipelineExited(id));
|
let _ = self.constellation_chan.send(ConstellationMsg::PipelineExited(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1606,7 +1612,7 @@ impl ScriptThread {
|
||||||
pipeline_ids.extend(self.documents.borrow().iter().next().map(|(pipeline_id, _)| pipeline_id));
|
pipeline_ids.extend(self.documents.borrow().iter().next().map(|(pipeline_id, _)| pipeline_id));
|
||||||
|
|
||||||
for pipeline_id in pipeline_ids {
|
for pipeline_id in pipeline_ids {
|
||||||
self.handle_exit_pipeline_msg(pipeline_id);
|
self.handle_exit_pipeline_msg(pipeline_id, DiscardBrowsingContext::Yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Exited script thread.");
|
debug!("Exited script thread.");
|
||||||
|
@ -1819,9 +1825,13 @@ impl ScriptThread {
|
||||||
referrer_policy);
|
referrer_policy);
|
||||||
document.set_ready_state(DocumentReadyState::Loading);
|
document.set_ready_state(DocumentReadyState::Loading);
|
||||||
|
|
||||||
|
if !incomplete.is_frozen {
|
||||||
|
document.fully_activate();
|
||||||
|
}
|
||||||
|
|
||||||
self.documents.borrow_mut().insert(incomplete.pipeline_id, &*document);
|
self.documents.borrow_mut().insert(incomplete.pipeline_id, &*document);
|
||||||
|
|
||||||
browsing_context.set_active_document(&document);
|
window.init_document(&document);
|
||||||
|
|
||||||
self.constellation_chan
|
self.constellation_chan
|
||||||
.send(ConstellationMsg::ActivateDocument(incomplete.pipeline_id))
|
.send(ConstellationMsg::ActivateDocument(incomplete.pipeline_id))
|
||||||
|
@ -2253,8 +2263,8 @@ fn shut_down_layout(window: &Window) {
|
||||||
// Drop our references to the JSContext and DOM objects.
|
// Drop our references to the JSContext and DOM objects.
|
||||||
window.clear_js_runtime();
|
window.clear_js_runtime();
|
||||||
|
|
||||||
// Sever the connection between the global and the DOM tree
|
// Discard the browsing context.
|
||||||
browsing_context.unset_active_document();
|
browsing_context.discard();
|
||||||
|
|
||||||
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
|
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
|
||||||
chan.send(message::Msg::ExitNow).ok();
|
chan.send(message::Msg::ExitNow).ok();
|
||||||
|
|
|
@ -184,6 +184,15 @@ pub struct NewLayoutInfo {
|
||||||
pub layout_threads: usize,
|
pub layout_threads: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When a pipeline is closed, should its browsing context be discarded too?
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
pub enum DiscardBrowsingContext {
|
||||||
|
/// Discard the browsing context
|
||||||
|
Yes,
|
||||||
|
/// Don't discard the browsing context
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
/// Messages sent from the constellation or layout to the script thread.
|
/// Messages sent from the constellation or layout to the script thread.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ConstellationControlMsg {
|
pub enum ConstellationControlMsg {
|
||||||
|
@ -194,7 +203,7 @@ pub enum ConstellationControlMsg {
|
||||||
/// Notifies script that window has been resized but to not take immediate action.
|
/// Notifies script that window has been resized but to not take immediate action.
|
||||||
ResizeInactive(PipelineId, WindowSizeData),
|
ResizeInactive(PipelineId, WindowSizeData),
|
||||||
/// Notifies the script that a pipeline should be closed.
|
/// Notifies the script that a pipeline should be closed.
|
||||||
ExitPipeline(PipelineId),
|
ExitPipeline(PipelineId, DiscardBrowsingContext),
|
||||||
/// Notifies the script that the whole thread should be closed.
|
/// Notifies the script that the whole thread should be closed.
|
||||||
ExitScriptThread,
|
ExitScriptThread,
|
||||||
/// Sends a DOM event.
|
/// Sends a DOM event.
|
||||||
|
|
|
@ -102,7 +102,8 @@ pub enum ScriptMsg {
|
||||||
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
/// Status message to be displayed in the chrome, eg. a link URL on mouseover.
|
||||||
NodeStatus(Option<String>),
|
NodeStatus(Option<String>),
|
||||||
/// Notification that this iframe should be removed.
|
/// Notification that this iframe should be removed.
|
||||||
RemoveIFrame(PipelineId, Option<IpcSender<()>>),
|
/// Returns a list of pipelines which were closed.
|
||||||
|
RemoveIFrame(FrameId, IpcSender<Vec<PipelineId>>),
|
||||||
/// Change pipeline visibility
|
/// Change pipeline visibility
|
||||||
SetVisible(PipelineId, bool),
|
SetVisible(PipelineId, bool),
|
||||||
/// Notifies constellation that an iframe's visibility has been changed.
|
/// Notifies constellation that an iframe's visibility has been changed.
|
||||||
|
|
|
@ -45852,6 +45852,12 @@
|
||||||
"path": "cssom/overflow-serialization.html",
|
"path": "cssom/overflow-serialization.html",
|
||||||
"url": "/cssom/overflow-serialization.html"
|
"url": "/cssom/overflow-serialization.html"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html": [
|
||||||
|
{
|
||||||
|
"path": "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html",
|
||||||
|
"url": "/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>IFrame discards are processed synchronously</title>
|
||||||
|
<body></body>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script>
|
||||||
|
async_test(function(t) {
|
||||||
|
var child = document.createElement("iframe");
|
||||||
|
child.src = "support/blank.htm?1";
|
||||||
|
child.onload = t.step_func(function () {
|
||||||
|
var childWindow = child.contentWindow;
|
||||||
|
var grandchild = childWindow.document.createElement("iframe");
|
||||||
|
grandchild.src = "blank.htm?2";
|
||||||
|
grandchild.onload = t.step_func(function () {
|
||||||
|
var grandchildWindow = grandchild.contentWindow;
|
||||||
|
assert_equals(child.contentWindow, childWindow, "child window");
|
||||||
|
assert_equals(childWindow.parent, window, "child parentage");
|
||||||
|
assert_equals(grandchild.contentWindow, grandchildWindow, "grandchild window");
|
||||||
|
assert_equals(grandchildWindow.parent, childWindow, "grandchild parentage");
|
||||||
|
document.body.removeChild(child);
|
||||||
|
assert_equals(child.contentWindow, null, "child should be discarded");
|
||||||
|
assert_equals(childWindow.parent, null, "child window should be discarded");
|
||||||
|
assert_equals(grandchild.contentWindow, null, "grandchild should be discarded");
|
||||||
|
assert_equals(grandchildWindow.parent, null, "grandchild window should be discarded");
|
||||||
|
t.done();
|
||||||
|
});
|
||||||
|
childWindow.document.body.appendChild(grandchild);
|
||||||
|
});
|
||||||
|
document.body.appendChild(child);
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue