diff --git a/webrender/res/brush.glsl b/webrender/res/brush.glsl index 48f5e18a43..547204443d 100644 --- a/webrender/res/brush.glsl +++ b/webrender/res/brush.glsl @@ -49,6 +49,7 @@ void main(void) { vec4[2] segment_info = fetch_from_gpu_cache_2(segment_address); segment_rect = RectWithSize(segment_info[0].xy, segment_info[0].zw); + segment_rect.p0 += ph.local_rect.p0; segment_data = segment_info[1]; } diff --git a/webrender/res/clip_shared.glsl b/webrender/res/clip_shared.glsl index 05074295c6..8fd0afd42c 100644 --- a/webrender/res/clip_shared.glsl +++ b/webrender/res/clip_shared.glsl @@ -17,6 +17,8 @@ in int aClipTransformId; in int aPrimTransformId; in int aClipSegment; in ivec4 aClipDataResourceAddress; +in vec2 aClipLocalPos; +in vec4 aClipTileRect; struct ClipMaskInstance { int render_task_address; @@ -25,6 +27,8 @@ struct ClipMaskInstance { int segment; ivec2 clip_data_address; ivec2 resource_address; + vec2 local_pos; + RectWithSize tile_rect; }; ClipMaskInstance fetch_clip_item() { @@ -36,6 +40,8 @@ ClipMaskInstance fetch_clip_item() { cmi.segment = aClipSegment; cmi.clip_data_address = aClipDataResourceAddress.xy; cmi.resource_address = aClipDataResourceAddress.zw; + cmi.local_pos = aClipLocalPos; + cmi.tile_rect = RectWithSize(aClipTileRect.xy, aClipTileRect.zw); return cmi; } diff --git a/webrender/res/cs_clip_box_shadow.glsl b/webrender/res/cs_clip_box_shadow.glsl index 4419241313..c8c98f7147 100644 --- a/webrender/res/cs_clip_box_shadow.glsl +++ b/webrender/res/cs_clip_box_shadow.glsl @@ -46,8 +46,11 @@ void main(void) { BoxShadowData bs_data = fetch_data(cmi.clip_data_address); ImageResource res = fetch_image_resource_direct(cmi.resource_address); + RectWithSize dest_rect = bs_data.dest_rect; + dest_rect.p0 += cmi.local_pos; + ClipVertexInfo vi = write_clip_tile_vertex( - bs_data.dest_rect, + dest_rect, prim_transform, clip_transform, area @@ -65,14 +68,14 @@ void main(void) { switch (bs_data.stretch_mode_x) { case MODE_STRETCH: { vEdge.x = 0.5; - vEdge.z = (bs_data.dest_rect.size.x / bs_data.src_rect_size.x) - 0.5; - vUv.x = (local_pos.x - bs_data.dest_rect.p0.x) / bs_data.src_rect_size.x; + vEdge.z = (dest_rect.size.x / bs_data.src_rect_size.x) - 0.5; + vUv.x = (local_pos.x - dest_rect.p0.x) / bs_data.src_rect_size.x; break; } case MODE_SIMPLE: default: { vEdge.xz = vec2(1.0); - vUv.x = (local_pos.x - bs_data.dest_rect.p0.x) / bs_data.dest_rect.size.x; + vUv.x = (local_pos.x - dest_rect.p0.x) / dest_rect.size.x; break; } } @@ -80,14 +83,14 @@ void main(void) { switch (bs_data.stretch_mode_y) { case MODE_STRETCH: { vEdge.y = 0.5; - vEdge.w = (bs_data.dest_rect.size.y / bs_data.src_rect_size.y) - 0.5; - vUv.y = (local_pos.y - bs_data.dest_rect.p0.y) / bs_data.src_rect_size.y; + vEdge.w = (dest_rect.size.y / bs_data.src_rect_size.y) - 0.5; + vUv.y = (local_pos.y - dest_rect.p0.y) / bs_data.src_rect_size.y; break; } case MODE_SIMPLE: default: { vEdge.yw = vec2(1.0); - vUv.y = (local_pos.y - bs_data.dest_rect.p0.y) / bs_data.dest_rect.size.y; + vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect.size.y; break; } } diff --git a/webrender/res/cs_clip_image.glsl b/webrender/res/cs_clip_image.glsl index a150344fbd..30640d4504 100644 --- a/webrender/res/cs_clip_image.glsl +++ b/webrender/res/cs_clip_image.glsl @@ -13,15 +13,12 @@ flat varying float vLayer; #ifdef WR_VERTEX_SHADER struct ImageMaskData { - RectWithSize local_mask_rect; - RectWithSize local_tile_rect; + vec2 local_mask_size; }; ImageMaskData fetch_mask_data(ivec2 address) { - vec4 data[2] = fetch_from_gpu_cache_2_direct(address); - RectWithSize mask_rect = RectWithSize(data[0].xy, data[0].zw); - RectWithSize tile_rect = RectWithSize(data[1].xy, data[1].zw); - ImageMaskData mask_data = ImageMaskData(mask_rect, tile_rect); + vec4 data = fetch_from_gpu_cache_1_direct(address); + ImageMaskData mask_data = ImageMaskData(data.xy); return mask_data; } @@ -31,7 +28,7 @@ void main(void) { Transform clip_transform = fetch_transform(cmi.clip_transform_id); Transform prim_transform = fetch_transform(cmi.prim_transform_id); ImageMaskData mask = fetch_mask_data(cmi.clip_data_address); - RectWithSize local_rect = mask.local_mask_rect; + RectWithSize local_rect = RectWithSize(cmi.local_pos, mask.local_mask_size); ImageResource res = fetch_image_resource_direct(cmi.resource_address); ClipVertexInfo vi = write_clip_tile_vertex( @@ -42,7 +39,7 @@ void main(void) { ); vLocalPos = vi.local_pos.xy / vi.local_pos.z; vLayer = res.layer; - vClipMaskImageUv = (vLocalPos - mask.local_tile_rect.p0) / mask.local_tile_rect.size; + vClipMaskImageUv = (vLocalPos - cmi.tile_rect.p0) / cmi.tile_rect.size; vec2 texture_size = vec2(textureSize(sColor0, 0)); vClipMaskUvRect = vec4(res.uv_rect.p0, res.uv_rect.p1 - res.uv_rect.p0) / texture_size.xyxy; // applying a half-texel offset to the UV boundaries to prevent linear samples from the outside diff --git a/webrender/res/cs_clip_rectangle.glsl b/webrender/res/cs_clip_rectangle.glsl index 3918c86346..468c5f353d 100644 --- a/webrender/res/cs_clip_rectangle.glsl +++ b/webrender/res/cs_clip_rectangle.glsl @@ -63,7 +63,9 @@ void main(void) { Transform clip_transform = fetch_transform(cmi.clip_transform_id); Transform prim_transform = fetch_transform(cmi.prim_transform_id); ClipData clip = fetch_clip(cmi.clip_data_address); + RectWithSize local_rect = clip.rect.rect; + local_rect.p0 = cmi.local_pos; ClipVertexInfo vi = write_clip_tile_vertex( local_rect, diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index aae0cf8a65..6db9410f79 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1971,7 +1971,7 @@ impl AlphaBatchBuilder { let base_instance = BrushInstance { prim_header_index, clip_task_address, - segment_index: 0, + segment_index: INVALID_SEGMENT_INDEX, edge_flags, brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, user_data: uv_rect_address.as_int(), @@ -2188,7 +2188,7 @@ fn add_gradient_tiles( BrushInstance { prim_header_index, clip_task_address, - segment_index: 0, + segment_index: INVALID_SEGMENT_INDEX, edge_flags: EdgeAaSegmentMask::all(), brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, user_data: 0, @@ -2442,6 +2442,7 @@ impl ClipBatcher { &mut self, task_address: RenderTaskAddress, clip_data_address: GpuCacheAddress, + local_pos: LayoutPoint, ) { let instance = ClipMaskInstance { render_task_address: task_address, @@ -2450,6 +2451,8 @@ impl ClipBatcher { segment: 0, clip_data_address, resource_address: GpuCacheAddress::invalid(), + local_pos, + tile_rect: LayoutRect::zero(), }; self.rectangles.push(instance); @@ -2490,21 +2493,27 @@ impl ClipBatcher { segment: 0, clip_data_address: GpuCacheAddress::invalid(), resource_address: GpuCacheAddress::invalid(), + local_pos: clip_instance.local_pos, + tile_rect: LayoutRect::zero(), }; match clip_node.item { - ClipItem::Image { ref mask, ref visible_tiles } => { + ClipItem::Image { image, size, .. } => { let request = ImageRequest { - key: mask.image, + key: image, rendering: ImageRendering::Auto, tile: None, }; - let mut add_image = |request: ImageRequest, clip_data_address: GpuCacheAddress| { + + let clip_data_address = + gpu_cache.get_address(&clip_node.gpu_cache_handle); + + let mut add_image = |request: ImageRequest, local_tile_rect: LayoutRect| { let cache_item = match resource_cache.get_cached_image(request) { Ok(item) => item, Err(..) => { warn!("Warnings: skip a image mask"); - debug!("Mask: {:?}, request: {:?}", mask, request); + debug!("request: {:?}", request); return; } }; @@ -2514,23 +2523,23 @@ impl ClipBatcher { .push(ClipMaskInstance { clip_data_address, resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle), + tile_rect: local_tile_rect, ..instance }); }; - match *visible_tiles { + match clip_instance.visible_tiles { Some(ref tiles) => { for tile in tiles { add_image( request.with_tile(tile.tile_offset), - gpu_cache.get_address(&tile.handle), + tile.tile_rect, ) } } None => { - let gpu_address = - gpu_cache.get_address(&clip_node.gpu_cache_handle); - add_image(request, gpu_address) + let mask_rect = LayoutRect::new(clip_instance.local_pos, size); + add_image(request, mask_rect) } } } diff --git a/webrender/src/border.rs b/webrender/src/border.rs index c22a428f6f..13aa052629 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -171,7 +171,7 @@ pub struct BorderSegmentCacheKey { pub fn ensure_no_corner_overlap( radius: &mut BorderRadius, - rect: &LayoutRect, + size: LayoutSize, ) { let mut ratio = 1.0; let top_left_radius = &mut radius.top_left; @@ -180,23 +180,23 @@ pub fn ensure_no_corner_overlap( let bottom_left_radius = &mut radius.bottom_left; let sum = top_left_radius.width + top_right_radius.width; - if rect.size.width < sum { - ratio = f32::min(ratio, rect.size.width / sum); + if size.width < sum { + ratio = f32::min(ratio, size.width / sum); } let sum = bottom_left_radius.width + bottom_right_radius.width; - if rect.size.width < sum { - ratio = f32::min(ratio, rect.size.width / sum); + if size.width < sum { + ratio = f32::min(ratio, size.width / sum); } let sum = top_left_radius.height + bottom_left_radius.height; - if rect.size.height < sum { - ratio = f32::min(ratio, rect.size.height / sum); + if size.height < sum { + ratio = f32::min(ratio, size.height / sum); } let sum = top_right_radius.height + bottom_right_radius.height; - if rect.size.height < sum { - ratio = f32::min(ratio, rect.size.height / sum); + if size.height < sum { + ratio = f32::min(ratio, size.height / sum); } if ratio < 1. { @@ -223,7 +223,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll: ScrollNodeAndClipChain, ) { let mut border = *border; - ensure_no_corner_overlap(&mut border.radius, &info.rect); + ensure_no_corner_overlap(&mut border.radius, info.rect.size); self.add_primitive( clip_and_scroll, @@ -649,12 +649,17 @@ fn get_edge_info( /// Create the set of border segments and render task /// cache keys for a given CSS border. pub fn create_border_segments( - rect: &LayoutRect, + size: LayoutSize, border: &NormalBorder, widths: &LayoutSideOffsets, border_segments: &mut Vec, brush_segments: &mut Vec, ) { + let rect = LayoutRect::new( + LayoutPoint::zero(), + size, + ); + let local_size_tl = LayoutSize::new( border.radius.top_left.width.max(widths.left), border.radius.top_left.height.max(widths.top), @@ -1143,8 +1148,13 @@ pub fn build_border_instances( impl NinePatchDescriptor { pub fn create_segments( &self, - rect: &LayoutRect, + size: LayoutSize, ) -> Vec { + let rect = LayoutRect::new( + LayoutPoint::zero(), + size, + ); + // Calculate the modified rect as specific by border-image-outset let origin = LayoutPoint::new( rect.origin.x - self.outset.left, diff --git a/webrender/src/box_shadow.rs b/webrender/src/box_shadow.rs index eaaa4fd71b..f14a526423 100644 --- a/webrender/src/box_shadow.rs +++ b/webrender/src/box_shadow.rs @@ -117,32 +117,47 @@ impl<'a> DisplayListFlattener<'a> { } // TODO(gw): Add a fast path for ClipOut + zero border radius! - clips.push(ClipItemKey::rounded_rect( - prim_info.rect, - border_radius, - ClipMode::ClipOut, - )); + clips.push( + ( + prim_info.rect.origin, + ClipItemKey::rounded_rect( + prim_info.rect.size, + border_radius, + ClipMode::ClipOut, + ), + ) + ); (shadow_rect, shadow_radius) } BoxShadowClipMode::Inset => { if shadow_rect.is_well_formed_and_nonempty() { - clips.push(ClipItemKey::rounded_rect( - shadow_rect, - shadow_radius, - ClipMode::ClipOut, - )); + clips.push( + ( + shadow_rect.origin, + ClipItemKey::rounded_rect( + shadow_rect.size, + shadow_radius, + ClipMode::ClipOut, + ), + ) + ); } (prim_info.rect, border_radius) } }; - clips.push(ClipItemKey::rounded_rect( - final_prim_rect, - clip_radius, - ClipMode::Clip, - )); + clips.push( + ( + final_prim_rect.origin, + ClipItemKey::rounded_rect( + final_prim_rect.size, + clip_radius, + ClipMode::Clip, + ), + ) + ); self.add_primitive( clip_and_scroll, @@ -159,11 +174,16 @@ impl<'a> DisplayListFlattener<'a> { // Add a normal clip mask to clip out the contents // of the surrounding primitive. - extra_clips.push(ClipItemKey::rounded_rect( - prim_info.rect, - border_radius, - prim_clip_mode, - )); + extra_clips.push( + ( + prim_info.rect.origin, + ClipItemKey::rounded_rect( + prim_info.rect.size, + border_radius, + prim_clip_mode, + ), + ) + ); // Get the local rect of where the shadow will be drawn, // expanded to include room for the blurred region. @@ -179,7 +199,7 @@ impl<'a> DisplayListFlattener<'a> { let shadow_clip_source = ClipItemKey::box_shadow( shadow_rect, shadow_radius, - dest_rect, + dest_rect.translate(&LayoutVector2D::new(-prim_info.rect.origin.x, -prim_info.rect.origin.y)), blur_radius, clip_mode, ); @@ -192,7 +212,12 @@ impl<'a> DisplayListFlattener<'a> { } // Add the box-shadow clip source. - extra_clips.push(shadow_clip_source); + extra_clips.push( + ( + prim_info.rect.origin, + shadow_clip_source, + ), + ); // Outset shadows are expanded by the shadow // region from the original primitive. @@ -212,7 +237,12 @@ impl<'a> DisplayListFlattener<'a> { // inset shadow rect becomes invalid (they will // just look like a solid rectangle). if shadow_rect.is_well_formed_and_nonempty() { - extra_clips.push(shadow_clip_source); + extra_clips.push( + ( + prim_info.rect.origin, + shadow_clip_source, + ), + ); } // Inset shadows draw inside the original primitive. diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index c5b8041ad6..2f3a4ae592 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -6,7 +6,7 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D}; use api::{BoxShadowClipMode, LayoutToWorldScale, PicturePixel, WorldPixel}; use api::{PictureRect, LayoutPixel, WorldPoint, WorldSize, WorldRect, LayoutToWorldTransform}; -use api::{VoidPtrToSizeFn, LayoutRectAu, ImageKey, AuHelpers}; +use api::{VoidPtrToSizeFn, ImageKey}; use app_units::Au; use border::{ensure_no_corner_overlap, BorderRadiusAu}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey}; @@ -18,6 +18,7 @@ use image::{self, Repetition}; use intern; use internal_types::FastHashSet; use prim_store::{ClipData, ImageMaskData, SpaceMapper, VisibleMaskImageTile}; +use prim_store::{PointKey, SizeKey, RectangleKey}; use render_task::to_cache_size; use resource_cache::{ImageRequest, ResourceCache}; use std::{cmp, u32}; @@ -136,31 +137,29 @@ pub struct ClipNode { impl From for ClipNode { fn from(item: ClipItemKey) -> Self { let item = match item { - ClipItemKey::Rectangle(rect, mode) => { - ClipItem::Rectangle(LayoutRect::from_au(rect), mode) + ClipItemKey::Rectangle(size, mode) => { + ClipItem::Rectangle(size.into(), mode) } - ClipItemKey::RoundedRectangle(rect, radius, mode) => { + ClipItemKey::RoundedRectangle(size, radius, mode) => { ClipItem::RoundedRectangle( - LayoutRect::from_au(rect), + size.into(), radius.into(), mode, ) } - ClipItemKey::ImageMask(rect, image, repeat) => { + ClipItemKey::ImageMask(size, image, repeat) => { ClipItem::Image { - mask: ImageMask { - image, - rect: LayoutRect::from_au(rect), - repeat, - }, - visible_tiles: None, + image, + size: size.into(), + repeat, } } - ClipItemKey::BoxShadow(shadow_rect, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => { + ClipItemKey::BoxShadow(shadow_rect_fract_offset, shadow_rect_size, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => { ClipItem::new_box_shadow( - LayoutRect::from_au(shadow_rect), + shadow_rect_fract_offset.into(), + shadow_rect_size.into(), shadow_radius.into(), - LayoutRect::from_au(prim_shadow_rect), + prim_shadow_rect.into(), blur_radius.to_f32_px(), clip_mode, ) @@ -203,6 +202,7 @@ impl ClipChainId { #[derive(Clone)] pub struct ClipChainNode { pub handle: ClipDataHandle, + pub local_pos: LayoutPoint, pub spatial_node_index: SpatialNodeIndex, pub parent_clip_chain_id: ClipChainId, } @@ -219,13 +219,16 @@ pub struct ClipNodeIndex(pub u32); // an index to the node data itself, as well as // some flags describing how this clip node instance // is positioned. -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ClipNodeInstance { pub handle: ClipDataHandle, pub flags: ClipNodeFlags, pub spatial_node_index: SpatialNodeIndex, + pub local_pos: LayoutPoint, + + pub visible_tiles: Option>, } // A range of clip node instances that were found by @@ -255,84 +258,111 @@ enum ClipSpaceConversion { struct ClipNodeInfo { conversion: ClipSpaceConversion, handle: ClipDataHandle, + local_pos: LayoutPoint, spatial_node_index: SpatialNodeIndex, } -impl ClipNode { - pub fn update( - &mut self, +impl ClipNodeInfo { + fn create_instance( + &self, + node: &ClipNode, + clipped_rect: &LayoutRect, gpu_cache: &mut GpuCache, resource_cache: &mut ResourceCache, - device_pixel_scale: DevicePixelScale, - clipped_rect: &LayoutRect, - ) { - match self.item { - ClipItem::Image { ref mask, ref mut visible_tiles } => { - let request = ImageRequest { - key: mask.image, - rendering: ImageRendering::Auto, - tile: None, - }; - *visible_tiles = None; - if let Some(props) = resource_cache.get_image_properties(mask.image) { - if let Some(tile_size) = props.tiling { - let mut mask_tiles = Vec::new(); - - let device_image_size = props.descriptor.size; - let visible_rect = if mask.repeat { - *clipped_rect - } else { - clipped_rect.intersection(&mask.rect).unwrap() - }; + ) -> ClipNodeInstance { + // Calculate some flags that are required for the segment + // building logic. + let flags = match self.conversion { + ClipSpaceConversion::Local => { + ClipNodeFlags::SAME_SPATIAL_NODE | ClipNodeFlags::SAME_COORD_SYSTEM + } + ClipSpaceConversion::ScaleOffset(..) => { + ClipNodeFlags::SAME_COORD_SYSTEM + } + ClipSpaceConversion::Transform(..) => { + ClipNodeFlags::empty() + } + }; + + let mut visible_tiles = None; + + if let ClipItem::Image { size, image, repeat } = node.item { + let request = ImageRequest { + key: image, + rendering: ImageRendering::Auto, + tile: None, + }; + + if let Some(props) = resource_cache.get_image_properties(image) { + if let Some(tile_size) = props.tiling { + let mut mask_tiles = Vec::new(); + let mask_rect = LayoutRect::new(self.local_pos, size); + + let device_image_size = props.descriptor.size; + let visible_rect = if repeat { + *clipped_rect + } else { + clipped_rect.intersection(&mask_rect).unwrap() + }; - let repetitions = image::repetitions( - &mask.rect, + let repetitions = image::repetitions( + &mask_rect, + &visible_rect, + size, + ); + + for Repetition { origin, .. } in repetitions { + let image_rect = LayoutRect { + origin, + size, + }; + let tiles = image::tiles( + &image_rect, &visible_rect, - mask.rect.size, + &device_image_size, + tile_size as i32, ); - - for Repetition { origin, .. } in repetitions { - let image_rect = LayoutRect { - origin, - size: mask.rect.size, - }; - let tiles = image::tiles( - &image_rect, - &visible_rect, - &device_image_size, - tile_size as i32, + for tile in tiles { + resource_cache.request_image( + request.with_tile(tile.offset), + gpu_cache, ); - for tile in tiles { - resource_cache.request_image( - request.with_tile(tile.offset), - gpu_cache, - ); - let mut handle = GpuCacheHandle::new(); - if let Some(request) = gpu_cache.request(&mut handle) { - let data = ImageMaskData { - local_mask_rect: mask.rect, - local_tile_rect: tile.rect, - }; - data.write_gpu_blocks(request); - } - - mask_tiles.push(VisibleMaskImageTile { - tile_offset: tile.offset, - handle, - }); - } + mask_tiles.push(VisibleMaskImageTile { + tile_offset: tile.offset, + tile_rect: tile.rect, + }); } - *visible_tiles = Some(mask_tiles); - } else { - if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) { - let data = ImageMaskData { - local_mask_rect: mask.rect, - local_tile_rect: mask.rect, - }; - data.write_gpu_blocks(request); - } - resource_cache.request_image(request, gpu_cache); } + visible_tiles = Some(mask_tiles); + } else { + resource_cache.request_image(request, gpu_cache); + } + } + } + + ClipNodeInstance { + handle: self.handle, + flags, + spatial_node_index: self.spatial_node_index, + local_pos: self.local_pos, + visible_tiles, + } + } +} + +impl ClipNode { + pub fn update( + &mut self, + gpu_cache: &mut GpuCache, + device_pixel_scale: DevicePixelScale, + ) { + match self.item { + ClipItem::Image { size, .. } => { + if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) { + let data = ImageMaskData { + local_mask_size: size, + }; + data.write_gpu_blocks(request); } } ClipItem::BoxShadow(ref mut info) => { @@ -376,7 +406,7 @@ impl ClipNode { if let Some(mut request) = gpu_cache.request(&mut info.clip_data_handle) { let data = ClipData::rounded_rect( - &info.minimal_shadow_rect, + info.minimal_shadow_rect.size, &info.shadow_radius, ClipMode::Clip, ); @@ -384,15 +414,15 @@ impl ClipNode { data.write(&mut request); } } - ClipItem::Rectangle(rect, mode) => { + ClipItem::Rectangle(size, mode) => { if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) { - let data = ClipData::uniform(rect, 0.0, mode); + let data = ClipData::uniform(size, 0.0, mode); data.write(&mut request); } } - ClipItem::RoundedRectangle(ref rect, ref radius, mode) => { + ClipItem::RoundedRectangle(size, ref radius, mode) => { if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) { - let data = ClipData::rounded_rect(rect, radius, mode); + let data = ClipData::rounded_rect(size, radius, mode); data.write(&mut request); } } @@ -442,6 +472,7 @@ impl ClipStore { pub fn add_clip_chain_node( &mut self, handle: ClipDataHandle, + local_pos: LayoutPoint, spatial_node_index: SpatialNodeIndex, parent_clip_chain_id: ClipChainId, ) -> ClipChainId { @@ -449,6 +480,7 @@ impl ClipStore { self.clip_chain_nodes.push(ClipChainNode { handle, spatial_node_index, + local_pos, parent_clip_chain_id, }); id @@ -523,6 +555,7 @@ impl ClipStore { if !add_clip_node_to_current_chain( clip_chain_node.handle, clip_chain_node.spatial_node_index, + clip_chain_node.local_pos, spatial_node_index, &mut local_clip_rect, &mut self.clip_node_info, @@ -541,14 +574,15 @@ impl ClipStore { // handled as part of this rasterization root. if let Some(clip_node_collector) = clip_node_collector { for clip_chain_id in &clip_node_collector.clips { - let (handle, clip_spatial_node_index) = { + let (handle, clip_spatial_node_index, local_pos) = { let clip_chain_node = &self.clip_chain_nodes[clip_chain_id.0 as usize]; - (clip_chain_node.handle, clip_chain_node.spatial_node_index) + (clip_chain_node.handle, clip_chain_node.spatial_node_index, clip_chain_node.local_pos) }; if !add_clip_node_to_current_chain( handle, clip_spatial_node_index, + local_pos, spatial_node_index, &mut local_clip_rect, &mut self.clip_node_info, @@ -580,15 +614,16 @@ impl ClipStore { // See how this clip affects the prim region. let clip_result = match node_info.conversion { ClipSpaceConversion::Local => { - node.item.get_clip_result(&local_bounding_rect) + node.item.get_clip_result(node_info.local_pos, &local_bounding_rect) } ClipSpaceConversion::ScaleOffset(ref scale_offset) => { has_non_local_clips = true; - node.item.get_clip_result(&scale_offset.unmap_rect(&local_bounding_rect)) + node.item.get_clip_result(node_info.local_pos, &scale_offset.unmap_rect(&local_bounding_rect)) } ClipSpaceConversion::Transform(ref transform) => { has_non_local_clips = true; node.item.get_clip_result_complex( + node_info.local_pos, transform, &world_clip_rect, world_rect, @@ -610,24 +645,16 @@ impl ClipStore { // TODO(gw): Ensure this only runs once on each node per frame? node.update( gpu_cache, - resource_cache, device_pixel_scale, - &local_bounding_rect, ); - // Calculate some flags that are required for the segment - // building logic. - let flags = match node_info.conversion { - ClipSpaceConversion::Local => { - ClipNodeFlags::SAME_SPATIAL_NODE | ClipNodeFlags::SAME_COORD_SYSTEM - } - ClipSpaceConversion::ScaleOffset(..) => { - ClipNodeFlags::SAME_COORD_SYSTEM - } - ClipSpaceConversion::Transform(..) => { - ClipNodeFlags::empty() - } - }; + // Create the clip node instance for this clip node + let instance = node_info.create_instance( + node, + &local_bounding_rect, + gpu_cache, + resource_cache, + ); // As a special case, a partial accept of a clip rect that is // in the same coordinate system as the primitive doesn't need @@ -644,16 +671,11 @@ impl ClipStore { } ClipItem::Rectangle(_, ClipMode::Clip) => { - !flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) + !instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) } }; // Store this in the index buffer for this clip chain instance. - let instance = ClipNodeInstance { - handle: node_info.handle, - flags, - spatial_node_index: node_info.spatial_node_index, - }; self.clip_node_instances.push(instance); } } @@ -815,24 +837,24 @@ pub struct ClipItemSceneData { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum ClipItemKey { - Rectangle(LayoutRectAu, ClipMode), - RoundedRectangle(LayoutRectAu, BorderRadiusAu, ClipMode), - ImageMask(LayoutRectAu, ImageKey, bool), - BoxShadow(LayoutRectAu, BorderRadiusAu, LayoutRectAu, Au, BoxShadowClipMode), + Rectangle(SizeKey, ClipMode), + RoundedRectangle(SizeKey, BorderRadiusAu, ClipMode), + ImageMask(SizeKey, ImageKey, bool), + BoxShadow(PointKey, SizeKey, BorderRadiusAu, RectangleKey, Au, BoxShadowClipMode), } impl ClipItemKey { - pub fn rectangle(rect: LayoutRect, mode: ClipMode) -> Self { - ClipItemKey::Rectangle(rect.to_au(), mode) + pub fn rectangle(size: LayoutSize, mode: ClipMode) -> Self { + ClipItemKey::Rectangle(size.into(), mode) } - pub fn rounded_rect(rect: LayoutRect, mut radii: BorderRadius, mode: ClipMode) -> Self { + pub fn rounded_rect(size: LayoutSize, mut radii: BorderRadius, mode: ClipMode) -> Self { if radii.is_zero() { - ClipItemKey::rectangle(rect, mode) + ClipItemKey::rectangle(size, mode) } else { - ensure_no_corner_overlap(&mut radii, &rect); + ensure_no_corner_overlap(&mut radii, size); ClipItemKey::RoundedRectangle( - rect.to_au(), + size.into(), radii.into(), mode, ) @@ -841,7 +863,7 @@ impl ClipItemKey { pub fn image_mask(image_mask: &ImageMask) -> Self { ClipItemKey::ImageMask( - image_mask.rect.to_au(), + image_mask.rect.size.into(), image_mask.image, image_mask.repeat, ) @@ -854,10 +876,18 @@ impl ClipItemKey { blur_radius: f32, clip_mode: BoxShadowClipMode, ) -> Self { + // Get the fractional offsets required to match the + // source rect with a minimal rect. + let fract_offset = LayoutPoint::new( + shadow_rect.origin.x.fract().abs(), + shadow_rect.origin.y.fract().abs(), + ); + ClipItemKey::BoxShadow( - shadow_rect.to_au(), + fract_offset.into(), + shadow_rect.size.into(), shadow_radius.into(), - prim_shadow_rect.to_au(), + prim_shadow_rect.into(), Au::from_f32_px(blur_radius), clip_mode, ) @@ -868,31 +898,30 @@ impl ClipItemKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum ClipItem { - Rectangle(LayoutRect, ClipMode), - RoundedRectangle(LayoutRect, BorderRadius, ClipMode), - Image { mask: ImageMask, visible_tiles: Option> }, + Rectangle(LayoutSize, ClipMode), + RoundedRectangle(LayoutSize, BorderRadius, ClipMode), + Image { + image: ImageKey, + size: LayoutSize, + repeat: bool, + }, BoxShadow(BoxShadowClipSource), } fn compute_box_shadow_parameters( - shadow_rect: LayoutRect, + shadow_rect_fract_offset: LayoutPoint, + shadow_rect_size: LayoutSize, mut shadow_radius: BorderRadius, prim_shadow_rect: LayoutRect, blur_radius: f32, clip_mode: BoxShadowClipMode, ) -> BoxShadowClipSource { // Make sure corners don't overlap. - ensure_no_corner_overlap(&mut shadow_radius, &shadow_rect); + ensure_no_corner_overlap(&mut shadow_radius, shadow_rect_size); - // Get the fractional offsets required to match the - // source rect with a minimal rect. - let fract_offset = LayoutPoint::new( - shadow_rect.origin.x.fract().abs(), - shadow_rect.origin.y.fract().abs(), - ); let fract_size = LayoutSize::new( - shadow_rect.size.width.fract().abs(), - shadow_rect.size.height.fract().abs(), + shadow_rect_size.width.fract().abs(), + shadow_rect_size.height.fract().abs(), ); // Create a minimal size primitive mask to blur. In this @@ -925,8 +954,8 @@ fn compute_box_shadow_parameters( // The minimal rect to blur. let mut minimal_shadow_rect = LayoutRect::new( LayoutPoint::new( - blur_region + fract_offset.x, - blur_region + fract_offset.y, + blur_region + shadow_rect_fract_offset.x, + blur_region + shadow_rect_fract_offset.y, ), LayoutSize::new( min_shadow_rect_size.width + fract_size.width, @@ -940,14 +969,14 @@ fn compute_box_shadow_parameters( // correctness, since the blur of one corner may affect the blur // in another corner. let mut stretch_mode_x = BoxShadowStretchMode::Stretch; - if shadow_rect.size.width < minimal_shadow_rect.size.width { - minimal_shadow_rect.size.width = shadow_rect.size.width; + if shadow_rect_size.width < minimal_shadow_rect.size.width { + minimal_shadow_rect.size.width = shadow_rect_size.width; stretch_mode_x = BoxShadowStretchMode::Simple; } let mut stretch_mode_y = BoxShadowStretchMode::Stretch; - if shadow_rect.size.height < minimal_shadow_rect.size.height { - minimal_shadow_rect.size.height = shadow_rect.size.height; + if shadow_rect_size.height < minimal_shadow_rect.size.height { + minimal_shadow_rect.size.height = shadow_rect_size.height; stretch_mode_y = BoxShadowStretchMode::Simple; } @@ -975,14 +1004,16 @@ fn compute_box_shadow_parameters( impl ClipItem { pub fn new_box_shadow( - shadow_rect: LayoutRect, + shadow_rect_fract_offset: LayoutPoint, + shadow_rect_size: LayoutSize, mut shadow_radius: BorderRadius, prim_shadow_rect: LayoutRect, blur_radius: f32, clip_mode: BoxShadowClipMode, ) -> Self { let mut source = compute_box_shadow_parameters( - shadow_rect, + shadow_rect_fract_offset, + shadow_rect_size, shadow_radius, prim_shadow_rect, blur_radius, @@ -1019,8 +1050,10 @@ impl ClipItem { shadow_radius.top_right.width *= downscale; let original_alloc_size = source.shadow_rect_alloc_size; + source = compute_box_shadow_parameters( - shadow_rect.scale(downscale, downscale), + shadow_rect_fract_offset * downscale, + shadow_rect_size * downscale, shadow_radius, prim_shadow_rect, blur_radius * downscale, @@ -1035,31 +1068,43 @@ impl ClipItem { // reduce the size of a primitive region. This is typically // used to eliminate redundant clips, and reduce the size of // any clip mask that eventually gets drawn. - fn get_local_clip_rect(&self) -> Option { - match *self { - ClipItem::Rectangle(clip_rect, ClipMode::Clip) => Some(clip_rect), + fn get_local_clip_rect(&self, local_pos: LayoutPoint) -> Option { + let size = match *self { + ClipItem::Rectangle(size, ClipMode::Clip) => Some(size), ClipItem::Rectangle(_, ClipMode::ClipOut) => None, - ClipItem::RoundedRectangle(clip_rect, _, ClipMode::Clip) => Some(clip_rect), + ClipItem::RoundedRectangle(size, _, ClipMode::Clip) => Some(size), ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) => None, - ClipItem::Image { ref mask, .. } if mask.repeat => None, - ClipItem::Image { ref mask, .. } => Some(mask.rect), + ClipItem::Image { repeat, size, .. } => { + if repeat { + None + } else { + Some(size) + } + } ClipItem::BoxShadow(..) => None, - } + }; + + size.map(|size| { + LayoutRect::new(local_pos, size) + }) } fn get_clip_result_complex( &self, + local_pos: LayoutPoint, transform: &LayoutToWorldTransform, prim_world_rect: &WorldRect, world_rect: &WorldRect, ) -> ClipResult { let (clip_rect, inner_rect) = match *self { - ClipItem::Rectangle(clip_rect, ClipMode::Clip) => { + ClipItem::Rectangle(size, ClipMode::Clip) => { + let clip_rect = LayoutRect::new(local_pos, size); (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::RoundedRectangle(size, ref radius, ClipMode::Clip) => { + let clip_rect = LayoutRect::new(local_pos, size); + let inner_clip_rect = extract_inner_rect_safe(&clip_rect, radius); + (clip_rect, inner_clip_rect) } ClipItem::Rectangle(_, ClipMode::ClipOut) | ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) | @@ -1101,10 +1146,13 @@ impl ClipItem { // Check how a given clip source affects a local primitive region. fn get_clip_result( &self, + local_pos: LayoutPoint, prim_rect: &LayoutRect, ) -> ClipResult { match *self { - ClipItem::Rectangle(ref clip_rect, ClipMode::Clip) => { + ClipItem::Rectangle(size, ClipMode::Clip) => { + let clip_rect = LayoutRect::new(local_pos, size); + if clip_rect.contains_rect(prim_rect) { return ClipResult::Accept; } @@ -1118,7 +1166,9 @@ impl ClipItem { } } } - ClipItem::Rectangle(ref clip_rect, ClipMode::ClipOut) => { + ClipItem::Rectangle(size, ClipMode::ClipOut) => { + let clip_rect = LayoutRect::new(local_pos, size); + if clip_rect.contains_rect(prim_rect) { return ClipResult::Reject; } @@ -1132,12 +1182,14 @@ impl ClipItem { } } } - ClipItem::RoundedRectangle(ref clip_rect, ref radius, ClipMode::Clip) => { + ClipItem::RoundedRectangle(size, ref radius, ClipMode::Clip) => { + let clip_rect = LayoutRect::new(local_pos, size); + // TODO(gw): Consider caching this in the ClipNode // if it ever shows in profiles. // TODO(gw): extract_inner_rect_safe is overly // conservative for this code! - let inner_clip_rect = extract_inner_rect_safe(clip_rect, radius); + let inner_clip_rect = extract_inner_rect_safe(&clip_rect, radius); if let Some(inner_clip_rect) = inner_clip_rect { if inner_clip_rect.contains_rect(prim_rect) { return ClipResult::Accept; @@ -1153,12 +1205,14 @@ impl ClipItem { } } } - ClipItem::RoundedRectangle(ref clip_rect, ref radius, ClipMode::ClipOut) => { + ClipItem::RoundedRectangle(size, ref radius, ClipMode::ClipOut) => { + let clip_rect = LayoutRect::new(local_pos, size); + // TODO(gw): Consider caching this in the ClipNode // if it ever shows in profiles. // TODO(gw): extract_inner_rect_safe is overly // conservative for this code! - let inner_clip_rect = extract_inner_rect_safe(clip_rect, radius); + let inner_clip_rect = extract_inner_rect_safe(&clip_rect, radius); if let Some(inner_clip_rect) = inner_clip_rect { if inner_clip_rect.contains_rect(prim_rect) { return ClipResult::Reject; @@ -1174,11 +1228,12 @@ impl ClipItem { } } } - ClipItem::Image { ref mask, .. } => { - if mask.repeat { + ClipItem::Image { size, repeat, .. } => { + if repeat { ClipResult::Partial } else { - match mask.rect.intersection(prim_rect) { + let mask_rect = LayoutRect::new(local_pos, size); + match mask_rect.intersection(prim_rect) { Some(..) => { ClipResult::Partial } @@ -1303,6 +1358,7 @@ impl ClipNodeCollector { fn add_clip_node_to_current_chain( handle: ClipDataHandle, clip_spatial_node_index: SpatialNodeIndex, + local_pos: LayoutPoint, spatial_node_index: SpatialNodeIndex, local_clip_rect: &mut LayoutRect, clip_node_info: &mut Vec, @@ -1336,7 +1392,7 @@ fn add_clip_node_to_current_chain( // If we can convert spaces, try to reduce the size of the region // 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() { + if let Some(clip_rect) = clip_node.item.get_local_clip_rect(local_pos) { match conversion { ClipSpaceConversion::Local => { *local_clip_rect = match local_clip_rect.intersection(&clip_rect) { @@ -1366,6 +1422,7 @@ fn add_clip_node_to_current_chain( } clip_node_info.push(ClipNodeInfo { conversion, + local_pos, handle, spatial_node_index: clip_spatial_node_index, }) diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index d7218f0c0c..698fc653b2 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -917,14 +917,14 @@ impl<'a> DisplayListFlattener<'a> { for _ in 0 .. item_clip_node.count { // Get the id of the clip sources entry for that clip chain node. - let (handle, spatial_node_index) = { + let (handle, spatial_node_index, local_pos) = { let clip_chain = self .clip_store .get_clip_chain(clip_node_clip_chain_id); clip_node_clip_chain_id = clip_chain.parent_clip_chain_id; - (clip_chain.handle, clip_chain.spatial_node_index) + (clip_chain.handle, clip_chain.spatial_node_index, clip_chain.local_pos) }; // Add a new clip chain node, which references the same clip sources, and @@ -933,6 +933,7 @@ impl<'a> DisplayListFlattener<'a> { .clip_store .add_clip_chain_node( handle, + local_pos, spatial_node_index, clip_chain_id, ); @@ -984,7 +985,7 @@ impl<'a> DisplayListFlattener<'a> { // just return the parent clip chain id directly. fn build_clip_chain( &mut self, - clip_items: Vec, + clip_items: Vec<(LayoutPoint, ClipItemKey)>, spatial_node_index: SpatialNodeIndex, parent_clip_chain_id: ClipChainId, ) -> ClipChainId { @@ -993,7 +994,7 @@ impl<'a> DisplayListFlattener<'a> { } else { let mut clip_chain_id = parent_clip_chain_id; - for item in clip_items { + for (local_pos, item) in clip_items { // Intern this clip item, and store the handle // in the clip chain node. let handle = self.resources @@ -1012,6 +1013,7 @@ impl<'a> DisplayListFlattener<'a> { clip_chain_id = self.clip_store .add_clip_chain_node( handle, + local_pos, spatial_node_index, clip_chain_id, ); @@ -1107,7 +1109,7 @@ impl<'a> DisplayListFlattener<'a> { &mut self, clip_and_scroll: ScrollNodeAndClipChain, info: &LayoutPrimitiveInfo, - clip_items: Vec, + clip_items: Vec<(LayoutPoint, ClipItemKey)>, key_kind: PrimitiveKeyKind, ) { // If a shadow context is not active, then add the primitive @@ -1587,7 +1589,7 @@ impl<'a> DisplayListFlattener<'a> { let handle = self .resources .clip_interner - .intern(&ClipItemKey::rectangle(clip_region.main, ClipMode::Clip), || { + .intern(&ClipItemKey::rectangle(clip_region.main.size, ClipMode::Clip), || { ClipItemSceneData { clip_rect: clip_region.main, } @@ -1597,6 +1599,7 @@ impl<'a> DisplayListFlattener<'a> { .clip_store .add_clip_chain_node( handle, + clip_region.main.origin, spatial_node, parent_clip_chain_index, ); @@ -1616,6 +1619,7 @@ impl<'a> DisplayListFlattener<'a> { .clip_store .add_clip_chain_node( handle, + image_mask.rect.origin, spatial_node, parent_clip_chain_index, ); @@ -1626,7 +1630,7 @@ impl<'a> DisplayListFlattener<'a> { let handle = self .resources .clip_interner - .intern(&ClipItemKey::rounded_rect(region.rect, region.radii, region.mode), || { + .intern(&ClipItemKey::rounded_rect(region.rect.size, region.radii, region.mode), || { ClipItemSceneData { clip_rect: region.get_local_clip_rect().unwrap_or(LayoutRect::max_rect()), } @@ -1636,6 +1640,7 @@ impl<'a> DisplayListFlattener<'a> { .clip_store .add_clip_chain_node( handle, + region.rect.origin, spatial_node, parent_clip_chain_index, ); diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 64afd556a7..f1f2c93908 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -5,7 +5,7 @@ use api::{ DevicePoint, DeviceSize, DeviceRect, LayoutRect, LayoutToWorldTransform, LayoutTransform, PremultipliedColorF, LayoutToPictureTransform, PictureToLayoutTransform, PicturePixel, - WorldPixel, WorldToLayoutTransform, + WorldPixel, WorldToLayoutTransform, LayoutPoint, }; use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex}; use gpu_cache::{GpuCacheAddress, GpuDataRequest}; @@ -140,6 +140,8 @@ pub struct ClipMaskInstance { pub segment: i32, pub clip_data_address: GpuCacheAddress, pub resource_address: GpuCacheAddress, + pub local_pos: LayoutPoint, + pub tile_rect: LayoutRect, } /// A border corner dot or dash drawn into the clipping mask. diff --git a/webrender/src/hit_test.rs b/webrender/src/hit_test.rs index fd7f3901c8..98ec34c860 100644 --- a/webrender/src/hit_test.rs +++ b/webrender/src/hit_test.rs @@ -34,13 +34,20 @@ pub struct HitTestClipNode { } impl HitTestClipNode { - fn new(node: &ClipNode) -> Self { + fn new(local_pos: LayoutPoint, node: &ClipNode) -> Self { let region = match node.item { - ClipItem::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode), - ClipItem::RoundedRectangle(ref rect, ref radii, ref mode) => - HitTestRegion::RoundedRectangle(*rect, *radii, *mode), - ClipItem::Image { ref mask, .. } => - HitTestRegion::Rectangle(mask.rect, ClipMode::Clip), + ClipItem::Rectangle(size, mode) => { + let rect = LayoutRect::new(local_pos, size); + HitTestRegion::Rectangle(rect, mode) + } + ClipItem::RoundedRectangle(size, radii, mode) => { + let rect = LayoutRect::new(local_pos, size); + HitTestRegion::RoundedRectangle(rect, radii, mode) + } + ClipItem::Image { size, .. } => { + let rect = LayoutRect::new(local_pos, size); + HitTestRegion::Rectangle(rect, ClipMode::Clip) + } ClipItem::BoxShadow(_) => HitTestRegion::Invalid, }; @@ -170,7 +177,7 @@ impl HitTester { for node in &clip_store.clip_chain_nodes { let clip_node = &clip_data_store[node.handle]; self.clip_chains.push(HitTestClipChainNode { - region: HitTestClipNode::new(clip_node), + region: HitTestClipNode::new(node.local_pos, clip_node), spatial_node_index: node.spatial_node_index, parent_clip_chain_id: HitTestClipChainId(node.parent_clip_chain_id.0), }); diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index fd27c55d60..f493d0667d 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -2,7 +2,7 @@ * 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 api::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU}; +use api::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D}; use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, ExtendMode, DeviceRect, LayoutSideOffsetsAu}; use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, TileOffset, RepeatMode}; use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, LayoutToWorldTransform}; @@ -833,7 +833,7 @@ impl PrimitiveKeyKind { let mut border_segments = Vec::new(); create_border_segments( - rect, + rect.size, &border, &widths, &mut border_segments, @@ -854,7 +854,7 @@ impl PrimitiveKeyKind { ref nine_patch, .. } => { - let brush_segments = nine_patch.create_segments(rect); + let brush_segments = nine_patch.create_segments(rect.size); PrimitiveTemplateKind::ImageBorder { request, @@ -921,7 +921,7 @@ impl PrimitiveKeyKind { let mut brush_segments = Vec::new(); if let Some(ref nine_patch) = nine_patch { - brush_segments = nine_patch.create_segments(rect); + brush_segments = nine_patch.create_segments(rect.size); } // Save opacity of the stops for use in @@ -955,7 +955,7 @@ impl PrimitiveKeyKind { let mut brush_segments = Vec::new(); if let Some(ref nine_patch) = nine_patch { - brush_segments = nine_patch.create_segments(rect); + brush_segments = nine_patch.create_segments(rect.size); } let stops = stops.iter().map(|stop| { @@ -1528,7 +1528,7 @@ pub struct VisibleImageTile { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct VisibleMaskImageTile { pub tile_offset: TileOffset, - pub handle: GpuCacheHandle, + pub tile_rect: LayoutRect, } #[derive(Debug)] @@ -2057,16 +2057,18 @@ impl ClipCorner { #[derive(Debug)] #[repr(C)] pub struct ImageMaskData { - /// The local rect of the whole masked area. - pub local_mask_rect: LayoutRect, - /// The local rect of an individual tile. - pub local_tile_rect: LayoutRect, + /// The local size of the whole masked area. + pub local_mask_size: LayoutSize, } impl ToGpuBlocks for ImageMaskData { fn write_gpu_blocks(&self, mut request: GpuDataRequest) { - request.push(self.local_mask_rect); - request.push(self.local_tile_rect); + request.push([ + self.local_mask_size.width, + self.local_mask_size.height, + 0.0, + 0.0, + ]); } } @@ -2080,10 +2082,19 @@ pub struct ClipData { } impl ClipData { - pub fn rounded_rect(rect: &LayoutRect, radii: &BorderRadius, mode: ClipMode) -> ClipData { + pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData { + // TODO(gw): For simplicity, keep most of the clip GPU structs the + // same as they were, even though the origin is now always + // zero, since they are in the clip's local space. In future, + // we could reduce the GPU cache size of ClipData. + let rect = LayoutRect::new( + LayoutPoint::zero(), + size, + ); + ClipData { rect: ClipRect { - rect: *rect, + rect, mode: mode as u32 as f32, }, top_left: ClipCorner { @@ -2138,7 +2149,16 @@ impl ClipData { } } - pub fn uniform(rect: LayoutRect, radius: f32, mode: ClipMode) -> ClipData { + pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData { + // TODO(gw): For simplicity, keep most of the clip GPU structs the + // same as they were, even though the origin is now always + // zero, since they are in the clip's local space. In future, + // we could reduce the GPU cache size of ClipData. + let rect = LayoutRect::new( + LayoutPoint::zero(), + size, + ); + ClipData { rect: ClipRect { rect, @@ -3474,7 +3494,6 @@ impl PrimitiveStore { request.push(PremultipliedColorF::WHITE); request.push(PremultipliedColorF::WHITE); request.push([tile.rect.size.width, tile.rect.size.height, 0.0, 0.0]); - request.write_segment(tile.rect, [0.0; 4]); } image_instance.visible_tiles.push(VisibleImageTile { @@ -3514,7 +3533,7 @@ impl PrimitiveStore { frame_state, &pic_context.dirty_world_rect, &mut scratch.gradient_tiles, - &mut |rect, mut request| { + &mut |_, mut request| { request.push([ start_point.x, start_point.y, @@ -3527,7 +3546,6 @@ impl PrimitiveStore { stretch_size.height, 0.0, ]); - request.write_segment(*rect, [0.0; 4]); } ); @@ -3554,7 +3572,7 @@ impl PrimitiveStore { frame_state, &pic_context.dirty_world_rect, &mut scratch.gradient_tiles, - &mut |rect, mut request| { + &mut |_, mut request| { request.push([ center.x, center.y, @@ -3567,7 +3585,6 @@ impl PrimitiveStore { stretch_size.width, stretch_size.height, ]); - request.write_segment(*rect, [0.0; 4]); }, ); @@ -3752,12 +3769,12 @@ impl<'a> GpuDataRequest<'a> { local_clip_count += 1; let (local_clip_rect, radius, mode) = match clip_node.item { - ClipItem::RoundedRectangle(rect, radii, clip_mode) => { + ClipItem::RoundedRectangle(size, radii, clip_mode) => { rect_clips_only = false; - (rect, Some(radii), clip_mode) + (LayoutRect::new(clip_instance.local_pos, size), Some(radii), clip_mode) } - ClipItem::Rectangle(rect, mode) => { - (rect, None, mode) + ClipItem::Rectangle(size, mode) => { + (LayoutRect::new(clip_instance.local_pos, size), None, mode) } ClipItem::BoxShadow(ref info) => { rect_clips_only = false; @@ -3775,9 +3792,12 @@ impl<'a> GpuDataRequest<'a> { // box-shadow can have an effect on the result. This // ensures clip-mask tasks get allocated for these // pixel regions, even if no other clips affect them. + let prim_shadow_rect = info.prim_shadow_rect.translate( + &LayoutVector2D::new(clip_instance.local_pos.x, clip_instance.local_pos.y), + ); segment_builder.push_mask_region( - info.prim_shadow_rect, - info.prim_shadow_rect.inflate( + prim_shadow_rect, + prim_shadow_rect.inflate( -0.5 * info.original_alloc_size.width, -0.5 * info.original_alloc_size.height, ), @@ -3896,7 +3916,7 @@ impl PrimitiveInstance { frame_state.segment_builder.build(|segment| { segments.push( BrushSegment::new( - segment.rect, + segment.rect.translate(&LayoutVector2D::new(-prim_local_rect.origin.x, -prim_local_rect.origin.y)), segment.has_mask, segment.edge_flags, [0.0; 4], @@ -3927,6 +3947,7 @@ impl PrimitiveInstance { fn update_clip_task_for_brush( &mut self, + prim_origin: LayoutPoint, prim_local_clip_rect: LayoutRect, root_spatial_node_index: SpatialNodeIndex, prim_bounding_rect: WorldRect, @@ -4075,7 +4096,7 @@ impl PrimitiveInstance { .clip_store .build_clip_chain_instance( self.clip_chain_id, - segment.local_rect, + segment.local_rect.translate(&LayoutVector2D::new(prim_origin.x, prim_origin.y)), prim_local_clip_rect, prim_context.spatial_node_index, &pic_state.map_local_to_pic, @@ -4142,6 +4163,7 @@ impl PrimitiveInstance { // First try to render this primitive's mask using optimized brush rendering. if self.update_clip_task_for_brush( + prim_local_rect.origin, prim_local_clip_rect, root_spatial_node_index, prim_bounding_rect, diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 28a8eaca90..433fc4ea0b 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, DeviceIntSideOffsets}; -use api::{DevicePixelScale, ImageDescriptor, ImageFormat}; +use api::{DevicePixelScale, ImageDescriptor, ImageFormat, LayoutPoint}; use api::{LineStyle, LineOrientation, LayoutSize, ColorF, DirtyRect}; #[cfg(feature = "pathfinder")] use api::FontRenderMode; @@ -253,6 +253,7 @@ pub struct CacheMaskTask { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ClipRegionTask { pub clip_data_address: GpuCacheAddress, + pub local_pos: LayoutPoint, } #[derive(Debug)] @@ -587,6 +588,7 @@ impl RenderTask { let mask_task = RenderTask::new_rounded_rect_mask( cache_size, clip_data_address, + info.minimal_shadow_rect.origin, ); let mask_task_id = render_tasks.add(mask_task); @@ -628,12 +630,14 @@ impl RenderTask { pub fn new_rounded_rect_mask( size: DeviceIntSize, clip_data_address: GpuCacheAddress, + local_pos: LayoutPoint, ) -> Self { RenderTask::with_dynamic_location( size, Vec::new(), RenderTaskKind::ClipRegion(ClipRegionTask { clip_data_address, + local_pos, }), ClearMode::One, ) diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index a5ed9fc607..f5e20a048d 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -534,6 +534,16 @@ pub(crate) mod desc { count: 4, kind: VertexAttributeKind::U16, }, + VertexAttribute { + name: "aClipLocalPos", + count: 2, + kind: VertexAttributeKind::F32, + }, + VertexAttribute { + name: "aClipTileRect", + count: 4, + kind: VertexAttributeKind::F32, + } ], }; diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index b480f4724f..97eccc8cc8 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -652,6 +652,7 @@ impl RenderTarget for AlphaRenderTarget { self.clip_batcher.add_clip_region( task_address, task.clip_data_address, + task.local_pos, ); } RenderTaskKind::Scaling(ref info) => { diff --git a/wrench/reftests/boxshadow/box-shadow-huge-radius.png b/wrench/reftests/boxshadow/box-shadow-huge-radius.png index c40699001c..f10110eae3 100644 Binary files a/wrench/reftests/boxshadow/box-shadow-huge-radius.png and b/wrench/reftests/boxshadow/box-shadow-huge-radius.png differ diff --git a/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png b/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png index b801b193ab..0616288708 100644 Binary files a/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png and b/wrench/reftests/boxshadow/box-shadow-large-blur-radius-3.png differ