diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index ce59bd392c..24a3e7f1b5 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -10,7 +10,7 @@ use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use prim_store::{ClipData, ImageMaskData}; use resource_cache::ResourceCache; -use util::{MaxRect, calculate_screen_bounding_rect, extract_inner_rect_safe}; +use util::{MaxRect, calculate_screen_inner_rect, calculate_screen_bounding_rect, extract_inner_rect_safe}; pub type ClipStore = FreeList; pub type ClipSourcesHandle = FreeListHandle; @@ -252,7 +252,7 @@ impl ClipSources { device_pixel_ratio: f32, ) -> (DeviceIntRect, Option) { let screen_inner_rect = - calculate_screen_bounding_rect(transform, &self.local_inner_rect, device_pixel_ratio); + calculate_screen_inner_rect(transform, &self.local_inner_rect, device_pixel_ratio); let screen_outer_rect = self.local_outer_rect.map(|outer_rect| calculate_screen_bounding_rect(transform, &outer_rect, device_pixel_ratio) ); diff --git a/webrender/src/util.rs b/webrender/src/util.rs index e3e9ea73cc..b6252883f5 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -4,11 +4,11 @@ use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, DeviceRect}; use api::{DeviceSize, LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, WorldRect}; -use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D}; -use euclid::TypedTransform3D; +use euclid::{Point2D, Rect, ScaleFactor, Size2D, TypedPoint2D, TypedRect, TypedSize2D}; +use euclid::{TypedTransform2D, TypedTransform3D}; use num_traits::Zero; -use std::i32; -use std::f32; +use std::{i32, f32}; +use std::cmp::Ordering; // Matches the definition of SK_ScalarNearlyZero in Skia. const NEARLY_ZERO: f32 = 1.0 / 4096.0; @@ -143,20 +143,52 @@ pub fn calculate_screen_bounding_rect( rect: &LayerRect, device_pixel_ratio: f32 ) -> DeviceIntRect { - let rect = WorldRect::from_points(&[ + let points = [ transform.transform_point2d(&rect.origin), transform.transform_point2d(&rect.top_right()), transform.transform_point2d(&rect.bottom_left()), transform.transform_point2d(&rect.bottom_right()), - ]) * device_pixel_ratio; + ]; + + let scale = ScaleFactor::new(device_pixel_ratio); + let rect: DeviceRect = WorldRect::from_points(&points) * scale; + + let max_rect = DeviceRect::max_rect(); + rect + .round_out() + .intersection(&max_rect) + .unwrap_or(max_rect) + .to_i32() +} + +pub fn calculate_screen_inner_rect( + transform: &LayerToWorldTransform, + rect: &LayerRect, + device_pixel_ratio: f32 +) -> DeviceIntRect { + let points = [ + transform.transform_point2d(&rect.origin), + transform.transform_point2d(&rect.top_right()), + transform.transform_point2d(&rect.bottom_left()), + transform.transform_point2d(&rect.bottom_right()), + ]; + let mut xs = [points[0].x, points[1].x, points[2].x, points[3].x]; + let mut ys = [points[0].y, points[1].y, points[2].y, points[3].y]; + + xs.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + ys.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); let rect = DeviceRect::new( - DevicePoint::new(rect.origin.x, rect.origin.y), - DeviceSize::new(rect.size.width, rect.size.height), - ); + DevicePoint::new(xs[1], ys[1]), + DeviceSize::new(xs[2] - xs[1], ys[2] - ys[1]), + ) * device_pixel_ratio; let max_rect = DeviceRect::max_rect(); - rect.round_out().intersection(&max_rect).unwrap_or(max_rect).to_i32() + rect + .intersection(&max_rect) + .unwrap_or(max_rect) + .round_in() + .to_i32() } pub fn _subtract_rect( diff --git a/wrench/reftests/clip/clip-45-degree-rotation-ref.png b/wrench/reftests/clip/clip-45-degree-rotation-ref.png new file mode 100644 index 0000000000..5a5e9ac10b Binary files /dev/null and b/wrench/reftests/clip/clip-45-degree-rotation-ref.png differ diff --git a/wrench/reftests/clip/clip-45-degree-rotation.yaml b/wrench/reftests/clip/clip-45-degree-rotation.yaml new file mode 100644 index 0000000000..04cfed5a29 --- /dev/null +++ b/wrench/reftests/clip/clip-45-degree-rotation.yaml @@ -0,0 +1,35 @@ +# Test that transformed content is clipped properly by clips with a different transform. +--- +root: + items: + - + bounds: [0, 0, 0, 0] + "clip-rect": [0, 0, 0, 0] + "clip-and-scroll": 0 + type: "stacking-context" + transform: rotate(45) translate(200, 0) + items: + - + bounds: [0, 0, 300, 300] + "clip-rect": [0, 0, 300, 300] + "clip-and-scroll": 0 + type: rect + color: red + - + bounds: [0, 0, 300, 300] + "clip-rect": [0, 0, 300, 300] + "clip-and-scroll": 0 + type: clip + id: 5 + - + bounds: [0, 0, 0, 0] + "clip-rect": [0, 0, 0, 0] + "clip-and-scroll": 5 + type: "stacking-context" + transform: rotate(-45) translate(-300, 0) + items: + - + bounds: [0, 0, 1598, 1200] + "clip-rect": [0, 0, 1598, 1200] + type: rect + color: green diff --git a/wrench/reftests/clip/reftest.list b/wrench/reftests/clip/reftest.list index 54a7e7337d..c414cde627 100644 --- a/wrench/reftests/clip/reftest.list +++ b/wrench/reftests/clip/reftest.list @@ -1,3 +1,3 @@ == clip-mode.yaml clip-mode.png == clip-ellipse.yaml clip-ellipse.png - +== clip-45-degree-rotation.yaml clip-45-degree-rotation-ref.png