Skip to content

Commit

Permalink
Auto merge of #17499 - asajeffrey:script-paint-worklets-zoom, r=glennw
Browse files Browse the repository at this point in the history
Fixed scaling artefacts in paint worklets caused by zoom and hidpi

<!-- Please describe your changes on the following line: -->

This PR renders paint worklet canvases at the device pixel resolution, rather than the CSS pixel resolution.

It's a dependent PR, building on #17239, #17326 and #17364.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #17454
- [X] These changes do not require tests because we don't run reftests with zoom enabled

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17499)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Jul 21, 2017
2 parents 4616f4a + caa3585 commit 9fcbeb3
Show file tree
Hide file tree
Showing 24 changed files with 160 additions and 77 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions components/compositing/compositor.rs
Expand Up @@ -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};
Expand All @@ -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};
Expand Down
3 changes: 2 additions & 1 deletion components/compositing/touch.rs
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion components/compositing/windowing.rs
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion components/constellation/pipeline.rs
Expand Up @@ -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};
Expand All @@ -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;

Expand Down
13 changes: 8 additions & 5 deletions components/layout/display_list_builder.rs
Expand Up @@ -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.
Expand All @@ -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),
}
Expand Down
8 changes: 6 additions & 2 deletions components/layout_thread/lib.rs
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand All @@ -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 =
Expand Down
9 changes: 8 additions & 1 deletion components/script/dom/bindings/trace.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion components/script/dom/mediaquerylist.rs
Expand Up @@ -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
Expand Down
32 changes: 26 additions & 6 deletions components/script/dom/paintrenderingcontext2d.rs
Expand Up @@ -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;
Expand All @@ -26,19 +25,26 @@ 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 {
fn new_inherited(global: &PaintWorkletGlobalScope) -> PaintRenderingContext2D {
let size = Size2D::zero();
PaintRenderingContext2D {
context: CanvasRenderingContext2D::new_inherited(global.upcast(), None, size),
device_pixel_ratio: Cell::new(ScaleFactor::new(1.0)),
}
}

Expand All @@ -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);
}
}
}

Expand Down Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions components/script/dom/paintsize.rs
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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)
}
}
Expand Down

0 comments on commit 9fcbeb3

Please sign in to comment.