Skip to content

Commit

Permalink
Allow window elements as well as iframes to the the target of mozbrow…
Browse files Browse the repository at this point in the history
…ser events.
  • Loading branch information
Alan Jeffrey committed Jul 18, 2016
1 parent fa432a5 commit 72aa4f2
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 153 deletions.
78 changes: 42 additions & 36 deletions components/constellation/constellation.rs
Expand Up @@ -1043,14 +1043,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason);

// Notify the browser chrome that the pipeline has failed
self.trigger_mozbrowsererror(pipeline_id, reason, backtrace);

if let Some(pipeline_id) = pipeline_id {
let pipeline_url = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.url.clone());
let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size);

// Notify the browser chrome that the pipeline has failed
self.trigger_mozbrowsererror(pipeline_id, reason, backtrace);

self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
self.pipelines.remove(&pipeline_id);

Expand Down Expand Up @@ -1082,12 +1082,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handled_panic = true;
}

// TODO: trigger a mozbrowsererror even if there's no pipeline id
fn handle_log_entry(&mut self, pipeline_id: Option<PipelineId>, thread_name: Option<String>, entry: LogEntry) {
match (pipeline_id, entry) {
(Some(pipeline_id), LogEntry::Panic(reason, backtrace)) =>
self.trigger_mozbrowsererror(pipeline_id, reason, backtrace),
(None, LogEntry::Panic(reason, _)) | (_, LogEntry::Error(reason)) | (_, LogEntry::Warn(reason)) => {
match entry {
LogEntry::Panic(reason, backtrace) => self.trigger_mozbrowsererror(pipeline_id, reason, backtrace),
LogEntry::Error(reason) | LogEntry::Warn(reason) => {
// VecDeque::truncate is unstable
if WARNINGS_BUFFER_SIZE <= self.handled_warnings.len() {
self.handled_warnings.pop_front();
Expand Down Expand Up @@ -1284,7 +1282,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt
let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(),
String::from(message), "".to_owned());
root_pipeline.trigger_mozbrowser_event(subpage_id, event);
root_pipeline.trigger_mozbrowser_event(Some(subpage_id), event);
}
None => return warn!("Alert sent to Pipeline {:?} after closure.", root_pipeline_id),
}
Expand Down Expand Up @@ -1578,7 +1576,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

fn handle_mozbrowser_event_msg(&mut self,
containing_pipeline_id: PipelineId,
subpage_id: SubpageId,
subpage_id: Option<SubpageId>,
event: MozBrowserEvent) {
assert!(PREFS.is_mozbrowser_enabled());

Expand Down Expand Up @@ -2271,7 +2269,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let can_go_backward = !frame.prev.is_empty();
let can_go_forward = !frame.next.is_empty();
let event = MozBrowserEvent::LocationChange(url, can_go_backward, can_go_forward);
parent_pipeline.trigger_mozbrowser_event(subpage_id, event);
parent_pipeline.trigger_mozbrowser_event(Some(subpage_id), event);
}
}
}
Expand All @@ -2280,35 +2278,43 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror
// Note that this does not require the pipeline to be an immediate child of the root
// TODO: allow the pipeline id to be optional, triggering the error on the root if it's not provided.
fn trigger_mozbrowsererror(&mut self, pipeline_id: PipelineId, reason: String, backtrace: String) {
fn trigger_mozbrowsererror(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: String) {
if !PREFS.is_mozbrowser_enabled() { return; }

let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id);

if let Some(ancestor_info) = ancestor_info {
match self.pipelines.get(&ancestor_info.0) {
Some(ancestor) => {
let mut report = String::new();
for (thread_name, warning) in self.handled_warnings.drain(..) {
report.push_str("\nWARNING: ");
if let Some(thread_name) = thread_name {
report.push_str("<");
report.push_str(&*thread_name);
report.push_str(">: ");
}
report.push_str(&*warning);
}
report.push_str("\nERROR: ");
report.push_str(&*reason);
report.push_str("\n\n");
report.push_str(&*backtrace);
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(report));
ancestor.trigger_mozbrowser_event(ancestor_info.1, event);
},
None => return warn!("Mozbrowsererror via closed pipeline {:?}.", ancestor_info.0),
let mut report = String::new();
for (thread_name, warning) in self.handled_warnings.drain(..) {
report.push_str("\nWARNING: ");
if let Some(thread_name) = thread_name {
report.push_str("<");
report.push_str(&*thread_name);
report.push_str(">: ");
}
report.push_str(&*warning);
}
report.push_str("\nERROR: ");
report.push_str(&*reason);
report.push_str("\n\n");
report.push_str(&*backtrace);

let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, Some(reason), Some(report));

if let Some(pipeline_id) = pipeline_id {
if let Some((ancestor_id, subpage_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
return ancestor.trigger_mozbrowser_event(Some(subpage_id), event);
}
}
}

if let Some(root_frame_id) = self.root_frame_id {
if let Some(root_frame) = self.frames.get(&root_frame_id) {
if let Some(root_pipeline) = self.pipelines.get(&root_frame.current) {
return root_pipeline.trigger_mozbrowser_event(None, event);
}
}
}

warn!("Mozbrowser error after root pipeline closed.");
}

fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion components/constellation/pipeline.rs
Expand Up @@ -376,7 +376,7 @@ impl Pipeline {
}

pub fn trigger_mozbrowser_event(&self,
subpage_id: SubpageId,
subpage_id: Option<SubpageId>,
event: MozBrowserEvent) {
assert!(PREFS.is_mozbrowser_enabled());

Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/document.rs
Expand Up @@ -1281,7 +1281,7 @@ impl Document {
if PREFS.is_mozbrowser_enabled() {
if let Some((containing_pipeline_id, subpage_id, _)) = self.window.parent_info() {
let event = ConstellationMsg::MozBrowserEvent(containing_pipeline_id,
subpage_id,
Some(subpage_id),
event);
self.window.constellation_chan().send(event).unwrap();
}
Expand Down
193 changes: 93 additions & 100 deletions components/script/dom/htmliframeelement.rs
Expand Up @@ -161,25 +161,11 @@ impl HTMLIFrameElement {

#[allow(unsafe_code)]
pub fn dispatch_mozbrowser_event(&self, event: MozBrowserEvent) {
// 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!(PREFS.is_mozbrowser_enabled());

if self.Mozbrowser() {
let window = window_from_node(self);
let custom_event = unsafe {
let cx = window.get_cx();
let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get());
rooted!(in(cx) let mut detail = UndefinedValue());
let event_name = Atom::from(event.name());
self.build_mozbrowser_event_detail(event, cx, detail.handle_mut());
CustomEvent::new(GlobalRef::Window(window.r()),
event_name,
true,
true,
detail.handle())
};
let custom_event = build_mozbrowser_custom_event(&window, event);
custom_event.upcast::<Event>().fire(self.upcast());
}
}
Expand Down Expand Up @@ -336,97 +322,104 @@ impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> {
}
}

pub trait MozBrowserEventDetailBuilder {
#[allow(unsafe_code)]
unsafe fn build_mozbrowser_event_detail(&self,
event: MozBrowserEvent,
cx: *mut JSContext,
rval: MutableHandleValue);
#[allow(unsafe_code)]
pub fn build_mozbrowser_custom_event(window: &Window, event: MozBrowserEvent) -> Root<CustomEvent> {
// 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.
let cx = window.get_cx();
let _ac = JSAutoCompartment::new(cx, window.reflector().get_jsobject().get());
rooted!(in(cx) let mut detail = UndefinedValue());
let event_name = Atom::from(event.name());
unsafe { build_mozbrowser_event_detail(event, cx, detail.handle_mut()); }
CustomEvent::new(GlobalRef::Window(window),
event_name,
true,
true,
detail.handle())
}

impl MozBrowserEventDetailBuilder for HTMLIFrameElement {
#[allow(unsafe_code)]
unsafe fn build_mozbrowser_event_detail(&self,
event: MozBrowserEvent,
cx: *mut JSContext,
rval: MutableHandleValue) {
match event {
MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu |
MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch |
MozBrowserEvent::UsernameAndPasswordRequired => {
rval.set(NullValue());
}
MozBrowserEvent::Error(error_type, description, report) => {
BrowserElementErrorEventDetail {
type_: Some(DOMString::from(error_type.name())),
description: description.map(DOMString::from),
report: report.map(DOMString::from),
version: Some(DOMString::from_string(servo_version().into())),
}.to_jsval(cx, rval);
},
MozBrowserEvent::SecurityChange(https_state) => {
BrowserElementSecurityChangeDetail {
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange
state: Some(DOMString::from(match https_state {
HttpsState::Modern => "secure",
HttpsState::Deprecated => "broken",
HttpsState::None => "insecure",
}.to_owned())),
// FIXME - Not supported yet:
trackingContent: None,
mixedContent: None,
trackingState: None,
extendedValidation: None,
mixedState: None,
}.to_jsval(cx, rval);
}
MozBrowserEvent::TitleChange(ref string) => {
string.to_jsval(cx, rval);
}
MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => {
BrowserElementLocationChangeEventDetail {
url: Some(DOMString::from(url)),
canGoBack: Some(can_go_back),
canGoForward: Some(can_go_forward),
}.to_jsval(cx, rval);
}
MozBrowserEvent::OpenTab(url) => {
BrowserElementOpenTabEventDetail {
url: Some(DOMString::from(url)),
}.to_jsval(cx, rval);
}
MozBrowserEvent::OpenWindow(url, target, features) => {
BrowserElementOpenWindowEventDetail {
url: Some(DOMString::from(url)),
target: target.map(DOMString::from),
features: features.map(DOMString::from),
}.to_jsval(cx, rval);
}
MozBrowserEvent::IconChange(rel, href, sizes) => {
BrowserElementIconChangeEventDetail {
rel: Some(DOMString::from(rel)),
href: Some(DOMString::from(href)),
sizes: Some(DOMString::from(sizes)),
}.to_jsval(cx, rval);
}
MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value) => {
BrowserShowModalPromptEventDetail {
promptType: Some(DOMString::from(prompt_type)),
title: Some(DOMString::from(title)),
message: Some(DOMString::from(message)),
returnValue: Some(DOMString::from(return_value)),
}.to_jsval(cx, rval)
}
MozBrowserEvent::VisibilityChange(visibility) => {
BrowserElementVisibilityChangeEventDetail {
visible: Some(visibility),
}.to_jsval(cx, rval);
}
#[allow(unsafe_code)]
unsafe fn build_mozbrowser_event_detail(event: MozBrowserEvent,
cx: *mut JSContext,
rval: MutableHandleValue) {
match event {
MozBrowserEvent::AsyncScroll | MozBrowserEvent::Close | MozBrowserEvent::ContextMenu |
MozBrowserEvent::LoadEnd | MozBrowserEvent::LoadStart |
MozBrowserEvent::Connected | MozBrowserEvent::OpenSearch |
MozBrowserEvent::UsernameAndPasswordRequired => {
rval.set(NullValue());
}
MozBrowserEvent::Error(error_type, description, report) => {
BrowserElementErrorEventDetail {
type_: Some(DOMString::from(error_type.name())),
description: description.map(DOMString::from),
report: report.map(DOMString::from),
version: Some(DOMString::from_string(servo_version().into())),
}.to_jsval(cx, rval);
},
MozBrowserEvent::SecurityChange(https_state) => {
BrowserElementSecurityChangeDetail {
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsersecuritychange
state: Some(DOMString::from(match https_state {
HttpsState::Modern => "secure",
HttpsState::Deprecated => "broken",
HttpsState::None => "insecure",
}.to_owned())),
// FIXME - Not supported yet:
trackingContent: None,
mixedContent: None,
trackingState: None,
extendedValidation: None,
mixedState: None,
}.to_jsval(cx, rval);
}
MozBrowserEvent::TitleChange(ref string) => {
string.to_jsval(cx, rval);
}
MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward) => {
BrowserElementLocationChangeEventDetail {
url: Some(DOMString::from(url)),
canGoBack: Some(can_go_back),
canGoForward: Some(can_go_forward),
}.to_jsval(cx, rval);
}
MozBrowserEvent::OpenTab(url) => {
BrowserElementOpenTabEventDetail {
url: Some(DOMString::from(url)),
}.to_jsval(cx, rval);
}
MozBrowserEvent::OpenWindow(url, target, features) => {
BrowserElementOpenWindowEventDetail {
url: Some(DOMString::from(url)),
target: target.map(DOMString::from),
features: features.map(DOMString::from),
}.to_jsval(cx, rval);
}
MozBrowserEvent::IconChange(rel, href, sizes) => {
BrowserElementIconChangeEventDetail {
rel: Some(DOMString::from(rel)),
href: Some(DOMString::from(href)),
sizes: Some(DOMString::from(sizes)),
}.to_jsval(cx, rval);
}
MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value) => {
BrowserShowModalPromptEventDetail {
promptType: Some(DOMString::from(prompt_type)),
title: Some(DOMString::from(title)),
message: Some(DOMString::from(message)),
returnValue: Some(DOMString::from(return_value)),
}.to_jsval(cx, rval)
}
MozBrowserEvent::VisibilityChange(visibility) => {
BrowserElementVisibilityChangeEventDetail {
visible: Some(visibility),
}.to_jsval(cx, rval);
}
}
}


pub fn Navigate(iframe: &HTMLIFrameElement, direction: NavigationDirection) -> ErrorResult {
if iframe.Mozbrowser() {
if iframe.upcast::<Node>().is_in_doc() {
Expand Down
11 changes: 10 additions & 1 deletion components/script/dom/window.rs
Expand Up @@ -28,7 +28,9 @@ use dom::crypto::Crypto;
use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration};
use dom::document::Document;
use dom::element::Element;
use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::htmliframeelement::build_mozbrowser_custom_event;
use dom::location::Location;
use dom::navigator::Navigator;
use dom::node::{Node, from_untrusted_node_address, window_from_node};
Expand Down Expand Up @@ -63,7 +65,7 @@ use script_runtime::{ScriptChan, ScriptPort, maybe_take_panic_result};
use script_thread::SendableMainThreadScriptChan;
use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, RunnableWrapper};
use script_traits::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
use script_traits::{ConstellationControlMsg, UntrustedNodeAddress};
use script_traits::{ConstellationControlMsg, MozBrowserEvent, UntrustedNodeAddress};
use script_traits::{DocumentState, MsDuration, TimerEvent, TimerEventId};
use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSource, WindowSizeData};
use std::ascii::AsciiExt;
Expand Down Expand Up @@ -1594,6 +1596,13 @@ impl Window {
_ => false,
}
}

#[allow(unsafe_code)]
pub fn dispatch_mozbrowser_event(&self, event: MozBrowserEvent) {
assert!(PREFS.is_mozbrowser_enabled());
let custom_event = build_mozbrowser_custom_event(&self, event);
custom_event.upcast::<Event>().fire(self.upcast());
}
}

impl Window {
Expand Down

0 comments on commit 72aa4f2

Please sign in to comment.