Separate "desktop" and "mobile" zoom calculations.

This ensures that the layout viewport responds to each type of zoom correctly,
and lays the ground for CSS Media Queries and CSS Device Adaption.

Until we have proper touch support, mobile-style "pinch" zoom can be simulated
by holding Ctrl while scrolling with a mousewheel or trackpad gesture.
This commit is contained in:
Matt Brubeck 2014-06-12 14:33:53 -07:00
parent afb6bf48e7
commit 4fef0d1c1c
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,6 +240,17 @@ 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) => {
match (window.get_key(glfw::KeyLeftControl),
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 dx = (xpos as f32) * 30.0;
let dy = (ypos as f32) * 30.0; let dy = (ypos as f32) * 30.0;
@ -253,6 +264,9 @@ impl Window {
self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(dx, dy), self.event_queue.borrow_mut().push(ScrollWindowEvent(TypedPoint2D(dx, dy),
TypedPoint2D(x as i32, y as i32))); 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.