auto merge of #2603 : mbrubeck/servo/units, r=pcwalton

This is a rebased, squashed, and updated version of #2444.
This commit is contained in:
bors-servo 2014-06-06 16:04:34 -04:00
commit 6c382243c4
7 changed files with 213 additions and 132 deletions

View file

@ -16,9 +16,10 @@ use windowing::{WindowEvent, WindowMethods, WindowNavigateMsg, ZoomWindowEvent};
use azure::azure_hl::{SourceSurfaceMethods, Color}; use azure::azure_hl::{SourceSurfaceMethods, Color};
use azure::azure_hl; use azure::azure_hl;
use geom::matrix::identity; use geom::matrix::identity;
use geom::point::Point2D; use geom::point::{Point2D, TypedPoint2D};
use geom::rect::Rect; 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::layers::{ContainerLayer, ContainerLayerKind};
use layers::platform::surface::NativeCompositingGraphicsContext; use layers::platform::surface::NativeCompositingGraphicsContext;
use layers::rendergl; 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::{ConstellationChan, ExitMsg, LoadUrlMsg, NavigateMsg};
use servo_msg::constellation_msg::{PipelineId, ResizedWindowMsg}; use servo_msg::constellation_msg::{PipelineId, ResizedWindowMsg};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_util::geometry::{DevicePixel, PagePx, ScreenPx};
use servo_util::opts::Opts; use servo_util::opts::Opts;
use servo_util::time::{profile, ProfilerChan}; use servo_util::time::{profile, ProfilerChan};
use servo_util::{time, url}; use servo_util::{time, url};
@ -60,7 +62,10 @@ pub struct IOCompositor {
scene: Scene, scene: Scene,
/// The application window size. /// 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. /// The platform-specific graphics context.
graphics_context: NativeCompositingGraphicsContext, graphics_context: NativeCompositingGraphicsContext,
@ -78,7 +83,7 @@ pub struct IOCompositor {
recomposite: bool, recomposite: bool,
/// Keeps track of the current zoom factor. /// Keeps track of the current zoom factor.
world_zoom: f32, world_zoom: ScaleFactor<PagePx, ScreenPx, f32>,
/// Tracks whether the zoom action has happend recently. /// Tracks whether the zoom action has happend recently.
zoom_action: bool, 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. // list. This is only here because we don't have that logic in the renderer yet.
let root_layer = Rc::new(ContainerLayer()); let root_layer = Rc::new(ContainerLayer());
let window_size = window.size(); let window_size = window.size();
let hidpi_factor = window.hidpi_factor();
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));
IOCompositor { IOCompositor {
window: window, window: window,
@ -142,14 +138,15 @@ impl IOCompositor {
context: rendergl::init_render_context(), context: rendergl::init_render_context(),
root_layer: root_layer.clone(), root_layer: root_layer.clone(),
root_pipeline: None, root_pipeline: None,
scene: Scene(ContainerLayerKind(root_layer), window_size, identity()), scene: Scene(ContainerLayerKind(root_layer), window_size.to_untyped(), identity()),
window_size: Size2D(window_size.width as uint, window_size.height as uint), window_size: window_size.as_uint(),
hidpi_factor: hidpi_factor,
graphics_context: CompositorTask::create_graphics_context(), graphics_context: CompositorTask::create_graphics_context(),
composite_ready: false, composite_ready: false,
shutting_down: false, shutting_down: false,
done: false, done: false,
recomposite: false, recomposite: false,
world_zoom: hidpi_factor, world_zoom: ScaleFactor(1.0),
zoom_action: false, zoom_action: false,
zoom_time: 0f64, zoom_time: 0f64,
ready_state: Blank, ready_state: Blank,
@ -171,6 +168,7 @@ impl IOCompositor {
port, port,
constellation_chan, constellation_chan,
profiler_chan); profiler_chan);
compositor.update_zoom_transform();
// Starts the compositor, which listens for messages on the specified port. // Starts the compositor, which listens for messages on the specified port.
compositor.run(); compositor.run();
@ -180,7 +178,7 @@ impl IOCompositor {
// Tell the constellation about the initial window size. // Tell the constellation about the initial window size.
{ {
let ConstellationChan(ref chan) = self.constellation_chan; 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. // Enter the main event loop.
@ -341,12 +339,10 @@ impl IOCompositor {
self.root_pipeline = Some(frame_tree.pipeline.clone()); self.root_pipeline = Some(frame_tree.pipeline.clone());
// Initialize the new constellation channel by sending it the root window size. // Initialize the new constellation channel by sending it the root window size.
let window_size = self.window.size(); let window_size = self.window.size().as_uint();
let window_size = Size2D(window_size.width as uint,
window_size.height as uint);
{ {
let ConstellationChan(ref chan) = new_constellation_chan; 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; self.constellation_chan = new_constellation_chan;
@ -424,17 +420,19 @@ impl IOCompositor {
self.ask_for_tiles(); 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, fn set_layer_page_size(&mut self,
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,
new_size: Size2D<f32>, new_size: Size2D<f32>,
epoch: Epoch) { epoch: Epoch) {
let page_window = self.page_window();
let (ask, move): (bool, bool) = match self.compositor_layer { let (ask, move): (bool, bool) = match self.compositor_layer {
Some(ref mut 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); layer.resize(pipeline_id, layer_id, new_size, page_window, epoch);
let move = self.fragment_point.take().map_or(false, |point| { let move = self.fragment_point.take().map_or(false, |point| {
layer.move(pipeline_id, layer_id, point, page_window) layer.move(pipeline_id, layer_id, point, page_window)
@ -503,13 +501,9 @@ impl IOCompositor {
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,
point: Point2D<f32>) { point: Point2D<f32>) {
let world_zoom = self.world_zoom; let page_window = self.page_window();
let page_window = Size2D(self.window_size.width as f32 / world_zoom,
self.window_size.height as f32 / world_zoom);
let (ask, move): (bool, bool) = match self.compositor_layer { let (ask, move): (bool, bool) = match self.compositor_layer {
Some(ref mut layer) if layer.pipeline.id == pipeline_id && !layer.hidden => { Some(ref mut layer) if layer.pipeline.id == pipeline_id && !layer.hidden => {
(true, layer.move(pipeline_id, layer_id, point, page_window)) (true, layer.move(pipeline_id, layer_id, point, page_window))
} }
Some(_) | None => { Some(_) | None => {
@ -581,15 +575,21 @@ impl IOCompositor {
} }
fn on_resize_window_event(&mut self, width: uint, height: uint) { 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 { if self.window_size != new_size {
debug!("osmain: window resized to {:u}x{:u}", width, height); debug!("osmain: window resized to {:u}x{:u}", width, height);
self.window_size = new_size; self.window_size = new_size;
let ConstellationChan(ref chan) = self.constellation_chan; let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ResizedWindowMsg(new_size)) chan.send(ResizedWindowMsg(new_size.to_untyped()))
} else { } else {
debug!("osmain: dropping window resize since size is still {:u}x{:u}", width, height); 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) { 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) { 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 { let point = match mouse_window_event {
MouseWindowClickEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom), MouseWindowClickEvent(_, p) => p / scale,
MouseWindowMouseDownEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom), MouseWindowMouseDownEvent(_, p) => p / scale,
MouseWindowMouseUpEvent(_, p) => Point2D(p.x / world_zoom, p.y / world_zoom), MouseWindowMouseUpEvent(_, p) => p / scale,
}; };
for layer in self.compositor_layer.iter() { for layer in self.compositor_layer.iter() {
layer.send_mouse_event(mouse_window_event, point); 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() { 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>) { fn on_scroll_window_event(&mut self,
let world_zoom = self.world_zoom; delta: TypedPoint2D<DevicePixel, f32>,
cursor: TypedPoint2D<DevicePixel, i32>) {
let scale = self.device_pixels_per_page_px();
// TODO: modify delta to snap scroll to pixels. // 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_delta = delta / scale;
let page_cursor: Point2D<f32> = Point2D(cursor.x as f32 / world_zoom, let page_cursor = cursor.as_f32() / scale;
cursor.y as f32 / world_zoom); let page_window = self.page_window();
let page_window = Size2D(self.window_size.width as f32 / world_zoom,
self.window_size.height as f32 / world_zoom);
let mut scroll = false; let mut scroll = false;
for layer in self.compositor_layer.mut_iter() { for layer in self.compositor_layer.mut_iter() {
scroll = layer.handle_scroll_event(page_delta, page_cursor, page_window) || scroll; scroll = layer.handle_scroll_event(page_delta, page_cursor, page_window) || scroll;
@ -639,27 +640,45 @@ impl IOCompositor {
self.ask_for_tiles(); 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) { fn on_zoom_window_event(&mut self, magnification: f32) {
self.zoom_action = true; self.zoom_action = true;
self.zoom_time = precise_time_s(); self.zoom_time = precise_time_s();
let old_world_zoom = self.world_zoom; let old_world_zoom = self.world_zoom;
let window_size = &self.window_size; let window_size = self.window_size.as_f32();
// Determine zoom amount // 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; let world_zoom = self.world_zoom;
{ self.update_zoom_transform();
self.root_layer.common.borrow_mut().set_transform(identity().scale(world_zoom, world_zoom, 1f32));
}
// Scroll as needed // Scroll as needed
let page_delta = Point2D(window_size.width as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5, let page_delta = TypedPoint2D(
window_size.height as f32 * (1.0 / world_zoom - 1.0 / old_world_zoom) * 0.5); 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. // TODO: modify delta to snap scroll to pixels.
let page_cursor = Point2D(-1f32, -1f32); // Make sure this hits the base layer let page_cursor = TypedPoint2D(-1f32, -1f32); // Make sure this hits the base layer
let page_window = Size2D(window_size.width as f32 / world_zoom, let page_window = self.page_window();
window_size.height as f32 / world_zoom);
for layer in self.compositor_layer.mut_iter() { for layer in self.compositor_layer.mut_iter() {
layer.handle_scroll_event(page_delta, page_cursor, page_window); layer.handle_scroll_event(page_delta, page_cursor, page_window);
} }
@ -678,15 +697,14 @@ impl IOCompositor {
/// Get BufferRequests from each layer. /// Get BufferRequests from each layer.
fn ask_for_tiles(&mut self) { fn ask_for_tiles(&mut self) {
let world_zoom = self.world_zoom; let scale = self.device_pixels_per_page_px();
let window_size_page = Size2D(self.window_size.width as f32 / world_zoom, let page_window = self.page_window();
self.window_size.height as f32 / world_zoom);
for layer in self.compositor_layer.mut_iter() { for layer in self.compositor_layer.mut_iter() {
if !layer.hidden { 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, let recomposite = layer.get_buffer_request(&self.graphics_context,
rect, rect,
world_zoom) || scale.get()) ||
self.recomposite; self.recomposite;
self.recomposite = recomposite; self.recomposite = recomposite;
} else { } else {
@ -699,7 +717,7 @@ impl IOCompositor {
profile(time::CompositingCategory, self.profiler_chan.clone(), || { profile(time::CompositingCategory, self.profiler_chan.clone(), || {
debug!("compositor: compositing"); debug!("compositor: compositing");
// Adjust the layer dimensions as necessary to correspond to the size of the window. // 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. // Render the scene.
match self.compositor_layer { match self.compositor_layer {
Some(ref mut layer) => { Some(ref mut layer) => {
@ -717,7 +735,7 @@ impl IOCompositor {
// self.window.present()) as OpenGL ES 2 does not have glReadBuffer(). // self.window.present()) as OpenGL ES 2 does not have glReadBuffer().
if self.load_complete && self.ready_state == FinishedLoading if self.load_complete && self.ready_state == FinishedLoading
&& self.opts.output_file.is_some() { && 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 path = from_str::<Path>(self.opts.output_file.get_ref().as_slice()).unwrap();
let mut pixels = gl2::read_pixels(0, 0, let mut pixels = gl2::read_pixels(0, 0,
width as gl2::GLsizei, width as gl2::GLsizei,

View file

@ -8,10 +8,11 @@ use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEve
use windowing::{MouseWindowMouseUpEvent}; use windowing::{MouseWindowMouseUpEvent};
use azure::azure_hl::Color; use azure::azure_hl::Color;
use geom::length::Length;
use geom::matrix::identity; use geom::matrix::identity;
use geom::point::Point2D; use geom::point::{Point2D, TypedPoint2D};
use geom::rect::Rect; use geom::rect::{Rect, TypedRect};
use geom::size::Size2D; use geom::size::{Size2D, TypedSize2D};
use gfx::render_task::{ReRenderMsg, UnusedBufferMsg}; use gfx::render_task::{ReRenderMsg, UnusedBufferMsg};
use gfx; use gfx;
use layers::layers::{ContainerLayerKind, ContainerLayer, Flip, NoFlip, TextureLayer}; 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::{Epoch, FixedPosition, LayerBuffer, LayerBufferSet, LayerId};
use servo_msg::compositor_msg::{ScrollPolicy, Tile}; use servo_msg::compositor_msg::{ScrollPolicy, Tile};
use servo_msg::constellation_msg::PipelineId; use servo_msg::constellation_msg::PipelineId;
use servo_util::geometry::PagePx;
use std::rc::Rc; use std::rc::Rc;
#[cfg(target_os="macos")] #[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 /// The offset of the page due to scrolling. (0,0) is when the window sees the
/// top left corner of the page. /// 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 /// This layer's children. These could be iframes or any element which
/// differs in scroll behavior from its parent. Each is associated with a /// differs in scroll behavior from its parent. Each is associated with a
@ -169,7 +171,7 @@ impl CompositorLayer {
id: layer_id, id: layer_id,
bounds: bounds, bounds: bounds,
page_size: page_size, page_size: page_size,
scroll_offset: Point2D(0f32, 0f32), scroll_offset: TypedPoint2D(0f32, 0f32),
children: vec!(), children: vec!(),
quadtree: match page_size { quadtree: match page_size {
None => NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)), None => NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)),
@ -202,7 +204,7 @@ impl CompositorLayer {
id: LayerId::null(), id: LayerId::null(),
bounds: Rect(Point2D(0f32, 0f32), page_size), bounds: Rect(Point2D(0f32, 0f32), page_size),
page_size: Some(page_size), page_size: Some(page_size),
scroll_offset: Point2D(0f32, 0f32), scroll_offset: TypedPoint2D(0f32, 0f32),
children: vec!(), children: vec!(),
quadtree: NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)), quadtree: NoTree(tile_size, Some(MAX_TILE_MEMORY_PER_LAYER)),
root_layer: Rc::new(ContainerLayer()), 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 /// mouse is over child layers first. If a layer successfully scrolled, returns true; otherwise
/// returns false, so a parent layer can scroll instead. /// returns false, so a parent layer can scroll instead.
pub fn handle_scroll_event(&mut self, pub fn handle_scroll_event(&mut self,
delta: Point2D<f32>, delta: TypedPoint2D<PagePx, f32>,
cursor: Point2D<f32>, cursor: TypedPoint2D<PagePx, f32>,
window_size: Size2D<f32>) window_size: TypedSize2D<PagePx, f32>)
-> bool { -> bool {
// If this layer is hidden, neither it nor its children will scroll. // If this layer is hidden, neither it nor its children will scroll.
if self.hidden { if self.hidden {
@ -308,6 +310,7 @@ impl CompositorLayer {
error!("CompositorLayer: unable to perform cursor hit test for layer"); error!("CompositorLayer: unable to perform cursor hit test for layer");
} }
Some(rect) => { 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 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 && cursor.y >= rect.origin.y && cursor.y < rect.origin.y + rect.size.height
&& child.child.handle_scroll_event(delta, && child.child.handle_scroll_event(delta,
@ -329,12 +332,17 @@ impl CompositorLayer {
Some(size) => size, Some(size) => size,
None => fail!("CompositorLayer: tried to scroll with no page size set"), 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 return false
} }
@ -358,7 +366,7 @@ impl CompositorLayer {
/// Actually scrolls the descendants of a layer that scroll. This is called by /// 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. /// `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; let mut result = false;
// Only scroll this layer if it's not fixed-positioned. // Only scroll this layer if it's not fixed-positioned.
@ -367,7 +375,7 @@ impl CompositorLayer {
self.scroll_offset = scroll_offset; self.scroll_offset = scroll_offset;
self.root_layer.common.borrow_mut().set_transform( 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 result = true
} }
@ -382,7 +390,7 @@ impl CompositorLayer {
// Takes in a MouseWindowEvent, determines if it should be passed to children, and // 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 // sends the event off to the appropriate pipeline. NB: the cursor position is in
// page coordinates. // 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; let cursor = cursor - self.scroll_offset;
for child in self.children.iter().filter(|&x| !x.child.hidden) { for child in self.children.iter().filter(|&x| !x.child.hidden) {
match *child.container.scissor.borrow() { match *child.container.scissor.borrow() {
@ -390,6 +398,7 @@ impl CompositorLayer {
error!("CompositorLayer: unable to perform cursor hit test for layer"); error!("CompositorLayer: unable to perform cursor hit test for layer");
} }
Some(rect) => { 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 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 { && cursor.y >= rect.origin.y && cursor.y < rect.origin.y + rect.size.height {
child.child.send_mouse_event(event, cursor - rect.origin); child.child.send_mouse_event(event, cursor - rect.origin);
@ -401,16 +410,16 @@ impl CompositorLayer {
// This mouse event is mine! // This mouse event is mine!
let message = match event { let message = match event {
MouseWindowClickEvent(button, _) => ClickEvent(button, cursor), MouseWindowClickEvent(button, _) => ClickEvent(button, cursor.to_untyped()),
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor), MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor.to_untyped()),
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor), MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor.to_untyped()),
}; };
let ScriptChan(ref chan) = self.pipeline.script_chan; let ScriptChan(ref chan) = self.pipeline.script_chan;
let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message)); let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message));
} }
pub fn send_mouse_move_event(&self, cursor: Point2D<f32>) { pub fn send_mouse_move_event(&self, cursor: TypedPoint2D<PagePx, f32>) {
let message = MouseMoveEvent(cursor); let message = MouseMoveEvent(cursor.to_untyped());
let ScriptChan(ref chan) = self.pipeline.script_chan; let ScriptChan(ref chan) = self.pipeline.script_chan;
let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message)); let _ = chan.send_opt(SendEventMsg(self.pipeline.id.clone(), message));
} }
@ -453,8 +462,9 @@ impl CompositorLayer {
match *x.container.scissor.borrow() { match *x.container.scissor.borrow() {
Some(scissor) => { Some(scissor) => {
let mut new_rect = window_rect; let mut new_rect = window_rect;
new_rect.origin.x = new_rect.origin.x - x.child.scroll_offset.x; let offset = x.child.scroll_offset.to_untyped();
new_rect.origin.y = new_rect.origin.y - x.child.scroll_offset.y; 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) { match new_rect.intersection(&scissor) {
Some(new_rect) => { Some(new_rect) => {
// Child layers act as if they are rendered at (0,0), so we // Child layers act as if they are rendered at (0,0), so we
@ -535,7 +545,7 @@ impl CompositorLayer {
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,
new_size: Size2D<f32>, new_size: Size2D<f32>,
window_size: Size2D<f32>, window_size: TypedSize2D<PagePx, f32>,
epoch: Epoch) epoch: Epoch)
-> bool { -> bool {
debug!("compositor_layer: starting resize()"); 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 // 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. // 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.hidden = false;
self.set_occlusions(); self.set_occlusions();
true true
@ -572,7 +582,7 @@ impl CompositorLayer {
pipeline_id: PipelineId, pipeline_id: PipelineId,
layer_id: LayerId, layer_id: LayerId,
origin: Point2D<f32>, origin: Point2D<f32>,
window_size: Size2D<f32>) window_size: TypedSize2D<PagePx, f32>)
-> bool { -> bool {
// Search children for the right layer to move. // Search children for the right layer to move.
if self.pipeline.id != pipeline_id || self.id != layer_id { if self.pipeline.id != pipeline_id || self.id != layer_id {
@ -587,20 +597,23 @@ impl CompositorLayer {
// Scroll this layer! // Scroll this layer!
let old_origin = self.scroll_offset; let old_origin = self.scroll_offset;
self.scroll_offset = Point2D(0f32, 0f32) - origin; self.scroll_offset = Point2D::from_untyped(&(origin * -1.0));
// bounds checking // bounds checking
let page_size = match self.page_size { let page_size = match self.page_size {
Some(size) => size, Some(size) => size,
None => fail!("CompositorLayer: tried to scroll with no page size set"), 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); 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); 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 // 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; return false;
} }
@ -669,9 +682,10 @@ impl CompositorLayer {
Some(scissor) => { Some(scissor) => {
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the // 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. // cursor position to make sure the scroll isn't propagated downwards.
child.handle_scroll_event(Point2D(0f32, 0f32), let size: TypedSize2D<PagePx, f32> = Size2D::from_untyped(&scissor.size);
Point2D(-1f32, -1f32), child.handle_scroll_event(TypedPoint2D(0f32, 0f32),
scissor.size); TypedPoint2D(-1f32, -1f32),
size);
child.hidden = false; child.hidden = false;
} }
None => {} // Nothing to do None => {} // Nothing to do

View file

@ -19,10 +19,12 @@ use std::cell::{Cell, RefCell};
use std::comm::Receiver; use std::comm::Receiver;
use std::rc::Rc; use std::rc::Rc;
use geom::point::Point2D; use geom::point::{Point2D, TypedPoint2D};
use geom::size::Size2D; use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState}; use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
use servo_util::geometry::{ScreenPx, DevicePixel};
use glfw; use glfw;
use glfw::Context; use glfw::Context;
@ -144,9 +146,9 @@ impl WindowMethods<Application> for Window {
} }
/// Returns the size of the 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(); 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). /// Presents the window to the screen (perhaps by page flipping).
@ -193,10 +195,10 @@ impl WindowMethods<Application> for Window {
self.update_window_title() 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 (backing_size, _) = self.glfw_window.get_framebuffer_size();
let (window_size, _) = self.glfw_window.get_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) => { 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) => { glfw::ScrollEvent(xpos, ypos) => {
let dx = (xpos as f32) * 30.0; let dx = (xpos as f32) * 30.0;
@ -241,7 +244,8 @@ impl Window {
let x = x as f32 * hidpi; let x = x as f32 * hidpi;
let y = y 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 => { glfw::Press => {
self.mouse_down_point.set(Point2D(x, y)); self.mouse_down_point.set(Point2D(x, y));
self.mouse_down_button.set(Some(button)); 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 => { glfw::Release => {
match self.mouse_down_button.get() { match self.mouse_down_button.get() {
@ -318,13 +322,13 @@ impl Window {
pixel_dist.y * pixel_dist.y) as f64).sqrt(); pixel_dist.y * pixel_dist.y) as f64).sqrt();
if pixel_dist < max_pixel_dist { if pixel_dist < max_pixel_dist {
let click_event = MouseWindowClickEvent(button as uint, 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)); self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
} }
} }
Some(_) => (), 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. :-(") _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
}; };

View file

@ -14,10 +14,12 @@ use alert::{Alert, AlertMethods};
use libc::{c_int, c_uchar}; use libc::{c_int, c_uchar};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use geom::point::Point2D; use geom::point::{Point2D, TypedPoint2D};
use geom::size::Size2D; use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState}; use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState}; use servo_msg::compositor_msg::{FinishedLoading, Blank, ReadyState};
use servo_util::geometry::{ScreenPx, DevicePixel};
use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight}; use glut::glut::{ACTIVE_SHIFT, DOUBLE, WindowHeight};
use glut::glut::WindowWidth; use glut::glut::WindowWidth;
@ -118,11 +120,15 @@ impl WindowMethods<Application> for Window {
match button { match button {
3 => { 3 => {
let tmp = local_window(); 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 => { 4 => {
let tmp = local_window(); 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. /// Returns the size of the window.
fn size(&self) -> Size2D<f32> { fn size(&self) -> TypedSize2D<DevicePixel, f32> {
Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32) TypedSize2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
} }
/// Presents the window to the screen (perhaps by page flipping). /// Presents the window to the screen (perhaps by page flipping).
@ -179,9 +185,9 @@ impl WindowMethods<Application> for Window {
//self.update_window_title() //self.update_window_title()
} }
fn hidpi_factor(&self) -> f32 { fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32> {
//FIXME: Do nothing in GLUT now. //FIXME: Do nothing in GLUT now.
1f32 ScaleFactor(1.0)
} }
} }
@ -218,8 +224,10 @@ impl Window {
42 => self.load_url(), 42 => self.load_url(),
43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)), 43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)),
45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)), 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))), 56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(0.0, 5.0 as f32),
50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))), 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 => { 127 => {
if (modifiers & ACTIVE_SHIFT) != 0 { if (modifiers & ACTIVE_SHIFT) != 0 {
self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward)); self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));
@ -240,7 +248,7 @@ impl Window {
glut::MOUSE_DOWN => { glut::MOUSE_DOWN => {
self.mouse_down_point.set(Point2D(x, y)); self.mouse_down_point.set(Point2D(x, y));
self.mouse_down_button.set(button); 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 => { glut::MOUSE_UP => {
if self.mouse_down_button.get() == button { if self.mouse_down_button.get() == button {
@ -249,11 +257,11 @@ impl Window {
pixel_dist.y * pixel_dist.y) as f32).sqrt(); pixel_dist.y * pixel_dist.y) as f32).sqrt();
if pixel_dist < max_pixel_dist { if pixel_dist < max_pixel_dist {
let click_event = MouseWindowClickEvent(button as uint, 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)); 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. :-(") _ => fail!("I cannot recognize the type of mouse action that occured. :-(")
}; };

View file

@ -4,15 +4,17 @@
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
use geom::point::Point2D; use geom::point::TypedPoint2D;
use geom::size::Size2D; use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use servo_msg::compositor_msg::{ReadyState, RenderState}; use servo_msg::compositor_msg::{ReadyState, RenderState};
use servo_util::geometry::{ScreenPx, DevicePixel};
use std::rc::Rc; use std::rc::Rc;
pub enum MouseWindowEvent { pub enum MouseWindowEvent {
MouseWindowClickEvent(uint, Point2D<f32>), MouseWindowClickEvent(uint, TypedPoint2D<DevicePixel, f32>),
MouseWindowMouseDownEvent(uint, Point2D<f32>), MouseWindowMouseDownEvent(uint, TypedPoint2D<DevicePixel, f32>),
MouseWindowMouseUpEvent(uint, Point2D<f32>), MouseWindowMouseUpEvent(uint, TypedPoint2D<DevicePixel, f32>),
} }
pub enum WindowNavigateMsg { pub enum WindowNavigateMsg {
@ -36,9 +38,9 @@ pub enum WindowEvent {
/// Sent when a mouse hit test is to be performed. /// Sent when a mouse hit test is to be performed.
MouseWindowEventClass(MouseWindowEvent), MouseWindowEventClass(MouseWindowEvent),
/// Sent when a mouse move. /// Sent when a mouse move.
MouseWindowMoveEventClass(Point2D<f32>), MouseWindowMoveEventClass(TypedPoint2D<DevicePixel, f32>),
/// Sent when the user scrolls. Includes the current cursor position. /// 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. /// Sent when the user zooms.
ZoomWindowEvent(f32), ZoomWindowEvent(f32),
/// Sent when the user uses chrome navigation (i.e. backspace or shift-backspace). /// 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. /// Creates a new window.
fn new(app: &A, is_foreground: bool) -> Rc<Self>; fn new(app: &A, is_foreground: bool) -> Rc<Self>;
/// Returns the size of the window. /// 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). /// Presents the window to the screen (perhaps by page flipping).
fn present(&self); fn present(&self);
@ -71,6 +73,6 @@ pub trait WindowMethods<A> {
fn set_render_state(&self, render_state: RenderState); fn set_render_state(&self, render_state: RenderState);
/// Returns the hidpi factor of the monitor. /// Returns the hidpi factor of the monitor.
fn hidpi_factor(&self) -> f32; fn hidpi_factor(&self) -> ScaleFactor<ScreenPx, DevicePixel, f32>;
} }

View file

@ -10,9 +10,41 @@ use std::default::Default;
use std::num::{NumCast, One, Zero}; use std::num::{NumCast, One, Zero};
use std::fmt; 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 // 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. // 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. // 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)] #[deriving(Clone, Eq, Ord, Zero)]
pub struct Au(pub i32); pub struct Au(pub i32);

View file

@ -5,8 +5,11 @@
//! Configuration options for a single run of the servo application. Created //! Configuration options for a single run of the servo application. Created
//! from command line arguments. //! from command line arguments.
use geometry::{DevicePixel, ScreenPx};
use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend}; use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend};
use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend}; use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend};
use geom::scale_factor::ScaleFactor;
use getopts; use getopts;
use std::cmp; use std::cmp;
use std::io; 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 /// The ratio of device pixels per px at the default scale. If unspecified, will use the
/// platform default setting. /// 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 /// `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`). /// 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| 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") { let n_render_threads: uint = match opt_match.opt_str("t") {