mirror of
https://github.com/servo/servo.git
synced 2025-06-17 04:44:28 +00:00
Report errors using the top-level frame id rather than the pipeline id.
This commit is contained in:
parent
22aebdf5d4
commit
c228a4cf03
9 changed files with 203 additions and 195 deletions
|
@ -419,9 +419,9 @@ impl Log for FromScriptLogger {
|
|||
fn log(&self, record: &LogRecord) {
|
||||
if let Some(entry) = log_entry(record) {
|
||||
debug!("Sending log entry {:?}.", entry);
|
||||
let pipeline_id = PipelineId::installed();
|
||||
let top_level_frame_id = FrameId::installed();
|
||||
let thread_name = thread::current().name().map(ToOwned::to_owned);
|
||||
let msg = FromScriptMsg::LogEntry(pipeline_id, thread_name, entry);
|
||||
let msg = FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry);
|
||||
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
|
||||
let _ = chan.send(msg);
|
||||
}
|
||||
|
@ -457,9 +457,9 @@ impl Log for FromCompositorLogger {
|
|||
fn log(&self, record: &LogRecord) {
|
||||
if let Some(entry) = log_entry(record) {
|
||||
debug!("Sending log entry {:?}.", entry);
|
||||
let pipeline_id = PipelineId::installed();
|
||||
let top_level_frame_id = FrameId::installed();
|
||||
let thread_name = thread::current().name().map(ToOwned::to_owned);
|
||||
let msg = FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry);
|
||||
let msg = FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry);
|
||||
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
|
||||
let _ = chan.send(msg);
|
||||
}
|
||||
|
@ -605,9 +605,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
None
|
||||
};
|
||||
|
||||
// TODO: think about the case where the child pipeline is created
|
||||
// before the parent is part of the frame tree.
|
||||
let top_level_frame_id = match parent_info {
|
||||
Some((_, FrameType::MozBrowserIFrame)) => frame_id,
|
||||
Some((parent_id, _)) => self.get_top_level_frame_for_pipeline(parent_id),
|
||||
None => self.root_frame_id,
|
||||
};
|
||||
|
||||
let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
|
||||
id: pipeline_id,
|
||||
frame_id: frame_id,
|
||||
top_level_frame_id: top_level_frame_id,
|
||||
parent_info: parent_info,
|
||||
constellation_chan: self.script_sender.clone(),
|
||||
layout_to_constellation_chan: self.layout_sender.clone(),
|
||||
|
@ -847,8 +856,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
debug!("constellation got reload message");
|
||||
self.handle_reload_msg();
|
||||
}
|
||||
FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry) => {
|
||||
self.handle_log_entry(pipeline_id, thread_name, entry);
|
||||
FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
|
||||
self.handle_log_entry(top_level_frame_id, thread_name, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -999,8 +1008,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
FromScriptMsg::Exit => {
|
||||
self.compositor_proxy.send(ToCompositorMsg::Exit);
|
||||
}
|
||||
FromScriptMsg::LogEntry(pipeline_id, thread_name, entry) => {
|
||||
self.handle_log_entry(pipeline_id, thread_name, entry);
|
||||
FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
|
||||
self.handle_log_entry(top_level_frame_id, thread_name, entry);
|
||||
}
|
||||
|
||||
FromScriptMsg::SetTitle(pipeline_id, title) => {
|
||||
|
@ -1172,10 +1181,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IOError) {
|
||||
// Treat send error the same as receiving a panic message
|
||||
debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
|
||||
self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err), None);
|
||||
let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
let reason = format!("Send failed ({})", err);
|
||||
self.handle_panic(top_level_frame_id, reason, None);
|
||||
}
|
||||
|
||||
fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
|
||||
fn handle_panic(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
|
||||
if opts::get().hard_fail {
|
||||
// It's quite difficult to make Servo exit cleanly if some threads have failed.
|
||||
// Hard fail exists for test runners so we crash and that's good enough.
|
||||
|
@ -1183,26 +1194,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
process::exit(1);
|
||||
}
|
||||
|
||||
debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason);
|
||||
debug!("Panic handler for top-level frame {}: {}.", top_level_frame_id, reason);
|
||||
|
||||
// Notify the browser chrome that the pipeline has failed
|
||||
self.trigger_mozbrowsererror(pipeline_id, reason, backtrace);
|
||||
self.trigger_mozbrowsererror(top_level_frame_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);
|
||||
let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
|
||||
let frame_id = FrameId::from(top_level_frame_id);
|
||||
let pipeline_id = self.frames.get(&frame_id).map(|frame| frame.current.pipeline_id);
|
||||
let pipeline_url = pipeline_id.and_then(|id| self.pipelines.get(&id).map(|pipeline| pipeline.url.clone()));
|
||||
let parent_info = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.parent_info));
|
||||
let window_size = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.size));
|
||||
|
||||
self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
|
||||
self.pipelines.remove(&pipeline_id);
|
||||
|
||||
while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| {
|
||||
pending.old_pipeline_id == Some(pipeline_id)
|
||||
}).map(|frame| frame.new_pipeline_id) {
|
||||
warn!("removing pending frame change for failed pipeline");
|
||||
self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force);
|
||||
}
|
||||
self.close_frame_children(frame_id, ExitPipelineMode::Force);
|
||||
|
||||
let failure_url = ServoUrl::parse("about:failure").expect("infallible");
|
||||
|
||||
|
@ -1214,27 +1217,27 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
|
||||
warn!("creating replacement pipeline for about:failure");
|
||||
|
||||
if let Some(frame_id) = frame_id {
|
||||
let new_pipeline_id = PipelineId::new();
|
||||
let load_data = LoadData::new(failure_url, None, None);
|
||||
self.new_pipeline(new_pipeline_id, frame_id, parent_info, Some(pipeline_id),
|
||||
self.new_pipeline(new_pipeline_id, frame_id, parent_info, pipeline_id,
|
||||
window_size, None, load_data, false);
|
||||
|
||||
self.pending_frames.push(FrameChange {
|
||||
frame_id: frame_id,
|
||||
old_pipeline_id: Some(pipeline_id),
|
||||
old_pipeline_id: pipeline_id,
|
||||
new_pipeline_id: new_pipeline_id,
|
||||
document_ready: false,
|
||||
replace: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_log_entry(&mut self, pipeline_id: Option<PipelineId>, thread_name: Option<String>, entry: LogEntry) {
|
||||
fn handle_log_entry(&mut self, top_level_frame_id: Option<FrameId>, thread_name: Option<String>, entry: LogEntry) {
|
||||
debug!("Received log entry {:?}.", entry);
|
||||
match entry {
|
||||
LogEntry::Panic(reason, backtrace) => self.handle_panic(pipeline_id, reason, Some(backtrace)),
|
||||
LogEntry::Panic(reason, backtrace) => {
|
||||
let top_level_frame_id = top_level_frame_id.unwrap_or(self.root_frame_id);
|
||||
self.handle_panic(top_level_frame_id, reason, Some(backtrace));
|
||||
},
|
||||
LogEntry::Error(reason) | LogEntry::Warn(reason) => {
|
||||
// VecDeque::truncate is unstable
|
||||
if WARNINGS_BUFFER_SIZE <= self.handled_warnings.len() {
|
||||
|
@ -1291,25 +1294,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
|
||||
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) {
|
||||
let (frame_id, parent_info) = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
|
||||
None => return warn!("Pipeline {:?} loaded after closure.", pipeline_id),
|
||||
};
|
||||
let subframe_parent_id = match parent_info {
|
||||
Some(ref parent) => parent.0,
|
||||
None => return warn!("Pipeline {:?} has no parent.", pipeline_id),
|
||||
let (frame_id, parent_id) = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => match pipeline.parent_info {
|
||||
Some((parent_id, _)) => (pipeline.frame_id, parent_id),
|
||||
None => return warn!("Pipeline {} has no parent.", pipeline_id),
|
||||
},
|
||||
None => return warn!("Pipeline {} loaded after closure.", pipeline_id),
|
||||
};
|
||||
let msg = ConstellationControlMsg::DispatchFrameLoadEvent {
|
||||
target: frame_id,
|
||||
parent: subframe_parent_id,
|
||||
parent: parent_id,
|
||||
child: pipeline_id,
|
||||
};
|
||||
let result = match self.pipelines.get(&subframe_parent_id) {
|
||||
Some(pipeline) => pipeline.script_chan.send(msg),
|
||||
None => return warn!("Pipeline {:?} subframe loaded after closure.", subframe_parent_id),
|
||||
let result = match self.pipelines.get(&parent_id) {
|
||||
Some(parent) => parent.script_chan.send(msg),
|
||||
None => return warn!("Parent {} frame loaded after closure.", parent_id),
|
||||
};
|
||||
if let Err(e) = result {
|
||||
self.handle_send_error(subframe_parent_id, e);
|
||||
self.handle_send_error(parent_id, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1371,7 +1373,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
(load_data, script_chan, window_size, is_private)
|
||||
};
|
||||
|
||||
|
||||
// Create the new pipeline, attached to the parent and push to pending frames
|
||||
self.new_pipeline(load_info.new_pipeline_id,
|
||||
load_info.frame_id,
|
||||
|
@ -1428,37 +1429,27 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
pipeline_id: PipelineId,
|
||||
message: String,
|
||||
sender: IpcSender<bool>) {
|
||||
let display_alert_dialog = if PREFS.is_mozbrowser_enabled() {
|
||||
let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
|
||||
if parent_pipeline_info.is_some() {
|
||||
let root_pipeline_id = self.frames.get(&self.root_frame_id)
|
||||
.map(|root_frame| root_frame.current.pipeline_id);
|
||||
let pipeline_isnt_root = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info).is_some();
|
||||
let mozbrowser_modal_prompt = pipeline_isnt_root && PREFS.is_mozbrowser_enabled();
|
||||
|
||||
let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id);
|
||||
if let Some((ancestor_id, mozbrowser_iframe_id)) = ancestor_info {
|
||||
if root_pipeline_id == Some(ancestor_id) {
|
||||
match root_pipeline_id.and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) {
|
||||
Some(root_pipeline) => {
|
||||
if mozbrowser_modal_prompt {
|
||||
// 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(Some(mozbrowser_iframe_id), event);
|
||||
}
|
||||
None => return warn!("Alert sent to Pipeline {:?} after closure.", root_pipeline_id),
|
||||
}
|
||||
} else {
|
||||
warn!("A non-current frame is trying to show an alert.")
|
||||
}
|
||||
}
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
let prompt_type = String::from("alert");
|
||||
let title = String::from("Alert");
|
||||
let return_value = String::from("");
|
||||
let event = MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value);
|
||||
let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
|
||||
let result = sender.send(display_alert_dialog);
|
||||
match self.frames.get(&self.root_frame_id) {
|
||||
None => warn!("Alert sent after root frame closure."),
|
||||
Some(root_frame) => match self.pipelines.get(&root_frame.current.pipeline_id) {
|
||||
None => warn!("Alert sent after root pipeline closure."),
|
||||
Some(root_pipeline) => root_pipeline.trigger_mozbrowser_event(Some(top_level_frame_id), event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = sender.send(!mozbrowser_modal_prompt);
|
||||
if let Err(e) = result {
|
||||
self.handle_send_error(pipeline_id, e);
|
||||
}
|
||||
|
@ -1546,7 +1537,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
|
||||
fn handle_load_start_msg(&mut self, pipeline_id: PipelineId) {
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
let forward = !self.joint_session_future_is_empty(frame_id);
|
||||
let back = !self.joint_session_past_is_empty(frame_id);
|
||||
self.compositor_proxy.send(ToCompositorMsg::LoadStart(back, forward));
|
||||
|
@ -1564,7 +1555,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
if webdriver_reset {
|
||||
self.webdriver.load_channel = None;
|
||||
}
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
let forward = !self.joint_session_future_is_empty(frame_id);
|
||||
let back = !self.joint_session_past_is_empty(frame_id);
|
||||
let root = self.root_frame_id == frame_id;
|
||||
|
@ -1575,13 +1566,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
fn handle_traverse_history_msg(&mut self,
|
||||
pipeline_id: Option<PipelineId>,
|
||||
direction: TraversalDirection) {
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
let top_level_frame_id = pipeline_id
|
||||
.map(|pipeline_id| self.get_top_level_frame_for_pipeline(pipeline_id))
|
||||
.unwrap_or(self.root_frame_id);
|
||||
|
||||
let mut traversal_info = HashMap::new();
|
||||
|
||||
match direction {
|
||||
TraversalDirection::Forward(delta) => {
|
||||
let mut future = self.joint_session_future(frame_id);
|
||||
let mut future = self.joint_session_future(top_level_frame_id);
|
||||
for _ in 0..delta {
|
||||
match future.pop() {
|
||||
Some((_, frame_id, pipeline_id)) => {
|
||||
|
@ -1592,7 +1585,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
},
|
||||
TraversalDirection::Back(delta) => {
|
||||
let mut past = self.joint_session_past(frame_id);
|
||||
let mut past = self.joint_session_past(top_level_frame_id);
|
||||
for _ in 0..delta {
|
||||
match past.pop() {
|
||||
Some((_, frame_id, pipeline_id)) => {
|
||||
|
@ -1609,7 +1602,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
|
||||
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) {
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
|
||||
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
|
||||
|
||||
// Initialize length at 1 to count for the current active entry
|
||||
let mut length = 1;
|
||||
|
@ -1966,11 +1959,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> FrameId {
|
||||
fn get_top_level_frame_for_pipeline(&self, mut pipeline_id: PipelineId) -> FrameId {
|
||||
if PREFS.is_mozbrowser_enabled() {
|
||||
pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id))
|
||||
.map(|(_, mozbrowser_iframe_id)| mozbrowser_iframe_id)
|
||||
.unwrap_or(self.root_frame_id)
|
||||
loop {
|
||||
match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => match pipeline.parent_info {
|
||||
Some((_, FrameType::MozBrowserIFrame)) => return pipeline.frame_id,
|
||||
Some((parent_id, _)) => pipeline_id = parent_id,
|
||||
None => return self.root_frame_id,
|
||||
},
|
||||
None => {
|
||||
warn!("Finding top-level ancestor for pipeline {} after closure.", pipeline_id);
|
||||
return self.root_frame_id;
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If mozbrowser is not enabled, the root frame is the only top-level frame
|
||||
self.root_frame_id
|
||||
|
@ -2025,7 +2028,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
// This is the result of a link being clicked and a navigation completing.
|
||||
self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id);
|
||||
|
||||
let top_level_frame_id = self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id));
|
||||
let top_level_frame_id = self.get_top_level_frame_for_pipeline(frame_change.new_pipeline_id);
|
||||
self.clear_joint_session_future(top_level_frame_id);
|
||||
}
|
||||
|
||||
|
@ -2262,30 +2265,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
|
||||
// Close a frame (and all children)
|
||||
fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
|
||||
debug!("Closing frame {:?}.", frame_id);
|
||||
// Store information about the pipelines to be closed. Then close the
|
||||
// pipelines, before removing ourself from the frames hash map. This
|
||||
// ordering is vital - so that if close_pipeline() ends up closing
|
||||
// any child frames, they can be removed from the parent frame correctly.
|
||||
debug!("Closing frame {}.", frame_id);
|
||||
let parent_info = self.frames.get(&frame_id)
|
||||
.and_then(|frame| self.pipelines.get(&frame.current.pipeline_id))
|
||||
.and_then(|pipeline| pipeline.parent_info);
|
||||
|
||||
let pipelines_to_close = {
|
||||
let mut pipelines_to_close = vec!();
|
||||
|
||||
if let Some(frame) = self.frames.get(&frame_id) {
|
||||
pipelines_to_close.extend_from_slice(&frame.next);
|
||||
pipelines_to_close.push(frame.current.clone());
|
||||
pipelines_to_close.extend_from_slice(&frame.prev);
|
||||
}
|
||||
|
||||
pipelines_to_close
|
||||
};
|
||||
|
||||
for entry in pipelines_to_close {
|
||||
self.close_pipeline(entry.pipeline_id, exit_mode);
|
||||
}
|
||||
self.close_frame_children(frame_id, exit_mode);
|
||||
|
||||
if self.frames.remove(&frame_id).is_none() {
|
||||
warn!("Closing frame {:?} twice.", frame_id);
|
||||
|
@ -2301,6 +2286,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
debug!("Closed frame {:?}.", frame_id);
|
||||
}
|
||||
|
||||
// Close the children of a frame
|
||||
fn close_frame_children(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
|
||||
debug!("Closing frame children {}.", frame_id);
|
||||
// Store information about the pipelines to be closed. Then close the
|
||||
// pipelines, before removing ourself from the frames hash map. This
|
||||
// ordering is vital - so that if close_pipeline() ends up closing
|
||||
// any child frames, they can be removed from the parent frame correctly.
|
||||
let mut pipelines_to_close: Vec<PipelineId> = self.pending_frames.iter()
|
||||
.filter(|frame_change| frame_change.frame_id == frame_id)
|
||||
.map(|frame_change| frame_change.new_pipeline_id)
|
||||
.collect();
|
||||
|
||||
if let Some(frame) = self.frames.get(&frame_id) {
|
||||
pipelines_to_close.extend(frame.next.iter().map(|state| state.pipeline_id));
|
||||
pipelines_to_close.push(frame.current.pipeline_id);
|
||||
pipelines_to_close.extend(frame.prev.iter().map(|state| state.pipeline_id));
|
||||
}
|
||||
|
||||
for pipeline_id in pipelines_to_close {
|
||||
self.close_pipeline(pipeline_id, exit_mode);
|
||||
}
|
||||
|
||||
debug!("Closed frame children {}.", frame_id);
|
||||
}
|
||||
|
||||
// Close all pipelines at and beneath a given frame
|
||||
fn close_pipeline(&mut self, pipeline_id: PipelineId, exit_mode: ExitPipelineMode) {
|
||||
debug!("Closing pipeline {:?}.", pipeline_id);
|
||||
|
@ -2410,49 +2420,29 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
/// For a given pipeline, determine the mozbrowser iframe that transitively contains
|
||||
/// it. There could be arbitrary levels of nested iframes in between them.
|
||||
fn get_mozbrowser_ancestor_info(&self, original_pipeline_id: PipelineId) -> Option<(PipelineId, FrameId)> {
|
||||
let mut pipeline_id = original_pipeline_id;
|
||||
loop {
|
||||
match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => match pipeline.parent_info {
|
||||
Some((parent_id, FrameType::MozBrowserIFrame)) => return Some((parent_id, pipeline.frame_id)),
|
||||
Some((parent_id, _)) => pipeline_id = parent_id,
|
||||
None => return None,
|
||||
},
|
||||
None => {
|
||||
warn!("Finding mozbrowser ancestor for pipeline {} after closure.", pipeline_id);
|
||||
return None;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange
|
||||
// Note that this is a no-op if the pipeline is not a mozbrowser iframe
|
||||
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
|
||||
if !PREFS.is_mozbrowser_enabled() { return; }
|
||||
|
||||
let url = match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => pipeline.url.to_string(),
|
||||
None => return warn!("triggered mozbrowser location change on closed pipeline {:?}", pipeline_id),
|
||||
};
|
||||
|
||||
// If this is a mozbrowser iframe, then send the event with new url
|
||||
if let Some((ancestor_id, mozbrowser_frame_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
|
||||
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
|
||||
let can_go_forward = !self.joint_session_future(mozbrowser_frame_id).is_empty();
|
||||
let can_go_back = !self.joint_session_past(mozbrowser_frame_id).is_empty();
|
||||
match self.pipelines.get(&pipeline_id) {
|
||||
Some(pipeline) => if let Some((parent_id, FrameType::MozBrowserIFrame)) = pipeline.parent_info {
|
||||
match self.pipelines.get(&parent_id) {
|
||||
Some(parent) => {
|
||||
let can_go_forward = !self.joint_session_future_is_empty(pipeline.frame_id);
|
||||
let can_go_back = !self.joint_session_past_is_empty(pipeline.frame_id);
|
||||
let url = pipeline.url.to_string();
|
||||
let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward);
|
||||
ancestor.trigger_mozbrowser_event(Some(mozbrowser_frame_id), event);
|
||||
parent.trigger_mozbrowser_event(Some(pipeline.frame_id), event);
|
||||
},
|
||||
None => warn!("triggered mozbrowser location change on closed parent {}", parent_id),
|
||||
}
|
||||
},
|
||||
None => warn!("triggered mozbrowser location change on closed pipeline {}", pipeline_id),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
fn trigger_mozbrowsererror(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
|
||||
fn trigger_mozbrowsererror(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
|
||||
if !PREFS.is_mozbrowser_enabled() { return; }
|
||||
|
||||
let mut report = String::new();
|
||||
|
@ -2474,21 +2464,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
|
||||
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, reason, report);
|
||||
|
||||
if let Some(pipeline_id) = pipeline_id {
|
||||
if let Some((ancestor_id, mozbrowser_iframe_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
|
||||
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
|
||||
return ancestor.trigger_mozbrowser_event(Some(mozbrowser_iframe_id), event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(root_frame) = self.frames.get(&self.root_frame_id) {
|
||||
if let Some(root_pipeline) = self.pipelines.get(&root_frame.current.pipeline_id) {
|
||||
return root_pipeline.trigger_mozbrowser_event(None, event);
|
||||
}
|
||||
}
|
||||
|
||||
warn!("Mozbrowser error after root pipeline closed.");
|
||||
match self.frames.get(&top_level_frame_id) {
|
||||
None => warn!("Mozbrowser error after top-level frame closed."),
|
||||
Some(frame) => match self.pipelines.get(&frame.current.pipeline_id) {
|
||||
None => warn!("Mozbrowser error after top-level pipeline closed."),
|
||||
Some(pipeline) => match pipeline.parent_info {
|
||||
None => pipeline.trigger_mozbrowser_event(None, event),
|
||||
Some((parent_id, _)) => match self.pipelines.get(&parent_id) {
|
||||
None => warn!("Mozbrowser error after root pipeline closed."),
|
||||
Some(parent) => parent.trigger_mozbrowser_event(Some(top_level_frame_id), event),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool {
|
||||
|
|
|
@ -82,6 +82,8 @@ pub struct InitialPipelineState {
|
|||
pub id: PipelineId,
|
||||
/// The ID of the frame that contains this Pipeline.
|
||||
pub frame_id: FrameId,
|
||||
/// The ID of the top-level frame that contains this Pipeline.
|
||||
pub top_level_frame_id: FrameId,
|
||||
/// The ID of the parent pipeline and frame type, if any.
|
||||
/// If `None`, this is the root.
|
||||
pub parent_info: Option<(PipelineId, FrameType)>,
|
||||
|
@ -204,6 +206,7 @@ impl Pipeline {
|
|||
let unprivileged_pipeline_content = UnprivilegedPipelineContent {
|
||||
id: state.id,
|
||||
frame_id: state.frame_id,
|
||||
top_level_frame_id: state.top_level_frame_id,
|
||||
parent_info: state.parent_info,
|
||||
constellation_chan: state.constellation_chan,
|
||||
scheduler_chan: state.scheduler_chan,
|
||||
|
@ -381,6 +384,7 @@ impl Pipeline {
|
|||
pub struct UnprivilegedPipelineContent {
|
||||
id: PipelineId,
|
||||
frame_id: FrameId,
|
||||
top_level_frame_id: FrameId,
|
||||
parent_info: Option<(PipelineId, FrameType)>,
|
||||
constellation_chan: IpcSender<ScriptMsg>,
|
||||
layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
|
@ -416,6 +420,7 @@ impl UnprivilegedPipelineContent {
|
|||
let layout_pair = STF::create(InitialScriptState {
|
||||
id: self.id,
|
||||
frame_id: self.frame_id,
|
||||
top_level_frame_id: self.top_level_frame_id,
|
||||
parent_info: self.parent_info,
|
||||
control_chan: self.script_chan.clone(),
|
||||
control_port: self.script_port,
|
||||
|
@ -433,6 +438,7 @@ impl UnprivilegedPipelineContent {
|
|||
}, self.load_data.clone());
|
||||
|
||||
LTF::create(self.id,
|
||||
Some(self.top_level_frame_id),
|
||||
self.load_data.url,
|
||||
self.parent_info.is_some(),
|
||||
layout_pair,
|
||||
|
|
|
@ -42,7 +42,6 @@ extern crate selectors;
|
|||
extern crate serde_json;
|
||||
extern crate servo_url;
|
||||
extern crate style;
|
||||
extern crate style_traits;
|
||||
extern crate util;
|
||||
extern crate webrender_traits;
|
||||
|
||||
|
@ -80,7 +79,7 @@ use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBui
|
|||
use layout::wrapper::LayoutNodeLayoutData;
|
||||
use layout::wrapper::drop_style_and_layout_data;
|
||||
use layout_traits::LayoutThreadFactory;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::{FrameId, PipelineId};
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||
use net_traits::image_cache_thread::UsePlaceholder;
|
||||
use parking_lot::RwLock;
|
||||
|
@ -235,6 +234,7 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
|
||||
/// Spawns a new layout thread.
|
||||
fn create(id: PipelineId,
|
||||
top_level_frame_id: Option<FrameId>,
|
||||
url: ServoUrl,
|
||||
is_iframe: bool,
|
||||
chan: (Sender<Msg>, Receiver<Msg>),
|
||||
|
@ -251,7 +251,11 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
thread::spawn_named(format!("LayoutThread {:?}", id),
|
||||
move || {
|
||||
thread_state::initialize(thread_state::LAYOUT);
|
||||
PipelineId::install(id);
|
||||
|
||||
if let Some(top_level_frame_id) = top_level_frame_id {
|
||||
FrameId::install(top_level_frame_id);
|
||||
}
|
||||
|
||||
{ // Ensures layout thread is destroyed before we send shutdown message
|
||||
let sender = chan.0;
|
||||
let layout = LayoutThread::new(id,
|
||||
|
@ -718,6 +722,7 @@ impl LayoutThread {
|
|||
|
||||
fn create_layout_thread(&self, info: NewLayoutThreadInfo) {
|
||||
LayoutThread::create(info.id,
|
||||
FrameId::installed(),
|
||||
info.url.clone(),
|
||||
info.is_parent,
|
||||
info.layout_pair,
|
||||
|
|
|
@ -20,7 +20,7 @@ extern crate webrender_traits;
|
|||
|
||||
use gfx::font_cache_thread::FontCacheThread;
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::{FrameId, PipelineId};
|
||||
use net_traits::image_cache_thread::ImageCacheThread;
|
||||
use profile_traits::{mem, time};
|
||||
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
|
||||
|
@ -33,6 +33,7 @@ use std::sync::mpsc::{Receiver, Sender};
|
|||
pub trait LayoutThreadFactory {
|
||||
type Message;
|
||||
fn create(id: PipelineId,
|
||||
top_level_frame_id: Option<FrameId>,
|
||||
url: ServoUrl,
|
||||
is_iframe: bool,
|
||||
chan: (Sender<Self::Message>, Receiver<Self::Message>),
|
||||
|
|
|
@ -217,8 +217,6 @@ impl PipelineNamespace {
|
|||
|
||||
thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
|
||||
|
||||
thread_local!(pub static PIPELINE_ID: Cell<Option<PipelineId>> = Cell::new(None));
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
||||
pub struct PipelineNamespaceId(pub u32);
|
||||
|
||||
|
@ -246,15 +244,6 @@ impl PipelineId {
|
|||
let PipelineIndex(index) = self.index;
|
||||
webrender_traits::PipelineId(namespace_id, index)
|
||||
}
|
||||
|
||||
pub fn install(id: PipelineId) {
|
||||
PIPELINE_ID.with(|tls| tls.set(Some(id)))
|
||||
}
|
||||
|
||||
pub fn installed() -> Option<PipelineId> {
|
||||
PIPELINE_ID.with(|tls| tls.get())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl fmt::Display for PipelineId {
|
||||
|
@ -265,6 +254,8 @@ impl fmt::Display for PipelineId {
|
|||
}
|
||||
}
|
||||
|
||||
thread_local!(pub static TOP_LEVEL_FRAME_ID: Cell<Option<FrameId>> = Cell::new(None));
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
||||
pub struct FrameIndex(pub u32);
|
||||
|
||||
|
@ -283,6 +274,16 @@ impl FrameId {
|
|||
new_frame_id
|
||||
})
|
||||
}
|
||||
|
||||
/// Each script and layout thread should have the top-level frame id installed,
|
||||
/// since it is used by crash reporting.
|
||||
pub fn install(id: FrameId) {
|
||||
TOP_LEVEL_FRAME_ID.with(|tls| tls.set(Some(id)))
|
||||
}
|
||||
|
||||
pub fn installed() -> Option<FrameId> {
|
||||
TOP_LEVEL_FRAME_ID.with(|tls| tls.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FrameId {
|
||||
|
|
|
@ -26,7 +26,7 @@ use js::jsapi::{HandleValue, JS_SetInterruptCallback};
|
|||
use js::jsapi::{JSAutoCompartment, JSContext};
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::Runtime;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use msg::constellation_msg::FrameId;
|
||||
use net_traits::{IpcSend, load_whole_resource};
|
||||
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
|
||||
use rand::random;
|
||||
|
@ -158,9 +158,14 @@ impl DedicatedWorkerGlobalScope {
|
|||
closing: Arc<AtomicBool>) {
|
||||
let serialized_worker_url = worker_url.to_string();
|
||||
let name = format!("WebWorker for {}", serialized_worker_url);
|
||||
let top_level_frame_id = FrameId::installed();
|
||||
|
||||
spawn_named(name, move || {
|
||||
thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER);
|
||||
PipelineId::install(init.pipeline_id);
|
||||
|
||||
if let Some(top_level_frame_id) = top_level_frame_id {
|
||||
FrameId::install(top_level_frame_id);
|
||||
}
|
||||
|
||||
let roots = RootCollection::new();
|
||||
let _stack_roots_tls = StackRootTLS::new(&roots);
|
||||
|
|
|
@ -517,8 +517,8 @@ impl ScriptThreadFactory for ScriptThread {
|
|||
thread::spawn_named(format!("ScriptThread {:?}", state.id),
|
||||
move || {
|
||||
thread_state::initialize(thread_state::SCRIPT);
|
||||
PipelineId::install(state.id);
|
||||
PipelineNamespace::install(state.pipeline_namespace_id);
|
||||
FrameId::install(state.top_level_frame_id);
|
||||
let roots = RootCollection::new();
|
||||
let _stack_roots_tls = StackRootTLS::new(&roots);
|
||||
let id = state.id;
|
||||
|
|
|
@ -442,6 +442,8 @@ pub struct InitialScriptState {
|
|||
pub parent_info: Option<(PipelineId, FrameType)>,
|
||||
/// The ID of the frame this script is part of.
|
||||
pub frame_id: FrameId,
|
||||
/// The ID of the top-level frame this script is part of.
|
||||
pub top_level_frame_id: FrameId,
|
||||
/// A channel with which messages can be sent to us (the script thread).
|
||||
pub control_chan: IpcSender<ConstellationControlMsg>,
|
||||
/// A port on which messages sent by the constellation to script can be received.
|
||||
|
@ -699,8 +701,8 @@ pub enum ConstellationMsg {
|
|||
WebDriverCommand(WebDriverCommandMsg),
|
||||
/// Reload the current page.
|
||||
Reload,
|
||||
/// A log entry, with the pipeline id and thread name
|
||||
LogEntry(Option<PipelineId>, Option<String>, LogEntry),
|
||||
/// A log entry, with the top-level frame id and thread name
|
||||
LogEntry(Option<FrameId>, Option<String>, LogEntry),
|
||||
}
|
||||
|
||||
/// Resources required by workerglobalscopes
|
||||
|
|
|
@ -15,8 +15,8 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
|
|||
use euclid::point::Point2D;
|
||||
use euclid::size::Size2D;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
|
||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||
use msg::constellation_msg::{PipelineId, TraversalDirection};
|
||||
use net_traits::CoreResourceMsg;
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||
|
@ -131,8 +131,8 @@ pub enum ScriptMsg {
|
|||
ResizeTo(Size2D<u32>),
|
||||
/// Script has handled a touch event, and either prevented or allowed default actions.
|
||||
TouchEventProcessed(EventResult),
|
||||
/// A log entry, with the pipeline id and thread name
|
||||
LogEntry(Option<PipelineId>, Option<String>, LogEntry),
|
||||
/// A log entry, with the top-level frame id and thread name
|
||||
LogEntry(Option<FrameId>, Option<String>, LogEntry),
|
||||
/// Notifies the constellation that this pipeline has exited.
|
||||
PipelineExited(PipelineId),
|
||||
/// Send messages from postMessage calls from serviceworker
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue