diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index e4584abad8..fb4a57e69e 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -4,18 +4,20 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelScale, ImageMask}; use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D, LocalClip}; -use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle, LayoutTransform}; +use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle}; +use api::{LayoutToWorldTransform, WorldPixel, WorldRect, WorldPoint, WorldSize}; use border::{ensure_no_corner_overlap}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey}; use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, SpatialNodeIndex}; use ellipse::Ellipse; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use gpu_types::BoxShadowStretchMode; -use prim_store::{BrushClipMaskKind, ClipData, ImageMaskData}; +use plane_split::{Clipper, Polygon}; +use prim_store::{ClipData, ImageMaskData}; use render_task::to_cache_size; use resource_cache::{ImageRequest, ResourceCache}; -use std::u32; -use util::{extract_inner_rect_safe, pack_as_float, recycle_vec, MatrixHelpers}; +use std::{cmp, u32}; +use util::{extract_inner_rect_safe, pack_as_float, recycle_vec, MaxRect}; /* @@ -199,41 +201,7 @@ pub struct ClipNodeRange { enum ClipSpaceConversion { Local, Offset(LayoutVector2D), - Transform(LayoutTransform, LayoutTransform), -} - -impl ClipSpaceConversion { - fn transform_to_prim_space(&self, rect: &LayoutRect) -> Option { - match *self { - ClipSpaceConversion::Local => { - Some(*rect) - } - ClipSpaceConversion::Offset(ref offset) => { - Some(rect.translate(offset)) - } - ClipSpaceConversion::Transform(ref transform, _) => { - if transform.has_perspective_component() { - None - } else { - transform.transform_rect(rect) - } - } - } - } - - fn transform_from_prim_space(&self, rect: &LayoutRect) -> Option { - match *self { - ClipSpaceConversion::Local => { - Some(*rect) - } - ClipSpaceConversion::Offset(offset) => { - Some(rect.translate(&-offset)) - } - ClipSpaceConversion::Transform(_, ref inv_transform) => { - inv_transform.transform_rect(rect) - } - } - } + Transform(LayoutToWorldTransform), } // Temporary information that is cached and reused @@ -356,8 +324,7 @@ pub struct ClipChainInstance { pub clips_range: ClipNodeRange, pub local_clip_rect: LayoutRect, pub has_non_root_coord_system: bool, - pub local_bounding_rect: LayoutRect, - pub clip_mask_kind: BrushClipMaskKind, + pub world_clip_rect: WorldRect, } impl ClipStore { @@ -453,17 +420,12 @@ impl ClipStore { resource_cache: &mut ResourceCache, device_pixel_scale: DevicePixelScale, ) -> Option { - // Trivial check to see if the primitive is clipped out by the - // local clip rect of the primitive itself. - let mut local_bounding_rect = match local_prim_rect.intersection(&local_prim_clip_rect) { - Some(rect) => rect, - None => return None, - }; - let mut current_local_clip_rect = local_prim_clip_rect; + let mut local_clip_rect = local_prim_clip_rect; + let mut world_clip_rect = WorldRect::max_rect(); let spatial_nodes = &clip_scroll_tree.spatial_nodes; // Walk the clip chain to build local rects, and collect the - // smallest possible local clip area. + // smallest possible local/device clip area. self.clip_node_info.clear(); let ref_spatial_node = &spatial_nodes[spatial_node_index.0]; @@ -491,13 +453,11 @@ impl ClipStore { } else { let xf = clip_scroll_tree.get_relative_transform( clip_node.spatial_node_index, - spatial_node_index, + SpatialNodeIndex(0), ); - xf.and_then(|xf| { - xf.inverse().map(|inv| { - ClipSpaceConversion::Transform(xf, inv) - }) + xf.map(|xf| { + ClipSpaceConversion::Transform(xf.with_destination::()) }) }; @@ -505,20 +465,33 @@ impl ClipStore { // requested, and cache the conversion information for the next step. if let Some(conversion) = conversion { if let Some(clip_rect) = clip_node.item.get_local_clip_rect() { - let clip_rect = conversion.transform_to_prim_space(&clip_rect); - if let Some(clip_rect) = clip_rect { - local_bounding_rect = match local_bounding_rect.intersection(&clip_rect) { - Some(new_local_bounding_rect) => new_local_bounding_rect, - None => return None, - }; - - if ref_spatial_node.coordinate_system_id == clip_spatial_node.coordinate_system_id { - current_local_clip_rect = match current_local_clip_rect.intersection(&clip_rect) { - Some(new_local_clip_rect) => new_local_clip_rect, - None => { - return None - } - } + match conversion { + ClipSpaceConversion::Local => { + local_clip_rect = match local_clip_rect.intersection(&clip_rect) { + Some(local_clip_rect) => local_clip_rect, + None => return None, + }; + } + ClipSpaceConversion::Offset(ref offset) => { + let clip_rect = clip_rect.translate(offset); + local_clip_rect = match local_clip_rect.intersection(&clip_rect) { + Some(local_clip_rect) => local_clip_rect, + None => return None, + }; + } + ClipSpaceConversion::Transform(ref transform) => { + let world_clip_rect_for_item = match project_rect( + transform, + &clip_rect, + ) { + Some(rect) => rect, + None => return None, + }; + + world_clip_rect = match world_clip_rect.intersection(&world_clip_rect_for_item) { + Some(world_clip_rect) => world_clip_rect, + None => return None, + }; } } } @@ -533,6 +506,24 @@ impl ClipStore { current_clip_chain_id = clip_chain_node.parent_clip_chain_id; } + let local_bounding_rect = match local_prim_rect.intersection(&local_clip_rect) { + Some(rect) => rect, + None => return None, + }; + + let world_bounding_rect = match project_rect( + &ref_spatial_node.world_content_transform.to_transform(), + &local_bounding_rect, + ) { + Some(world_bounding_rect) => world_bounding_rect, + None => return None, + }; + + let world_clip_rect = match world_clip_rect.intersection(&world_bounding_rect) { + Some(world_clip_rect) => world_clip_rect, + None => return None, + }; + // Now, we've collected all the clip nodes that *potentially* affect this // primitive region, and reduced the size of the prim region as much as possible. @@ -540,36 +531,24 @@ impl ClipStore { let first_clip_node_index = self.clip_node_indices.len() as u32; let mut has_non_root_coord_system = false; - let mut clip_mask_kind = BrushClipMaskKind::Individual; // For each potential clip node for node_info in self.clip_node_info.drain(..) { let node = &mut self.clip_nodes[node_info.node_index.0 as usize]; - // TODO(gw): We can easily extend the segment builder to support these clip sources in - // the future, but they are rarely used. - // We must do this check here in case we continue early below. - if node.item.is_image_or_line_decoration_clip() { - clip_mask_kind = BrushClipMaskKind::Global; - } - - // Convert the prim rect into the clip nodes local space - let prim_rect = node_info - .conversion - .transform_from_prim_space(¤t_local_clip_rect); - // See how this clip affects the prim region. - let clip_result = match prim_rect { - Some(prim_rect) => { - node.item.get_clip_result(&prim_rect) + let clip_result = match node_info.conversion { + ClipSpaceConversion::Local => { + node.item.get_clip_result(&local_bounding_rect) } - None => { - // If we can't get a local rect due to perspective - // weirdness, just assume that we need a clip mask - // for this case. - // TODO(gw): We can probably improve on this once - // we support local space picture raster. - ClipResult::Partial + ClipSpaceConversion::Offset(offset) => { + node.item.get_clip_result(&local_bounding_rect.translate(&-offset)) + } + ClipSpaceConversion::Transform(ref transform) => { + node.item.get_clip_result_complex( + transform, + &world_bounding_rect, + ) } }; @@ -598,15 +577,9 @@ impl ClipStore { ClipNodeFlags::SAME_SPATIAL_NODE | ClipNodeFlags::SAME_COORD_SYSTEM } ClipSpaceConversion::Offset(..) => { - if !node.item.is_rect() { - clip_mask_kind = BrushClipMaskKind::Global; - } ClipNodeFlags::SAME_COORD_SYSTEM } ClipSpaceConversion::Transform(..) => { - // If this primitive is clipped by clips from a different coordinate system, then we - // need to apply a clip mask for the entire primitive. - clip_mask_kind = BrushClipMaskKind::Global; ClipNodeFlags::empty() } }; @@ -630,9 +603,8 @@ impl ClipStore { Some(ClipChainInstance { clips_range, has_non_root_coord_system, - local_clip_rect: current_local_clip_rect, - local_bounding_rect, - clip_mask_kind, + local_clip_rect, + world_clip_rect, }) } } @@ -873,20 +845,6 @@ impl ClipItem { } } - pub fn is_rect(&self) -> bool { - match *self { - ClipItem::Rectangle(..) => true, - _ => false, - } - } - - pub fn is_image_or_line_decoration_clip(&self) -> bool { - match *self { - ClipItem::Image(..) | ClipItem::LineDecoration(..) => true, - _ => false, - } - } - // Get an optional clip rect that a clip source can provide to // reduce the size of a primitive region. This is typically // used to eliminate redundant clips, and reduce the size of @@ -904,6 +862,53 @@ impl ClipItem { } } + fn get_clip_result_complex( + &self, + transform: &LayoutToWorldTransform, + prim_rect: &WorldRect, + ) -> ClipResult { + let (clip_rect, inner_rect) = match *self { + ClipItem::Rectangle(clip_rect, ClipMode::Clip) => { + (clip_rect, Some(clip_rect)) + } + ClipItem::RoundedRectangle(ref clip_rect, ref radius, ClipMode::Clip) => { + let inner_clip_rect = extract_inner_rect_safe(clip_rect, radius); + (*clip_rect, inner_clip_rect) + } + ClipItem::Rectangle(_, ClipMode::ClipOut) | + ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) | + ClipItem::Image(..) | + ClipItem::BoxShadow(..) | + ClipItem::LineDecoration(..) => { + return ClipResult::Partial + } + }; + + let inner_clip_rect = inner_rect.and_then(|ref inner_rect| { + project_inner_rect(transform, inner_rect) + }); + + if let Some(inner_clip_rect) = inner_clip_rect { + if inner_clip_rect.contains_rect(prim_rect) { + return ClipResult::Accept; + } + } + + let outer_clip_rect = match project_rect(transform, &clip_rect) { + Some(outer_clip_rect) => outer_clip_rect, + None => return ClipResult::Partial, + }; + + match outer_clip_rect.intersection(prim_rect) { + Some(..) => { + ClipResult::Partial + } + None => { + ClipResult::Reject + } + } + } + // Check how a given clip source affects a local primitive region. fn get_clip_result( &self, @@ -1056,3 +1061,71 @@ pub fn rounded_rectangle_contains_point( true } + +fn project_rect( + transform: &LayoutToWorldTransform, + rect: &LayoutRect, +) -> Option { + let homogens = [ + transform.transform_point2d_homogeneous(&rect.origin), + transform.transform_point2d_homogeneous(&rect.top_right()), + transform.transform_point2d_homogeneous(&rect.bottom_left()), + transform.transform_point2d_homogeneous(&rect.bottom_right()), + ]; + + // Note: we only do the full frustum collision when the polygon approaches the camera plane. + // Otherwise, it will be clamped to the screen bounds anyway. + if homogens.iter().any(|h| h.w <= 0.0) { + let mut clipper = Clipper::new(); + clipper.add_frustum( + transform, + None, + ); + + let polygon = Polygon::from_rect(*rect, 1); + let results = clipper.clip(polygon); + if results.is_empty() { + return None + } + + Some(WorldRect::from_points(results + .into_iter() + // filter out parts behind the view plane + .flat_map(|poly| &poly.points) + .map(|p| { + let mut homo = transform.transform_point2d_homogeneous(&p.to_2d()); + homo.w = homo.w.max(0.00000001); // avoid infinite values + homo.to_point2d().unwrap() + }) + )) + } else { + // we just checked for all the points to be in positive hemisphere, so `unwrap` is valid + Some(WorldRect::from_points(&[ + homogens[0].to_point2d().unwrap(), + homogens[1].to_point2d().unwrap(), + homogens[2].to_point2d().unwrap(), + homogens[3].to_point2d().unwrap(), + ])) + } +} + +pub fn project_inner_rect( + transform: &LayoutToWorldTransform, + rect: &LayoutRect, +) -> Option { + 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(cmp::Ordering::Equal)); + ys.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal)); + Some(WorldRect::new( + WorldPoint::new(xs[1], ys[1]), + WorldSize::new(xs[2] - xs[1], ys[2] - ys[1]), + )) +} diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index a5274611a5..1aa29257dd 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -24,7 +24,7 @@ use hit_test::{HitTestingItem, HitTestingRun}; use image::simplify_repeated_primitive; use internal_types::{FastHashMap, FastHashSet}; use picture::{PictureCompositeMode, PictureId, PicturePrimitive}; -use prim_store::{BrushClipMaskKind, BrushKind, BrushPrimitive, BrushSegmentDescriptor}; +use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor}; use prim_store::{EdgeAaSegmentMask, ImageSource}; use prim_store::{BorderSource, BrushSegment, PrimitiveContainer, PrimitiveIndex, PrimitiveStore}; use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive}; @@ -1706,7 +1706,6 @@ impl<'a> DisplayListFlattener<'a> { ); let descriptor = BrushSegmentDescriptor { segments, - clip_mask_kind: BrushClipMaskKind::Unknown, }; let brush_kind = match border.source { diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index c5826e081e..451055dbd6 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -28,7 +28,7 @@ use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use resource_cache::{ImageProperties, ImageRequest, ResourceCache}; use scene::SceneProperties; use segment::SegmentBuilder; -use std::{mem, usize}; +use std::{cmp, mem, usize}; use util::{MatrixHelpers, calculate_screen_bounding_rect}; use util::{pack_as_float, recycle_vec, TransformedRectKind}; @@ -482,17 +482,9 @@ impl BrushSegment { } } -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum BrushClipMaskKind { - Unknown, - Individual, - Global, -} - #[derive(Debug)] pub struct BrushSegmentDescriptor { pub segments: Vec, - pub clip_mask_kind: BrushClipMaskKind, } #[derive(Debug)] @@ -1659,21 +1651,9 @@ impl PrimitiveStore { } }; - let clipped_device_rect = match calculate_screen_bounding_rect( - &prim_context.spatial_node.world_content_transform, - &clip_chain.local_bounding_rect, - frame_context.device_pixel_scale, - None, - ) { - Some(rect) => rect, - None => { - if cfg!(debug_assertions) && is_chased { - println!("\tculled for being behind the near plane of transform: {:?}", - prim_context.spatial_node.world_content_transform); - } - return None - } - }; + let clipped_device_rect = (clip_chain.world_clip_rect * frame_context.device_pixel_scale) + .round_out() + .to_i32(); let clipped_device_rect = match clipped_device_rect.intersection(&frame_context.screen_rect) { Some(clipped_device_rect) => clipped_device_rect, @@ -1971,12 +1951,9 @@ fn write_brush_segment_description( frame_state: &mut FrameBuildingState, ) { match brush.segment_desc { - Some(ref segment_desc) => { - // If we already have a segment descriptor, only run through the - // clips list if we haven't already determined the mask kind. - if segment_desc.clip_mask_kind == clip_chain.clip_mask_kind { - return; - } + Some(..) => { + // If we already have a segment descriptor, skip segment build. + return; } None => { // If no segment descriptor built yet, see if it is a brush @@ -2006,6 +1983,7 @@ fn write_brush_segment_description( ); // Segment the primitive on all the local-space clip sources that we can. + let mut local_clip_count = 0; for i in 0 .. clip_chain.clips_range.count { let (clip_node, flags) = frame_state.clip_store.get_node_from_range(&clip_chain.clips_range, i); @@ -2018,6 +1996,8 @@ fn write_brush_segment_description( continue; } + local_clip_count += 1; + let (local_clip_rect, radius, mode) = match clip_node.item { ClipItem::RoundedRectangle(rect, radii, clip_mode) => { rect_clips_only = false; @@ -2063,10 +2043,40 @@ fn write_brush_segment_description( } if is_large || rect_clips_only { - match brush.segment_desc { - Some(ref mut segment_desc) => { - segment_desc.clip_mask_kind = clip_chain.clip_mask_kind; + // If there were no local clips, then we will subdivide the primitive into + // a uniform grid (up to 8x8 segments). This will typically result in + // a significant number of those segments either being completely clipped, + // or determined to not need a clip mask for that segment. + if local_clip_count == 0 && clip_chain.clips_range.count > 0 { + let x_clip_count = cmp::min(8, (metadata.local_rect.size.width / 128.0).ceil() as i32); + let y_clip_count = cmp::min(8, (metadata.local_rect.size.height / 128.0).ceil() as i32); + + for y in 0 .. y_clip_count { + let y0 = metadata.local_rect.size.height * y as f32 / y_clip_count as f32; + let y1 = metadata.local_rect.size.height * (y+1) as f32 / y_clip_count as f32; + + for x in 0 .. x_clip_count { + let x0 = metadata.local_rect.size.width * x as f32 / x_clip_count as f32; + let x1 = metadata.local_rect.size.width * (x+1) as f32 / x_clip_count as f32; + + let rect = LayoutRect::new( + LayoutPoint::new( + x0 + metadata.local_rect.origin.x, + y0 + metadata.local_rect.origin.y, + ), + LayoutSize::new( + x1 - x0, + y1 - y0, + ), + ); + + segment_builder.push_mask_region(rect, LayoutRect::zero(), None); + } } + } + + match brush.segment_desc { + Some(..) => panic!("bug: should not already have descriptor"), None => { // TODO(gw): We can probably make the allocation // patterns of this and the segment @@ -2088,7 +2098,6 @@ fn write_brush_segment_description( brush.segment_desc = Some(BrushSegmentDescriptor { segments, - clip_mask_kind: clip_chain.clip_mask_kind, }); } } @@ -2099,7 +2108,7 @@ impl Primitive { fn update_clip_task_for_brush( &mut self, prim_context: &PrimitiveContext, - clip_chain: &ClipChainInstance, + prim_clip_chain: &ClipChainInstance, combined_outer_rect: &DeviceIntRect, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, @@ -2115,7 +2124,7 @@ impl Primitive { write_brush_segment_description( brush, &self.metadata, - clip_chain, + prim_clip_chain, frame_state, ); @@ -2123,42 +2132,51 @@ impl Primitive { Some(ref mut description) => description, None => return false, }; - let clip_mask_kind = segment_desc.clip_mask_kind; for segment in &mut segment_desc.segments { - if !segment.may_need_clip_mask && clip_mask_kind != BrushClipMaskKind::Global { - segment.clip_task_id = BrushSegmentTaskId::Opaque; - continue; - } + // Build a clip chain for the smaller segment rect. This will + // often manage to eliminate most/all clips, and sometimes + // clip the segment completely. + let segment_clip_chain = frame_state + .clip_store + .build_clip_chain_instance( + self.metadata.clip_chain_id, + segment.local_rect, + self.metadata.local_clip_rect, + prim_context.spatial_node_index, + &frame_context.clip_scroll_tree, + frame_state.gpu_cache, + frame_state.resource_cache, + frame_context.device_pixel_scale, + ); - let intersected_rect = calculate_screen_bounding_rect( - &prim_context.spatial_node.world_content_transform, - &segment.local_rect, - frame_context.device_pixel_scale, - Some(&combined_outer_rect), - ); + match segment_clip_chain { + Some(segment_clip_chain) => { + if segment_clip_chain.clips_range.count == 0 { + segment.clip_task_id = BrushSegmentTaskId::Opaque; + continue; + } + + let bounds = (segment_clip_chain.world_clip_rect * frame_context.device_pixel_scale) + .round_out() + .to_i32(); + + let clip_task = RenderTask::new_mask( + bounds, + segment_clip_chain.clips_range, + frame_state.clip_store, + frame_state.gpu_cache, + frame_state.resource_cache, + frame_state.render_tasks, + ); - let bounds = match intersected_rect { - Some(bounds) => bounds, + let clip_task_id = frame_state.render_tasks.add(clip_task); + pic_state.tasks.push(clip_task_id); + segment.clip_task_id = BrushSegmentTaskId::RenderTaskId(clip_task_id); + } None => { segment.clip_task_id = BrushSegmentTaskId::Empty; - continue; } - }; - - if clip_chain.clips_range.count > 0 { - let clip_task = RenderTask::new_mask( - bounds, - clip_chain.clips_range, - frame_state.clip_store, - frame_state.gpu_cache, - frame_state.resource_cache, - frame_state.render_tasks, - ); - - let clip_task_id = frame_state.render_tasks.add(clip_task); - pic_state.tasks.push(clip_task_id); - segment.clip_task_id = BrushSegmentTaskId::RenderTaskId(clip_task_id); } } @@ -2754,7 +2772,6 @@ impl Primitive { if needs_update { brush.segment_desc = Some(BrushSegmentDescriptor { segments: new_segments, - clip_mask_kind: BrushClipMaskKind::Unknown, }); // The segments have changed, so force the GPU cache to diff --git a/webrender/src/util.rs b/webrender/src/util.rs index 480a753f4c..d3af3122a4 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale}; -use api::{DevicePoint, DeviceRect, DeviceSize, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize}; +use api::{DeviceRect, LayoutPixel, LayoutRect}; use api::{WorldPixel, WorldRect}; use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D}; use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D}; @@ -331,15 +331,6 @@ pub trait MaxRect { fn max_rect() -> Self; } -impl MaxRect for LayoutRect { - fn max_rect() -> Self { - LayoutRect::new( - LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0), - LayoutSize::new(f32::MAX, f32::MAX), - ) - } -} - impl MaxRect for DeviceIntRect { fn max_rect() -> Self { DeviceIntRect::new( @@ -349,7 +340,7 @@ impl MaxRect for DeviceIntRect { } } -impl MaxRect for DeviceRect { +impl MaxRect for TypedRect { fn max_rect() -> Self { // Having an unlimited bounding box is fine up until we try // to cast it to `i32`, where we get `-2147483648` for any @@ -359,9 +350,9 @@ impl MaxRect for DeviceRect { // with explanation left as an exercise for the reader. const MAX_COORD: f32 = 1.0e9; - DeviceRect::new( - DevicePoint::new(-MAX_COORD, -MAX_COORD), - DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD), + TypedRect::new( + TypedPoint2D::new(-MAX_COORD, -MAX_COORD), + TypedSize2D::new(2.0 * MAX_COORD, 2.0 * MAX_COORD), ) } } diff --git a/wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png b/wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png index 23eeba6384..95dbd6b260 100644 Binary files a/wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png and b/wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png differ diff --git a/wrench/reftests/clip/border-with-rounded-clip.png b/wrench/reftests/clip/border-with-rounded-clip.png index dd368d4661..b7e7dd7884 100644 Binary files a/wrench/reftests/clip/border-with-rounded-clip.png and b/wrench/reftests/clip/border-with-rounded-clip.png differ diff --git a/wrench/reftests/transforms/coord-system.png b/wrench/reftests/transforms/coord-system.png new file mode 100644 index 0000000000..e18a5b8746 Binary files /dev/null and b/wrench/reftests/transforms/coord-system.png differ diff --git a/wrench/reftests/transforms/perspective-mask.png b/wrench/reftests/transforms/perspective-mask.png index bdce73d262..49d465179c 100644 Binary files a/wrench/reftests/transforms/perspective-mask.png and b/wrench/reftests/transforms/perspective-mask.png differ diff --git a/wrench/reftests/transforms/perspective.png b/wrench/reftests/transforms/perspective.png index 34678c2576..7189227bb7 100644 Binary files a/wrench/reftests/transforms/perspective.png and b/wrench/reftests/transforms/perspective.png differ diff --git a/wrench/reftests/transforms/reftest.list b/wrench/reftests/transforms/reftest.list index dfeeb6d81c..fb2660255e 100644 --- a/wrench/reftests/transforms/reftest.list +++ b/wrench/reftests/transforms/reftest.list @@ -10,7 +10,7 @@ platform(linux) fuzzy(1,630) == perspective.yaml perspective.png platform(linux,mac) fuzzy(1,156) == prim-suite.yaml prim-suite.png == segments-bug.yaml segments-bug-ref.yaml platform(linux,mac) == content-offset.yaml content-offset.png -platform(linux,mac) == coord-system.yaml blank.yaml +platform(linux,mac) == coord-system.yaml coord-system.png platform(linux,mac) zoom(4) == border-zoom.yaml border-zoom.png platform(linux) fuzzy(1,520) == perspective-origin.yaml perspective-origin.png platform(linux,mac) color_targets(1) alpha_targets(0) fuzzy(1,180) == screen-space-blit.yaml screen-space-blit.png @@ -19,3 +19,4 @@ platform(linux,mac) == nested-rotate-x.yaml nested-rotate-x.png platform(linux,mac) == nested-preserve-3d.yaml nested-preserve-3d.png platform(linux,mac) == near-plane-clip.yaml near-plane-clip.png platform(linux,mac) == perspective-mask.yaml perspective-mask.png +rotate-clip.yaml rotate-clip-ref.yaml diff --git a/wrench/reftests/transforms/rotate-clip-ref.yaml b/wrench/reftests/transforms/rotate-clip-ref.yaml new file mode 100644 index 0000000000..133279fca8 --- /dev/null +++ b/wrench/reftests/transforms/rotate-clip-ref.yaml @@ -0,0 +1,7 @@ +--- +root: + items: + - + bounds: [100, 146, 150, 107] + type: rect + color: 0 128 0 1.0000 diff --git a/wrench/reftests/transforms/rotate-clip.yaml b/wrench/reftests/transforms/rotate-clip.yaml new file mode 100644 index 0000000000..209d53d103 --- /dev/null +++ b/wrench/reftests/transforms/rotate-clip.yaml @@ -0,0 +1,18 @@ +--- +root: + items: + - + type: clip + bounds: [0, 0, 2000, 2000] + clip-rect: [0, 0, 2000, 2000] + items: + - + bounds: [100, 0, 150, 150] + type: "stacking-context" + transform: rotate-x(45) + transform-origin: [0, 500] + items: + - + bounds: [0, 0, 150, 150] + type: rect + color: 0 128 0 1.0000