aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-03-22 21:36:51 -0600
committerbors-servo <metajack+bors@gmail.com>2015-03-22 21:36:51 -0600
commit1f682d878db99651bfd26b8a28b57895f2238f87 (patch)
treec74936efd24415d3603b9658b21f4aee44c68a9b /components/script/dom
parentdfb8929b001c8d0fb6d5e63f5a9d6dcc17cb388a (diff)
parentbf9b8f705019e8d0bb2ff9ff18846b3e81d4b26f (diff)
downloadservo-1f682d878db99651bfd26b8a28b57895f2238f87.tar.gz
servo-1f682d878db99651bfd26b8a28b57895f2238f87.zip
auto merge of #5281 : glennw/servo/mozbrowser, r=jdm
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/document.rs23
-rw-r--r--components/script/dom/htmliframeelement.rs119
-rw-r--r--components/script/dom/webidls/BrowserElement.webidl138
-rw-r--r--components/script/dom/webidls/HTMLIFrameElement.webidl7
-rw-r--r--components/script/dom/window.rs16
5 files changed, 291 insertions, 12 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index d6e5f49b433..c11c22b67b6 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -60,13 +60,14 @@ use dom::window::{Window, WindowHelpers, ReflowReason};
use layout_interface::{HitTestResponse, MouseOverResponse};
use msg::compositor_msg::ScriptListener;
-use msg::constellation_msg::{Key, KeyState, KeyModifiers};
+use msg::constellation_msg::Msg as ConstellationMsg;
+use msg::constellation_msg::{ConstellationChan, Key, KeyState, KeyModifiers};
use msg::constellation_msg::{SUPER, ALT, SHIFT, CONTROL};
use net::resource_task::ControlMsg::{SetCookiesForUrl, GetCookiesForUrl};
use net::cookie_storage::CookieSource::NonHTTP;
use script_task::Runnable;
use script_traits::UntrustedNodeAddress;
-use util::namespace;
+use util::{opts, namespace};
use util::str::{DOMString, split_html_space_chars};
use layout_interface::{ReflowGoal, ReflowQueryType};
@@ -1450,7 +1451,23 @@ impl DocumentProgressHandler {
event.r().fire(target);
});
- window_ref.reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DocumentLoaded);
+ if opts::experimental_enabled() {
+ // If this is a child frame, and experimental mode is enabled,
+ // send the mozbrowserloadend event. For details, see
+ // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadend
+ if let Some((containing_pipeline_id, subpage_id)) = window_ref.parent_info() {
+ let ConstellationChan(ref chan) = window_ref.constellation_chan();
+ let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id,
+ subpage_id,
+ "mozbrowserloadend".to_owned(),
+ None);
+ chan.send(event);
+ }
+ }
+
+ window_ref.reflow(ReflowGoal::ForDisplay,
+ ReflowQueryType::NoQuery,
+ ReflowReason::DocumentLoaded);
}
}
diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs
index 61ce736bb7e..b35fb8695f8 100644
--- a/components/script/dom/htmliframeelement.rs
+++ b/components/script/dom/htmliframeelement.rs
@@ -8,12 +8,18 @@ use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
-use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
-use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLIFrameElementDerived};
+use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventCast};
+use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLElementCast, HTMLIFrameElementDerived};
+use dom::bindings::conversions::ToJSValConvertible;
+use dom::bindings::error::{ErrorResult, Fallible};
+use dom::bindings::error::Error::NotSupported;
+use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
+use dom::customevent::CustomEvent;
use dom::document::Document;
use dom::element::Element;
use dom::element::AttributeHandlers;
+use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::element::ElementTypeId;
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
@@ -23,13 +29,15 @@ use dom::virtualmethods::VirtualMethods;
use dom::window::{Window, WindowHelpers};
use page::IterablePage;
-use msg::constellation_msg::{PipelineId, SubpageId, ConstellationChan};
+use msg::constellation_msg::{PipelineId, SubpageId, ConstellationChan, NavigationDirection};
use msg::constellation_msg::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed};
use msg::constellation_msg::Msg as ConstellationMsg;
+use util::opts;
use util::str::DOMString;
use string_cache::Atom;
use std::ascii::AsciiExt;
+use std::borrow::ToOwned;
use std::cell::Cell;
use url::{Url, UrlParser};
@@ -64,6 +72,7 @@ pub trait HTMLIFrameElementHelpers {
fn process_the_iframe_attributes(self);
fn generate_new_subpage_id(self) -> (SubpageId, Option<SubpageId>);
fn navigate_child_browsing_context(self, url: Url);
+ fn dispatch_mozbrowser_event(self, event_name: String, event_detail: Option<String>);
}
impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
@@ -112,6 +121,11 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
new_subpage_id,
old_subpage_id,
sandboxed)).unwrap();
+
+ if opts::experimental_enabled() {
+ // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
+ self.dispatch_mozbrowser_event("mozbrowserloadstart".to_owned(), None);
+ }
}
fn process_the_iframe_attributes(self) {
@@ -122,6 +136,26 @@ impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
self.navigate_child_browsing_context(url);
}
+
+ fn dispatch_mozbrowser_event(self, event_name: String, event_detail: Option<String>) {
+ // TODO(gw): Support mozbrowser event types that have detail which is not a string.
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API
+ // for a list of mozbrowser events.
+ assert!(opts::experimental_enabled());
+
+ if self.Mozbrowser() {
+ let window = window_from_node(self).root();
+ let cx = window.r().get_cx();
+ let custom_event = CustomEvent::new(GlobalRef::Window(window.r()),
+ event_name.to_owned(),
+ true,
+ true,
+ event_detail.to_jsval(cx)).root();
+ let target: JSRef<EventTarget> = EventTargetCast::from_ref(self);
+ let event: JSRef<Event> = EventCast::from_ref(custom_event.r());
+ event.fire(target);
+ }
+ }
}
impl HTMLIFrameElement {
@@ -199,6 +233,85 @@ impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
}
})
}
+
+ // Experimental mozbrowser implementation is based on the webidl
+ // present in the gecko source tree, and the documentation here:
+ // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API
+
+ // TODO(gw): Use experimental codegen when it is available to avoid
+ // exposing these APIs. See https://github.com/servo/servo/issues/5264.
+
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-mozbrowser
+ fn Mozbrowser(self) -> bool {
+ if opts::experimental_enabled() {
+ let element: JSRef<Element> = ElementCast::from_ref(self);
+ element.has_attribute(&Atom::from_slice("mozbrowser"))
+ } else {
+ false
+ }
+ }
+
+ fn SetMozbrowser(self, value: bool) -> ErrorResult {
+ if opts::experimental_enabled() {
+ let element: JSRef<Element> = ElementCast::from_ref(self);
+ element.set_bool_attribute(&Atom::from_slice("mozbrowser"), value);
+ }
+ Ok(())
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goBack
+ fn GoBack(self) -> Fallible<()> {
+ if self.Mozbrowser() {
+ let node: JSRef<Node> = NodeCast::from_ref(self);
+ if node.is_in_doc() {
+ let window = window_from_node(self).root();
+ let window = window.r();
+
+ let pipeline_info = Some((self.containing_page_pipeline_id().unwrap(),
+ self.subpage_id().unwrap()));
+ let ConstellationChan(ref chan) = window.constellation_chan();
+ let msg = ConstellationMsg::Navigate(pipeline_info, NavigationDirection::Back);
+ chan.send(msg).unwrap();
+ }
+
+ Ok(())
+ } else {
+ debug!("this frame is not mozbrowser (or experimental_enabled is false)");
+ Err(NotSupported)
+ }
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/goForward
+ fn GoForward(self) -> Fallible<()> {
+ if self.Mozbrowser() {
+ let node: JSRef<Node> = NodeCast::from_ref(self);
+ if node.is_in_doc() {
+ let window = window_from_node(self).root();
+ let window = window.r();
+
+ let pipeline_info = Some((self.containing_page_pipeline_id().unwrap(),
+ self.subpage_id().unwrap()));
+ let ConstellationChan(ref chan) = window.constellation_chan();
+ let msg = ConstellationMsg::Navigate(pipeline_info, NavigationDirection::Forward);
+ chan.send(msg).unwrap();
+ }
+
+ Ok(())
+ } else {
+ debug!("this frame is not mozbrowser (or experimental_enabled is false)");
+ Err(NotSupported)
+ }
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/reload
+ fn Reload(self, _hardReload: bool) -> Fallible<()> {
+ Err(NotSupported)
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/stop
+ fn Stop(self) -> Fallible<()> {
+ Err(NotSupported)
+ }
}
impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
diff --git a/components/script/dom/webidls/BrowserElement.webidl b/components/script/dom/webidls/BrowserElement.webidl
new file mode 100644
index 00000000000..a0db071972e
--- /dev/null
+++ b/components/script/dom/webidls/BrowserElement.webidl
@@ -0,0 +1,138 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/.
+ */
+
+//callback BrowserElementNextPaintEventCallback = void ();
+
+//dictionary BrowserElementDownloadOptions {
+// DOMString? filename;
+//};
+
+[NoInterfaceObject]
+interface BrowserElement {
+};
+
+BrowserElement implements BrowserElementCommon;
+BrowserElement implements BrowserElementPrivileged;
+
+[NoInterfaceObject]
+interface BrowserElementCommon {
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser embed-widgets"]
+ //void setVisible(boolean visible);
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser embed-widgets"]
+ //DOMRequest getVisible();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser embed-widgets"]
+ //void addNextPaintListener(BrowserElementNextPaintEventCallback listener);
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser embed-widgets"]
+ //void removeNextPaintListener(BrowserElementNextPaintEventCallback listener);
+};
+
+[NoInterfaceObject]
+interface BrowserElementPrivileged {
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //void sendMouseEvent(DOMString type,
+ // unsigned long x,
+ // unsigned long y,
+ // unsigned long button,
+ // unsigned long clickCount,
+ // unsigned long modifiers);
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // Func="TouchEvent::PrefEnabled",
+ // CheckPermissions="browser"]
+ //void sendTouchEvent(DOMString type,
+ // sequence<unsigned long> identifiers,
+ // sequence<long> x,
+ // sequence<long> y,
+ // sequence<unsigned long> rx,
+ // sequence<unsigned long> ry,
+ // sequence<float> rotationAngles,
+ // sequence<float> forces,
+ // unsigned long count,
+ // unsigned long modifiers);
+
+ [Throws,
+ Pref="dom.mozBrowserFramesEnabled",
+ CheckPermissions="browser"]
+ void goBack();
+
+ [Throws,
+ Pref="dom.mozBrowserFramesEnabled",
+ CheckPermissions="browser"]
+ void goForward();
+
+ [Throws,
+ Pref="dom.mozBrowserFramesEnabled",
+ CheckPermissions="browser"]
+ void reload(optional boolean hardReload = false);
+
+ [Throws,
+ Pref="dom.mozBrowserFramesEnabled",
+ CheckPermissions="browser"]
+ void stop();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest download(DOMString url,
+ // optional BrowserElementDownloadOptions options);
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest purgeHistory();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest getScreenshot([EnforceRange] unsigned long width,
+ // [EnforceRange] unsigned long height,
+ // optional DOMString mimeType="");
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //void zoom(float zoom);
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest getCanGoBack();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest getCanGoForward();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest getContentDimensions();
+
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //DOMRequest setInputMethodActive(boolean isActive);
+
+ // Additional |nfc-manager| permission is required for setNFCFocus API
+ //[Throws,
+ // Pref="dom.mozBrowserFramesEnabled",
+ // CheckPermissions="browser"]
+ //void setNFCFocus(boolean isFocus);
+};
diff --git a/components/script/dom/webidls/HTMLIFrameElement.webidl b/components/script/dom/webidls/HTMLIFrameElement.webidl
index 7768065545c..558cdfd8030 100644
--- a/components/script/dom/webidls/HTMLIFrameElement.webidl
+++ b/components/script/dom/webidls/HTMLIFrameElement.webidl
@@ -31,3 +31,10 @@ partial interface HTMLIFrameElement {
//[TreatNullAs=EmptyString] attribute DOMString marginHeight;
//[TreatNullAs=EmptyString] attribute DOMString marginWidth;
};
+
+partial interface HTMLIFrameElement {
+ [ChromeOnly,SetterThrows]
+ attribute boolean mozbrowser;
+};
+
+HTMLIFrameElement implements BrowserElement;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 47b5c1c3149..038ec358f73 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -114,7 +114,7 @@ pub struct Window {
id: PipelineId,
/// Subpage id associated with this page, if any.
- subpage_id: Option<SubpageId>,
+ parent_info: Option<(PipelineId, SubpageId)>,
/// Unique id for last reflow request; used for confirming completion reply.
last_reflow_id: Cell<uint>,
@@ -164,11 +164,15 @@ impl Window {
}
pub fn pipeline(&self) -> PipelineId {
- self.id.clone()
+ self.id
}
pub fn subpage(&self) -> Option<SubpageId> {
- self.subpage_id.clone()
+ self.parent_info.map(|p| p.1)
+ }
+
+ pub fn parent_info(&self) -> Option<(PipelineId, SubpageId)> {
+ self.parent_info
}
pub fn control_chan<'a>(&'a self) -> &'a ScriptControlChan {
@@ -549,7 +553,7 @@ impl<'a> WindowHelpers for JSRef<'a, Window> {
let reflow = box Reflow {
document_root: root.to_trusted_node_address(),
url: self.get_url(),
- iframe: self.subpage_id.is_some(),
+ iframe: self.parent_info.is_some(),
goal: goal,
window_size: window_size,
script_chan: self.control_chan.clone(),
@@ -768,7 +772,7 @@ impl Window {
constellation_chan: ConstellationChan,
layout_chan: LayoutChan,
id: PipelineId,
- subpage_id: Option<SubpageId>,
+ parent_info: Option<(PipelineId, SubpageId)>,
window_size: Option<WindowSizeData>)
-> Temporary<Window> {
let layout_rpc: Box<LayoutRPC> = {
@@ -797,7 +801,7 @@ impl Window {
local_storage: Default::default(),
timers: TimerManager::new(),
id: id,
- subpage_id: subpage_id,
+ parent_info: parent_info,
dom_static: GlobalStaticData::new(),
js_context: DOMRefCell::new(Some(js_context.clone())),
resource_task: resource_task,