Auto merge of #9603 - Ms2ger:document-bc, r=jdm

Store a pointer to the browsing context in the Document.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9603)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-02-19 12:49:35 +05:30
commit ee158cc65f
10 changed files with 53 additions and 23 deletions

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::cell::DOMRefCell;
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject}; use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference}; use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor}; use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
@ -25,26 +26,24 @@ use js::jsval::{ObjectValue, UndefinedValue, PrivateValue};
#[dom_struct] #[dom_struct]
pub struct BrowsingContext { pub struct BrowsingContext {
reflector: Reflector, reflector: Reflector,
history: Vec<SessionHistoryEntry>, history: DOMRefCell<Vec<SessionHistoryEntry>>,
active_index: usize, active_index: usize,
frame_element: Option<JS<Element>>, frame_element: Option<JS<Element>>,
} }
impl BrowsingContext { impl BrowsingContext {
pub fn new_inherited(document: &Document, frame_element: Option<&Element>) -> BrowsingContext { pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
BrowsingContext { BrowsingContext {
reflector: Reflector::new(), reflector: Reflector::new(),
history: vec![SessionHistoryEntry::new(document)], history: DOMRefCell::new(vec![]),
active_index: 0, active_index: 0,
frame_element: frame_element.map(JS::from_ref), frame_element: frame_element.map(JS::from_ref),
} }
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn new(document: &Document, frame_element: Option<&Element>) -> Root<BrowsingContext> { pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
unsafe { unsafe {
let window = document.window();
let WindowProxyHandler(handler) = window.windowproxy_handler(); let WindowProxyHandler(handler) = window.windowproxy_handler();
assert!(!handler.is_null()); assert!(!handler.is_null());
@ -58,7 +57,7 @@ impl BrowsingContext {
NewWindowProxy(cx, parent, handler)); NewWindowProxy(cx, parent, handler));
assert!(!window_proxy.ptr.is_null()); assert!(!window_proxy.ptr.is_null());
let object = box BrowsingContext::new_inherited(document, frame_element); let object = box BrowsingContext::new_inherited(frame_element);
let raw = Box::into_raw(object); let raw = Box::into_raw(object);
SetProxyExtra(window_proxy.ptr, 0, PrivateValue(raw as *const _)); SetProxyExtra(window_proxy.ptr, 0, PrivateValue(raw as *const _));
@ -69,12 +68,18 @@ impl BrowsingContext {
} }
} }
pub fn active_document(&self) -> &Document { pub fn init(&self, document: &Document) {
&*self.history[self.active_index].document assert!(self.history.borrow().is_empty());
assert_eq!(self.active_index, 0);
self.history.borrow_mut().push(SessionHistoryEntry::new(document));
} }
pub fn active_window(&self) -> &Window { pub fn active_document(&self) -> Root<Document> {
self.active_document().window() Root::from_ref(&*self.history.borrow()[self.active_index].document)
}
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> {

View file

@ -30,6 +30,7 @@ use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::trace::RootedVec; use dom::bindings::trace::RootedVec;
use dom::bindings::xmlname::XMLName::InvalidXMLName; use dom::bindings::xmlname::XMLName::InvalidXMLName;
use dom::bindings::xmlname::{validate_and_extract, namespace_from_domstring, xml_name_type}; use dom::bindings::xmlname::{validate_and_extract, namespace_from_domstring, xml_name_type};
use dom::browsingcontext::BrowsingContext;
use dom::comment::Comment; use dom::comment::Comment;
use dom::customevent::CustomEvent; use dom::customevent::CustomEvent;
use dom::documentfragment::DocumentFragment; use dom::documentfragment::DocumentFragment;
@ -129,6 +130,8 @@ enum ParserBlockedByScript {
pub struct Document { pub struct Document {
node: Node, node: Node,
window: JS<Window>, window: JS<Window>,
/// https://html.spec.whatwg.org/multipage/#concept-document-bc
browsing_context: Option<JS<BrowsingContext>>,
implementation: MutNullableHeap<JS<DOMImplementation>>, implementation: MutNullableHeap<JS<DOMImplementation>>,
location: MutNullableHeap<JS<Location>>, location: MutNullableHeap<JS<Location>>,
content_type: DOMString, content_type: DOMString,
@ -279,6 +282,12 @@ impl Document {
self.loader.borrow_mut() self.loader.borrow_mut()
} }
/// 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)
}
#[inline] #[inline]
pub fn window(&self) -> &Window { pub fn window(&self) -> &Window {
&*self.window &*self.window
@ -309,7 +318,7 @@ impl Document {
let browsing_context = browsing_context.as_ref().unwrap(); let browsing_context = browsing_context.as_ref().unwrap();
let active_document = browsing_context.active_document(); let active_document = browsing_context.active_document();
if self != active_document { if self != &*active_document {
return false; return false;
} }
// FIXME: It should also check whether the browser context is top-level or not // FIXME: It should also check whether the browser context is top-level or not
@ -1507,6 +1516,7 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
impl Document { impl Document {
pub fn new_inherited(window: &Window, pub fn new_inherited(window: &Window,
browsing_context: Option<&BrowsingContext>,
url: Option<Url>, url: Option<Url>,
is_html_document: IsHTMLDocument, is_html_document: IsHTMLDocument,
content_type: Option<DOMString>, content_type: Option<DOMString>,
@ -1525,6 +1535,7 @@ impl Document {
Document { Document {
node: Node::new_document_node(), node: Node::new_document_node(),
window: JS::from_ref(window), window: JS::from_ref(window),
browsing_context: browsing_context.map(JS::from_ref),
implementation: Default::default(), implementation: Default::default(),
location: Default::default(), location: Default::default(),
content_type: match content_type { content_type: match content_type {
@ -1593,6 +1604,7 @@ impl Document {
let doc = doc.r(); let doc = doc.r();
let docloader = DocumentLoader::new(&*doc.loader()); let docloader = DocumentLoader::new(&*doc.loader());
Ok(Document::new(win, Ok(Document::new(win,
None,
None, None,
IsHTMLDocument::NonHTMLDocument, IsHTMLDocument::NonHTMLDocument,
None, None,
@ -1602,6 +1614,7 @@ impl Document {
} }
pub fn new(window: &Window, pub fn new(window: &Window,
browsing_context: Option<&BrowsingContext>,
url: Option<Url>, url: Option<Url>,
doctype: IsHTMLDocument, doctype: IsHTMLDocument,
content_type: Option<DOMString>, content_type: Option<DOMString>,
@ -1610,6 +1623,7 @@ impl Document {
doc_loader: DocumentLoader) doc_loader: DocumentLoader)
-> Root<Document> { -> Root<Document> {
let document = reflect_dom_object(box Document::new_inherited(window, let document = reflect_dom_object(box Document::new_inherited(window,
browsing_context,
url, url,
doctype, doctype,
content_type, content_type,
@ -1672,6 +1686,7 @@ impl Document {
IsHTMLDocument::NonHTMLDocument IsHTMLDocument::NonHTMLDocument
}; };
let new_doc = Document::new(self.window(), let new_doc = Document::new(self.window(),
None,
None, None,
doctype, doctype,
None, None,
@ -1761,7 +1776,7 @@ impl DocumentMethods for Document {
// Step 2. // Step 2.
let candidate = browsing_context.active_document(); let candidate = browsing_context.active_document();
// Step 3. // Step 3.
if candidate == target { if &*candidate == target {
true true
} else { } else {
false //TODO Step 4. false //TODO Step 4.

View file

@ -115,6 +115,7 @@ impl DOMImplementationMethods for DOMImplementation {
// Step 1-2. // Step 1-2.
let doc = Document::new(win, let doc = Document::new(win,
None,
None, None,
IsHTMLDocument::HTMLDocument, IsHTMLDocument::HTMLDocument,
None, None,

View file

@ -59,6 +59,7 @@ impl DOMParserMethods for DOMParser {
match ty { match ty {
Text_html => { Text_html => {
let document = Document::new(&self.window, let document = Document::new(&self.window,
None,
Some(url.clone()), Some(url.clone()),
IsHTMLDocument::HTMLDocument, IsHTMLDocument::HTMLDocument,
Some(content_type), Some(content_type),
@ -72,6 +73,7 @@ impl DOMParserMethods for DOMParser {
Text_xml => { Text_xml => {
// FIXME: this should probably be FromParser when we actually parse the string (#3756). // FIXME: this should probably be FromParser when we actually parse the string (#3756).
let document = Document::new(&self.window, let document = Document::new(&self.window,
None,
Some(url.clone()), Some(url.clone()),
IsHTMLDocument::NonHTMLDocument, IsHTMLDocument::NonHTMLDocument,
Some(content_type), Some(content_type),

View file

@ -1605,7 +1605,8 @@ impl Node {
}; };
let window = document.window(); let window = document.window();
let loader = DocumentLoader::new(&*document.loader()); let loader = DocumentLoader::new(&*document.loader());
let document = Document::new(window, Some((*document.url()).clone()), let document = Document::new(window, None,
Some((*document.url()).clone()),
is_html_doc, None, is_html_doc, None,
None, DocumentSource::NotFromParser, loader); None, DocumentSource::NotFromParser, loader);
Root::upcast::<Node>(document) Root::upcast::<Node>(document)

View file

@ -426,7 +426,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> {
Root::from_ref(self.browsing_context().as_ref().unwrap().active_document()) self.browsing_context().as_ref().unwrap().active_document()
} }
// https://html.spec.whatwg.org/multipage/#dom-location // https://html.spec.whatwg.org/multipage/#dom-location
@ -1095,8 +1095,9 @@ impl Window {
(element, response.rect) (element, response.rect)
} }
pub fn init_browsing_context(&self, doc: &Document, frame_element: Option<&Element>) { pub fn init_browsing_context(&self, browsing_context: &BrowsingContext) {
self.browsing_context.set(Some(&BrowsingContext::new(doc, frame_element))); assert!(self.browsing_context.get().is_none());
self.browsing_context.set(Some(&browsing_context));
} }
/// 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.
@ -1283,7 +1284,7 @@ impl Window {
browsing_context.frame_element().map(|frame_element| { browsing_context.frame_element().map(|frame_element| {
let window = window_from_node(frame_element); let window = window_from_node(frame_element);
let context = window.browsing_context(); let context = window.browsing_context();
Root::from_ref(context.unwrap().active_window()) context.unwrap().active_window()
}) })
} }
} }

View file

@ -35,6 +35,7 @@ impl XMLDocument {
doc_loader: DocumentLoader) -> XMLDocument { doc_loader: DocumentLoader) -> XMLDocument {
XMLDocument { XMLDocument {
document: Document::new_inherited(window, document: Document::new_inherited(window,
None,
url, url,
is_html_document, is_html_document,
content_type, content_type,

View file

@ -1230,6 +1230,7 @@ impl XMLHttpRequest {
DOMString::from(format!("{}", mime)) DOMString::from(format!("{}", mime))
}); });
Document::new(win, Document::new(win,
None,
parsed_url, parsed_url,
is_html_document, is_html_document,
content_type, content_type,

View file

@ -275,7 +275,7 @@ pub fn parse_html_fragment(context_node: &Node,
// Step 1. // Step 1.
let loader = DocumentLoader::new(&*context_document.loader()); let loader = DocumentLoader::new(&*context_document.loader());
let document = Document::new(window.r(), Some(url.clone()), let document = Document::new(window.r(), None, Some(url.clone()),
IsHTMLDocument::HTMLDocument, IsHTMLDocument::HTMLDocument,
None, None, None, None,
DocumentSource::FromParser, DocumentSource::FromParser,

View file

@ -32,6 +32,7 @@ use dom::bindings::js::{RootCollectionPtr, RootedReference};
use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference, trace_refcounted_objects}; use dom::bindings::refcounted::{LiveDOMReferences, Trusted, TrustedReference, trace_refcounted_objects};
use dom::bindings::trace::{JSTraceable, RootedVec, trace_traceables}; use dom::bindings::trace::{JSTraceable, RootedVec, trace_traceables};
use dom::bindings::utils::{DOM_CALLBACKS, WRAP_CALLBACKS}; use dom::bindings::utils::{DOM_CALLBACKS, WRAP_CALLBACKS};
use dom::browsingcontext::BrowsingContext;
use dom::document::{Document, DocumentProgressHandler, DocumentSource, FocusType, IsHTMLDocument}; use dom::document::{Document, DocumentProgressHandler, DocumentSource, FocusType, IsHTMLDocument};
use dom::element::Element; use dom::element::Element;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
@ -1795,6 +1796,10 @@ impl ScriptThread {
incomplete.parent_info, incomplete.parent_info,
incomplete.window_size); incomplete.window_size);
let frame_element = frame_element.r().map(Castable::upcast);
let browsing_context = BrowsingContext::new(&window, frame_element);
window.init_browsing_context(&browsing_context);
let last_modified = metadata.headers.as_ref().and_then(|headers| { let last_modified = metadata.headers.as_ref().and_then(|headers| {
headers.get().map(|&LastModified(HttpDate(ref tm))| dom_last_modified(tm)) headers.get().map(|&LastModified(HttpDate(ref tm))| dom_last_modified(tm))
}); });
@ -1822,16 +1827,14 @@ impl ScriptThread {
}; };
let document = Document::new(window.r(), let document = Document::new(window.r(),
Some(&browsing_context),
Some(final_url.clone()), Some(final_url.clone()),
is_html_document, is_html_document,
content_type, content_type,
last_modified, last_modified,
DocumentSource::FromParser, DocumentSource::FromParser,
loader); loader);
browsing_context.init(&document);
let frame_element = frame_element.r().map(Castable::upcast);
window.init_browsing_context(document.r(), frame_element);
document.set_ready_state(DocumentReadyState::Loading); document.set_ready_state(DocumentReadyState::Loading);
// Create the root frame // Create the root frame