mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 06:05:44 +00:00
servo: Merge #15120 - Allow windows to share browsing contexts (from asajeffrey:script-windows-share-browsing-contexts); r=jdm
<!-- Please describe your changes on the following line: --> This PR allows different `Window` objects in the same browsing context to share a `BrowsingContext` object. SpiderMonkey requires a `WindowProxy` object to be in the same compartment as its `Window`, so when a `WindowProxy` changes `Window`, we have to brain-transplant it. In turn this requires the reflector of a `BrowsingContext` to be mutable. --- <!-- 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 #13608 and #14843 - [X] These changes do not require tests because an existing test catches this (`/html/browsers/the-window-object/Window-document.html` is now `PASS`) <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 67c182638253211553161495cd2e4570002fd5bc
This commit is contained in:
parent
aa1b5f335e
commit
612d31497f
@ -5,7 +5,7 @@
|
||||
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
|
||||
use dom::bindings::js::{JS, Root, RootedReference};
|
||||
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
|
||||
use dom::bindings::reflector::{DomObject, MutDomObject, Reflector};
|
||||
use dom::bindings::reflector::{DomObject, Reflector};
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::bindings::utils::WindowProxyHandler;
|
||||
use dom::bindings::utils::get_array_index_from_id;
|
||||
@ -19,11 +19,13 @@ use js::jsapi::{JSAutoCompartment, JSContext, JSErrNum, JSFreeOp, JSObject};
|
||||
use js::jsapi::{JSPROP_READONLY, JSTracer, JS_DefinePropertyById};
|
||||
use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo};
|
||||
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById};
|
||||
use js::jsapi::{JS_TransplantObject, SetWindowProxy};
|
||||
use js::jsapi::{MutableHandle, MutableHandleObject, MutableHandleValue};
|
||||
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
|
||||
use js::jsval::{UndefinedValue, PrivateValue};
|
||||
use js::rust::get_object_class;
|
||||
use std::cell::Cell;
|
||||
use std::ptr;
|
||||
|
||||
#[dom_struct]
|
||||
// NOTE: the browsing context for a window is managed in two places:
|
||||
@ -31,6 +33,10 @@ use std::cell::Cell;
|
||||
// manages the session history, which in script is accessed through
|
||||
// History objects, messaging the constellation.
|
||||
pub struct BrowsingContext {
|
||||
/// The WindowProxy object.
|
||||
/// Unlike other reflectors, we mutate this field because
|
||||
/// we have to brain-transplant the reflector when the WindowProxy
|
||||
/// changes Window.
|
||||
reflector: Reflector,
|
||||
|
||||
/// Has this browsing context been discarded?
|
||||
@ -44,7 +50,7 @@ impl BrowsingContext {
|
||||
pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
|
||||
BrowsingContext {
|
||||
reflector: Reflector::new(),
|
||||
discarded: Cell::new(false),
|
||||
discarded: Cell::new(false),
|
||||
frame_element: frame_element.map(JS::from_ref),
|
||||
}
|
||||
}
|
||||
@ -56,21 +62,29 @@ impl BrowsingContext {
|
||||
assert!(!handler.is_null());
|
||||
|
||||
let cx = window.get_cx();
|
||||
let parent = window.reflector().get_jsobject();
|
||||
assert!(!parent.get().is_null());
|
||||
assert!(((*get_object_class(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
|
||||
let _ac = JSAutoCompartment::new(cx, parent.get());
|
||||
rooted!(in(cx) let window_proxy = NewWindowProxy(cx, parent, handler));
|
||||
let window_jsobject = window.reflector().get_jsobject();
|
||||
assert!(!window_jsobject.get().is_null());
|
||||
assert!(((*get_object_class(window_jsobject.get())).flags & JSCLASS_IS_GLOBAL) != 0);
|
||||
let _ac = JSAutoCompartment::new(cx, window_jsobject.get());
|
||||
|
||||
// Create a new window proxy.
|
||||
rooted!(in(cx) let window_proxy = NewWindowProxy(cx, window_jsobject, handler));
|
||||
assert!(!window_proxy.is_null());
|
||||
|
||||
let object = box BrowsingContext::new_inherited(frame_element);
|
||||
// Create a new browsing context.
|
||||
let mut browsing_context = box BrowsingContext::new_inherited(frame_element);
|
||||
|
||||
let raw = Box::into_raw(object);
|
||||
SetProxyExtra(window_proxy.get(), 0, &PrivateValue(raw as *const _));
|
||||
// The window proxy owns the browsing context.
|
||||
// When we finalize the window proxy, it drops the browsing context it owns.
|
||||
SetProxyExtra(window_proxy.get(), 0, &PrivateValue(&*browsing_context as *const _ as *const _));
|
||||
|
||||
(*raw).init_reflector(window_proxy.get());
|
||||
// Notify the JS engine about the new window proxy binding.
|
||||
SetWindowProxy(cx, window_jsobject, window_proxy.handle());
|
||||
|
||||
Root::from_ref(&*raw)
|
||||
// Set the reflector.
|
||||
debug!("Initializing reflector of {:p} to {:p}.", browsing_context, window_proxy.get());
|
||||
browsing_context.reflector.set_jsobject(window_proxy.get());
|
||||
Root::from_ref(&*Box::into_raw(browsing_context))
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,6 +100,50 @@ impl BrowsingContext {
|
||||
self.frame_element.r()
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
/// Change the Window that this browsing context's WindowProxy resolves to.
|
||||
// TODO: support setting the window proxy to a dummy value,
|
||||
// to handle the case when the active document is in another script thread.
|
||||
pub fn set_window_proxy(&self, window: &Window) {
|
||||
unsafe {
|
||||
debug!("Setting window proxy of {:p}.", self);
|
||||
let WindowProxyHandler(handler) = window.windowproxy_handler();
|
||||
assert!(!handler.is_null());
|
||||
|
||||
let cx = window.get_cx();
|
||||
let window_jsobject = window.reflector().get_jsobject();
|
||||
let old_window_proxy = self.reflector.get_jsobject();
|
||||
assert!(!window_jsobject.get().is_null());
|
||||
assert!(((*get_object_class(window_jsobject.get())).flags & JSCLASS_IS_GLOBAL) != 0);
|
||||
let _ac = JSAutoCompartment::new(cx, window_jsobject.get());
|
||||
|
||||
// The old window proxy no longer owns this browsing context.
|
||||
SetProxyExtra(old_window_proxy.get(), 0, &PrivateValue(ptr::null_mut()));
|
||||
|
||||
// Brain transpant the window proxy.
|
||||
// We need to do this, because the Window and WindowProxy
|
||||
// objects need to be in the same compartment.
|
||||
// JS_TransplantObject does this by copying the contents
|
||||
// of the old window proxy to the new window proxy, then
|
||||
// making the old window proxy a cross-compartment wrapper
|
||||
// pointing to the new window proxy.
|
||||
rooted!(in(cx) let new_window_proxy = NewWindowProxy(cx, window_jsobject, handler));
|
||||
debug!("Transplanting window proxy from {:p} to {:p}.", old_window_proxy.get(), new_window_proxy.get());
|
||||
rooted!(in(cx) let new_window_proxy = JS_TransplantObject(cx, old_window_proxy, new_window_proxy.handle()));
|
||||
debug!("Transplanted window proxy is {:p}.", new_window_proxy.get());
|
||||
|
||||
// Transfer ownership of this browsing context from the old window proxy to the new one.
|
||||
SetProxyExtra(new_window_proxy.get(), 0, &PrivateValue(self as *const _ as *const _));
|
||||
|
||||
// Notify the JS engine about the new window proxy binding.
|
||||
SetWindowProxy(cx, window_jsobject, new_window_proxy.handle());
|
||||
|
||||
// Update the reflector.
|
||||
debug!("Setting reflector of {:p} to {:p}.", self, new_window_proxy.get());
|
||||
self.reflector.rootable().set(new_window_proxy.get());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn window_proxy(&self) -> *mut JSObject {
|
||||
let window_proxy = self.reflector.get_jsobject();
|
||||
assert!(!window_proxy.get().is_null());
|
||||
@ -277,16 +335,20 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe extern fn finalize(_fop: *mut JSFreeOp, obj: *mut JSObject) {
|
||||
let this = GetProxyExtra(obj, 0).to_private() as *mut BrowsingContext;
|
||||
assert!(!this.is_null());
|
||||
if this.is_null() {
|
||||
// GC during obj creation or after transplanting.
|
||||
return;
|
||||
}
|
||||
let jsobject = (*this).reflector.get_jsobject().get();
|
||||
debug!("BrowsingContext finalize: {:p}, with reflector {:p} from {:p}.", this, jsobject, obj);
|
||||
let _ = Box::from_raw(this);
|
||||
debug!("BrowsingContext finalize: {:p}", this);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe extern fn trace(trc: *mut JSTracer, obj: *mut JSObject) {
|
||||
let this = GetProxyExtra(obj, 0).to_private() as *const BrowsingContext;
|
||||
if this.is_null() {
|
||||
// GC during obj creation
|
||||
// GC during obj creation or after transplanting.
|
||||
return;
|
||||
}
|
||||
(*this).trace(trc);
|
||||
|
@ -184,13 +184,12 @@ impl PendingRestyle {
|
||||
pub struct Document {
|
||||
node: Node,
|
||||
window: JS<Window>,
|
||||
/// https://html.spec.whatwg.org/multipage/#concept-document-bc
|
||||
browsing_context: Option<JS<BrowsingContext>>,
|
||||
implementation: MutNullableJS<DOMImplementation>,
|
||||
location: MutNullableJS<Location>,
|
||||
content_type: DOMString,
|
||||
last_modified: Option<String>,
|
||||
encoding: Cell<EncodingRef>,
|
||||
has_browsing_context: bool,
|
||||
is_html_document: bool,
|
||||
activity: Cell<DocumentActivity>,
|
||||
url: DOMRefCell<ServoUrl>,
|
||||
@ -369,8 +368,12 @@ impl Document {
|
||||
|
||||
/// https://html.spec.whatwg.org/multipage/#concept-document-bc
|
||||
#[inline]
|
||||
pub fn browsing_context(&self) -> Option<&BrowsingContext> {
|
||||
self.browsing_context.as_ref().map(|browsing_context| &**browsing_context)
|
||||
pub fn browsing_context(&self) -> Option<Root<BrowsingContext>> {
|
||||
if self.has_browsing_context {
|
||||
Some(self.window.browsing_context())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -398,7 +401,7 @@ impl Document {
|
||||
|
||||
pub fn set_activity(&self, activity: DocumentActivity) {
|
||||
// This function should only be called on documents with a browsing context
|
||||
assert!(self.browsing_context.is_some());
|
||||
assert!(self.has_browsing_context);
|
||||
// Set the document's activity level, reflow if necessary, and suspend or resume timers.
|
||||
if activity != self.activity.get() {
|
||||
self.activity.set(activity);
|
||||
@ -1568,7 +1571,7 @@ impl Document {
|
||||
self.process_deferred_scripts();
|
||||
},
|
||||
LoadType::PageSource(_) => {
|
||||
if self.browsing_context.is_some() {
|
||||
if self.has_browsing_context {
|
||||
// Disarm the reflow timer and trigger the initial reflow.
|
||||
self.reflow_timeout.set(None);
|
||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||
@ -1830,7 +1833,7 @@ impl Document {
|
||||
|
||||
/// https://html.spec.whatwg.org/multipage/#cookie-averse-document-object
|
||||
pub fn is_cookie_averse(&self) -> bool {
|
||||
self.browsing_context.is_none() || !url_has_network_scheme(&self.url())
|
||||
!self.has_browsing_context || !url_has_network_scheme(&self.url())
|
||||
}
|
||||
|
||||
pub fn nodes_from_point(&self, client_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> {
|
||||
@ -1901,9 +1904,15 @@ fn url_has_network_scheme(url: &ServoUrl) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, HeapSizeOf, JSTraceable, PartialEq, Eq)]
|
||||
pub enum HasBrowsingContext {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl Document {
|
||||
pub fn new_inherited(window: &Window,
|
||||
browsing_context: Option<&BrowsingContext>,
|
||||
has_browsing_context: HasBrowsingContext,
|
||||
url: Option<ServoUrl>,
|
||||
origin: Origin,
|
||||
is_html_document: IsHTMLDocument,
|
||||
@ -1926,7 +1935,7 @@ impl Document {
|
||||
Document {
|
||||
node: Node::new_document_node(),
|
||||
window: JS::from_ref(window),
|
||||
browsing_context: browsing_context.map(JS::from_ref),
|
||||
has_browsing_context: has_browsing_context == HasBrowsingContext::Yes,
|
||||
implementation: Default::default(),
|
||||
location: Default::default(),
|
||||
content_type: match content_type {
|
||||
@ -1970,7 +1979,7 @@ impl Document {
|
||||
deferred_scripts: Default::default(),
|
||||
asap_in_order_scripts_list: Default::default(),
|
||||
asap_scripts_set: Default::default(),
|
||||
scripting_enabled: browsing_context.is_some(),
|
||||
scripting_enabled: has_browsing_context == HasBrowsingContext::Yes,
|
||||
animation_frame_ident: Cell::new(0),
|
||||
animation_frame_list: DOMRefCell::new(vec![]),
|
||||
running_animation_callbacks: Cell::new(false),
|
||||
@ -2007,7 +2016,7 @@ impl Document {
|
||||
let doc = window.Document();
|
||||
let docloader = DocumentLoader::new(&*doc.loader());
|
||||
Ok(Document::new(window,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
doc.origin().alias(),
|
||||
IsHTMLDocument::NonHTMLDocument,
|
||||
@ -2021,7 +2030,7 @@ impl Document {
|
||||
}
|
||||
|
||||
pub fn new(window: &Window,
|
||||
browsing_context: Option<&BrowsingContext>,
|
||||
has_browsing_context: HasBrowsingContext,
|
||||
url: Option<ServoUrl>,
|
||||
origin: Origin,
|
||||
doctype: IsHTMLDocument,
|
||||
@ -2034,7 +2043,7 @@ impl Document {
|
||||
referrer_policy: Option<ReferrerPolicy>)
|
||||
-> Root<Document> {
|
||||
let document = reflect_dom_object(box Document::new_inherited(window,
|
||||
browsing_context,
|
||||
has_browsing_context,
|
||||
url,
|
||||
origin,
|
||||
doctype,
|
||||
@ -2107,7 +2116,7 @@ impl Document {
|
||||
IsHTMLDocument::NonHTMLDocument
|
||||
};
|
||||
let new_doc = Document::new(self.window(),
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
// https://github.com/whatwg/html/issues/2109
|
||||
Origin::opaque_identifier(),
|
||||
@ -3011,10 +3020,10 @@ impl DocumentMethods for Document {
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-document-defaultview
|
||||
fn GetDefaultView(&self) -> Option<Root<Window>> {
|
||||
if self.browsing_context.is_none() {
|
||||
None
|
||||
} else {
|
||||
if self.has_browsing_context {
|
||||
Some(Root::from_ref(&*self.window))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::bindings::xmlname::{namespace_from_domstring, validate_qualified_name};
|
||||
use dom::document::{Document, IsHTMLDocument};
|
||||
use dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::document::DocumentSource;
|
||||
use dom::documenttype::DocumentType;
|
||||
use dom::htmlbodyelement::HTMLBodyElement;
|
||||
@ -78,7 +78,7 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||
|
||||
// Step 1.
|
||||
let doc = XMLDocument::new(win,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
self.document.origin().alias(),
|
||||
IsHTMLDocument::NonHTMLDocument,
|
||||
@ -125,7 +125,7 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||
|
||||
// Step 1-2.
|
||||
let doc = Document::new(win,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
None,
|
||||
self.document.origin().alias(),
|
||||
IsHTMLDocument::HTMLDocument,
|
||||
|
@ -15,7 +15,7 @@ use dom::bindings::error::Fallible;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::document::{Document, IsHTMLDocument};
|
||||
use dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::document::DocumentSource;
|
||||
use dom::servoparser::ServoParser;
|
||||
use dom::window::Window;
|
||||
@ -60,7 +60,7 @@ impl DOMParserMethods for DOMParser {
|
||||
match ty {
|
||||
Text_html => {
|
||||
let document = Document::new(&self.window,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
Some(url.clone()),
|
||||
doc.origin().alias(),
|
||||
IsHTMLDocument::HTMLDocument,
|
||||
@ -78,7 +78,7 @@ impl DOMParserMethods for DOMParser {
|
||||
Text_xml | Application_xml | Application_xhtml_xml => {
|
||||
// FIXME: this should probably be FromParser when we actually parse the string (#3756).
|
||||
let document = Document::new(&self.window,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
Some(url.clone()),
|
||||
doc.origin().alias(),
|
||||
IsHTMLDocument::NonHTMLDocument,
|
||||
|
@ -17,7 +17,6 @@ use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||
use js::jsapi::{HandleValue, Heap, JSContext};
|
||||
use js::jsval::JSVal;
|
||||
use servo_atoms::Atom;
|
||||
use std::default::Default;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct ExtendableMessageEvent {
|
||||
@ -32,13 +31,12 @@ impl ExtendableMessageEvent {
|
||||
bubbles: bool, cancelable: bool,
|
||||
data: HandleValue, origin: DOMString, lastEventId: DOMString)
|
||||
-> Root<ExtendableMessageEvent> {
|
||||
let mut ev = box ExtendableMessageEvent {
|
||||
let ev = box ExtendableMessageEvent {
|
||||
event: ExtendableEvent::new_inherited(),
|
||||
data: Heap::default(),
|
||||
data: Heap::new(data.get()),
|
||||
origin: origin,
|
||||
lastEventId: lastEventId,
|
||||
};
|
||||
ev.data.set(data.get());
|
||||
let ev = reflect_dom_object(ev, global, ExtendableMessageEventBinding::Wrap);
|
||||
{
|
||||
let event = ev.upcast::<Event>();
|
||||
|
@ -27,7 +27,7 @@ pub struct ImageData {
|
||||
impl ImageData {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(global: &GlobalScope, width: u32, height: u32, data: Option<Vec<u8>>) -> Root<ImageData> {
|
||||
let mut imagedata = box ImageData {
|
||||
let imagedata = box ImageData {
|
||||
reflector_: Reflector::new(),
|
||||
width: width,
|
||||
height: height,
|
||||
|
@ -16,7 +16,6 @@ use dom::globalscope::GlobalScope;
|
||||
use js::jsapi::{HandleValue, Heap, JSContext};
|
||||
use js::jsval::JSVal;
|
||||
use servo_atoms::Atom;
|
||||
use std::default::Default;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct MessageEvent {
|
||||
@ -38,13 +37,12 @@ impl MessageEvent {
|
||||
data: HandleValue,
|
||||
origin: DOMString,
|
||||
lastEventId: DOMString) -> Root<MessageEvent> {
|
||||
let mut ev = box MessageEvent {
|
||||
let ev = box MessageEvent {
|
||||
event: Event::new_inherited(),
|
||||
data: Heap::default(),
|
||||
data: Heap::new(data.get()),
|
||||
origin: origin,
|
||||
lastEventId: lastEventId,
|
||||
};
|
||||
ev.data.set(data.get());
|
||||
reflect_dom_object(ev, global, MessageEventBinding::Wrap)
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ use dom::bindings::str::{DOMString, USVString};
|
||||
use dom::bindings::xmlname::namespace_from_domstring;
|
||||
use dom::characterdata::{CharacterData, LayoutCharacterDataHelpers};
|
||||
use dom::cssstylesheet::CSSStyleSheet;
|
||||
use dom::document::{Document, DocumentSource, IsHTMLDocument};
|
||||
use dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::documentfragment::DocumentFragment;
|
||||
use dom::documenttype::DocumentType;
|
||||
use dom::element::{Element, ElementCreator};
|
||||
@ -1726,7 +1726,7 @@ impl Node {
|
||||
};
|
||||
let window = document.window();
|
||||
let loader = DocumentLoader::new(&*document.loader());
|
||||
let document = Document::new(window, None,
|
||||
let document = Document::new(window, HasBrowsingContext::No,
|
||||
Some(document.url()),
|
||||
// https://github.com/whatwg/dom/issues/378
|
||||
document.origin().alias(),
|
||||
|
@ -14,7 +14,7 @@ use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::characterdata::CharacterData;
|
||||
use dom::document::{Document, DocumentSource, IsHTMLDocument};
|
||||
use dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::element::Element;
|
||||
use dom::globalscope::GlobalScope;
|
||||
use dom::htmlformelement::HTMLFormElement;
|
||||
@ -102,7 +102,7 @@ impl ServoParser {
|
||||
let loader = DocumentLoader::new_with_threads(context_document.loader().resource_threads().clone(),
|
||||
Some(url.clone()));
|
||||
let document = Document::new(window,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
Some(url.clone()),
|
||||
context_document.origin().alias(),
|
||||
IsHTMLDocument::HTMLDocument,
|
||||
|
@ -31,7 +31,7 @@ impl VREyeParameters {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(parameters: WebVREyeParameters, global: &GlobalScope) -> VREyeParameters {
|
||||
let fov = VRFieldOfView::new(&global, parameters.field_of_view.clone());
|
||||
let mut result = VREyeParameters {
|
||||
let result = VREyeParameters {
|
||||
reflector_: Reflector::new(),
|
||||
parameters: DOMRefCell::new(parameters),
|
||||
offset: Heap::default(),
|
||||
|
@ -39,7 +39,7 @@ impl VRFrameData {
|
||||
0.0, 0.0, 0.0, 1.0f32];
|
||||
let pose = VRPose::new(&global, &Default::default());
|
||||
|
||||
let mut framedata = VRFrameData {
|
||||
let framedata = VRFrameData {
|
||||
reflector_: Reflector::new(),
|
||||
left_proj: Heap::default(),
|
||||
left_view: Heap::default(),
|
||||
|
@ -29,7 +29,7 @@ pub struct VRPose {
|
||||
unsafe fn update_or_create_typed_array(cx: *mut JSContext,
|
||||
src: Option<&[f32]>,
|
||||
dst: &DOMRefCell<Heap<*mut JSObject>>) {
|
||||
let mut dst = dst.borrow_mut();
|
||||
let dst = dst.borrow();
|
||||
match src {
|
||||
Some(ref data) => {
|
||||
if dst.get().is_null() {
|
||||
|
@ -28,7 +28,7 @@ impl VRStageParameters {
|
||||
#[allow(unsafe_code)]
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(parameters: WebVRStageParameters, global: &GlobalScope) -> VRStageParameters {
|
||||
let mut stage = VRStageParameters {
|
||||
let stage = VRStageParameters {
|
||||
reflector_: Reflector::new(),
|
||||
parameters: DOMRefCell::new(parameters),
|
||||
transform: Heap::default()
|
||||
|
@ -50,7 +50,7 @@ use fetch;
|
||||
use gfx_traits::ScrollRootId;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext};
|
||||
use js::jsapi::{JS_GC, JS_GetRuntime, SetWindowProxy};
|
||||
use js::jsapi::{JS_GC, JS_GetRuntime};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::{FrameType, PipelineId};
|
||||
@ -1375,10 +1375,6 @@ impl Window {
|
||||
pub fn init_browsing_context(&self, browsing_context: &BrowsingContext) {
|
||||
assert!(self.browsing_context.get().is_none());
|
||||
self.browsing_context.set(Some(&browsing_context));
|
||||
let window = self.reflector().get_jsobject();
|
||||
let cx = self.get_cx();
|
||||
let _ac = JSAutoCompartment::new(cx, window.get());
|
||||
unsafe { SetWindowProxy(cx, window, browsing_context.reflector().get_jsobject()); }
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
@ -1489,7 +1485,11 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn suspend(&self) {
|
||||
// Suspend timer events.
|
||||
self.upcast::<GlobalScope>().suspend();
|
||||
|
||||
// TODO: set the window proxy to resolve to an object which throws security errors. #15233
|
||||
|
||||
// A hint to the JS runtime that now would be a good time to
|
||||
// GC any unreachable objects generated by user script,
|
||||
// or unattached DOM nodes. Attached DOM nodes can't be GCd yet,
|
||||
@ -1498,7 +1498,15 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn resume(&self) {
|
||||
// Resume timer events.
|
||||
self.upcast::<GlobalScope>().resume();
|
||||
|
||||
// Set the window proxy to be this object.
|
||||
self.browsing_context().set_window_proxy(&self);
|
||||
|
||||
// Push the document title to the compositor since we are
|
||||
// activating this document due to a navigation.
|
||||
self.Document().title_changed();
|
||||
}
|
||||
|
||||
pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool {
|
||||
|
@ -10,8 +10,7 @@ use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::js::Root;
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::browsingcontext::BrowsingContext;
|
||||
use dom::document::{Document, DocumentSource, IsHTMLDocument};
|
||||
use dom::document::{Document, DocumentSource, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::location::Location;
|
||||
use dom::node::Node;
|
||||
use dom::window::Window;
|
||||
@ -28,7 +27,7 @@ pub struct XMLDocument {
|
||||
|
||||
impl XMLDocument {
|
||||
fn new_inherited(window: &Window,
|
||||
browsing_context: Option<&BrowsingContext>,
|
||||
has_browsing_context: HasBrowsingContext,
|
||||
url: Option<ServoUrl>,
|
||||
origin: Origin,
|
||||
is_html_document: IsHTMLDocument,
|
||||
@ -39,7 +38,7 @@ impl XMLDocument {
|
||||
doc_loader: DocumentLoader) -> XMLDocument {
|
||||
XMLDocument {
|
||||
document: Document::new_inherited(window,
|
||||
browsing_context,
|
||||
has_browsing_context,
|
||||
url,
|
||||
origin,
|
||||
is_html_document,
|
||||
@ -54,7 +53,7 @@ impl XMLDocument {
|
||||
}
|
||||
|
||||
pub fn new(window: &Window,
|
||||
browsing_context: Option<&BrowsingContext>,
|
||||
has_browsing_context: HasBrowsingContext,
|
||||
url: Option<ServoUrl>,
|
||||
origin: Origin,
|
||||
doctype: IsHTMLDocument,
|
||||
@ -66,7 +65,7 @@ impl XMLDocument {
|
||||
-> Root<XMLDocument> {
|
||||
let doc = reflect_dom_object(
|
||||
box XMLDocument::new_inherited(window,
|
||||
browsing_context,
|
||||
has_browsing_context,
|
||||
url,
|
||||
origin,
|
||||
doctype,
|
||||
|
@ -20,7 +20,7 @@ use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::reflector::{DomObject, reflect_dom_object};
|
||||
use dom::bindings::str::{ByteString, DOMString, USVString, is_token};
|
||||
use dom::blob::{Blob, BlobImpl};
|
||||
use dom::document::{Document, IsHTMLDocument};
|
||||
use dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
|
||||
use dom::document::DocumentSource;
|
||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use dom::eventtarget::EventTarget;
|
||||
@ -1223,7 +1223,7 @@ impl XMLHttpRequest {
|
||||
DOMString::from(format!("{}", mime))
|
||||
});
|
||||
Document::new(win,
|
||||
None,
|
||||
HasBrowsingContext::No,
|
||||
parsed_url,
|
||||
doc.origin().alias(),
|
||||
is_html_document,
|
||||
|
@ -41,7 +41,7 @@ use dom::bindings::str::DOMString;
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::bindings::utils::WRAP_CALLBACKS;
|
||||
use dom::browsingcontext::BrowsingContext;
|
||||
use dom::document::{Document, DocumentSource, FocusType, IsHTMLDocument, TouchEventResult};
|
||||
use dom::document::{Document, DocumentSource, FocusType, HasBrowsingContext, IsHTMLDocument, TouchEventResult};
|
||||
use dom::element::Element;
|
||||
use dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use dom::globalscope::GlobalScope;
|
||||
@ -391,13 +391,15 @@ impl<'a> Iterator for DocumentsIter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
// ScriptThread instances are rooted on creation, so this is okay
|
||||
#[allow(unrooted_must_root)]
|
||||
pub struct ScriptThread {
|
||||
/// The documents for pipelines managed by this thread
|
||||
documents: DOMRefCell<Documents>,
|
||||
/// The browsing contexts known by this thread
|
||||
/// TODO: this map grows, but never shrinks. Issue #15258.
|
||||
browsing_contexts: DOMRefCell<HashMap<FrameId, JS<BrowsingContext>>>,
|
||||
/// A list of data pertaining to loads that have not yet received a network response
|
||||
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
|
||||
/// A map to store service worker registrations for a given origin
|
||||
@ -651,6 +653,7 @@ impl ScriptThread {
|
||||
|
||||
ScriptThread {
|
||||
documents: DOMRefCell::new(Documents::new()),
|
||||
browsing_contexts: DOMRefCell::new(HashMap::new()),
|
||||
incomplete_loads: DOMRefCell::new(vec!()),
|
||||
registration_map: DOMRefCell::new(HashMap::new()),
|
||||
job_queue_map: Rc::new(JobQueue::new()),
|
||||
@ -1514,29 +1517,26 @@ impl ScriptThread {
|
||||
load.pipeline_id == id
|
||||
});
|
||||
|
||||
if let Some(idx) = idx {
|
||||
let chan = if let Some(idx) = idx {
|
||||
let load = self.incomplete_loads.borrow_mut().remove(idx);
|
||||
|
||||
// Tell the layout thread to begin shutting down, and wait until it
|
||||
// processed this message.
|
||||
let (response_chan, response_port) = channel();
|
||||
let chan = &load.layout_chan;
|
||||
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
|
||||
debug!("shutting down layout for page {}", id);
|
||||
response_port.recv().unwrap();
|
||||
chan.send(message::Msg::ExitNow).ok();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(document) = self.documents.borrow_mut().remove(id) {
|
||||
shut_down_layout(document.window());
|
||||
load.layout_chan.clone()
|
||||
} else if let Some(document) = self.documents.borrow_mut().remove(id) {
|
||||
let window = document.window();
|
||||
if discard_bc == DiscardBrowsingContext::Yes {
|
||||
if let Some(context) = document.browsing_context() {
|
||||
context.discard();
|
||||
}
|
||||
window.browsing_context().discard();
|
||||
}
|
||||
let _ = self.constellation_chan.send(ConstellationMsg::PipelineExited(id));
|
||||
}
|
||||
window.clear_js_runtime();
|
||||
window.layout_chan().clone()
|
||||
} else {
|
||||
return warn!("Exiting nonexistant pipeline {}.", id);
|
||||
};
|
||||
|
||||
let (response_chan, response_port) = channel();
|
||||
chan.send(message::Msg::PrepareToExit(response_chan)).ok();
|
||||
debug!("shutting down layout for page {}", id);
|
||||
response_port.recv().unwrap();
|
||||
chan.send(message::Msg::ExitNow).ok();
|
||||
self.constellation_chan.send(ConstellationMsg::PipelineExited(id)).ok();
|
||||
|
||||
debug!("Exited pipeline {}.", id);
|
||||
}
|
||||
@ -1693,8 +1693,18 @@ impl ScriptThread {
|
||||
self.webvr_thread.clone());
|
||||
let frame_element = frame_element.r().map(Castable::upcast);
|
||||
|
||||
let browsing_context = BrowsingContext::new(&window, frame_element);
|
||||
window.init_browsing_context(&browsing_context);
|
||||
match self.browsing_contexts.borrow_mut().entry(incomplete.frame_id) {
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let browsing_context = BrowsingContext::new(&window, frame_element);
|
||||
entry.insert(JS::from_ref(&*browsing_context));
|
||||
window.init_browsing_context(&browsing_context);
|
||||
},
|
||||
hash_map::Entry::Occupied(entry) => {
|
||||
let browsing_context = entry.get();
|
||||
browsing_context.set_window_proxy(&window);
|
||||
window.init_browsing_context(browsing_context);
|
||||
},
|
||||
}
|
||||
|
||||
let last_modified = metadata.headers.as_ref().and_then(|headers| {
|
||||
headers.get().map(|&LastModified(HttpDate(ref tm))| dom_last_modified(tm))
|
||||
@ -1735,7 +1745,7 @@ impl ScriptThread {
|
||||
.map(ReferrerPolicy::from);
|
||||
|
||||
let document = Document::new(&window,
|
||||
Some(&browsing_context),
|
||||
HasBrowsingContext::Yes,
|
||||
Some(final_url.clone()),
|
||||
incomplete.origin,
|
||||
is_html_document,
|
||||
@ -2139,29 +2149,6 @@ impl Drop for ScriptThread {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shuts down layout for the given window.
|
||||
fn shut_down_layout(window: &Window) {
|
||||
// Tell the layout thread to begin shutting down, and wait until it
|
||||
// processed this message.
|
||||
let (response_chan, response_port) = channel();
|
||||
let chan = window.layout_chan().clone();
|
||||
if chan.send(message::Msg::PrepareToExit(response_chan)).is_ok() {
|
||||
let _ = response_port.recv();
|
||||
}
|
||||
|
||||
// The browsing context is cleared by window.clear_js_runtime(), so we need to save a copy
|
||||
let browsing_context = window.browsing_context();
|
||||
|
||||
// Drop our references to the JSContext and DOM objects.
|
||||
window.clear_js_runtime();
|
||||
|
||||
// Discard the browsing context.
|
||||
browsing_context.discard();
|
||||
|
||||
// Destroy the layout thread. If there were node leaks, layout will now crash safely.
|
||||
chan.send(message::Msg::ExitNow).ok();
|
||||
}
|
||||
|
||||
fn dom_last_modified(tm: &Tm) -> String {
|
||||
tm.to_local().strftime("%m/%d/%Y %H:%M:%S").unwrap().to_string()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user