mirror of
https://github.com/servo/servo.git
synced 2025-06-21 15:49:04 +01:00
ports/cef: Implement accelerated compositing for the CEF port.
This commit is contained in:
parent
315e166cf7
commit
8b2aadc30b
35 changed files with 1746 additions and 642 deletions
|
@ -3,23 +3,23 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents};
|
use compositor_layer::{CompositorData, CompositorLayer, DoesntWantScrollEvents};
|
||||||
use compositor_layer::WantsScrollEvents;
|
use compositor_layer::{WantsScrollEvents};
|
||||||
use compositor_task::{ChangeReadyState, ChangePaintState, CompositorEventListener};
|
use compositor_task::{ChangePageLoadData, ChangePageTitle, ChangePaintState, ChangeReadyState};
|
||||||
use compositor_task::{CompositorProxy, CompositorReceiver, CompositorTask};
|
use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver};
|
||||||
use compositor_task::{CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer, Exit};
|
use compositor_task::{CompositorTask, CreateOrUpdateDescendantLayer, CreateOrUpdateRootLayer};
|
||||||
use compositor_task::{FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties};
|
use compositor_task::{Exit, FrameTreeUpdateMsg, GetGraphicsMetadata, LayerProperties};
|
||||||
use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint};
|
use compositor_task::{LoadComplete, Msg, Paint, PaintMsgDiscarded, ScrollFragmentPoint};
|
||||||
use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete};
|
use compositor_task::{ScrollTimeout, SetIds, SetLayerOrigin, ShutdownComplete};
|
||||||
use constellation::{SendableFrameTree, FrameTreeDiff};
|
use constellation::{FrameId, FrameTreeDiff, SendableFrameTree};
|
||||||
use pipeline::CompositionPipeline;
|
use pipeline::CompositionPipeline;
|
||||||
use scrolling::ScrollingTimerProxy;
|
use scrolling::ScrollingTimerProxy;
|
||||||
use windowing;
|
use windowing;
|
||||||
use windowing::{IdleWindowEvent, LoadUrlWindowEvent, MouseWindowClickEvent};
|
use windowing::{IdleWindowEvent, InitializeCompositingWindowEvent};
|
||||||
use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEvent};
|
use windowing::{KeyEvent, LoadUrlWindowEvent, MouseWindowClickEvent, MouseWindowEvent};
|
||||||
use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent};
|
use windowing::{MouseWindowEventClass, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||||
|
use windowing::{MouseWindowMoveEventClass, NavigationWindowEvent, PinchZoomWindowEvent};
|
||||||
use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent};
|
use windowing::{QuitWindowEvent, RefreshWindowEvent, ResizeWindowEvent, ScrollWindowEvent};
|
||||||
use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
|
use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
|
||||||
use windowing::{PinchZoomWindowEvent, KeyEvent};
|
|
||||||
|
|
||||||
use azure::azure_hl;
|
use azure::azure_hl;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -40,11 +40,11 @@ use gleam::gl::types::{GLint, GLsizei};
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use script_traits::{ViewportMsg, ScriptControlChan};
|
use script_traits::{ViewportMsg, ScriptControlChan};
|
||||||
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId};
|
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdlePaintState, LayerId};
|
||||||
use servo_msg::compositor_msg::{ReadyState, PaintingPaintState, PaintState, Scrollable};
|
use servo_msg::compositor_msg::{ReadyState, PaintState, PaintingPaintState, Scrollable};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{mod, ConstellationChan, ExitMsg};
|
||||||
use servo_msg::constellation_msg::{NavigateMsg, LoadData, PipelineId, ResizedWindowMsg};
|
use servo_msg::constellation_msg::{GetPipelineTitleMsg, Key, KeyModifiers, KeyState, LoadData};
|
||||||
use servo_msg::constellation_msg::{WindowSizeData, KeyState, Key, KeyModifiers};
|
use servo_msg::constellation_msg::{LoadUrlMsg, NavigateMsg, PipelineId, ResizedWindowMsg};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg::{WindowSizeData};
|
||||||
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
|
use servo_util::geometry::{PagePx, ScreenPx, ViewportPx};
|
||||||
use servo_util::memory::MemoryProfilerChan;
|
use servo_util::memory::MemoryProfilerChan;
|
||||||
use servo_util::opts;
|
use servo_util::opts;
|
||||||
|
@ -58,6 +58,7 @@ use std::slice::bytes::copy_memory;
|
||||||
use time::{precise_time_ns, precise_time_s};
|
use time::{precise_time_ns, precise_time_s};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
|
||||||
pub struct IOCompositor<Window: WindowMethods> {
|
pub struct IOCompositor<Window: WindowMethods> {
|
||||||
/// The application window.
|
/// The application window.
|
||||||
window: Rc<Window>,
|
window: Rc<Window>,
|
||||||
|
@ -65,8 +66,9 @@ pub struct IOCompositor<Window: WindowMethods> {
|
||||||
/// The port on which we receive messages.
|
/// The port on which we receive messages.
|
||||||
port: Box<CompositorReceiver>,
|
port: Box<CompositorReceiver>,
|
||||||
|
|
||||||
/// The render context.
|
/// The render context. This will be `None` if the windowing system has not yet sent us a
|
||||||
context: RenderContext,
|
/// `PrepareRenderingEvent`.
|
||||||
|
context: Option<RenderContext>,
|
||||||
|
|
||||||
/// The root pipeline.
|
/// The root pipeline.
|
||||||
root_pipeline: Option<CompositionPipeline>,
|
root_pipeline: Option<CompositionPipeline>,
|
||||||
|
@ -177,13 +179,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
// display list. This is only here because we don't have that logic in the painter yet.
|
// display list. This is only here because we don't have that logic in the painter yet.
|
||||||
let window_size = window.framebuffer_size();
|
let window_size = window.framebuffer_size();
|
||||||
let hidpi_factor = window.hidpi_factor();
|
let hidpi_factor = window.hidpi_factor();
|
||||||
let context = CompositorTask::create_graphics_context(&window.native_metadata());
|
|
||||||
|
|
||||||
let show_debug_borders = opts::get().show_debug_borders;
|
|
||||||
IOCompositor {
|
IOCompositor {
|
||||||
window: window,
|
window: window,
|
||||||
port: receiver,
|
port: receiver,
|
||||||
context: rendergl::RenderContext::new(context, show_debug_borders),
|
context: None,
|
||||||
root_pipeline: None,
|
root_pipeline: None,
|
||||||
scene: Scene::new(Rect {
|
scene: Scene::new(Rect {
|
||||||
origin: Zero::zero(),
|
origin: Zero::zero(),
|
||||||
|
@ -262,6 +261,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.change_paint_state(pipeline_id, paint_state);
|
self.change_paint_state(pipeline_id, paint_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(ChangePageTitle(pipeline_id, title), NotShuttingDown) => {
|
||||||
|
self.change_page_title(pipeline_id, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
(ChangePageLoadData(frame_id, load_data), NotShuttingDown) => {
|
||||||
|
self.change_page_load_data(frame_id, load_data);
|
||||||
|
}
|
||||||
|
|
||||||
(PaintMsgDiscarded, NotShuttingDown) => {
|
(PaintMsgDiscarded, NotShuttingDown) => {
|
||||||
self.remove_outstanding_paint_msg();
|
self.remove_outstanding_paint_msg();
|
||||||
}
|
}
|
||||||
|
@ -305,13 +312,18 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.scroll_fragment_to_point(pipeline_id, layer_id, point);
|
self.scroll_fragment_to_point(pipeline_id, layer_id, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
(LoadComplete(..), NotShuttingDown) => {
|
(LoadComplete, NotShuttingDown) => {
|
||||||
self.got_load_complete_message = true;
|
self.got_load_complete_message = true;
|
||||||
|
|
||||||
// If we're painting in headless mode, schedule a recomposite.
|
// If we're painting in headless mode, schedule a recomposite.
|
||||||
if opts::get().output_file.is_some() {
|
if opts::get().output_file.is_some() {
|
||||||
self.composite_if_necessary();
|
self.composite_if_necessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inform the embedder that the load has finished.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Specify which frame's load completed.
|
||||||
|
self.window.load_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
(ScrollTimeout(timestamp), NotShuttingDown) => {
|
(ScrollTimeout(timestamp), NotShuttingDown) => {
|
||||||
|
@ -371,6 +383,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.window.set_paint_state(paint_state);
|
self.window.set_paint_state(paint_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn change_page_title(&mut self, _: PipelineId, title: Option<String>) {
|
||||||
|
self.window.set_page_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_page_load_data(&mut self, _: FrameId, load_data: LoadData) {
|
||||||
|
self.window.set_page_load_data(load_data);
|
||||||
|
}
|
||||||
|
|
||||||
fn all_pipelines_in_idle_paint_state(&self) -> bool {
|
fn all_pipelines_in_idle_paint_state(&self) -> bool {
|
||||||
if self.ready_states.len() == 0 {
|
if self.ready_states.len() == 0 {
|
||||||
return false;
|
return false;
|
||||||
|
@ -629,7 +649,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
IdleWindowEvent => {}
|
IdleWindowEvent => {}
|
||||||
|
|
||||||
RefreshWindowEvent => {
|
RefreshWindowEvent => {
|
||||||
self.composite_if_necessary()
|
self.composite();
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeCompositingWindowEvent => {
|
||||||
|
self.initialize_compositing();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResizeWindowEvent(size) => {
|
ResizeWindowEvent(size) => {
|
||||||
|
@ -678,6 +702,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_resize_window_event(&mut self, new_size: TypedSize2D<DevicePixel, uint>) {
|
fn on_resize_window_event(&mut self, new_size: TypedSize2D<DevicePixel, uint>) {
|
||||||
|
debug!("compositor resizing to {}", new_size.to_untyped());
|
||||||
|
|
||||||
// A size change could also mean a resolution change.
|
// A size change could also mean a resolution change.
|
||||||
let new_hidpi_factor = self.window.hidpi_factor();
|
let new_hidpi_factor = self.window.hidpi_factor();
|
||||||
if self.hidpi_factor != new_hidpi_factor {
|
if self.hidpi_factor != new_hidpi_factor {
|
||||||
|
@ -960,6 +986,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn composite(&mut self) {
|
fn composite(&mut self) {
|
||||||
|
if !self.window.prepare_for_composite() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let output_image = opts::get().output_file.is_some() &&
|
let output_image = opts::get().output_file.is_some() &&
|
||||||
self.is_ready_to_paint_image_output();
|
self.is_ready_to_paint_image_output();
|
||||||
|
|
||||||
|
@ -995,7 +1025,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
// paint the scene.
|
// paint the scene.
|
||||||
match self.scene.root {
|
match self.scene.root {
|
||||||
Some(ref layer) => {
|
Some(ref layer) => {
|
||||||
rendergl::render_scene(layer.clone(), self.context, &self.scene);
|
match self.context {
|
||||||
|
None => {
|
||||||
|
debug!("compositor: not compositing because context not yet set up")
|
||||||
|
}
|
||||||
|
Some(context) => {
|
||||||
|
rendergl::render_scene(layer.clone(), context, &self.scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
@ -1053,6 +1090,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initialize_compositing(&mut self) {
|
||||||
|
let context = CompositorTask::create_graphics_context(&self.window.native_metadata());
|
||||||
|
let show_debug_borders = opts::get().show_debug_borders;
|
||||||
|
self.context = Some(rendergl::RenderContext::new(context, show_debug_borders))
|
||||||
|
}
|
||||||
|
|
||||||
fn find_topmost_layer_at_point_for_layer(&self,
|
fn find_topmost_layer_at_point_for_layer(&self,
|
||||||
layer: Rc<Layer<CompositorData>>,
|
layer: Rc<Layer<CompositorData>>,
|
||||||
point: TypedPoint2D<LayerPixel, f32>)
|
point: TypedPoint2D<LayerPixel, f32>)
|
||||||
|
@ -1229,4 +1272,17 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
|
||||||
|
|
||||||
self.scrolling_timer.shutdown();
|
self.scrolling_timer.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pinch_zoom_level(&self) -> f32 {
|
||||||
|
self.viewport_zoom.get() as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_title_for_main_frame(&self) {
|
||||||
|
let root_pipeline_id = match self.root_pipeline {
|
||||||
|
None => return,
|
||||||
|
Some(ref root_pipeline) => root_pipeline.id,
|
||||||
|
};
|
||||||
|
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||||
|
chan.send(GetPipelineTitleMsg(root_pipeline_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! Communication with the compositor task.
|
//! Communication with the compositor task.
|
||||||
|
|
||||||
pub use windowing;
|
pub use windowing;
|
||||||
pub use constellation::{SendableFrameTree, FrameTreeDiff};
|
pub use constellation::{FrameId, SendableFrameTree, FrameTreeDiff};
|
||||||
|
|
||||||
use compositor;
|
use compositor;
|
||||||
use headless;
|
use headless;
|
||||||
|
@ -19,7 +19,7 @@ use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphics
|
||||||
use layers::layers::LayerBufferSet;
|
use layers::layers::LayerBufferSet;
|
||||||
use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
|
use servo_msg::compositor_msg::{Epoch, LayerId, LayerMetadata, ReadyState};
|
||||||
use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy};
|
use servo_msg::compositor_msg::{PaintListener, PaintState, ScriptListener, ScrollPolicy};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadData, PipelineId};
|
||||||
use servo_util::memory::MemoryProfilerChan;
|
use servo_util::memory::MemoryProfilerChan;
|
||||||
use servo_util::time::TimeProfilerChan;
|
use servo_util::time::TimeProfilerChan;
|
||||||
use std::comm::{channel, Sender, Receiver};
|
use std::comm::{channel, Sender, Receiver};
|
||||||
|
@ -81,8 +81,13 @@ impl ScriptListener for Box<CompositorProxy+'static+Send> {
|
||||||
fn dup(&mut self) -> Box<ScriptListener+'static> {
|
fn dup(&mut self) -> Box<ScriptListener+'static> {
|
||||||
box self.clone_compositor_proxy() as Box<ScriptListener+'static>
|
box self.clone_compositor_proxy() as Box<ScriptListener+'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_title(&mut self, pipeline_id: PipelineId, title: Option<String>) {
|
||||||
|
self.send(ChangePageTitle(pipeline_id, title))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about each layer that the compositor keeps.
|
||||||
pub struct LayerProperties {
|
pub struct LayerProperties {
|
||||||
pub pipeline_id: PipelineId,
|
pub pipeline_id: PipelineId,
|
||||||
pub epoch: Epoch,
|
pub epoch: Epoch,
|
||||||
|
@ -184,9 +189,13 @@ pub enum Msg {
|
||||||
ChangeReadyState(PipelineId, ReadyState),
|
ChangeReadyState(PipelineId, ReadyState),
|
||||||
/// Alerts the compositor to the current status of painting.
|
/// Alerts the compositor to the current status of painting.
|
||||||
ChangePaintState(PipelineId, PaintState),
|
ChangePaintState(PipelineId, PaintState),
|
||||||
/// Alerts the compositor that the PaintMsg has been discarded.
|
/// Alerts the compositor that the current page has changed its title.
|
||||||
|
ChangePageTitle(PipelineId, Option<String>),
|
||||||
|
/// Alerts the compositor that the current page has changed its load data (including URL).
|
||||||
|
ChangePageLoadData(FrameId, LoadData),
|
||||||
|
/// Alerts the compositor that a `PaintMsg` has been discarded.
|
||||||
PaintMsgDiscarded,
|
PaintMsgDiscarded,
|
||||||
/// Sets the channel to the current layout and paint tasks, along with their id
|
/// Sets the channel to the current layout and paint tasks, along with their ID.
|
||||||
SetIds(SendableFrameTree, Sender<()>, ConstellationChan),
|
SetIds(SendableFrameTree, Sender<()>, ConstellationChan),
|
||||||
/// Sends an updated version of the frame tree.
|
/// Sends an updated version of the frame tree.
|
||||||
FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>),
|
FrameTreeUpdateMsg(FrameTreeDiff, Sender<()>),
|
||||||
|
@ -210,6 +219,8 @@ impl Show for Msg {
|
||||||
Paint(..) => write!(f, "Paint"),
|
Paint(..) => write!(f, "Paint"),
|
||||||
ChangeReadyState(..) => write!(f, "ChangeReadyState"),
|
ChangeReadyState(..) => write!(f, "ChangeReadyState"),
|
||||||
ChangePaintState(..) => write!(f, "ChangePaintState"),
|
ChangePaintState(..) => write!(f, "ChangePaintState"),
|
||||||
|
ChangePageTitle(..) => write!(f, "ChangePageTitle"),
|
||||||
|
ChangePageLoadData(..) => write!(f, "ChangePageLoadData"),
|
||||||
PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"),
|
PaintMsgDiscarded(..) => write!(f, "PaintMsgDiscarded"),
|
||||||
SetIds(..) => write!(f, "SetIds"),
|
SetIds(..) => write!(f, "SetIds"),
|
||||||
FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"),
|
FrameTreeUpdateMsg(..) => write!(f, "FrameTreeUpdateMsg"),
|
||||||
|
@ -269,5 +280,8 @@ pub trait CompositorEventListener {
|
||||||
fn handle_event(&mut self, event: WindowEvent) -> bool;
|
fn handle_event(&mut self, event: WindowEvent) -> bool;
|
||||||
fn repaint_synchronously(&mut self);
|
fn repaint_synchronously(&mut self);
|
||||||
fn shutdown(&mut self);
|
fn shutdown(&mut self);
|
||||||
|
fn pinch_zoom_level(&self) -> f32;
|
||||||
|
/// Requests that the compositor send the title for the main frame as soon as possible.
|
||||||
|
fn get_title_for_main_frame(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
|
|
||||||
use pipeline::{Pipeline, CompositionPipeline};
|
use pipeline::{Pipeline, CompositionPipeline};
|
||||||
|
|
||||||
use compositor_task::{CompositorProxy, FrameTreeUpdateMsg, LoadComplete, ShutdownComplete, SetLayerOrigin, SetIds};
|
use compositor_task::{ChangePageLoadData, ChangePageTitle, CompositorProxy, FrameTreeUpdateMsg};
|
||||||
|
use compositor_task::{LoadComplete, SetLayerOrigin, SetIds, ShutdownComplete};
|
||||||
use devtools_traits;
|
use devtools_traits;
|
||||||
use devtools_traits::DevtoolsControlChan;
|
use devtools_traits::DevtoolsControlChan;
|
||||||
use geom::rect::{Rect, TypedRect};
|
use geom::rect::{Rect, TypedRect};
|
||||||
|
@ -14,16 +15,16 @@ use gfx::paint_task;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg};
|
use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg};
|
||||||
use libc;
|
use libc;
|
||||||
use script_traits;
|
use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
|
||||||
use script_traits::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg};
|
|
||||||
use script_traits::{ScriptControlChan, ScriptTaskFactory};
|
use script_traits::{ScriptControlChan, ScriptTaskFactory};
|
||||||
use servo_msg::compositor_msg::LayerId;
|
use servo_msg::compositor_msg::LayerId;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg};
|
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg};
|
||||||
|
use servo_msg::constellation_msg::{GetPipelineTitleMsg};
|
||||||
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
|
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
|
||||||
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadUrlMsg, LoadData, Msg, NavigateMsg};
|
use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers, LoadCompleteMsg};
|
||||||
use servo_msg::constellation_msg::{NavigationType, PipelineId, PainterReadyMsg, ResizedWindowMsg};
|
use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, Msg, NavigateMsg, NavigationType};
|
||||||
|
use servo_msg::constellation_msg::{PainterReadyMsg, PipelineId, ResizedWindowMsg};
|
||||||
use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData};
|
use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SubpageId, WindowSizeData};
|
||||||
use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers};
|
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
|
@ -76,6 +77,10 @@ pub struct Constellation<LTF, STF> {
|
||||||
/// The next free ID to assign to a pipeline.
|
/// The next free ID to assign to a pipeline.
|
||||||
next_pipeline_id: PipelineId,
|
next_pipeline_id: PipelineId,
|
||||||
|
|
||||||
|
/// The next free ID to assign to a frame.
|
||||||
|
next_frame_id: FrameId,
|
||||||
|
|
||||||
|
/// Navigation operations that are in progress.
|
||||||
pending_frames: Vec<FrameChange>,
|
pending_frames: Vec<FrameChange>,
|
||||||
|
|
||||||
pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
|
pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
|
||||||
|
@ -86,17 +91,28 @@ pub struct Constellation<LTF, STF> {
|
||||||
pub window_size: WindowSizeData,
|
pub window_size: WindowSizeData,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the Id of the outermost frame's pipeline, along with a vector of children frames
|
/// A unique ID used to identify a frame.
|
||||||
|
pub struct FrameId(u32);
|
||||||
|
|
||||||
|
/// One frame in the hierarchy.
|
||||||
struct FrameTree {
|
struct FrameTree {
|
||||||
|
/// The ID of this frame.
|
||||||
|
pub id: FrameId,
|
||||||
|
/// The pipeline for this frame.
|
||||||
pub pipeline: Rc<Pipeline>,
|
pub pipeline: Rc<Pipeline>,
|
||||||
|
/// The parent frame's pipeline.
|
||||||
pub parent: RefCell<Option<Rc<Pipeline>>>,
|
pub parent: RefCell<Option<Rc<Pipeline>>>,
|
||||||
|
/// A vector of child frames.
|
||||||
pub children: RefCell<Vec<ChildFrameTree>>,
|
pub children: RefCell<Vec<ChildFrameTree>>,
|
||||||
|
/// Whether this frame has a compositor layer.
|
||||||
pub has_compositor_layer: Cell<bool>,
|
pub has_compositor_layer: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameTree {
|
impl FrameTree {
|
||||||
fn new(pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>) -> FrameTree {
|
fn new(id: FrameId, pipeline: Rc<Pipeline>, parent_pipeline: Option<Rc<Pipeline>>)
|
||||||
|
-> FrameTree {
|
||||||
FrameTree {
|
FrameTree {
|
||||||
|
id: id,
|
||||||
pipeline: pipeline,
|
pipeline: pipeline,
|
||||||
parent: RefCell::new(parent_pipeline),
|
parent: RefCell::new(parent_pipeline),
|
||||||
children: RefCell::new(vec!()),
|
children: RefCell::new(vec!()),
|
||||||
|
@ -234,16 +250,19 @@ impl Iterator<Rc<FrameTree>> for FrameTreeIterator {
|
||||||
|
|
||||||
/// Represents the portion of a page that is changing in navigating.
|
/// Represents the portion of a page that is changing in navigating.
|
||||||
struct FrameChange {
|
struct FrameChange {
|
||||||
|
/// The old pipeline ID.
|
||||||
pub before: Option<PipelineId>,
|
pub before: Option<PipelineId>,
|
||||||
|
/// The resulting frame tree after navigation.
|
||||||
pub after: Rc<FrameTree>,
|
pub after: Rc<FrameTree>,
|
||||||
|
/// The kind of navigation that is occurring.
|
||||||
pub navigation_type: NavigationType,
|
pub navigation_type: NavigationType,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the Id's of the pipelines previous and next in the browser's history
|
/// Stores the Id's of the pipelines previous and next in the browser's history
|
||||||
struct NavigationContext {
|
struct NavigationContext {
|
||||||
pub previous: Vec<Rc<FrameTree>>,
|
previous: Vec<Rc<FrameTree>>,
|
||||||
pub next: Vec<Rc<FrameTree>>,
|
next: Vec<Rc<FrameTree>>,
|
||||||
pub current: Option<Rc<FrameTree>>,
|
current: Option<Rc<FrameTree>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavigationContext {
|
impl NavigationContext {
|
||||||
|
@ -258,29 +277,30 @@ impl NavigationContext {
|
||||||
/* Note that the following two methods can fail. They should only be called *
|
/* Note that the following two methods can fail. They should only be called *
|
||||||
* when it is known that there exists either a previous page or a next page. */
|
* when it is known that there exists either a previous page or a next page. */
|
||||||
|
|
||||||
fn back(&mut self) -> Rc<FrameTree> {
|
fn back(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
|
||||||
self.next.push(self.current.take().unwrap());
|
self.next.push(self.current.take().unwrap());
|
||||||
let prev = self.previous.pop().unwrap();
|
let prev = self.previous.pop().unwrap();
|
||||||
self.current = Some(prev.clone());
|
self.set_current(prev.clone(), compositor_proxy);
|
||||||
prev
|
prev
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forward(&mut self) -> Rc<FrameTree> {
|
fn forward(&mut self, compositor_proxy: &mut CompositorProxy) -> Rc<FrameTree> {
|
||||||
self.previous.push(self.current.take().unwrap());
|
self.previous.push(self.current.take().unwrap());
|
||||||
let next = self.next.pop().unwrap();
|
let next = self.next.pop().unwrap();
|
||||||
self.current = Some(next.clone());
|
self.set_current(next.clone(), compositor_proxy);
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a new set of page frames, returning all evicted frame trees
|
/// Loads a new set of page frames, returning all evicted frame trees
|
||||||
fn load(&mut self, frame_tree: Rc<FrameTree>) -> Vec<Rc<FrameTree>> {
|
fn load(&mut self, frame_tree: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy)
|
||||||
|
-> Vec<Rc<FrameTree>> {
|
||||||
debug!("navigating to {}", frame_tree.pipeline.id);
|
debug!("navigating to {}", frame_tree.pipeline.id);
|
||||||
let evicted = replace(&mut self.next, vec!());
|
let evicted = replace(&mut self.next, vec!());
|
||||||
match self.current.take() {
|
match self.current.take() {
|
||||||
Some(current) => self.previous.push(current),
|
Some(current) => self.previous.push(current),
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
self.current = Some(frame_tree);
|
self.set_current(frame_tree, compositor_proxy);
|
||||||
evicted
|
evicted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,6 +328,14 @@ impl NavigationContext {
|
||||||
frame_tree.contains(pipeline_id)
|
frame_tree.contains(pipeline_id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Always use this method to set the currently-displayed frame. It correctly informs the
|
||||||
|
/// compositor of the new URLs.
|
||||||
|
fn set_current(&mut self, new_frame: Rc<FrameTree>, compositor_proxy: &mut CompositorProxy) {
|
||||||
|
self.current = Some(new_frame.clone());
|
||||||
|
compositor_proxy.send(ChangePageLoadData(new_frame.id,
|
||||||
|
new_frame.pipeline.load_data.clone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
|
@ -334,6 +362,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
pipelines: HashMap::new(),
|
pipelines: HashMap::new(),
|
||||||
navigation_context: NavigationContext::new(),
|
navigation_context: NavigationContext::new(),
|
||||||
next_pipeline_id: PipelineId(0),
|
next_pipeline_id: PipelineId(0),
|
||||||
|
next_frame_id: FrameId(0),
|
||||||
pending_frames: vec!(),
|
pending_frames: vec!(),
|
||||||
pending_sizes: HashMap::new(),
|
pending_sizes: HashMap::new(),
|
||||||
time_profiler_chan: time_profiler_chan,
|
time_profiler_chan: time_profiler_chan,
|
||||||
|
@ -358,31 +387,30 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function for creating a pipeline
|
/// Helper function for creating a pipeline
|
||||||
fn new_pipeline(&self,
|
fn new_pipeline(&mut self,
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
subpage_id: Option<SubpageId>,
|
subpage_id: Option<SubpageId>,
|
||||||
script_pipeline: Option<Rc<Pipeline>>,
|
script_pipeline: Option<Rc<Pipeline>>,
|
||||||
load_data: LoadData)
|
load_data: LoadData)
|
||||||
-> Rc<Pipeline> {
|
-> Rc<Pipeline> {
|
||||||
let pipe = Pipeline::create::<LTF, STF>(id,
|
let pipe = Pipeline::create::<LTF, STF>(id,
|
||||||
subpage_id,
|
subpage_id,
|
||||||
self.chan.clone(),
|
self.chan.clone(),
|
||||||
self.compositor_proxy.clone_compositor_proxy(),
|
self.compositor_proxy.clone_compositor_proxy(),
|
||||||
self.devtools_chan.clone(),
|
self.devtools_chan.clone(),
|
||||||
self.image_cache_task.clone(),
|
self.image_cache_task.clone(),
|
||||||
self.font_cache_task.clone(),
|
self.font_cache_task.clone(),
|
||||||
self.resource_task.clone(),
|
self.resource_task.clone(),
|
||||||
self.storage_task.clone(),
|
self.storage_task.clone(),
|
||||||
self.time_profiler_chan.clone(),
|
self.time_profiler_chan.clone(),
|
||||||
self.window_size,
|
self.window_size,
|
||||||
script_pipeline,
|
script_pipeline,
|
||||||
load_data);
|
load_data.clone());
|
||||||
pipe.load();
|
pipe.load();
|
||||||
Rc::new(pipe)
|
Rc::new(pipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function for getting a unique pipeline ID.
|
||||||
/// Helper function for getting a unique pipeline Id
|
|
||||||
fn get_next_pipeline_id(&mut self) -> PipelineId {
|
fn get_next_pipeline_id(&mut self) -> PipelineId {
|
||||||
let id = self.next_pipeline_id;
|
let id = self.next_pipeline_id;
|
||||||
let PipelineId(ref mut i) = self.next_pipeline_id;
|
let PipelineId(ref mut i) = self.next_pipeline_id;
|
||||||
|
@ -390,6 +418,14 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function for getting a unique frame ID.
|
||||||
|
fn get_next_frame_id(&mut self) -> FrameId {
|
||||||
|
let id = self.next_frame_id;
|
||||||
|
let FrameId(ref mut i) = self.next_frame_id;
|
||||||
|
*i += 1;
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
/// Convenience function for getting the currently active frame tree.
|
/// Convenience function for getting the currently active frame tree.
|
||||||
/// The currently active frame tree should always be the current painter
|
/// The currently active frame tree should always be the current painter
|
||||||
fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> {
|
fn current_frame<'a>(&'a self) -> &'a Option<Rc<FrameTree>> {
|
||||||
|
@ -465,6 +501,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
debug!("constellation got key event message");
|
debug!("constellation got key event message");
|
||||||
self.handle_key_msg(key, state, modifiers);
|
self.handle_key_msg(key, state, modifiers);
|
||||||
}
|
}
|
||||||
|
GetPipelineTitleMsg(pipeline_id) => {
|
||||||
|
debug!("constellation got get-pipeline-title message");
|
||||||
|
self.handle_get_pipeline_title_msg(pipeline_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -529,27 +569,38 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
debug!("creating replacement pipeline for about:failure");
|
debug!("creating replacement pipeline for about:failure");
|
||||||
|
|
||||||
let new_id = self.get_next_pipeline_id();
|
let new_id = self.get_next_pipeline_id();
|
||||||
|
let new_frame_id = self.get_next_frame_id();
|
||||||
let pipeline = self.new_pipeline(new_id, subpage_id, None,
|
let pipeline = self.new_pipeline(new_id, subpage_id, None,
|
||||||
LoadData::new(Url::parse("about:failure").unwrap()));
|
LoadData::new(Url::parse("about:failure").unwrap()));
|
||||||
|
|
||||||
self.pending_frames.push(FrameChange{
|
self.browse(Some(pipeline_id),
|
||||||
before: Some(pipeline_id),
|
Rc::new(FrameTree::new(new_frame_id, pipeline.clone(), None)),
|
||||||
after: Rc::new(FrameTree::new(pipeline.clone(), None)),
|
constellation_msg::Load);
|
||||||
navigation_type: constellation_msg::Load,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.pipelines.insert(new_id, pipeline);
|
self.pipelines.insert(new_id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs navigation. This pushes a `FrameChange` object onto the list of pending frames.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Send a `BeforeBrowse` message to the embedder and allow cancellation.
|
||||||
|
fn browse(&mut self,
|
||||||
|
before: Option<PipelineId>,
|
||||||
|
after: Rc<FrameTree>,
|
||||||
|
navigation_type: NavigationType) {
|
||||||
|
self.pending_frames.push(FrameChange {
|
||||||
|
before: before,
|
||||||
|
after: after,
|
||||||
|
navigation_type: navigation_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_init_load(&mut self, url: Url) {
|
fn handle_init_load(&mut self, url: Url) {
|
||||||
let next_pipeline_id = self.get_next_pipeline_id();
|
let next_pipeline_id = self.get_next_pipeline_id();
|
||||||
|
let next_frame_id = self.get_next_frame_id();
|
||||||
let pipeline = self.new_pipeline(next_pipeline_id, None, None, LoadData::new(url));
|
let pipeline = self.new_pipeline(next_pipeline_id, None, None, LoadData::new(url));
|
||||||
|
self.browse(None,
|
||||||
self.pending_frames.push(FrameChange {
|
Rc::new(FrameTree::new(next_frame_id, pipeline.clone(), None)),
|
||||||
before: None,
|
constellation_msg::Load);
|
||||||
after: Rc::new(FrameTree::new(pipeline.clone(), None)),
|
|
||||||
navigation_type: constellation_msg::Load,
|
|
||||||
});
|
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,15 +741,19 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
|
|
||||||
let rect = self.pending_sizes.remove(&(source_pipeline_id, subpage_id));
|
let rect = self.pending_sizes.remove(&(source_pipeline_id, subpage_id));
|
||||||
for frame_tree in frame_trees.iter() {
|
for frame_tree in frame_trees.iter() {
|
||||||
|
let next_frame_id = self.get_next_frame_id();
|
||||||
frame_tree.children.borrow_mut().push(ChildFrameTree::new(
|
frame_tree.children.borrow_mut().push(ChildFrameTree::new(
|
||||||
Rc::new(FrameTree::new(pipeline.clone(), Some(source_pipeline.clone()))),
|
Rc::new(FrameTree::new(next_frame_id,
|
||||||
|
pipeline.clone(),
|
||||||
|
Some(source_pipeline.clone()))),
|
||||||
rect));
|
rect));
|
||||||
}
|
}
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) {
|
fn handle_load_url_msg(&mut self, source_id: PipelineId, load_data: LoadData) {
|
||||||
debug!("Constellation: received message to load {:s}", load_data.url.to_string());
|
let url = load_data.url.to_string();
|
||||||
|
debug!("Constellation: received message to load {:s}", url);
|
||||||
// Make sure no pending page would be overridden.
|
// Make sure no pending page would be overridden.
|
||||||
let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect(
|
let source_frame = self.current_frame().as_ref().unwrap().find(source_id).expect(
|
||||||
"Constellation: received a LoadUrlMsg from a pipeline_id associated
|
"Constellation: received a LoadUrlMsg from a pipeline_id associated
|
||||||
|
@ -723,14 +778,13 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
let parent = source_frame.parent.clone();
|
let parent = source_frame.parent.clone();
|
||||||
let subpage_id = source_frame.pipeline.subpage_id;
|
let subpage_id = source_frame.pipeline.subpage_id;
|
||||||
let next_pipeline_id = self.get_next_pipeline_id();
|
let next_pipeline_id = self.get_next_pipeline_id();
|
||||||
|
let next_frame_id = self.get_next_frame_id();
|
||||||
let pipeline = self.new_pipeline(next_pipeline_id, subpage_id, None, load_data);
|
let pipeline = self.new_pipeline(next_pipeline_id, subpage_id, None, load_data);
|
||||||
|
self.browse(Some(source_id),
|
||||||
self.pending_frames.push(FrameChange {
|
Rc::new(FrameTree::new(next_frame_id,
|
||||||
before: Some(source_id),
|
pipeline.clone(),
|
||||||
after: Rc::new(FrameTree::new(pipeline.clone(), parent.borrow().clone())),
|
parent.borrow().clone())),
|
||||||
navigation_type: constellation_msg::Load,
|
constellation_msg::Load);
|
||||||
});
|
|
||||||
self.pipelines.insert(pipeline.id, pipeline);
|
self.pipelines.insert(pipeline.id, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +806,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
frame.pipeline.revoke_paint_permission();
|
frame.pipeline.revoke_paint_permission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.navigation_context.forward()
|
self.navigation_context.forward(&mut *self.compositor_proxy)
|
||||||
}
|
}
|
||||||
constellation_msg::Back => {
|
constellation_msg::Back => {
|
||||||
if self.navigation_context.previous.is_empty() {
|
if self.navigation_context.previous.is_empty() {
|
||||||
|
@ -764,7 +818,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
frame.pipeline.revoke_paint_permission();
|
frame.pipeline.revoke_paint_permission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.navigation_context.back()
|
self.navigation_context.back(&mut *self.compositor_proxy)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -787,6 +841,16 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) {
|
||||||
|
match self.pipelines.get(&pipeline_id) {
|
||||||
|
None => self.compositor_proxy.send(ChangePageTitle(pipeline_id, None)),
|
||||||
|
Some(pipeline) => {
|
||||||
|
let ScriptControlChan(ref script_channel) = pipeline.script_chan;
|
||||||
|
script_channel.send(GetTitleMsg(pipeline_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_painter_ready_msg(&mut self, pipeline_id: PipelineId) {
|
fn handle_painter_ready_msg(&mut self, pipeline_id: PipelineId) {
|
||||||
debug!("Painter {} ready to send paint msg", pipeline_id);
|
debug!("Painter {} ready to send paint msg", pipeline_id);
|
||||||
// This message could originate from a pipeline in the navigation context or
|
// This message could originate from a pipeline in the navigation context or
|
||||||
|
@ -941,7 +1005,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
||||||
match navigation_type {
|
match navigation_type {
|
||||||
constellation_msg::Load => {
|
constellation_msg::Load => {
|
||||||
debug!("evicting old frames due to load");
|
debug!("evicting old frames due to load");
|
||||||
let evicted = self.navigation_context.load(frame_tree);
|
let evicted = self.navigation_context.load(frame_tree,
|
||||||
|
&mut *self.compositor_proxy);
|
||||||
self.handle_evicted_frames(evicted);
|
self.handle_evicted_frames(evicted);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
|
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
|
||||||
use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds};
|
use compositor_task::{Exit, ChangeReadyState, LoadComplete, Paint, ScrollFragmentPoint, SetIds};
|
||||||
use compositor_task::{SetLayerOrigin, ShutdownComplete, ChangePaintState, PaintMsgDiscarded};
|
use compositor_task::{SetLayerOrigin, ShutdownComplete, ChangePaintState, PaintMsgDiscarded};
|
||||||
use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, FrameTreeUpdateMsg};
|
use compositor_task::{CompositorEventListener, CompositorReceiver, ScrollTimeout, ChangePageTitle};
|
||||||
|
use compositor_task::{ChangePageLoadData, FrameTreeUpdateMsg};
|
||||||
use windowing::WindowEvent;
|
use windowing::WindowEvent;
|
||||||
|
|
||||||
use geom::scale_factor::ScaleFactor;
|
use geom::scale_factor::ScaleFactor;
|
||||||
|
@ -104,7 +105,8 @@ impl CompositorEventListener for NullCompositor {
|
||||||
CreateOrUpdateDescendantLayer(..) |
|
CreateOrUpdateDescendantLayer(..) |
|
||||||
SetLayerOrigin(..) | Paint(..) |
|
SetLayerOrigin(..) | Paint(..) |
|
||||||
ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) |
|
ChangeReadyState(..) | ChangePaintState(..) | ScrollFragmentPoint(..) |
|
||||||
LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) => ()
|
LoadComplete | PaintMsgDiscarded(..) | ScrollTimeout(..) | ChangePageTitle(..) |
|
||||||
|
ChangePageLoadData(..) => ()
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -119,4 +121,10 @@ impl CompositorEventListener for NullCompositor {
|
||||||
self.time_profiler_chan.send(time::ExitMsg);
|
self.time_profiler_chan.send(time::ExitMsg);
|
||||||
self.memory_profiler_chan.send(memory::ExitMsg);
|
self.memory_profiler_chan.send(memory::ExitMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pinch_zoom_level(&self) -> f32 {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_title_for_main_frame(&self) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,10 @@ pub struct Pipeline {
|
||||||
pub paint_chan: PaintChan,
|
pub paint_chan: PaintChan,
|
||||||
pub layout_shutdown_port: Receiver<()>,
|
pub layout_shutdown_port: Receiver<()>,
|
||||||
pub paint_shutdown_port: Receiver<()>,
|
pub paint_shutdown_port: Receiver<()>,
|
||||||
/// The most recently loaded page
|
/// Load data corresponding to the most recently-loaded page.
|
||||||
pub load_data: LoadData,
|
pub load_data: LoadData,
|
||||||
|
/// The title of the most recently-loaded page.
|
||||||
|
pub title: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The subset of the pipeline that is needed for layer composition.
|
/// The subset of the pipeline that is needed for layer composition.
|
||||||
|
@ -44,21 +46,21 @@ impl Pipeline {
|
||||||
/// Starts a paint task, layout task, and possibly a script task.
|
/// Starts a paint task, layout task, and possibly a script task.
|
||||||
/// Returns the channels wrapped in a struct.
|
/// Returns the channels wrapped in a struct.
|
||||||
/// If script_pipeline is not None, then subpage_id must also be not None.
|
/// If script_pipeline is not None, then subpage_id must also be not None.
|
||||||
pub fn create<LTF:LayoutTaskFactory, STF:ScriptTaskFactory>(
|
pub fn create<LTF,STF>(id: PipelineId,
|
||||||
id: PipelineId,
|
subpage_id: Option<SubpageId>,
|
||||||
subpage_id: Option<SubpageId>,
|
constellation_chan: ConstellationChan,
|
||||||
constellation_chan: ConstellationChan,
|
compositor_proxy: Box<CompositorProxy+'static+Send>,
|
||||||
compositor_proxy: Box<CompositorProxy+'static+Send>,
|
devtools_chan: Option<DevtoolsControlChan>,
|
||||||
devtools_chan: Option<DevtoolsControlChan>,
|
image_cache_task: ImageCacheTask,
|
||||||
image_cache_task: ImageCacheTask,
|
font_cache_task: FontCacheTask,
|
||||||
font_cache_task: FontCacheTask,
|
resource_task: ResourceTask,
|
||||||
resource_task: ResourceTask,
|
storage_task: StorageTask,
|
||||||
storage_task: StorageTask,
|
time_profiler_chan: TimeProfilerChan,
|
||||||
time_profiler_chan: TimeProfilerChan,
|
window_size: WindowSizeData,
|
||||||
window_size: WindowSizeData,
|
script_pipeline: Option<Rc<Pipeline>>,
|
||||||
script_pipeline: Option<Rc<Pipeline>>,
|
load_data: LoadData)
|
||||||
load_data: LoadData)
|
-> Pipeline
|
||||||
-> Pipeline {
|
where LTF: LayoutTaskFactory, STF:ScriptTaskFactory {
|
||||||
let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>);
|
let layout_pair = ScriptTaskFactory::create_layout_channel(None::<&mut STF>);
|
||||||
let (paint_port, paint_chan) = PaintChan::new();
|
let (paint_port, paint_chan) = PaintChan::new();
|
||||||
let (paint_shutdown_chan, paint_shutdown_port) = channel();
|
let (paint_shutdown_chan, paint_shutdown_port) = channel();
|
||||||
|
@ -153,6 +155,7 @@ impl Pipeline {
|
||||||
layout_shutdown_port: layout_shutdown_port,
|
layout_shutdown_port: layout_shutdown_port,
|
||||||
paint_shutdown_port: paint_shutdown_port,
|
paint_shutdown_port: paint_shutdown_port,
|
||||||
load_data: load_data,
|
load_data: load_data,
|
||||||
|
title: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ use geom::scale_factor::ScaleFactor;
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeGraphicsMetadata;
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
use servo_msg::compositor_msg::{PaintState, ReadyState};
|
||||||
use servo_msg::compositor_msg::{ReadyState, PaintState};
|
use servo_msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData};
|
||||||
use servo_util::geometry::ScreenPx;
|
use servo_util::geometry::ScreenPx;
|
||||||
use std::fmt::{FormatError, Formatter, Show};
|
use std::fmt::{FormatError, Formatter, Show};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -37,8 +37,12 @@ pub enum WindowEvent {
|
||||||
/// It's possible that this should be something like
|
/// It's possible that this should be something like
|
||||||
/// `CompositorMessageWindowEvent(compositor_task::Msg)` instead.
|
/// `CompositorMessageWindowEvent(compositor_task::Msg)` instead.
|
||||||
IdleWindowEvent,
|
IdleWindowEvent,
|
||||||
/// Sent when part of the window is marked dirty and needs to be redrawn.
|
/// Sent when part of the window is marked dirty and needs to be redrawn. Before sending this
|
||||||
|
/// message, the window must make the same GL context as in `PrepareRenderingEvent` current.
|
||||||
RefreshWindowEvent,
|
RefreshWindowEvent,
|
||||||
|
/// Sent to initialize the GL context. The windowing system must have a valid, current GL
|
||||||
|
/// context when this message is sent.
|
||||||
|
InitializeCompositingWindowEvent,
|
||||||
/// Sent when the window is resized.
|
/// Sent when the window is resized.
|
||||||
ResizeWindowEvent(TypedSize2D<DevicePixel, uint>),
|
ResizeWindowEvent(TypedSize2D<DevicePixel, uint>),
|
||||||
/// Sent when a new URL is to be loaded.
|
/// Sent when a new URL is to be loaded.
|
||||||
|
@ -47,7 +51,8 @@ pub enum WindowEvent {
|
||||||
MouseWindowEventClass(MouseWindowEvent),
|
MouseWindowEventClass(MouseWindowEvent),
|
||||||
/// Sent when a mouse move.
|
/// Sent when a mouse move.
|
||||||
MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>),
|
MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>),
|
||||||
/// Sent when the user scrolls. Includes the current cursor position.
|
/// Sent when the user scrolls. The first point is the delta and the second point is the
|
||||||
|
/// origin.
|
||||||
ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>),
|
ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>),
|
||||||
/// Sent when the user zooms.
|
/// Sent when the user zooms.
|
||||||
ZoomWindowEvent(f32),
|
ZoomWindowEvent(f32),
|
||||||
|
@ -66,6 +71,7 @@ impl Show for WindowEvent {
|
||||||
match *self {
|
match *self {
|
||||||
IdleWindowEvent => write!(f, "Idle"),
|
IdleWindowEvent => write!(f, "Idle"),
|
||||||
RefreshWindowEvent => write!(f, "Refresh"),
|
RefreshWindowEvent => write!(f, "Refresh"),
|
||||||
|
InitializeCompositingWindowEvent => write!(f, "InitializeCompositing"),
|
||||||
ResizeWindowEvent(..) => write!(f, "Resize"),
|
ResizeWindowEvent(..) => write!(f, "Resize"),
|
||||||
KeyEvent(..) => write!(f, "Key"),
|
KeyEvent(..) => write!(f, "Key"),
|
||||||
LoadUrlWindowEvent(..) => write!(f, "LoadUrl"),
|
LoadUrlWindowEvent(..) => write!(f, "LoadUrl"),
|
||||||
|
@ -92,6 +98,12 @@ pub trait WindowMethods {
|
||||||
fn set_ready_state(&self, ready_state: ReadyState);
|
fn set_ready_state(&self, ready_state: ReadyState);
|
||||||
/// Sets the paint state of the current page.
|
/// Sets the paint state of the current page.
|
||||||
fn set_paint_state(&self, paint_state: PaintState);
|
fn set_paint_state(&self, paint_state: PaintState);
|
||||||
|
/// Sets the page title for the current page.
|
||||||
|
fn set_page_title(&self, title: Option<String>);
|
||||||
|
/// Sets the load data for the current page.
|
||||||
|
fn set_page_load_data(&self, load_data: LoadData);
|
||||||
|
/// Called when the browser is done loading a frame.
|
||||||
|
fn load_end(&self);
|
||||||
|
|
||||||
/// Returns the hidpi factor of the monitor.
|
/// Returns the hidpi factor of the monitor.
|
||||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
|
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
|
||||||
|
@ -106,5 +118,10 @@ pub trait WindowMethods {
|
||||||
/// magic to wake the up window's event loop.
|
/// magic to wake the up window's event loop.
|
||||||
fn create_compositor_channel(_: &Option<Rc<Self>>)
|
fn create_compositor_channel(_: &Option<Rc<Self>>)
|
||||||
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>);
|
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>);
|
||||||
|
|
||||||
|
/// Requests that the window system prepare a composite. Typically this will involve making
|
||||||
|
/// some type of platform-specific graphics context current. Returns true if the composite may
|
||||||
|
/// proceed and false if it should not.
|
||||||
|
fn prepare_for_composite(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub enum PaintState {
|
||||||
PaintingPaintState,
|
PaintingPaintState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone)]
|
#[deriving(Eq, Ord, PartialEq, PartialOrd, Clone, Show)]
|
||||||
pub enum ReadyState {
|
pub enum ReadyState {
|
||||||
/// Informs the compositor that nothing has been done yet. Used for setting status
|
/// Informs the compositor that nothing has been done yet. Used for setting status
|
||||||
Blank,
|
Blank,
|
||||||
|
@ -111,6 +111,8 @@ pub trait ScriptListener {
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
layer_id: LayerId,
|
layer_id: LayerId,
|
||||||
point: Point2D<f32>);
|
point: Point2D<f32>);
|
||||||
|
/// Informs the compositor that the title of the page with the given pipeline ID has changed.
|
||||||
|
fn set_title(&mut self, pipeline_id: PipelineId, new_title: Option<String>);
|
||||||
fn close(&mut self);
|
fn close(&mut self);
|
||||||
fn dup(&mut self) -> Box<ScriptListener+'static>;
|
fn dup(&mut self) -> Box<ScriptListener+'static>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,6 +205,9 @@ pub enum Msg {
|
||||||
PainterReadyMsg(PipelineId),
|
PainterReadyMsg(PipelineId),
|
||||||
ResizedWindowMsg(WindowSizeData),
|
ResizedWindowMsg(WindowSizeData),
|
||||||
KeyEvent(Key, KeyState, KeyModifiers),
|
KeyEvent(Key, KeyState, KeyModifiers),
|
||||||
|
/// Requests that the constellation inform the compositor of the title of the pipeline
|
||||||
|
/// immediately.
|
||||||
|
GetPipelineTitleMsg(PipelineId),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to net::resource_task::LoadData
|
/// Similar to net::resource_task::LoadData
|
||||||
|
|
|
@ -189,6 +189,7 @@ pub trait DocumentHelpers<'a> {
|
||||||
fn begin_focus_transaction(self);
|
fn begin_focus_transaction(self);
|
||||||
fn request_focus(self, elem: JSRef<Element>);
|
fn request_focus(self, elem: JSRef<Element>);
|
||||||
fn commit_focus_transaction(self);
|
fn commit_focus_transaction(self);
|
||||||
|
fn send_title_to_compositor(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
|
@ -369,6 +370,12 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> {
|
||||||
//TODO: dispatch blur, focus, focusout, and focusin events
|
//TODO: dispatch blur, focus, focusout, and focusin events
|
||||||
self.focused.assign(self.possibly_focused.get());
|
self.focused.assign(self.possibly_focused.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sends this document's title to the compositor.
|
||||||
|
fn send_title_to_compositor(self) {
|
||||||
|
let window = self.window().root();
|
||||||
|
window.page().send_title_to_compositor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deriving(PartialEq)]
|
#[deriving(PartialEq)]
|
||||||
|
@ -985,3 +992,4 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
||||||
global_event_handlers!()
|
global_event_handlers!()
|
||||||
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange)
|
event_handler!(readystatechange, GetOnreadystatechange, SetOnreadystatechange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,15 +5,17 @@
|
||||||
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding;
|
||||||
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods;
|
use dom::bindings::codegen::Bindings::HTMLTitleElementBinding::HTMLTitleElementMethods;
|
||||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLTitleElementDerived, NodeCast, TextCast};
|
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLTitleElementDerived, NodeCast};
|
||||||
|
use dom::bindings::codegen::InheritTypes::{TextCast};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::HTMLTitleElementTypeId;
|
use dom::element::HTMLTitleElementTypeId;
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -68,3 +70,19 @@ impl Reflectable for HTMLTitleElement {
|
||||||
self.htmlelement.reflector()
|
self.htmlelement.reflector()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> VirtualMethods for JSRef<'a, HTMLTitleElement> {
|
||||||
|
fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
|
||||||
|
let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
|
||||||
|
Some(htmlelement as &VirtualMethods)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_to_tree(&self, is_in_doc: bool) {
|
||||||
|
let node: JSRef<Node> = NodeCast::from_ref(*self);
|
||||||
|
if is_in_doc {
|
||||||
|
let document = node.owner_doc().root();
|
||||||
|
document.send_title_to_compositor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ use dom::bindings::codegen::InheritTypes::HTMLSelectElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLStyleElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLTableCellElementCast;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
|
use dom::bindings::codegen::InheritTypes::HTMLTextAreaElementCast;
|
||||||
|
use dom::bindings::codegen::InheritTypes::HTMLTitleElementCast;
|
||||||
use dom::bindings::js::JSRef;
|
use dom::bindings::js::JSRef;
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
|
@ -47,6 +48,7 @@ use dom::element::HTMLStyleElementTypeId;
|
||||||
use dom::element::HTMLTableDataCellElementTypeId;
|
use dom::element::HTMLTableDataCellElementTypeId;
|
||||||
use dom::element::HTMLTableHeaderCellElementTypeId;
|
use dom::element::HTMLTableHeaderCellElementTypeId;
|
||||||
use dom::element::HTMLTextAreaElementTypeId;
|
use dom::element::HTMLTextAreaElementTypeId;
|
||||||
|
use dom::element::HTMLTitleElementTypeId;
|
||||||
use dom::event::Event;
|
use dom::event::Event;
|
||||||
use dom::htmlanchorelement::HTMLAnchorElement;
|
use dom::htmlanchorelement::HTMLAnchorElement;
|
||||||
use dom::htmlareaelement::HTMLAreaElement;
|
use dom::htmlareaelement::HTMLAreaElement;
|
||||||
|
@ -67,6 +69,7 @@ use dom::htmlselectelement::HTMLSelectElement;
|
||||||
use dom::htmlstyleelement::HTMLStyleElement;
|
use dom::htmlstyleelement::HTMLStyleElement;
|
||||||
use dom::htmltablecellelement::HTMLTableCellElement;
|
use dom::htmltablecellelement::HTMLTableCellElement;
|
||||||
use dom::htmltextareaelement::HTMLTextAreaElement;
|
use dom::htmltextareaelement::HTMLTextAreaElement;
|
||||||
|
use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, CloneChildrenFlag};
|
||||||
|
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
@ -232,6 +235,11 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a VirtualMethods + 'a {
|
||||||
let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap();
|
let element: &'a JSRef<'a, HTMLTextAreaElement> = HTMLTextAreaElementCast::to_borrowed_ref(node).unwrap();
|
||||||
element as &'a VirtualMethods + 'a
|
element as &'a VirtualMethods + 'a
|
||||||
}
|
}
|
||||||
|
ElementNodeTypeId(HTMLTitleElementTypeId) => {
|
||||||
|
let element: &'a JSRef<'a, HTMLTitleElement> =
|
||||||
|
HTMLTitleElementCast::to_borrowed_ref(node).unwrap();
|
||||||
|
element as &'a VirtualMethods + 'a
|
||||||
|
}
|
||||||
ElementNodeTypeId(ElementTypeId_) => {
|
ElementNodeTypeId(ElementTypeId_) => {
|
||||||
let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap();
|
let element: &'a JSRef<'a, Element> = ElementCast::to_borrowed_ref(node).unwrap();
|
||||||
element as &'a VirtualMethods + 'a
|
element as &'a VirtualMethods + 'a
|
||||||
|
|
|
@ -21,7 +21,6 @@ use script_traits::{UntrustedNodeAddress, ScriptControlChan};
|
||||||
|
|
||||||
use geom::{Point2D, Rect, Size2D};
|
use geom::{Point2D, Rect, Size2D};
|
||||||
use js::rust::Cx;
|
use js::rust::Cx;
|
||||||
use servo_msg::compositor_msg::PerformingLayout;
|
|
||||||
use servo_msg::compositor_msg::ScriptListener;
|
use servo_msg::compositor_msg::ScriptListener;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
|
use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||||
|
@ -266,6 +265,17 @@ impl Page {
|
||||||
// because it was built for infinite clip (MAX_RECT).
|
// because it was built for infinite clip (MAX_RECT).
|
||||||
had_clip_rect
|
had_clip_rect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send_title_to_compositor(&self) {
|
||||||
|
match *self.frame() {
|
||||||
|
None => {}
|
||||||
|
Some(ref frame) => {
|
||||||
|
let window = frame.window.root();
|
||||||
|
let document = frame.document.root();
|
||||||
|
window.compositor().set_title(self.id, Some(document.Title()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator<Rc<Page>> for PageIterator {
|
impl Iterator<Rc<Page>> for PageIterator {
|
||||||
|
@ -356,7 +366,7 @@ impl Page {
|
||||||
pub fn reflow(&self,
|
pub fn reflow(&self,
|
||||||
goal: ReflowGoal,
|
goal: ReflowGoal,
|
||||||
script_chan: ScriptControlChan,
|
script_chan: ScriptControlChan,
|
||||||
compositor: &mut ScriptListener,
|
_: &mut ScriptListener,
|
||||||
query_type: ReflowQueryType) {
|
query_type: ReflowQueryType) {
|
||||||
let root = match *self.frame() {
|
let root = match *self.frame() {
|
||||||
None => return,
|
None => return,
|
||||||
|
@ -376,9 +386,6 @@ impl Page {
|
||||||
// Now, join the layout so that they will see the latest changes we have made.
|
// Now, join the layout so that they will see the latest changes we have made.
|
||||||
self.join_layout();
|
self.join_layout();
|
||||||
|
|
||||||
// Tell the user that we're performing layout.
|
|
||||||
compositor.set_ready_state(self.id, PerformingLayout);
|
|
||||||
|
|
||||||
// Layout will let us know when it's done.
|
// Layout will let us know when it's done.
|
||||||
let (join_chan, join_port) = channel();
|
let (join_chan, join_port) = channel();
|
||||||
let mut layout_join_port = self.layout_join_port.borrow_mut();
|
let mut layout_join_port = self.layout_join_port.borrow_mut();
|
||||||
|
|
|
@ -43,10 +43,12 @@ use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, Scrip
|
||||||
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg};
|
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, ViewportMsg, SendEventMsg};
|
||||||
use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel};
|
use script_traits::{ResizeInactiveMsg, ExitPipelineMsg, NewLayoutInfo, OpaqueScriptLayoutChannel};
|
||||||
use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent};
|
use script_traits::{ScriptControlChan, ReflowCompleteMsg, UntrustedNodeAddress, KeyEvent};
|
||||||
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading};
|
use script_traits::{GetTitleMsg};
|
||||||
|
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading, PerformingLayout};
|
||||||
use servo_msg::compositor_msg::{ScriptListener};
|
use servo_msg::compositor_msg::{ScriptListener};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
|
use servo_msg::constellation_msg::{ConstellationChan, LoadCompleteMsg};
|
||||||
use servo_msg::constellation_msg::{LoadData, PipelineId, Failure, FailureMsg, WindowSizeData, Key, KeyState};
|
use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, NavigationDirection, PipelineId};
|
||||||
|
use servo_msg::constellation_msg::{Failure, FailureMsg, WindowSizeData, Key, KeyState};
|
||||||
use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed};
|
use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed};
|
||||||
use servo_msg::constellation_msg::{Released};
|
use servo_msg::constellation_msg::{Released};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
|
@ -550,6 +552,9 @@ impl ScriptTask {
|
||||||
FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"),
|
FromConstellation(ViewportMsg(..)) => panic!("should have handled ViewportMsg already"),
|
||||||
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
|
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
|
||||||
FromConstellation(ResizeMsg(..)) => panic!("should have handled ResizeMsg already"),
|
FromConstellation(ResizeMsg(..)) => panic!("should have handled ResizeMsg already"),
|
||||||
|
FromConstellation(GetTitleMsg(pipeline_id)) => {
|
||||||
|
self.handle_get_title_msg(pipeline_id)
|
||||||
|
}
|
||||||
FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_progress(addr, progress),
|
FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_progress(addr, progress),
|
||||||
FromScript(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr),
|
FromScript(XHRReleaseMsg(addr)) => XMLHttpRequest::handle_release(addr),
|
||||||
FromScript(DOMMessage(..)) => panic!("unexpected message"),
|
FromScript(DOMMessage(..)) => panic!("unexpected message"),
|
||||||
|
@ -661,6 +666,11 @@ impl ScriptTask {
|
||||||
self.compositor.borrow_mut().close();
|
self.compositor.borrow_mut().close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles a request for the window title.
|
||||||
|
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
|
||||||
|
get_page(&*self.page.borrow(), pipeline_id).send_title_to_compositor();
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles a request to exit the script task and shut down layout.
|
/// Handles a request to exit the script task and shut down layout.
|
||||||
/// Returns true if the script task should shut down and false otherwise.
|
/// Returns true if the script task should shut down and false otherwise.
|
||||||
fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool {
|
fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool {
|
||||||
|
@ -784,6 +794,7 @@ impl ScriptTask {
|
||||||
parse_html(*document, parser_input, &final_url);
|
parse_html(*document, parser_input, &final_url);
|
||||||
|
|
||||||
document.set_ready_state(DocumentReadyStateValues::Interactive);
|
document.set_ready_state(DocumentReadyStateValues::Interactive);
|
||||||
|
self.compositor.borrow_mut().set_ready_state(pipeline_id, PerformingLayout);
|
||||||
|
|
||||||
// Kick off the initial reflow of the page.
|
// Kick off the initial reflow of the page.
|
||||||
debug!("kicking off initial reflow of {}", final_url);
|
debug!("kicking off initial reflow of {}", final_url);
|
||||||
|
|
|
@ -65,7 +65,10 @@ pub enum ConstellationControlMsg {
|
||||||
SendEventMsg(PipelineId, CompositorEvent),
|
SendEventMsg(PipelineId, CompositorEvent),
|
||||||
/// Notifies script that reflow is finished.
|
/// Notifies script that reflow is finished.
|
||||||
ReflowCompleteMsg(PipelineId, uint),
|
ReflowCompleteMsg(PipelineId, uint),
|
||||||
|
/// Notifies script of the viewport.
|
||||||
ViewportMsg(PipelineId, Rect<f32>),
|
ViewportMsg(PipelineId, Rect<f32>),
|
||||||
|
/// Requests that the script task immediately send the constellation the title of a pipeline.
|
||||||
|
GetTitleMsg(PipelineId),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Events from the compositor that the script task needs to know about
|
/// Events from the compositor that the script task needs to know about
|
||||||
|
|
4
components/servo/Cargo.lock
generated
4
components/servo/Cargo.lock
generated
|
@ -58,7 +58,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cocoa"
|
name = "cocoa"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/servo/rust-cocoa#78b823bec1affcab20b6977e1057125088a6034c"
|
source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compile_msg"
|
name = "compile_msg"
|
||||||
|
@ -394,7 +394,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "layers"
|
name = "layers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf"
|
source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
|
|
|
@ -153,6 +153,14 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
|
||||||
self.compositor.repaint_synchronously()
|
self.compositor.repaint_synchronously()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pinch_zoom_level(&self) -> f32 {
|
||||||
|
self.compositor.pinch_zoom_level()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_title_for_main_frame(&self) {
|
||||||
|
self.compositor.get_title_for_main_frame()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn shutdown(mut self) {
|
pub fn shutdown(mut self) {
|
||||||
self.compositor.shutdown();
|
self.compositor.shutdown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,9 @@ use servo_util::rtinstrument;
|
||||||
#[cfg(not(any(test,target_os="android")))]
|
#[cfg(not(any(test,target_os="android")))]
|
||||||
use servo::Browser;
|
use servo::Browser;
|
||||||
#[cfg(not(any(test,target_os="android")))]
|
#[cfg(not(any(test,target_os="android")))]
|
||||||
use compositing::windowing::{IdleWindowEvent, ResizeWindowEvent, WindowEvent};
|
use compositing::windowing::{IdleWindowEvent, InitializeCompositingWindowEvent, ResizeWindowEvent};
|
||||||
|
#[cfg(not(any(test,target_os="android")))]
|
||||||
|
use compositing::windowing::{WindowEvent};
|
||||||
|
|
||||||
#[cfg(not(any(test,target_os="android")))]
|
#[cfg(not(any(test,target_os="android")))]
|
||||||
use std::os;
|
use std::os;
|
||||||
|
@ -65,6 +67,8 @@ fn start(argc: int, argv: *const *const u8) -> int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
browser.browser.handle_event(InitializeCompositingWindowEvent);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let should_continue = match window {
|
let should_continue = match window {
|
||||||
None => browser.browser.handle_event(IdleWindowEvent),
|
None => browser.browser.handle_event(IdleWindowEvent),
|
||||||
|
|
2
ports/android/glut_app/Cargo.lock
generated
2
ports/android/glut_app/Cargo.lock
generated
|
@ -327,7 +327,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "layers"
|
name = "layers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982"
|
source = "git+https://github.com/servo/rust-layers#63d1093f2a01a6fb9599ea6d932aadf79598451f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
|
|
|
@ -19,8 +19,8 @@ use geom::scale_factor::ScaleFactor;
|
||||||
use geom::size::TypedSize2D;
|
use geom::size::TypedSize2D;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeGraphicsMetadata;
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
use msg::compositor_msg::{IdlePaintState, PaintState};
|
use msg::compositor_msg::{Blank, IdlePaintState, PaintState, ReadyState};
|
||||||
use msg::compositor_msg::{Blank, ReadyState};
|
use msg::constellation_msg::LoadData;
|
||||||
use util::geometry::ScreenPx;
|
use util::geometry::ScreenPx;
|
||||||
|
|
||||||
use glut::glut::{ACTIVE_SHIFT, WindowHeight};
|
use glut::glut::{ACTIVE_SHIFT, WindowHeight};
|
||||||
|
@ -176,19 +176,23 @@ impl WindowMethods for Window {
|
||||||
/// Sets the ready state.
|
/// Sets the ready state.
|
||||||
fn set_ready_state(&self, ready_state: ReadyState) {
|
fn set_ready_state(&self, ready_state: ReadyState) {
|
||||||
self.ready_state.set(ready_state);
|
self.ready_state.set(ready_state);
|
||||||
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
|
// FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
|
||||||
//self.update_window_title()
|
// blocked.
|
||||||
|
//
|
||||||
|
// self.update_window_title()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the paint state.
|
/// Sets the paint state.
|
||||||
fn set_paint_state(&self, paint_state: PaintState) {
|
fn set_paint_state(&self, paint_state: PaintState) {
|
||||||
self.paint_state.set(paint_state);
|
self.paint_state.set(paint_state);
|
||||||
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
|
// FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily
|
||||||
//self.update_window_title()
|
// blocked.
|
||||||
|
//
|
||||||
|
// self.update_window_title()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||||
//FIXME: Do nothing in GLUT now.
|
// FIXME: Do nothing in GLUT now.
|
||||||
ScaleFactor(1.0)
|
ScaleFactor(1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +202,22 @@ impl WindowMethods for Window {
|
||||||
display: GetCurrentDisplay(),
|
display: GetCurrentDisplay(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_page_title(&self, _: Option<String>) {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_load_data(&self, _: LoadData) {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_end(&self) {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_for_composite(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
8
ports/cef/Cargo.lock
generated
8
ports/cef/Cargo.lock
generated
|
@ -3,6 +3,7 @@ name = "embedding"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
"azure 0.1.0 (git+https://github.com/servo/rust-azure)",
|
||||||
|
"cocoa 0.1.1 (git+https://github.com/servo/rust-cocoa)",
|
||||||
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
||||||
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
|
"core_text 0.1.0 (git+https://github.com/servo/rust-core-text)",
|
||||||
"devtools 0.0.1",
|
"devtools 0.0.1",
|
||||||
|
@ -56,6 +57,11 @@ dependencies = [
|
||||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cocoa"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/servo/rust-cocoa#084f8e1baf40391eb12819d16765af25ca96c7ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compositing"
|
name = "compositing"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -358,7 +364,7 @@ source = "git+https://github.com/bjz/gl-rs.git#79cd3b3f9f19aa0e39f6af572fc8673a6
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "layers"
|
name = "layers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-layers#b068d2a96d54bf173b548aece36f5ea4ef9353cf"
|
source = "git+https://github.com/servo/rust-layers#0f6edd58b3b572f2aac97567b752c15db5fa1982"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
|
|
|
@ -65,3 +65,6 @@ git = "https://github.com/servo/rust-core-graphics"
|
||||||
|
|
||||||
[dependencies.core_text]
|
[dependencies.core_text]
|
||||||
git = "https://github.com/servo/rust-core-text"
|
git = "https://github.com/servo/rust-core-text"
|
||||||
|
|
||||||
|
[dependencies.cocoa]
|
||||||
|
git = "https://github.com/servo/rust-cocoa"
|
||||||
|
|
|
@ -2,38 +2,90 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use interfaces::{CefBrowser, CefClient, CefRequestContext, cef_browser_t, cef_client_t};
|
use browser_host::{ServoCefBrowserHost, ServoCefBrowserHostExtensions};
|
||||||
use interfaces::{cef_request_context_t};
|
use core::{mod, OffScreenGlobals, OnScreenGlobals, globals};
|
||||||
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t};
|
|
||||||
|
|
||||||
use eutil::Downcast;
|
use eutil::Downcast;
|
||||||
|
use frame::ServoCefFrame;
|
||||||
|
use interfaces::{CefBrowser, CefBrowserHost, CefClient, CefFrame, CefRequestContext};
|
||||||
|
use interfaces::{cef_browser_t, cef_browser_host_t, cef_client_t, cef_frame_t};
|
||||||
|
use interfaces::{cef_request_context_t};
|
||||||
|
use servo::Browser;
|
||||||
|
use types::{cef_browser_settings_t, cef_string_t, cef_window_info_t};
|
||||||
|
use window;
|
||||||
|
|
||||||
|
use compositing::windowing::{Back, Forward, NavigationWindowEvent};
|
||||||
use glfw_app;
|
use glfw_app;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use servo::Browser;
|
|
||||||
use servo_util::opts;
|
use servo_util::opts;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::rc::Rc;
|
|
||||||
|
cef_class_impl! {
|
||||||
|
ServoCefBrowser : CefBrowser, cef_browser_t {
|
||||||
|
fn get_host(&this) -> *mut cef_browser_host_t {
|
||||||
|
this.downcast().host.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_back(&_this) -> () {
|
||||||
|
core::send_window_event(NavigationWindowEvent(Back));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_forward(&_this) -> () {
|
||||||
|
core::send_window_event(NavigationWindowEvent(Forward));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the main (top-level) frame for the browser window.
|
||||||
|
fn get_main_frame(&this) -> *mut cef_frame_t {
|
||||||
|
this.downcast().frame.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ServoCefBrowser {
|
pub struct ServoCefBrowser {
|
||||||
|
/// A reference to the browser's primary frame.
|
||||||
|
pub frame: CefFrame,
|
||||||
|
/// A reference to the browser's host.
|
||||||
|
pub host: CefBrowserHost,
|
||||||
|
/// A reference to the browser client.
|
||||||
pub client: CefClient,
|
pub client: CefClient,
|
||||||
pub servo_browser: RefCell<Option<Browser<glfw_app::window::Window>>>,
|
/// Whether the on-created callback has fired yet.
|
||||||
pub window: RefCell<Option<Rc<glfw_app::window::Window>>>,
|
|
||||||
pub callback_executed: Cell<bool>,
|
pub callback_executed: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServoCefBrowser {
|
impl ServoCefBrowser {
|
||||||
pub fn new(client: CefClient) -> ServoCefBrowser {
|
pub fn new(window_info: &cef_window_info_t, client: CefClient) -> ServoCefBrowser {
|
||||||
|
let frame = ServoCefFrame::new().as_cef_interface();
|
||||||
|
let host = ServoCefBrowserHost::new(client.clone()).as_cef_interface();
|
||||||
|
if window_info.windowless_rendering_enabled == 0 {
|
||||||
|
let glfw_window = glfw_app::create_window();
|
||||||
|
globals.replace(Some(OnScreenGlobals(RefCell::new(glfw_window.clone()),
|
||||||
|
RefCell::new(Browser::new(Some(glfw_window))))));
|
||||||
|
}
|
||||||
|
|
||||||
ServoCefBrowser {
|
ServoCefBrowser {
|
||||||
|
frame: frame,
|
||||||
|
host: host,
|
||||||
client: client,
|
client: client,
|
||||||
servo_browser: RefCell::new(None),
|
|
||||||
window: RefCell::new(None),
|
|
||||||
callback_executed: Cell::new(false),
|
callback_executed: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cef_class_impl! {
|
trait ServoCefBrowserExtensions {
|
||||||
ServoCefBrowser : CefBrowser, cef_browser_t {}
|
fn init(&self, window_info: &cef_window_info_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServoCefBrowserExtensions for CefBrowser {
|
||||||
|
fn init(&self, window_info: &cef_window_info_t) {
|
||||||
|
if window_info.windowless_rendering_enabled != 0 {
|
||||||
|
let window = window::Window::new();
|
||||||
|
let servo_browser = Browser::new(Some(window.clone()));
|
||||||
|
window.set_browser(self.clone());
|
||||||
|
globals.replace(Some(OffScreenGlobals(RefCell::new(window),
|
||||||
|
RefCell::new(servo_browser))));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.downcast().host.set_browser((*self).clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local_data_key!(pub GLOBAL_BROWSERS: RefCell<Vec<CefBrowser>>)
|
local_data_key!(pub GLOBAL_BROWSERS: RefCell<Vec<CefBrowser>>)
|
||||||
|
@ -50,12 +102,16 @@ pub fn browser_callback_after_created(browser: CefBrowser) {
|
||||||
browser.downcast().callback_executed.set(true);
|
browser.downcast().callback_executed.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn browser_host_create(client: CefClient, callback_executed: bool) -> CefBrowser {
|
fn browser_host_create(window_info: &cef_window_info_t,
|
||||||
|
client: CefClient,
|
||||||
|
callback_executed: bool)
|
||||||
|
-> CefBrowser {
|
||||||
let mut urls = Vec::new();
|
let mut urls = Vec::new();
|
||||||
urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string());
|
urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string());
|
||||||
let mut opts = opts::default_opts();
|
let mut opts = opts::default_opts();
|
||||||
opts.urls = urls;
|
opts.urls = urls;
|
||||||
let browser = ServoCefBrowser::new(client).as_cef_interface();
|
let browser = ServoCefBrowser::new(window_info, client).as_cef_interface();
|
||||||
|
browser.init(window_info);
|
||||||
if callback_executed {
|
if callback_executed {
|
||||||
browser_callback_after_created(browser.clone());
|
browser_callback_after_created(browser.clone());
|
||||||
}
|
}
|
||||||
|
@ -73,32 +129,30 @@ fn browser_host_create(client: CefClient, callback_executed: bool) -> CefBrowser
|
||||||
}
|
}
|
||||||
|
|
||||||
cef_static_method_impls! {
|
cef_static_method_impls! {
|
||||||
fn cef_browser_host_create_browser(_window_info: *const cef_window_info_t,
|
fn cef_browser_host_create_browser(window_info: *const cef_window_info_t,
|
||||||
client: *mut cef_client_t,
|
client: *mut cef_client_t,
|
||||||
_url: *const cef_string_t,
|
_url: *const cef_string_t,
|
||||||
_browser_settings: *const cef_browser_settings_t,
|
_browser_settings: *const cef_browser_settings_t,
|
||||||
_request_context: *mut cef_request_context_t)
|
_request_context: *mut cef_request_context_t)
|
||||||
-> c_int {
|
-> c_int {
|
||||||
let _window_info: &cef_window_info_t = _window_info;
|
|
||||||
let client: CefClient = client;
|
let client: CefClient = client;
|
||||||
let _url: &[u16] = _url;
|
let _url: &[u16] = _url;
|
||||||
let _browser_settings: &cef_browser_settings_t = _browser_settings;
|
let _browser_settings: &cef_browser_settings_t = _browser_settings;
|
||||||
let _request_context: CefRequestContext = _request_context;
|
let _request_context: CefRequestContext = _request_context;
|
||||||
browser_host_create(client, false);
|
browser_host_create(window_info, client, false);
|
||||||
1i32
|
1i32
|
||||||
}
|
}
|
||||||
|
fn cef_browser_host_create_browser_sync(window_info: *const cef_window_info_t,
|
||||||
fn cef_browser_host_create_browser_sync(_window_info: *const cef_window_info_t,
|
|
||||||
client: *mut cef_client_t,
|
client: *mut cef_client_t,
|
||||||
_url: *const cef_string_t,
|
_url: *const cef_string_t,
|
||||||
_browser_settings: *const cef_browser_settings_t,
|
_browser_settings: *const cef_browser_settings_t,
|
||||||
_request_context: *mut cef_request_context_t)
|
_request_context: *mut cef_request_context_t)
|
||||||
-> *mut cef_browser_t {
|
-> *mut cef_browser_t {
|
||||||
let _window_info: &cef_window_info_t = _window_info;
|
|
||||||
let client: CefClient = client;
|
let client: CefClient = client;
|
||||||
let _url: &[u16] = _url;
|
let _url: &[u16] = _url;
|
||||||
let _browser_settings: &cef_browser_settings_t = _browser_settings;
|
let _browser_settings: &cef_browser_settings_t = _browser_settings;
|
||||||
let _request_context: CefRequestContext = _request_context;
|
let _request_context: CefRequestContext = _request_context;
|
||||||
browser_host_create(client, true)
|
browser_host_create(window_info, client, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
158
ports/cef/browser_host.rs
Normal file
158
ports/cef/browser_host.rs
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use core;
|
||||||
|
use eutil::Downcast;
|
||||||
|
use interfaces::{CefBrowser, CefBrowserHost, CefClient, cef_browser_host_t, cef_client_t};
|
||||||
|
use types::{KEYEVENT_CHAR, KEYEVENT_KEYDOWN, KEYEVENT_KEYUP, KEYEVENT_RAWKEYDOWN, cef_key_event};
|
||||||
|
use types::{cef_mouse_button_type_t, cef_mouse_event, cef_rect_t};
|
||||||
|
|
||||||
|
use compositing::windowing::{InitializeCompositingWindowEvent, KeyEvent, MouseWindowClickEvent};
|
||||||
|
use compositing::windowing::{MouseWindowEventClass, MouseWindowMouseUpEvent, PinchZoomWindowEvent};
|
||||||
|
use compositing::windowing::{ResizeWindowEvent, ScrollWindowEvent};
|
||||||
|
use geom::point::TypedPoint2D;
|
||||||
|
use geom::size::TypedSize2D;
|
||||||
|
use libc::{c_double, c_int};
|
||||||
|
use servo_msg::constellation_msg::{mod, KeyModifiers, Pressed, Released, Repeated};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
pub struct ServoCefBrowserHost {
|
||||||
|
/// A reference to the browser.
|
||||||
|
pub browser: RefCell<Option<CefBrowser>>,
|
||||||
|
/// A reference to the client.
|
||||||
|
pub client: CefClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
cef_class_impl! {
|
||||||
|
ServoCefBrowserHost : CefBrowserHost, cef_browser_host_t {
|
||||||
|
fn get_client(&this) -> *mut cef_client_t {
|
||||||
|
this.downcast().client.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn was_resized(&this) -> () {
|
||||||
|
let mut rect = cef_rect_t::zero();
|
||||||
|
this.get_client()
|
||||||
|
.get_render_handler()
|
||||||
|
.get_backing_rect(this.downcast().browser.borrow().clone().unwrap(), &mut rect);
|
||||||
|
let size = TypedSize2D(rect.width as uint, rect.height as uint);
|
||||||
|
core::send_window_event(ResizeWindowEvent(size));
|
||||||
|
core::repaint_synchronously();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_key_event(&_this, event: *const cef_key_event) -> () {
|
||||||
|
// FIXME(pcwalton): So awful. But it's nearly midnight here and I have to get
|
||||||
|
// Google working.
|
||||||
|
let event: &cef_key_event = event;
|
||||||
|
let key = match (*event).character as u8 {
|
||||||
|
b'a' | b'A' => constellation_msg::KeyA,
|
||||||
|
b'b' | b'B' => constellation_msg::KeyB,
|
||||||
|
b'c' | b'C' => constellation_msg::KeyC,
|
||||||
|
b'd' | b'D' => constellation_msg::KeyD,
|
||||||
|
b'e' | b'E' => constellation_msg::KeyE,
|
||||||
|
b'f' | b'F' => constellation_msg::KeyF,
|
||||||
|
b'g' | b'G' => constellation_msg::KeyG,
|
||||||
|
b'h' | b'H' => constellation_msg::KeyH,
|
||||||
|
b'i' | b'I' => constellation_msg::KeyI,
|
||||||
|
b'j' | b'J' => constellation_msg::KeyJ,
|
||||||
|
b'k' | b'K' => constellation_msg::KeyK,
|
||||||
|
b'l' | b'L' => constellation_msg::KeyL,
|
||||||
|
b'm' | b'M' => constellation_msg::KeyM,
|
||||||
|
b'n' | b'N' => constellation_msg::KeyN,
|
||||||
|
b'o' | b'O' => constellation_msg::KeyO,
|
||||||
|
b'p' | b'P' => constellation_msg::KeyP,
|
||||||
|
b'q' | b'Q' => constellation_msg::KeyQ,
|
||||||
|
b'r' | b'R' => constellation_msg::KeyR,
|
||||||
|
b's' | b'S' => constellation_msg::KeyS,
|
||||||
|
b't' | b'T' => constellation_msg::KeyT,
|
||||||
|
b'u' | b'U' => constellation_msg::KeyU,
|
||||||
|
b'v' | b'V' => constellation_msg::KeyV,
|
||||||
|
b'w' | b'W' => constellation_msg::KeyW,
|
||||||
|
b'x' | b'X' => constellation_msg::KeyX,
|
||||||
|
b'y' | b'Y' => constellation_msg::KeyY,
|
||||||
|
b'z' | b'Z' => constellation_msg::KeyZ,
|
||||||
|
b'0' => constellation_msg::Key0,
|
||||||
|
b'1' => constellation_msg::Key1,
|
||||||
|
b'2' => constellation_msg::Key2,
|
||||||
|
b'3' => constellation_msg::Key3,
|
||||||
|
b'4' => constellation_msg::Key4,
|
||||||
|
b'5' => constellation_msg::Key5,
|
||||||
|
b'6' => constellation_msg::Key6,
|
||||||
|
b'7' => constellation_msg::Key7,
|
||||||
|
b'8' => constellation_msg::Key8,
|
||||||
|
b'9' => constellation_msg::Key9,
|
||||||
|
b'\n' | b'\r' => constellation_msg::KeyEnter,
|
||||||
|
_ => constellation_msg::KeySpace,
|
||||||
|
};
|
||||||
|
let key_state = match (*event).t {
|
||||||
|
KEYEVENT_RAWKEYDOWN => Pressed,
|
||||||
|
KEYEVENT_KEYDOWN | KEYEVENT_CHAR => Repeated,
|
||||||
|
KEYEVENT_KEYUP => Released,
|
||||||
|
};
|
||||||
|
let key_modifiers = KeyModifiers::empty(); // TODO(pcwalton)
|
||||||
|
core::send_window_event(KeyEvent(key, key_state, key_modifiers))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mouse_click_event(&_this,
|
||||||
|
event: *const cef_mouse_event,
|
||||||
|
mouse_button_type: cef_mouse_button_type_t,
|
||||||
|
mouse_up: c_int,
|
||||||
|
_click_count: c_int)
|
||||||
|
-> () {
|
||||||
|
let event: &cef_mouse_event = event;
|
||||||
|
let button_type = mouse_button_type as uint;
|
||||||
|
let point = TypedPoint2D((*event).x as f32, (*event).y as f32);
|
||||||
|
if mouse_up != 0 {
|
||||||
|
core::send_window_event(MouseWindowEventClass(MouseWindowClickEvent(button_type,
|
||||||
|
point)))
|
||||||
|
} else {
|
||||||
|
core::send_window_event(MouseWindowEventClass(MouseWindowMouseUpEvent(button_type,
|
||||||
|
point)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_mouse_wheel_event(&_this,
|
||||||
|
event: *const cef_mouse_event,
|
||||||
|
delta_x: c_int,
|
||||||
|
delta_y: c_int)
|
||||||
|
-> () {
|
||||||
|
let event: &cef_mouse_event = event;
|
||||||
|
let delta = TypedPoint2D(delta_x as f32, delta_y as f32);
|
||||||
|
let origin = TypedPoint2D((*event).x as i32, (*event).y as i32);
|
||||||
|
core::send_window_event(ScrollWindowEvent(delta, origin))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_zoom_level(&_this) -> c_double {
|
||||||
|
core::pinch_zoom_level() as c_double
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_zoom_level(&this, new_zoom_level: c_double) -> () {
|
||||||
|
let old_zoom_level = this.get_zoom_level();
|
||||||
|
core::send_window_event(PinchZoomWindowEvent((new_zoom_level / old_zoom_level) as f32))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_compositing(&_this) -> () {
|
||||||
|
core::send_window_event(InitializeCompositingWindowEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServoCefBrowserHost {
|
||||||
|
pub fn new(client: CefClient) -> ServoCefBrowserHost {
|
||||||
|
ServoCefBrowserHost {
|
||||||
|
browser: RefCell::new(None),
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ServoCefBrowserHostExtensions {
|
||||||
|
fn set_browser(&self, browser: CefBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServoCefBrowserHostExtensions for CefBrowserHost {
|
||||||
|
fn set_browser(&self, browser: CefBrowser) {
|
||||||
|
*self.downcast().browser.borrow_mut() = Some(browser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub fn command_line_init(argc: c_int, argv: *const *const u8) {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, name: *const cef_string_t) -> cef_string_userfree_t {
|
pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, name: *const cef_string_t) -> cef_string_userfree_t {
|
||||||
if cmd.is_null() || name.is_null() {
|
if cmd.is_null() || name.is_null() {
|
||||||
return cef_string::empty_utf16_string()
|
return cef_string::empty_utf16_userfree_string()
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
//technically cef_string_t can be any type of character size
|
//technically cef_string_t can be any type of character size
|
||||||
|
@ -67,11 +67,11 @@ pub extern "C" fn command_line_get_switch_value(cmd: *mut cef_command_line_t, na
|
||||||
&mut string,
|
&mut string,
|
||||||
1);
|
1);
|
||||||
});
|
});
|
||||||
return string
|
return cef_string::string_to_userfree_string(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cef_string::empty_utf16_string()
|
return cef_string::empty_utf16_userfree_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -2,19 +2,43 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use browser::{GLOBAL_BROWSERS, browser_callback_after_created};
|
|
||||||
use command_line::command_line_init;
|
use command_line::command_line_init;
|
||||||
use interfaces::cef_app_t;
|
use interfaces::cef_app_t;
|
||||||
use eutil::Downcast;
|
|
||||||
use switches::{KPROCESSTYPE, KWAITFORDEBUGGER};
|
|
||||||
use types::{cef_main_args_t, cef_settings_t};
|
use types::{cef_main_args_t, cef_settings_t};
|
||||||
|
use window;
|
||||||
|
|
||||||
|
use compositing::windowing::{IdleWindowEvent, WindowEvent};
|
||||||
|
use geom::size::TypedSize2D;
|
||||||
use glfw_app;
|
use glfw_app;
|
||||||
use libc::funcs::c95::string::strlen;
|
|
||||||
use libc::{c_char, c_int, c_void};
|
use libc::{c_char, c_int, c_void};
|
||||||
use native;
|
use native;
|
||||||
|
use rustrt::local::Local;
|
||||||
use servo::Browser;
|
use servo::Browser;
|
||||||
use std::slice;
|
use servo_util::opts;
|
||||||
|
use servo_util::opts::OpenGL;
|
||||||
|
use std::c_str::CString;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::rt;
|
||||||
|
|
||||||
|
const MAX_RENDERING_THREADS: uint = 128;
|
||||||
|
|
||||||
|
// TODO(pcwalton): Get the home page via the CEF API.
|
||||||
|
static HOME_URL: &'static str = "http://s27.postimg.org/vqbtrolyr/servo.jpg";
|
||||||
|
|
||||||
|
// TODO(pcwalton): Support multiple windows.
|
||||||
|
pub enum ServoCefGlobals {
|
||||||
|
OnScreenGlobals(RefCell<Rc<glfw_app::window::Window>>,
|
||||||
|
RefCell<Browser<glfw_app::window::Window>>),
|
||||||
|
OffScreenGlobals(RefCell<Rc<window::Window>>, RefCell<Browser<window::Window>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
local_data_key!(pub globals: ServoCefGlobals)
|
||||||
|
|
||||||
|
local_data_key!(pub message_queue: RefCell<Vec<WindowEvent>>)
|
||||||
|
|
||||||
|
// Copied from `libnative/lib.rs`.
|
||||||
|
static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20);
|
||||||
|
|
||||||
static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
|
static CEF_API_HASH_UNIVERSAL: &'static [u8] = b"8efd129f4afc344bd04b2feb7f73a149b6c4e27f\0";
|
||||||
#[cfg(target_os="windows")]
|
#[cfg(target_os="windows")]
|
||||||
|
@ -26,68 +50,109 @@ static CEF_API_HASH_PLATFORM: &'static [u8] = b"2bc564c3871965ef3a2531b528bda3e1
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
|
pub extern "C" fn cef_initialize(args: *const cef_main_args_t,
|
||||||
_settings: *mut cef_settings_t,
|
settings: *mut cef_settings_t,
|
||||||
application: *mut cef_app_t,
|
application: *mut cef_app_t,
|
||||||
_windows_sandbox_info: *const c_void)
|
_windows_sandbox_info: *const c_void)
|
||||||
-> c_int {
|
-> c_int {
|
||||||
if args.is_null() {
|
if args.is_null() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
rt::init((*args).argc as int, (*args).argv);
|
||||||
command_line_init((*args).argc, (*args).argv);
|
command_line_init((*args).argc, (*args).argv);
|
||||||
(*application).get_browser_process_handler.map(|cb| {
|
|
||||||
let handler = cb(application);
|
if !application.is_null() {
|
||||||
if handler.is_not_null() {
|
(*application).get_browser_process_handler.map(|cb| {
|
||||||
(*handler).on_context_initialized.map(|hcb| hcb(handler));
|
let handler = cb(application);
|
||||||
}
|
if handler.is_not_null() {
|
||||||
});
|
(*handler).on_context_initialized.map(|hcb| hcb(handler));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_rust_task();
|
||||||
|
|
||||||
|
message_queue.replace(Some(RefCell::new(Vec::new())));
|
||||||
|
|
||||||
|
let urls = vec![HOME_URL.to_string()];
|
||||||
|
opts::set_opts(opts::Opts {
|
||||||
|
urls: urls,
|
||||||
|
n_paint_threads: 1,
|
||||||
|
gpu_painting: false,
|
||||||
|
tile_size: 512,
|
||||||
|
device_pixels_per_px: None,
|
||||||
|
time_profiler_period: None,
|
||||||
|
memory_profiler_period: None,
|
||||||
|
enable_experimental: false,
|
||||||
|
nonincremental_layout: false,
|
||||||
|
layout_threads: unsafe {
|
||||||
|
if ((*settings).rendering_threads as uint) < 1 {
|
||||||
|
1
|
||||||
|
} else if (*settings).rendering_threads as uint > MAX_RENDERING_THREADS {
|
||||||
|
MAX_RENDERING_THREADS
|
||||||
|
} else {
|
||||||
|
(*settings).rendering_threads as uint
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output_file: None,
|
||||||
|
headless: false,
|
||||||
|
hard_fail: false,
|
||||||
|
bubble_inline_sizes_separately: false,
|
||||||
|
show_debug_borders: false,
|
||||||
|
show_debug_fragment_borders: false,
|
||||||
|
enable_text_antialiasing: true,
|
||||||
|
trace_layout: false,
|
||||||
|
devtools_port: None,
|
||||||
|
initial_window_size: TypedSize2D(800, 600),
|
||||||
|
profile_tasks: false,
|
||||||
|
user_agent: None,
|
||||||
|
dump_flow_tree: false,
|
||||||
|
validate_display_list_geometry: false,
|
||||||
|
render_api: OpenGL,
|
||||||
|
});
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copied from `libnative/lib.rs`.
|
||||||
|
fn create_rust_task() {
|
||||||
|
let something_around_the_top_of_the_stack = 1;
|
||||||
|
let addr = &something_around_the_top_of_the_stack as *const int;
|
||||||
|
let my_stack_top = addr as uint;
|
||||||
|
|
||||||
|
// FIXME #11359 we just assume that this thread has a stack of a
|
||||||
|
// certain size, and estimate that there's at most 20KB of stack
|
||||||
|
// frames above our current position.
|
||||||
|
|
||||||
|
let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE;
|
||||||
|
|
||||||
|
let task = native::task::new((my_stack_bottom, my_stack_top), rt::thread::main_guard_page());
|
||||||
|
Local::put(task);
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_shutdown() {
|
pub extern "C" fn cef_shutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_run_message_loop() {
|
pub extern "C" fn cef_run_message_loop() {
|
||||||
native::start(0, 0 as *const *const u8, proc() {
|
let mut the_globals = globals.get();
|
||||||
GLOBAL_BROWSERS.get().map(|refcellbrowsers| {
|
let the_globals = the_globals.as_mut().unwrap();
|
||||||
let browsers = refcellbrowsers.borrow();
|
match **the_globals {
|
||||||
let mut num = browsers.len();
|
OnScreenGlobals(ref window, ref browser) => {
|
||||||
for active_browser in browsers.iter() {
|
while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
|
||||||
*active_browser.downcast().window.borrow_mut() =
|
}
|
||||||
Some(glfw_app::create_window());
|
OffScreenGlobals(ref window, ref browser) => {
|
||||||
*active_browser.downcast().servo_browser.borrow_mut() =
|
while browser.borrow_mut().handle_event(window.borrow_mut().wait_events()) {}
|
||||||
Some(Browser::new((*active_browser.downcast()
|
}
|
||||||
.window
|
}
|
||||||
.borrow()).clone()));
|
}
|
||||||
if !active_browser.downcast().callback_executed.get() {
|
|
||||||
browser_callback_after_created((*active_browser).clone());
|
#[no_mangle]
|
||||||
}
|
pub extern "C" fn cef_do_message_loop_work() {
|
||||||
}
|
send_window_event(IdleWindowEvent)
|
||||||
while num > 0 {
|
|
||||||
for active_browser in browsers.iter()
|
|
||||||
.filter(|&active_browser| {
|
|
||||||
active_browser.downcast()
|
|
||||||
.servo_browser
|
|
||||||
.borrow()
|
|
||||||
.is_some()
|
|
||||||
}) {
|
|
||||||
let ref mut browser = active_browser.downcast();
|
|
||||||
let mut servobrowser = browser.servo_browser.borrow_mut().take().unwrap();
|
|
||||||
if !servobrowser.handle_event(browser.window
|
|
||||||
.borrow_mut()
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.wait_events()) {
|
|
||||||
servobrowser.shutdown();
|
|
||||||
num -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -95,33 +160,91 @@ pub extern "C" fn cef_quit_message_loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_execute_process(args: *const cef_main_args_t,
|
pub extern "C" fn cef_execute_process(_args: *const cef_main_args_t,
|
||||||
_app: *mut cef_app_t,
|
_app: *mut cef_app_t,
|
||||||
_windows_sandbox_info: *mut c_void)
|
_windows_sandbox_info: *mut c_void)
|
||||||
-> c_int {
|
-> c_int {
|
||||||
unsafe {
|
-1
|
||||||
if args.is_null() {
|
}
|
||||||
println!("args must be passed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for i in range(0u, (*args).argc as uint) {
|
|
||||||
let u = (*args).argv.offset(i as int) as *const u8;
|
|
||||||
slice::raw::buf_as_slice(u, strlen(u as *const i8) as uint, |s| {
|
|
||||||
if s.starts_with("--".as_bytes()) {
|
|
||||||
if s.slice_from(2) == KWAITFORDEBUGGER.as_bytes() {
|
|
||||||
//FIXME: this is NOT functionally equivalent to chromium!
|
|
||||||
|
|
||||||
//this should be a pause() call with an installed signal
|
pub fn send_window_event(event: WindowEvent) {
|
||||||
//handler callback, something which is impossible now in rust
|
message_queue.get().as_mut().unwrap().borrow_mut().push(event);
|
||||||
} else if s.slice_from(2) == KPROCESSTYPE.as_bytes() {
|
|
||||||
//TODO: run other process now
|
let mut the_globals = globals.get();
|
||||||
}
|
let the_globals = match the_globals.as_mut() {
|
||||||
}
|
None => return,
|
||||||
});
|
Some(the_globals) => the_globals,
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
match **the_globals {
|
||||||
|
OnScreenGlobals(_, ref browser) => {
|
||||||
|
match browser.try_borrow_mut() {
|
||||||
|
None => {
|
||||||
|
// We're trying to send an event while processing another one. This will
|
||||||
|
// cause general badness, so queue up that event instead of immediately
|
||||||
|
// processing it.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Some(ref mut browser) => {
|
||||||
|
let event = match message_queue.get()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.pop() {
|
||||||
|
None => return,
|
||||||
|
Some(event) => event,
|
||||||
|
};
|
||||||
|
browser.handle_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OffScreenGlobals(_, ref browser) => {
|
||||||
|
match browser.try_borrow_mut() {
|
||||||
|
None => {
|
||||||
|
// We're trying to send an event while processing another one. This will
|
||||||
|
// cause general badness, so queue up that event instead of immediately
|
||||||
|
// processing it.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Some(ref mut browser) => {
|
||||||
|
let event = match message_queue.get()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.borrow_mut()
|
||||||
|
.pop() {
|
||||||
|
None => return,
|
||||||
|
Some(event) => event,
|
||||||
|
};
|
||||||
|
browser.handle_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//process type not specified, must be browser process (NOOP)
|
}
|
||||||
-1
|
|
||||||
|
macro_rules! browser_method_delegate(
|
||||||
|
( $( fn $method:ident ( ) -> $return_type:ty ; )* ) => (
|
||||||
|
$(
|
||||||
|
pub fn $method() -> $return_type {
|
||||||
|
let mut the_globals = globals.get();
|
||||||
|
let the_globals = match the_globals.as_mut() {
|
||||||
|
None => panic!("{}: no globals created", stringify!($method)),
|
||||||
|
Some(the_globals) => the_globals,
|
||||||
|
};
|
||||||
|
match **the_globals {
|
||||||
|
OnScreenGlobals(_, ref browser) => browser.borrow_mut().$method(),
|
||||||
|
OffScreenGlobals(_, ref browser) => browser.borrow_mut().$method(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
browser_method_delegate! {
|
||||||
|
fn repaint_synchronously() -> ();
|
||||||
|
fn pinch_zoom_level() -> f32;
|
||||||
|
fn get_title_for_main_frame() -> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -133,6 +256,16 @@ pub extern "C" fn cef_api_hash(entry: c_int) -> *const c_char {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn cef_log(_file: *const c_char,
|
||||||
|
_line: c_int,
|
||||||
|
_severity: c_int,
|
||||||
|
message: *const c_char) {
|
||||||
|
unsafe {
|
||||||
|
println!("{}", CString::new(message, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_get_min_log_level() -> c_int {
|
pub extern "C" fn cef_get_min_log_level() -> c_int {
|
||||||
0
|
0
|
||||||
|
|
45
ports/cef/frame.rs
Normal file
45
ports/cef/frame.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use eutil::Downcast;
|
||||||
|
use interfaces::{CefFrame, CefStringVisitor, cef_frame_t, cef_string_visitor_t};
|
||||||
|
use types::{cef_string_t, cef_string_userfree_t};
|
||||||
|
|
||||||
|
use core;
|
||||||
|
use compositing::windowing::LoadUrlWindowEvent;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
pub struct ServoCefFrame {
|
||||||
|
pub title_visitor: RefCell<Option<CefStringVisitor>>,
|
||||||
|
pub url: RefCell<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServoCefFrame {
|
||||||
|
pub fn new() -> ServoCefFrame {
|
||||||
|
ServoCefFrame {
|
||||||
|
title_visitor: RefCell::new(None),
|
||||||
|
url: RefCell::new(String::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cef_class_impl! {
|
||||||
|
ServoCefFrame : CefFrame, cef_frame_t {
|
||||||
|
fn load_url(&this, url: *const cef_string_t) -> () {
|
||||||
|
let this = this.downcast();
|
||||||
|
*this.url.borrow_mut() = String::from_utf16(url).unwrap();
|
||||||
|
core::send_window_event(LoadUrlWindowEvent(String::from_utf16(url).unwrap()));
|
||||||
|
}
|
||||||
|
fn get_url(&this) -> cef_string_userfree_t {
|
||||||
|
let this = this.downcast();
|
||||||
|
(*this.url.borrow()).clone()
|
||||||
|
}
|
||||||
|
fn get_text(&this, visitor: *mut cef_string_visitor_t) -> () {
|
||||||
|
let this = this.downcast();
|
||||||
|
*this.title_visitor.borrow_mut() = Some(visitor);
|
||||||
|
core::get_title_for_main_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,11 +14,12 @@ extern crate log;
|
||||||
extern crate "plugins" as servo_plugins;
|
extern crate "plugins" as servo_plugins;
|
||||||
|
|
||||||
extern crate servo;
|
extern crate servo;
|
||||||
|
extern crate compositing;
|
||||||
|
|
||||||
extern crate azure;
|
extern crate azure;
|
||||||
extern crate compositing;
|
|
||||||
extern crate geom;
|
extern crate geom;
|
||||||
extern crate gfx;
|
extern crate gfx;
|
||||||
|
extern crate gleam;
|
||||||
extern crate glfw;
|
extern crate glfw;
|
||||||
extern crate glfw_app;
|
extern crate glfw_app;
|
||||||
extern crate js;
|
extern crate js;
|
||||||
|
@ -34,9 +35,14 @@ extern crate stb_image;
|
||||||
|
|
||||||
extern crate green;
|
extern crate green;
|
||||||
extern crate native;
|
extern crate native;
|
||||||
|
extern crate rustrt;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate "url" as std_url;
|
extern crate "url" as std_url;
|
||||||
|
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
extern crate cgl;
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
extern crate cocoa;
|
||||||
#[cfg(target_os="macos")]
|
#[cfg(target_os="macos")]
|
||||||
extern crate core_graphics;
|
extern crate core_graphics;
|
||||||
#[cfg(target_os="macos")]
|
#[cfg(target_os="macos")]
|
||||||
|
@ -46,14 +52,17 @@ extern crate core_text;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
pub mod browser;
|
pub mod browser;
|
||||||
|
pub mod browser_host;
|
||||||
pub mod command_line;
|
pub mod command_line;
|
||||||
pub mod cookie;
|
pub mod cookie;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod drag_data;
|
pub mod drag_data;
|
||||||
pub mod eutil;
|
pub mod eutil;
|
||||||
|
pub mod frame;
|
||||||
pub mod interfaces;
|
pub mod interfaces;
|
||||||
pub mod print_settings;
|
pub mod print_settings;
|
||||||
pub mod process_message;
|
pub mod process_message;
|
||||||
|
pub mod render_handler;
|
||||||
pub mod request;
|
pub mod request;
|
||||||
pub mod request_context;
|
pub mod request_context;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
@ -67,8 +76,9 @@ pub mod switches;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod urlrequest;
|
pub mod urlrequest;
|
||||||
pub mod values;
|
|
||||||
pub mod v8;
|
pub mod v8;
|
||||||
|
pub mod values;
|
||||||
|
pub mod window;
|
||||||
pub mod wrappers;
|
pub mod wrappers;
|
||||||
pub mod xml_reader;
|
pub mod xml_reader;
|
||||||
pub mod zip_reader;
|
pub mod zip_reader;
|
||||||
|
|
19
ports/cef/render_handler.rs
Normal file
19
ports/cef/render_handler.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use interfaces::{CefBrowser, CefRenderHandler};
|
||||||
|
use types::PET_VIEW;
|
||||||
|
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
pub trait CefRenderHandlerExtensions {
|
||||||
|
fn paint(&self, browser: CefBrowser);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CefRenderHandlerExtensions for CefRenderHandler {
|
||||||
|
fn paint(&self, browser: CefBrowser) {
|
||||||
|
self.on_paint(browser, PET_VIEW, 0, ptr::null(), &mut (), 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
|
||||||
use eutil::slice_to_str;
|
use eutil::slice_to_str;
|
||||||
use libc::{mod, size_t, c_int, c_ushort,c_void};
|
use libc::{mod, size_t, c_int, c_ushort, c_void};
|
||||||
use libc::types::os::arch::c95::wchar_t;
|
use libc::types::os::arch::c95::wchar_t;
|
||||||
use std::char;
|
use std::char;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -54,7 +54,7 @@ pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) {
|
pub extern "C" fn cef_string_userfree_utf16_free(cs: cef_string_userfree_utf16_t) {
|
||||||
unsafe {
|
unsafe {
|
||||||
cef_string_utf16_clear(cs);
|
cef_string_utf16_clear(cs);
|
||||||
libc::free(cs as *mut c_void)
|
libc::free(cs as *mut c_void)
|
||||||
|
@ -269,19 +269,6 @@ pub extern "C" fn cef_string_utf8_to_wide(src: *const u8, src_len: size_t, outpu
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a borrowed reference to a UTF-16 CEF string.
|
|
||||||
pub struct CefStringRef<'a> {
|
|
||||||
pub c_object: &'a *const cef_string_utf16_t,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CefStringRef<'a> {
|
|
||||||
pub unsafe fn from_c_object(c_object: &'a *const cef_string_utf16_t) -> CefStringRef<'a> {
|
|
||||||
CefStringRef {
|
|
||||||
c_object: c_object,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn cef_string_wide_to_utf8(src: *const wchar_t, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
|
pub extern "C" fn cef_string_wide_to_utf8(src: *const wchar_t, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
|
||||||
if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
|
if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
|
||||||
|
@ -321,3 +308,16 @@ pub fn empty_utf16_string() -> cef_string_utf16_t {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn string_to_userfree_string(string: cef_string_utf16_t) -> cef_string_userfree_utf16_t {
|
||||||
|
unsafe {
|
||||||
|
let allocation: cef_string_userfree_utf16_t =
|
||||||
|
mem::transmute(libc::malloc(mem::size_of::<cef_string_utf16_t>() as size_t));
|
||||||
|
ptr::write(allocation, string);
|
||||||
|
allocation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty_utf16_userfree_string() -> cef_string_userfree_utf16_t {
|
||||||
|
string_to_userfree_string(empty_utf16_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ use std::collections::TreeMap;
|
||||||
use std::iter::AdditiveIterator;
|
use std::iter::AdditiveIterator;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use string::{cef_string_userfree_utf16_alloc,cef_string_userfree_utf16_free,cef_string_utf16_set};
|
use string::{cef_string_userfree_utf16_alloc, cef_string_userfree_utf16_free};
|
||||||
|
use string::{cef_string_utf16_set};
|
||||||
use types::{cef_string_multimap_t,cef_string_t};
|
use types::{cef_string_multimap_t,cef_string_t};
|
||||||
|
|
||||||
fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
|
fn string_multimap_to_treemap(smm: *mut cef_string_multimap_t) -> *mut TreeMap<String, Vec<*mut cef_string_t>> {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
284
ports/cef/window.rs
Normal file
284
ports/cef/window.rs
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Off-screen windows.
|
||||||
|
//!
|
||||||
|
//! This is used for off-screen rendering mode only; on-screen windows (the default embedding mode)
|
||||||
|
//! are managed by a platform toolkit (GLFW or Glutin).
|
||||||
|
|
||||||
|
use eutil::Downcast;
|
||||||
|
use interfaces::CefBrowser;
|
||||||
|
use render_handler::CefRenderHandlerExtensions;
|
||||||
|
use types::cef_rect_t;
|
||||||
|
use wrappers::Utf16Encoder;
|
||||||
|
|
||||||
|
use compositing::compositor_task::{mod, CompositorProxy, CompositorReceiver};
|
||||||
|
use compositing::windowing::{IdleWindowEvent, WindowEvent, WindowMethods};
|
||||||
|
use geom::scale_factor::ScaleFactor;
|
||||||
|
use geom::size::TypedSize2D;
|
||||||
|
use gleam::gl;
|
||||||
|
use layers::geometry::DevicePixel;
|
||||||
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
|
use libc::{c_char, c_void};
|
||||||
|
use servo_msg::compositor_msg::{Blank, FinishedLoading, Loading, PerformingLayout, PaintState};
|
||||||
|
use servo_msg::compositor_msg::{ReadyState};
|
||||||
|
use servo_msg::constellation_msg::LoadData;
|
||||||
|
use servo_util::geometry::ScreenPx;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
/// The type of an off-screen window.
|
||||||
|
#[deriving(Clone)]
|
||||||
|
pub struct Window {
|
||||||
|
cef_browser: RefCell<Option<CefBrowser>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
/// Creates a new window.
|
||||||
|
pub fn new() -> Rc<Window> {
|
||||||
|
const RTLD_DEFAULT: *mut c_void = (-2) as *mut c_void;
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl::load_with(|s| {
|
||||||
|
unsafe {
|
||||||
|
let c_str = s.to_c_str();
|
||||||
|
dlsym(RTLD_DEFAULT, c_str.as_ptr()) as *const c_void
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Rc::new(Window {
|
||||||
|
cef_browser: RefCell::new(None),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the current browser.
|
||||||
|
pub fn set_browser(&self, browser: CefBrowser) {
|
||||||
|
*self.cef_browser.borrow_mut() = Some(browser)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Currently unimplemented.
|
||||||
|
pub fn wait_events(&self) -> WindowEvent {
|
||||||
|
IdleWindowEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowMethods for Window {
|
||||||
|
fn framebuffer_size(&self) -> TypedSize2D<DevicePixel,uint> {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
match *browser {
|
||||||
|
None => TypedSize2D(400, 300),
|
||||||
|
Some(ref browser) => {
|
||||||
|
let mut rect = cef_rect_t::zero();
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_render_handler()
|
||||||
|
.get_backing_rect((*browser).clone(), &mut rect);
|
||||||
|
TypedSize2D(rect.width as uint, rect.height as uint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> TypedSize2D<ScreenPx,f32> {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
match *browser {
|
||||||
|
None => TypedSize2D(400.0, 300.0),
|
||||||
|
Some(ref browser) => {
|
||||||
|
let mut rect = cef_rect_t::zero();
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_render_handler()
|
||||||
|
.get_view_rect((*browser).clone(), &mut rect);
|
||||||
|
TypedSize2D(rect.width as f32, rect.height as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&self) {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
match *browser {
|
||||||
|
None => {}
|
||||||
|
Some(ref browser) => {
|
||||||
|
browser.get_host().get_client().get_render_handler().on_present(browser.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ready_state(&self, ready_state: ReadyState) {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
let browser = match *browser {
|
||||||
|
None => return,
|
||||||
|
Some(ref browser) => browser,
|
||||||
|
};
|
||||||
|
let is_loading = match ready_state {
|
||||||
|
Blank | FinishedLoading => 0,
|
||||||
|
Loading | PerformingLayout => 1,
|
||||||
|
};
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_load_handler()
|
||||||
|
.on_loading_state_change(browser.clone(), is_loading, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_paint_state(&self, _: PaintState) {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx,DevicePixel,f32> {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
match *browser {
|
||||||
|
None => ScaleFactor(1.0),
|
||||||
|
Some(ref browser) => {
|
||||||
|
let mut view_rect = cef_rect_t::zero();
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_render_handler()
|
||||||
|
.get_view_rect((*browser).clone(), &mut view_rect);
|
||||||
|
let mut backing_rect = cef_rect_t::zero();
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_render_handler()
|
||||||
|
.get_backing_rect((*browser).clone(), &mut backing_rect);
|
||||||
|
ScaleFactor(backing_rect.width as f32 / view_rect.width as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
use cgl::{CGLGetCurrentContext, CGLGetPixelFormat};
|
||||||
|
|
||||||
|
// FIXME(pcwalton)
|
||||||
|
unsafe {
|
||||||
|
NativeGraphicsMetadata {
|
||||||
|
pixel_format: CGLGetPixelFormat(CGLGetCurrentContext()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")]
|
||||||
|
fn native_metadata(&self) -> NativeGraphicsMetadata {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_compositor_channel(_: &Option<Rc<Window>>)
|
||||||
|
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) {
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
(box CefCompositorProxy {
|
||||||
|
sender: sender,
|
||||||
|
} as Box<CompositorProxy+Send>,
|
||||||
|
box receiver as Box<CompositorReceiver>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_for_composite(&self) -> bool {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
match *browser {
|
||||||
|
None => {}
|
||||||
|
Some(ref browser) => {
|
||||||
|
browser.get_host().get_client().get_render_handler().paint(browser.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_end(&self) {
|
||||||
|
// FIXME(pcwalton): The status code 200 is a lie.
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
let browser = match *browser {
|
||||||
|
None => return,
|
||||||
|
Some(ref browser) => browser,
|
||||||
|
};
|
||||||
|
browser.get_host()
|
||||||
|
.get_client()
|
||||||
|
.get_load_handler()
|
||||||
|
.on_load_end((*browser).clone(), browser.get_main_frame(), 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_title(&self, string: Option<String>) {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
let browser = match *browser {
|
||||||
|
None => return,
|
||||||
|
Some(ref browser) => browser,
|
||||||
|
};
|
||||||
|
let frame = browser.get_main_frame();
|
||||||
|
let frame = frame.downcast();
|
||||||
|
let mut title_visitor = frame.title_visitor.borrow_mut();
|
||||||
|
match &mut *title_visitor {
|
||||||
|
&None => {}
|
||||||
|
&Some(ref mut visitor) => {
|
||||||
|
match string {
|
||||||
|
None => visitor.visit(&[]),
|
||||||
|
Some(string) => {
|
||||||
|
let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
|
||||||
|
visitor.visit(utf16_chars.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_page_load_data(&self, load_data: LoadData) {
|
||||||
|
let browser = self.cef_browser.borrow();
|
||||||
|
let browser = match *browser {
|
||||||
|
None => return,
|
||||||
|
Some(ref browser) => browser,
|
||||||
|
};
|
||||||
|
let frame = browser.get_main_frame();
|
||||||
|
let frame = frame.downcast();
|
||||||
|
*frame.url.borrow_mut() = load_data.url.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CefCompositorProxy {
|
||||||
|
sender: Sender<compositor_task::Msg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompositorProxy for CefCompositorProxy {
|
||||||
|
#[cfg(target_os="macos")]
|
||||||
|
fn send(&mut self, msg: compositor_task::Msg) {
|
||||||
|
use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined, NSAutoreleasePool};
|
||||||
|
use cocoa::appkit::{NSEvent, NSPoint};
|
||||||
|
use cocoa::base::nil;
|
||||||
|
|
||||||
|
// Send a message and kick the OS event loop awake.
|
||||||
|
self.sender.send(msg);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let pool = NSAutoreleasePool::new(nil);
|
||||||
|
let event =
|
||||||
|
NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2(
|
||||||
|
nil,
|
||||||
|
NSApplicationDefined,
|
||||||
|
NSPoint::new(0.0, 0.0),
|
||||||
|
0,
|
||||||
|
0.0,
|
||||||
|
0,
|
||||||
|
ptr::null_mut(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
NSApp().postEvent_atStart_(event, false);
|
||||||
|
pool.drain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os="linux")]
|
||||||
|
fn send(&mut self, msg: compositor_task::Msg) {
|
||||||
|
// FIXME(pcwalton): Kick the GTK event loop awake?
|
||||||
|
self.sender.send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_compositor_proxy(&self) -> Box<CompositorProxy+Send> {
|
||||||
|
box CefCompositorProxy {
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
} as Box<CompositorProxy+Send>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ use types::{cef_load_handler_t, cef_menu_item_type_t, cef_mouse_button_type_t};
|
||||||
use types::{cef_mouse_event, cef_navigation_type_t};
|
use types::{cef_mouse_event, cef_navigation_type_t};
|
||||||
use types::{cef_page_range_t, cef_paint_element_type_t, cef_point_t, cef_postdataelement_type_t};
|
use types::{cef_page_range_t, cef_paint_element_type_t, cef_point_t, cef_postdataelement_type_t};
|
||||||
use types::{cef_popup_features_t, cef_process_id_t};
|
use types::{cef_popup_features_t, cef_process_id_t};
|
||||||
use types::{cef_rect_t, cef_request_context_t, cef_request_handler_t};
|
use types::{cef_rect_t, cef_request_handler_t};
|
||||||
use types::{cef_resource_type_t};
|
use types::{cef_resource_type_t};
|
||||||
use types::{cef_screen_info_t, cef_size_t, cef_string_t};
|
use types::{cef_screen_info_t, cef_size_t, cef_string_t, cef_string_userfree_t};
|
||||||
use types::{cef_string_list_t, cef_string_map_t, cef_string_multimap_t, cef_string_utf16};
|
use types::{cef_string_list_t, cef_string_map_t, cef_string_multimap_t, cef_string_utf16};
|
||||||
use types::{cef_termination_status_t, cef_text_input_context_t, cef_thread_id_t};
|
use types::{cef_termination_status_t, cef_text_input_context_t, cef_thread_id_t};
|
||||||
use types::{cef_time_t, cef_transition_type_t, cef_urlrequest_status_t};
|
use types::{cef_time_t, cef_transition_type_t, cef_urlrequest_status_t};
|
||||||
|
@ -126,7 +126,6 @@ cef_noop_wrapper!(*mut cef_geolocation_handler_t)
|
||||||
cef_noop_wrapper!(*mut cef_jsdialog_handler_t)
|
cef_noop_wrapper!(*mut cef_jsdialog_handler_t)
|
||||||
cef_noop_wrapper!(*mut cef_keyboard_handler_t)
|
cef_noop_wrapper!(*mut cef_keyboard_handler_t)
|
||||||
cef_noop_wrapper!(*mut cef_load_handler_t)
|
cef_noop_wrapper!(*mut cef_load_handler_t)
|
||||||
cef_noop_wrapper!(*mut cef_request_context_t)
|
|
||||||
cef_noop_wrapper!(*mut cef_request_handler_t)
|
cef_noop_wrapper!(*mut cef_request_handler_t)
|
||||||
cef_noop_wrapper!(*mut cef_string_list_t)
|
cef_noop_wrapper!(*mut cef_string_list_t)
|
||||||
cef_noop_wrapper!(*mut cef_string_utf16)
|
cef_noop_wrapper!(*mut cef_string_utf16)
|
||||||
|
@ -181,9 +180,8 @@ cef_unimplemented_wrapper!(cef_string_t, String)
|
||||||
impl<'a> CefWrap<*const cef_string_t> for &'a [u16] {
|
impl<'a> CefWrap<*const cef_string_t> for &'a [u16] {
|
||||||
fn to_c(buffer: &'a [u16]) -> *const cef_string_t {
|
fn to_c(buffer: &'a [u16]) -> *const cef_string_t {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr: *mut c_ushort =
|
let ptr: *mut c_ushort = mem::transmute(libc::malloc(((buffer.len() + 1) * 2) as u64));
|
||||||
mem::transmute(libc::calloc(1, ((buffer.len() * 2) + 1) as u64));
|
ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), buffer.len());
|
||||||
ptr::copy_memory(ptr, mem::transmute(buffer.as_ptr()), (buffer.len() * 2) as uint);
|
|
||||||
*ptr.offset(buffer.len() as int) = 0;
|
*ptr.offset(buffer.len() as int) = 0;
|
||||||
|
|
||||||
// FIXME(pcwalton): This leaks!! We should instead have the caller pass some scratch
|
// FIXME(pcwalton): This leaks!! We should instead have the caller pass some scratch
|
||||||
|
@ -240,6 +238,71 @@ impl<'a,'b> CefWrap<*mut *const c_char> for &'a mut &'b str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> CefWrap<cef_string_userfree_t> for String {
|
||||||
|
fn to_c(string: String) -> cef_string_userfree_t {
|
||||||
|
let utf16_chars: Vec<u16> = Utf16Encoder::new(string.chars()).collect();
|
||||||
|
|
||||||
|
let boxed_string;
|
||||||
|
unsafe {
|
||||||
|
let buffer = libc::malloc((mem::size_of::<c_ushort>() as u64) *
|
||||||
|
((utf16_chars.len() + 1) as u64 + 1)) as *mut u16;
|
||||||
|
for (i, ch) in utf16_chars.iter().enumerate() {
|
||||||
|
*buffer.offset(i as int) = *ch
|
||||||
|
}
|
||||||
|
*buffer.offset(utf16_chars.len() as int) = 0;
|
||||||
|
|
||||||
|
boxed_string = libc::malloc(mem::size_of::<cef_string_utf16>() as u64) as
|
||||||
|
*mut cef_string_utf16;
|
||||||
|
ptr::write(&mut (*boxed_string).str, buffer);
|
||||||
|
ptr::write(&mut (*boxed_string).length, utf16_chars.len() as u64);
|
||||||
|
ptr::write(&mut (*boxed_string).dtor, Some(free_utf16_buffer));
|
||||||
|
mem::forget(utf16_chars);
|
||||||
|
}
|
||||||
|
boxed_string
|
||||||
|
}
|
||||||
|
unsafe fn to_rust(_: cef_string_userfree_t) -> String {
|
||||||
|
panic!("unimplemented CEF type conversion: cef_string_userfree_t")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn free_utf16_buffer(buffer: *mut c_ushort) {
|
||||||
|
unsafe {
|
||||||
|
libc::free(buffer as *mut c_void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Post Rust-upgrade, remove this and use `collections::str::Utf16Encoder`.
|
||||||
|
pub struct Utf16Encoder<I> {
|
||||||
|
chars: I,
|
||||||
|
extra: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Utf16Encoder<I> {
|
||||||
|
pub fn new(chars: I) -> Utf16Encoder<I> where I: Iterator<char> {
|
||||||
|
Utf16Encoder {
|
||||||
|
chars: chars,
|
||||||
|
extra: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Iterator<u16> for Utf16Encoder<I> where I: Iterator<char> {
|
||||||
|
fn next(&mut self) -> Option<u16> {
|
||||||
|
if self.extra != 0 {
|
||||||
|
return Some(mem::replace(&mut self.extra, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buf = [0u16, ..2];
|
||||||
|
self.chars.next().map(|ch| {
|
||||||
|
let n = ch.encode_utf16(buf.as_mut_slice()).unwrap_or(0);
|
||||||
|
if n == 2 {
|
||||||
|
self.extra = buf[1]
|
||||||
|
}
|
||||||
|
buf[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> CefWrap<cef_string_t> for &'a mut String {
|
impl<'a> CefWrap<cef_string_t> for &'a mut String {
|
||||||
fn to_c(_: &'a mut String) -> cef_string_t {
|
fn to_c(_: &'a mut String) -> cef_string_t {
|
||||||
panic!("unimplemented CEF type conversion: &'a mut String")
|
panic!("unimplemented CEF type conversion: &'a mut String")
|
||||||
|
|
|
@ -23,9 +23,9 @@ use gleam::gl;
|
||||||
use layers::geometry::DevicePixel;
|
use layers::geometry::DevicePixel;
|
||||||
use layers::platform::surface::NativeGraphicsMetadata;
|
use layers::platform::surface::NativeGraphicsMetadata;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
|
use msg::compositor_msg::{Blank, FinishedLoading, IdlePaintState, Loading, PaintState};
|
||||||
use msg::compositor_msg::{IdlePaintState, PaintState, PaintingPaintState};
|
use msg::compositor_msg::{PaintingPaintState, PerformingLayout, ReadyState};
|
||||||
use msg::constellation_msg;
|
use msg::constellation_msg::{mod, LoadData};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::comm::Receiver;
|
use std::comm::Receiver;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -97,6 +97,15 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_events(&self) -> WindowEvent {
|
pub fn wait_events(&self) -> WindowEvent {
|
||||||
|
self.wait_or_poll_events(|glfw| glfw.wait_events())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poll_events(&self) -> WindowEvent {
|
||||||
|
self.wait_or_poll_events(|glfw| glfw.poll_events())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method to factor out functionality from `poll_events` and `wait_events`.
|
||||||
|
fn wait_or_poll_events(&self, callback: |glfw: &glfw::Glfw|) -> WindowEvent {
|
||||||
{
|
{
|
||||||
let mut event_queue = self.event_queue.borrow_mut();
|
let mut event_queue = self.event_queue.borrow_mut();
|
||||||
if !event_queue.is_empty() {
|
if !event_queue.is_empty() {
|
||||||
|
@ -104,7 +113,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.glfw.wait_events();
|
callback(&self.glfw);
|
||||||
for (_, event) in glfw::flush_messages(&self.events) {
|
for (_, event) in glfw::flush_messages(&self.events) {
|
||||||
self.handle_window_event(&self.glfw_window, event);
|
self.handle_window_event(&self.glfw_window, event);
|
||||||
}
|
}
|
||||||
|
@ -196,6 +205,16 @@ impl WindowMethods for Window {
|
||||||
} as Box<CompositorProxy+Send>,
|
} as Box<CompositorProxy+Send>,
|
||||||
box receiver as Box<CompositorReceiver>)
|
box receiver as Box<CompositorReceiver>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_for_composite(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_end(&self) {}
|
||||||
|
|
||||||
|
fn set_page_title(&self, _: Option<String>) {}
|
||||||
|
|
||||||
|
fn set_page_load_data(&self, _: LoadData) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
|
|
|
@ -113,7 +113,7 @@ class MachCommands(CommandBase):
|
||||||
|
|
||||||
build_start = time()
|
build_start = time()
|
||||||
with cd(path.join("ports", "cef")):
|
with cd(path.join("ports", "cef")):
|
||||||
ret = subprocess.call(["cargo", "build"],
|
ret = subprocess.call(["cargo", "build"] + opts,
|
||||||
env=self.build_env())
|
env=self.build_env())
|
||||||
elapsed = time() - build_start
|
elapsed = time() - build_start
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue