Merge pull request #2666 from mbrubeck/pinch

Separate "desktop" and "mobile" zoom calculations.
This commit is contained in:
Lars Bergstrom 2014-06-21 08:06:26 -05:00
commit 6c150724f4
13 changed files with 149 additions and 66 deletions

View file

@ -12,6 +12,7 @@ use windowing::{MouseWindowEvent, MouseWindowEventClass, MouseWindowMouseDownEve
use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent}; use windowing::{MouseWindowMouseUpEvent, MouseWindowMoveEventClass, NavigationWindowEvent};
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;
use azure::azure_hl::{SourceSurfaceMethods, Color}; use azure::azure_hl::{SourceSurfaceMethods, Color};
use azure::azure_hl; use azure::azure_hl;
@ -30,9 +31,9 @@ use png;
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdleRenderState, LayerBufferSet}; use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdleRenderState, LayerBufferSet};
use servo_msg::compositor_msg::{LayerId, ReadyState, RenderState, ScrollPolicy, Scrollable}; use servo_msg::compositor_msg::{LayerId, ReadyState, RenderState, ScrollPolicy, Scrollable};
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, WindowSizeData};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_util::geometry::{DevicePixel, PagePx, ScreenPx}; use servo_util::geometry::{DevicePixel, PagePx, ScreenPx, ViewportPx};
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};
@ -64,6 +65,13 @@ pub struct IOCompositor {
/// The application window size. /// The application window size.
window_size: TypedSize2D<DevicePixel, uint>, window_size: TypedSize2D<DevicePixel, uint>,
/// "Mobile-style" zoom that does not reflow the page.
viewport_zoom: ScaleFactor<PagePx, ViewportPx, f32>,
/// "Desktop-style" zoom that resizes the viewport to fit the window.
/// See `ViewportPx` docs in util/geom.rs for details.
page_zoom: ScaleFactor<ViewportPx, ScreenPx, f32>,
/// The device pixel ratio for this window. /// The device pixel ratio for this window.
hidpi_factor: ScaleFactor<ScreenPx, DevicePixel, f32>, hidpi_factor: ScaleFactor<ScreenPx, DevicePixel, f32>,
@ -82,9 +90,6 @@ pub struct IOCompositor {
/// Tracks whether we need to re-composite a page. /// Tracks whether we need to re-composite a page.
recomposite: bool, recomposite: bool,
/// Keeps track of the current zoom factor.
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,
@ -146,7 +151,8 @@ impl IOCompositor {
shutting_down: false, shutting_down: false,
done: false, done: false,
recomposite: false, recomposite: false,
world_zoom: ScaleFactor(1.0), page_zoom: ScaleFactor(1.0),
viewport_zoom: ScaleFactor(1.0),
zoom_action: false, zoom_action: false,
zoom_time: 0f64, zoom_time: 0f64,
ready_state: Blank, ready_state: Blank,
@ -417,10 +423,17 @@ impl IOCompositor {
self.window_size.as_f32() / self.device_pixels_per_page_px() self.window_size.as_f32() / self.device_pixels_per_page_px()
} }
/// The size of the window in screen px.
fn send_window_size(&self) { fn send_window_size(&self) {
let dppx = self.page_zoom * self.device_pixels_per_screen_px();
let initial_viewport = self.window_size.as_f32() / dppx;
let visible_viewport = initial_viewport / self.viewport_zoom;
let ConstellationChan(ref chan) = self.constellation_chan; let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ResizedWindowMsg(self.page_window())); chan.send(ResizedWindowMsg(WindowSizeData {
device_pixel_ratio: dppx,
initial_viewport: initial_viewport,
visible_viewport: visible_viewport,
}));
} }
fn set_layer_page_size(&mut self, fn set_layer_page_size(&mut self,
@ -549,6 +562,10 @@ impl IOCompositor {
self.on_zoom_window_event(magnification); self.on_zoom_window_event(magnification);
} }
PinchZoomWindowEvent(magnification) => {
self.on_pinch_zoom_window_event(magnification);
}
NavigationWindowEvent(direction) => { NavigationWindowEvent(direction) => {
self.on_navigation_window_event(direction); self.on_navigation_window_event(direction);
} }
@ -647,7 +664,7 @@ impl IOCompositor {
} }
fn device_pixels_per_page_px(&self) -> ScaleFactor<PagePx, DevicePixel, f32> { fn device_pixels_per_page_px(&self) -> ScaleFactor<PagePx, DevicePixel, f32> {
self.world_zoom * self.device_pixels_per_screen_px() self.viewport_zoom * self.page_zoom * self.device_pixels_per_screen_px()
} }
fn update_zoom_transform(&mut self) { fn update_zoom_transform(&mut self) {
@ -656,21 +673,26 @@ impl IOCompositor {
} }
fn on_zoom_window_event(&mut self, magnification: f32) { fn on_zoom_window_event(&mut self, magnification: f32) {
self.page_zoom = ScaleFactor((self.page_zoom.get() * magnification).max(1.0));
self.update_zoom_transform();
self.send_window_size();
}
fn on_pinch_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_viewport_zoom = self.viewport_zoom;
let window_size = self.window_size.as_f32(); let window_size = self.window_size.as_f32();
// Determine zoom amount self.viewport_zoom = ScaleFactor((self.viewport_zoom.get() * magnification).max(1.0));
self.world_zoom = ScaleFactor((self.world_zoom.get() * magnification).max(1.0)); let viewport_zoom = self.viewport_zoom;
let world_zoom = self.world_zoom;
self.update_zoom_transform(); self.update_zoom_transform();
// Scroll as needed // Scroll as needed
let page_delta = TypedPoint2D( let page_delta = TypedPoint2D(
window_size.width.get() * (world_zoom.inv() - old_world_zoom.inv()).get() * 0.5, window_size.width.get() * (viewport_zoom.inv() - old_viewport_zoom.inv()).get() * 0.5,
window_size.height.get() * (world_zoom.inv() - old_world_zoom.inv()).get() * 0.5); window_size.height.get() * (viewport_zoom.inv() - old_viewport_zoom.inv()).get() * 0.5);
// TODO: modify delta to snap scroll to pixels. // TODO: modify delta to snap scroll to pixels.
let page_cursor = TypedPoint2D(-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 = self.page_window(); let page_window = self.page_window();

View file

@ -4,8 +4,9 @@
use compositing::*; use compositing::*;
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, ResizedWindowMsg}; use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, ResizedWindowMsg, WindowSizeData};
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use servo_util::time; use servo_util::time;
@ -33,7 +34,11 @@ impl NullCompositor {
// Tell the constellation about the initial fake size. // Tell the constellation about the initial fake size.
{ {
let ConstellationChan(ref chan) = constellation_chan; let ConstellationChan(ref chan) = constellation_chan;
chan.send(ResizedWindowMsg(TypedSize2D(640_f32, 480_f32))); chan.send(ResizedWindowMsg(WindowSizeData {
initial_viewport: TypedSize2D(640_f32, 480_f32),
visible_viewport: TypedSize2D(640_f32, 480_f32),
device_pixel_ratio: ScaleFactor(1.0),
}));
} }
compositor.handle_message(constellation_chan); compositor.handle_message(constellation_chan);

View file

@ -6,6 +6,7 @@ use compositing::{CompositorChan, LoadComplete, SetIds, SetLayerClipRect, Shutdo
use collections::hashmap::{HashMap, HashSet}; use collections::hashmap::{HashMap, HashSet};
use geom::rect::{Rect, TypedRect}; use geom::rect::{Rect, TypedRect};
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use gfx::render_task; use gfx::render_task;
use libc; use libc;
@ -19,7 +20,7 @@ use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failu
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg}; use servo_msg::constellation_msg::{LoadCompleteMsg, LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg};
use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg}; use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg};
use servo_msg::constellation_msg::SubpageId; use servo_msg::constellation_msg::{SubpageId, WindowSizeData};
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;
@ -48,7 +49,7 @@ pub struct Constellation {
pending_frames: Vec<FrameChange>, pending_frames: Vec<FrameChange>,
pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>, pending_sizes: HashMap<(PipelineId, SubpageId), TypedRect<PagePx, f32>>,
pub profiler_chan: ProfilerChan, pub profiler_chan: ProfilerChan,
pub window_size: TypedSize2D<PagePx, f32>, pub window_size: WindowSizeData,
pub opts: Opts, pub opts: Opts,
} }
@ -261,7 +262,11 @@ impl Constellation {
pending_frames: vec!(), pending_frames: vec!(),
pending_sizes: HashMap::new(), pending_sizes: HashMap::new(),
profiler_chan: profiler_chan, profiler_chan: profiler_chan,
window_size: TypedSize2D(800_f32, 600_f32), window_size: WindowSizeData {
visible_viewport: TypedSize2D(800_f32, 600_f32),
initial_viewport: TypedSize2D(800_f32, 600_f32),
device_pixel_ratio: ScaleFactor(1.0),
},
opts: opts_clone, opts: opts_clone,
}; };
constellation.run(); constellation.run();
@ -491,7 +496,11 @@ impl Constellation {
if !already_sent.contains(&pipeline.id) { if !already_sent.contains(&pipeline.id) {
if is_active { if is_active {
let ScriptChan(ref script_chan) = pipeline.script_chan; let ScriptChan(ref script_chan) = pipeline.script_chan;
script_chan.send(ResizeMsg(pipeline.id, rect.size)); script_chan.send(ResizeMsg(pipeline.id, WindowSizeData {
visible_viewport: rect.size,
initial_viewport: rect.size * ScaleFactor(1.0),
device_pixel_ratio: self.window_size.device_pixel_ratio,
}));
self.compositor_chan.send(SetLayerClipRect(pipeline.id, self.compositor_chan.send(SetLayerClipRect(pipeline.id,
LayerId::null(), LayerId::null(),
rect.to_untyped())); rect.to_untyped()));
@ -788,7 +797,7 @@ impl Constellation {
} }
/// Called when the window is resized. /// Called when the window is resized.
fn handle_resized_window_msg(&mut self, new_size: TypedSize2D<PagePx, f32>) { fn handle_resized_window_msg(&mut self, new_size: WindowSizeData) {
let mut already_seen = HashSet::new(); let mut already_seen = HashSet::new();
for frame_tree in self.current_frame().iter() { for frame_tree in self.current_frame().iter() {
debug!("constellation sending resize message to active frame"); debug!("constellation sending resize message to active frame");

View file

@ -581,8 +581,12 @@ impl LayoutTask {
_ => false _ => false
}; };
let current_screen_size = Size2D(Au::from_page_px(data.window_size.width), // TODO: Calculate the "actual viewport":
Au::from_page_px(data.window_size.height)); // http://www.w3.org/TR/css-device-adapt/#actual-viewport
let viewport_size = data.window_size.initial_viewport;
let current_screen_size = Size2D(Au::from_frac32_px(viewport_size.width.get()),
Au::from_frac32_px(viewport_size.height.get()));
if self.screen_size != current_screen_size { if self.screen_size != current_screen_size {
all_style_damage = true all_style_damage = true
} }

View file

@ -5,7 +5,6 @@
use compositing::CompositorChan; use compositing::CompositorChan;
use layout::layout_task::LayoutTask; use layout::layout_task::LayoutTask;
use geom::size::TypedSize2D;
use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked}; use gfx::render_task::{PaintPermissionGranted, PaintPermissionRevoked};
use gfx::render_task::{RenderChan, RenderTask}; use gfx::render_task::{RenderChan, RenderTask};
use script::layout_interface::LayoutChan; use script::layout_interface::LayoutChan;
@ -13,9 +12,9 @@ use script::script_task::LoadMsg;
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan}; use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
use script::script_task; use script::script_task;
use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId}; use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId};
use servo_msg::constellation_msg::WindowSizeData;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::geometry::PagePx;
use servo_util::opts::Opts; use servo_util::opts::Opts;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
use std::rc::Rc; use std::rc::Rc;
@ -113,7 +112,7 @@ impl Pipeline {
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
resource_task: ResourceTask, resource_task: ResourceTask,
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
window_size: TypedSize2D<PagePx, f32>, window_size: WindowSizeData,
opts: Opts, opts: Opts,
url: Url) url: Url)
-> Pipeline { -> Pipeline {

View file

@ -6,7 +6,7 @@
use windowing::{ApplicationMethods, WindowEvent, WindowMethods}; use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass, MouseWindowMoveEventClass}; use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass, MouseWindowMoveEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent}; use windowing::{ScrollWindowEvent, ZoomWindowEvent, PinchZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent}; use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::RefreshWindowEvent; use windowing::RefreshWindowEvent;
use windowing::{Forward, Back}; use windowing::{Forward, Back};
@ -240,19 +240,33 @@ impl Window {
MouseWindowMoveEventClass(TypedPoint2D(xpos as f32, ypos as f32))); MouseWindowMoveEventClass(TypedPoint2D(xpos as f32, ypos as f32)));
}, },
glfw::ScrollEvent(xpos, ypos) => { glfw::ScrollEvent(xpos, ypos) => {
let dx = (xpos as f32) * 30.0; match (window.get_key(glfw::KeyLeftControl),
let dy = (ypos as f32) * 30.0; window.get_key(glfw::KeyRightControl)) {
(glfw::Press, _) | (_, glfw::Press) => {
// Ctrl-Scrollwheel simulates a "pinch zoom" gesture.
if ypos < 0.0 {
self.event_queue.borrow_mut().push(PinchZoomWindowEvent(1.0/1.1));
} else if ypos > 0.0 {
self.event_queue.borrow_mut().push(PinchZoomWindowEvent(1.1));
}
},
_ => {
let dx = (xpos as f32) * 30.0;
let dy = (ypos as f32) * 30.0;
let (x, y) = window.get_cursor_pos(); let (x, y) = window.get_cursor_pos();
//handle hidpi displays, since GLFW returns non-hi-def coordinates. //handle hidpi displays, since GLFW returns non-hi-def coordinates.
let (backing_size, _) = window.get_framebuffer_size(); let (backing_size, _) = window.get_framebuffer_size();
let (window_size, _) = window.get_size(); let (window_size, _) = window.get_size();
let hidpi = (backing_size as f32) / (window_size as f32); let hidpi = (backing_size as f32) / (window_size as f32);
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(TypedPoint2D(dx, dy),
TypedPoint2D(x as i32, y as i32)));
}
}
self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(dx, dy),
TypedPoint2D(x as i32, y as i32)));
}, },
_ => {} _ => {}
} }
@ -298,7 +312,7 @@ impl Window {
self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)); self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1));
} }
glfw::KeyMinus if mods.contains(glfw::Control) => { // Ctrl-- glfw::KeyMinus if mods.contains(glfw::Control) => { // Ctrl--
self.event_queue.borrow_mut().push(ZoomWindowEvent(0.90909090909)); self.event_queue.borrow_mut().push(ZoomWindowEvent(1.0/1.1));
} }
glfw::KeyBackspace if mods.contains(glfw::Shift) => { // Shift-Backspace glfw::KeyBackspace if mods.contains(glfw::Shift) => { // Shift-Backspace
self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward)); self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));

View file

@ -43,6 +43,8 @@ pub enum WindowEvent {
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),
/// Simulated "pinch zoom" gesture for non-touch platforms (e.g. ctrl-scrollwheel).
PinchZoomWindowEvent(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).
NavigationWindowEvent(WindowNavigateMsg), NavigationWindowEvent(WindowNavigateMsg),
/// Sent when rendering is finished. /// Sent when rendering is finished.

View file

@ -7,7 +7,8 @@
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::TypedSize2D; use geom::size::TypedSize2D;
use servo_util::geometry::PagePx; use geom::scale_factor::ScaleFactor;
use servo_util::geometry::{DevicePixel, PagePx, ViewportPx};
use std::comm::{channel, Sender, Receiver}; use std::comm::{channel, Sender, Receiver};
use url::Url; use url::Url;
@ -34,6 +35,18 @@ pub struct Failure {
pub subpage_id: Option<SubpageId>, pub subpage_id: Option<SubpageId>,
} }
pub struct WindowSizeData {
/// The size of the initial layout viewport, before parsing an
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
pub initial_viewport: TypedSize2D<ViewportPx, f32>,
/// The "viewing area" in page px. See `PagePx` documentation for details.
pub visible_viewport: TypedSize2D<PagePx, f32>,
/// The resolution of the window in dppx, not including any "pinch zoom" factor.
pub device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>,
}
/// Messages from the compositor and script to the constellation. /// Messages from the compositor and script to the constellation.
pub enum Msg { pub enum Msg {
ExitMsg, ExitMsg,
@ -45,7 +58,7 @@ pub enum Msg {
LoadIframeUrlMsg(Url, PipelineId, SubpageId, IFrameSandboxState), LoadIframeUrlMsg(Url, PipelineId, SubpageId, IFrameSandboxState),
NavigateMsg(NavigationDirection), NavigateMsg(NavigationDirection),
RendererReadyMsg(PipelineId), RendererReadyMsg(PipelineId),
ResizedWindowMsg(TypedSize2D<PagePx, f32>), ResizedWindowMsg(WindowSizeData),
} }
/// Represents the two different ways to which a page can be navigated /// Represents the two different ways to which a page can be navigated

View file

@ -10,17 +10,16 @@ use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::window::Window; use dom::window::Window;
use servo_msg::constellation_msg::WindowSizeData;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use servo_util::geometry::PagePx;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::TypedSize2D;
use time; use time;
pub enum Event_ { pub enum Event_ {
ResizeEvent(TypedSize2D<PagePx, f32>), ResizeEvent(WindowSizeData),
ReflowEvent, ReflowEvent,
ClickEvent(uint, Point2D<f32>), ClickEvent(uint, Point2D<f32>),
MouseDownEvent(uint, Point2D<f32>), MouseDownEvent(uint, Point2D<f32>),

View file

@ -11,10 +11,10 @@ use dom::node::{Node, LayoutDataRef};
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use geom::size::TypedSize2D;
use libc::c_void; use libc::c_void;
use script_task::{ScriptChan}; use script_task::{ScriptChan};
use servo_util::geometry::{Au, PagePx}; use servo_msg::constellation_msg::WindowSizeData;
use servo_util::geometry::Au;
use std::cmp; use std::cmp;
use std::comm::{channel, Receiver, Sender}; use std::comm::{channel, Receiver, Sender};
use style::Stylesheet; use style::Stylesheet;
@ -137,7 +137,7 @@ pub struct Reflow {
/// The channel through which messages can be sent back to the script task. /// The channel through which messages can be sent back to the script task.
pub script_chan: ScriptChan, pub script_chan: ScriptChan,
/// The current window size. /// The current window size.
pub window_size: TypedSize2D<PagePx, f32>, pub window_size: WindowSizeData,
/// The channel that we send a notification to. /// The channel that we send a notification to.
pub script_join_chan: Sender<()>, pub script_join_chan: Sender<()>,
/// Unique identifier /// Unique identifier

View file

@ -19,14 +19,12 @@ use layout_interface::UntrustedNodeAddress;
use script_task::ScriptChan; use script_task::ScriptChan;
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::TypedSize2D;
use js::rust::Cx; use js::rust::Cx;
use servo_msg::compositor_msg::PerformingLayout; use servo_msg::compositor_msg::PerformingLayout;
use servo_msg::compositor_msg::ScriptListener; use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::ConstellationChan; use servo_msg::constellation_msg::{ConstellationChan, WindowSizeData};
use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::geometry::PagePx;
use servo_util::namespace::Null; use servo_util::namespace::Null;
use servo_util::str::DOMString; use servo_util::str::DOMString;
use std::cell::{Cell, RefCell, Ref, RefMut}; use std::cell::{Cell, RefCell, Ref, RefMut};
@ -62,7 +60,7 @@ pub struct Page {
damage: Traceable<RefCell<Option<DocumentDamage>>>, damage: Traceable<RefCell<Option<DocumentDamage>>>,
/// The current size of the window, in pixels. /// The current size of the window, in pixels.
pub window_size: Untraceable<Cell<TypedSize2D<PagePx, f32>>>, pub window_size: Untraceable<Cell<WindowSizeData>>,
js_info: Traceable<RefCell<Option<JSPageInfo>>>, js_info: Traceable<RefCell<Option<JSPageInfo>>>,
@ -75,7 +73,7 @@ pub struct Page {
next_subpage_id: Untraceable<Cell<SubpageId>>, next_subpage_id: Untraceable<Cell<SubpageId>>,
/// Pending resize event, if any. /// Pending resize event, if any.
pub resize_event: Untraceable<Cell<Option<TypedSize2D<PagePx, f32>>>>, pub resize_event: Untraceable<Cell<Option<WindowSizeData>>>,
/// Pending scroll to fragment event, if any /// Pending scroll to fragment event, if any
pub fragment_node: Cell<Option<JS<Element>>>, pub fragment_node: Cell<Option<JS<Element>>>,
@ -119,7 +117,8 @@ impl IterablePage for Rc<Page> {
impl Page { impl Page {
pub fn new(id: PipelineId, subpage_id: Option<SubpageId>, pub fn new(id: PipelineId, subpage_id: Option<SubpageId>,
layout_chan: LayoutChan, layout_chan: LayoutChan,
window_size: TypedSize2D<PagePx, f32>, resource_task: ResourceTask, window_size: WindowSizeData,
resource_task: ResourceTask,
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
js_context: Rc<Cx>) -> Page { js_context: Rc<Cx>) -> Page {
let js_info = JSPageInfo { let js_info = JSPageInfo {

View file

@ -32,7 +32,6 @@ use layout_interface;
use page::{Page, IterablePage, Frame}; use page::{Page, IterablePage, Frame};
use geom::point::Point2D; use geom::point::Point2D;
use geom::size::TypedSize2D;
use js::jsapi::JS_CallFunctionValue; use js::jsapi::JS_CallFunctionValue;
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC}; use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
use js::jsapi::{JSContext, JSRuntime}; use js::jsapi::{JSContext, JSRuntime};
@ -43,11 +42,11 @@ use js;
use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading}; use servo_msg::compositor_msg::{FinishedLoading, LayerId, Loading};
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, LoadUrlMsg, NavigationDirection};
use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg}; use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg, WindowSizeData};
use servo_msg::constellation_msg; use servo_msg::constellation_msg;
use servo_net::image_cache_task::ImageCacheTask; use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask; use servo_net::resource_task::ResourceTask;
use servo_util::geometry::{PagePx, to_frac_px}; use servo_util::geometry::to_frac_px;
use servo_util::task::send_on_failure; use servo_util::task::send_on_failure;
use std::cell::RefCell; use std::cell::RefCell;
use std::comm::{channel, Sender, Receiver}; use std::comm::{channel, Sender, Receiver};
@ -76,13 +75,13 @@ pub enum ScriptMsg {
/// Sends a DOM event. /// Sends a DOM event.
SendEventMsg(PipelineId, Event_), SendEventMsg(PipelineId, Event_),
/// Window resized. Sends a DOM event eventually, but first we combine events. /// Window resized. Sends a DOM event eventually, but first we combine events.
ResizeMsg(PipelineId, TypedSize2D<PagePx, f32>), ResizeMsg(PipelineId, WindowSizeData),
/// Fires a JavaScript timeout. /// Fires a JavaScript timeout.
FireTimerMsg(PipelineId, TimerId), FireTimerMsg(PipelineId, TimerId),
/// Notifies script that reflow is finished. /// Notifies script that reflow is finished.
ReflowCompleteMsg(PipelineId, uint), ReflowCompleteMsg(PipelineId, uint),
/// Notifies script that window has been resized but to not take immediate action. /// Notifies script that window has been resized but to not take immediate action.
ResizeInactiveMsg(PipelineId, TypedSize2D<PagePx, f32>), ResizeInactiveMsg(PipelineId, WindowSizeData),
/// Notifies the script that a pipeline should be closed. /// Notifies the script that a pipeline should be closed.
ExitPipelineMsg(PipelineId), ExitPipelineMsg(PipelineId),
/// Notifies the script that a window associated with a particular pipeline should be closed. /// Notifies the script that a window associated with a particular pipeline should be closed.
@ -208,7 +207,7 @@ impl ScriptTask {
constellation_chan: ConstellationChan, constellation_chan: ConstellationChan,
resource_task: ResourceTask, resource_task: ResourceTask,
img_cache_task: ImageCacheTask, img_cache_task: ImageCacheTask,
window_size: TypedSize2D<PagePx, f32>) window_size: WindowSizeData)
-> Rc<ScriptTask> { -> Rc<ScriptTask> {
let (js_runtime, js_context) = ScriptTask::new_rt_and_cx(); let (js_runtime, js_context) = ScriptTask::new_rt_and_cx();
let page = Page::new(id, None, layout_chan, window_size, let page = Page::new(id, None, layout_chan, window_size,
@ -289,7 +288,7 @@ impl ScriptTask {
failure_msg: Failure, failure_msg: Failure,
resource_task: ResourceTask, resource_task: ResourceTask,
image_cache_task: ImageCacheTask, image_cache_task: ImageCacheTask,
window_size: TypedSize2D<PagePx, f32>) { window_size: WindowSizeData) {
let mut builder = TaskBuilder::new().named("ScriptTask"); let mut builder = TaskBuilder::new().named("ScriptTask");
let ConstellationChan(const_chan) = constellation_chan.clone(); let ConstellationChan(const_chan) = constellation_chan.clone();
send_on_failure(&mut builder, FailureMsg(failure_msg), const_chan); send_on_failure(&mut builder, FailureMsg(failure_msg), const_chan);
@ -463,7 +462,7 @@ impl ScriptTask {
} }
/// Window was resized, but this script was not active, so don't reflow yet /// Window was resized, but this script was not active, so don't reflow yet
fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: TypedSize2D<PagePx, f32>) { fn handle_resize_inactive_msg(&self, id: PipelineId, new_size: WindowSizeData) {
let mut page = self.page.borrow_mut(); let mut page = self.page.borrow_mut();
let page = page.find(id).expect("Received resize message for PipelineId not associated let page = page.find(id).expect("Received resize message for PipelineId not associated
with a page in the page tree. This is a bug."); with a page in the page tree. This is a bug.");

View file

@ -33,14 +33,32 @@ pub enum DevicePixel {}
/// `servo::windowing::WindowMethods::hidpi_factor`. /// `servo::windowing::WindowMethods::hidpi_factor`.
pub enum ScreenPx {} pub enum ScreenPx {}
/// One CSS "px" in the coordinate system of the "initial viewport":
/// http://www.w3.org/TR/css-device-adapt/#initial-viewport
///
/// ViewportPx is equal to ScreenPx times a "page zoom" factor controlled by the user. This is
/// the desktop-style "full page" zoom that enlarges content but then reflows the layout viewport
/// so it still exactly fits the visible area.
///
/// 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 ViewportPx {}
/// One CSS "px" in the root coordinate system for the content document. /// One CSS "px" in the root coordinate system for the content document.
/// ///
/// /// PagePx is equal to ViewportPx multiplied by a "viewport zoom" factor controlled by the user.
/// PagePx is equal to ScreenPx multiplied by a "zoom" factor controlled by the user. At the /// This is the mobile-style "pinch zoom" that enlarges content without reflowing it. When the
/// default zoom level of 100%, one PagePx is equal to one ScreenPx. However, if the document /// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
/// is zoomed in or out then this scale may be larger or smaller. /// as the viewable area.
pub enum PagePx {} pub enum PagePx {}
// In summary, the hierarchy of pixel units and the factors to convert from one to the next:
//
// DevicePixel
// / hidpi_ratio => ScreenPx
// / desktop_zoom => ViewportPx
// / pinch_zoom => 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.