ports/cef: Implement accelerated compositing for the CEF port.

This commit is contained in:
Patrick Walton 2014-11-24 17:23:30 -08:00
parent 315e166cf7
commit 8b2aadc30b
35 changed files with 1746 additions and 642 deletions

View file

@ -3,23 +3,23 @@
* 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 compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents}; use compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents};
use compositor_layer::WantsScrollEvents; use compositor_layer::{WantsScrollEvents};
use compositor_task::{ChangeReadyState, ChangePaintState, CompositorEventListener}; use compositor_task::{ChangePageLoadData, ChangePageTitle, ChangePaintState, ChangeReadyState};
use compositor_task::{CompositorProxy, CompositorReceiver, CompositorTask}; use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver};
use compositor_task::{CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer, Exit}; use compositor_task::{CompositorTask, CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer};
use compositor_task::{FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties}; use compositor_task::{Exit, FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties};
use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint}; use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint};
use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete}; use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete};
use constellation::{SendableFrameTree, FrameTreeDiff}; use constellation::{FrameId, FrameTreeDiff, SendableFrameTree};
use pipeline::CompositionPipeline; use pipeline::CompositionPipeline;
use scrolling::ScrollingTimerProxy; use scrolling::ScrollingTimerProxy;
use windowing; use windowing;
use windowing::{IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent}; use windowing::{IdleWindowEvent, InitializeCompositingWindowEvent};
use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEvent}; use windowing::{KeyEvent, LoadUrlWindowEvent, MouseWindowClickEvent, MouseWindowEvent};
use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent}; use windowing::{MouseWindowEventClass, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{MouseWindowMoveEventClass, NavigationWindowEvent, PinchZoomWindowEvent};
use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent}; use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent};
use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent}; use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
use windowing::{PinchZoomWindowEvent, KeyEvent};
use azure::azure_hl; use azure::azure_hl;
use std::cmp; use std::cmp;
@ -40,11 +40,11 @@ use gleam::gl::types::{GLint, GLsizei};
use gleam::gl; use gleam::gl;
use script_traits::{ViewportMsg, ScriptControlChan}; use script_traits::{ViewportMsg, ScriptControlChan};
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId}; use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId};
use servo_msg::compositor_msg::{ReadyState, PaintingPaintState, PaintState, Scrollable}; use servo_msg::compositor_msg::{ReadyState, PaintState, PaintingPaintState, Scrollable};
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg}; use servo_msg::constellation_msg::{mod, ConstellationChan, ExitMsg};
use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg}; use servo_msg::constellation_msg::{GetPipelineTitleMsg, Key, KeyModifiers, KeyState, LoadData};
use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key, KeyModifiers}; use servo_msg::constellation_msg::{LoadUrlMsg, NavigateMsg, PipelineId, ResizedWindowMsg};
use servo_msg::constellation_msg; use servo_msg::constellation_msg::{WindowSizeData};
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx}; use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
use servo_util::memory::MemoryProfilerChan; use servo_util::memory::MemoryProfilerChan;
use servo_util::opts; use servo_util::opts;
@ -58,6 +58,7 @@ use std::slice::bytes::copy_memory;
use time::{precise_time_ns, precise_time_s}; use time::{precise_time_ns, precise_time_s};
use url::Url; use url::Url;
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
pub struct IOCompositor<Window: WindowMethods> { pub struct IOCompositor<Window: WindowMethods> {
/// The application window. /// The application window.
window: Rc<Window>, window: Rc<Window>,
@ -65,8 +66,9 @@ pub struct IOCompositor<Window: WindowMethods> {
/// The port on which we receive messages. /// The port on which we receive messages.
port: Box<CompositorReceiver>, port: Box<CompositorReceiver>,
/// The render context. /// The render context. This will be `None` if the windowing system has not yet sent us a
context: RenderContext, /// `PrepareRenderingEvent`.
context: Option<RenderContext>,
/// The root pipeline. /// The root pipeline.
root_pipeline: Option<CompositionPipeline>, root_pipeline: Option<CompositionPipeline>,
@ -177,13 +179,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// display list. This is only here because we don't have that logic in the painter yet. // display list. This is only here because we don't have that logic in the painter yet.
let window_size = window.framebuffer_size(); let window_size = window.framebuffer_size();
let hidpi_factor = window.hidpi_factor(); let hidpi_factor = window.hidpi_factor();
let context = CompositorTask::create_graphics_context(&window.native_metadata());
let show_debug_borders = opts::get().show_debug_borders;
IOCompositor { IOCompositor {
window: window, window: window,
port: receiver, port: receiver,
context: rendergl::RenderContext::new(context, show_debug_borders), context: None,
root_pipeline: None, root_pipeline: None,
scene: Scene::new(Rect { scene: Scene::new(Rect {
origin: Zero::zero(), origin: Zero::zero(),
@ -262,6 +261,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.change_paint_state(pipeline_id, paint_state); self.change_paint_state(pipeline_id, paint_state);
} }
(ChangePageTitle(pipeline_id, title), NotShuttingDown) => {
self.change_page_title(pipeline_id, title);
}
(ChangePageLoadData(frame_id, load_data), NotShuttingDown) => {
self.change_page_load_data(frame_id, load_data);
}
(PaintMsgDiscarded, NotShuttingDown) => { (PaintMsgDiscarded, NotShuttingDown) => {
self.remove_outstanding_paint_msg(); self.remove_outstanding_paint_msg();
} }
@ -305,13 +312,18 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.scroll_fragment_to_point(pipeline_id, layer_id, point); self.scroll_fragment_to_point(pipeline_id, layer_id, point);
} }
(LoadComplete(..), NotShuttingDown) => { (LoadComplete, NotShuttingDown) => {
self.got_load_complete_message = true; self.got_load_complete_message = true;
// If we're painting in headless mode, schedule a recomposite. // If we're painting in headless mode, schedule a recomposite.
if opts::get().output_file.is_some() { if opts::get().output_file.is_some() {
self.composite_if_necessary(); self.composite_if_necessary();
} }
// Inform the embedder that the load has finished.
//
// TODO(pcwalton): Specify which frame's load completed.
self.window.load_end();
} }
(ScrollTimeout(timestamp), NotShuttingDown) => { (ScrollTimeout(timestamp), NotShuttingDown) => {
@ -371,6 +383,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.window.set_paint_state(paint_state); self.window.set_paint_state(paint_state);
} }
fn change_page_title(&mut self, _: PipelineId, title: Option<String>) {
self.window.set_page_title(title);
}
fn change_page_load_data(&mut self, _: FrameId, load_data: LoadData) {
self.window.set_page_load_data(load_data);
}
fn all_pipelines_in_idle_paint_state(&self) -> bool { fn all_pipelines_in_idle_paint_state(&self) -> bool {
if self.ready_states.len() == 0 { if self.ready_states.len() == 0 {
return false; return false;
@ -629,7 +649,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
IdleWindowEvent => {} IdleWindowEvent => {}
RefreshWindowEvent => { RefreshWindowEvent => {
self.composite_if_necessary() self.composite();
}
InitializeCompositingWindowEvent => {
self.initialize_compositing();
} }
ResizeWindowEvent(size) => { ResizeWindowEvent(size) => {
@ -678,6 +702,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
fn on_resize_window_event(&mut self, new_size: TypedSize2D<DevicePixel, uint>) { fn on_resize_window_event(&mut self, new_size: TypedSize2D<DevicePixel, uint>) {
debug!("compositor resizing to {}", new_size.to_untyped());
// A size change could also mean a resolution change. // A size change could also mean a resolution change.
let new_hidpi_factor = self.window.hidpi_factor(); let new_hidpi_factor = self.window.hidpi_factor();
if self.hidpi_factor != new_hidpi_factor { if self.hidpi_factor != new_hidpi_factor {
@ -960,6 +986,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
fn composite(&mut self) { fn composite(&mut self) {
if !self.window.prepare_for_composite() {
return
}
let output_image = opts::get().output_file.is_some() && let output_image = opts::get().output_file.is_some() &&
self.is_ready_to_paint_image_output(); self.is_ready_to_paint_image_output();
@ -995,7 +1025,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// paint the scene. // paint the scene.
match self.scene.root { match self.scene.root {
Some(ref layer) => { Some(ref layer) => {
rendergl::render_scene(layer.clone(), self.context, &self.scene); match self.context {
None => {
debug!("compositor: not compositing because context not yet set up")
}
Some(context) => {
rendergl::render_scene(layer.clone(), context, &self.scene);
}
}
} }
None => {} None => {}
} }
@ -1053,6 +1090,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
} }
fn initialize_compositing(&mut self) {
let context = CompositorTask::create_graphics_context(&self.window.native_metadata());
let show_debug_borders = opts::get().show_debug_borders;
self.context = Some(rendergl::RenderContext::new(context, show_debug_borders))
}
fn find_topmost_layer_at_point_for_layer(&self, fn find_topmost_layer_at_point_for_layer(&self,
layer: Rc<Layer<CompositorData>>, layer: Rc<Layer<CompositorData>>,
point: TypedPoint2D<LayerPixel, f32>) point: TypedPoint2D<LayerPixel, f32>)
@ -1229,4 +1272,17 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
self.scrolling_timer.shutdown(); self.scrolling_timer.shutdown();
} }
fn pinch_zoom_level(&self) -> f32 {
self.viewport_zoom.get() as f32
}
fn get_title_for_main_frame(&self) {
let root_pipeline_id = match self.root_pipeline {
None => return,
Some(ref root_pipeline) => root_pipeline.id,
};
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(GetPipelineTitleMsg(root_pipeline_id));
}
} }

View file

@ -5,7 +5,7 @@
//! Communication with the compositor task. //! Communication with the compositor task.
pub use windowing; pub use windowing;
pub use constellation::{SendableFrameTree, FrameTreeDiff}; pub use constellation::{FrameId, SendableFrameTree, FrameTreeDiff};
use compositor; use compositor;
use headless; use headless;
@ -19,7 +19,7 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics
use layers::layers::LayerBufferSet; use layers::layers::LayerBufferSet;
use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState}; use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy}; use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId}; use servo_msg::constellation_msg::{ConstellationChan, LoadData, PipelineId};
use servo_util::memory::MemoryProfilerChan; use servo_util::memory::MemoryProfilerChan;
use servo_util::time::TimeProfilerChan; use servo_util::time::TimeProfilerChan;
use std::comm::{channel, Sender, Receiver}; use std::comm::{channel, Sender, Receiver};
@ -81,8 +81,13 @@ impl ScriptListener for Box<CompositorProxy+'static+Send> {
fn dup(&mut self) -> Box<ScriptListener+'static> { fn dup(&mut self) -> Box<ScriptListener+'static> {
box self.clone_compositor_proxy() as Box<ScriptListener+'static> box self.clone_compositor_proxy() as Box<ScriptListener+'static>
} }
fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) {
self.send(ChangePageTitle(pipeline_id, title))
}
} }
/// Information about each layer that the compositor keeps.
pub struct LayerProperties { pub struct LayerProperties {
pub pipeline_id: PipelineId, pub pipeline_id: PipelineId,
pub epoch: Epoch, pub epoch: Epoch,
@ -184,9 +189,13 @@ pub enum Msg {
ChangeReadyState(PipelineId, ReadyState), ChangeReadyState(PipelineId, ReadyState),
/// Alerts the compositor to the current status of painting. /// Alerts the compositor to the current status of painting.
ChangePaintState(PipelineId, PaintState), ChangePaintState(PipelineId, PaintState),
/// Alerts the compositor that the PaintMsg has been discarded. /// Alerts the compositor that the current page has changed its title.
ChangePageTitle(PipelineId, Option<String>),
/// Alerts the compositor that the current page has changed its load data (including URL).
ChangePageLoadData(FrameId, LoadData),
/// Alerts the compositor that a `PaintMsg` has been discarded.
PaintMsgDiscarded, PaintMsgDiscarded,
/// Sets the channel to the current layout and paint tasks, along with their id /// Sets the channel to the current layout and paint tasks, along with their ID.
SetIds(SendableFrameTree, Sender<()>, ConstellationChan), SetIds(SendableFrameTree, Sender<()>, ConstellationChan),
/// Sends an updated version of the frame tree. /// Sends an updated version of the frame tree.
FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>), FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>),
@ -210,6 +219,8 @@ impl Show for Msg {
Paint(..) => write!(f, "Paint"), Paint(..) => write!(f, "Paint"),
ChangeReadyState(..) => write!(f, "ChangeReadyState"), ChangeReadyState(..) => write!(f, "ChangeReadyState"),
ChangePaintState(..) => write!(f, "ChangePaintState"), ChangePaintState(..) => write!(f, "ChangePaintState"),
ChangePageTitle(..) => write!(f, "ChangePageTitle"),
ChangePageLoadData(..) => write!(f, "ChangePageLoadData"),
PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"), PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"),
SetIds(..) => write!(f, "SetIds"), SetIds(..) => write!(f, "SetIds"),
FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"), FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"),
@ -269,5 +280,8 @@ pub trait CompositorEventListener {
fn handle_event(&mut self, event: WindowEvent) -> bool; fn handle_event(&mut self, event: WindowEvent) -> bool;
fn repaint_synchronously(&mut self); fn repaint_synchronously(&mut self);
fn shutdown(&mut self); fn shutdown(&mut self);
fn pinch_zoom_level(&self) -> f32;
/// Requests that the compositor send the title for the main frame as soon as possible.
fn get_title_for_main_frame(&self);
} }

View file

@ -4,7 +4,8 @@
use pipeline::{Pipeline, CompositionPipeline}; use pipeline::{Pipeline, CompositionPipeline};
use compositor_task::{CompositorProxy, FrameTreeUpdateMsg, LoadComplete, ShutdownComplete, SetLayerOrigin, SetIds}; use compositor_task::{ChangePageLoadData, ChangePageTitle, CompositorProxy, FrameTreeUpdateMsg};
use compositor_task::{LoadComplete, SetLayerOrigin, SetIds, ShutdownComplete};
use devtools_traits; use devtools_traits;
use devtools_traits::DevtoolsControlChan; use devtools_traits::DevtoolsControlChan;
use geom::rect::{Rect, TypedRect}; use geom::rect::{Rect, TypedRect};
@ -14,16 +15,16 @@ use gfx::paint_task;
use layers::geometry::DevicePixel; use layers::geometry::DevicePixel;
use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg}; use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg};
use libc; use libc;
use script_traits; use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
use script_traits::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
use script_traits::{ScriptControlChan, ScriptTaskFactory}; use script_traits::{ScriptControlChan, ScriptTaskFactory};
use servo_msg::compositor_msg::LayerId; use servo_msg::compositor_msg::LayerId;
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg};
use servo_msg::constellation_msg::{GetPipelineTitleMsg};
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg}; use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers, LoadCompleteMsg};
use servo_msg::constellation_msg::{NavigationType, PipelineId, PainterReadyMsg, ResizedWindowMsg}; use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, Msg, NavigateMsg, NavigationType};
use servo_msg::constellation_msg::{PainterReadyMsg, PipelineId, ResizedWindowMsg};
use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData}; use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData};
use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
@ -76,6 +77,10 @@ pub struct Constellation<LTF, STF> {
/// The next free ID to assign to a pipeline. /// The next free ID to assign to a pipeline.
next_pipeline_id: PipelineId, next_pipeline_id: PipelineId,
/// The next free ID to assign to a frame.
next_frame_id: FrameId,
/// Navigation operations that are in progress.
pending_frames: Vec<FrameChange>, pending_frames: Vec<FrameChange>,
pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>, pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
@ -86,17 +91,28 @@ pub struct Constellation<LTF, STF> {
pub window_size: WindowSizeData, pub window_size: WindowSizeData,
} }
/// Stores the Id of the outermost frame's pipeline, along with a vector of children frames /// A unique ID used to identify a frame.
pub struct FrameId(u32);
/// One frame in the hierarchy.
struct FrameTree { struct FrameTree {
/// The ID of this frame.
pub id: FrameId,
/// The pipeline for this frame.
pub pipeline: Rc<Pipeline>, pub pipeline: Rc<Pipeline>,
/// The parent frame's pipeline.
pub parent: RefCell<Option<Rc<Pipeline>>>, pub parent: RefCell<Option<Rc<Pipeline>>>,
/// A vector of child frames.
pub children: RefCell<Vec<ChildFrameTree>>, pub children: RefCell<Vec<ChildFrameTree>>,
/// Whether this frame has a compositor layer.
pub has_compositor_layer: Cell<bool>, pub has_compositor_layer: Cell<bool>,
} }
impl FrameTree { impl FrameTree {
fn new(pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>) -> FrameTree { fn new(id: FrameId, pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>)
-> FrameTree {
FrameTree { FrameTree {
id: id,
pipeline: pipeline, pipeline: pipeline,
parent: RefCell::new(parent_pipeline), parent: RefCell::new(parent_pipeline),
children: RefCell::new(vec!()), children: RefCell::new(vec!()),
@ -234,16 +250,19 @@ impl Iterator<Rc<FrameTree>> for FrameTreeIterator {
/// Represents the portion of a page that is changing in navigating. /// Represents the portion of a page that is changing in navigating.
struct FrameChange { struct FrameChange {
/// The old pipeline ID.
pub before: Option<PipelineId>, pub before: Option<PipelineId>,
/// The resulting frame tree after navigation.
pub after: Rc<FrameTree>, pub after: Rc<FrameTree>,
/// The kind of navigation that is occurring.
pub navigation_type: NavigationType, pub navigation_type: NavigationType,
} }
/// Stores the Id's of the pipelines previous and next in the browser's history /// Stores the Id's of the pipelines previous and next in the browser's history
struct NavigationContext { struct NavigationContext {
pub previous: Vec<Rc<FrameTree>>, previous: Vec<Rc<FrameTree>>,
pub next: Vec<Rc<FrameTree>>, next: Vec<Rc<FrameTree>>,
pub current: Option<Rc<FrameTree>>, current: Option<Rc<FrameTree>>,
} }
impl NavigationContext { impl NavigationContext {
@ -258,29 +277,30 @@ impl NavigationContext {
/* Note that the following two methods can fail. They should only be called * /* Note that the following two methods can fail. They should only be called *
* when it is known that there exists either a previous page or a next page. */ * when it is known that there exists either a previous page or a next page. */
fn back(&mut self) -> Rc<FrameTree> { fn back(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
self.next.push(self.current.take().unwrap()); self.next.push(self.current.take().unwrap());
let prev = self.previous.pop().unwrap(); let prev = self.previous.pop().unwrap();
self.current = Some(prev.clone()); self.set_current(prev.clone(), compositor_proxy);
prev prev
} }
fn forward(&mut self) -> Rc<FrameTree> { fn forward(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
self.previous.push(self.current.take().unwrap()); self.previous.push(self.current.take().unwrap());
let next = self.next.pop().unwrap(); let next = self.next.pop().unwrap();
self.current = Some(next.clone()); self.set_current(next.clone(), compositor_proxy);
next next
} }
/// Loads a new set of page frames, returning all evicted frame trees /// Loads a new set of page frames, returning all evicted frame trees
fn load(&mut self, frame_tree: Rc<FrameTree>) -> Vec<Rc<FrameTree>> { fn load(&mut self, frame_tree: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy)
-> Vec<Rc<FrameTree>> {
debug!("navigating to {}", frame_tree.pipeline.id); debug!("navigating to {}", frame_tree.pipeline.id);
let evicted = replace(&mut self.next, vec!()); let evicted = replace(&mut self.next, vec!());
match self.current.take() { match self.current.take() {
Some(current) => self.previous.push(current), Some(current) => self.previous.push(current),
None => (), None => (),
} }
self.current = Some(frame_tree); self.set_current(frame_tree, compositor_proxy);
evicted evicted
} }
@ -308,6 +328,14 @@ impl NavigationContext {
frame_tree.contains(pipeline_id) frame_tree.contains(pipeline_id)
}) })
} }
/// Always use this method to set the currently-displayed frame. It correctly informs the
/// compositor of the new URLs.
fn set_current(&mut self, new_frame: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy) {
self.current = Some(new_frame.clone());
compositor_proxy.send(ChangePageLoadData(new_frame.id,
new_frame.pipeline.load_data.clone()));
}
} }
impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
@ -334,6 +362,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipelines: HashMap::new(), pipelines: HashMap::new(),
navigation_context: NavigationContext::new(), navigation_context: NavigationContext::new(),
next_pipeline_id: PipelineId(0), next_pipeline_id: PipelineId(0),
next_frame_id: FrameId(0),
pending_frames: vec!(), pending_frames: vec!(),
pending_sizes: HashMap::new(), pending_sizes: HashMap::new(),
time_profiler_chan: time_profiler_chan, time_profiler_chan: time_profiler_chan,
@ -358,31 +387,30 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
} }
/// Helper function for creating a pipeline /// Helper function for creating a pipeline
fn new_pipeline(&self, fn new_pipeline(&mut self,
id: PipelineId, id: PipelineId,
subpage_id: Option<SubpageId>, subpage_id: Option<SubpageId>,
script_pipeline: Option<Rc<Pipeline>>, script_pipeline: Option<Rc<Pipeline>>,
load_data: LoadData) load_data: LoadData)
-> Rc<Pipeline> { -> Rc<Pipeline> {
let pipe = Pipeline::create::<LTF, STF>(id, let pipe = Pipeline::create::<LTF, STF>(id,
subpage_id, subpage_id,
self.chan.clone(), self.chan.clone(),
self.compositor_proxy.clone_compositor_proxy(), self.compositor_proxy.clone_compositor_proxy(),
self.devtools_chan.clone(), self.devtools_chan.clone(),
self.image_cache_task.clone(), self.image_cache_task.clone(),
self.font_cache_task.clone(), self.font_cache_task.clone(),
self.resource_task.clone(), self.resource_task.clone(),
self.storage_task.clone(), self.storage_task.clone(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
self.window_size, self.window_size,
script_pipeline, script_pipeline,
load_data); load_data.clone());
pipe.load(); pipe.load();
Rc::new(pipe) Rc::new(pipe)
} }
/// Helper function for getting a unique pipeline ID.
/// Helper function for getting a unique pipeline Id
fn get_next_pipeline_id(&mut self) -> PipelineId { fn get_next_pipeline_id(&mut self) -> PipelineId {
let id = self.next_pipeline_id; let id = self.next_pipeline_id;
let PipelineId(ref mut i) = self.next_pipeline_id; let PipelineId(ref mut i) = self.next_pipeline_id;
@ -390,6 +418,14 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
id id
} }
/// Helper function for getting a unique frame ID.
fn get_next_frame_id(&mut self) -> FrameId {
let id = self.next_frame_id;
let FrameId(ref mut i) = self.next_frame_id;
*i += 1;
id
}
/// Convenience function for getting the currently active frame tree. /// Convenience function for getting the currently active frame tree.
/// The currently active frame tree should always be the current painter /// The currently active frame tree should always be the current painter
fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> { fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> {
@ -465,6 +501,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("constellation got key event message"); debug!("constellation got key event message");
self.handle_key_msg(key, state, modifiers); self.handle_key_msg(key, state, modifiers);
} }
GetPipelineTitleMsg(pipeline_id) => {
debug!("constellation got get-pipeline-title message");
self.handle_get_pipeline_title_msg(pipeline_id);
}
} }
true true
} }
@ -529,27 +569,38 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("creating replacement pipeline for about:failure"); debug!("creating replacement pipeline for about:failure");
let new_id = self.get_next_pipeline_id(); let new_id = self.get_next_pipeline_id();
let new_frame_id = self.get_next_frame_id();
let pipeline = self.new_pipeline(new_id, subpage_id, None, let pipeline = self.new_pipeline(new_id, subpage_id, None,
LoadData::new(Url::parse("about:failure").unwrap())); LoadData::new(Url::parse("about:failure").unwrap()));
self.pending_frames.push(FrameChange{ self.browse(Some(pipeline_id),
before: Some(pipeline_id), Rc::new(FrameTree::new(new_frame_id, pipeline.clone(), None)),
after: Rc::new(FrameTree::new(pipeline.clone(), None)), constellation_msg::Load);
navigation_type: constellation_msg::Load,
});
self.pipelines.insert(new_id, pipeline); self.pipelines.insert(new_id, pipeline);
} }
/// Performs navigation. This pushes a `FrameChange` object onto the list of pending frames.
///
/// TODO(pcwalton): Send a `BeforeBrowse` message to the embedder and allow cancellation.
fn browse(&mut self,
before: Option<PipelineId>,
after: Rc<FrameTree>,
navigation_type: NavigationType) {
self.pending_frames.push(FrameChange {
before: before,
after: after,
navigation_type: navigation_type,
});
}
fn handle_init_load(&mut self, url: Url) { fn handle_init_load(&mut self, url: Url) {
let next_pipeline_id = self.get_next_pipeline_id(); let next_pipeline_id = self.get_next_pipeline_id();
let next_frame_id = self.get_next_frame_id();
let pipeline = self.new_pipeline(next_pipeline_id, None, None, LoadData::new(url)); let pipeline = self.new_pipeline(next_pipeline_id, None, None, LoadData::new(url));
self.browse(None,
self.pending_frames.push(FrameChange { Rc::new(FrameTree::new(next_frame_id, pipeline.clone(), None)),
before: None, constellation_msg::Load);
after: Rc::new(FrameTree::new(pipeline.clone(), None)),
navigation_type: constellation_msg::Load,
});
self.pipelines.insert(pipeline.id, pipeline); self.pipelines.insert(pipeline.id, pipeline);
} }
@ -690,15 +741,19 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
let rect = self.pending_sizes.remove(&(source_pipeline_id, subpage_id)); let rect = self.pending_sizes.remove(&(source_pipeline_id, subpage_id));
for frame_tree in frame_trees.iter() { for frame_tree in frame_trees.iter() {
let next_frame_id = self.get_next_frame_id();
frame_tree.children.borrow_mut().push(ChildFrameTree::new( frame_tree.children.borrow_mut().push(ChildFrameTree::new(
Rc::new(FrameTree::new(pipeline.clone(), Some(source_pipeline.clone()))), Rc::new(FrameTree::new(next_frame_id,
pipeline.clone(),
Some(source_pipeline.clone()))),
rect)); rect));
} }
self.pipelines.insert(pipeline.id, pipeline); self.pipelines.insert(pipeline.id, pipeline);
} }
fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) { fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) {
debug!("Constellation: received message to load {:s}", load_data.url.to_string()); let url = load_data.url.to_string();
debug!("Constellation: received message to load {:s}", url);
// Make sure no pending page would be overridden. // Make sure no pending page would be overridden.
let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect( let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect(
"Constellation: received a LoadUrlMsg from a pipeline_id associated "Constellation: received a LoadUrlMsg from a pipeline_id associated
@ -723,14 +778,13 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
let parent = source_frame.parent.clone(); let parent = source_frame.parent.clone();
let subpage_id = source_frame.pipeline.subpage_id; let subpage_id = source_frame.pipeline.subpage_id;
let next_pipeline_id = self.get_next_pipeline_id(); let next_pipeline_id = self.get_next_pipeline_id();
let next_frame_id = self.get_next_frame_id();
let pipeline = self.new_pipeline(next_pipeline_id, subpage_id, None, load_data); let pipeline = self.new_pipeline(next_pipeline_id, subpage_id, None, load_data);
self.browse(Some(source_id),
self.pending_frames.push(FrameChange { Rc::new(FrameTree::new(next_frame_id,
before: Some(source_id), pipeline.clone(),
after: Rc::new(FrameTree::new(pipeline.clone(), parent.borrow().clone())), parent.borrow().clone())),
navigation_type: constellation_msg::Load, constellation_msg::Load);
});
self.pipelines.insert(pipeline.id, pipeline); self.pipelines.insert(pipeline.id, pipeline);
} }
@ -752,7 +806,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
frame.pipeline.revoke_paint_permission(); frame.pipeline.revoke_paint_permission();
} }
} }
self.navigation_context.forward() self.navigation_context.forward(&mut *self.compositor_proxy)
} }
constellation_msg::Back => { constellation_msg::Back => {
if self.navigation_context.previous.is_empty() { if self.navigation_context.previous.is_empty() {
@ -764,7 +818,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
frame.pipeline.revoke_paint_permission(); frame.pipeline.revoke_paint_permission();
} }
} }
self.navigation_context.back() self.navigation_context.back(&mut *self.compositor_proxy)
} }
}; };
@ -787,6 +841,16 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
}); });
} }
fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) {
match self.pipelines.get(&pipeline_id) {
None => self.compositor_proxy.send(ChangePageTitle(pipeline_id, None)),
Some(pipeline) => {
let ScriptControlChan(ref script_channel) = pipeline.script_chan;
script_channel.send(GetTitleMsg(pipeline_id));
}
}
}
fn handle_painter_ready_msg(&mut self, pipeline_id: PipelineId) { fn handle_painter_ready_msg(&mut self, pipeline_id: PipelineId) {
debug!("Painter {} ready to send paint msg", pipeline_id); debug!("Painter {} ready to send paint msg", pipeline_id);
// This message could originate from a pipeline in the navigation context or // This message could originate from a pipeline in the navigation context or
@ -941,7 +1005,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
match navigation_type { match navigation_type {
constellation_msg::Load => { constellation_msg::Load => {
debug!("evicting old frames due to load"); debug!("evicting old frames due to load");
let evicted = self.navigation_context.load(frame_tree); let evicted = self.navigation_context.load(frame_tree,
&mut *self.compositor_proxy);
self.handle_evicted_frames(evicted); self.handle_evicted_frames(evicted);
} }
_ => { _ => {

View file

@ -5,7 +5,8 @@
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer}; use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds}; use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds};
use compositor_task::{SetLayerOrigin, ShutdownComplete, ChangePaintState, PaintMsgDiscarded}; use compositor_task::{SetLayerOrigin, ShutdownComplete, ChangePaintState, PaintMsgDiscarded};
use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, FrameTreeUpdateMsg}; use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, ChangePageTitle};
use compositor_task::{ChangePageLoadData, FrameTreeUpdateMsg};
use windowing::WindowEvent; use windowing::WindowEvent;
use geom::scale_factor::ScaleFactor; use geom::scale_factor::ScaleFactor;
@ -104,7 +105,8 @@ impl CompositorEventListener for NullCompositor {
CreateOrUpdateDescendantLayer(..) | CreateOrUpdateDescendantLayer(..) |
SetLayerOrigin(..) | Paint(..) | SetLayerOrigin(..) | Paint(..) |
ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) | ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) |
LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) => () LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) | ChangePageTitle(..) |
ChangePageLoadData(..) => ()
} }
true true
} }
@ -119,4 +121,10 @@ impl CompositorEventListener for NullCompositor {
self.time_profiler_chan.send(time::ExitMsg); self.time_profiler_chan.send(time::ExitMsg);
self.memory_profiler_chan.send(memory::ExitMsg); self.memory_profiler_chan.send(memory::ExitMsg);
} }
fn pinch_zoom_level(&self) -> f32 {
1.0
}
fn get_title_for_main_frame(&self) {}
} }

View file

@ -28,8 +28,10 @@ pub struct Pipeline {
pub paint_chan: PaintChan, pub paint_chan: PaintChan,
pub layout_shutdown_port: Receiver<()>, pub layout_shutdown_port: Receiver<()>,
pub paint_shutdown_port: Receiver<()>, pub paint_shutdown_port: Receiver<()>,
/// The most recently loaded page /// Load data corresponding to the most recently-loaded page.
pub load_data: LoadData, pub load_data: LoadData,
/// The title of the most recently-loaded page.
pub title: Option<String>,
} }
/// The subset of the pipeline that is needed for layer composition. /// The subset of the pipeline that is needed for layer composition.
@ -44,21 +46,21 @@ impl Pipeline {
/// Starts a paint task, layout task, and possibly a script task. /// Starts a paint task, layout task, and possibly a script task.
/// Returns the channels wrapped in a struct. /// Returns the channels wrapped in a struct.
/// If script_pipeline is not None, then subpage_id must also be not None. /// If script_pipeline is not None, then subpage_id must also be not None.
pub fn create<LTF:LayoutTaskFactory, STF:ScriptTaskFactory>( pub fn create<LTF,STF>(id: PipelineId,
id: PipelineId, subpage_id: Option<SubpageId>,
subpage_id: Option<SubpageId>, constellation_chan: ConstellationChan,
constellation_chan: ConstellationChan, compositor_proxy: Box<CompositorProxy+'static+Send>,
compositor_proxy: Box<CompositorProxy+'static+Send>, devtools_chan: Option<DevtoolsControlChan>,
devtools_chan: Option<DevtoolsControlChan>, image_cache_task: ImageCacheTask,
image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask,
font_cache_task: FontCacheTask, resource_task: ResourceTask,
resource_task: ResourceTask, storage_task: StorageTask,
storage_task: StorageTask, time_profiler_chan: TimeProfilerChan,
time_profiler_chan: TimeProfilerChan, window_size: WindowSizeData,
window_size: WindowSizeData, script_pipeline: Option<Rc<Pipeline>>,
script_pipeline: Option<Rc<Pipeline>>, load_data: LoadData)
load_data: LoadData) -> Pipeline
-> Pipeline { where LTF: LayoutTaskFactory, STF:ScriptTaskFactory {
let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>); let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>);
let (paint_port, paint_chan) = PaintChan::new(); let (paint_port, paint_chan) = PaintChan::new();
let (paint_shutdown_chan, paint_shutdown_port) = channel(); let (paint_shutdown_chan, paint_shutdown_port) = channel();
@ -153,6 +155,7 @@ impl Pipeline {
layout_shutdown_port: layout_shutdown_port, layout_shutdown_port: layout_shutdown_port,
paint_shutdown_port: paint_shutdown_port, paint_shutdown_port: paint_shutdown_port,
load_data: load_data, load_data: load_data,
title: None,
} }
} }

View file

@ -11,8 +11,8 @@ use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use layers::geometry::DevicePixel; use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata; use layers::platform::surface::NativeGraphicsMetadata;
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers}; use servo_msg::compositor_msg::{PaintState, ReadyState};
use servo_msg::compositor_msg::{ReadyState, PaintState}; use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData};
use servo_util::geometry::ScreenPx; use servo_util::geometry::ScreenPx;
use std::fmt::{FormatError, Formatter, Show}; use std::fmt::{FormatError, Formatter, Show};
use std::rc::Rc; use std::rc::Rc;
@ -37,8 +37,12 @@ pub enum WindowEvent {
/// It's possible that this should be something like /// It's possible that this should be something like
/// `CompositorMessageWindowEvent(compositor_task::Msg)` instead. /// `CompositorMessageWindowEvent(compositor_task::Msg)` instead.
IdleWindowEvent, IdleWindowEvent,
/// Sent when part of the window is marked dirty and needs to be redrawn. /// Sent when part of the window is marked dirty and needs to be redrawn. Before sending this
/// message, the window must make the same GL context as in `PrepareRenderingEvent` current.
RefreshWindowEvent, RefreshWindowEvent,
/// Sent to initialize the GL context. The windowing system must have a valid, current GL
/// context when this message is sent.
InitializeCompositingWindowEvent,
/// Sent when the window is resized. /// Sent when the window is resized.
ResizeWindowEvent(TypedSize2D<DevicePixel, uint>), ResizeWindowEvent(TypedSize2D<DevicePixel, uint>),
/// Sent when a new URL is to be loaded. /// Sent when a new URL is to be loaded.
@ -47,7 +51,8 @@ pub enum WindowEvent {
MouseWindowEventClass(MouseWindowEvent), MouseWindowEventClass(MouseWindowEvent),
/// Sent when a mouse move. /// Sent when a mouse move.
MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>), MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>),
/// Sent when the user scrolls. Includes the current cursor position. /// Sent when the user scrolls. The first point is the delta and the second point is the
/// origin.
ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>), ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>),
/// Sent when the user zooms. /// Sent when the user zooms.
ZoomWindowEvent(f32), ZoomWindowEvent(f32),
@ -66,6 +71,7 @@ impl Show for WindowEvent {
match *self { match *self {
IdleWindowEvent => write!(f, "Idle"), IdleWindowEvent => write!(f, "Idle"),
RefreshWindowEvent => write!(f, "Refresh"), RefreshWindowEvent => write!(f, "Refresh"),
InitializeCompositingWindowEvent => write!(f, "InitializeCompositing"),
ResizeWindowEvent(..) => write!(f, "Resize"), ResizeWindowEvent(..) => write!(f, "Resize"),
KeyEvent(..) => write!(f, "Key"), KeyEvent(..) => write!(f, "Key"),
LoadUrlWindowEvent(..) => write!(f, "LoadUrl"), LoadUrlWindowEvent(..) => write!(f, "LoadUrl"),
@ -92,6 +98,12 @@ pub trait WindowMethods {
fn set_ready_state(&self, ready_state: ReadyState); fn set_ready_state(&self, ready_state: ReadyState);
/// Sets the paint state of the current page. /// Sets the paint state of the current page.
fn set_paint_state(&self, paint_state: PaintState); fn set_paint_state(&self, paint_state: PaintState);
/// Sets the page title for the current page.
fn set_page_title(&self, title: Option<String>);
/// Sets the load data for the current page.
fn set_page_load_data(&self, load_data: LoadData);
/// Called when the browser is done loading a frame.
fn load_end(&self);
/// Returns the hidpi factor of the monitor. /// Returns the hidpi factor of the monitor.
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>; fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
@ -106,5 +118,10 @@ pub trait WindowMethods {
/// magic to wake the up window's event loop. /// magic to wake the up window's event loop.
fn create_compositor_channel(_: &Option<Rc<Self>>) fn create_compositor_channel(_: &Option<Rc<Self>>)
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>); -> (Box<CompositorProxy+Send>, Box<CompositorReceiver>);
/// Requests that the window system prepare a composite. Typically this will involve making
/// some type of platform-specific graphics context current. Returns true if the composite may
/// proceed and false if it should not.
fn prepare_for_composite(&self) -> bool;
} }

View file

@ -19,7 +19,7 @@ pub enum PaintState {
PaintingPaintState, PaintingPaintState,
} }
#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone)] #[deriving(Eq, Ord, PartialEq, PartialOrd, Clone, Show)]
pub enum ReadyState { pub enum ReadyState {
/// Informs the compositor that nothing has been done yet. Used for setting status /// Informs the compositor that nothing has been done yet. Used for setting status
Blank, Blank,
@ -111,6 +111,8 @@ pub trait ScriptListener {
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,
point: Point2D<f32>); point: Point2D<f32>);
/// Informs the compositor that the title of the page with the given pipeline ID has changed.
fn set_title(&mut self, pipeline_id: PipelineId, new_title: Option<String>);
fn close(&mut self); fn close(&mut self);
fn dup(&mut self) -> Box<ScriptListener+'static>; fn dup(&mut self) -> Box<ScriptListener+'static>;
} }

View file

@ -205,6 +205,9 @@ pub enum Msg {
PainterReadyMsg(PipelineId), PainterReadyMsg(PipelineId),
ResizedWindowMsg(WindowSizeData), ResizedWindowMsg(WindowSizeData),
KeyEvent(Key, KeyState, KeyModifiers), KeyEvent(Key, KeyState, KeyModifiers),
/// Requests that the constellation inform the compositor of the title of the pipeline
/// immediately.
GetPipelineTitleMsg(PipelineId),
} }
/// Similar to net::resource_task::LoadData /// Similar to net::resource_task::LoadData

View file

@ -189,6 +189,7 @@ pub trait DocumentHelpers<'a> {
fn begin_focus_transaction(self); fn begin_focus_transaction(self);
fn request_focus(self, elem: JSRef<Element>); fn request_focus(self, elem: JSRef<Element>);
fn commit_focus_transaction(self); fn commit_focus_transaction(self);
fn send_title_to_compositor(self);
} }
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
@ -369,6 +370,12 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
//TODO: dispatch blur, focus, focusout, and focusin events //TODO: dispatch blur, focus, focusout, and focusin events
self.focused.assign(self.possibly_focused.get()); self.focused.assign(self.possibly_focused.get());
} }
/// Sends this document's title to the compositor.
fn send_title_to_compositor(self) {
let window = self.window().root();
window.page().send_title_to_compositor();
}
} }
#[deriving(PartialEq)] #[deriving(PartialEq)]
@ -985,3 +992,4 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
global_event_handlers!() global_event_handlers!()
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange) event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange)
} }

View file

@ -5,15 +5,17 @@
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding; use dom::bindings::codegen::Bindings::HTMLTitleElementBinding;
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods; use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{HTMLTitleElementDerived, NodeCast, TextCast}; use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTitleElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::{TextCast};
use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document; use dom::document::{Document, DocumentHelpers};
use dom::element::HTMLTitleElementTypeId; use dom::element::HTMLTitleElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId}; use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
use dom::text::Text; use dom::text::Text;
use dom::virtualmethods::VirtualMethods;
use servo_util::str::DOMString; use servo_util::str::DOMString;
#[dom_struct] #[dom_struct]
@ -68,3 +70,19 @@ impl Reflectable for HTMLTitleElement {
self.htmlelement.reflector() self.htmlelement.reflector()
} }
} }
impl<'a> VirtualMethods for JSRef<'a, HTMLTitleElement> {
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
Some(htmlelement as &VirtualMethods)
}
fn bind_to_tree(&self, is_in_doc: bool) {
let node: JSRef<Node> = NodeCast::from_ref(*self);
if is_in_doc {
let document = node.owner_doc().root();
document.send_title_to_compositor()
}
}
}

View file

@ -24,6 +24,7 @@ use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast; use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast; use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast; use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
use dom::bindings::js::JSRef; use dom::bindings::js::JSRef;
use dom::document::Document; use dom::document::Document;
use dom::element::Element; use dom::element::Element;
@ -47,6 +48,7 @@ use dom::element::HTMLStyleElementTypeId;
use dom::element::HTMLTableDataCellElementTypeId; use dom::element::HTMLTableDataCellElementTypeId;
use dom::element::HTMLTableHeaderCellElementTypeId; use dom::element::HTMLTableHeaderCellElementTypeId;
use dom::element::HTMLTextAreaElementTypeId; use dom::element::HTMLTextAreaElementTypeId;
use dom::element::HTMLTitleElementTypeId;
use dom::event::Event; use dom::event::Event;
use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmlanchorelement::HTMLAnchorElement;
use dom::htmlareaelement::HTMLAreaElement; use dom::htmlareaelement::HTMLAreaElement;
@ -67,6 +69,7 @@ use dom::htmlselectelement::HTMLSelectElement;
use dom::htmlstyleelement::HTMLStyleElement; use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltablecellelement::HTMLTableCellElement; use dom::htmltablecellelement::HTMLTableCellElement;
use dom::htmltextareaelement::HTMLTextAreaElement; use dom::htmltextareaelement::HTMLTextAreaElement;
use dom::htmltitleelement::HTMLTitleElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag}; use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
use servo_util::str::DOMString; use servo_util::str::DOMString;
@ -232,6 +235,11 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a {
let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap(); let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a element as &'a VirtualMethods + 'a
} }
ElementNodeTypeId(HTMLTitleElementTypeId) => {
let element: &'a JSRef<'a, HTMLTitleElement> =
HTMLTitleElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a
}
ElementNodeTypeId(ElementTypeId_) => { ElementNodeTypeId(ElementTypeId_) => {
let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap(); let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a element as &'a VirtualMethods + 'a

View file

@ -21,7 +21,6 @@ use script_traits::{UntrustedNodeAddress, ScriptControlChan};
use geom::{Point2D, Rect, Size2D}; use geom::{Point2D, Rect, Size2D};
use js::rust::Cx; use js::rust::Cx;
use servo_msg::compositor_msg::PerformingLayout;
use servo_msg::compositor_msg::ScriptListener; use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData}; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_msg::constellation_msg::{PipelineId, SubpageId};
@ -266,6 +265,17 @@ impl Page {
// because it was built for infinite clip (MAX_RECT). // because it was built for infinite clip (MAX_RECT).
had_clip_rect had_clip_rect
} }
pub fn send_title_to_compositor(&self) {
match *self.frame() {
None => {}
Some(ref frame) => {
let window = frame.window.root();
let document = frame.document.root();
window.compositor().set_title(self.id, Some(document.Title()));
}
}
}
} }
impl Iterator<Rc<Page>> for PageIterator { impl Iterator<Rc<Page>> for PageIterator {
@ -356,7 +366,7 @@ impl Page {
pub fn reflow(&self, pub fn reflow(&self,
goal: ReflowGoal, goal: ReflowGoal,
script_chan: ScriptControlChan, script_chan: ScriptControlChan,
compositor: &mut ScriptListener, _: &mut ScriptListener,
query_type: ReflowQueryType) { query_type: ReflowQueryType) {
let root = match *self.frame() { let root = match *self.frame() {
None => return, None => return,
@ -376,9 +386,6 @@ impl Page {
// Now, join the layout so that they will see the latest changes we have made. // Now, join the layout so that they will see the latest changes we have made.
self.join_layout(); self.join_layout();
// Tell the user that we're performing layout.
compositor.set_ready_state(self.id, PerformingLayout);
// Layout will let us know when it's done. // Layout will let us know when it's done.
let (join_chan, join_port) = channel(); let (join_chan, join_port) = channel();
let mut layout_join_port = self.layout_join_port.borrow_mut(); let mut layout_join_port = self.layout_join_port.borrow_mut();

View file

@ -43,10 +43,12 @@ use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, Scrip
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg}; use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg};
use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel}; use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel};
use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent}; use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent};
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading}; use script_traits::{GetTitleMsg};
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout};
use servo_msg::compositor_msg::{ScriptListener}; use servo_msg::compositor_msg::{ScriptListener};
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection}; use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg};
use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState}; use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, NavigationDirection, PipelineId};
use servo_msg::constellation_msg::{Failure, FailureMsg, WindowSizeData, Key, KeyState};
use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed}; use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed};
use servo_msg::constellation_msg::{Released}; use servo_msg::constellation_msg::{Released};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
@ -550,6 +552,9 @@ impl ScriptTask {
FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"), FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"),
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id), FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
FromConstellation(ResizeMsg(..)) => panic!("should have handled ResizeMsg already"), FromConstellation(ResizeMsg(..)) => panic!("should have handled ResizeMsg already"),
FromConstellation(GetTitleMsg(pipeline_id)) => {
self.handle_get_title_msg(pipeline_id)
}
FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_progress(addr, progress), FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_progress(addr, progress),
FromScript(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr), FromScript(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr),
FromScript(DOMMessage(..)) => panic!("unexpected message"), FromScript(DOMMessage(..)) => panic!("unexpected message"),
@ -661,6 +666,11 @@ impl ScriptTask {
self.compositor.borrow_mut().close(); self.compositor.borrow_mut().close();
} }
/// Handles a request for the window title.
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
get_page(&*self.page.borrow(), pipeline_id).send_title_to_compositor();
}
/// Handles a request to exit the script task and shut down layout. /// Handles a request to exit the script task and shut down layout.
/// Returns true if the script task should shut down and false otherwise. /// Returns true if the script task should shut down and false otherwise.
fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool { fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool {
@ -784,6 +794,7 @@ impl ScriptTask {
parse_html(*document, parser_input, &final_url); parse_html(*document, parser_input, &final_url);
document.set_ready_state(DocumentReadyStateValues::Interactive); document.set_ready_state(DocumentReadyStateValues::Interactive);
self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout);
// Kick off the initial reflow of the page. // Kick off the initial reflow of the page.
debug!("kicking off initial reflow of {}", final_url); debug!("kicking off initial reflow of {}", final_url);

View file

@ -65,7 +65,10 @@ pub enum ConstellationControlMsg {
SendEventMsg(PipelineId, CompositorEvent), SendEventMsg(PipelineId, CompositorEvent),
/// Notifies script that reflow is finished. /// Notifies script that reflow is finished.
ReflowCompleteMsg(PipelineId, uint), ReflowCompleteMsg(PipelineId, uint),
/// Notifies script of the viewport.
ViewportMsg(PipelineId, Rect<f32>), ViewportMsg(PipelineId, Rect<f32>),
/// Requests that the script task immediately send the constellation the title of a pipeline.
GetTitleMsg(PipelineId),
} }
/// Events from the compositor that the script task needs to know about /// Events from the compositor that the script task needs to know about

View file

@ -58,7 +58,7 @@ dependencies = [
[[package]] [[package]]
name = "cocoa" name = "cocoa"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/servo/rust-cocoa#78b823bec1affcab20b6977e1057125088a6034c" source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
[[package]] [[package]]
name = "compile_msg" name = "compile_msg"
@ -394,7 +394,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]] [[package]]
name = "layers" name = "layers"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf" source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
dependencies = [ dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)", "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",

View file

@ -153,6 +153,14 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
self.compositor.repaint_synchronously() self.compositor.repaint_synchronously()
} }
pub fn pinch_zoom_level(&self) -> f32 {
self.compositor.pinch_zoom_level()
}
pub fn get_title_for_main_frame(&self) {
self.compositor.get_title_for_main_frame()
}
pub fn shutdown(mut self) { pub fn shutdown(mut self) {
self.compositor.shutdown(); self.compositor.shutdown();
} }

View file

@ -30,7 +30,9 @@ use servo_util::rtinstrument;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(any(test,target_os="android")))]
use servo::Browser; use servo::Browser;
#[cfg(not(any(test,target_os="android")))] #[cfg(not(any(test,target_os="android")))]
use compositing::windowing::{IdleWindowEvent, ResizeWindowEvent, WindowEvent}; use compositing::windowing::{IdleWindowEvent, InitializeCompositingWindowEvent, ResizeWindowEvent};
#[cfg(not(any(test,target_os="android")))]
use compositing::windowing::{WindowEvent};
#[cfg(not(any(test,target_os="android")))] #[cfg(not(any(test,target_os="android")))]
use std::os; use std::os;
@ -65,6 +67,8 @@ fn start(argc: int, argv: *const *const u8) -> int {
} }
} }
browser.browser.handle_event(InitializeCompositingWindowEvent);
loop { loop {
let should_continue = match window { let should_continue = match window {
None => browser.browser.handle_event(IdleWindowEvent), None => browser.browser.handle_event(IdleWindowEvent),

View file

@ -327,7 +327,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]] [[package]]
name = "layers" name = "layers"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982" source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
dependencies = [ dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)", "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",

View file

@ -19,8 +19,8 @@ use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use layers::geometry::DevicePixel; use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata; use layers::platform::surface::NativeGraphicsMetadata;
use msg::compositor_msg::{IdlePaintState, PaintState}; use msg::compositor_msg::{Blank, IdlePaintState, PaintState, ReadyState};
use msg::compositor_msg::{Blank, ReadyState}; use msg::constellation_msg::LoadData;
use util::geometry::ScreenPx; use util::geometry::ScreenPx;
use glut::glut::{ACTIVE_SHIFT, WindowHeight}; use glut::glut::{ACTIVE_SHIFT, WindowHeight};
@ -176,19 +176,23 @@ impl WindowMethods for Window {
/// Sets the ready state. /// Sets the ready state.
fn set_ready_state(&self, ready_state: ReadyState) { fn set_ready_state(&self, ready_state: ReadyState) {
self.ready_state.set(ready_state); self.ready_state.set(ready_state);
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked. // FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
//self.update_window_title() // blocked.
//
// self.update_window_title()
} }
/// Sets the paint state. /// Sets the paint state.
fn set_paint_state(&self, paint_state: PaintState) { fn set_paint_state(&self, paint_state: PaintState) {
self.paint_state.set(paint_state); self.paint_state.set(paint_state);
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked. // FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
//self.update_window_title() // blocked.
//
// self.update_window_title()
} }
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> { fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
//FIXME: Do nothing in GLUT now. // FIXME: Do nothing in GLUT now.
ScaleFactor(1.0) ScaleFactor(1.0)
} }
@ -198,6 +202,22 @@ impl WindowMethods for Window {
display: GetCurrentDisplay(), display: GetCurrentDisplay(),
} }
} }
fn set_page_title(&self, _: Option<String>) {
// TODO(pcwalton)
}
fn set_page_load_data(&self, _: LoadData) {
// TODO(pcwalton)
}
fn load_end(&self) {
// TODO(pcwalton)
}
fn prepare_for_composite(&self) -> bool {
true
}
} }
impl Window { impl Window {

8
ports/cef/Cargo.lock generated
View file

@ -3,6 +3,7 @@ name = "embedding"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"azure 0.1.0 (git+https://github.com/servo/rust-azure)", "azure 0.1.0 (git+https://github.com/servo/rust-azure)",
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)", "core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
"devtools 0.0.1", "devtools 0.0.1",
@ -56,6 +57,11 @@ dependencies = [
"gleam 0.0.1 (git+https://github.com/servo/gleam)", "gleam 0.0.1 (git+https://github.com/servo/gleam)",
] ]
[[package]]
name = "cocoa"
version = "0.1.1"
source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
[[package]] [[package]]
name = "compositing" name = "compositing"
version = "0.0.1" version = "0.0.1"
@ -358,7 +364,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]] [[package]]
name = "layers" name = "layers"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf" source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982"
dependencies = [ dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)", "cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",

View file

@ -65,3 +65,6 @@ git = "https://github.com/servo/rust-core-graphics"
[dependencies.core_text] [dependencies.core_text]
git = "https://github.com/servo/rust-core-text" git = "https://github.com/servo/rust-core-text"
[dependencies.cocoa]
git = "https://github.com/servo/rust-cocoa"

View file

@ -2,38 +2,90 @@
* 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 interfaces::{CefBrowser, CefClient, CefRequestContext, cef_browser_t, cef_client_t}; use browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions};
use interfaces::{cef_request_context_t}; use core::{mod, OffScreenGlobals, OnScreenGlobals, globals};
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t};
use eutil::Downcast; use eutil::Downcast;
use frame::ServoCefFrame;
use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestContext};
use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t};
use interfaces::{cef_request_context_t};
use servo::Browser;
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t};
use window;
use compositing::windowing::{Back, Forward, NavigationWindowEvent};
use glfw_app; use glfw_app;
use libc::c_int; use libc::c_int;
use servo::Browser;
use servo_util::opts; use servo_util::opts;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc;
cef_class_impl! {
ServoCefBrowser : CefBrowser, cef_browser_t {
fn get_host(&this) -> *mut cef_browser_host_t {
this.downcast().host.clone()
}
fn go_back(&_this) -> () {
core::send_window_event(NavigationWindowEvent(Back));
}
fn go_forward(&_this) -> () {
core::send_window_event(NavigationWindowEvent(Forward));
}
// Returns the main (top-level) frame for the browser window.
fn get_main_frame(&this) -> *mut cef_frame_t {
this.downcast().frame.clone()
}
}
}
pub struct ServoCefBrowser { pub struct ServoCefBrowser {
/// A reference to the browser's primary frame.
pub frame: CefFrame,
/// A reference to the browser's host.
pub host: CefBrowserHost,
/// A reference to the browser client.
pub client: CefClient, pub client: CefClient,
pub servo_browser: RefCell<Option<Browser<glfw_app::window::Window>>>, /// Whether the on-created callback has fired yet.
pub window: RefCell<Option<Rc<glfw_app::window::Window>>>,
pub callback_executed: Cell<bool>, pub callback_executed: Cell<bool>,
} }
impl ServoCefBrowser { impl ServoCefBrowser {
pub fn new(client: CefClient) -> ServoCefBrowser { pub fn new(window_info: &cef_window_info_t, client: CefClient) -> ServoCefBrowser {
let frame = ServoCefFrame::new().as_cef_interface();
let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface();
if window_info.windowless_rendering_enabled == 0 {
let glfw_window = glfw_app::create_window();
globals.replace(Some(OnScreenGlobals(RefCell::new(glfw_window.clone()),
RefCell::new(Browser::new(Some(glfw_window))))));
}
ServoCefBrowser { ServoCefBrowser {
frame: frame,
host: host,
client: client, client: client,
servo_browser: RefCell::new(None),
window: RefCell::new(None),
callback_executed: Cell::new(false), callback_executed: Cell::new(false),
} }
} }
} }
cef_class_impl! { trait ServoCefBrowserExtensions {
ServoCefBrowser : CefBrowser, cef_browser_t {} fn init(&self, window_info: &cef_window_info_t);
}
impl ServoCefBrowserExtensions for CefBrowser {
fn init(&self, window_info: &cef_window_info_t) {
if window_info.windowless_rendering_enabled != 0 {
let window = window::Window::new();
let servo_browser = Browser::new(Some(window.clone()));
window.set_browser(self.clone());
globals.replace(Some(OffScreenGlobals(RefCell::new(window),
RefCell::new(servo_browser))));
}
self.downcast().host.set_browser((*self).clone());
}
} }
local_data_key!(pub GLOBAL_BROWSERS: RefCell<Vec<CefBrowser>>) local_data_key!(pub GLOBAL_BROWSERS: RefCell<Vec<CefBrowser>>)
@ -50,12 +102,16 @@ pub fn browser_callback_after_created(browser: CefBrowser) {
browser.downcast().callback_executed.set(true); browser.downcast().callback_executed.set(true);
} }
fn browser_host_create(client: CefClient, callback_executed: bool) -> CefBrowser { fn browser_host_create(window_info: &cef_window_info_t,
client: CefClient,
callback_executed: bool)
-> CefBrowser {
let mut urls = Vec::new(); let mut urls = Vec::new();
urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string()); urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string());
let mut opts = opts::default_opts(); let mut opts = opts::default_opts();
opts.urls = urls; opts.urls = urls;
let browser = ServoCefBrowser::new(client).as_cef_interface(); let browser = ServoCefBrowser::new(window_info, client).as_cef_interface();
browser.init(window_info);
if callback_executed { if callback_executed {
browser_callback_after_created(browser.clone()); browser_callback_after_created(browser.clone());
} }
@ -73,32 +129,30 @@ fn browser_host_create(client: CefClient, callback_executed: bool) -> CefBrowser
} }
cef_static_method_impls! { cef_static_method_impls! {
fn cef_browser_host_create_browser(_window_info: *const cef_window_info_t, fn cef_browser_host_create_browser(window_info: *const cef_window_info_t,
client: *mut cef_client_t, client: *mut cef_client_t,
_url: *const cef_string_t, _url: *const cef_string_t,
_browser_settings: *const cef_browser_settings_t, _browser_settings: *const cef_browser_settings_t,
_request_context: *mut cef_request_context_t) _request_context: *mut cef_request_context_t)
-> c_int { -> c_int {
let _window_info: &cef_window_info_t = _window_info;
let client: CefClient = client; let client: CefClient = client;
let _url: &[u16] = _url; let _url: &[u16] = _url;
let _browser_settings: &cef_browser_settings_t = _browser_settings; let _browser_settings: &cef_browser_settings_t = _browser_settings;
let _request_context: CefRequestContext = _request_context; let _request_context: CefRequestContext = _request_context;
browser_host_create(client, false); browser_host_create(window_info, client, false);
1i32 1i32
} }
fn cef_browser_host_create_browser_sync(window_info: *const cef_window_info_t,
fn cef_browser_host_create_browser_sync(_window_info: *const cef_window_info_t,
client: *mut cef_client_t, client: *mut cef_client_t,
_url: *const cef_string_t, _url: *const cef_string_t,
_browser_settings: *const cef_browser_settings_t, _browser_settings: *const cef_browser_settings_t,
_request_context: *mut cef_request_context_t) _request_context: *mut cef_request_context_t)
-> *mut cef_browser_t { -> *mut cef_browser_t {
let _window_info: &cef_window_info_t = _window_info;
let client: CefClient = client; let client: CefClient = client;
let _url: &[u16] = _url; let _url: &[u16] = _url;
let _browser_settings: &cef_browser_settings_t = _browser_settings; let _browser_settings: &cef_browser_settings_t = _browser_settings;
let _request_context: CefRequestContext = _request_context; let _request_context: CefRequestContext = _request_context;
browser_host_create(client, true) browser_host_create(window_info, client, true)
} }
} }

158
ports/cef/browser_host.rs Normal file
View file

@ -0,0 +1,158 @@
/* 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/. */
use core;
use eutil::Downcast;
use interfaces::{CefBrowser, CefBrowserHost, CefClient, cef_browser_host_t, cef_client_t};
use types::{KEYEVENT_CHAR, KEYEVENT_KEYDOWN, KEYEVENT_KEYUP, KEYEVENT_RAWKEYDOWN, cef_key_event};
use types::{cef_mouse_button_type_t, cef_mouse_event, cef_rect_t};
use compositing::windowing::{InitializeCompositingWindowEvent, KeyEvent, MouseWindowClickEvent};
use compositing::windowing::{MouseWindowEventClass, MouseWindowMouseUpEvent, PinchZoomWindowEvent};
use compositing::windowing::{ResizeWindowEvent, ScrollWindowEvent};
use geom::point::TypedPoint2D;
use geom::size::TypedSize2D;
use libc::{c_double, c_int};
use servo_msg::constellation_msg::{mod, KeyModifiers, Pressed, Released, Repeated};
use std::cell::RefCell;
pub struct ServoCefBrowserHost {
/// A reference to the browser.
pub browser: RefCell<Option<CefBrowser>>,
/// A reference to the client.
pub client: CefClient,
}
cef_class_impl! {
ServoCefBrowserHost : CefBrowserHost, cef_browser_host_t {
fn get_client(&this) -> *mut cef_client_t {
this.downcast().client.clone()
}
fn was_resized(&this) -> () {
let mut rect = cef_rect_t::zero();
this.get_client()
.get_render_handler()
.get_backing_rect(this.downcast().browser.borrow().clone().unwrap(), &mut rect);
let size = TypedSize2D(rect.width as uint, rect.height as uint);
core::send_window_event(ResizeWindowEvent(size));
core::repaint_synchronously();
}
fn send_key_event(&_this, event: *const cef_key_event) -> () {
// FIXME(pcwalton): So awful. But it's nearly midnight here and I have to get
// Google working.
let event: &cef_key_event = event;
let key = match (*event).character as u8 {
b'a' | b'A' => constellation_msg::KeyA,
b'b' | b'B' => constellation_msg::KeyB,
b'c' | b'C' => constellation_msg::KeyC,
b'd' | b'D' => constellation_msg::KeyD,
b'e' | b'E' => constellation_msg::KeyE,
b'f' | b'F' => constellation_msg::KeyF,
b'g' | b'G' => constellation_msg::KeyG,
b'h' | b'H' => constellation_msg::KeyH,
b'i' | b'I' => constellation_msg::KeyI,
b'j' | b'J' => constellation_msg::KeyJ,
b'k' | b'K' => constellation_msg::KeyK,
b'l' | b'L' => constellation_msg::KeyL,
b'm' | b'M' => constellation_msg::KeyM,
b'n' | b'N' => constellation_msg::KeyN,
b'o' | b'O' => constellation_msg::KeyO,
b'p' | b'P' => constellation_msg::KeyP,
b'q' | b'Q' => constellation_msg::KeyQ,
b'r' | b'R' => constellation_msg::KeyR,
b's' | b'S' => constellation_msg::KeyS,
b't' | b'T' => constellation_msg::KeyT,
b'u' | b'U' => constellation_msg::KeyU,
b'v' | b'V' => constellation_msg::KeyV,
b'w' | b'W' => constellation_msg::KeyW,
b'x' | b'X' => constellation_msg::KeyX,
b'y' | b'Y' => constellation_msg::KeyY,
b'z' | b'Z' => constellation_msg::KeyZ,
b'0' => constellation_msg::Key0,
b'1' => constellation_msg::Key1,
b'2' => constellation_msg::Key2,
b'3' => constellation_msg::Key3,
b'4' => constellation_msg::Key4,
b'5' => constellation_msg::Key5,
b'6' => constellation_msg::Key6,
b'7' => constellation_msg::Key7,
b'8' => constellation_msg::Key8,
b'9' => constellation_msg::Key9,
b'\n' | b'\r' => constellation_msg::KeyEnter,
_ => constellation_msg::KeySpace,
};
let key_state = match (*event).t {
KEYEVENT_RAWKEYDOWN => Pressed,
KEYEVENT_KEYDOWN | KEYEVENT_CHAR => Repeated,
KEYEVENT_KEYUP => Released,
};
let key_modifiers = KeyModifiers::empty(); // TODO(pcwalton)
core::send_window_event(KeyEvent(key, key_state, key_modifiers))
}
fn send_mouse_click_event(&_this,
event: *const cef_mouse_event,
mouse_button_type: cef_mouse_button_type_t,
mouse_up: c_int,
_click_count: c_int)
-> () {
let event: &cef_mouse_event = event;
let button_type = mouse_button_type as uint;
let point = TypedPoint2D((*event).x as f32, (*event).y as f32);
if mouse_up != 0 {
core::send_window_event(MouseWindowEventClass(MouseWindowClickEvent(button_type,
point)))
} else {
core::send_window_event(MouseWindowEventClass(MouseWindowMouseUpEvent(button_type,
point)))
}
}
fn send_mouse_wheel_event(&_this,
event: *const cef_mouse_event,
delta_x: c_int,
delta_y: c_int)
-> () {
let event: &cef_mouse_event = event;
let delta = TypedPoint2D(delta_x as f32, delta_y as f32);
let origin = TypedPoint2D((*event).x as i32, (*event).y as i32);
core::send_window_event(ScrollWindowEvent(delta, origin))
}
fn get_zoom_level(&_this) -> c_double {
core::pinch_zoom_level() as c_double
}
fn set_zoom_level(&this, new_zoom_level: c_double) -> () {
let old_zoom_level = this.get_zoom_level();
core::send_window_event(PinchZoomWindowEvent((new_zoom_level / old_zoom_level) as f32))
}
fn initialize_compositing(&_this) -> () {
core::send_window_event(InitializeCompositingWindowEvent);
}
}
}
impl ServoCefBrowserHost {
pub fn new(client: CefClient) -> ServoCefBrowserHost {
ServoCefBrowserHost {
browser: RefCell::new(None),
client: client,
}
}
}
pub trait ServoCefBrowserHostExtensions {
fn set_browser(&self, browser: CefBrowser);
}
impl ServoCefBrowserHostExtensions for CefBrowserHost {
fn set_browser(&self, browser: CefBrowser) {
*self.downcast().browser.borrow_mut() = Some(browser)
}
}

View file

@ -46,7 +46,7 @@ pub fn command_line_init(argc: c_int, argv: *const *const u8) {
#[no_mangle] #[no_mangle]
pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, name: *const cef_string_t) -> cef_string_userfree_t { pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, name: *const cef_string_t) -> cef_string_userfree_t {
if cmd.is_null() || name.is_null() { if cmd.is_null() || name.is_null() {
return cef_string::empty_utf16_string() return cef_string::empty_utf16_userfree_string()
} }
unsafe { unsafe {
//technically cef_string_t can be any type of character size //technically cef_string_t can be any type of character size
@ -67,11 +67,11 @@ pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, na
&mut string, &mut string,
1); 1);
}); });
return string return cef_string::string_to_userfree_string(string)
} }
} }
} }
return cef_string::empty_utf16_string() return cef_string::empty_utf16_userfree_string()
} }
#[no_mangle] #[no_mangle]

View file

@ -2,19 +2,43 @@
* 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 browser::{GLOBAL_BROWSERS, browser_callback_after_created};
use command_line::command_line_init; use command_line::command_line_init;
use interfaces::cef_app_t; use interfaces::cef_app_t;
use eutil::Downcast;
use switches::{KPROCESSTYPE, KWAITFORDEBUGGER};
use types::{cef_main_args_t, cef_settings_t}; use types::{cef_main_args_t, cef_settings_t};
use window;
use compositing::windowing::{IdleWindowEvent, WindowEvent};
use geom::size::TypedSize2D;
use glfw_app; use glfw_app;
use libc::funcs::c95::string::strlen;
use libc::{c_char, c_int, c_void}; use libc::{c_char, c_int, c_void};
use native; use native;
use rustrt::local::Local;
use servo::Browser; use servo::Browser;
use std::slice; use servo_util::opts;
use servo_util::opts::OpenGL;
use std::c_str::CString;
use std::cell::RefCell;
use std::rc::Rc;
use std::rt;
const MAX_RENDERING_THREADS: uint = 128;
// TODO(pcwalton): Get the home page via the CEF API.
static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";
// TODO(pcwalton): Support multiple windows.
pub enum ServoCefGlobals {
OnScreenGlobals(RefCell<Rc<glfw_app::window::Window>>,
RefCell<Browser<glfw_app::window::Window>>),
OffScreenGlobals(RefCell<Rc<window::Window>>, RefCell<Browser<window::Window>>),
}
local_data_key!(pub globals: ServoCefGlobals)
local_data_key!(pub message_queue: RefCell<Vec<WindowEvent>>)
// Copied from `libnative/lib.rs`.
static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20);
static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0"; static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
#[cfg(target_os="windows")] #[cfg(target_os="windows")]
@ -26,68 +50,109 @@ static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e1
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_initialize(args: *const cef_main_args_t, pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
_settings: *mut cef_settings_t, settings: *mut cef_settings_t,
application: *mut cef_app_t, application: *mut cef_app_t,
_windows_sandbox_info: *const c_void) _windows_sandbox_info: *const c_void)
-> c_int { -> c_int {
if args.is_null() { if args.is_null() {
return 0; return 0;
} }
unsafe { unsafe {
rt::init((*args).argc as int, (*args).argv);
command_line_init((*args).argc, (*args).argv); command_line_init((*args).argc, (*args).argv);
(*application).get_browser_process_handler.map(|cb| {
let handler = cb(application); if !application.is_null() {
if handler.is_not_null() { (*application).get_browser_process_handler.map(|cb| {
(*handler).on_context_initialized.map(|hcb| hcb(handler)); let handler = cb(application);
} if handler.is_not_null() {
}); (*handler).on_context_initialized.map(|hcb| hcb(handler));
}
});
}
} }
create_rust_task();
message_queue.replace(Some(RefCell::new(Vec::new())));
let urls = vec![HOME_URL.to_string()];
opts::set_opts(opts::Opts {
urls: urls,
n_paint_threads: 1,
gpu_painting: false,
tile_size: 512,
device_pixels_per_px: None,
time_profiler_period: None,
memory_profiler_period: None,
enable_experimental: false,
nonincremental_layout: false,
layout_threads: unsafe {
if ((*settings).rendering_threads as uint) < 1 {
1
} else if (*settings).rendering_threads as uint > MAX_RENDERING_THREADS {
MAX_RENDERING_THREADS
} else {
(*settings).rendering_threads as uint
}
},
output_file: None,
headless: false,
hard_fail: false,
bubble_inline_sizes_separately: false,
show_debug_borders: false,
show_debug_fragment_borders: false,
enable_text_antialiasing: true,
trace_layout: false,
devtools_port: None,
initial_window_size: TypedSize2D(800, 600),
profile_tasks: false,
user_agent: None,
dump_flow_tree: false,
validate_display_list_geometry: false,
render_api: OpenGL,
});
return 1 return 1
} }
// Copied from `libnative/lib.rs`.
fn create_rust_task() {
let something_around_the_top_of_the_stack = 1;
let addr = &something_around_the_top_of_the_stack as *const int;
let my_stack_top = addr as uint;
// FIXME #11359 we just assume that this thread has a stack of a
// certain size, and estimate that there's at most 20KB of stack
// frames above our current position.
let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE;
let task = native::task::new((my_stack_bottom, my_stack_top), rt::thread::main_guard_page());
Local::put(task);
}
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_shutdown() { pub extern "C" fn cef_shutdown() {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_run_message_loop() { pub extern "C" fn cef_run_message_loop() {
native::start(0, 0 as *const *const u8, proc() { let mut the_globals = globals.get();
GLOBAL_BROWSERS.get().map(|refcellbrowsers| { let the_globals = the_globals.as_mut().unwrap();
let browsers = refcellbrowsers.borrow(); match **the_globals {
let mut num = browsers.len(); OnScreenGlobals(ref window, ref browser) => {
for active_browser in browsers.iter() { while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
*active_browser.downcast().window.borrow_mut() = }
Some(glfw_app::create_window()); OffScreenGlobals(ref window, ref browser) => {
*active_browser.downcast().servo_browser.borrow_mut() = while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
Some(Browser::new((*active_browser.downcast() }
.window }
.borrow()).clone())); }
if !active_browser.downcast().callback_executed.get() {
browser_callback_after_created((*active_browser).clone()); #[no_mangle]
} pub extern "C" fn cef_do_message_loop_work() {
} send_window_event(IdleWindowEvent)
while num > 0 {
for active_browser in browsers.iter()
.filter(|&active_browser| {
active_browser.downcast()
.servo_browser
.borrow()
.is_some()
}) {
let ref mut browser = active_browser.downcast();
let mut servobrowser = browser.servo_browser.borrow_mut().take().unwrap();
if !servobrowser.handle_event(browser.window
.borrow_mut()
.as_ref()
.unwrap()
.wait_events()) {
servobrowser.shutdown();
num -= 1;
}
}
}
});
});
} }
#[no_mangle] #[no_mangle]
@ -95,33 +160,91 @@ pub extern "C" fn cef_quit_message_loop() {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_execute_process(args: *const cef_main_args_t, pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
_app: *mut cef_app_t, _app: *mut cef_app_t,
_windows_sandbox_info: *mut c_void) _windows_sandbox_info: *mut c_void)
-> c_int { -> c_int {
unsafe { -1
if args.is_null() { }
println!("args must be passed");
return -1;
}
for i in range(0u, (*args).argc as uint) {
let u = (*args).argv.offset(i as int) as *const u8;
slice::raw::buf_as_slice(u, strlen(u as *const i8) as uint, |s| {
if s.starts_with("--".as_bytes()) {
if s.slice_from(2) == KWAITFORDEBUGGER.as_bytes() {
//FIXME: this is NOT functionally equivalent to chromium!
//this should be a pause() call with an installed signal pub fn send_window_event(event: WindowEvent) {
//handler callback, something which is impossible now in rust message_queue.get().as_mut().unwrap().borrow_mut().push(event);
} else if s.slice_from(2) == KPROCESSTYPE.as_bytes() {
//TODO: run other process now let mut the_globals = globals.get();
} let the_globals = match the_globals.as_mut() {
} None => return,
}); Some(the_globals) => the_globals,
};
loop {
match **the_globals {
OnScreenGlobals(_, ref browser) => {
match browser.try_borrow_mut() {
None => {
// We're trying to send an event while processing another one. This will
// cause general badness, so queue up that event instead of immediately
// processing it.
break
}
Some(ref mut browser) => {
let event = match message_queue.get()
.as_mut()
.unwrap()
.borrow_mut()
.pop() {
None => return,
Some(event) => event,
};
browser.handle_event(event);
}
}
}
OffScreenGlobals(_, ref browser) => {
match browser.try_borrow_mut() {
None => {
// We're trying to send an event while processing another one. This will
// cause general badness, so queue up that event instead of immediately
// processing it.
break
}
Some(ref mut browser) => {
let event = match message_queue.get()
.as_mut()
.unwrap()
.borrow_mut()
.pop() {
None => return,
Some(event) => event,
};
browser.handle_event(event);
}
}
}
} }
} }
//process type not specified, must be browser process (NOOP) }
-1
macro_rules! browser_method_delegate(
( $( fn $method:ident ( ) -> $return_type:ty ; )* ) => (
$(
pub fn $method() -> $return_type {
let mut the_globals = globals.get();
let the_globals = match the_globals.as_mut() {
None => panic!("{}: no globals created", stringify!($method)),
Some(the_globals) => the_globals,
};
match **the_globals {
OnScreenGlobals(_, ref browser) => browser.borrow_mut().$method(),
OffScreenGlobals(_, ref browser) => browser.borrow_mut().$method(),
}
}
)*
)
)
browser_method_delegate! {
fn repaint_synchronously() -> ();
fn pinch_zoom_level() -> f32;
fn get_title_for_main_frame() -> ();
} }
#[no_mangle] #[no_mangle]
@ -133,6 +256,16 @@ pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
} }
} }
#[no_mangle]
pub extern "C" fn cef_log(_file: *const c_char,
_line: c_int,
_severity: c_int,
message: *const c_char) {
unsafe {
println!("{}", CString::new(message, false))
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_get_min_log_level() -> c_int { pub extern "C" fn cef_get_min_log_level() -> c_int {
0 0

45
ports/cef/frame.rs Normal file
View file

@ -0,0 +1,45 @@
/* 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/. */
use eutil::Downcast;
use interfaces::{CefFrame, CefStringVisitor, cef_frame_t, cef_string_visitor_t};
use types::{cef_string_t, cef_string_userfree_t};
use core;
use compositing::windowing::LoadUrlWindowEvent;
use std::cell::RefCell;
pub struct ServoCefFrame {
pub title_visitor: RefCell<Option<CefStringVisitor>>,
pub url: RefCell<String>,
}
impl ServoCefFrame {
pub fn new() -> ServoCefFrame {
ServoCefFrame {
title_visitor: RefCell::new(None),
url: RefCell::new(String::new()),
}
}
}
cef_class_impl! {
ServoCefFrame : CefFrame, cef_frame_t {
fn load_url(&this, url: *const cef_string_t) -> () {
let this = this.downcast();
*this.url.borrow_mut() = String::from_utf16(url).unwrap();
core::send_window_event(LoadUrlWindowEvent(String::from_utf16(url).unwrap()));
}
fn get_url(&this) -> cef_string_userfree_t {
let this = this.downcast();
(*this.url.borrow()).clone()
}
fn get_text(&this, visitor: *mut cef_string_visitor_t) -> () {
let this = this.downcast();
*this.title_visitor.borrow_mut() = Some(visitor);
core::get_title_for_main_frame();
}
}
}

View file

@ -14,11 +14,12 @@ extern crate log;
extern crate "plugins" as servo_plugins; extern crate "plugins" as servo_plugins;
extern crate servo; extern crate servo;
extern crate compositing;
extern crate azure; extern crate azure;
extern crate compositing;
extern crate geom; extern crate geom;
extern crate gfx; extern crate gfx;
extern crate gleam;
extern crate glfw; extern crate glfw;
extern crate glfw_app; extern crate glfw_app;
extern crate js; extern crate js;
@ -34,9 +35,14 @@ extern crate stb_image;
extern crate green; extern crate green;
extern crate native; extern crate native;
extern crate rustrt;
extern crate libc; extern crate libc;
extern crate "url" as std_url; extern crate "url" as std_url;
#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
extern crate core_graphics; extern crate core_graphics;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
@ -46,14 +52,17 @@ extern crate core_text;
pub mod macros; pub mod macros;
pub mod browser; pub mod browser;
pub mod browser_host;
pub mod command_line; pub mod command_line;
pub mod cookie; pub mod cookie;
pub mod core; pub mod core;
pub mod drag_data; pub mod drag_data;
pub mod eutil; pub mod eutil;
pub mod frame;
pub mod interfaces; pub mod interfaces;
pub mod print_settings; pub mod print_settings;
pub mod process_message; pub mod process_message;
pub mod render_handler;
pub mod request; pub mod request;
pub mod request_context; pub mod request_context;
pub mod response; pub mod response;
@ -67,8 +76,9 @@ pub mod switches;
pub mod task; pub mod task;
pub mod types; pub mod types;
pub mod urlrequest; pub mod urlrequest;
pub mod values;
pub mod v8; pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers; pub mod wrappers;
pub mod xml_reader; pub mod xml_reader;
pub mod zip_reader; pub mod zip_reader;

View file

@ -0,0 +1,19 @@
/* 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/. */
use interfaces::{CefBrowser, CefRenderHandler};
use types::PET_VIEW;
use std::ptr;
pub trait CefRenderHandlerExtensions {
fn paint(&self, browser: CefBrowser);
}
impl CefRenderHandlerExtensions for CefRenderHandler {
fn paint(&self, browser: CefBrowser) {
self.on_paint(browser, PET_VIEW, 0, ptr::null(), &mut (), 0, 0)
}
}

View file

@ -4,7 +4,7 @@
use eutil::slice_to_str; use eutil::slice_to_str;
use libc::{mod, size_t, c_int, c_ushort,c_void}; use libc::{mod, size_t, c_int, c_ushort, c_void};
use libc::types::os::arch::c95::wchar_t; use libc::types::os::arch::c95::wchar_t;
use std::char; use std::char;
use std::mem; use std::mem;
@ -54,7 +54,7 @@ pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) { pub extern "C" fn cef_string_userfree_utf16_free(cs: cef_string_userfree_utf16_t) {
unsafe { unsafe {
cef_string_utf16_clear(cs); cef_string_utf16_clear(cs);
libc::free(cs as *mut c_void) libc::free(cs as *mut c_void)
@ -269,19 +269,6 @@ pub extern "C" fn cef_string_utf8_to_wide(src: *const u8, src_len: size_t, outpu
}) })
} }
/// Wraps a borrowed reference to a UTF-16 CEF string.
pub struct CefStringRef<'a> {
pub c_object: &'a *const cef_string_utf16_t,
}
impl<'a> CefStringRef<'a> {
pub unsafe fn from_c_object(c_object: &'a *const cef_string_utf16_t) -> CefStringRef<'a> {
CefStringRef {
c_object: c_object,
}
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn cef_string_wide_to_utf8(src: *const wchar_t, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int { pub extern "C" fn cef_string_wide_to_utf8(src: *const wchar_t, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
if mem::size_of::<wchar_t>() == mem::size_of::<u16>() { if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
@ -321,3 +308,16 @@ pub fn empty_utf16_string() -> cef_string_utf16_t {
} }
} }
pub fn string_to_userfree_string(string: cef_string_utf16_t) -> cef_string_userfree_utf16_t {
unsafe {
let allocation: cef_string_userfree_utf16_t =
mem::transmute(libc::malloc(mem::size_of::<cef_string_utf16_t>() as size_t));
ptr::write(allocation, string);
allocation
}
}
pub fn empty_utf16_userfree_string() -> cef_string_userfree_utf16_t {
string_to_userfree_string(empty_utf16_string())
}

View file

@ -8,7 +8,8 @@ use std::collections::TreeMap;
use std::iter::AdditiveIterator; use std::iter::AdditiveIterator;
use std::mem; use std::mem;
use std::string::String; use std::string::String;
use string::{cef_string_userfree_utf16_alloc,cef_string_userfree_utf16_free,cef_string_utf16_set}; use string::{cef_string_userfree_utf16_alloc, cef_string_userfree_utf16_free};
use string::{cef_string_utf16_set};
use types::{cef_string_multimap_t,cef_string_t}; use types::{cef_string_multimap_t,cef_string_t};
fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> { fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {

File diff suppressed because it is too large Load diff

284
ports/cef/window.rs Normal file
View file

@ -0,0 +1,284 @@
/* 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/. */
//! Off-screen windows.
//!
//! This is used for off-screen rendering mode only; on-screen windows (the default embedding mode)
//! are managed by a platform toolkit (GLFW or Glutin).
use eutil::Downcast;
use interfaces::CefBrowser;
use render_handler::CefRenderHandlerExtensions;
use types::cef_rect_t;
use wrappers::Utf16Encoder;
use compositing::compositor_task::{mod, CompositorProxy, CompositorReceiver};
use compositing::windowing::{IdleWindowEvent, WindowEvent, WindowMethods};
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use gleam::gl;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
use libc::{c_char, c_void};
use servo_msg::compositor_msg::{Blank, FinishedLoading, Loading, PerformingLayout, PaintState};
use servo_msg::compositor_msg::{ReadyState};
use servo_msg::constellation_msg::LoadData;
use servo_util::geometry::ScreenPx;
use std::cell::RefCell;
use std::rc::Rc;
#[cfg(target_os="macos")]
use std::ptr;
/// The type of an off-screen window.
#[deriving(Clone)]
pub struct Window {
cef_browser: RefCell<Option<CefBrowser>>,
}
impl Window {
/// Creates a new window.
pub fn new() -> Rc<Window> {
const RTLD_DEFAULT: *mut c_void = (-2) as *mut c_void;
extern {
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
}
gl::load_with(|s| {
unsafe {
let c_str = s.to_c_str();
dlsym(RTLD_DEFAULT, c_str.as_ptr()) as *const c_void
}
});
Rc::new(Window {
cef_browser: RefCell::new(None),
})
}
/// Sets the current browser.
pub fn set_browser(&self, browser: CefBrowser) {
*self.cef_browser.borrow_mut() = Some(browser)
}
/// Currently unimplemented.
pub fn wait_events(&self) -> WindowEvent {
IdleWindowEvent
}
}
impl WindowMethods for Window {
fn framebuffer_size(&self) -> TypedSize2D<DevicePixel,uint> {
let browser = self.cef_browser.borrow();
match *browser {
None => TypedSize2D(400, 300),
Some(ref browser) => {
let mut rect = cef_rect_t::zero();
browser.get_host()
.get_client()
.get_render_handler()
.get_backing_rect((*browser).clone(), &mut rect);
TypedSize2D(rect.width as uint, rect.height as uint)
}
}
}
fn size(&self) -> TypedSize2D<ScreenPx,f32> {
let browser = self.cef_browser.borrow();
match *browser {
None => TypedSize2D(400.0, 300.0),
Some(ref browser) => {
let mut rect = cef_rect_t::zero();
browser.get_host()
.get_client()
.get_render_handler()
.get_view_rect((*browser).clone(), &mut rect);
TypedSize2D(rect.width as f32, rect.height as f32)
}
}
}
fn present(&self) {
let browser = self.cef_browser.borrow();
match *browser {
None => {}
Some(ref browser) => {
browser.get_host().get_client().get_render_handler().on_present(browser.clone());
}
}
}
fn set_ready_state(&self, ready_state: ReadyState) {
let browser = self.cef_browser.borrow();
let browser = match *browser {
None => return,
Some(ref browser) => browser,
};
let is_loading = match ready_state {
Blank | FinishedLoading => 0,
Loading | PerformingLayout => 1,
};
browser.get_host()
.get_client()
.get_load_handler()
.on_loading_state_change(browser.clone(), is_loading, 1, 1);
}
fn set_paint_state(&self, _: PaintState) {
// TODO(pcwalton)
}
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx,DevicePixel,f32> {
let browser = self.cef_browser.borrow();
match *browser {
None => ScaleFactor(1.0),
Some(ref browser) => {
let mut view_rect = cef_rect_t::zero();
browser.get_host()
.get_client()
.get_render_handler()
.get_view_rect((*browser).clone(), &mut view_rect);
let mut backing_rect = cef_rect_t::zero();
browser.get_host()
.get_client()
.get_render_handler()
.get_backing_rect((*browser).clone(), &mut backing_rect);
ScaleFactor(backing_rect.width as f32 / view_rect.width as f32)
}
}
}
#[cfg(target_os="macos")]
fn native_metadata(&self) -> NativeGraphicsMetadata {
use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};
// FIXME(pcwalton)
unsafe {
NativeGraphicsMetadata {
pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
}
}
}
#[cfg(target_os="linux")]
fn native_metadata(&self) -> NativeGraphicsMetadata {
// TODO(pcwalton)
panic!()
}
fn create_compositor_channel(_: &Option<Rc<Window>>)
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
let (sender, receiver) = channel();
(box CefCompositorProxy {
sender: sender,
} as Box<CompositorProxy+Send>,
box receiver as Box<CompositorReceiver>)
}
fn prepare_for_composite(&self) -> bool {
let browser = self.cef_browser.borrow();
match *browser {
None => {}
Some(ref browser) => {
browser.get_host().get_client().get_render_handler().paint(browser.clone());
}
}
true
}
fn load_end(&self) {
// FIXME(pcwalton): The status code 200 is a lie.
let browser = self.cef_browser.borrow();
let browser = match *browser {
None => return,
Some(ref browser) => browser,
};
browser.get_host()
.get_client()
.get_load_handler()
.on_load_end((*browser).clone(), browser.get_main_frame(), 200);
}
fn set_page_title(&self, string: Option<String>) {
let browser = self.cef_browser.borrow();
let browser = match *browser {
None => return,
Some(ref browser) => browser,
};
let frame = browser.get_main_frame();
let frame = frame.downcast();
let mut title_visitor = frame.title_visitor.borrow_mut();
match &mut *title_visitor {
&None => {}
&Some(ref mut visitor) => {
match string {
None => visitor.visit(&[]),
Some(string) => {
let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
visitor.visit(utf16_chars.as_slice())
}
}
}
}
}
fn set_page_load_data(&self, load_data: LoadData) {
let browser = self.cef_browser.borrow();
let browser = match *browser {
None => return,
Some(ref browser) => browser,
};
let frame = browser.get_main_frame();
let frame = frame.downcast();
*frame.url.borrow_mut() = load_data.url.to_string()
}
}
struct CefCompositorProxy {
sender: Sender<compositor_task::Msg>,
}
impl CompositorProxy for CefCompositorProxy {
#[cfg(target_os="macos")]
fn send(&mut self, msg: compositor_task::Msg) {
use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined, NSAutoreleasePool};
use cocoa::appkit::{NSEvent, NSPoint};
use cocoa::base::nil;
// Send a message and kick the OS event loop awake.
self.sender.send(msg);
unsafe {
let pool = NSAutoreleasePool::new(nil);
let event =
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2(
nil,
NSApplicationDefined,
NSPoint::new(0.0, 0.0),
0,
0.0,
0,
ptr::null_mut(),
0,
0,
0);
NSApp().postEvent_atStart_(event, false);
pool.drain();
}
}
#[cfg(target_os="linux")]
fn send(&mut self, msg: compositor_task::Msg) {
// FIXME(pcwalton): Kick the GTK event loop awake?
self.sender.send(msg);
}
fn clone_compositor_proxy(&self) -> Box<CompositorProxy+Send> {
box CefCompositorProxy {
sender: self.sender.clone(),
} as Box<CompositorProxy+Send>
}
}

View file

@ -21,9 +21,9 @@ use types::{cef_load_handler_t, cef_menu_item_type_t, cef_mouse_button_type_t};
use types::{cef_mouse_event, cef_navigation_type_t}; use types::{cef_mouse_event, cef_navigation_type_t};
use types::{cef_page_range_t, cef_paint_element_type_t, cef_point_t, cef_postdataelement_type_t}; use types::{cef_page_range_t, cef_paint_element_type_t, cef_point_t, cef_postdataelement_type_t};
use types::{cef_popup_features_t, cef_process_id_t}; use types::{cef_popup_features_t, cef_process_id_t};
use types::{cef_rect_t, cef_request_context_t, cef_request_handler_t}; use types::{cef_rect_t, cef_request_handler_t};
use types::{cef_resource_type_t}; use types::{cef_resource_type_t};
use types::{cef_screen_info_t, cef_size_t, cef_string_t}; use types::{cef_screen_info_t, cef_size_t, cef_string_t, cef_string_userfree_t};
use types::{cef_string_list_t, cef_string_map_t, cef_string_multimap_t, cef_string_utf16}; use types::{cef_string_list_t, cef_string_map_t, cef_string_multimap_t, cef_string_utf16};
use types::{cef_termination_status_t, cef_text_input_context_t, cef_thread_id_t}; use types::{cef_termination_status_t, cef_text_input_context_t, cef_thread_id_t};
use types::{cef_time_t, cef_transition_type_t, cef_urlrequest_status_t}; use types::{cef_time_t, cef_transition_type_t, cef_urlrequest_status_t};
@ -126,7 +126,6 @@ cef_noop_wrapper!(*mut cef_geolocation_handler_t)
cef_noop_wrapper!(*mut cef_jsdialog_handler_t) cef_noop_wrapper!(*mut cef_jsdialog_handler_t)
cef_noop_wrapper!(*mut cef_keyboard_handler_t) cef_noop_wrapper!(*mut cef_keyboard_handler_t)
cef_noop_wrapper!(*mut cef_load_handler_t) cef_noop_wrapper!(*mut cef_load_handler_t)
cef_noop_wrapper!(*mut cef_request_context_t)
cef_noop_wrapper!(*mut cef_request_handler_t) cef_noop_wrapper!(*mut cef_request_handler_t)
cef_noop_wrapper!(*mut cef_string_list_t) cef_noop_wrapper!(*mut cef_string_list_t)
cef_noop_wrapper!(*mut cef_string_utf16) cef_noop_wrapper!(*mut cef_string_utf16)
@ -181,9 +180,8 @@ cef_unimplemented_wrapper!(cef_string_t, String)
impl<'a> CefWrap<*const cef_string_t> for &'a [u16] { impl<'a> CefWrap<*const cef_string_t> for &'a [u16] {
fn to_c(buffer: &'a [u16]) -> *const cef_string_t { fn to_c(buffer: &'a [u16]) -> *const cef_string_t {
unsafe { unsafe {
let ptr: *mut c_ushort = let ptr: *mut c_ushort = mem::transmute(libc::malloc(((buffer.len() + 1) * 2) as u64));
mem::transmute(libc::calloc(1, ((buffer.len() * 2) + 1) as u64)); ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), buffer.len());
ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), (buffer.len() * 2) as uint);
*ptr.offset(buffer.len() as int) = 0; *ptr.offset(buffer.len() as int) = 0;
// FIXME(pcwalton): This leaks!! We should instead have the caller pass some scratch // FIXME(pcwalton): This leaks!! We should instead have the caller pass some scratch
@ -240,6 +238,71 @@ impl<'a,'b> CefWrap<*mut *const c_char> for &'a mut &'b str {
} }
} }
impl<'a> CefWrap<cef_string_userfree_t> for String {
fn to_c(string: String) -> cef_string_userfree_t {
let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
let boxed_string;
unsafe {
let buffer = libc::malloc((mem::size_of::<c_ushort>() as u64) *
((utf16_chars.len() + 1) as u64 + 1)) as *mut u16;
for (i, ch) in utf16_chars.iter().enumerate() {
*buffer.offset(i as int) = *ch
}
*buffer.offset(utf16_chars.len() as int) = 0;
boxed_string = libc::malloc(mem::size_of::<cef_string_utf16>() as u64) as
*mut cef_string_utf16;
ptr::write(&mut (*boxed_string).str, buffer);
ptr::write(&mut (*boxed_string).length, utf16_chars.len() as u64);
ptr::write(&mut (*boxed_string).dtor, Some(free_utf16_buffer));
mem::forget(utf16_chars);
}
boxed_string
}
unsafe fn to_rust(_: cef_string_userfree_t) -> String {
panic!("unimplemented CEF type conversion: cef_string_userfree_t")
}
}
extern "C" fn free_utf16_buffer(buffer: *mut c_ushort) {
unsafe {
libc::free(buffer as *mut c_void)
}
}
// TODO(pcwalton): Post Rust-upgrade, remove this and use `collections::str::Utf16Encoder`.
pub struct Utf16Encoder<I> {
chars: I,
extra: u16,
}
impl<I> Utf16Encoder<I> {
pub fn new(chars: I) -> Utf16Encoder<I> where I: Iterator<char> {
Utf16Encoder {
chars: chars,
extra: 0,
}
}
}
impl<I> Iterator<u16> for Utf16Encoder<I> where I: Iterator<char> {
fn next(&mut self) -> Option<u16> {
if self.extra != 0 {
return Some(mem::replace(&mut self.extra, 0))
}
let mut buf = [0u16, ..2];
self.chars.next().map(|ch| {
let n = ch.encode_utf16(buf.as_mut_slice()).unwrap_or(0);
if n == 2 {
self.extra = buf[1]
}
buf[0]
})
}
}
impl<'a> CefWrap<cef_string_t> for &'a mut String { impl<'a> CefWrap<cef_string_t> for &'a mut String {
fn to_c(_: &'a mut String) -> cef_string_t { fn to_c(_: &'a mut String) -> cef_string_t {
panic!("unimplemented CEF type conversion: &'a mut String") panic!("unimplemented CEF type conversion: &'a mut String")

View file

@ -23,9 +23,9 @@ use gleam::gl;
use layers::geometry::DevicePixel; use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata; use layers::platform::surface::NativeGraphicsMetadata;
use libc::c_int; use libc::c_int;
use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; use msg::compositor_msg::{Blank, FinishedLoading, IdlePaintState, Loading, PaintState};
use msg::compositor_msg::{IdlePaintState, PaintState, PaintingPaintState}; use msg::compositor_msg::{PaintingPaintState, PerformingLayout, ReadyState};
use msg::constellation_msg; use msg::constellation_msg::{mod, LoadData};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::comm::Receiver; use std::comm::Receiver;
use std::rc::Rc; use std::rc::Rc;
@ -97,6 +97,15 @@ impl Window {
} }
pub fn wait_events(&self) -> WindowEvent { pub fn wait_events(&self) -> WindowEvent {
self.wait_or_poll_events(|glfw| glfw.wait_events())
}
pub fn poll_events(&self) -> WindowEvent {
self.wait_or_poll_events(|glfw| glfw.poll_events())
}
/// Helper method to factor out functionality from `poll_events` and `wait_events`.
fn wait_or_poll_events(&self, callback: |glfw: &glfw::Glfw|) -> WindowEvent {
{ {
let mut event_queue = self.event_queue.borrow_mut(); let mut event_queue = self.event_queue.borrow_mut();
if !event_queue.is_empty() { if !event_queue.is_empty() {
@ -104,7 +113,7 @@ impl Window {
} }
} }
self.glfw.wait_events(); callback(&self.glfw);
for (_, event) in glfw::flush_messages(&self.events) { for (_, event) in glfw::flush_messages(&self.events) {
self.handle_window_event(&self.glfw_window, event); self.handle_window_event(&self.glfw_window, event);
} }
@ -196,6 +205,16 @@ impl WindowMethods for Window {
} as Box<CompositorProxy+Send>, } as Box<CompositorProxy+Send>,
box receiver as Box<CompositorReceiver>) box receiver as Box<CompositorReceiver>)
} }
fn prepare_for_composite(&self) -> bool {
true
}
fn load_end(&self) {}
fn set_page_title(&self, _: Option<String>) {}
fn set_page_load_data(&self, _: LoadData) {}
} }
impl Window { impl Window {

View file

@ -113,7 +113,7 @@ class MachCommands(CommandBase):
build_start = time() build_start = time()
with cd(path.join("ports", "cef")): with cd(path.join("ports", "cef")):
ret = subprocess.call(["cargo", "build"], ret = subprocess.call(["cargo", "build"] + opts,
env=self.build_env()) env=self.build_env())
elapsed = time() - build_start elapsed = time() - build_start