aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/browsingcontext.rs92
-rw-r--r--components/script/dom/document.rs43
-rw-r--r--components/script/dom/domimplementation.rs6
-rw-r--r--components/script/dom/domparser.rs6
-rw-r--r--components/script/dom/node.rs4
-rw-r--r--components/script/dom/servoparser/mod.rs4
-rw-r--r--components/script/dom/window.rs18
-rw-r--r--components/script/dom/xmldocument.rs11
-rw-r--r--components/script/dom/xmlhttprequest.rs4
9 files changed, 133 insertions, 55 deletions
diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs
index 1c2ca66b33e..9f0be02e484 100644
--- a/components/script/dom/browsingcontext.rs
+++ b/components/script/dom/browsingcontext.rs
@@ -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);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index da4d715fe21..be44ae0a91c 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -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
}
}
diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs
index 45983c3292d..4ec27cc5b36 100644
--- a/components/script/dom/domimplementation.rs
+++ b/components/script/dom/domimplementation.rs
@@ -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,
diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs
index 54132ef94a9..32b5c5343a1 100644
--- a/components/script/dom/domparser.rs
+++ b/components/script/dom/domparser.rs
@@ -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,
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 6931fca1822..37b5764c174 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -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(),
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index d64704b2368..0d8e02d273e 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -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,
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 37c62543526..86957d943d9 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -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 {
diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs
index 593749c4499..eaf90fbfe01 100644
--- a/components/script/dom/xmldocument.rs
+++ b/components/script/dom/xmldocument.rs
@@ -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,
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index f42afe87f8b..6fe89476994 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -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,