diff options
24 files changed, 160 insertions, 77 deletions
diff --git a/Cargo.lock b/Cargo.lock index b2a05f3be0f..10ad2c40ac6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2558,7 +2558,6 @@ dependencies = [ name = "script_traits" version = "0.0.1" dependencies = [ - "app_units 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bluetooth_traits 0.0.1", "canvas_traits 0.0.1", "cookie 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 93431755a4d..051454400ca 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -16,7 +16,7 @@ use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId, Tra use net_traits::image::base::{Image, PixelFormat}; use profile_traits::time::{self, ProfilerCategory, profile}; use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg}; -use script_traits::{ConstellationMsg, DevicePixel, LayoutControlMsg, LoadData, MouseButton}; +use script_traits::{ConstellationMsg, LayoutControlMsg, LoadData, MouseButton}; use script_traits::{MouseEventType, ScrollState}; use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType}; use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent}; @@ -29,7 +29,7 @@ use std::fs::File; use std::rc::Rc; use std::sync::mpsc::Sender; use std::time::{Duration, Instant}; -use style_traits::{CSSPixel, PinchZoomFactor}; +use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor}; use style_traits::viewport::ViewportConstraints; use time::{precise_time_ns, precise_time_s}; use touch::{TouchHandler, TouchAction}; diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index 1edafa017c8..0d6a7561a2b 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -4,8 +4,9 @@ use euclid::{TypedPoint2D, TypedVector2D}; use euclid::ScaleFactor; -use script_traits::{DevicePixel, EventResult, TouchId}; +use script_traits::{EventResult, TouchId}; use self::TouchState::*; +use style_traits::DevicePixel; /// Minimum number of `DeviceIndependentPixel` to begin touch scrolling. const TOUCH_PAN_MIN_SCREEN_PX: f32 = 20.0; diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 8604b41de46..65ab7cc1bf0 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -11,11 +11,12 @@ use gleam::gl; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState, TraversalDirection}; use net_traits::net_error_list::NetError; -use script_traits::{DevicePixel, LoadData, MouseButton, TouchEventType, TouchId, TouchpadPressurePhase}; +use script_traits::{LoadData, MouseButton, TouchEventType, TouchId, TouchpadPressurePhase}; use servo_geometry::DeviceIndependentPixel; use servo_url::ServoUrl; use std::fmt::{Debug, Error, Formatter}; use std::rc::Rc; +use style_traits::DevicePixel; use style_traits::cursor::Cursor; use webrender_api::ScrollLocation; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index d6571c208c9..8c3b2f3edbc 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -21,7 +21,7 @@ use net_traits::{IpcSend, ResourceThreads}; use net_traits::image_cache::ImageCache; use profile_traits::mem as profile_mem; use profile_traits::time; -use script_traits::{ConstellationControlMsg, DevicePixel, DiscardBrowsingContext}; +use script_traits::{ConstellationControlMsg, DiscardBrowsingContext}; use script_traits::{DocumentActivity, InitialScriptState}; use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent}; use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg}; @@ -38,6 +38,7 @@ use std::rc::Rc; use std::sync::Arc; use std::sync::mpsc::Sender; use style_traits::CSSPixel; +use style_traits::DevicePixel; use webrender_api; use webvr_traits::WebVRMsg; diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index d993170fb08..c7850965758 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1170,7 +1170,10 @@ impl FragmentDisplayListBuilding for Fragment { // including padding, but not border or margin, so we follow suit. // https://github.com/w3c/css-houdini-drafts/issues/417 let unbordered_box = self.border_box - style.logical_border_width(); - let size = unbordered_box.size.to_physical(style.writing_mode); + let device_pixel_ratio = state.layout_context.style_context.device_pixel_ratio(); + let size_in_au = unbordered_box.size.to_physical(style.writing_mode); + let size_in_px = TypedSize2D::new(size_in_au.width.to_f32_px(), size_in_au.height.to_f32_px()); + let size_in_dpx = size_in_px * device_pixel_ratio; let name = paint_worklet.name.clone(); // Get the painter, and the computed values for its properties. @@ -1188,17 +1191,17 @@ impl FragmentDisplayListBuilding for Fragment { // TODO: add a one-place cache to avoid drawing the paint image every time. // https://github.com/servo/servo/issues/17369 - debug!("Drawing a paint image {}({},{}).", name, size.width.to_px(), size.height.to_px()); + debug!("Drawing a paint image {}({},{}).", name, size_in_px.width, size_in_px.height); let (sender, receiver) = ipc::channel().unwrap(); - painter.draw_a_paint_image(size, properties, sender); + painter.draw_a_paint_image(size_in_px, device_pixel_ratio, properties, sender); // TODO: timeout let webrender_image = match receiver.recv() { Ok(CanvasData::Image(canvas_data)) => { WebRenderImageInfo { // TODO: it would be nice to get this data back from the canvas - width: size.width.to_px().abs() as u32, - height: size.height.to_px().abs() as u32, + width: size_in_dpx.width as u32, + height: size_in_dpx.height as u32, format: PixelFormat::BGRA8, key: Some(canvas_data.image_key), } diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 5faf114740b..2f0fa57e5a3 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -462,9 +462,12 @@ impl LayoutThread { layout_threads: usize, paint_time_metrics: PaintTimeMetrics) -> LayoutThread { + // The device pixel ratio is incorrect (it does not have the hidpi value), + // but it will be set correctly when the initial reflow takes place. let device = Device::new( MediaType::Screen, - opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0)); + opts::get().initial_window_size.to_f32() * ScaleFactor::new(1.0), + ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0))); let configuration = rayon::Configuration::new().num_threads(layout_threads); @@ -1125,6 +1128,7 @@ impl LayoutThread { trace!("{:?}", ShowSubtree(element.as_node())); let initial_viewport = data.window_size.initial_viewport; + let device_pixel_ratio = data.window_size.device_pixel_ratio; let old_viewport_size = self.viewport_size; let current_screen_size = Size2D::new(Au::from_f32_px(initial_viewport.width), Au::from_f32_px(initial_viewport.height)); @@ -1134,7 +1138,7 @@ impl LayoutThread { let document_shared_lock = document.style_shared_lock(); self.document_shared_lock = Some(document_shared_lock.clone()); let author_guard = document_shared_lock.read(); - let device = Device::new(MediaType::Screen, initial_viewport); + let device = Device::new(MediaType::Screen, initial_viewport, device_pixel_ratio); self.stylist.set_device(device, &author_guard, &data.document_stylesheets); self.viewport_size = diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 232ef20ec16..6ddeb49acf7 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -43,7 +43,7 @@ use dom::bindings::str::{DOMString, USVString}; use dom::bindings::utils::WindowProxyHandler; use dom::document::PendingRestyle; use encoding::types::EncodingRef; -use euclid::{Transform2D, Transform3D, Point2D, Vector2D, Rect, Size2D}; +use euclid::{Transform2D, Transform3D, Point2D, Vector2D, Rect, Size2D, ScaleFactor}; use euclid::Length as EuclidLength; use html5ever::{Prefix, LocalName, Namespace, QualName}; use html5ever::buffer_queue::BufferQueue; @@ -484,6 +484,13 @@ unsafe impl JSTraceable for Point2D<f32> { } } +unsafe impl<T, U> JSTraceable for ScaleFactor<f32, T, U> { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for Vector2D<f32> { #[inline] unsafe fn trace(&self, _trc: *mut JSTracer) { diff --git a/components/script/dom/mediaquerylist.rs b/components/script/dom/mediaquerylist.rs index b25e041f4ef..1765ef88bce 100644 --- a/components/script/dom/mediaquerylist.rs +++ b/components/script/dom/mediaquerylist.rs @@ -76,7 +76,8 @@ impl MediaQueryList { pub fn evaluate(&self) -> bool { if let Some(window_size) = self.document.window().window_size() { let viewport_size = window_size.initial_viewport; - let device = Device::new(MediaType::Screen, viewport_size); + let device_pixel_ratio = window_size.device_pixel_ratio; + let device = Device::new(MediaType::Screen, viewport_size, device_pixel_ratio); self.media_query_list.evaluate(&device, self.document.quirks_mode()) } else { false diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index dd91ec0960e..48ae1b18637 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -2,7 +2,6 @@ * 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 app_units::Au; use canvas_traits::CanvasData; use canvas_traits::CanvasMsg; use canvas_traits::FromLayoutMsg; @@ -26,12 +25,18 @@ use dom::canvaspattern::CanvasPattern; use dom::canvasrenderingcontext2d::CanvasRenderingContext2D; use dom::paintworkletglobalscope::PaintWorkletGlobalScope; use dom_struct::dom_struct; +use euclid::ScaleFactor; use euclid::Size2D; +use euclid::TypedSize2D; use ipc_channel::ipc::IpcSender; +use std::cell::Cell; +use style_traits::CSSPixel; +use style_traits::DevicePixel; #[dom_struct] pub struct PaintRenderingContext2D { context: CanvasRenderingContext2D, + device_pixel_ratio: Cell<ScaleFactor<f32, CSSPixel, DevicePixel>>, } impl PaintRenderingContext2D { @@ -39,6 +44,7 @@ impl PaintRenderingContext2D { let size = Size2D::zero(); PaintRenderingContext2D { context: CanvasRenderingContext2D::new_inherited(global.upcast(), None, size), + device_pixel_ratio: Cell::new(ScaleFactor::new(1.0)), } } @@ -53,9 +59,21 @@ impl PaintRenderingContext2D { let _ = self.context.ipc_renderer().send(msg); } - pub fn set_bitmap_dimensions(&self, size: Size2D<Au>) { - let size = Size2D::new(size.width.to_px(), size.height.to_px()); - self.context.set_bitmap_dimensions(size); + pub fn set_bitmap_dimensions(&self, + size: TypedSize2D<f32, CSSPixel>, + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>) + { + let size = size * device_pixel_ratio; + self.device_pixel_ratio.set(device_pixel_ratio); + self.context.set_bitmap_dimensions(size.to_untyped().to_i32()); + self.scale_by_device_pixel_ratio(); + } + + fn scale_by_device_pixel_ratio(&self) { + let device_pixel_ratio = self.device_pixel_ratio.get().get() as f64; + if device_pixel_ratio != 1.0 { + self.Scale(device_pixel_ratio, device_pixel_ratio); + } } } @@ -92,12 +110,14 @@ impl PaintRenderingContext2DMethods for PaintRenderingContext2D { // https://html.spec.whatwg.org/multipage/#dom-context-2d-settransform fn SetTransform(&self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) { - self.context.SetTransform(a, b, c, d, e, f) + self.context.SetTransform(a, b, c, d, e, f); + self.scale_by_device_pixel_ratio(); } // https://html.spec.whatwg.org/multipage/#dom-context-2d-resettransform fn ResetTransform(&self) { - self.context.ResetTransform() + self.context.ResetTransform(); + self.scale_by_device_pixel_ratio(); } // https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha diff --git a/components/script/dom/paintsize.rs b/components/script/dom/paintsize.rs index c012850f344..df94bd36566 100644 --- a/components/script/dom/paintsize.rs +++ b/components/script/dom/paintsize.rs @@ -2,7 +2,6 @@ * 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 app_units::Au; use dom::bindings::codegen::Bindings::PaintSizeBinding; use dom::bindings::codegen::Bindings::PaintSizeBinding::PaintSizeMethods; use dom::bindings::js::Root; @@ -11,7 +10,8 @@ use dom::bindings::reflector::Reflector; use dom::bindings::reflector::reflect_dom_object; use dom::paintworkletglobalscope::PaintWorkletGlobalScope; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::TypedSize2D; +use style_traits::CSSPixel; #[dom_struct] pub struct PaintSize { @@ -21,15 +21,15 @@ pub struct PaintSize { } impl PaintSize { - fn new_inherited(size: Size2D<Au>) -> PaintSize { + fn new_inherited(size: TypedSize2D<f32, CSSPixel>) -> PaintSize { PaintSize { reflector: Reflector::new(), - width: Finite::wrap(size.width.to_px().abs() as f64), - height: Finite::wrap(size.height.to_px().abs() as f64), + width: Finite::wrap(size.width as f64), + height: Finite::wrap(size.height as f64), } } - pub fn new(global: &PaintWorkletGlobalScope, size: Size2D<Au>) -> Root<PaintSize> { + pub fn new(global: &PaintWorkletGlobalScope, size: TypedSize2D<f32, CSSPixel>) -> Root<PaintSize> { reflect_dom_object(box PaintSize::new_inherited(size), global, PaintSizeBinding::Wrap) } } diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs index 95f885cd662..058c017693f 100644 --- a/components/script/dom/paintworkletglobalscope.rs +++ b/components/script/dom/paintworkletglobalscope.rs @@ -2,7 +2,6 @@ * 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 app_units::Au; use canvas_traits::CanvasData; use canvas_traits::CanvasImageData; use dom::bindings::callback::CallbackContainer; @@ -27,7 +26,8 @@ use dom::workletglobalscope::WorkletGlobalScope; use dom::workletglobalscope::WorkletGlobalScopeInit; use dom::workletglobalscope::WorkletTask; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::ScaleFactor; +use euclid::TypedSize2D; use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSharedMemory; use js::jsapi::Call; @@ -59,6 +59,8 @@ use std::ptr::null_mut; use std::rc::Rc; use std::sync::Arc; use std::sync::Mutex; +use style_traits::CSSPixel; +use style_traits::DevicePixel; /// https://drafts.css-houdini.org/css-paint-api/#paintworkletglobalscope #[dom_struct] @@ -94,9 +96,9 @@ impl PaintWorkletGlobalScope { pub fn perform_a_worklet_task(&self, task: PaintWorkletTask) { match task { - PaintWorkletTask::DrawAPaintImage(name, size, properties, sender) => { + PaintWorkletTask::DrawAPaintImage(name, size, device_pixel_ratio, properties, sender) => { let properties = StylePropertyMapReadOnly::from_iter(self.upcast(), properties); - self.draw_a_paint_image(name, size, &*properties, sender); + self.draw_a_paint_image(name, size, device_pixel_ratio, &*properties, sender); } } } @@ -104,25 +106,28 @@ impl PaintWorkletGlobalScope { /// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image fn draw_a_paint_image(&self, name: Atom, - size: Size2D<Au>, + size_in_px: TypedSize2D<f32, CSSPixel>, + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>, properties: &StylePropertyMapReadOnly, sender: IpcSender<CanvasData>) { // TODO: document paint definitions. - self.invoke_a_paint_callback(name, size, properties, sender); + self.invoke_a_paint_callback(name, size_in_px, device_pixel_ratio, properties, sender); } /// https://drafts.css-houdini.org/css-paint-api/#invoke-a-paint-callback #[allow(unsafe_code)] fn invoke_a_paint_callback(&self, name: Atom, - size: Size2D<Au>, + size_in_px: TypedSize2D<f32, CSSPixel>, + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>, properties: &StylePropertyMapReadOnly, sender: IpcSender<CanvasData>) { - let width = size.width.to_px().abs() as u32; - let height = size.height.to_px().abs() as u32; - debug!("Invoking a paint callback {}({},{}).", name, width, height); + let size_in_dpx = size_in_px * device_pixel_ratio; + let size_in_dpx = TypedSize2D::new(size_in_dpx.width.abs() as u32, size_in_dpx.height.abs() as u32); + debug!("Invoking a paint callback {}({},{}) at {}.", + name, size_in_px.width, size_in_px.height, device_pixel_ratio); let cx = self.worklet_global.get_cx(); let _ac = JSAutoCompartment::new(cx, self.worklet_global.reflector().get_jsobject().get()); @@ -135,13 +140,13 @@ impl PaintWorkletGlobalScope { None => { // Step 2.2. warn!("Drawing un-registered paint definition {}.", name); - return self.send_invalid_image(size, sender); + return self.send_invalid_image(size_in_dpx, sender); } Some(definition) => { // Step 5.1 if !definition.constructor_valid_flag.get() { debug!("Drawing invalid paint definition {}.", name); - return self.send_invalid_image(size, sender); + return self.send_invalid_image(size_in_dpx, sender); } class_constructor.set(definition.class_constructor.get()); paint_function.set(definition.paint_function.get()); @@ -169,7 +174,7 @@ impl PaintWorkletGlobalScope { self.paint_definitions.borrow_mut().get_mut(&name) .expect("Vanishing paint definition.") .constructor_valid_flag.set(false); - return self.send_invalid_image(size, sender); + return self.send_invalid_image(size_in_dpx, sender); } // Step 5.4 entry.insert(Box::new(Heap::default())).set(paint_instance.get()); @@ -180,10 +185,10 @@ impl PaintWorkletGlobalScope { // Step 8 // TODO: the spec requires creating a new paint rendering context each time, // this code recycles the same one. - rendering_context.set_bitmap_dimensions(size); + rendering_context.set_bitmap_dimensions(size_in_px, device_pixel_ratio); // Step 9 - let paint_size = PaintSize::new(self, size); + let paint_size = PaintSize::new(self, size_in_px); // TODO: Step 10 // Steps 11-12 @@ -202,17 +207,19 @@ impl PaintWorkletGlobalScope { if unsafe { JS_IsExceptionPending(cx) } { debug!("Paint function threw an exception {}.", name); unsafe { JS_ClearPendingException(cx); } - return self.send_invalid_image(size, sender); + return self.send_invalid_image(size_in_dpx, sender); } rendering_context.send_data(sender); } - // https://drafts.csswg.org/css-images-4/#invalid-image - fn send_invalid_image(&self, size: Size2D<Au>, sender: IpcSender<CanvasData>) { + fn send_invalid_image(&self, + size: TypedSize2D<u32, DevicePixel>, + sender: IpcSender<CanvasData>) + { debug!("Sending an invalid image."); - let width = size.width.to_px().abs() as u32; - let height = size.height.to_px().abs() as u32; + let width = size.width as u32; + let height = size.height as u32; let len = (width as usize) * (height as usize) * 4; let pixel = [0x00, 0x00, 0x00, 0x00]; let bytes: Vec<u8> = pixel.iter().cloned().cycle().take(len).collect(); @@ -235,12 +242,13 @@ impl PaintWorkletGlobalScope { struct WorkletPainter(Atom, Mutex<WorkletExecutor>); impl Painter for WorkletPainter { fn draw_a_paint_image(&self, - size: Size2D<Au>, + size: TypedSize2D<f32, CSSPixel>, + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>, properties: Vec<(Atom, String)>, sender: IpcSender<CanvasData>) { let name = self.0.clone(); - let task = PaintWorkletTask::DrawAPaintImage(name, size, properties, sender); + let task = PaintWorkletTask::DrawAPaintImage(name, size, device_pixel_ratio, properties, sender); self.1.lock().expect("Locking a painter.") .schedule_a_worklet_task(WorkletTask::Paint(task)); } @@ -334,7 +342,11 @@ impl PaintWorkletGlobalScopeMethods for PaintWorkletGlobalScope { /// Tasks which can be peformed by a paint worklet pub enum PaintWorkletTask { - DrawAPaintImage(Atom, Size2D<Au>, Vec<(Atom, String)>, IpcSender<CanvasData>) + DrawAPaintImage(Atom, + TypedSize2D<f32, CSSPixel>, + ScaleFactor<f32, CSSPixel, DevicePixel>, + Vec<(Atom, String)>, + IpcSender<CanvasData>) } /// A paint definition diff --git a/components/script_traits/Cargo.toml b/components/script_traits/Cargo.toml index 8a8965ce3e3..70fcdbb3f33 100644 --- a/components/script_traits/Cargo.toml +++ b/components/script_traits/Cargo.toml @@ -10,7 +10,6 @@ name = "script_traits" path = "lib.rs" [dependencies] -app_units = "0.5" bluetooth_traits = {path = "../bluetooth_traits"} canvas_traits = {path = "../canvas_traits"} cookie = "0.6" diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 40b8532ab54..72af4d23108 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -9,7 +9,6 @@ #![deny(missing_docs)] #![deny(unsafe_code)] -extern crate app_units; extern crate bluetooth_traits; extern crate canvas_traits; extern crate cookie as cookie_rs; @@ -39,7 +38,6 @@ extern crate webvr_traits; mod script_msg; pub mod webdriver_msg; -use app_units::Au; use bluetooth_traits::BluetoothRequest; use canvas_traits::CanvasData; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId}; @@ -68,6 +66,7 @@ use std::fmt; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, RecvTimeoutError}; use style_traits::CSSPixel; +use style_traits::DevicePixel; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; use webrender_api::ClipId; use webvr_traits::{WebVREvent, WebVRMsg}; @@ -687,12 +686,6 @@ pub struct ScrollState { pub scroll_offset: Vector2D<f32>, } -/// One hardware pixel. -/// -/// This unit corresponds to the smallest addressable element of the display hardware. -#[derive(Copy, Clone, Debug)] -pub enum DevicePixel {} - /// Data about the window size. #[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)] pub struct WindowSizeData { @@ -828,7 +821,8 @@ impl From<RecvTimeoutError> for PaintWorkletError { pub trait Painter: Sync + Send { /// https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image fn draw_a_paint_image(&self, - concrete_object_size: Size2D<Au>, + size: TypedSize2D<f32, CSSPixel>, + zoom: ScaleFactor<f32, CSSPixel, DevicePixel>, properties: Vec<(Atom, String)>, sender: IpcSender<CanvasData>); } diff --git a/components/style/context.rs b/components/style/context.rs index befcd9d9e03..e9733cb0985 100644 --- a/components/style/context.rs +++ b/components/style/context.rs @@ -11,6 +11,7 @@ use bloom::StyleBloom; use cache::LRUCache; use data::{EagerPseudoStyles, ElementData}; use dom::{OpaqueNode, TNode, TElement, SendElement}; +use euclid::ScaleFactor; use euclid::Size2D; use fnv::FnvHashMap; use font_metrics::FontMetricsProvider; @@ -27,6 +28,8 @@ use std::fmt; use std::ops; #[cfg(feature = "servo")] use std::sync::Mutex; #[cfg(feature = "servo")] use std::sync::mpsc::Sender; +use style_traits::CSSPixel; +use style_traits::DevicePixel; use stylist::Stylist; use thread_state; use time; @@ -152,6 +155,11 @@ impl<'a> SharedStyleContext<'a> { pub fn viewport_size(&self) -> Size2D<Au> { self.stylist.device().au_viewport_size() } + + /// The device pixel ratio + pub fn device_pixel_ratio(&self) -> ScaleFactor<f32, CSSPixel, DevicePixel> { + self.stylist.device().device_pixel_ratio() + } } /// The structure holds various intermediate inputs that are eventually used by diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 922a5df637f..8b0e00b91fe 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -4,9 +4,11 @@ //! Gecko's media-query device and expression representation. +use app_units::AU_PER_PX; use app_units::Au; use context::QuirksMode; use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseError}; +use euclid::ScaleFactor; use euclid::Size2D; use font_metrics::get_metrics_provider_for_product; use gecko::values::convert_nscolor_to_rgba; @@ -25,6 +27,7 @@ use std::fmt::{self, Write}; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; use str::starts_with_ignore_ascii_case; use string_cache::Atom; +use style_traits::{CSSPixel, DevicePixel}; use style_traits::{ToCss, ParseError, StyleParseError}; use style_traits::viewport::ViewportConstraints; use values::{CSSFloat, specified}; @@ -153,6 +156,15 @@ impl Device { }) } + /// Returns the device pixel ratio. + pub fn device_pixel_ratio(&self) -> ScaleFactor<f32, CSSPixel, DevicePixel> { + let override_dppx = self.pres_context().mOverrideDPPX; + if override_dppx > 0.0 { return ScaleFactor::new(override_dppx); } + let au_per_dpx = self.pres_context().mCurAppUnitsPerDevPixel as f32; + let au_per_px = AU_PER_PX as f32; + ScaleFactor::new(au_per_px / au_per_dpx) + } + /// Returns whether document colors are enabled. pub fn use_document_colors(&self) -> bool { self.pres_context().mUseDocumentColors() != 0 diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index 4c56860d2cd..7583a89f7da 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -7,7 +7,7 @@ use app_units::Au; use context::QuirksMode; use cssparser::{Parser, RGBA}; -use euclid::{Size2D, TypedSize2D}; +use euclid::{ScaleFactor, Size2D, TypedSize2D}; use font_metrics::ServoMetricsProvider; use media_queries::MediaType; use parser::ParserContext; @@ -16,7 +16,7 @@ use properties::longhands::font_size; use selectors::parser::SelectorParseError; use std::fmt; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; -use style_traits::{CSSPixel, ToCss, ParseError}; +use style_traits::{CSSPixel, DevicePixel, ToCss, ParseError}; use style_traits::viewport::ViewportConstraints; use values::computed::{self, ToComputedValue}; use values::specified; @@ -31,6 +31,8 @@ pub struct Device { media_type: MediaType, /// The current viewport size, in CSS pixels. viewport_size: TypedSize2D<f32, CSSPixel>, + /// The current device pixel ratio, from CSS pixels to device pixels. + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>, /// The font size of the root element /// This is set when computing the style of the root @@ -51,11 +53,13 @@ pub struct Device { impl Device { /// Trivially construct a new `Device`. pub fn new(media_type: MediaType, - viewport_size: TypedSize2D<f32, CSSPixel>) + viewport_size: TypedSize2D<f32, CSSPixel>, + device_pixel_ratio: ScaleFactor<f32, CSSPixel, DevicePixel>) -> Device { Device { media_type: media_type, viewport_size: viewport_size, + device_pixel_ratio: device_pixel_ratio, root_font_size: AtomicIsize::new(font_size::get_initial_value().0 as isize), // FIXME(bz): Seems dubious? used_root_font_size: AtomicBool::new(false), } @@ -99,6 +103,11 @@ impl Device { self.viewport_size } + /// Returns the device pixel ratio. + pub fn device_pixel_ratio(&self) -> ScaleFactor<f32, CSSPixel, DevicePixel> { + self.device_pixel_ratio + } + /// 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; diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index b0b299ec64f..5047388ac37 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -59,6 +59,12 @@ impl PinchZoomFactor { #[derive(Clone, Copy, Debug)] pub enum CSSPixel {} +/// One hardware pixel. +/// +/// This unit corresponds to the smallest addressable element of the display hardware. +#[derive(Copy, Clone, Debug)] +pub enum DevicePixel {} + // In summary, the hierarchy of pixel units and the factors to convert from one to the next: // // DevicePixel diff --git a/ports/cef/window.rs b/ports/cef/window.rs index f38a7c11a74..b598e35abdd 100644 --- a/ports/cef/window.rs +++ b/ports/cef/window.rs @@ -23,7 +23,7 @@ use euclid::{Point2D, TypedPoint2D, TypedRect, Size2D, TypedSize2D, ScaleFactor} use gleam::gl; use msg::constellation_msg::{Key, KeyModifiers}; use net_traits::net_error_list::NetError; -use script_traits::{DevicePixel, LoadData}; +use script_traits::LoadData; use servo::ipc_channel::ipc::IpcSender; use servo_geometry::DeviceIndependentPixel; use std::cell::RefCell; @@ -34,6 +34,7 @@ use std::rc::Rc; use std::sync::mpsc::{Sender, channel}; use servo_url::ServoUrl; use style_traits::cursor::Cursor; +use style_traits::DevicePixel; #[cfg(target_os="linux")] extern crate x11; #[cfg(target_os="linux")] diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index b35b7d5f3c0..b3ea8be90c0 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -24,7 +24,7 @@ use msg::constellation_msg::{ALT, CONTROL, KeyState, NONE, SHIFT, SUPER, Travers use net_traits::net_error_list::NetError; #[cfg(any(target_os = "linux", target_os = "macos"))] use osmesa_sys; -use script_traits::{DevicePixel, LoadData, TouchEventType, TouchpadPressurePhase}; +use script_traits::{LoadData, TouchEventType, TouchpadPressurePhase}; use servo::ipc_channel::ipc::IpcSender; use servo_config::opts; use servo_config::prefs::PREFS; @@ -39,6 +39,7 @@ use std::mem; use std::os::raw::c_void; use std::ptr; use std::rc::Rc; +use style_traits::DevicePixel; use style_traits::cursor::Cursor; #[cfg(target_os = "windows")] use user32; diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs index dc24eed3594..0fa770f4ae6 100644 --- a/tests/unit/style/media_queries.rs +++ b/tests/unit/style/media_queries.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::{Parser, SourcePosition}; +use euclid::ScaleFactor; use euclid::TypedSize2D; use servo_arc::Arc; use servo_url::ServoUrl; @@ -39,7 +40,7 @@ fn test_media_rule<F>(css: &str, callback: F) let stylesheet = Stylesheet::from_str( css, url, Origin::Author, media_list, lock, None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0u64); - let dummy = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0)); + let dummy = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0), ScaleFactor::new(1.0)); let mut rule_count = 0; let guard = stylesheet.shared_lock.read(); for rule in stylesheet.iter_rules::<AllRules>(&dummy, &guard) { @@ -342,7 +343,7 @@ fn test_mq_malformed_expressions() { #[test] fn test_matching_simple() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0), ScaleFactor::new(1.0)); media_query_test(&device, "@media not all { a { color: red; } }", 0); media_query_test(&device, "@media not screen { a { color: red; } }", 0); @@ -358,7 +359,7 @@ fn test_matching_simple() { #[test] fn test_matching_width() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0), ScaleFactor::new(1.0)); media_query_test(&device, "@media { a { color: red; } }", 1); @@ -399,7 +400,7 @@ fn test_matching_width() { #[test] fn test_matching_invalid() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(200.0, 100.0), ScaleFactor::new(1.0)); media_query_test(&device, "@media fridge { a { color: red; } }", 0); media_query_test(&device, "@media screen and (height: 100px) { a { color: red; } }", 0); diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index bf3f1c12e08..ed69ee9fe70 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -5,6 +5,7 @@ //! Tests for parsing and serialization of values/properties use cssparser::{Parser, ParserInput}; +use euclid::ScaleFactor; use euclid::TypedSize2D; use media_queries::CSSErrorReporterTest; use style::context::QuirksMode; @@ -50,7 +51,7 @@ fn assert_computed_serialization<C, F, T>(f: F, input: &'static str, output: &st { let viewport_size = TypedSize2D::new(0., 0.); let initial_style = ComputedValues::initial_values(); - let device = Device::new(MediaType::Screen, viewport_size); + let device = Device::new(MediaType::Screen, viewport_size, ScaleFactor::new(1.0)); let context = Context { is_root_element: true, diff --git a/tests/unit/style/stylist.rs b/tests/unit/style/stylist.rs index b1cf2ef2508..f4d319d33a4 100644 --- a/tests/unit/style/stylist.rs +++ b/tests/unit/style/stylist.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::SourceLocation; +use euclid::ScaleFactor; use euclid::TypedSize2D; use html5ever::LocalName; use selectors::parser::{AncestorHashes, Selector}; @@ -235,7 +236,7 @@ fn test_get_universal_rules() { } fn mock_stylist() -> Stylist { - let device = Device::new(MediaType::Screen, TypedSize2D::new(0f32, 0f32)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(0f32, 0f32), ScaleFactor::new(1.0)); Stylist::new(device, QuirksMode::NoQuirks) } diff --git a/tests/unit/style/viewport.rs b/tests/unit/style/viewport.rs index 9f71e312925..3affe7434c4 100644 --- a/tests/unit/style/viewport.rs +++ b/tests/unit/style/viewport.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::{Parser, ParserInput}; +use euclid::ScaleFactor; use euclid::TypedSize2D; use media_queries::CSSErrorReporterTest; use servo_arc::Arc; @@ -96,7 +97,7 @@ macro_rules! viewport_length { #[test] fn empty_viewport_rule() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.), ScaleFactor::new(1.0)); test_viewport_rule("@viewport {}", &device, |declarations, css| { println!("{}", css); @@ -119,7 +120,7 @@ macro_rules! assert_decl_eq { #[test] fn simple_viewport_rules() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.), ScaleFactor::new(1.0)); test_viewport_rule("@viewport { width: auto; height: auto;\ zoom: auto; min-zoom: 0; max-zoom: 200%;\ @@ -191,7 +192,7 @@ fn simple_meta_viewport_contents() { #[test] fn cascading_within_viewport_rule() { - let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.), ScaleFactor::new(1.0)); // normal order of appearance test_viewport_rule("@viewport { min-width: 200px; min-width: auto; }", @@ -257,7 +258,7 @@ fn cascading_within_viewport_rule() { #[test] fn multiple_stylesheets_cascading() { PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); - let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.)); + let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.), ScaleFactor::new(1.0)); let error_reporter = CSSErrorReporterTest; let shared_lock = SharedRwLock::new(); let stylesheets = vec![ @@ -313,7 +314,7 @@ fn constrain_viewport() { } let initial_viewport = TypedSize2D::new(800., 600.); - let device = Device::new(MediaType::Screen, initial_viewport); + let device = Device::new(MediaType::Screen, initial_viewport, ScaleFactor::new(1.0)); let mut input = ParserInput::new(""); assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks), None); @@ -362,7 +363,7 @@ fn constrain_viewport() { })); let initial_viewport = TypedSize2D::new(200., 150.); - let device = Device::new(MediaType::Screen, initial_viewport); + let device = Device::new(MediaType::Screen, initial_viewport, ScaleFactor::new(1.0)); let mut input = ParserInput::new("width: 320px auto"); assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(input), QuirksMode::NoQuirks), Some(ViewportConstraints { |