зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #2603 - Use some typed units in compositor and windowing (from mbrubeck:units); r=pcwalton
This is a rebased, squashed, and updated version of #2444. Source-Repo: https://github.com/servo/servo Source-Revision: 6c382243c4b3de9f0eec9cd71c757897ffd1b2e0
This commit is contained in:
Родитель
50c03a2fec
Коммит
67ff35687f
|
@ -16,9 +16,10 @@ use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
|
|||
use azure::azure_hl::{SourceSurfaceMethods, Color};
|
||||
use azure::azure_hl;
|
||||
use geom::matrix::identity;
|
||||
use geom::point::Point2D;
|
||||
use geom::point::{Point2D, TypedPoint2D};
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use geom::size::{Size2D, TypedSize2D};
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use layers::layers::{ContainerLayer, ContainerLayerKind};
|
||||
use layers::platform::surface::NativeCompositingGraphicsContext;
|
||||
use layers::rendergl;
|
||||
|
@ -31,6 +32,7 @@ use servo_msg::compositor_msg::{LayerId, ReadyState, RenderState, ScrollPolicy,
|
|||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg, NavigateMsg};
|
||||
use servo_msg::constellation_msg::{PipelineId, ResizedWindowMsg};
|
||||
use servo_msg::constellation_msg;
|
||||
use servo_util::geometry::{DevicePixel, PagePx, ScreenPx};
|
||||
use servo_util::opts::Opts;
|
||||
use servo_util::time::{profile, ProfilerChan};
|
||||
use servo_util::{time, url};
|
||||
|
@ -60,7 +62,10 @@ pub struct IOCompositor {
|
|||
scene: Scene,
|
||||
|
||||
/// The application window size.
|
||||
window_size: Size2D<uint>,
|
||||
window_size: TypedSize2D<DevicePixel, uint>,
|
||||
|
||||
/// The device pixel ratio for this window.
|
||||
hidpi_factor: ScaleFactor<ScreenPx, DevicePixel, f32>,
|
||||
|
||||
/// The platform-specific graphics context.
|
||||
graphics_context: NativeCompositingGraphicsContext,
|
||||
|
@ -78,7 +83,7 @@ pub struct IOCompositor {
|
|||
recomposite: bool,
|
||||
|
||||
/// Keeps track of the current zoom factor.
|
||||
world_zoom: f32,
|
||||
world_zoom: ScaleFactor<PagePx, ScreenPx, f32>,
|
||||
|
||||
/// Tracks whether the zoom action has happend recently.
|
||||
zoom_action: bool,
|
||||
|
@ -124,16 +129,7 @@ impl IOCompositor {
|
|||
// list. This is only here because we don't have that logic in the renderer yet.
|
||||
let root_layer = Rc::new(ContainerLayer());
|
||||
let window_size = window.size();
|
||||
|
||||
let hidpi_factor = match opts.device_pixels_per_px {
|
||||
Some(dppx) => dppx,
|
||||
None => match opts.output_file {
|
||||
Some(_) => 1.0,
|
||||
None => window.hidpi_factor(),
|
||||
}
|
||||
};
|
||||
|
||||
root_layer.common.borrow_mut().set_transform(identity().scale(hidpi_factor, hidpi_factor, 1f32));
|
||||
let hidpi_factor = window.hidpi_factor();
|
||||
|
||||
IOCompositor {
|
||||
window: window,
|
||||
|
@ -142,14 +138,15 @@ impl IOCompositor {
|
|||
context: rendergl::init_render_context(),
|
||||
root_layer: root_layer.clone(),
|
||||
root_pipeline: None,
|
||||
scene: Scene(ContainerLayerKind(root_layer), window_size, identity()),
|
||||
window_size: Size2D(window_size.width as uint, window_size.height as uint),
|
||||
scene: Scene(ContainerLayerKind(root_layer), window_size.to_untyped(), identity()),
|
||||
window_size: window_size.as_uint(),
|
||||
hidpi_factor: hidpi_factor,
|
||||
graphics_context: CompositorTask::create_graphics_context(),
|
||||
composite_ready: false,
|
||||
shutting_down: false,
|
||||
done: false,
|
||||
recomposite: false,
|
||||
world_zoom: hidpi_factor,
|
||||
world_zoom: ScaleFactor(1.0),
|
||||
zoom_action: false,
|
||||
zoom_time: 0f64,
|
||||
ready_state: Blank,
|
||||
|
@ -171,6 +168,7 @@ impl IOCompositor {
|
|||
port,
|
||||
constellation_chan,
|
||||
profiler_chan);
|
||||
compositor.update_zoom_transform();
|
||||
|
||||
// Starts the compositor, which listens for messages on the specified port.
|
||||
compositor.run();
|
||||
|
@ -180,7 +178,7 @@ impl IOCompositor {
|
|||
// Tell the constellation about the initial window size.
|
||||
{
|
||||
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||
chan.send(ResizedWindowMsg(self.window_size));
|
||||
chan.send(ResizedWindowMsg(self.window_size.to_untyped()));
|
||||
}
|
||||
|
||||
// Enter the main event loop.
|
||||
|
@ -341,12 +339,10 @@ impl IOCompositor {
|
|||
self.root_pipeline = Some(frame_tree.pipeline.clone());
|
||||
|
||||
// Initialize the new constellation channel by sending it the root window size.
|
||||
let window_size = self.window.size();
|
||||
let window_size = Size2D(window_size.width as uint,
|
||||
window_size.height as uint);
|
||||
let window_size = self.window.size().as_uint();
|
||||
{
|
||||
let ConstellationChan(ref chan) = new_constellation_chan;
|
||||
chan.send(ResizedWindowMsg(window_size));
|
||||
chan.send(ResizedWindowMsg(window_size.to_untyped()));
|
||||
}
|
||||
|
||||
self.constellation_chan = new_constellation_chan;
|
||||
|
@ -424,17 +420,19 @@ impl IOCompositor {
|
|||
self.ask_for_tiles();
|
||||
}
|
||||
|
||||
/// The size of the content area in CSS px at the current zoom level
|
||||
fn page_window(&self) -> TypedSize2D<PagePx, f32> {
|
||||
self.window_size.as_f32() / self.device_pixels_per_page_px()
|
||||
}
|
||||
|
||||
fn set_layer_page_size(&mut self,
|
||||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
new_size: Size2D<f32>,
|
||||
epoch: Epoch) {
|
||||
let page_window = self.page_window();
|
||||
let (ask, move): (bool, bool) = match self.compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
let window_size = &self.window_size;
|
||||
let world_zoom = self.world_zoom;
|
||||
let page_window = Size2D(window_size.width as f32 / world_zoom,
|
||||
window_size.height as f32 / world_zoom);
|
||||
layer.resize(pipeline_id, layer_id, new_size, page_window, epoch);
|
||||
let move = self.fragment_point.take().map_or(false, |point| {
|
||||
layer.move(pipeline_id, layer_id, point, page_window)
|
||||
|
@ -503,13 +501,9 @@ impl IOCompositor {
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
point: Point2D<f32>) {
|
||||
let world_zoom = self.world_zoom;
|
||||
let page_window = Size2D(self.window_size.width as f32 / world_zoom,
|
||||
self.window_size.height as f32 / world_zoom);
|
||||
|
||||
let page_window = self.page_window();
|
||||
let (ask, move): (bool, bool) = match self.compositor_layer {
|
||||
Some(ref mut layer) if layer.pipeline.id == pipeline_id && !layer.hidden => {
|
||||
|
||||
(true, layer.move(pipeline_id, layer_id, point, page_window))
|
||||
}
|
||||
Some(_) | None => {
|
||||
|
@ -581,15 +575,21 @@ impl IOCompositor {
|
|||
}
|
||||
|
||||
fn on_resize_window_event(&mut self, width: uint, height: uint) {
|
||||
let new_size = Size2D(width, height);
|
||||
let new_size: TypedSize2D<DevicePixel, uint> = TypedSize2D(width, height);
|
||||
if self.window_size != new_size {
|
||||
debug!("osmain: window resized to {:u}x{:u}", width, height);
|
||||
self.window_size = new_size;
|
||||
let ConstellationChan(ref chan) = self.constellation_chan;
|
||||
chan.send(ResizedWindowMsg(new_size))
|
||||
chan.send(ResizedWindowMsg(new_size.to_untyped()))
|
||||
} else {
|
||||
debug!("osmain: dropping window resize since size is still {:u}x{:u}", width, height);
|
||||
}
|
||||
// A size change could also mean a resolution change.
|
||||
let new_hidpi_factor = self.window.hidpi_factor();
|
||||
if self.hidpi_factor != new_hidpi_factor {
|
||||
self.hidpi_factor = new_hidpi_factor;
|
||||
self.update_zoom_transform();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_load_url_window_event(&mut self, url_string: String) {
|
||||
|
@ -606,31 +606,32 @@ impl IOCompositor {
|
|||
}
|
||||
|
||||
fn on_mouse_window_event_class(&self, mouse_window_event: MouseWindowEvent) {
|
||||
let world_zoom = self.world_zoom;
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
let point = match mouse_window_event {
|
||||
MouseWindowClickEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
|
||||
MouseWindowMouseDownEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
|
||||
MouseWindowMouseUpEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom),
|
||||
MouseWindowClickEvent(_, p) => p / scale,
|
||||
MouseWindowMouseDownEvent(_, p) => p / scale,
|
||||
MouseWindowMouseUpEvent(_, p) => p / scale,
|
||||
};
|
||||
for layer in self.compositor_layer.iter() {
|
||||
layer.send_mouse_event(mouse_window_event, point);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_mouse_window_move_event_class(&self, cursor: Point2D<f32>) {
|
||||
fn on_mouse_window_move_event_class(&self, cursor: TypedPoint2D<DevicePixel, f32>) {
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
for layer in self.compositor_layer.iter() {
|
||||
layer.send_mouse_move_event(cursor);
|
||||
layer.send_mouse_move_event(cursor / scale);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_scroll_window_event(&mut self, delta: Point2D<f32>, cursor: Point2D<i32>) {
|
||||
let world_zoom = self.world_zoom;
|
||||
fn on_scroll_window_event(&mut self,
|
||||
delta: TypedPoint2D<DevicePixel, f32>,
|
||||
cursor: TypedPoint2D<DevicePixel, i32>) {
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
// TODO: modify delta to snap scroll to pixels.
|
||||
let page_delta = Point2D(delta.x as f32 / world_zoom, delta.y as f32 / world_zoom);
|
||||
let page_cursor: Point2D<f32> = Point2D(cursor.x as f32 / world_zoom,
|
||||
cursor.y as f32 / world_zoom);
|
||||
let page_window = Size2D(self.window_size.width as f32 / world_zoom,
|
||||
self.window_size.height as f32 / world_zoom);
|
||||
let page_delta = delta / scale;
|
||||
let page_cursor = cursor.as_f32() / scale;
|
||||
let page_window = self.page_window();
|
||||
let mut scroll = false;
|
||||
for layer in self.compositor_layer.mut_iter() {
|
||||
scroll = layer.handle_scroll_event(page_delta, page_cursor, page_window) || scroll;
|
||||
|
@ -639,27 +640,45 @@ impl IOCompositor {
|
|||
self.ask_for_tiles();
|
||||
}
|
||||
|
||||
fn device_pixels_per_screen_px(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||
match self.opts.device_pixels_per_px {
|
||||
Some(device_pixels_per_px) => device_pixels_per_px,
|
||||
None => match self.opts.output_file {
|
||||
Some(_) => ScaleFactor(1.0),
|
||||
None => self.hidpi_factor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn device_pixels_per_page_px(&self) -> ScaleFactor<PagePx, DevicePixel, f32> {
|
||||
self.world_zoom * self.device_pixels_per_screen_px()
|
||||
}
|
||||
|
||||
fn update_zoom_transform(&mut self) {
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
self.root_layer.common.borrow_mut().set_transform(identity().scale(scale.get(), scale.get(), 1f32));
|
||||
}
|
||||
|
||||
fn on_zoom_window_event(&mut self, magnification: f32) {
|
||||
self.zoom_action = true;
|
||||
self.zoom_time = precise_time_s();
|
||||
let old_world_zoom = self.world_zoom;
|
||||
let window_size = &self.window_size;
|
||||
let window_size = self.window_size.as_f32();
|
||||
|
||||
// Determine zoom amount
|
||||
self.world_zoom = (self.world_zoom * magnification).max(1.0);
|
||||
self.world_zoom = ScaleFactor((self.world_zoom.get() * magnification).max(1.0));
|
||||
let world_zoom = self.world_zoom;
|
||||
|
||||
{
|
||||
self.root_layer.common.borrow_mut().set_transform(identity().scale(world_zoom, world_zoom, 1f32));
|
||||
}
|
||||
self.update_zoom_transform();
|
||||
|
||||
// Scroll as needed
|
||||
let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5,
|
||||
window_size.height as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5);
|
||||
let page_delta = TypedPoint2D(
|
||||
window_size.width.get() * (world_zoom.inv() - old_world_zoom.inv()).get() * 0.5,
|
||||
window_size.height.get() * (world_zoom.inv() - old_world_zoom.inv()).get() * 0.5);
|
||||
// TODO: modify delta to snap scroll to pixels.
|
||||
let page_cursor = Point2D(-1f32, -1f32); // Make sure this hits the base layer
|
||||
let page_window = Size2D(window_size.width as f32 / world_zoom,
|
||||
window_size.height as f32 / world_zoom);
|
||||
let page_cursor = TypedPoint2D(-1f32, -1f32); // Make sure this hits the base layer
|
||||
let page_window = self.page_window();
|
||||
|
||||
for layer in self.compositor_layer.mut_iter() {
|
||||
layer.handle_scroll_event(page_delta, page_cursor, page_window);
|
||||
}
|
||||
|
@ -678,15 +697,14 @@ impl IOCompositor {
|
|||
|
||||
/// Get BufferRequests from each layer.
|
||||
fn ask_for_tiles(&mut self) {
|
||||
let world_zoom = self.world_zoom;
|
||||
let window_size_page = Size2D(self.window_size.width as f32 / world_zoom,
|
||||
self.window_size.height as f32 / world_zoom);
|
||||
let scale = self.device_pixels_per_page_px();
|
||||
let page_window = self.page_window();
|
||||
for layer in self.compositor_layer.mut_iter() {
|
||||
if !layer.hidden {
|
||||
let rect = Rect(Point2D(0f32, 0f32), window_size_page);
|
||||
let rect = Rect(Point2D(0f32, 0f32), page_window.to_untyped());
|
||||
let recomposite = layer.get_buffer_request(&self.graphics_context,
|
||||
rect,
|
||||
world_zoom) ||
|
||||
scale.get()) ||
|
||||
self.recomposite;
|
||||
self.recomposite = recomposite;
|
||||
} else {
|
||||
|
@ -699,7 +717,7 @@ impl IOCompositor {
|
|||
profile(time::CompositingCategory, self.profiler_chan.clone(), || {
|
||||
debug!("compositor: compositing");
|
||||
// Adjust the layer dimensions as necessary to correspond to the size of the window.
|
||||
self.scene.size = self.window.size();
|
||||
self.scene.size = self.window.size().to_untyped();
|
||||
// Render the scene.
|
||||
match self.compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
|
@ -717,7 +735,7 @@ impl IOCompositor {
|
|||
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
|
||||
if self.load_complete && self.ready_state == FinishedLoading
|
||||
&& self.opts.output_file.is_some() {
|
||||
let (width, height) = (self.window_size.width as uint, self.window_size.height as uint);
|
||||
let (width, height) = (self.window_size.width.get(), self.window_size.height.get());
|
||||
let path = from_str::<Path>(self.opts.output_file.get_ref().as_slice()).unwrap();
|
||||
let mut pixels = gl2::read_pixels(0, 0,
|
||||
width as gl2::GLsizei,
|
||||
|
|
|
@ -8,10 +8,11 @@ use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEve
|
|||
use windowing::{MouseWindowMouseUpEvent};
|
||||
|
||||
use azure::azure_hl::Color;
|
||||
use geom::length::Length;
|
||||
use geom::matrix::identity;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use geom::point::{Point2D, TypedPoint2D};
|
||||
use geom::rect::{Rect, TypedRect};
|
||||
use geom::size::{Size2D, TypedSize2D};
|
||||
use gfx::render_task::{ReRenderMsg, UnusedBufferMsg};
|
||||
use gfx;
|
||||
use layers::layers::{ContainerLayerKind, ContainerLayer, Flip, NoFlip, TextureLayer};
|
||||
|
@ -23,6 +24,7 @@ use script::script_task::{ScriptChan, SendEventMsg};
|
|||
use servo_msg::compositor_msg::{Epoch, FixedPosition, LayerBuffer, LayerBufferSet, LayerId};
|
||||
use servo_msg::compositor_msg::{ScrollPolicy, Tile};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use servo_util::geometry::PagePx;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
|
@ -59,7 +61,7 @@ pub struct CompositorLayer {
|
|||
|
||||
/// The offset of the page due to scrolling. (0,0) is when the window sees the
|
||||
/// top left corner of the page.
|
||||
pub scroll_offset: Point2D<f32>,
|
||||
pub scroll_offset: TypedPoint2D<PagePx, f32>,
|
||||
|
||||
/// This layer's children. These could be iframes or any element which
|
||||
/// differs in scroll behavior from its parent. Each is associated with a
|
||||
|
@ -169,7 +171,7 @@ impl CompositorLayer {
|
|||
id: layer_id,
|
||||
bounds: bounds,
|
||||
page_size: page_size,
|
||||
scroll_offset: Point2D(0f32, 0f32),
|
||||
scroll_offset: TypedPoint2D(0f32, 0f32),
|
||||
children: vec!(),
|
||||
quadtree: match page_size {
|
||||
None => NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)),
|
||||
|
@ -202,7 +204,7 @@ impl CompositorLayer {
|
|||
id: LayerId::null(),
|
||||
bounds: Rect(Point2D(0f32, 0f32), page_size),
|
||||
page_size: Some(page_size),
|
||||
scroll_offset: Point2D(0f32, 0f32),
|
||||
scroll_offset: TypedPoint2D(0f32, 0f32),
|
||||
children: vec!(),
|
||||
quadtree: NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)),
|
||||
root_layer: Rc::new(ContainerLayer()),
|
||||
|
@ -285,9 +287,9 @@ impl CompositorLayer {
|
|||
/// mouse is over child layers first. If a layer successfully scrolled, returns true; otherwise
|
||||
/// returns false, so a parent layer can scroll instead.
|
||||
pub fn handle_scroll_event(&mut self,
|
||||
delta: Point2D<f32>,
|
||||
cursor: Point2D<f32>,
|
||||
window_size: Size2D<f32>)
|
||||
delta: TypedPoint2D<PagePx, f32>,
|
||||
cursor: TypedPoint2D<PagePx, f32>,
|
||||
window_size: TypedSize2D<PagePx, f32>)
|
||||
-> bool {
|
||||
// If this layer is hidden, neither it nor its children will scroll.
|
||||
if self.hidden {
|
||||
|
@ -308,6 +310,7 @@ impl CompositorLayer {
|
|||
error!("CompositorLayer: unable to perform cursor hit test for layer");
|
||||
}
|
||||
Some(rect) => {
|
||||
let rect: TypedRect<PagePx, f32> = Rect::from_untyped(&rect);
|
||||
if cursor.x >= rect.origin.x && cursor.x < rect.origin.x + rect.size.width
|
||||
&& cursor.y >= rect.origin.y && cursor.y < rect.origin.y + rect.size.height
|
||||
&& child.child.handle_scroll_event(delta,
|
||||
|
@ -329,12 +332,17 @@ impl CompositorLayer {
|
|||
Some(size) => size,
|
||||
None => fail!("CompositorLayer: tried to scroll with no page size set"),
|
||||
};
|
||||
let min_x = (window_size.width - page_size.width).min(0.0);
|
||||
self.scroll_offset.x = self.scroll_offset.x.clamp(&min_x, &0.0);
|
||||
let min_y = (window_size.height - page_size.height).min(0.0);
|
||||
self.scroll_offset.y = self.scroll_offset.y.clamp(&min_y, &0.0);
|
||||
|
||||
if old_origin - self.scroll_offset == Point2D(0f32, 0f32) {
|
||||
let window_size = window_size.to_untyped();
|
||||
let scroll_offset = self.scroll_offset.to_untyped();
|
||||
|
||||
let min_x = (window_size.width - page_size.width).min(0.0);
|
||||
self.scroll_offset.x = Length(scroll_offset.x.clamp(&min_x, &0.0));
|
||||
|
||||
let min_y = (window_size.height - page_size.height).min(0.0);
|
||||
self.scroll_offset.y = Length(scroll_offset.y.clamp(&min_y, &0.0));
|
||||
|
||||
if old_origin - self.scroll_offset == TypedPoint2D(0f32, 0f32) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -358,7 +366,7 @@ impl CompositorLayer {
|
|||
|
||||
/// Actually scrolls the descendants of a layer that scroll. This is called by
|
||||
/// `handle_scroll_event` above when it determines that a layer wants to scroll.
|
||||
fn scroll(&mut self, scroll_offset: Point2D<f32>) -> bool {
|
||||
fn scroll(&mut self, scroll_offset: TypedPoint2D<PagePx, f32>) -> bool {
|
||||
let mut result = false;
|
||||
|
||||
// Only scroll this layer if it's not fixed-positioned.
|
||||
|
@ -367,7 +375,7 @@ impl CompositorLayer {
|
|||
self.scroll_offset = scroll_offset;
|
||||
|
||||
self.root_layer.common.borrow_mut().set_transform(
|
||||
identity().translate(self.scroll_offset.x, self.scroll_offset.y, 0.0));
|
||||
identity().translate(self.scroll_offset.x.get(), self.scroll_offset.y.get(), 0.0));
|
||||
|
||||
result = true
|
||||
}
|
||||
|
@ -382,7 +390,7 @@ impl CompositorLayer {
|
|||
// Takes in a MouseWindowEvent, determines if it should be passed to children, and
|
||||
// sends the event off to the appropriate pipeline. NB: the cursor position is in
|
||||
// page coordinates.
|
||||
pub fn send_mouse_event(&self, event: MouseWindowEvent, cursor: Point2D<f32>) {
|
||||
pub fn send_mouse_event(&self, event: MouseWindowEvent, cursor: TypedPoint2D<PagePx, f32>) {
|
||||
let cursor = cursor - self.scroll_offset;
|
||||
for child in self.children.iter().filter(|&x| !x.child.hidden) {
|
||||
match *child.container.scissor.borrow() {
|
||||
|
@ -390,6 +398,7 @@ impl CompositorLayer {
|
|||
error!("CompositorLayer: unable to perform cursor hit test for layer");
|
||||
}
|
||||
Some(rect) => {
|
||||
let rect: TypedRect<PagePx, f32> = Rect::from_untyped(&rect);
|
||||
if cursor.x >= rect.origin.x && cursor.x < rect.origin.x + rect.size.width
|
||||
&& cursor.y >= rect.origin.y && cursor.y < rect.origin.y + rect.size.height {
|
||||
child.child.send_mouse_event(event, cursor - rect.origin);
|
||||
|
@ -401,16 +410,16 @@ impl CompositorLayer {
|
|||
|
||||
// This mouse event is mine!
|
||||
let message = match event {
|
||||
MouseWindowClickEvent(button, _) => ClickEvent(button, cursor),
|
||||
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor),
|
||||
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor),
|
||||
MouseWindowClickEvent(button, _) => ClickEvent(button, cursor.to_untyped()),
|
||||
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor.to_untyped()),
|
||||
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor.to_untyped()),
|
||||
};
|
||||
let ScriptChan(ref chan) = self.pipeline.script_chan;
|
||||
let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message));
|
||||
}
|
||||
|
||||
pub fn send_mouse_move_event(&self, cursor: Point2D<f32>) {
|
||||
let message = MouseMoveEvent(cursor);
|
||||
pub fn send_mouse_move_event(&self, cursor: TypedPoint2D<PagePx, f32>) {
|
||||
let message = MouseMoveEvent(cursor.to_untyped());
|
||||
let ScriptChan(ref chan) = self.pipeline.script_chan;
|
||||
let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message));
|
||||
}
|
||||
|
@ -453,8 +462,9 @@ impl CompositorLayer {
|
|||
match *x.container.scissor.borrow() {
|
||||
Some(scissor) => {
|
||||
let mut new_rect = window_rect;
|
||||
new_rect.origin.x = new_rect.origin.x - x.child.scroll_offset.x;
|
||||
new_rect.origin.y = new_rect.origin.y - x.child.scroll_offset.y;
|
||||
let offset = x.child.scroll_offset.to_untyped();
|
||||
new_rect.origin.x = new_rect.origin.x - offset.x;
|
||||
new_rect.origin.y = new_rect.origin.y - offset.y;
|
||||
match new_rect.intersection(&scissor) {
|
||||
Some(new_rect) => {
|
||||
// Child layers act as if they are rendered at (0,0), so we
|
||||
|
@ -535,7 +545,7 @@ impl CompositorLayer {
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
new_size: Size2D<f32>,
|
||||
window_size: Size2D<f32>,
|
||||
window_size: TypedSize2D<PagePx, f32>,
|
||||
epoch: Epoch)
|
||||
-> bool {
|
||||
debug!("compositor_layer: starting resize()");
|
||||
|
@ -562,7 +572,7 @@ impl CompositorLayer {
|
|||
}
|
||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
||||
// to make sure the scroll isn't propagated downwards.
|
||||
self.handle_scroll_event(Point2D(0f32, 0f32), Point2D(-1f32, -1f32), window_size);
|
||||
self.handle_scroll_event(TypedPoint2D(0f32, 0f32), TypedPoint2D(-1f32, -1f32), window_size);
|
||||
self.hidden = false;
|
||||
self.set_occlusions();
|
||||
true
|
||||
|
@ -572,7 +582,7 @@ impl CompositorLayer {
|
|||
pipeline_id: PipelineId,
|
||||
layer_id: LayerId,
|
||||
origin: Point2D<f32>,
|
||||
window_size: Size2D<f32>)
|
||||
window_size: TypedSize2D<PagePx, f32>)
|
||||
-> bool {
|
||||
// Search children for the right layer to move.
|
||||
if self.pipeline.id != pipeline_id || self.id != layer_id {
|
||||
|
@ -587,20 +597,23 @@ impl CompositorLayer {
|
|||
|
||||
// Scroll this layer!
|
||||
let old_origin = self.scroll_offset;
|
||||
self.scroll_offset = Point2D(0f32, 0f32) - origin;
|
||||
self.scroll_offset = Point2D::from_untyped(&(origin * -1.0));
|
||||
|
||||
// bounds checking
|
||||
let page_size = match self.page_size {
|
||||
Some(size) => size,
|
||||
None => fail!("CompositorLayer: tried to scroll with no page size set"),
|
||||
};
|
||||
let window_size = window_size.to_untyped();
|
||||
let scroll_offset = self.scroll_offset.to_untyped();
|
||||
|
||||
let min_x = (window_size.width - page_size.width).min(0.0);
|
||||
self.scroll_offset.x = self.scroll_offset.x.clamp(&min_x, &0.0);
|
||||
self.scroll_offset.x = Length(scroll_offset.x.clamp(&min_x, &0.0));
|
||||
let min_y = (window_size.height - page_size.height).min(0.0);
|
||||
self.scroll_offset.y = self.scroll_offset.y.clamp(&min_y, &0.0);
|
||||
self.scroll_offset.y = Length(scroll_offset.y.clamp(&min_y, &0.0));
|
||||
|
||||
// check to see if we scrolled
|
||||
if old_origin - self.scroll_offset == Point2D(0f32, 0f32) {
|
||||
if old_origin - self.scroll_offset == TypedPoint2D(0f32, 0f32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -669,9 +682,10 @@ impl CompositorLayer {
|
|||
Some(scissor) => {
|
||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the
|
||||
// cursor position to make sure the scroll isn't propagated downwards.
|
||||
child.handle_scroll_event(Point2D(0f32, 0f32),
|
||||
Point2D(-1f32, -1f32),
|
||||
scissor.size);
|
||||
let size: TypedSize2D<PagePx, f32> = Size2D::from_untyped(&scissor.size);
|
||||
child.handle_scroll_event(TypedPoint2D(0f32, 0f32),
|
||||
TypedPoint2D(-1f32, -1f32),
|
||||
size);
|
||||
child.hidden = false;
|
||||
}
|
||||
None => {} // Nothing to do
|
||||
|
|
|
@ -19,10 +19,12 @@ use std::cell::{Cell, RefCell};
|
|||
use std::comm::Receiver;
|
||||
use std::rc::Rc;
|
||||
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::point::{Point2D, TypedPoint2D};
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::TypedSize2D;
|
||||
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
|
||||
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
|
||||
use servo_util::geometry::{ScreenPx, DevicePixel};
|
||||
|
||||
use glfw;
|
||||
use glfw::Context;
|
||||
|
@ -144,9 +146,9 @@ impl WindowMethods<Application> for Window {
|
|||
}
|
||||
|
||||
/// Returns the size of the window.
|
||||
fn size(&self) -> Size2D<f32> {
|
||||
fn size(&self) -> TypedSize2D<DevicePixel, f32> {
|
||||
let (width, height) = self.glfw_window.get_framebuffer_size();
|
||||
Size2D(width as f32, height as f32)
|
||||
TypedSize2D(width as f32, height as f32)
|
||||
}
|
||||
|
||||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
|
@ -193,10 +195,10 @@ impl WindowMethods<Application> for Window {
|
|||
self.update_window_title()
|
||||
}
|
||||
|
||||
fn hidpi_factor(&self) -> f32 {
|
||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||
let (backing_size, _) = self.glfw_window.get_framebuffer_size();
|
||||
let (window_size, _) = self.glfw_window.get_size();
|
||||
(backing_size as f32) / (window_size as f32)
|
||||
ScaleFactor((backing_size as f32) / (window_size as f32))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +229,8 @@ impl Window {
|
|||
}
|
||||
},
|
||||
glfw::CursorPosEvent(xpos, ypos) => {
|
||||
self.event_queue.borrow_mut().push(MouseWindowMoveEventClass(Point2D(xpos as f32, ypos as f32)));
|
||||
self.event_queue.borrow_mut().push(
|
||||
MouseWindowMoveEventClass(TypedPoint2D(xpos as f32, ypos as f32)));
|
||||
},
|
||||
glfw::ScrollEvent(xpos, ypos) => {
|
||||
let dx = (xpos as f32) * 30.0;
|
||||
|
@ -241,7 +244,8 @@ impl Window {
|
|||
let x = x as f32 * hidpi;
|
||||
let y = y as f32 * hidpi;
|
||||
|
||||
self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(dx, dy), Point2D(x as i32, y as i32)));
|
||||
self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(dx, dy),
|
||||
TypedPoint2D(x as i32, y as i32)));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
@ -307,7 +311,7 @@ impl Window {
|
|||
glfw::Press => {
|
||||
self.mouse_down_point.set(Point2D(x, y));
|
||||
self.mouse_down_button.set(Some(button));
|
||||
MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
|
||||
MouseWindowMouseDownEvent(button as uint, TypedPoint2D(x as f32, y as f32))
|
||||
}
|
||||
glfw::Release => {
|
||||
match self.mouse_down_button.get() {
|
||||
|
@ -318,13 +322,13 @@ impl Window {
|
|||
pixel_dist.y * pixel_dist.y) as f64).sqrt();
|
||||
if pixel_dist < max_pixel_dist {
|
||||
let click_event = MouseWindowClickEvent(button as uint,
|
||||
Point2D(x as f32, y as f32));
|
||||
TypedPoint2D(x as f32, y as f32));
|
||||
self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
|
||||
}
|
||||
}
|
||||
Some(_) => (),
|
||||
}
|
||||
MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
|
||||
MouseWindowMouseUpEvent(button as uint, TypedPoint2D(x as f32, y as f32))
|
||||
}
|
||||
_ => fail!("I cannot recognize the type of mouse action that occured. :-(")
|
||||
};
|
||||
|
|
|
@ -14,10 +14,12 @@ use alert::{Alert, AlertMethods};
|
|||
use libc::{c_int, c_uchar};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::point::{Point2D, TypedPoint2D};
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::TypedSize2D;
|
||||
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
|
||||
use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};
|
||||
use servo_util::geometry::{ScreenPx, DevicePixel};
|
||||
|
||||
use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
|
||||
use glut::glut::WindowWidth;
|
||||
|
@ -118,11 +120,15 @@ impl WindowMethods<Application> for Window {
|
|||
match button {
|
||||
3 => {
|
||||
let tmp = local_window();
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(
|
||||
TypedPoint2D(0.0, 5.0 as f32),
|
||||
TypedPoint2D(0.0 as i32, 5.0 as i32)));
|
||||
},
|
||||
4 => {
|
||||
let tmp = local_window();
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(
|
||||
TypedPoint2D(0.0, -5.0 as f32),
|
||||
TypedPoint2D(0.0 as i32, -5.0 as i32)));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
@ -139,8 +145,8 @@ impl WindowMethods<Application> for Window {
|
|||
}
|
||||
|
||||
/// Returns the size of the window.
|
||||
fn size(&self) -> Size2D<f32> {
|
||||
Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
|
||||
fn size(&self) -> TypedSize2D<DevicePixel, f32> {
|
||||
TypedSize2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
|
||||
}
|
||||
|
||||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
|
@ -179,9 +185,9 @@ impl WindowMethods<Application> for Window {
|
|||
//self.update_window_title()
|
||||
}
|
||||
|
||||
fn hidpi_factor(&self) -> f32 {
|
||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
|
||||
//FIXME: Do nothing in GLUT now.
|
||||
1f32
|
||||
ScaleFactor(1.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,8 +224,10 @@ impl Window {
|
|||
42 => self.load_url(),
|
||||
43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)),
|
||||
45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)),
|
||||
56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))),
|
||||
50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))),
|
||||
56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(0.0, 5.0 as f32),
|
||||
TypedPoint2D(0.0 as i32, 5.0 as i32))),
|
||||
50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(0.0, -5.0 as f32),
|
||||
TypedPoint2D(0.0 as i32, -5.0 as i32))),
|
||||
127 => {
|
||||
if (modifiers & ACTIVE_SHIFT) != 0 {
|
||||
self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));
|
||||
|
@ -240,7 +248,7 @@ impl Window {
|
|||
glut::MOUSE_DOWN => {
|
||||
self.mouse_down_point.set(Point2D(x, y));
|
||||
self.mouse_down_button.set(button);
|
||||
MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
|
||||
MouseWindowMouseDownEvent(button as uint, TypedPoint2D(x as f32, y as f32))
|
||||
}
|
||||
glut::MOUSE_UP => {
|
||||
if self.mouse_down_button.get() == button {
|
||||
|
@ -249,11 +257,11 @@ impl Window {
|
|||
pixel_dist.y * pixel_dist.y) as f32).sqrt();
|
||||
if pixel_dist < max_pixel_dist {
|
||||
let click_event = MouseWindowClickEvent(button as uint,
|
||||
Point2D(x as f32, y as f32));
|
||||
TypedPoint2D(x as f32, y as f32));
|
||||
self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
|
||||
}
|
||||
}
|
||||
MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
|
||||
MouseWindowMouseUpEvent(button as uint, TypedPoint2D(x as f32, y as f32))
|
||||
}
|
||||
_ => fail!("I cannot recognize the type of mouse action that occured. :-(")
|
||||
};
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
|
||||
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
|
||||
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::point::TypedPoint2D;
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use geom::size::TypedSize2D;
|
||||
use servo_msg::compositor_msg::{ReadyState, RenderState};
|
||||
use servo_util::geometry::{ScreenPx, DevicePixel};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub enum MouseWindowEvent {
|
||||
MouseWindowClickEvent(uint, Point2D<f32>),
|
||||
MouseWindowMouseDownEvent(uint, Point2D<f32>),
|
||||
MouseWindowMouseUpEvent(uint, Point2D<f32>),
|
||||
MouseWindowClickEvent(uint, TypedPoint2D<DevicePixel, f32>),
|
||||
MouseWindowMouseDownEvent(uint, TypedPoint2D<DevicePixel, f32>),
|
||||
MouseWindowMouseUpEvent(uint, TypedPoint2D<DevicePixel, f32>),
|
||||
}
|
||||
|
||||
pub enum WindowNavigateMsg {
|
||||
|
@ -36,9 +38,9 @@ pub enum WindowEvent {
|
|||
/// Sent when a mouse hit test is to be performed.
|
||||
MouseWindowEventClass(MouseWindowEvent),
|
||||
/// Sent when a mouse move.
|
||||
MouseWindowMoveEventClass(Point2D<f32>),
|
||||
MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>),
|
||||
/// Sent when the user scrolls. Includes the current cursor position.
|
||||
ScrollWindowEvent(Point2D<f32>, Point2D<i32>),
|
||||
ScrollWindowEvent(TypedPoint2D<DevicePixel, f32>, TypedPoint2D<DevicePixel, i32>),
|
||||
/// Sent when the user zooms.
|
||||
ZoomWindowEvent(f32),
|
||||
/// Sent when the user uses chrome navigation (i.e. backspace or shift-backspace).
|
||||
|
@ -58,7 +60,7 @@ pub trait WindowMethods<A> {
|
|||
/// Creates a new window.
|
||||
fn new(app: &A, is_foreground: bool) -> Rc<Self>;
|
||||
/// Returns the size of the window.
|
||||
fn size(&self) -> Size2D<f32>;
|
||||
fn size(&self) -> TypedSize2D<DevicePixel, f32>;
|
||||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
fn present(&self);
|
||||
|
||||
|
@ -71,6 +73,6 @@ pub trait WindowMethods<A> {
|
|||
fn set_render_state(&self, render_state: RenderState);
|
||||
|
||||
/// Returns the hidpi factor of the monitor.
|
||||
fn hidpi_factor(&self) -> f32;
|
||||
fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,41 @@ use std::default::Default;
|
|||
use std::num::{NumCast, One, Zero};
|
||||
use std::fmt;
|
||||
|
||||
// Units for use with geom::length and geom::scale_factor.
|
||||
|
||||
/// One hardware pixel.
|
||||
///
|
||||
/// This unit corresponds to the smallest addressable element of the display hardware.
|
||||
pub enum DevicePixel {}
|
||||
|
||||
/// A normalized "pixel" at the default resolution for the display.
|
||||
///
|
||||
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
|
||||
/// should approximate a device-independent reference length. This unit corresponds to Android's
|
||||
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
|
||||
///
|
||||
/// The relationship between DevicePixel and ScreenPx is defined by the OS. On most low-dpi
|
||||
/// screens, one ScreenPx is equal to one DevicePixel. But on high-density screens it can be
|
||||
/// some larger number. For example, by default on Apple "retina" displays, one ScreenPx equals
|
||||
/// two DevicePixels. On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
|
||||
///
|
||||
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
|
||||
/// `servo::windowing::WindowMethods::hidpi_factor`.
|
||||
pub enum ScreenPx {}
|
||||
|
||||
/// One CSS "px" in the root coordinate system for the content document.
|
||||
///
|
||||
///
|
||||
/// PagePx is equal to ScreenPx multiplied by a "zoom" factor controlled by the user. At the
|
||||
/// default zoom level of 100%, one PagePx is equal to one ScreenPx. However, if the document
|
||||
/// is zoomed in or out then this scale may be larger or smaller.
|
||||
pub enum PagePx {}
|
||||
|
||||
// An Au is an "App Unit" and represents 1/60th of a CSS pixel. It was
|
||||
// originally proposed in 2002 as a standard unit of measure in Gecko.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.
|
||||
//
|
||||
// FIXME: Implement Au using Length and ScaleFactor instead of a custom type.
|
||||
#[deriving(Clone, Eq, Ord, Zero)]
|
||||
pub struct Au(pub i32);
|
||||
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
//! Configuration options for a single run of the servo application. Created
|
||||
//! from command line arguments.
|
||||
|
||||
use geometry::{DevicePixel, ScreenPx};
|
||||
|
||||
use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend};
|
||||
use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend};
|
||||
use geom::scale_factor::ScaleFactor;
|
||||
use getopts;
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
|
@ -36,7 +39,7 @@ pub struct Opts {
|
|||
|
||||
/// The ratio of device pixels per px at the default scale. If unspecified, will use the
|
||||
/// platform default setting.
|
||||
pub device_pixels_per_px: Option<f32>,
|
||||
pub device_pixels_per_px: Option<ScaleFactor<ScreenPx, DevicePixel, f32>>,
|
||||
|
||||
/// `None` to disable the profiler or `Some` with an interval in seconds to enable it and cause
|
||||
/// it to produce output on that interval (`-p`).
|
||||
|
@ -136,7 +139,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> {
|
|||
};
|
||||
|
||||
let device_pixels_per_px = opt_match.opt_str("device-pixel-ratio").map(|dppx_str|
|
||||
from_str(dppx_str.as_slice()).unwrap()
|
||||
ScaleFactor(from_str(dppx_str.as_slice()).unwrap())
|
||||
);
|
||||
|
||||
let n_render_threads: uint = match opt_match.opt_str("t") {
|
||||
|
|
Загрузка…
Ссылка в новой задаче