servo: Merge #15700 - Introduce CSSPixel as a replacement for ViewportPx and PagePx (from glennw:zoom-wip-2); r=mbrubeck
authorGlenn Watson <github@intuitionlibrary.com>
Thu, 23 Feb 2017 16:01:16 -0800
changeset 373572 6559514972f54076f719cc172313f02321c68ed4
parent 373571 165111e8940e9bd2285becfbde5755b488650584
child 373573 45eac3e757c79eb1033101aa0b6491d224835b9d
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
milestone54.0a1
servo: Merge #15700 - Introduce CSSPixel as a replacement for ViewportPx and PagePx (from glennw:zoom-wip-2); r=mbrubeck Source-Repo: https://github.com/servo/servo Source-Revision: 1d13e6a2df42af3cce427a0b2062ac70d28c05d0
servo/components/compositing/compositor.rs
servo/components/compositing/lib.rs
servo/components/constellation/constellation.rs
servo/components/constellation/pipeline.rs
servo/components/layout/display_list_builder.rs
servo/components/script/dom/document.rs
servo/components/script/dom/mediaquerylist.rs
servo/components/script/dom/window.rs
servo/components/script_traits/lib.rs
servo/components/script_traits/script_msg.rs
servo/components/style/servo/media_queries.rs
servo/components/style/viewport.rs
servo/components/style_traits/lib.rs
servo/components/style_traits/viewport.rs
servo/components/webdriver_server/lib.rs
servo/tests/unit/style/viewport.rs
--- a/servo/components/compositing/compositor.rs
+++ b/servo/components/compositing/compositor.rs
@@ -29,17 +29,17 @@ use servo_config::opts;
 use servo_config::prefs::PREFS;
 use servo_geometry::DeviceIndependentPixel;
 use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::fs::File;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
 use std::time::{Duration, Instant};
-use style_traits::{PagePx, ViewportPx};
+use style_traits::{CSSPixel, PinchZoomFactor};
 use style_traits::viewport::ViewportConstraints;
 use time::{precise_time_ns, precise_time_s};
 use touch::{TouchHandler, TouchAction};
 use webrender;
 use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint, ScrollLocation};
 use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
 
 #[derive(Debug, PartialEq)]
@@ -142,25 +142,24 @@ pub struct IOCompositor<Window: WindowMe
 
     /// The application window size.
     window_size: TypedSize2D<u32, DevicePixel>,
 
     /// The overridden viewport.
     viewport: Option<(TypedPoint2D<u32, DevicePixel>, TypedSize2D<u32, DevicePixel>)>,
 
     /// "Mobile-style" zoom that does not reflow the page.
-    viewport_zoom: ScaleFactor<f32, PagePx, ViewportPx>,
+    viewport_zoom: PinchZoomFactor,
 
     /// Viewport zoom constraints provided by @viewport.
-    min_viewport_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
-    max_viewport_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
+    min_viewport_zoom: Option<PinchZoomFactor>,
+    max_viewport_zoom: Option<PinchZoomFactor>,
 
     /// "Desktop-style" zoom that resizes the viewport to fit the window.
-    /// See `ViewportPx` docs in util/geom.rs for details.
-    page_zoom: ScaleFactor<f32, ViewportPx, DeviceIndependentPixel>,
+    page_zoom: ScaleFactor<f32, CSSPixel, DeviceIndependentPixel>,
 
     /// The device pixel ratio for this window.
     scale_factor: ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>,
 
     channel_to_self: Box<CompositorProxy + Send>,
 
     /// A handle to the delayed composition timer.
     delayed_composition_timer: DelayedCompositionTimerProxy,
@@ -397,17 +396,17 @@ impl<Window: WindowMethods> IOCompositor
             delayed_composition_timer: DelayedCompositionTimerProxy::new(state.sender),
             composition_request: CompositionRequest::NoCompositingNecessary,
             touch_handler: TouchHandler::new(),
             pending_scroll_zoom_events: Vec::new(),
             waiting_for_results_of_scroll: false,
             composite_target: composite_target,
             shutdown_state: ShutdownState::NotShuttingDown,
             page_zoom: ScaleFactor::new(1.0),
-            viewport_zoom: ScaleFactor::new(1.0),
+            viewport_zoom: PinchZoomFactor::new(1.0),
             min_viewport_zoom: None,
             max_viewport_zoom: None,
             zoom_action: false,
             zoom_time: 0f64,
             got_load_complete_message: false,
             frame_tree_id: FrameTreeId(0),
             constellation_chan: state.constellation_chan,
             time_profiler_chan: state.time_profiler_chan,
@@ -753,21 +752,19 @@ impl<Window: WindowMethods> IOCompositor
 
     fn remove_pipeline_root_layer(&mut self, pipeline_id: PipelineId) {
         self.pipeline_details.remove(&pipeline_id);
     }
 
     fn send_window_size(&self, size_type: WindowSizeType) {
         let dppx = self.page_zoom * self.hidpi_factor();
         let initial_viewport = self.window_size.to_f32() / dppx;
-        let visible_viewport = initial_viewport / self.viewport_zoom;
         let msg = ConstellationMsg::WindowSize(WindowSizeData {
             device_pixel_ratio: dppx,
             initial_viewport: initial_viewport,
-            visible_viewport: visible_viewport,
         }, size_type);
 
         if let Err(e) = self.constellation_chan.send(msg) {
             warn!("Sending window resize to constellation failed ({}).", e);
         }
     }
 
     fn schedule_delayed_composite_if_necessary(&mut self) {
@@ -1277,18 +1274,16 @@ impl<Window: WindowMethods> IOCompositor
     }
 
     fn constrain_viewport(&mut self, pipeline_id: PipelineId, constraints: ViewportConstraints) {
         let is_root = self.root_pipeline.as_ref().map_or(false, |root_pipeline| {
             root_pipeline.id == pipeline_id
         });
 
         if is_root {
-            // TODO: actual viewport size
-
             self.viewport_zoom = constraints.initial_zoom;
             self.min_viewport_zoom = constraints.min_zoom;
             self.max_viewport_zoom = constraints.max_zoom;
             self.update_zoom_transform();
         }
     }
 
     fn hidpi_factor(&self) -> ScaleFactor<f32, DeviceIndependentPixel, DevicePixel> {
@@ -1296,18 +1291,18 @@ impl<Window: WindowMethods> IOCompositor
             Some(device_pixels_per_px) => ScaleFactor::new(device_pixels_per_px),
             None => match opts::get().output_file {
                 Some(_) => ScaleFactor::new(1.0),
                 None => self.scale_factor
             }
         }
     }
 
-    fn device_pixels_per_page_px(&self) -> ScaleFactor<f32, PagePx, DevicePixel> {
-        self.viewport_zoom * self.page_zoom * self.hidpi_factor()
+    fn device_pixels_per_page_px(&self) -> ScaleFactor<f32, CSSPixel, DevicePixel> {
+        self.page_zoom * self.hidpi_factor()
     }
 
     fn update_zoom_transform(&mut self) {
         let scale = self.device_pixels_per_page_px();
         self.scale = ScaleFactor::new(scale.get());
     }
 
     fn on_zoom_reset_window_event(&mut self) {
@@ -1705,17 +1700,18 @@ impl<Window: WindowMethods> IOCompositor
             }
             if !keep_going {
                 break
             }
         }
     }
 
     pub fn pinch_zoom_level(&self) -> f32 {
-        self.viewport_zoom.get() as f32
+        // TODO(gw): Access via WR.
+        1.0
     }
 
     pub fn title_for_main_frame(&self) {
         let root_pipeline_id = match self.root_pipeline {
             None => return,
             Some(ref root_pipeline) => root_pipeline.id,
         };
         let msg = ConstellationMsg::GetPipelineTitle(root_pipeline_id);
--- a/servo/components/compositing/lib.rs
+++ b/servo/components/compositing/lib.rs
@@ -25,27 +25,27 @@ extern crate webrender;
 extern crate webrender_traits;
 
 pub use compositor_thread::CompositorProxy;
 pub use compositor::IOCompositor;
 use euclid::size::TypedSize2D;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::PipelineId;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
-use style_traits::PagePx;
+use style_traits::CSSPixel;
 
 mod compositor;
 pub mod compositor_thread;
 mod delayed_composition;
 mod touch;
 pub mod windowing;
 
 pub struct SendableFrameTree {
     pub pipeline: CompositionPipeline,
-    pub size: Option<TypedSize2D<f32, PagePx>>,
+    pub size: Option<TypedSize2D<f32, CSSPixel>>,
     pub children: Vec<SendableFrameTree>,
 }
 
 /// The subset of the pipeline that is needed for layer composition.
 #[derive(Clone)]
 pub struct CompositionPipeline {
     pub id: PipelineId,
     pub script_chan: IpcSender<ConstellationControlMsg>,
--- a/servo/components/constellation/constellation.rs
+++ b/servo/components/constellation/constellation.rs
@@ -114,17 +114,17 @@ use std::collections::{HashMap, VecDeque
 use std::iter::once;
 use std::marker::PhantomData;
 use std::process;
 use std::rc::{Rc, Weak};
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::thread;
 use std::time::Instant;
-use style_traits::PagePx;
+use style_traits::CSSPixel;
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 use timer_scheduler::TimerScheduler;
 use webrender_traits;
 use webvr_traits::WebVRMsg;
 
 /// The `Constellation` itself. In the servo browser, there is one
 /// constellation, which maintains all of the browser global data.
@@ -529,18 +529,16 @@ impl<Message, LTF, STF> Constellation<Me
                 pending_frames: vec!(),
                 // We initialize the namespace at 1, since we reserved namespace 0 for the constellation
                 next_pipeline_namespace_id: PipelineNamespaceId(1),
                 root_frame_id: FrameId::new(),
                 focus_pipeline_id: None,
                 time_profiler_chan: state.time_profiler_chan,
                 mem_profiler_chan: state.mem_profiler_chan,
                 window_size: WindowSizeData {
-                    visible_viewport: opts::get().initial_window_size.to_f32() *
-                                          ScaleFactor::new(1.0),
                     initial_viewport: opts::get().initial_window_size.to_f32() *
                         ScaleFactor::new(1.0),
                     device_pixel_ratio:
                         ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)),
                 },
                 phantom: PhantomData,
                 webdriver: WebDriverData::new(),
                 scheduler_chan: TimerScheduler::start(),
@@ -583,17 +581,17 @@ impl<Message, LTF, STF> Constellation<Me
         namespace_id
     }
 
     /// Helper function for creating a pipeline
     fn new_pipeline(&mut self,
                     pipeline_id: PipelineId,
                     frame_id: FrameId,
                     parent_info: Option<(PipelineId, FrameType)>,
-                    initial_window_size: Option<TypedSize2D<f32, PagePx>>,
+                    initial_window_size: Option<TypedSize2D<f32, CSSPixel>>,
                     load_data: LoadData,
                     sandbox: IFrameSandboxState,
                     is_private: bool) {
         if self.shutting_down { return; }
 
         // TODO: can we get a case where the child pipeline is created
         // before the parent is part of the frame tree?
         let top_level_frame_id = match parent_info {
@@ -1330,17 +1328,17 @@ impl<Message, LTF, STF> Constellation<Me
                     let _ = pipeline.event_loop.send(ConstellationControlMsg::WebVREvent(id, event.clone()));
                 },
                 None => warn!("constellation got webvr event for dead pipeline")
             }
         }
     }
 
     fn handle_init_load(&mut self, url: ServoUrl) {
-        let window_size = self.window_size.visible_viewport;
+        let window_size = self.window_size.initial_viewport;
         let root_pipeline_id = PipelineId::new();
         let root_frame_id = self.root_frame_id;
         let load_data = LoadData::new(url.clone(), None, None);
         let sandbox = IFrameSandboxState::IFrameUnsandboxed;
         self.new_pipeline(root_pipeline_id, root_frame_id, None, Some(window_size), load_data, sandbox, false);
         self.handle_load_start_msg(root_pipeline_id);
         self.pending_frames.push(FrameChange {
             frame_id: self.root_frame_id,
@@ -1348,32 +1346,31 @@ impl<Message, LTF, STF> Constellation<Me
             new_pipeline_id: root_pipeline_id,
             url: url.clone(),
             replace: None,
         });
         self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
     }
 
     fn handle_frame_size_msg(&mut self,
-                             iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, PagePx>)>) {
+                             iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>) {
         for (pipeline_id, size) in iframe_sizes {
             let result = {
                 let pipeline = match self.pipelines.get_mut(&pipeline_id) {
                     Some(pipeline) => pipeline,
                     None => continue,
                 };
 
                 if pipeline.size == Some(size) {
                     continue;
                 }
 
                 pipeline.size = Some(size);
                 let msg = ConstellationControlMsg::Resize(pipeline_id, WindowSizeData {
-                    visible_viewport: size,
-                    initial_viewport: size * ScaleFactor::new(1.0),
+                    initial_viewport: size,
                     device_pixel_ratio: self.window_size.device_pixel_ratio,
                 }, WindowSizeType::Initial);
 
                 pipeline.event_loop.send(msg)
             };
             if let Err(e) = result {
                 self.handle_send_error(pipeline_id, e);
             }
@@ -2207,18 +2204,17 @@ impl<Message, LTF, STF> Constellation<Me
         if let Some(pending_index) = pending_index {
             let frame_change = self.pending_frames.swap_remove(pending_index);
             self.add_or_replace_pipeline_in_frame_tree(frame_change);
         }
     }
 
     /// Called when the window is resized.
     fn handle_window_size_msg(&mut self, new_size: WindowSizeData, size_type: WindowSizeType) {
-        debug!("handle_window_size_msg: {:?} {:?}", new_size.initial_viewport.to_untyped(),
-                                                       new_size.visible_viewport.to_untyped());
+        debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped());
 
         if let Some(frame) = self.frames.get(&self.root_frame_id) {
             // Send Resize (or ResizeInactive) messages to each
             // pipeline in the frame tree.
             let pipeline_id = frame.pipeline_id;
             let pipeline = match self.pipelines.get(&pipeline_id) {
                 None => return warn!("Pipeline {:?} resized after closing.", pipeline_id),
                 Some(pipeline) => pipeline,
--- a/servo/components/constellation/pipeline.rs
+++ b/servo/components/constellation/pipeline.rs
@@ -30,17 +30,17 @@ use servo_config::prefs::{PREFS, Pref};
 use servo_url::ServoUrl;
 use std::collections::HashMap;
 #[cfg(not(windows))]
 use std::env;
 use std::ffi::OsStr;
 use std::process;
 use std::rc::Rc;
 use std::sync::mpsc::Sender;
-use style_traits::{PagePx, ViewportPx};
+use style_traits::CSSPixel;
 use webrender_traits;
 use webvr_traits::WebVRMsg;
 
 /// A `Pipeline` is the constellation's view of a `Document`. Each pipeline has an
 /// event loop (executed by a script thread) and a layout thread. A script thread
 /// may be responsible for many pipelines, but a layout thread is only responsible
 /// for one.
 pub struct Pipeline {
@@ -71,17 +71,17 @@ pub struct Pipeline {
     /// to a hash URL.
     pub url: ServoUrl,
 
     /// The title of the most recently-loaded page.
     pub title: Option<String>,
 
     /// The size of the frame.
     /// TODO: move this field to `Frame`.
-    pub size: Option<TypedSize2D<f32, PagePx>>,
+    pub size: Option<TypedSize2D<f32, CSSPixel>>,
 
     /// Whether this pipeline is currently running animations. Pipelines that are running
     /// animations cause composites to be continually scheduled.
     pub running_animations: bool,
 
     /// The child frames of this pipeline (these are iframes in the document).
     pub children: Vec<FrameId>,
 
@@ -144,20 +144,20 @@ pub struct InitialPipelineState {
 
     /// A channel to the time profiler thread.
     pub time_profiler_chan: time::ProfilerChan,
 
     /// A channel to the memory profiler thread.
     pub mem_profiler_chan: profile_mem::ProfilerChan,
 
     /// Information about the initial window size.
-    pub window_size: Option<TypedSize2D<f32, PagePx>>,
+    pub window_size: Option<TypedSize2D<f32, CSSPixel>>,
 
     /// Information about the device pixel ratio.
-    pub device_pixel_ratio: ScaleFactor<f32, ViewportPx, DevicePixel>,
+    pub device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>,
 
     /// The event loop to run in, if applicable.
     pub event_loop: Option<Rc<EventLoop>>,
 
     /// Information about the page to load.
     pub load_data: LoadData,
 
     /// The ID of the pipeline namespace for this script thread.
@@ -188,18 +188,17 @@ impl Pipeline {
             .expect("Pipeline main chan");
 
         let (layout_content_process_shutdown_chan, layout_content_process_shutdown_port) =
             ipc::channel().expect("Pipeline layout content shutdown chan");
 
         let device_pixel_ratio = state.device_pixel_ratio;
         let window_size = state.window_size.map(|size| {
             WindowSizeData {
-                visible_viewport: size,
-                initial_viewport: size * ScaleFactor::new(1.0),
+                initial_viewport: size,
                 device_pixel_ratio: device_pixel_ratio,
             }
         });
 
         let (script_chan, content_ports) = match state.event_loop {
             Some(script_chan) => {
                 let new_layout_info = NewLayoutInfo {
                     parent_info: state.parent_info,
@@ -302,17 +301,17 @@ impl Pipeline {
     pub fn new(id: PipelineId,
                frame_id: FrameId,
                parent_info: Option<(PipelineId, FrameType)>,
                event_loop: Rc<EventLoop>,
                layout_chan: IpcSender<LayoutControlMsg>,
                compositor_proxy: Box<CompositorProxy + 'static + Send>,
                is_private: bool,
                url: ServoUrl,
-               size: Option<TypedSize2D<f32, PagePx>>,
+               size: Option<TypedSize2D<f32, CSSPixel>>,
                visible: bool)
                -> Pipeline {
         let pipeline = Pipeline {
             id: id,
             frame_id: frame_id,
             parent_info: parent_info,
             event_loop: event_loop,
             layout_chan: layout_chan,
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -54,17 +54,17 @@ use style::computed_values::text_shadow:
 use style::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
 use style::properties::{self, ServoComputedValues};
 use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
 use style::properties::style_structs;
 use style::servo::restyle_damage::REPAINT;
 use style::values::{RGBA, computed};
 use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
 use style::values::specified::{HorizontalDirection, VerticalDirection};
-use style_traits::PagePx;
+use style_traits::CSSPixel;
 use style_traits::cursor::Cursor;
 use table_cell::CollapsedBordersForCell;
 use webrender_traits::{ColorF, GradientStop, RepeatMode, ScrollPolicy};
 
 trait ResolvePercentage {
     fn resolve(&self, length: u32) -> u32;
 }
 
@@ -133,17 +133,17 @@ pub struct DisplayListBuildState<'a> {
     pub current_stacking_context_id: StackingContextId,
 
     /// The current scroll root id, used to keep track of state when
     /// recursively building and processing the display list.
     pub current_scroll_root_id: ScrollRootId,
 
     /// Vector containing iframe sizes, used to inform the constellation about
     /// new iframe sizes
-    pub iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, PagePx>)>,
+    pub iframe_sizes: Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>,
 }
 
 impl<'a> DisplayListBuildState<'a> {
     pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> {
         DisplayListBuildState {
             layout_context: layout_context,
             root_stacking_context: StackingContext::root(),
             items: HashMap::new(),
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -3247,17 +3247,17 @@ impl DocumentMethods for Document {
 
     #[allow(unsafe_code)]
     // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
     fn ElementFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Option<Root<Element>> {
         let x = *x as f32;
         let y = *y as f32;
         let point = &Point2D::new(x, y);
         let window = window_from_node(self);
-        let viewport = window.window_size().unwrap().visible_viewport;
+        let viewport = window.window_size().unwrap().initial_viewport;
 
         if self.browsing_context().is_none() {
             return None;
         }
 
         if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
             return None;
         }
@@ -3280,17 +3280,17 @@ impl DocumentMethods for Document {
 
     #[allow(unsafe_code)]
     // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint
     fn ElementsFromPoint(&self, x: Finite<f64>, y: Finite<f64>) -> Vec<Root<Element>> {
         let x = *x as f32;
         let y = *y as f32;
         let point = &Point2D::new(x, y);
         let window = window_from_node(self);
-        let viewport = window.window_size().unwrap().visible_viewport;
+        let viewport = window.window_size().unwrap().initial_viewport;
 
         if self.browsing_context().is_none() {
             return vec!();
         }
 
         // Step 2
         if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
             return vec!();
--- a/servo/components/script/dom/mediaquerylist.rs
+++ b/servo/components/script/dom/mediaquerylist.rs
@@ -13,22 +13,21 @@ use dom::bindings::reflector::DomObject;
 use dom::bindings::reflector::reflect_dom_object;
 use dom::bindings::str::DOMString;
 use dom::bindings::trace::JSTraceable;
 use dom::bindings::weakref::{WeakRef, WeakRefVec};
 use dom::document::Document;
 use dom::event::Event;
 use dom::eventtarget::EventTarget;
 use dom::mediaquerylistevent::MediaQueryListEvent;
-use euclid::scale_factor::ScaleFactor;
 use js::jsapi::JSTracer;
 use std::cell::Cell;
 use std::rc::Rc;
 use style::media_queries::{Device, MediaList, MediaType};
-use style_traits::{PagePx, ToCss, ViewportPx};
+use style_traits::ToCss;
 
 pub enum MediaQueryListMatchState {
     Same(bool),
     Changed(bool),
 }
 
 #[dom_struct]
 pub struct MediaQueryList {
@@ -70,22 +69,18 @@ impl MediaQueryList {
         };
 
         self.last_match_state.set(Some(matches));
         result
     }
 
     pub fn evaluate(&self) -> bool {
         if let Some(window_size) = self.document.window().window_size() {
-            let viewport_size = window_size.visible_viewport;
-            // TODO: support real ViewportPx, including zoom level
-            // This information seems not to be tracked currently, so we assume
-            // ViewportPx == PagePx
-            let page_to_viewport: ScaleFactor<f32, PagePx, ViewportPx> = ScaleFactor::new(1.0);
-            let device = Device::new(MediaType::Screen, viewport_size * page_to_viewport);
+            let viewport_size = window_size.initial_viewport;
+            let device = Device::new(MediaType::Screen, viewport_size);
             self.media_query_list.evaluate(&device)
         } else {
             false
         }
     }
 }
 
 impl MediaQueryListMethods for MediaQueryList {
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -769,25 +769,25 @@ impl WindowMethods for Window {
                                  pseudo,
                                  CSSModificationAccess::Readonly)
     }
 
     // https://drafts.csswg.org/cssom-view/#dom-window-innerheight
     //TODO Include Scrollbar
     fn InnerHeight(&self) -> i32 {
         self.window_size.get()
-                        .and_then(|e| e.visible_viewport.height.to_i32())
+                        .and_then(|e| e.initial_viewport.height.to_i32())
                         .unwrap_or(0)
     }
 
     // https://drafts.csswg.org/cssom-view/#dom-window-innerwidth
     //TODO Include Scrollbar
     fn InnerWidth(&self) -> i32 {
         self.window_size.get()
-                        .and_then(|e| e.visible_viewport.width.to_i32())
+                        .and_then(|e| e.initial_viewport.width.to_i32())
                         .unwrap_or(0)
     }
 
     // https://drafts.csswg.org/cssom-view/#dom-window-scrollx
     fn ScrollX(&self) -> i32 {
         self.current_viewport.get().origin.x.to_px()
     }
 
--- a/servo/components/script_traits/lib.rs
+++ b/servo/components/script_traits/lib.rs
@@ -62,17 +62,17 @@ use net_traits::response::HttpsState;
 use net_traits::storage_thread::StorageType;
 use profile_traits::mem;
 use profile_traits::time as profile_time;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 use servo_url::ServoUrl;
 use std::collections::HashMap;
 use std::fmt;
 use std::sync::mpsc::{Receiver, Sender};
-use style_traits::{PagePx, UnsafeNode, ViewportPx};
+use style_traits::{CSSPixel, UnsafeNode};
 use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
 use webvr_traits::{WebVRDisplayEvent, WebVRMsg};
 
 pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
 pub use script_msg::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage};
 
 /// The address of a node. Layout sends these back. They must be validated via
 /// `from_untrusted_node_address` before they can be used, because we do not trust layout.
@@ -658,23 +658,20 @@ pub struct StackingContextScrollState {
 #[derive(Copy, Clone, Debug)]
 pub enum DevicePixel {}
 
 /// Data about the window size.
 #[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)]
 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<f32, ViewportPx>,
-
-    /// The "viewing area" in page px. See `PagePx` documentation for details.
-    pub visible_viewport: TypedSize2D<f32, PagePx>,
+    pub initial_viewport: TypedSize2D<f32, CSSPixel>,
 
     /// The resolution of the window in dppx, not including any "pinch zoom" factor.
-    pub device_pixel_ratio: ScaleFactor<f32, ViewportPx, DevicePixel>,
+    pub device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>,
 }
 
 /// The type of window size change.
 #[derive(Deserialize, Eq, PartialEq, Serialize, Copy, Clone, HeapSizeOf)]
 pub enum WindowSizeType {
     /// Initial load.
     Initial,
     /// Window resize.
--- a/servo/components/script_traits/script_msg.rs
+++ b/servo/components/script_traits/script_msg.rs
@@ -19,27 +19,27 @@ use euclid::size::{Size2D, TypedSize2D};
 use gfx_traits::ScrollRootId;
 use ipc_channel::ipc::IpcSender;
 use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
 use msg::constellation_msg::{Key, KeyModifiers, KeyState};
 use net_traits::CoreResourceMsg;
 use net_traits::storage_thread::StorageType;
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use servo_url::ServoUrl;
-use style_traits::PagePx;
+use style_traits::CSSPixel;
 use style_traits::cursor::Cursor;
 use style_traits::viewport::ViewportConstraints;
 
 /// Messages from the layout to the constellation.
 #[derive(Deserialize, Serialize)]
 pub enum LayoutMsg {
     /// Indicates whether this pipeline is currently running animations.
     ChangeRunningAnimationsState(PipelineId, AnimationState),
     /// Inform the constellation of the size of the pipeline's viewport.
-    FrameSizes(Vec<(PipelineId, TypedSize2D<f32, PagePx>)>),
+    FrameSizes(Vec<(PipelineId, TypedSize2D<f32, CSSPixel>)>),
     /// Requests that the constellation inform the compositor of the a cursor change.
     SetCursor(Cursor),
     /// Notifies the constellation that the viewport has been constrained in some manner
     ViewportConstrained(PipelineId, ViewportConstraints),
 }
 
 /// Whether a DOM event was prevented by web content
 #[derive(Deserialize, Serialize)]
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -5,37 +5,37 @@
 //! Servo's media-query device and expression representation.
 
 use app_units::Au;
 use cssparser::Parser;
 use euclid::{Size2D, TypedSize2D};
 use media_queries::MediaType;
 use properties::ComputedValues;
 use std::fmt;
-use style_traits::{ToCss, ViewportPx};
+use style_traits::{CSSPixel, ToCss};
 use style_traits::viewport::ViewportConstraints;
 use values::computed::{self, ToComputedValue};
 use values::specified;
 
 /// A device is a structure that represents the current media a given document
 /// is displayed in.
 ///
 /// This is the struct against which media queries are evaluated.
 #[derive(Debug, HeapSizeOf)]
 pub struct Device {
     /// The current media type used by de device.
     media_type: MediaType,
-    /// The current viewport size, in viewport pixels.
-    viewport_size: TypedSize2D<f32, ViewportPx>,
+    /// The current viewport size, in CSS pixels.
+    viewport_size: TypedSize2D<f32, CSSPixel>,
 }
 
 impl Device {
     /// Trivially construct a new `Device`.
     pub fn new(media_type: MediaType,
-               viewport_size: TypedSize2D<f32, ViewportPx>)
+               viewport_size: TypedSize2D<f32, CSSPixel>)
                -> Device {
         Device {
             media_type: media_type,
             viewport_size: viewport_size,
         }
     }
 
     /// Return the default computed values for this device.
@@ -48,17 +48,17 @@ impl Device {
     #[inline]
     pub fn au_viewport_size(&self) -> Size2D<Au> {
         Size2D::new(Au::from_f32_px(self.viewport_size.width),
                     Au::from_f32_px(self.viewport_size.height))
     }
 
     /// Returns the viewport size in pixels.
     #[inline]
-    pub fn px_viewport_size(&self) -> TypedSize2D<f32, ViewportPx> {
+    pub fn px_viewport_size(&self) -> TypedSize2D<f32, CSSPixel> {
         self.viewport_size
     }
 
     /// Take into account a viewport rule taken from the stylesheets.
     pub fn account_for_viewport_rule(&mut self, constraints: &ViewportConstraints) {
         self.viewport_size = constraints.size;
     }
 
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -7,26 +7,25 @@
 //! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
 //! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
 
 #![deny(missing_docs)]
 
 use app_units::Au;
 use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
 use cssparser::ToCss as ParserToCss;
-use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use media_queries::Device;
 use parser::{ParserContext, log_css_error};
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::fmt;
 use std::iter::Enumerate;
 use std::str::Chars;
-use style_traits::ToCss;
+use style_traits::{PinchZoomFactor, ToCss};
 use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom};
 use stylesheets::{Stylesheet, Origin};
 use values::computed::{Context, ToComputedValue};
 use values::specified::{NoCalcLength, LengthOrPercentageOrAuto, ViewportPercentageLength};
 
 macro_rules! declare_viewport_descriptor {
     ( $( $variant_name: expr => $variant: ident($data: ident), )+ ) => {
          declare_viewport_descriptor_inner!([] [ $( $variant_name => $variant($data), )+ ] 0);
@@ -791,17 +790,17 @@ impl MaybeNew for ViewportConstraints {
                 Au::from_f32_px(width.to_f32_px() * ratio)
             }
         });
 
         Some(ViewportConstraints {
             size: TypedSize2D::new(width.to_f32_px(), height.to_f32_px()),
 
             // TODO: compute a zoom factor for 'auto' as suggested by DEVICE-ADAPT ยง 10.
-            initial_zoom: ScaleFactor::new(initial_zoom.unwrap_or(1.)),
-            min_zoom: min_zoom.map(ScaleFactor::new),
-            max_zoom: max_zoom.map(ScaleFactor::new),
+            initial_zoom: PinchZoomFactor::new(initial_zoom.unwrap_or(1.)),
+            min_zoom: min_zoom.map(PinchZoomFactor::new),
+            max_zoom: max_zoom.map(PinchZoomFactor::new),
 
             user_zoom: user_zoom,
             orientation: orientation
         })
     }
 }
--- a/servo/components/style_traits/lib.rs
+++ b/servo/components/style_traits/lib.rs
@@ -21,42 +21,50 @@ extern crate euclid;
 #[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
 extern crate rustc_serialize;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
 
 /// Opaque type stored in type-unsafe work queues for parallel layout.
 /// Must be transmutable to and from `TNode`.
 pub type UnsafeNode = (usize, usize);
 
+/// Represents a mobile style pinch zoom factor.
+/// TODO(gw): Once WR supports pinch zoom, use a type directly from webrender_traits.
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
+pub struct PinchZoomFactor(f32);
+
+impl PinchZoomFactor {
+    /// Construct a new pinch zoom factor.
+    pub fn new(scale: f32) -> PinchZoomFactor {
+        PinchZoomFactor(scale)
+    }
+
+    /// Get the pinch zoom factor as an untyped float.
+    pub fn get(&self) -> f32 {
+        self.0
+    }
+}
+
 /// 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 `DeviceIndependentPixel` times a "page zoom" factor controlled by the user.  This is
+/// `CSSPixel` is equal to `DeviceIndependentPixel` 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 `DeviceIndependentPixel`.  However, if the
+/// At the default zoom level of 100%, one `CSSPixel` is equal to one `DeviceIndependentPixel`.  However, if the
 /// document is zoomed in or out then this scale may be larger or smaller.
 #[derive(Clone, Copy, Debug)]
-pub enum ViewportPx {}
-
-/// 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.
-/// This is the mobile-style "pinch zoom" that enlarges content without reflowing it.  When the
-/// viewport zoom is not equal to 1.0, then the layout viewport is no longer the same physical size
-/// as the viewable area.
-#[derive(Clone, Copy, Debug)]
-pub enum PagePx {}
+pub enum CSSPixel {}
 
 // In summary, the hierarchy of pixel units and the factors to convert from one to the next:
 //
 // DevicePixel
 //   / hidpi_ratio => DeviceIndependentPixel
-//     / desktop_zoom => ViewportPx
-//       / pinch_zoom => PagePx
+//     / desktop_zoom => CSSPixel
 
 pub mod cursor;
 #[macro_use]
 pub mod values;
 pub mod viewport;
 
 pub use values::{ToCss, OneOrMoreCommaSeparated};
--- a/servo/components/style_traits/viewport.rs
+++ b/servo/components/style_traits/viewport.rs
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Helper types for the `@viewport` rule.
 
-use {PagePx, ViewportPx};
+use {CSSPixel, PinchZoomFactor};
 use cssparser::{Parser, ToCss};
-use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use std::ascii::AsciiExt;
 use std::fmt;
 use values::specified::AllowedNumericType;
 
 define_css_keyword_enum!(UserZoom:
                          "zoom" => Zoom,
                          "fixed" => Fixed);
@@ -26,23 +25,23 @@ define_css_keyword_enum!(Orientation:
 ///
 /// https://drafts.csswg.org/css-device-adapt/#viewport-desc
 #[derive(Clone, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
 pub struct ViewportConstraints {
     /// Width and height:
     ///  * https://drafts.csswg.org/css-device-adapt/#width-desc
     ///  * https://drafts.csswg.org/css-device-adapt/#height-desc
-    pub size: TypedSize2D<f32, ViewportPx>,
+    pub size: TypedSize2D<f32, CSSPixel>,
     /// https://drafts.csswg.org/css-device-adapt/#zoom-desc
-    pub initial_zoom: ScaleFactor<f32, PagePx, ViewportPx>,
+    pub initial_zoom: PinchZoomFactor,
     /// https://drafts.csswg.org/css-device-adapt/#min-max-width-desc
-    pub min_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
+    pub min_zoom: Option<PinchZoomFactor>,
     /// https://drafts.csswg.org/css-device-adapt/#min-max-width-desc
-    pub max_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
+    pub max_zoom: Option<PinchZoomFactor>,
     /// https://drafts.csswg.org/css-device-adapt/#user-zoom-desc
     pub user_zoom: UserZoom,
     /// https://drafts.csswg.org/css-device-adapt/#orientation-desc
     pub orientation: Orientation
 }
 
 impl ToCss for ViewportConstraints {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
--- a/servo/components/webdriver_server/lib.rs
+++ b/servo/components/webdriver_server/lib.rs
@@ -394,17 +394,17 @@ impl Handler {
     fn handle_window_size(&self) -> WebDriverResult<WebDriverResponse> {
         let (sender, receiver) = ipc::channel().unwrap();
         let pipeline_id = try!(self.root_pipeline());
         let cmd_msg = WebDriverCommandMsg::GetWindowSize(pipeline_id, sender);
 
         self.constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
 
         let window_size = receiver.recv().unwrap();
-        let vp = window_size.visible_viewport;
+        let vp = window_size.initial_viewport;
         let window_size_response = WindowSizeResponse::new(vp.width as u64, vp.height as u64);
         Ok(WebDriverResponse::WindowSize(window_size_response))
     }
 
     fn handle_set_window_size(&self, params: &WindowSizeParameters) -> WebDriverResult<WebDriverResponse> {
         let (sender, receiver) = ipc::channel().unwrap();
         let size = Size2D::new(params.width as u32, params.height as u32);
         let pipeline_id = try!(self.root_pipeline());
@@ -418,17 +418,17 @@ impl Handler {
             // On timeout, we send a GetWindowSize message to the constellation,
             // which will give the current window size.
             thread::sleep(Duration::from_millis(timeout as u64));
             let cmd_msg = WebDriverCommandMsg::GetWindowSize(pipeline_id, sender);
             constellation_chan.send(ConstellationMsg::WebDriverCommand(cmd_msg)).unwrap();
         });
 
         let window_size = receiver.recv().unwrap();
-        let vp = window_size.visible_viewport;
+        let vp = window_size.initial_viewport;
         let window_size_response = WindowSizeResponse::new(vp.width as u64, vp.height as u64);
         Ok(WebDriverResponse::WindowSize(window_size_response))
     }
 
     fn handle_is_enabled(&self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
         let (sender, receiver) = ipc::channel().unwrap();
 
         try!(self.root_script_command(WebDriverScriptCommand::IsEnabled(element.id.clone(), sender)));
--- a/servo/tests/unit/style/viewport.rs
+++ b/servo/tests/unit/style/viewport.rs
@@ -1,26 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::Parser;
-use euclid::scale_factor::ScaleFactor;
 use euclid::size::TypedSize2D;
 use media_queries::CSSErrorReporterTest;
 use servo_config::prefs::{PREFS, PrefValue};
 use servo_url::ServoUrl;
 use style::error_reporting::ParseErrorReporter;
 use style::media_queries::{Device, MediaType};
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::stylesheets::{Stylesheet, Origin};
 use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
 use style::values::specified::NoCalcLength::{self, ViewportPercentage};
 use style::values::specified::ViewportPercentageLength::Vw;
 use style::viewport::*;
+use style_traits::PinchZoomFactor;
 use style_traits::viewport::*;
 
 macro_rules! stylesheet {
     ($css:expr, $origin:ident, $error_reporter:expr) => {
         Box::new(Stylesheet::from_str(
             $css,
             ServoUrl::parse("http://localhost").unwrap(),
             Origin::$origin,
@@ -290,57 +290,57 @@ fn constrain_viewport() {
     let initial_viewport = TypedSize2D::new(800., 600.);
     let device = Device::new(MediaType::Screen, initial_viewport);
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("")), None);
 
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
-                   initial_zoom: ScaleFactor::new(1.),
+                   initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
-                   initial_zoom: ScaleFactor::new(1.),
+                   initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 800px; height: 600px;\
                                                                      zoom: 1;\
                                                                      user-zoom: zoom;\
                                                                      orientation: auto;")),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
-                   initial_zoom: ScaleFactor::new(1.),
+                   initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
     let initial_viewport = TypedSize2D::new(200., 150.);
     let device = Device::new(MediaType::Screen, initial_viewport);
     assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
                Some(ViewportConstraints {
                    size: TypedSize2D::new(320., 240.),
 
-                   initial_zoom: ScaleFactor::new(1.),
+                   initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 }