aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-11-24 17:23:30 -0800
committerPatrick Walton <pcwalton@mimiga.net>2014-12-10 08:35:47 -0800
commit8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e (patch)
tree722684b4013644a1ccc3d635f45f3521dd66dc08
parent315e166cf7f24f4586e8ce863be597ce0a3f34c9 (diff)
downloadservo-8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e.tar.gz
servo-8b2aadc30be9e7da163b0eb5b88f2988f5b43f9e.zip
ports/cef: Implement accelerated compositing for the CEF port.
-rw-r--r--components/compositing/compositor.rs104
-rw-r--r--components/compositing/compositor_task.rs22
-rw-r--r--components/compositing/constellation.rs185
-rw-r--r--components/compositing/headless.rs12
-rw-r--r--components/compositing/pipeline.rs35
-rw-r--r--components/compositing/windowing.rs25
-rw-r--r--components/msg/compositor_msg.rs4
-rw-r--r--components/msg/constellation_msg.rs3
-rw-r--r--components/script/dom/document.rs8
-rw-r--r--components/script/dom/htmltitleelement.rs22
-rw-r--r--components/script/dom/virtualmethods.rs8
-rw-r--r--components/script/page.rs17
-rw-r--r--components/script/script_task.rs17
-rw-r--r--components/script_traits/lib.rs3
-rw-r--r--components/servo/Cargo.lock4
-rw-r--r--components/servo/lib.rs8
-rw-r--r--components/servo/main.rs6
-rw-r--r--ports/android/glut_app/Cargo.lock2
-rw-r--r--ports/android/glut_app/window.rs34
-rw-r--r--ports/cef/Cargo.lock8
-rw-r--r--ports/cef/Cargo.toml3
-rw-r--r--ports/cef/browser.rs94
-rw-r--r--ports/cef/browser_host.rs158
-rw-r--r--ports/cef/command_line.rs6
-rw-r--r--ports/cef/core.rs275
-rw-r--r--ports/cef/frame.rs45
-rw-r--r--ports/cef/lib.rs14
-rw-r--r--ports/cef/render_handler.rs19
-rw-r--r--ports/cef/string.rs30
-rw-r--r--ports/cef/string_multimap.rs3
-rw-r--r--ports/cef/types.rs828
-rw-r--r--ports/cef/window.rs284
-rw-r--r--ports/cef/wrappers.rs75
-rw-r--r--ports/glfw/window.rs27
-rw-r--r--python/servo/build_commands.py2
35 files changed, 1747 insertions, 643 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index 44015c8012c..c5a11fa1605 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -3,23 +3,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents};
-use compositor_layer::WantsScrollEvents;
-use compositor_task::{ChangeReadyState, ChangePaintState, CompositorEventListener};
-use compositor_task::{CompositorProxy, CompositorReceiver, CompositorTask};
-use compositor_task::{CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer, Exit};
-use compositor_task::{FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties};
+use compositor_layer::{WantsScrollEvents};
+use compositor_task::{ChangePageLoadData, ChangePageTitle, ChangePaintState, ChangeReadyState};
+use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver};
+use compositor_task::{CompositorTask, CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer};
+use compositor_task::{Exit, FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties};
use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint};
use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete};
-use constellation::{SendableFrameTree, FrameTreeDiff};
+use constellation::{FrameId, FrameTreeDiff, SendableFrameTree};
use pipeline::CompositionPipeline;
use scrolling::ScrollingTimerProxy;
use windowing;
-use windowing::{IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent};
-use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEvent};
-use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent};
+use windowing::{IdleWindowEvent, InitializeCompositingWindowEvent};
+use windowing::{KeyEvent, LoadUrlWindowEvent, MouseWindowClickEvent, MouseWindowEvent};
+use windowing::{MouseWindowEventClass, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
+use windowing::{MouseWindowMoveEventClass, NavigationWindowEvent, PinchZoomWindowEvent};
use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent};
use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
-use windowing::{PinchZoomWindowEvent, KeyEvent};
use azure::azure_hl;
use std::cmp;
@@ -40,11 +40,11 @@ use gleam::gl::types::{GLint, GLsizei};
use gleam::gl;
use script_traits::{ViewportMsg, ScriptControlChan};
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId};
-use servo_msg::compositor_msg::{ReadyState, PaintingPaintState, PaintState, Scrollable};
-use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg};
-use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg};
-use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key, KeyModifiers};
-use servo_msg::constellation_msg;
+use servo_msg::compositor_msg::{ReadyState, PaintState, PaintingPaintState, Scrollable};
+use servo_msg::constellation_msg::{mod, ConstellationChan, ExitMsg};
+use servo_msg::constellation_msg::{GetPipelineTitleMsg, Key, KeyModifiers, KeyState, LoadData};
+use servo_msg::constellation_msg::{LoadUrlMsg, NavigateMsg, PipelineId, ResizedWindowMsg};
+use servo_msg::constellation_msg::{WindowSizeData};
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
use servo_util::memory::MemoryProfilerChan;
use servo_util::opts;
@@ -58,6 +58,7 @@ use std::slice::bytes::copy_memory;
use time::{precise_time_ns, precise_time_s};
use url::Url;
+/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
pub struct IOCompositor<Window: WindowMethods> {
/// The application window.
window: Rc<Window>,
@@ -65,8 +66,9 @@ pub struct IOCompositor<Window: WindowMethods> {
/// The port on which we receive messages.
port: Box<CompositorReceiver>,
- /// The render context.
- context: RenderContext,
+ /// The render context. This will be `None` if the windowing system has not yet sent us a
+ /// `PrepareRenderingEvent`.
+ context: Option<RenderContext>,
/// The root pipeline.
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.
let window_size = window.framebuffer_size();
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 {
window: window,
port: receiver,
- context: rendergl::RenderContext::new(context, show_debug_borders),
+ context: None,
root_pipeline: None,
scene: Scene::new(Rect {
origin: Zero::zero(),
@@ -262,6 +261,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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) => {
self.remove_outstanding_paint_msg();
}
@@ -305,13 +312,18 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.scroll_fragment_to_point(pipeline_id, layer_id, point);
}
- (LoadComplete(..), NotShuttingDown) => {
+ (LoadComplete, NotShuttingDown) => {
self.got_load_complete_message = true;
// If we're painting in headless mode, schedule a recomposite.
if opts::get().output_file.is_some() {
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) => {
@@ -371,6 +383,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
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 {
if self.ready_states.len() == 0 {
return false;
@@ -629,7 +649,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
IdleWindowEvent => {}
RefreshWindowEvent => {
- self.composite_if_necessary()
+ self.composite();
+ }
+
+ InitializeCompositingWindowEvent => {
+ self.initialize_compositing();
}
ResizeWindowEvent(size) => {
@@ -678,6 +702,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
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.
let new_hidpi_factor = self.window.hidpi_factor();
if self.hidpi_factor != new_hidpi_factor {
@@ -960,6 +986,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
fn composite(&mut self) {
+ if !self.window.prepare_for_composite() {
+ return
+ }
+
let output_image = opts::get().output_file.is_some() &&
self.is_ready_to_paint_image_output();
@@ -995,7 +1025,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// paint the scene.
match self.scene.root {
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 => {}
}
@@ -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,
layer: Rc<Layer<CompositorData>>,
point: TypedPoint2D<LayerPixel, f32>)
@@ -1229,4 +1272,17 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
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));
+ }
}
diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs
index 89aed5defa0..e7d851ceaf6 100644
--- a/components/compositing/compositor_task.rs
+++ b/components/compositing/compositor_task.rs
@@ -5,7 +5,7 @@
//! Communication with the compositor task.
pub use windowing;
-pub use constellation::{SendableFrameTree, FrameTreeDiff};
+pub use constellation::{FrameId, SendableFrameTree, FrameTreeDiff};
use compositor;
use headless;
@@ -19,7 +19,7 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics
use layers::layers::LayerBufferSet;
use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
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::time::TimeProfilerChan;
use std::comm::{channel, Sender, Receiver};
@@ -81,8 +81,13 @@ impl ScriptListener for Box<CompositorProxy+'static+Send> {
fn dup(&mut self) -> 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 pipeline_id: PipelineId,
pub epoch: Epoch,
@@ -184,9 +189,13 @@ pub enum Msg {
ChangeReadyState(PipelineId, ReadyState),
/// Alerts the compositor to the current status of painting.
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,
- /// 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),
/// Sends an updated version of the frame tree.
FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>),
@@ -210,6 +219,8 @@ impl Show for Msg {
Paint(..) => write!(f, "Paint"),
ChangeReadyState(..) => write!(f, "ChangeReadyState"),
ChangePaintState(..) => write!(f, "ChangePaintState"),
+ ChangePageTitle(..) => write!(f, "ChangePageTitle"),
+ ChangePageLoadData(..) => write!(f, "ChangePageLoadData"),
PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"),
SetIds(..) => write!(f, "SetIds"),
FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"),
@@ -269,5 +280,8 @@ pub trait CompositorEventListener {
fn handle_event(&mut self, event: WindowEvent) -> bool;
fn repaint_synchronously(&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);
}
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs
index 5155801f553..a993394de13 100644
--- a/components/compositing/constellation.rs
+++ b/components/compositing/constellation.rs
@@ -4,7 +4,8 @@
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::DevtoolsControlChan;
use geom::rect::{Rect, TypedRect};
@@ -14,16 +15,16 @@ use gfx::paint_task;
use layers::geometry::DevicePixel;
use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg};
use libc;
-use script_traits;
-use script_traits::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
+use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
use script_traits::{ScriptControlChan, ScriptTaskFactory};
use servo_msg::compositor_msg::LayerId;
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::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg};
-use servo_msg::constellation_msg::{NavigationType, PipelineId, PainterReadyMsg, ResizedWindowMsg};
+use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers, LoadCompleteMsg};
+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::{KeyEvent, Key, KeyState, KeyModifiers};
use servo_msg::constellation_msg;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask;
@@ -76,6 +77,10 @@ pub struct Constellation<LTF, STF> {
/// The next free ID to assign to a pipeline.
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_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
@@ -86,17 +91,28 @@ pub struct Constellation<LTF, STF> {
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 {
+ /// The ID of this frame.
+ pub id: FrameId,
+ /// The pipeline for this frame.
pub pipeline: Rc<Pipeline>,
+ /// The parent frame's pipeline.
pub parent: RefCell<Option<Rc<Pipeline>>>,
+ /// A vector of child frames.
pub children: RefCell<Vec<ChildFrameTree>>,
+ /// Whether this frame has a compositor layer.
pub has_compositor_layer: Cell<bool>,
}
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 {
+ id: id,
pipeline: pipeline,
parent: RefCell::new(parent_pipeline),
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.
struct FrameChange {
+ /// The old pipeline ID.
pub before: Option<PipelineId>,
+ /// The resulting frame tree after navigation.
pub after: Rc<FrameTree>,
+ /// The kind of navigation that is occurring.
pub navigation_type: NavigationType,
}
/// Stores the Id's of the pipelines previous and next in the browser's history
struct NavigationContext {
- pub previous: Vec<Rc<FrameTree>>,
- pub next: Vec<Rc<FrameTree>>,
- pub current: Option<Rc<FrameTree>>,
+ previous: Vec<Rc<FrameTree>>,
+ next: Vec<Rc<FrameTree>>,
+ current: Option<Rc<FrameTree>>,
}
impl NavigationContext {
@@ -258,29 +277,30 @@ impl NavigationContext {
/* 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. */
- fn back(&mut self) -> Rc<FrameTree> {
+ fn back(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
self.next.push(self.current.take().unwrap());
let prev = self.previous.pop().unwrap();
- self.current = Some(prev.clone());
+ self.set_current(prev.clone(), compositor_proxy);
prev
}
- fn forward(&mut self) -> Rc<FrameTree> {
+ fn forward(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
self.previous.push(self.current.take().unwrap());
let next = self.next.pop().unwrap();
- self.current = Some(next.clone());
+ self.set_current(next.clone(), compositor_proxy);
next
}
/// 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);
let evicted = replace(&mut self.next, vec!());
match self.current.take() {
Some(current) => self.previous.push(current),
None => (),
}
- self.current = Some(frame_tree);
+ self.set_current(frame_tree, compositor_proxy);
evicted
}
@@ -308,6 +328,14 @@ impl NavigationContext {
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> {
@@ -334,6 +362,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipelines: HashMap::new(),
navigation_context: NavigationContext::new(),
next_pipeline_id: PipelineId(0),
+ next_frame_id: FrameId(0),
pending_frames: vec!(),
pending_sizes: HashMap::new(),
time_profiler_chan: time_profiler_chan,
@@ -358,31 +387,30 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
}
/// Helper function for creating a pipeline
- fn new_pipeline(&self,
+ fn new_pipeline(&mut self,
id: PipelineId,
subpage_id: Option<SubpageId>,
script_pipeline: Option<Rc<Pipeline>>,
load_data: LoadData)
-> Rc<Pipeline> {
- let pipe = Pipeline::create::<LTF, STF>(id,
- subpage_id,
- self.chan.clone(),
- self.compositor_proxy.clone_compositor_proxy(),
- self.devtools_chan.clone(),
- self.image_cache_task.clone(),
- self.font_cache_task.clone(),
- self.resource_task.clone(),
- self.storage_task.clone(),
- self.time_profiler_chan.clone(),
- self.window_size,
- script_pipeline,
- load_data);
- pipe.load();
- Rc::new(pipe)
- }
-
-
- /// Helper function for getting a unique pipeline Id
+ let pipe = Pipeline::create::<LTF, STF>(id,
+ subpage_id,
+ self.chan.clone(),
+ self.compositor_proxy.clone_compositor_proxy(),
+ self.devtools_chan.clone(),
+ self.image_cache_task.clone(),
+ self.font_cache_task.clone(),
+ self.resource_task.clone(),
+ self.storage_task.clone(),
+ self.time_profiler_chan.clone(),
+ self.window_size,
+ script_pipeline,
+ load_data.clone());
+ pipe.load();
+ Rc::new(pipe)
+ }
+
+ /// Helper function for getting a unique pipeline ID.
fn get_next_pipeline_id(&mut self) -> PipelineId {
let id = 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
}
+ /// 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.
/// The currently active frame tree should always be the current painter
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");
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
}
@@ -529,27 +569,38 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
debug!("creating replacement pipeline for about:failure");
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,
LoadData::new(Url::parse("about:failure").unwrap()));
- self.pending_frames.push(FrameChange{
- before: Some(pipeline_id),
- after: Rc::new(FrameTree::new(pipeline.clone(), None)),
- navigation_type: constellation_msg::Load,
- });
+ self.browse(Some(pipeline_id),
+ Rc::new(FrameTree::new(new_frame_id, pipeline.clone(), None)),
+ constellation_msg::Load);
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) {
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));
-
- self.pending_frames.push(FrameChange {
- before: None,
- after: Rc::new(FrameTree::new(pipeline.clone(), None)),
- navigation_type: constellation_msg::Load,
- });
+ self.browse(None,
+ Rc::new(FrameTree::new(next_frame_id, pipeline.clone(), None)),
+ constellation_msg::Load);
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));
for frame_tree in frame_trees.iter() {
+ let next_frame_id = self.get_next_frame_id();
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));
}
self.pipelines.insert(pipeline.id, pipeline);
}
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.
let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect(
"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 subpage_id = source_frame.pipeline.subpage_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);
-
- self.pending_frames.push(FrameChange {
- before: Some(source_id),
- after: Rc::new(FrameTree::new(pipeline.clone(), parent.borrow().clone())),
- navigation_type: constellation_msg::Load,
- });
+ self.browse(Some(source_id),
+ Rc::new(FrameTree::new(next_frame_id,
+ pipeline.clone(),
+ parent.borrow().clone())),
+ constellation_msg::Load);
self.pipelines.insert(pipeline.id, pipeline);
}
@@ -752,7 +806,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
frame.pipeline.revoke_paint_permission();
}
}
- self.navigation_context.forward()
+ self.navigation_context.forward(&mut *self.compositor_proxy)
}
constellation_msg::Back => {
if self.navigation_context.previous.is_empty() {
@@ -764,7 +818,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
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) {
debug!("Painter {} ready to send paint msg", pipeline_id);
// 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 {
constellation_msg::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);
}
_ => {
diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs
index 459af00fcc2..7fc1df7dbe6 100644
--- a/components/compositing/headless.rs
+++ b/components/compositing/headless.rs
@@ -5,7 +5,8 @@
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds};
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 geom::scale_factor::ScaleFactor;
@@ -104,7 +105,8 @@ impl CompositorEventListener for NullCompositor {
CreateOrUpdateDescendantLayer(..) |
SetLayerOrigin(..) | Paint(..) |
ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) |
- LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) => ()
+ LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) | ChangePageTitle(..) |
+ ChangePageLoadData(..) => ()
}
true
}
@@ -119,4 +121,10 @@ impl CompositorEventListener for NullCompositor {
self.time_profiler_chan.send(time::ExitMsg);
self.memory_profiler_chan.send(memory::ExitMsg);
}
+
+ fn pinch_zoom_level(&self) -> f32 {
+ 1.0
+ }
+
+ fn get_title_for_main_frame(&self) {}
}
diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs
index cf1ebd16f8c..6dd9dabb0bf 100644
--- a/components/compositing/pipeline.rs
+++ b/components/compositing/pipeline.rs
@@ -28,8 +28,10 @@ pub struct Pipeline {
pub paint_chan: PaintChan,
pub layout_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,
+ /// The title of the most recently-loaded page.
+ pub title: Option<String>,
}
/// 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.
/// Returns the channels wrapped in a struct.
/// If script_pipeline is not None, then subpage_id must also be not None.
- pub fn create<LTF:LayoutTaskFactory, STF:ScriptTaskFactory>(
- id: PipelineId,
- subpage_id: Option<SubpageId>,
- constellation_chan: ConstellationChan,
- compositor_proxy: Box<CompositorProxy+'static+Send>,
- devtools_chan: Option<DevtoolsControlChan>,
- image_cache_task: ImageCacheTask,
- font_cache_task: FontCacheTask,
- resource_task: ResourceTask,
- storage_task: StorageTask,
- time_profiler_chan: TimeProfilerChan,
- window_size: WindowSizeData,
- script_pipeline: Option<Rc<Pipeline>>,
- load_data: LoadData)
- -> Pipeline {
+ pub fn create<LTF,STF>(id: PipelineId,
+ subpage_id: Option<SubpageId>,
+ constellation_chan: ConstellationChan,
+ compositor_proxy: Box<CompositorProxy+'static+Send>,
+ devtools_chan: Option<DevtoolsControlChan>,
+ image_cache_task: ImageCacheTask,
+ font_cache_task: FontCacheTask,
+ resource_task: ResourceTask,
+ storage_task: StorageTask,
+ time_profiler_chan: TimeProfilerChan,
+ window_size: WindowSizeData,
+ script_pipeline: Option<Rc<Pipeline>>,
+ load_data: LoadData)
+ -> Pipeline
+ where LTF: LayoutTaskFactory, STF:ScriptTaskFactory {
let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>);
let (paint_port, paint_chan) = PaintChan::new();
let (paint_shutdown_chan, paint_shutdown_port) = channel();
@@ -153,6 +155,7 @@ impl Pipeline {
layout_shutdown_port: layout_shutdown_port,
paint_shutdown_port: paint_shutdown_port,
load_data: load_data,
+ title: None,
}
}
diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs
index 0dffe0a8f94..339a5fe789d 100644
--- a/components/compositing/windowing.rs
+++ b/components/compositing/windowing.rs
@@ -11,8 +11,8 @@ use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
-use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers};
-use servo_msg::compositor_msg::{ReadyState, PaintState};
+use servo_msg::compositor_msg::{PaintState, ReadyState};
+use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData};
use servo_util::geometry::ScreenPx;
use std::fmt::{FormatError, Formatter, Show};
use std::rc::Rc;
@@ -37,8 +37,12 @@ pub enum WindowEvent {
/// It's possible that this should be something like
/// `CompositorMessageWindowEvent(compositor_task::Msg)` instead.
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,
+ /// 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.
ResizeWindowEvent(TypedSize2D<DevicePixel, uint>),
/// Sent when a new URL is to be loaded.
@@ -47,7 +51,8 @@ pub enum WindowEvent {
MouseWindowEventClass(MouseWindowEvent),
/// Sent when a mouse move.
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>),
/// Sent when the user zooms.
ZoomWindowEvent(f32),
@@ -66,6 +71,7 @@ impl Show for WindowEvent {
match *self {
IdleWindowEvent => write!(f, "Idle"),
RefreshWindowEvent => write!(f, "Refresh"),
+ InitializeCompositingWindowEvent => write!(f, "InitializeCompositing"),
ResizeWindowEvent(..) => write!(f, "Resize"),
KeyEvent(..) => write!(f, "Key"),
LoadUrlWindowEvent(..) => write!(f, "LoadUrl"),
@@ -92,6 +98,12 @@ pub trait WindowMethods {
fn set_ready_state(&self, ready_state: ReadyState);
/// Sets the paint state of the current page.
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.
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
@@ -106,5 +118,10 @@ pub trait WindowMethods {
/// magic to wake the up window's event loop.
fn create_compositor_channel(_: &Option<Rc<Self>>)
-> (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;
}
diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs
index 4635e2667d4..dad31c08976 100644
--- a/components/msg/compositor_msg.rs
+++ b/components/msg/compositor_msg.rs
@@ -19,7 +19,7 @@ pub enum PaintState {
PaintingPaintState,
}
-#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone)]
+#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone, Show)]
pub enum ReadyState {
/// Informs the compositor that nothing has been done yet. Used for setting status
Blank,
@@ -111,6 +111,8 @@ pub trait ScriptListener {
pipeline_id: PipelineId,
layer_id: LayerId,
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 dup(&mut self) -> Box<ScriptListener+'static>;
}
diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs
index 483f03803cf..9b2a654310c 100644
--- a/components/msg/constellation_msg.rs
+++ b/components/msg/constellation_msg.rs
@@ -205,6 +205,9 @@ pub enum Msg {
PainterReadyMsg(PipelineId),
ResizedWindowMsg(WindowSizeData),
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
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 4fbdaab837d..738ac6be90e 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -189,6 +189,7 @@ pub trait DocumentHelpers<'a> {
fn begin_focus_transaction(self);
fn request_focus(self, elem: JSRef<Element>);
fn commit_focus_transaction(self);
+ fn send_title_to_compositor(self);
}
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
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)]
@@ -985,3 +992,4 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
global_event_handlers!()
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange)
}
+
diff --git a/components/script/dom/htmltitleelement.rs b/components/script/dom/htmltitleelement.rs
index ef8b70aa4fa..4e6e9f7e9bb 100644
--- a/components/script/dom/htmltitleelement.rs
+++ b/components/script/dom/htmltitleelement.rs
@@ -5,15 +5,17 @@
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding;
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods;
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::utils::{Reflectable, Reflector};
-use dom::document::Document;
+use dom::document::{Document, DocumentHelpers};
use dom::element::HTMLTitleElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
use dom::text::Text;
+use dom::virtualmethods::VirtualMethods;
use servo_util::str::DOMString;
#[dom_struct]
@@ -68,3 +70,19 @@ impl Reflectable for HTMLTitleElement {
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()
+ }
+ }
+}
+
diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs
index 66378463a82..a90055bc50d 100644
--- a/components/script/dom/virtualmethods.rs
+++ b/components/script/dom/virtualmethods.rs
@@ -24,6 +24,7 @@ use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
+use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
use dom::bindings::js::JSRef;
use dom::document::Document;
use dom::element::Element;
@@ -47,6 +48,7 @@ use dom::element::HTMLStyleElementTypeId;
use dom::element::HTMLTableDataCellElementTypeId;
use dom::element::HTMLTableHeaderCellElementTypeId;
use dom::element::HTMLTextAreaElementTypeId;
+use dom::element::HTMLTitleElementTypeId;
use dom::event::Event;
use dom::htmlanchorelement::HTMLAnchorElement;
use dom::htmlareaelement::HTMLAreaElement;
@@ -67,6 +69,7 @@ use dom::htmlselectelement::HTMLSelectElement;
use dom::htmlstyleelement::HTMLStyleElement;
use dom::htmltablecellelement::HTMLTableCellElement;
use dom::htmltextareaelement::HTMLTextAreaElement;
+use dom::htmltitleelement::HTMLTitleElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
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();
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_) => {
let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap();
element as &'a VirtualMethods + 'a
diff --git a/components/script/page.rs b/components/script/page.rs
index 37f4ba155bb..c8e46463077 100644
--- a/components/script/page.rs
+++ b/components/script/page.rs
@@ -21,7 +21,6 @@ use script_traits::{UntrustedNodeAddress, ScriptControlChan};
use geom::{Point2D, Rect, Size2D};
use js::rust::Cx;
-use servo_msg::compositor_msg::PerformingLayout;
use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
use servo_msg::constellation_msg::{PipelineId, SubpageId};
@@ -266,6 +265,17 @@ impl Page {
// because it was built for infinite clip (MAX_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 {
@@ -356,7 +366,7 @@ impl Page {
pub fn reflow(&self,
goal: ReflowGoal,
script_chan: ScriptControlChan,
- compositor: &mut ScriptListener,
+ _: &mut ScriptListener,
query_type: ReflowQueryType) {
let root = match *self.frame() {
None => return,
@@ -376,9 +386,6 @@ impl Page {
// Now, join the layout so that they will see the latest changes we have made.
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.
let (join_chan, join_port) = channel();
let mut layout_join_port = self.layout_join_port.borrow_mut();
diff --git a/components/script/script_task.rs b/components/script/script_task.rs
index f41558b598c..b4fdaa6f833 100644
--- a/components/script/script_task.rs
+++ b/components/script/script_task.rs
@@ -43,10 +43,12 @@ use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, Scrip
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg};
use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel};
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::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
-use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState};
+use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg};
+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::{Released};
use servo_msg::constellation_msg;
@@ -550,6 +552,9 @@ impl ScriptTask {
FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"),
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
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(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr),
FromScript(DOMMessage(..)) => panic!("unexpected message"),
@@ -661,6 +666,11 @@ impl ScriptTask {
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.
/// Returns true if the script task should shut down and false otherwise.
fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool {
@@ -784,6 +794,7 @@ impl ScriptTask {
parse_html(*document, parser_input, &final_url);
document.set_ready_state(DocumentReadyStateValues::Interactive);
+ self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout);
// Kick off the initial reflow of the page.
debug!("kicking off initial reflow of {}", final_url);
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index dec1d090178..59a1447a75a 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -65,7 +65,10 @@ pub enum ConstellationControlMsg {
SendEventMsg(PipelineId, CompositorEvent),
/// Notifies script that reflow is finished.
ReflowCompleteMsg(PipelineId, uint),
+ /// Notifies script of the viewport.
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
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index ade8b873593..f9200ea627c 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -58,7 +58,7 @@ dependencies = [
[[package]]
name = "cocoa"
version = "0.1.1"
-source = "git+https://github.com/servo/rust-cocoa#78b823bec1affcab20b6977e1057125088a6034c"
+source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
[[package]]
name = "compile_msg"
@@ -394,7 +394,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf"
+source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 1ddfbc1dc5d..9e5d4be9467 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -153,6 +153,14 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
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) {
self.compositor.shutdown();
}
diff --git a/components/servo/main.rs b/components/servo/main.rs
index 16ef1980668..a6d7f28db73 100644
--- a/components/servo/main.rs
+++ b/components/servo/main.rs
@@ -30,7 +30,9 @@ use servo_util::rtinstrument;
#[cfg(not(any(test,target_os="android")))]
use servo::Browser;
#[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")))]
use std::os;
@@ -65,6 +67,8 @@ fn start(argc: int, argv: *const *const u8) -> int {
}
}
+ browser.browser.handle_event(InitializeCompositingWindowEvent);
+
loop {
let should_continue = match window {
None => browser.browser.handle_event(IdleWindowEvent),
diff --git a/ports/android/glut_app/Cargo.lock b/ports/android/glut_app/Cargo.lock
index dddf42fec3e..7c8b12f9acb 100644
--- a/ports/android/glut_app/Cargo.lock
+++ b/ports/android/glut_app/Cargo.lock
@@ -327,7 +327,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982"
+source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
diff --git a/ports/android/glut_app/window.rs b/ports/android/glut_app/window.rs
index a8f76ae628b..29ec9cdcd2b 100644
--- a/ports/android/glut_app/window.rs
+++ b/ports/android/glut_app/window.rs
@@ -19,8 +19,8 @@ use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
-use msg::compositor_msg::{IdlePaintState, PaintState};
-use msg::compositor_msg::{Blank, ReadyState};
+use msg::compositor_msg::{Blank, IdlePaintState, PaintState, ReadyState};
+use msg::constellation_msg::LoadData;
use util::geometry::ScreenPx;
use glut::glut::{ACTIVE_SHIFT, WindowHeight};
@@ -176,19 +176,23 @@ impl WindowMethods for Window {
/// Sets the ready state.
fn set_ready_state(&self, ready_state: ReadyState) {
self.ready_state.set(ready_state);
- //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
- //self.update_window_title()
+ // FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
+ // blocked.
+ //
+ // self.update_window_title()
}
/// Sets the paint state.
fn set_paint_state(&self, paint_state: PaintState) {
self.paint_state.set(paint_state);
- //FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
- //self.update_window_title()
+ // FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
+ // blocked.
+ //
+ // self.update_window_title()
}
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
- //FIXME: Do nothing in GLUT now.
+ // FIXME: Do nothing in GLUT now.
ScaleFactor(1.0)
}
@@ -198,6 +202,22 @@ impl WindowMethods for Window {
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 {
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index e1b04196d67..f27fc02021c 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -3,6 +3,7 @@ name = "embedding"
version = "0.0.1"
dependencies = [
"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_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
"devtools 0.0.1",
@@ -57,6 +58,11 @@ dependencies = [
]
[[package]]
+name = "cocoa"
+version = "0.1.1"
+source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
+
+[[package]]
name = "compositing"
version = "0.0.1"
dependencies = [
@@ -358,7 +364,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
[[package]]
name = "layers"
version = "0.1.0"
-source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf"
+source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982"
dependencies = [
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
diff --git a/ports/cef/Cargo.toml b/ports/cef/Cargo.toml
index bfbbda58bca..817ba629c94 100644
--- a/ports/cef/Cargo.toml
+++ b/ports/cef/Cargo.toml
@@ -65,3 +65,6 @@ git = "https://github.com/servo/rust-core-graphics"
[dependencies.core_text]
git = "https://github.com/servo/rust-core-text"
+
+[dependencies.cocoa]
+git = "https://github.com/servo/rust-cocoa"
diff --git a/ports/cef/browser.rs b/ports/cef/browser.rs
index 6bdfba87772..2bd93ac1712 100644
--- a/ports/cef/browser.rs
+++ b/ports/cef/browser.rs
@@ -2,38 +2,90 @@
* 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, CefClient, CefRequestContext, cef_browser_t, cef_client_t};
+use browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions};
+use core::{mod, OffScreenGlobals, OnScreenGlobals, globals};
+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 eutil::Downcast;
+use compositing::windowing::{Back, Forward, NavigationWindowEvent};
use glfw_app;
use libc::c_int;
-use servo::Browser;
use servo_util::opts;
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 {
+ /// 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 servo_browser: RefCell<Option<Browser<glfw_app::window::Window>>>,
- pub window: RefCell<Option<Rc<glfw_app::window::Window>>>,
+ /// Whether the on-created callback has fired yet.
pub callback_executed: Cell<bool>,
}
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 {
+ frame: frame,
+ host: host,
client: client,
- servo_browser: RefCell::new(None),
- window: RefCell::new(None),
callback_executed: Cell::new(false),
}
}
}
-cef_class_impl! {
- ServoCefBrowser : CefBrowser, cef_browser_t {}
+trait ServoCefBrowserExtensions {
+ 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>>)
@@ -50,12 +102,16 @@ pub fn browser_callback_after_created(browser: CefBrowser) {
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();
urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string());
let mut opts = opts::default_opts();
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 {
browser_callback_after_created(browser.clone());
}
@@ -73,32 +129,30 @@ fn browser_host_create(client: CefClient, callback_executed: bool) -> CefBrowser
}
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,
_url: *const cef_string_t,
_browser_settings: *const cef_browser_settings_t,
_request_context: *mut cef_request_context_t)
-> c_int {
- let _window_info: &cef_window_info_t = _window_info;
let client: CefClient = client;
let _url: &[u16] = _url;
let _browser_settings: &cef_browser_settings_t = _browser_settings;
let _request_context: CefRequestContext = _request_context;
- browser_host_create(client, false);
+ browser_host_create(window_info, client, false);
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,
_url: *const cef_string_t,
_browser_settings: *const cef_browser_settings_t,
_request_context: *mut cef_request_context_t)
-> *mut cef_browser_t {
- let _window_info: &cef_window_info_t = _window_info;
let client: CefClient = client;
let _url: &[u16] = _url;
let _browser_settings: &cef_browser_settings_t = _browser_settings;
let _request_context: CefRequestContext = _request_context;
- browser_host_create(client, true)
+ browser_host_create(window_info, client, true)
}
}
+
diff --git a/ports/cef/browser_host.rs b/ports/cef/browser_host.rs
new file mode 100644
index 00000000000..66ec82af343
--- /dev/null
+++ b/ports/cef/browser_host.rs
@@ -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)
+ }
+}
+
diff --git a/ports/cef/command_line.rs b/ports/cef/command_line.rs
index ed3578dfbcd..53655b28c79 100644
--- a/ports/cef/command_line.rs
+++ b/ports/cef/command_line.rs
@@ -46,7 +46,7 @@ pub fn command_line_init(argc: c_int, argv: *const *const u8) {
#[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 {
if cmd.is_null() || name.is_null() {
- return cef_string::empty_utf16_string()
+ return cef_string::empty_utf16_userfree_string()
}
unsafe {
//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,
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]
diff --git a/ports/cef/core.rs b/ports/cef/core.rs
index a3e6b90dd9a..8a895f76ebb 100644
--- a/ports/cef/core.rs
+++ b/ports/cef/core.rs
@@ -2,19 +2,43 @@
* 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 browser::{GLOBAL_BROWSERS, browser_callback_after_created};
use command_line::command_line_init;
use interfaces::cef_app_t;
-use eutil::Downcast;
-use switches::{KPROCESSTYPE, KWAITFORDEBUGGER};
use types::{cef_main_args_t, cef_settings_t};
+use window;
+use compositing::windowing::{IdleWindowEvent, WindowEvent};
+use geom::size::TypedSize2D;
use glfw_app;
-use libc::funcs::c95::string::strlen;
use libc::{c_char, c_int, c_void};
use native;
+use rustrt::local::Local;
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";
#[cfg(target_os="windows")]
@@ -26,68 +50,109 @@ static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e1
#[no_mangle]
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,
_windows_sandbox_info: *const c_void)
-> c_int {
if args.is_null() {
return 0;
}
+
unsafe {
+ rt::init((*args).argc as int, (*args).argv);
command_line_init((*args).argc, (*args).argv);
- (*application).get_browser_process_handler.map(|cb| {
- let handler = cb(application);
- if handler.is_not_null() {
- (*handler).on_context_initialized.map(|hcb| hcb(handler));
- }
- });
+
+ if !application.is_null() {
+ (*application).get_browser_process_handler.map(|cb| {
+ 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
}
+// 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]
pub extern "C" fn cef_shutdown() {
}
#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
- native::start(0, 0 as *const *const u8, proc() {
- GLOBAL_BROWSERS.get().map(|refcellbrowsers| {
- let browsers = refcellbrowsers.borrow();
- let mut num = browsers.len();
- for active_browser in browsers.iter() {
- *active_browser.downcast().window.borrow_mut() =
- Some(glfw_app::create_window());
- *active_browser.downcast().servo_browser.borrow_mut() =
- Some(Browser::new((*active_browser.downcast()
- .window
- .borrow()).clone()));
- if !active_browser.downcast().callback_executed.get() {
- browser_callback_after_created((*active_browser).clone());
- }
- }
- 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;
- }
- }
- }
- });
- });
+ let mut the_globals = globals.get();
+ let the_globals = the_globals.as_mut().unwrap();
+ match **the_globals {
+ OnScreenGlobals(ref window, ref browser) => {
+ while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
+ }
+ OffScreenGlobals(ref window, ref browser) => {
+ while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn cef_do_message_loop_work() {
+ send_window_event(IdleWindowEvent)
}
#[no_mangle]
@@ -95,33 +160,91 @@ pub extern "C" fn cef_quit_message_loop() {
}
#[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,
_windows_sandbox_info: *mut c_void)
-> c_int {
- unsafe {
- 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
- //handler callback, something which is impossible now in rust
- } else if s.slice_from(2) == KPROCESSTYPE.as_bytes() {
- //TODO: run other process now
- }
- }
- });
+ -1
+}
+
+pub fn send_window_event(event: WindowEvent) {
+ message_queue.get().as_mut().unwrap().borrow_mut().push(event);
+
+ 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]
@@ -134,6 +257,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]
pub extern "C" fn cef_get_min_log_level() -> c_int {
0
}
diff --git a/ports/cef/frame.rs b/ports/cef/frame.rs
new file mode 100644
index 00000000000..eb915fe9fe3
--- /dev/null
+++ b/ports/cef/frame.rs
@@ -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();
+ }
+ }
+}
+
diff --git a/ports/cef/lib.rs b/ports/cef/lib.rs
index 28e3d33509a..3b44180ec11 100644
--- a/ports/cef/lib.rs
+++ b/ports/cef/lib.rs
@@ -14,11 +14,12 @@ extern crate log;
extern crate "plugins" as servo_plugins;
extern crate servo;
+extern crate compositing;
extern crate azure;
-extern crate compositing;
extern crate geom;
extern crate gfx;
+extern crate gleam;
extern crate glfw;
extern crate glfw_app;
extern crate js;
@@ -34,10 +35,15 @@ extern crate stb_image;
extern crate green;
extern crate native;
+extern crate rustrt;
extern crate libc;
extern crate "url" as std_url;
#[cfg(target_os="macos")]
+extern crate cgl;
+#[cfg(target_os="macos")]
+extern crate cocoa;
+#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;
@@ -46,14 +52,17 @@ extern crate core_text;
pub mod macros;
pub mod browser;
+pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
+pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
+pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
@@ -67,8 +76,9 @@ pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
-pub mod values;
pub mod v8;
+pub mod values;
+pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
diff --git a/ports/cef/render_handler.rs b/ports/cef/render_handler.rs
new file mode 100644
index 00000000000..13e277c061d
--- /dev/null
+++ b/ports/cef/render_handler.rs
@@ -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)
+ }
+}
+
diff --git a/ports/cef/string.rs b/ports/cef/string.rs
index b4ead90f71d..9a817e97674 100644
--- a/ports/cef/string.rs
+++ b/ports/cef/string.rs
@@ -4,7 +4,7 @@
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 std::char;
use std::mem;
@@ -54,7 +54,7 @@ pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf
}
#[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 {
cef_string_utf16_clear(cs);
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]
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>() {
@@ -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())
+}
+
diff --git a/ports/cef/string_multimap.rs b/ports/cef/string_multimap.rs
index 88d83db9618..31974d5a95d 100644
--- a/ports/cef/string_multimap.rs
+++ b/ports/cef/string_multimap.rs
@@ -8,7 +8,8 @@ use std::collections::TreeMap;
use std::iter::AdditiveIterator;
use std::mem;
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};
fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
diff --git a/ports/cef/types.rs b/ports/cef/types.rs
index 66809dc0223..3f0d0752661 100644
--- a/ports/cef/types.rs
+++ b/ports/cef/types.rs
@@ -25,7 +25,6 @@ pub enum cef_response_t {}
pub enum cef_urlrequest_client_t {}
pub enum cef_domnode_t {}
pub enum cef_load_handler_t {}
-pub enum cef_request_context_t {}
pub enum cef_browser_settings_t {}
pub enum cef_v8context_t {}
pub enum cef_v8exception_t {}
@@ -68,7 +67,7 @@ pub type CefBrowserSettings = cef_browser_settings_t;
pub type CefScreenInfo = cef_screen_info_t;
pub type cef_string_t = cef_string_utf16; //FIXME: this is #defined...
-pub type cef_string_userfree_t = cef_string_t; //FIXME: this is #defined...
+pub type cef_string_userfree_t = *mut cef_string_t; //FIXME: this is #defined...
pub struct cef_string_utf8 {
pub str: *mut u8,
@@ -79,7 +78,7 @@ pub type cef_string_utf8_t = cef_string_utf8;
pub type cef_string_userfree_utf8_t = cef_string_utf8;
pub type cef_string_utf16_t = cef_string_utf16;
-pub type cef_string_userfree_utf16_t = cef_string_utf16;
+pub type cef_string_userfree_utf16_t = *mut cef_string_utf16;
pub struct cef_string_utf16 {
pub str: *mut c_ushort,
pub length: size_t,
@@ -102,61 +101,61 @@ pub struct cef_main_args {
pub type cef_color_t = c_uint;
-///
+//
// Existing thread IDs.
-///
+//
pub enum cef_thread_id_t {
// BROWSER PROCESS THREADS -- Only available in the browser process.
- ///
+ //
// The main thread in the browser. This will be the same as the main
// application thread if CefInitialize() is called with a
// CefSettings.multi_threaded_message_loop value of false.
- ///
+ //
TID_UI,
- ///
+ //
// Used to interact with the database.
- ///
+ //
TID_DB,
- ///
+ //
// Used to interact with the file system.
- ///
+ //
TID_FILE,
- ///
+ //
// Used for file system operations that block user interactions.
// Responsiveness of this thread affects users.
- ///
+ //
TID_FILE_USER_BLOCKING,
- ///
+ //
// Used to launch and terminate browser processes.
- ///
+ //
TID_PROCESS_LAUNCHER,
- ///
+ //
// Used to handle slow HTTP cache operations.
- ///
+ //
TID_CACHE,
- ///
+ //
// Used to process IPC and network messages.
- ///
+ //
TID_IO,
// RENDER PROCESS THREADS -- Only available in the render process.
- ///
+ //
// The main thread in the renderer. Used for all WebKit and V8 interaction.
- ///
+ //
TID_RENDERER,
}
-///
+//
// Navigation types.
-///
+//
pub enum cef_navigation_type_t {
NAVIGATION_LINK_CLICKED = 0,
NAVIGATION_FORM_SUBMITTED,
@@ -166,138 +165,138 @@ pub enum cef_navigation_type_t {
NAVIGATION_OTHER,
}
-///
+//
// Mouse button types.
-///
+//
pub enum cef_mouse_button_type_t {
MBT_LEFT = 0,
MBT_MIDDLE,
MBT_RIGHT,
}
-///
+//
// Structure representing mouse event information.
-///
+//
pub type cef_mouse_event_t = cef_mouse_event;
pub type CefMouseEvent = cef_mouse_event_t;
pub struct cef_mouse_event {
- ///
+ //
// X coordinate relative to the left side of the view.
- ///
+ //
pub x: c_int,
- ///
+ //
// Y coordinate relative to the top side of the view.
- ///
+ //
pub y: c_int,
- ///
+ //
// Bit flags describing any pressed modifier keys. See
// cef_event_flags_t for values.
- ///
+ //
pub modifiers: c_uint,
}
-///
+//
// Post data elements may represent either bytes or files.
-///
+//
pub enum cef_postdataelement_type_t {
PDE_TYPE_EMPTY = 0,
PDE_TYPE_BYTES,
PDE_TYPE_FILE,
}
-///
+//
// Flags used to customize the behavior of CefURLRequest.
-///
+//
pub enum cef_urlrequest_flags_t {
- ///
+ //
// Default behavior.
- ///
+ //
UR_FLAG_NONE = 0,
- ///
+ //
// If set the cache will be skipped when handling the request.
- ///
+ //
UR_FLAG_SKIP_CACHE = 1 << 0,
- ///
+ //
// If set user name, password, and cookies may be sent with the request.
- ///
+ //
UR_FLAG_ALLOW_CACHED_CREDENTIALS = 1 << 1,
- ///
+ //
// If set cookies may be sent with the request and saved from the response.
// UR_FLAG_ALLOW_CACHED_CREDENTIALS must also be set.
- ///
+ //
UR_FLAG_ALLOW_COOKIES = 1 << 2,
- ///
+ //
// If set upload progress events will be generated when a request has a body.
- ///
+ //
UR_FLAG_REPORT_UPLOAD_PROGRESS = 1 << 3,
- ///
+ //
// If set load timing info will be collected for the request.
- ///
+ //
UR_FLAG_REPORT_LOAD_TIMING = 1 << 4,
- ///
+ //
// If set the headers sent and received for the request will be recorded.
- ///
+ //
UR_FLAG_REPORT_RAW_HEADERS = 1 << 5,
- ///
+ //
// If set the CefURLRequestClient::OnDownloadData method will not be called.
- ///
+ //
UR_FLAG_NO_DOWNLOAD_DATA = 1 << 6,
- ///
+ //
// If set 5XX redirect errors will be propagated to the observer instead of
// automatically re-tried. This currently only applies for requests
// originated in the browser process.
- ///
+ //
UR_FLAG_NO_RETRY_ON_5XX = 1 << 7,
}
-///
+//
// Flags that represent CefURLRequest status.
-///
+//
pub enum cef_urlrequest_status_t {
- ///
+ //
// Unknown status.
- ///
+ //
UR_UNKNOWN = 0,
- ///
+ //
// Request succeeded.
- ///
+ //
UR_SUCCESS,
- ///
+ //
// An IO request is pending, and the caller will be informed when it is
// completed.
- ///
+ //
UR_IO_PENDING,
- ///
+ //
// Request was canceled programatically.
- ///
+ //
UR_CANCELED,
- ///
+ //
// Request failed for some reason.
- ///
+ //
UR_FAILED,
}
-///
+//
// Supported error code values. See net\base\net_error_list.h for complete
// descriptions of the error codes.
-///
+//
pub enum cef_errorcode_t {
ERR_NONE = 0,
ERR_FAILED = -2,
@@ -351,9 +350,9 @@ pub enum cef_errorcode_t {
}
-///
+//
// Key event types.
-///
+//
pub enum cef_key_event_type_t {
KEYEVENT_RAWKEYDOWN = 0,
KEYEVENT_KEYDOWN,
@@ -361,74 +360,74 @@ pub enum cef_key_event_type_t {
KEYEVENT_CHAR
}
-///
+//
// Structure representing keyboard event information.
-///
+//
pub type cef_key_event_t = cef_key_event;
pub struct cef_key_event {
- ///
+ //
// The type of keyboard event.
- ///
+ //
pub t: cef_key_event_type_t,
- ///
+ //
// Bit flags describing any pressed modifier keys. See
// cef_event_flags_t for values.
- ///
+ //
pub modifiers: c_uint,
- ///
+ //
// The Windows key code for the key event. This value is used by the DOM
// specification. Sometimes it comes directly from the event (i.e. on
// Windows) and sometimes it's determined using a mapping function. See
// WebCore/platform/chromium/KeyboardCodes.h for the list of values.
- ///
+ //
pub windows_key_code: c_int,
- ///
+ //
// The actual key code genenerated by the platform.
- ///
+ //
pub native_key_code: c_int,
- ///
+ //
// Indicates whether the event is considered a "system key" event (see
// http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx for details).
// This value will always be false on non-Windows platforms.
- ///
+ //
pub is_system_key: c_int,
- ///
+ //
// The character generated by the keystroke.
- ///
+ //
pub character: c_ushort, //FIXME: can be wchar_t also?
- ///
+ //
// Same as |character| but unmodified by any concurrently-held modifiers
// (except shift). This is useful for working out shortcut keys.
- ///
+ //
pub unmodified_character: c_ushort, //FIXME: can be wchar_t also?
- ///
+ //
// True if the focus is currently on an editable field on the page. This is
// useful for determining if standard key events should be intercepted.
- ///
+ //
pub focus_on_editable_field: c_int,
}
pub type CefKeyEvent = cef_key_event_t;
-///
+//
// Structure representing a point.
-///
+//
pub type cef_point_t = cef_point;
pub struct cef_point {
pub x: c_int,
pub y: c_int,
}
-///
+//
// Structure representing a rectangle.
-///
+//
pub struct cef_rect {
pub x: c_int,
pub y: c_int,
@@ -447,17 +446,17 @@ impl cef_rect {
}
}
-///
+//
// Paint element types.
-///
+//
pub enum cef_paint_element_type_t {
PET_VIEW = 0,
PET_POPUP,
}
-///
+//
// DOM document types.
-///
+//
pub enum cef_dom_document_type_t {
DOM_DOCUMENT_TYPE_UNKNOWN = 0,
DOM_DOCUMENT_TYPE_HTML,
@@ -465,30 +464,30 @@ pub enum cef_dom_document_type_t {
DOM_DOCUMENT_TYPE_PLUGIN,
}
-///
+//
// Supported file dialog modes.
-///
+//
pub enum cef_file_dialog_mode_t {
- ///
+ //
// Requires that the file exists before allowing the user to pick it.
- ///
+ //
FILE_DIALOG_OPEN = 0,
- ///
+ //
// Like Open, but allows picking multiple files to open.
- ///
+ //
FILE_DIALOG_OPEN_MULTIPLE,
- ///
+ //
// Allows picking a nonexistent file, and prompts to overwrite if the file
// already exists.
- ///
+ //
FILE_DIALOG_SAVE,
}
-///
+//
// Supported value types.
-///
+//
pub enum cef_value_type_t {
VTYPE_INVALID = 0,
VTYPE_NULL,
@@ -503,229 +502,233 @@ pub enum cef_value_type_t {
pub type CefValueType = cef_value_type_t;
-///
+//
// Existing process IDs.
-///
+//
pub enum cef_process_id_t {
- ///
+ //
// Browser process.
- ///
+ //
PID_BROWSER,
- ///
+ //
// Renderer process.
- ///
+ //
PID_RENDERER,
}
pub type CefProcessId = cef_process_id_t;
-///
+//
// Log severity levels.
-///
+//
pub enum cef_log_severity_t {
- ///
+ //
// Default logging (currently INFO logging).
- ///
+ //
LOGSEVERITY_DEFAULT,
- ///
+ //
// Verbose logging.
- ///
+ //
LOGSEVERITY_VERBOSE,
- ///
+ //
// INFO logging.
- ///
+ //
LOGSEVERITY_INFO,
- ///
+ //
// WARNING logging.
- ///
+ //
LOGSEVERITY_WARNING,
- ///
+ //
// ERROR logging.
- ///
+ //
LOGSEVERITY_ERROR,
- ///
+ //
// ERROR_REPORT logging.
- ///
+ //
LOGSEVERITY_ERROR_REPORT,
- ///
+ //
// Completely disable logging.
- ///
+ //
LOGSEVERITY_DISABLE = 99
}
-///
+//
// Initialization settings. Specify NULL or 0 to get the recommended default
// values. Many of these and other settings can also configured using command-
// line switches.
-///
+//
pub type cef_settings_t = cef_settings;
+
+#[repr(C)]
pub struct cef_settings {
- ///
+ //
// Size of this structure.
- ///
+ //
pub size: size_t,
- ///
+ //
// Set to true (1) to use a single process for the browser and renderer. This
// run mode is not officially supported by Chromium and is less stable than
// the multi-process default. Also configurable using the "single-process"
// command-line switch.
- ///
+ //
pub single_process: c_int,
- ///
+ //
// Set to true (1) to disable the sandbox for sub-processes. See
// cef_sandbox_win.h for requirements to enable the sandbox on Windows. Also
// configurable using the "no-sandbox" command-line switch.
- ///
+ //
pub no_sandbox: c_int,
- ///
+ //
// The path to a separate executable that will be launched for sub-processes.
// By default the browser process executable is used. See the comments on
// CefExecuteProcess() for details. Also configurable using the
// "browser-subprocess-path" command-line switch.
- ///
+ //
pub browser_subprocess_path: cef_string_t,
- ///
+ //
// Set to true (1) to have the browser process message loop run in a separate
// thread. If false (0) than the CefDoMessageLoopWork() function must be
// called from your application message loop.
- ///
+ //
pub multi_threaded_message_loop: c_int,
- ///
+
+ //
+ // Set to true (1) to enable windowless (off-screen) rendering support. Do not
+ // enable this value if the application does not use windowless rendering as
+ // it may reduce rendering performance on some systems.
+ //
+ pub windowless_rendering_enabled: c_int,
+
+ //
// Set to true (1) to disable configuration of browser process features using
// standard CEF and Chromium command-line arguments. Configuration can still
// be specified using CEF data structures or via the
// CefApp::OnBeforeCommandLineProcessing() method.
- ///
+ //
pub command_line_args_disabled: c_int,
- ///
+ //
// The location where cache data will be stored on disk. If empty an in-memory
// cache will be used for some features and a temporary disk cache for others.
// HTML5 databases such as localStorage will only persist across sessions if a
// cache path is specified.
- ///
+ //
pub cache_path: cef_string_t,
- ///
+ //
// To persist session cookies (cookies without an expiry date or validity
// interval) by default when using the global cookie manager set this value to
// true. Session cookies are generally intended to be transient and most Web
// browsers do not persist them. A |cache_path| value must also be specified to
// enable this feature. Also configurable using the "persist-session-cookies"
// command-line switch.
- ///
+ //
pub persist_session_cookies: c_int,
- ///
+ //
// Value that will be returned as the User-Agent HTTP header. If empty the
// default User-Agent string will be used. Also configurable using the
// "user-agent" command-line switch.
- ///
+ //
pub user_agent: cef_string_t,
- ///
+ //
// Value that will be inserted as the product portion of the default
// User-Agent string. If empty the Chromium product version will be used. If
// |userAgent| is specified this value will be ignored. Also configurable
// using the "product-version" command-line switch.
- ///
+ //
pub product_version: cef_string_t,
- ///
+ //
// The locale string that will be passed to WebKit. If empty the default
// locale of "en-US" will be used. This value is ignored on Linux where locale
// is determined using environment variable parsing with the precedence order:
// LANGUAGE, LC_ALL, LC_MESSAGES and LANG. Also configurable using the "lang"
// command-line switch.
- ///
+ //
pub locale: cef_string_t,
- ///
+ //
// The directory and file name to use for the debug log. If empty, the
// default name of "debug.log" will be used and the file will be written
// to the application directory. Also configurable using the "log-file"
// command-line switch.
- ///
+ //
pub log_file: cef_string_t,
- ///
+ //
// The log severity. Only messages of this severity level or higher will be
// logged. Also configurable using the "log-severity" command-line switch with
// a value of "verbose", "info", "warning", "error", "error-report" or
// "disable".
- ///
+ //
pub log_severity: cef_log_severity_t,
- ///
- // Enable DCHECK in release mode to ease debugging. Also configurable using the
- // "enable-release-dcheck" command-line switch.
- ///
- pub release_dcheck_enabled: c_int,
-
- ///
+ //
// Custom flags that will be used when initializing the V8 JavaScript engine.
// The consequences of using custom flags may not be well tested. Also
// configurable using the "js-flags" command-line switch.
- ///
+ //
pub javascript_flags: cef_string_t,
- ///
+ //
// The fully qualified path for the resources directory. If this value is
// empty the cef.pak and/or devtools_resources.pak files must be located in
// the module directory on Windows/Linux or the app bundle Resources directory
// on Mac OS X. Also configurable using the "resources-dir-path" command-line
// switch.
- ///
+ //
pub resources_dir_path: cef_string_t,
- ///
+ //
// The fully qualified path for the locales directory. If this value is empty
// the locales directory must be located in the module directory. This value
// is ignored on Mac OS X where pack files are always loaded from the app
// bundle Resources directory. Also configurable using the "locales-dir-path"
// command-line switch.
- ///
+ //
pub locales_dir_path: cef_string_t,
- ///
+ //
// Set to true (1) to disable loading of pack files for resources and locales.
// A resource bundle handler must be provided for the browser and render
// processes via CefApp::GetResourceBundleHandler() if loading of pack files
// is disabled. Also configurable using the "disable-pack-loading" command-
// line switch.
- ///
+ //
pub pack_loading_disabled: c_int,
- ///
+ //
// Set to a value between 1024 and 65535 to enable remote debugging on the
// specified port. For example, if 8080 is specified the remote debugging URL
// will be http://localhost:8080. CEF can be remotely debugged from any CEF or
// Chrome browser window. Also configurable using the "remote-debugging-port"
// command-line switch.
- ///
+ //
pub remote_debugging_port: c_int,
- ///
+ //
// The number of stack trace frames to capture for uncaught exceptions.
// Specify a positive value to enable the CefV8ContextHandler::
// OnUncaughtException() callback. Specify 0 (default value) and
// OnUncaughtException() will not be called. Also configurable using the
// "uncaught-exception-stack-size" command-line switch.
- ///
+ //
pub uncaught_exception_stack_size: c_int,
- ///
+ //
// By default CEF V8 references will be invalidated (the IsValid() method will
// return false) after the owning context has been released. This reduces the
// need for external record keeping and avoids crashes due to the use of V8
@@ -744,73 +747,124 @@ pub struct cef_settings {
//
// Also configurable using the "context-safety-implementation" command-line
// switch.
- ///
+ //
pub context_safety_implementation: c_int,
- ///
+ //
// Set to true (1) to ignore errors related to invalid SSL certificates.
// Enabling this setting can lead to potential security vulnerabilities like
// "man in the middle" attacks. Applications that load content from the
// internet should not enable this setting. Also configurable using the
// "ignore-certificate-errors" command-line switch.
- ///
+ //
pub ignore_certificate_errors: c_int,
- ///
+ //
// Opaque background color used for accelerated content. By default the
// background color will be white. Only the RGB compontents of the specified
// value will be used. The alpha component must greater than 0 to enable use
// of the background color but will be otherwise ignored.
- ///
+ //
pub background_color: cef_color_t,
+
+ //
+ // Determines how many rendering threads are used.
+ //
+ pub rendering_threads: c_int,
}
-///
+//
// Structure defining the reference count implementation functions. All
// framework structures must include the cef_base_t structure first.
-///
+//
pub type cef_base_t = cef_base;
pub struct cef_base {
- ///
+ //
// Size of the data structure.
- ///
+ //
pub size: size_t,
- ///
+ //
// Increment the reference count.
- ///
+ //
pub add_ref: Option<extern "C" fn(base: *mut cef_base) -> c_int>,
- ///
+ //
// Decrement the reference count. Delete this object when no references
// remain.
- ///
+ //
pub release: Option<extern "C" fn(base: *mut cef_base) -> c_int>,
- ///
+ //
// Returns the current number of references.
- ///
+ //
pub get_refct: Option<extern "C" fn(base: *mut cef_base) -> c_int>,
}
pub type CefBase = *mut cef_base_t;
-///
+//
// Class representing window information.
-///
+//
pub type cef_window_info_t = cef_window_info;
+
+#[cfg(target_os="linux")]
+pub struct cef_window_info {
+ pub x: c_uint,
+ pub y: c_uint,
+ pub width: c_uint,
+ pub height: c_uint,
+
+ //
+ // Pointer for the parent window.
+ //
+ pub parent_window: cef_window_handle_t,
+
+ //
+ // Set to true (1) to create the browser using windowless (off-screen)
+ // rendering. No window will be created for the browser and all rendering will
+ // occur via the CefRenderHandler interface. The |parent_window| value will be
+ // used to identify monitor info and to act as the parent window for dialogs,
+ // context menus, etc. If |parent_window| is not provided then the main screen
+ // monitor will be used and some functionality that requires a parent window
+ // may not function correctly. In order to create windowless browsers the
+ // CefSettings.windowless_rendering_enabled value must be set to true.
+ //
+ pub windowless_rendering_enabled: c_int,
+
+ //
+ // Set to true (1) to enable transparent painting in combination with
+ // windowless rendering. When this value is true a transparent background
+ // color will be used (RGBA=0x00000000). When this value is false the
+ // background will be white and opaque.
+ //
+ pub transparent_painting_enabled: c_int,
+
+ //
+ // Pointer for the new browser window. Only used with windowed rendering.
+ //
+ pub window: cef_window_handle_t
+}
+
+#[cfg(target_os="macos")]
pub struct cef_window_info {
+ pub window_name: cef_string_t,
pub x: c_uint,
pub y: c_uint,
pub width: c_uint,
pub height: c_uint,
- ///
+ //
+ // Set to true (1) to create the view initially hidden.
+ //
+ pub hidden: c_int,
+
+ //
// Pointer for the parent window.
- ///
+ //
pub parent_window: cef_window_handle_t,
- ///
+ //
// Set to true (1) to create the browser using windowless (off-screen)
// rendering. No window will be created for the browser and all rendering will
// occur via the CefRenderHandler interface. The |parent_window| value will be
@@ -819,28 +873,28 @@ pub struct cef_window_info {
// monitor will be used and some functionality that requires a parent window
// may not function correctly. In order to create windowless browsers the
// CefSettings.windowless_rendering_enabled value must be set to true.
- ///
+ //
pub windowless_rendering_enabled: c_int,
- ///
+ //
// Set to true (1) to enable transparent painting in combination with
// windowless rendering. When this value is true a transparent background
// color will be used (RGBA=0x00000000). When this value is false the
// background will be white and opaque.
- ///
+ //
pub transparent_painting_enabled: c_int,
- ///
+ //
// Pointer for the new browser window. Only used with windowed rendering.
- ///
+ //
pub window: cef_window_handle_t
}
pub type CefWindowInfo = cef_window_info_t;
-///
+//
// Supported menu item types.
-///
+//
pub enum cef_menu_item_type_t {
MENUITEMTYPE_NONE,
MENUITEMTYPE_COMMAND,
@@ -850,73 +904,73 @@ pub enum cef_menu_item_type_t {
MENUITEMTYPE_SUBMENU,
}
-///
+//
// Supported context menu type flags.
-///
+//
pub enum cef_context_menu_type_flags_t {
- ///
+ //
// No node is selected.
- ///
+ //
CM_TYPEFLAG_NONE = 0,
- ///
+ //
// The top page is selected.
- ///
+ //
CM_TYPEFLAG_PAGE = 1 << 0,
- ///
+ //
// A subframe page is selected.
- ///
+ //
CM_TYPEFLAG_FRAME = 1 << 1,
- ///
+ //
// A link is selected.
- ///
+ //
CM_TYPEFLAG_LINK = 1 << 2,
- ///
+ //
// A media node is selected.
- ///
+ //
CM_TYPEFLAG_MEDIA = 1 << 3,
- ///
+ //
// There is a textual or mixed selection that is selected.
- ///
+ //
CM_TYPEFLAG_SELECTION = 1 << 4,
- ///
+ //
// An editable element is selected.
- ///
+ //
CM_TYPEFLAG_EDITABLE = 1 << 5,
}
-///
+//
// Supported context menu media types.
-///
+//
pub enum cef_context_menu_media_type_t {
- ///
+ //
// No special node is in context.
- ///
+ //
CM_MEDIATYPE_NONE,
- ///
+ //
// An image node is selected.
- ///
+ //
CM_MEDIATYPE_IMAGE,
- ///
+ //
// A video node is selected.
- ///
+ //
CM_MEDIATYPE_VIDEO,
- ///
+ //
// An audio node is selected.
- ///
+ //
CM_MEDIATYPE_AUDIO,
- ///
+ //
// A file node is selected.
- ///
+ //
CM_MEDIATYPE_FILE,
- ///
+ //
// A plugin node is selected.
- ///
+ //
CM_MEDIATYPE_PLUGIN,
}
-///
+//
// Supported context menu media state bit flags.
-///
+//
pub enum cef_context_menu_media_state_flags_t {
CM_MEDIAFLAG_NONE = 0,
CM_MEDIAFLAG_ERROR = 1 << 0,
@@ -931,9 +985,9 @@ pub enum cef_context_menu_media_state_flags_t {
CM_MEDIAFLAG_CAN_ROTATE = 1 << 9,
}
-///
+//
// Supported context menu edit state bit flags.
-///
+//
pub enum cef_context_menu_edit_state_flags_t {
CM_EDITFLAG_NONE = 0,
CM_EDITFLAG_CAN_UNDO = 1 << 0,
@@ -946,9 +1000,9 @@ pub enum cef_context_menu_edit_state_flags_t {
CM_EDITFLAG_CAN_TRANSLATE = 1 << 7,
}
-///
+//
// Supported event bit flags.
-///
+//
pub enum cef_event_flags_t {
EVENTFLAG_NONE = 0,
EVENTFLAG_CAPS_LOCK_ON = 1 << 0,
@@ -966,9 +1020,9 @@ pub enum cef_event_flags_t {
EVENTFLAG_IS_RIGHT = 1 << 11,
}
-///
+//
// Time information. Values should always be in UTC.
-///
+//
#[repr(C)]
pub struct _cef_time_t {
year: c_int, // Four digit year "2007"
@@ -984,9 +1038,9 @@ pub struct _cef_time_t {
pub type cef_time_t = _cef_time_t;
-///
+//
// DOM event processing phases.
-///
+//
pub enum cef_dom_event_phase_t {
DOM_EVENT_PHASE_UNKNOWN = 0,
DOM_EVENT_PHASE_CAPTURING,
@@ -994,9 +1048,9 @@ pub enum cef_dom_event_phase_t {
DOM_EVENT_PHASE_BUBBLING,
}
-///
+//
// DOM node types.
-///
+//
pub enum cef_dom_node_type_t {
DOM_NODE_TYPE_UNSUPPORTED = 0,
DOM_NODE_TYPE_ELEMENT,
@@ -1010,32 +1064,32 @@ pub enum cef_dom_node_type_t {
DOM_NODE_TYPE_DOCUMENT_FRAGMENT,
}
-///
+//
// Focus sources.
-///
+//
pub enum cef_focus_source_t {
- ///
+ //
// The source is explicit navigation via the API (LoadURL(), etc).
- ///
+ //
FOCUS_SOURCE_NAVIGATION = 0,
- ///
+ //
// The source is a system-generated focus event.
- ///
+ //
FOCUS_SOURCE_SYSTEM,
}
-///
+//
// Supported JavaScript dialog types.
-///
+//
pub enum cef_jsdialog_type_t {
JSDIALOGTYPE_ALERT = 0,
JSDIALOGTYPE_CONFIRM,
JSDIALOGTYPE_PROMPT,
}
-///
+//
// Structure representing a size.
-///
+//
pub struct _cef_size_t {
pub width: c_int,
pub height: c_int,
@@ -1043,9 +1097,9 @@ pub struct _cef_size_t {
pub type cef_size_t = _cef_size_t;
-///
+//
// Structure representing a print job page range.
-///
+//
pub struct _cef_page_range_t {
pub from: c_int,
pub to: c_int,
@@ -1053,9 +1107,9 @@ pub struct _cef_page_range_t {
pub type cef_page_range_t = _cef_page_range_t;
-///
+//
// Print job duplex mode values.
-///
+//
pub enum cef_duplex_mode_t {
DUPLEX_MODE_UNKNOWN = -1,
DUPLEX_MODE_SIMPLEX,
@@ -1063,9 +1117,9 @@ pub enum cef_duplex_mode_t {
DUPLEX_MODE_SHORT_EDGE,
}
-///
+//
// Print job color mode values.
-///
+//
pub enum cef_color_model_t {
COLOR_MODEL_UNKNOWN,
COLOR_MODEL_GRAY,
@@ -1090,216 +1144,216 @@ pub enum cef_color_model_t {
COLOR_MODEL_PROCESSCOLORMODEL_RGB, // Used in canon printer ppds
}
-///
+//
// Resource type for a request.
-///
+//
pub enum cef_resource_type_t {
- ///
+ //
// Top level page.
- ///
+ //
RT_MAIN_FRAME = 0,
- ///
+ //
// Frame or iframe.
- ///
+ //
RT_SUB_FRAME,
- ///
+ //
// CSS stylesheet.
- ///
+ //
RT_STYLESHEET,
- ///
+ //
// External script.
- ///
+ //
RT_SCRIPT,
- ///
+ //
// Image (jpg/gif/png/etc).
- ///
+ //
RT_IMAGE,
- ///
+ //
// Font.
- ///
+ //
RT_FONT_RESOURCE,
- ///
+ //
// Some other subresource. This is the default type if the actual type is
// unknown.
- ///
+ //
RT_SUB_RESOURCE,
- ///
+ //
// Object (or embed) tag for a plugin, or a resource that a plugin requested.
- ///
+ //
RT_OBJECT,
- ///
+ //
// Media resource.
- ///
+ //
RT_MEDIA,
- ///
+ //
// Main resource of a dedicated worker.
- ///
+ //
RT_WORKER,
- ///
+ //
// Main resource of a shared worker.
- ///
+ //
RT_SHARED_WORKER,
- ///
+ //
// Explicitly requested prefetch.
- ///
+ //
RT_PREFETCH,
- ///
+ //
// Favicon.
- ///
+ //
RT_FAVICON,
- ///
+ //
// XMLHttpRequest.
- ///
+ //
RT_XHR,
- ///
+ //
// A request for a <ping>
- ///
+ //
RT_PING,
- ///
+ //
// Main resource of a service worker.
- ///
+ //
RT_SERVICE_WORKER,
}
-///
+//
// Transition type for a request. Made up of one source value and 0 or more
// qualifiers.
-///
+//
pub enum cef_transition_type_t {
- ///
+ //
// Source is a link click or the JavaScript window.open function. This is
// also the default value for requests like sub-resource loads that are not
// navigations.
- ///
+ //
TT_LINK = 0,
- ///
+ //
// Source is some other "explicit" navigation action such as creating a new
// browser or using the LoadURL function. This is also the default value
// for navigations where the actual type is unknown.
- ///
+ //
TT_EXPLICIT = 1,
- ///
+ //
// Source is a subframe navigation. This is any content that is automatically
// loaded in a non-toplevel frame. For example, if a page consists of several
// frames containing ads, those ad URLs will have this transition type.
// The user may not even realize the content in these pages is a separate
// frame, so may not care about the URL.
- ///
+ //
TT_AUTO_SUBFRAME = 3,
- ///
+ //
// Source is a subframe navigation explicitly requested by the user that will
// generate new navigation entries in the back/forward list. These are
// probably more important than frames that were automatically loaded in
// the background because the user probably cares about the fact that this
// link was loaded.
- ///
+ //
TT_MANUAL_SUBFRAME = 4,
- ///
+ //
// Source is a form submission by the user. NOTE: In some situations
// submitting a form does not result in this transition type. This can happen
// if the form uses a script to submit the contents.
- ///
+ //
TT_FORM_SUBMIT = 7,
- ///
+ //
// Source is a "reload" of the page via the Reload function or by re-visiting
// the same URL. NOTE: This is distinct from the concept of whether a
// particular load uses "reload semantics" (i.e. bypasses cached data).
- ///
+ //
TT_RELOAD = 8,
- ///
+ //
// General mask defining the bits used for the source values.
- ///
+ //
TT_SOURCE_MASK = 0xFF,
// Qualifiers.
// Any of the core values above can be augmented by one or more qualifiers.
// These qualifiers further define the transition.
- ///
+ //
// Attempted to visit a URL but was blocked.
- ///
+ //
TT_BLOCKED_FLAG = 0x00800000,
- ///
+ //
// Used the Forward or Back function to navigate among browsing history.
- ///
+ //
TT_FORWARD_BACK_FLAG = 0x01000000,
- ///
+ //
// The beginning of a navigation chain.
- ///
+ //
TT_CHAIN_START_FLAG = 0x10000000,
- ///
+ //
// The last transition in a redirect chain.
- ///
+ //
TT_CHAIN_END_FLAG = 0x20000000,
- ///
+ //
// Redirects caused by JavaScript or a meta refresh tag on the page.
- ///
+ //
TT_CLIENT_REDIRECT_FLAG = 0x40000000,
- ///
+ //
// Redirects sent from the server by HTTP headers.
- ///
+ //
TT_SERVER_REDIRECT_FLAG = 0x80000000,
- ///
+ //
// Used to test whether a transition involves a redirect.
- ///
+ //
TT_IS_REDIRECT_MASK = 0xC0000000,
- ///
+ //
// General mask defining the bits used for the qualifiers.
- ///
+ //
TT_QUALIFIER_MASK = 0xFFFFFF00,
}
-///
+//
// Process termination status values.
-///
+//
pub enum cef_termination_status_t {
- ///
+ //
// Non-zero exit status.
- ///
+ //
TS_ABNORMAL_TERMINATION,
- ///
+ //
// SIGKILL or task manager kill.
- ///
+ //
TS_PROCESS_WAS_KILLED,
- ///
+ //
// Segmentation fault.
- ///
+ //
TS_PROCESS_CRASHED,
}
-///
+//
// V8 access control values.
-///
+//
pub enum cef_v8_accesscontrol_t {
V8_ACCESS_CONTROL_DEFAULT = 0,
V8_ACCESS_CONTROL_ALL_CAN_READ = 1,
@@ -1307,9 +1361,9 @@ pub enum cef_v8_accesscontrol_t {
V8_ACCESS_CONTROL_PROHIBITS_OVERWRITING = 1 << 2
}
-///
+//
// V8 property attribute values.
-///
+//
pub enum cef_v8_propertyattribute_t {
V8_PROPERTY_ATTRIBUTE_NONE = 0, // Writeable, Enumerable,
// Configurable
@@ -1318,9 +1372,9 @@ pub enum cef_v8_propertyattribute_t {
V8_PROPERTY_ATTRIBUTE_DONTDELETE = 1 << 2 // Not configurable
}
-///
+//
// XML node types.
-///
+//
pub enum cef_xml_node_type_t {
XML_NODE_UNSUPPORTED = 0,
XML_NODE_PROCESSING_INSTRUCTION,
@@ -1335,9 +1389,9 @@ pub enum cef_xml_node_type_t {
XML_NODE_COMMENT,
}
-///
+//
// Geoposition error codes.
-///
+//
pub enum cef_geoposition_error_code_t {
GEOPOSITON_ERROR_NONE = 0,
GEOPOSITON_ERROR_PERMISSION_DENIED,
@@ -1345,61 +1399,61 @@ pub enum cef_geoposition_error_code_t {
GEOPOSITON_ERROR_TIMEOUT,
}
-///
+//
// Structure representing geoposition information. The properties of this
// structure correspond to those of the JavaScript Position object although
// their types may differ.
-///
+//
pub struct _cef_geoposition_t {
- ///
+ //
// Latitude in decimal degrees north (WGS84 coordinate frame).
- ///
+ //
pub latitude: c_double,
- ///
+ //
// Longitude in decimal degrees west (WGS84 coordinate frame).
- ///
+ //
pub longitude: c_double,
- ///
+ //
// Altitude in meters (above WGS84 datum).
- ///
+ //
pub altitude: c_double,
- ///
+ //
// Accuracy of horizontal position in meters.
- ///
+ //
pub accuracy: c_double,
- ///
+ //
// Accuracy of altitude in meters.
- ///
+ //
pub altitude_accuracy: c_double,
- ///
+ //
// Heading in decimal degrees clockwise from true north.
- ///
+ //
pub heading: c_double,
- ///
+ //
// Horizontal component of device velocity in meters per second.
- ///
+ //
pub speed: c_double,
- ///
+ //
// Time of position measurement in miliseconds since Epoch in UTC time. This
// is taken from the host computer's system clock.
- ///
+ //
pub timestamp: cef_time_t,
- ///
+ //
// Error code, see enum above.
- ///
+ //
pub error_code: cef_geoposition_error_code_t,
- ///
+ //
// Human-readable error message.
- ///
+ //
pub error_message: cef_string_t,
}
@@ -1407,58 +1461,58 @@ pub type cef_geoposition_t = _cef_geoposition_t;
pub type CefGeoposition = cef_geoposition_t;
-///
+//
// Cookie information.
-///
+//
pub struct _cef_cookie_t {
- ///
+ //
// The cookie name.
- ///
+ //
pub name: cef_string_t,
- ///
+ //
// The cookie value.
- ///
+ //
pub value: cef_string_t,
- ///
+ //
// If |domain| is empty a host cookie will be created instead of a domain
// cookie. Domain cookies are stored with a leading "." and are visible to
// sub-domains whereas host cookies are not.
- ///
+ //
pub domain: cef_string_t,
- ///
+ //
// If |path| is non-empty only URLs at or below the path will get the cookie
// value.
- ///
+ //
pub path: cef_string_t,
- ///
+ //
// If |secure| is true the cookie will only be sent for HTTPS requests.
- ///
+ //
pub secure: c_int,
- ///
+ //
// If |httponly| is true the cookie will only be sent for HTTP requests.
- ///
+ //
pub httponly: c_int,
- ///
+ //
// The cookie creation date. This is automatically populated by the system on
// cookie creation.
- ///
+ //
pub creation: cef_time_t,
- ///
+ //
// The cookie last access date. This is automatically populated by the system
// on access.
- ///
+ //
pub last_access: cef_time_t,
- ///
+ //
// The cookie expiration date is only valid if |has_expires| is true.
- ///
+ //
pub has_expires: c_int,
pub expires: cef_time_t,
}
@@ -1467,9 +1521,9 @@ pub type cef_cookie_t = _cef_cookie_t;
pub type CefCookie = cef_cookie_t;
-///
+//
// Popup window features.
-///
+//
pub struct _cef_popup_features_t {
pub x: c_int,
pub x_set: c_int,
diff --git a/ports/cef/window.rs b/ports/cef/window.rs
new file mode 100644
index 00000000000..2e3ec5c34a1
--- /dev/null
+++ b/ports/cef/window.rs
@@ -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>
+ }
+}
+
diff --git a/ports/cef/wrappers.rs b/ports/cef/wrappers.rs
index ae871595743..8c650dad1dd 100644
--- a/ports/cef/wrappers.rs
+++ b/ports/cef/wrappers.rs
@@ -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_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_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_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_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};
@@ -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_keyboard_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_string_list_t)
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] {
fn to_c(buffer: &'a [u16]) -> *const cef_string_t {
unsafe {
- let ptr: *mut c_ushort =
- mem::transmute(libc::calloc(1, ((buffer.len() * 2) + 1) as u64));
- ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), (buffer.len() * 2) as uint);
+ let ptr: *mut c_ushort = mem::transmute(libc::malloc(((buffer.len() + 1) * 2) as u64));
+ ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), buffer.len());
*ptr.offset(buffer.len() as int) = 0;
// 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 {
fn to_c(_: &'a mut String) -> cef_string_t {
panic!("unimplemented CEF type conversion: &'a mut String")
diff --git a/ports/glfw/window.rs b/ports/glfw/window.rs
index 422ea221c02..d391b274f03 100644
--- a/ports/glfw/window.rs
+++ b/ports/glfw/window.rs
@@ -23,9 +23,9 @@ use gleam::gl;
use layers::geometry::DevicePixel;
use layers::platform::surface::NativeGraphicsMetadata;
use libc::c_int;
-use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
-use msg::compositor_msg::{IdlePaintState, PaintState, PaintingPaintState};
-use msg::constellation_msg;
+use msg::compositor_msg::{Blank, FinishedLoading, IdlePaintState, Loading, PaintState};
+use msg::compositor_msg::{PaintingPaintState, PerformingLayout, ReadyState};
+use msg::constellation_msg::{mod, LoadData};
use std::cell::{Cell, RefCell};
use std::comm::Receiver;
use std::rc::Rc;
@@ -97,6 +97,15 @@ impl Window {
}
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();
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) {
self.handle_window_event(&self.glfw_window, event);
}
@@ -196,6 +205,16 @@ impl WindowMethods for Window {
} as Box<CompositorProxy+Send>,
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 {
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py
index e3e41ca38e2..cade77fbbd7 100644
--- a/python/servo/build_commands.py
+++ b/python/servo/build_commands.py
@@ -113,7 +113,7 @@ class MachCommands(CommandBase):
build_start = time()
with cd(path.join("ports", "cef")):
- ret = subprocess.call(["cargo", "build"],
+ ret = subprocess.call(["cargo", "build"] + opts,
env=self.build_env())
elapsed = time() - build_start