Refactor embedder NewBrowser flow

This commit is contained in:
Gregory Terzian 2018-06-07 22:37:53 +08:00
parent 96f75465cf
commit e784f5a9f7
7 changed files with 83 additions and 48 deletions

View file

@ -8,7 +8,6 @@ use embedder_traits::EventLoopWaker;
use euclid::TypedScale; use euclid::TypedScale;
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]
use gleam::gl; use gleam::gl;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
use script_traits::{MouseButton, TouchEventType, TouchId}; use script_traits::{MouseButton, TouchEventType, TouchId};
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength}; use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
@ -75,7 +74,7 @@ pub enum WindowEvent {
/// Sent when Ctr+R/Apple+R is called to reload the current page. /// Sent when Ctr+R/Apple+R is called to reload the current page.
Reload(TopLevelBrowsingContextId), Reload(TopLevelBrowsingContextId),
/// Create a new top level browsing context /// Create a new top level browsing context
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), NewBrowser(ServoUrl, TopLevelBrowsingContextId),
/// Close a top level browsing context /// Close a top level browsing context
CloseBrowser(TopLevelBrowsingContextId), CloseBrowser(TopLevelBrowsingContextId),
/// Panic a top level browsing context. /// Panic a top level browsing context.

View file

@ -578,7 +578,8 @@ where
let swmanager_receiver = let swmanager_receiver =
route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver); route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
PipelineNamespace::install(PipelineNamespaceId(0)); // Zero is reserved for the embedder.
PipelineNamespace::install(PipelineNamespaceId(1));
let mut constellation: Constellation<Message, LTF, STF> = Constellation { let mut constellation: Constellation<Message, LTF, STF> = Constellation {
script_sender: ipc_script_sender, script_sender: ipc_script_sender,
@ -605,8 +606,10 @@ where
pipelines: HashMap::new(), pipelines: HashMap::new(),
browsing_contexts: HashMap::new(), browsing_contexts: HashMap::new(),
pending_changes: vec![], pending_changes: vec![],
// We initialize the namespace at 1, since we reserved namespace 0 for the constellation // We initialize the namespace at 2,
next_pipeline_namespace_id: PipelineNamespaceId(1), // since we reserved namespace 0 for the embedder,
// and 0 for the constellation
next_pipeline_namespace_id: PipelineNamespaceId(2),
focus_pipeline_id: None, focus_pipeline_id: None,
time_profiler_chan: state.time_profiler_chan, time_profiler_chan: state.time_profiler_chan,
mem_profiler_chan: state.mem_profiler_chan, mem_profiler_chan: state.mem_profiler_chan,
@ -1026,8 +1029,8 @@ where
}, },
// Create a new top level browsing context. Will use response_chan to return // Create a new top level browsing context. Will use response_chan to return
// the browsing context id. // the browsing context id.
FromCompositorMsg::NewBrowser(url, response_chan) => { FromCompositorMsg::NewBrowser(url, top_level_browsing_context_id) => {
self.handle_new_top_level_browsing_context(url, response_chan); self.handle_new_top_level_browsing_context(url, top_level_browsing_context_id);
}, },
// Close a top level browsing context. // Close a top level browsing context.
FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => { FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => {
@ -1651,17 +1654,12 @@ where
fn handle_new_top_level_browsing_context( fn handle_new_top_level_browsing_context(
&mut self, &mut self,
url: ServoUrl, url: ServoUrl,
reply: IpcSender<TopLevelBrowsingContextId>, top_level_browsing_context_id: TopLevelBrowsingContextId
) { ) {
let window_size = self.window_size.initial_viewport; let window_size = self.window_size.initial_viewport;
let pipeline_id = PipelineId::new(); let pipeline_id = PipelineId::new();
let top_level_browsing_context_id = TopLevelBrowsingContextId::new(); let msg = (Some(top_level_browsing_context_id), EmbedderMsg::BrowserCreated(top_level_browsing_context_id));
if let Err(e) = reply.send(top_level_browsing_context_id) { self.embedder_proxy.send(msg);
warn!(
"Failed to send newly created top level browsing context ({}).",
e
);
}
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
let load_data = LoadData::new(url.clone(), None, None, None); let load_data = LoadData::new(url.clone(), None, None, None);
let sandbox = IFrameSandboxState::IFrameUnsandboxed; let sandbox = IFrameSandboxState::IFrameUnsandboxed;

View file

@ -717,7 +717,7 @@ pub enum ConstellationMsg {
/// Dispatch WebVR events to the subscribed script threads. /// Dispatch WebVR events to the subscribed script threads.
WebVREvents(Vec<PipelineId>, Vec<WebVREvent>), WebVREvents(Vec<PipelineId>, Vec<WebVREvent>),
/// Create a new top level browsing context. /// Create a new top level browsing context.
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>), NewBrowser(ServoUrl, TopLevelBrowsingContextId),
/// Close a top level browsing context. /// Close a top level browsing context.
CloseBrowser(TopLevelBrowsingContextId), CloseBrowser(TopLevelBrowsingContextId),
/// Panic a top level browsing context. /// Panic a top level browsing context.

View file

@ -87,6 +87,7 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_thread::FontCacheThread; use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use log::{Log, Metadata, Record}; use log::{Log, Metadata, Record};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId};
use net::resource_thread::new_resource_threads; use net::resource_thread::new_resource_threads;
use net_traits::IpcSend; use net_traits::IpcSend;
use profile::mem as profile_mem; use profile::mem as profile_mem;
@ -135,6 +136,9 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
// Make sure the gl context is made current. // Make sure the gl context is made current.
window.prepare_for_composite(Length::new(0), Length::new(0)); window.prepare_for_composite(Length::new(0), Length::new(0));
// Reserving a namespace to create TopLevelBrowserContextId.
PipelineNamespace::install(PipelineNamespaceId(0));
// Get both endpoints of a special channel for communication between // Get both endpoints of a special channel for communication between
// the client window and the compositor. This channel is unique because // the client window and the compositor. This channel is unique because
// messages to client may need to pump a platform-specific event loop // messages to client may need to pump a platform-specific event loop
@ -326,8 +330,8 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
self.compositor.capture_webrender(); self.compositor.capture_webrender();
} }
WindowEvent::NewBrowser(url, response_chan) => { WindowEvent::NewBrowser(url, browser_id) => {
let msg = ConstellationMsg::NewBrowser(url, response_chan); let msg = ConstellationMsg::NewBrowser(url, browser_id);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.constellation_chan.send(msg) {
warn!("Sending NewBrowser message to constellation failed ({}).", e); warn!("Sending NewBrowser message to constellation failed ({}).", e);
} }

View file

@ -8,7 +8,6 @@ use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, MouseWi
use servo::embedder_traits::EmbedderMsg; use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::resources::{self, Resource}; use servo::embedder_traits::resources::{self, Resource};
use servo::euclid::{Length, TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D}; use servo::euclid::{Length, TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
use servo::ipc_channel::ipc;
use servo::msg::constellation_msg::TraversalDirection; use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::{MouseButton, TouchEventType}; use servo::script_traits::{MouseButton, TouchEventType};
use servo::servo_config::opts; use servo::servo_config::opts;
@ -75,7 +74,14 @@ pub struct ServoGlue {
servo: Servo<ServoCallbacks>, servo: Servo<ServoCallbacks>,
batch_mode: bool, batch_mode: bool,
callbacks: Rc<ServoCallbacks>, callbacks: Rc<ServoCallbacks>,
browser_id: BrowserId, /// id of the top level browsing context. It is unique as tabs
/// are not supported yet. None until created.
browser_id: Option<BrowserId>,
// A rudimentary stack of "tabs".
// EmbedderMsg::BrowserCreated will push onto it.
// EmbedderMsg::CloseBrowser will pop from it,
// and exit if it is empty afterwards.
browsers: Vec<BrowserId>,
events: Vec<WindowEvent>, events: Vec<WindowEvent>,
current_url: Option<ServoUrl>, current_url: Option<ServoUrl>,
} }
@ -133,28 +139,34 @@ pub fn init(
waker, waker,
}); });
let mut servo = Servo::new(callbacks.clone()); let servo = Servo::new(callbacks.clone());
let (sender, receiver) = ipc::channel().map_err(|_| "Can't create ipc::channel")?;
servo.handle_events(vec![WindowEvent::NewBrowser(url.clone(), sender)]);
let browser_id = receiver.recv().map_err(|_| "Can't receive browser_id")?;
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
SERVO.with(|s| { SERVO.with(|s| {
*s.borrow_mut() = Some(ServoGlue { let mut servo_glue = ServoGlue {
servo, servo,
batch_mode: false, batch_mode: false,
callbacks, callbacks,
browser_id, browser_id: None,
browsers: vec![],
events: vec![], events: vec![],
current_url: Some(url), current_url: Some(url.clone()),
}); };
let browser_id = BrowserId::new();
let _ = servo_glue.process_event(WindowEvent::NewBrowser(url, browser_id));
*s.borrow_mut() = Some(servo_glue);
}); });
Ok(()) Ok(())
} }
impl ServoGlue { impl ServoGlue {
fn get_browser_id(&self) -> Result<BrowserId, &'static str> {
let browser_id = match self.browser_id {
Some(id) => id,
None => return Err("No BrowserId set yet.")
};
Ok(browser_id)
}
/// This is the Servo heartbeat. This needs to be called /// This is the Servo heartbeat. This needs to be called
/// everytime wakeup is called or when embedder wants Servo /// everytime wakeup is called or when embedder wants Servo
/// to act on its pending events. /// to act on its pending events.
@ -182,7 +194,8 @@ impl ServoGlue {
ServoUrl::parse(url) ServoUrl::parse(url)
.map_err(|_| "Can't parse URL") .map_err(|_| "Can't parse URL")
.and_then(|url| { .and_then(|url| {
let event = WindowEvent::LoadUrl(self.browser_id, url); let browser_id = self.get_browser_id()?;
let event = WindowEvent::LoadUrl(browser_id, url);
self.process_event(event) self.process_event(event)
}) })
} }
@ -190,7 +203,8 @@ impl ServoGlue {
/// Reload the page. /// Reload the page.
pub fn reload(&mut self) -> Result<(), &'static str> { pub fn reload(&mut self) -> Result<(), &'static str> {
debug!("reload"); debug!("reload");
let event = WindowEvent::Reload(self.browser_id); let browser_id = self.get_browser_id()?;
let event = WindowEvent::Reload(browser_id);
self.process_event(event) self.process_event(event)
} }
@ -203,14 +217,16 @@ impl ServoGlue {
/// Go back in history. /// Go back in history.
pub fn go_back(&mut self) -> Result<(), &'static str> { pub fn go_back(&mut self) -> Result<(), &'static str> {
debug!("go_back"); debug!("go_back");
let event = WindowEvent::Navigation(self.browser_id, TraversalDirection::Back(1)); let browser_id = self.get_browser_id()?;
let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1));
self.process_event(event) self.process_event(event)
} }
/// Go forward in history. /// Go forward in history.
pub fn go_forward(&mut self) -> Result<(), &'static str> { pub fn go_forward(&mut self) -> Result<(), &'static str> {
debug!("go_forward"); debug!("go_forward");
let event = WindowEvent::Navigation(self.browser_id, TraversalDirection::Forward(1)); let browser_id = self.get_browser_id()?;
let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1));
self.process_event(event) self.process_event(event)
} }
@ -329,7 +345,31 @@ impl ServoGlue {
info!("Alert: {}", message); info!("Alert: {}", message);
let _ = sender.send(()); let _ = sender.send(());
}, },
EmbedderMsg::CloseBrowser | EmbedderMsg::AllowOpeningBrowser(response_chan) => {
// Note: would be a place to handle pop-ups config.
// see Step 7 of #the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
if let Err(e) = response_chan.send(true) {
warn!("Failed to send AllowOpeningBrowser response: {}", e);
};
},
EmbedderMsg::BrowserCreated(new_browser_id) => {
// TODO: properly handle a new "tab"
self.browsers.push(new_browser_id);
if self.browser_id.is_none() {
self.browser_id = Some(new_browser_id);
}
self.events.push(WindowEvent::SelectBrowser(new_browser_id));
},
EmbedderMsg::CloseBrowser => {
// TODO: close the appropriate "tab".
let _ = self.browsers.pop();
if let Some(prev_browser_id) = self.browsers.last() {
self.browser_id = Some(*prev_browser_id);
self.events.push(WindowEvent::SelectBrowser(*prev_browser_id));
} else {
self.events.push(WindowEvent::Quit);
}
},
EmbedderMsg::Status(..) | EmbedderMsg::Status(..) |
EmbedderMsg::SelectFiles(..) | EmbedderMsg::SelectFiles(..) |
EmbedderMsg::MoveTo(..) | EmbedderMsg::MoveTo(..) |

View file

@ -67,11 +67,6 @@ impl Browser {
mem::replace(&mut self.event_queue, Vec::new()) mem::replace(&mut self.event_queue, Vec::new())
} }
pub fn set_browser_id(&mut self, browser_id: BrowserId) {
self.browser_id = Some(browser_id);
self.browsers.push(browser_id);
}
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) { pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
for event in events { for event in events {
match event { match event {
@ -302,6 +297,9 @@ impl Browser {
EmbedderMsg::BrowserCreated(new_browser_id) => { EmbedderMsg::BrowserCreated(new_browser_id) => {
// TODO: properly handle a new "tab" // TODO: properly handle a new "tab"
self.browsers.push(new_browser_id); self.browsers.push(new_browser_id);
if self.browser_id.is_none() {
self.browser_id = Some(new_browser_id);
}
self.event_queue.push(WindowEvent::SelectBrowser(new_browser_id)); self.event_queue.push(WindowEvent::SelectBrowser(new_browser_id));
} }
EmbedderMsg::KeyEvent(ch, key, state, modified) => { EmbedderMsg::KeyEvent(ch, key, state, modified) => {
@ -332,6 +330,7 @@ impl Browser {
// TODO: close the appropriate "tab". // TODO: close the appropriate "tab".
let _ = self.browsers.pop(); let _ = self.browsers.pop();
if let Some(prev_browser_id) = self.browsers.last() { if let Some(prev_browser_id) = self.browsers.last() {
self.browser_id = Some(*prev_browser_id);
self.event_queue.push(WindowEvent::SelectBrowser(*prev_browser_id)); self.event_queue.push(WindowEvent::SelectBrowser(*prev_browser_id));
} else { } else {
self.event_queue.push(WindowEvent::Quit); self.event_queue.push(WindowEvent::Quit);

View file

@ -27,11 +27,10 @@ mod resources;
mod browser; mod browser;
use backtrace::Backtrace; use backtrace::Backtrace;
use servo::Servo; use servo::{Servo, BrowserId};
use servo::compositing::windowing::WindowEvent; use servo::compositing::windowing::WindowEvent;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename}; use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version; use servo::config::servo_version;
use servo::ipc_channel::ipc;
use servo::servo_config::prefs::PREFS; use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use std::env; use std::env;
@ -150,12 +149,8 @@ pub fn main() {
let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap(); let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();
let mut servo = Servo::new(window.clone()); let mut servo = Servo::new(window.clone());
let browser_id = BrowserId::new();
let (sender, receiver) = ipc::channel().unwrap(); servo.handle_events(vec![WindowEvent::NewBrowser(target_url, browser_id)]);
servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
let browser_id = receiver.recv().unwrap();
browser.set_browser_id(browser_id);
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
servo.setup_logging(); servo.setup_logging();