From c04d052bbb5188002cd821398c8273d5625d9698 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 6 Nov 2015 18:58:10 -0800 Subject: [PATCH 1/2] Fix box shadow fragment shader. I accidentally submitted an old, broken version of the box shadow shader in the previous patch. --- res/box_shadow.fs.glsl | 24 ++++++++++++++++-------- src/renderer.rs | 16 ++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/res/box_shadow.fs.glsl b/res/box_shadow.fs.glsl index 2d83b576f4..4574a293b4 100644 --- a/res/box_shadow.fs.glsl +++ b/res/box_shadow.fs.glsl @@ -16,18 +16,26 @@ void main(void) float sigma = vBlurRadius / 2.0; float sigmaSqrt2 = sigma * 1.41421356237; + float length; + float value; vec2 position = vPosition - vBorderPosition.zw; - vec2 arcCenter = vDestTextureSize; - float arcRadius = vBorderRadii.x; - float distance = distance(position, vec2(arcCenter)); - float value = clamp(distance, arcRadius - vBlurRadius, arcRadius + vBlurRadius); - float minValue = min(value - range, arcRadius) - value; - float maxValue = min(value + range, arcRadius) - value; + if (vBorderRadii.y == 0.0) { + length = range; + value = position.x; + } else { + length = vBorderRadii.x; + vec2 center = vec2(max(position.x - range, length), + max(position.y - range, length)); + value = distance(position - range, center); + } + + float minValue = min(value - range, length) - value; + float maxValue = min(value + range, length) - value; if (minValue < maxValue) { value = 1.0 - 0.5 * (erf(maxValue / sigmaSqrt2) - erf(minValue / sigmaSqrt2)); } else { - value = 0.0; + value = 1.0; } - SetFragColor(vColor - vec4(value)); + SetFragColor(vec4(vColor.rgb, vColor.a == 0.0 ? value : 1.0 - value)); } diff --git a/src/renderer.rs b/src/renderer.rs index d5d3644614..7e37706a21 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -67,7 +67,7 @@ pub struct Renderer { u_filter_params: UniformLocation, u_filter_texture_size: UniformLocation, - shadow_corner_program_id: ProgramId, + box_shadow_program_id: ProgramId, blur_program_id: ProgramId, u_direction: UniformLocation, @@ -94,8 +94,8 @@ impl Renderer { let border_program_id = device.create_program("border.vs.glsl", "border.fs.glsl"); let blend_program_id = device.create_program("blend.vs.glsl", "blend.fs.glsl"); let filter_program_id = device.create_program("filter.vs.glsl", "filter.fs.glsl"); - let shadow_corner_program_id = device.create_program("shadow_corner.vs.glsl", - "shadow_corner.fs.glsl"); + let box_shadow_program_id = device.create_program("box_shadow.vs.glsl", + "box_shadow.fs.glsl"); let blur_program_id = device.create_program("blur.vs.glsl", "blur.fs.glsl"); let tile_program_id = device.create_program("tile.vs.glsl", "tile.fs.glsl"); @@ -170,7 +170,7 @@ impl Renderer { filter_program_id: filter_program_id, quad_program_id: quad_program_id, blit_program_id: blit_program_id, - shadow_corner_program_id: shadow_corner_program_id, + box_shadow_program_id: box_shadow_program_id, blur_program_id: blur_program_id, tile_program_id: tile_program_id, u_blend_params: u_blend_params, @@ -486,7 +486,7 @@ impl Renderer { let border_program_id = self.border_program_id; let color = if inverted { - ColorF::new(0.0, 0.0, 0.0, 0.0) + ColorF::new(0.0, 0.0, 0.0, 1.0) } else { ColorF::new(1.0, 1.0, 1.0, 1.0) }; @@ -660,12 +660,12 @@ impl Renderer { blur_radius: Au, box_shadow_part: BoxShadowPart, inverted: bool) { - let shadow_corner_program_id = self.shadow_corner_program_id; + let box_shadow_program_id = self.box_shadow_program_id; let blur_radius = blur_radius.to_f32_px(); let color = if inverted { - ColorF::new(0.0, 0.0, 0.0, 0.0) + ColorF::new(1.0, 1.0, 1.0, 0.0) } else { ColorF::new(1.0, 1.0, 1.0, 1.0) }; @@ -730,7 +730,7 @@ impl Renderer { let mut batch = self.get_or_create_raster_batch(update_id, update_index, TextureId(0), - shadow_corner_program_id, + box_shadow_program_id, None); batch.add_draw_item(update_id, TextureId(0), &vertices); } From 58efc4e8e8331398a6cef192521ac327cfc83e36 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 6 Nov 2015 18:59:37 -0800 Subject: [PATCH 2/2] Unify clip rects and clip regions into a single "combined clip region" structure, and clip inset box shadows to rounded rectangle corners. This necessitated changing box shadows to RGBA, because we can't use two mask textures. An alternate solution for the future would be have a "mask combiner" path that can combine two masks as a raster op, but this is more complex. --- src/clipper.rs | 387 ++++++++++++++++----------------- src/internal_types.rs | 54 ++++- src/render_backend.rs | 484 +++++++++++++++++++----------------------- src/resource_list.rs | 10 +- src/texture_cache.rs | 2 +- src/types.rs | 29 ++- 6 files changed, 498 insertions(+), 468 deletions(-) diff --git a/src/clipper.rs b/src/clipper.rs index 457b6de014..ed0a6fce1f 100644 --- a/src/clipper.rs +++ b/src/clipper.rs @@ -1,10 +1,11 @@ use euclid::{Point2D, Rect, Size2D}; -use internal_types::{ClipRectToRegionMaskResult, ClipRectToRegionResult, PolygonPosColorUv}; -use internal_types::{RectPosUv, RectUv, WorkVertex}; +use internal_types::{ClipRectToRegionMaskResult, ClipRectToRegionResult}; +use internal_types::{CombinedClipRegion, PolygonPosColorUv, RectPosUv, RectUv, WorkVertex}; use render_backend::MAX_RECT; use simd::f32x4; +use std::fmt::Debug; use std::mem; -use types::{BoxShadowClipMode, ClipRegion, ColorF}; +use types::{ColorF, ComplexClipRegion}; use util; /// Computes whether the point c is inside the clipping edge ab. @@ -149,183 +150,166 @@ pub fn clip_polygon<'a>(buffers: &'a mut ShClipBuffers, result } -pub fn clip_rect_with_mode

(polygon: P, - sh_clip_buffers: &mut ShClipBuffers, - clip_rect: &Rect, - clip_mode: BoxShadowClipMode, - output: &mut Vec

) - where P: Polygon { - match clip_mode { - BoxShadowClipMode::None => output.push(polygon), - BoxShadowClipMode::Inset => polygon.clip_to_rect(sh_clip_buffers, clip_rect, output), - BoxShadowClipMode::Outset => polygon.clip_out_rect(sh_clip_buffers, clip_rect, output), - } -} - -fn clip_to_region

(polygon: P, - sh_clip_buffers: &mut ShClipBuffers, - polygon_scratch: &mut Vec

, - clip_rect_to_region_result_scratch: &mut Vec>, - output: &mut Vec>, - region: &ClipRegion) - where P: Polygon + Clone { - polygon_scratch.clear(); - polygon.clip_to_rect(sh_clip_buffers, ®ion.main, polygon_scratch); - if polygon_scratch.is_empty() { - return - } - - for main_result in polygon_scratch.drain(..) { - output.push(ClipRectToRegionResult::new(main_result, None)); - } +fn clip_to_complex_region

( + sh_clip_buffers: &mut ShClipBuffers, + polygon_scratch: &mut Vec

, + clip_rect_to_region_result_scratch: &mut Vec>, + output: &mut Vec>, + complex_region: &ComplexClipRegion) + where P: Polygon + Clone { + mem::swap(clip_rect_to_region_result_scratch, output); + for intermediate_result in clip_rect_to_region_result_scratch.drain(..) { + // Quick rejection: + let intermediate_polygon = intermediate_result.rect_result.clone(); + if !intermediate_polygon.intersects_rect(&complex_region.rect) { + continue + } - for complex_region in region.complex.iter() { - mem::swap(clip_rect_to_region_result_scratch, output); - for intermediate_result in clip_rect_to_region_result_scratch.drain(..) { - // Quick rejection: - let intermediate_polygon = intermediate_result.rect_result.clone(); - if !intermediate_polygon.intersects_rect(&complex_region.rect) { - continue - } + // FIXME(pcwalton): This is pretty bogus. I guess we should create a region for the + // inner area -- which may not be rectangular due to nonequal border radii! -- and use + // Sutherland-Hodgman clipping for it. + let border_radius = + f32::max(f32::max(f32::max(size_max(&complex_region.radii.top_left), + size_max(&complex_region.radii.top_right)), + size_max(&complex_region.radii.bottom_left)), + size_max(&complex_region.radii.bottom_right)); + + if border_radius == 0.0 { + intermediate_polygon.clip_to_rect(sh_clip_buffers, + &complex_region.rect, + polygon_scratch); + push_results(output, polygon_scratch, None); + continue + } - // FIXME(pcwalton): This is pretty bogus. I guess we should create a region for the - // inner area -- which may not be rectangular due to nonequal border radii! -- and use - // Sutherland-Hodgman clipping for it. - let border_radius = - f32::max(f32::max(f32::max(size_max(&complex_region.radii.top_left), - size_max(&complex_region.radii.top_right)), - size_max(&complex_region.radii.bottom_left)), - size_max(&complex_region.radii.bottom_right)); - - // Compute the middle intersected region: - // - // +--+-----------------+--+ - // | /| |\ | - // +--+-----------------+--+ - // |#######################| - // |#######################| - // |#######################| - // +--+-----------------+--+ - // | \| |/ | - // +--+-----------------+--+ - let inner_rect = Rect::new( - Point2D::new(complex_region.rect.origin.x, - complex_region.rect.origin.y + border_radius), - Size2D::new(complex_region.rect.size.width, - complex_region.rect.size.height - (border_radius + border_radius))); - if !util::rect_is_empty(&inner_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &inner_rect, polygon_scratch); - push_results(output, polygon_scratch, None); - } + // Compute the middle intersected region: + // + // +--+-----------------+--+ + // | /| |\ | + // +--+-----------------+--+ + // |#######################| + // |#######################| + // |#######################| + // +--+-----------------+--+ + // | \| |/ | + // +--+-----------------+--+ + let inner_rect = Rect::new( + Point2D::new(complex_region.rect.origin.x, + complex_region.rect.origin.y + border_radius), + Size2D::new(complex_region.rect.size.width, + complex_region.rect.size.height - (border_radius + border_radius))); + if !util::rect_is_empty(&inner_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &inner_rect, polygon_scratch); + push_results(output, polygon_scratch, None); + } - // Compute the top region: - // - // +--+-----------------+--+ - // | /|#################|\ | - // +--+-----------------+--+ - // | | - // | | - // | | - // +--+-----------------+--+ - // | \| |/ | - // +--+-----------------+--+ - let top_rect = Rect::new( - Point2D::new(complex_region.rect.origin.x + border_radius, - complex_region.rect.origin.y), - Size2D::new(complex_region.rect.size.width - (border_radius + border_radius), - border_radius)); - if !util::rect_is_empty(&top_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &top_rect, polygon_scratch); - push_results(output, polygon_scratch, None); - } + // Compute the top region: + // + // +--+-----------------+--+ + // | /|#################|\ | + // +--+-----------------+--+ + // | | + // | | + // | | + // +--+-----------------+--+ + // | \| |/ | + // +--+-----------------+--+ + let top_rect = Rect::new( + Point2D::new(complex_region.rect.origin.x + border_radius, + complex_region.rect.origin.y), + Size2D::new(complex_region.rect.size.width - (border_radius + border_radius), + border_radius)); + if !util::rect_is_empty(&top_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &top_rect, polygon_scratch); + push_results(output, polygon_scratch, None); + } - // Compute the bottom region: - // - // +--+-----------------+--+ - // | /| |\ | - // +--+-----------------+--+ - // | | - // | | - // | | - // +--+-----------------+--+ - // | \|#################|/ | - // +--+-----------------+--+ - let bottom_rect = Rect::new( - Point2D::new(complex_region.rect.origin.x + border_radius, - complex_region.rect.max_y() - border_radius), - Size2D::new(complex_region.rect.size.width - (border_radius + border_radius), - border_radius)); - if !util::rect_is_empty(&bottom_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &bottom_rect, polygon_scratch); - push_results(output, polygon_scratch, None); - } + // Compute the bottom region: + // + // +--+-----------------+--+ + // | /| |\ | + // +--+-----------------+--+ + // | | + // | | + // | | + // +--+-----------------+--+ + // | \|#################|/ | + // +--+-----------------+--+ + let bottom_rect = Rect::new( + Point2D::new(complex_region.rect.origin.x + border_radius, + complex_region.rect.max_y() - border_radius), + Size2D::new(complex_region.rect.size.width - (border_radius + border_radius), + border_radius)); + if !util::rect_is_empty(&bottom_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &bottom_rect, polygon_scratch); + push_results(output, polygon_scratch, None); + } - // Now for the corners: - // - // +--+-----------------+--+ - // A | /| |\ | B - // +--+-----------------+--+ - // | | - // | | - // | | - // +--+-----------------+--+ - // C | \| |/ | D - // +--+-----------------+--+ - // - // FIXME(pcwalton): This should clip the mask u and v properly too. For now we just - // blindly assume that the border was not clipped. - - // Compute A: - let mut corner_rect = Rect::new(complex_region.rect.origin, - Size2D::new(border_radius, border_radius)); - if !util::rect_is_empty(&corner_rect) { - let mask_rect = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1.0, 1.0)); - intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); - push_results(output, - polygon_scratch, - Some(ClipRectToRegionMaskResult::new(&mask_rect, - &corner_rect, - border_radius))) - } + // Now for the corners: + // + // +--+-----------------+--+ + // A | /| |\ | B + // +--+-----------------+--+ + // | | + // | | + // | | + // +--+-----------------+--+ + // C | \| |/ | D + // +--+-----------------+--+ + // + // FIXME(pcwalton): This should clip the mask u and v properly too. For now we just + // blindly assume that the border was not clipped. + + // Compute A: + let mut corner_rect = Rect::new(complex_region.rect.origin, + Size2D::new(border_radius, border_radius)); + if !util::rect_is_empty(&corner_rect) { + let mask_rect = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(1.0, 1.0)); + intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); + push_results(output, + polygon_scratch, + Some(ClipRectToRegionMaskResult::new(&mask_rect, + &corner_rect, + border_radius))) + } - // B: - corner_rect.origin = Point2D::new(complex_region.rect.max_x() - border_radius, - complex_region.rect.origin.y); - if !util::rect_is_empty(&corner_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); - let mask_rect = Rect::new(Point2D::new(1.0, 0.0), Size2D::new(-1.0, 1.0)); - push_results(output, - polygon_scratch, - Some(ClipRectToRegionMaskResult::new(&mask_rect, - &corner_rect, - border_radius))) - } + // B: + corner_rect.origin = Point2D::new(complex_region.rect.max_x() - border_radius, + complex_region.rect.origin.y); + if !util::rect_is_empty(&corner_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); + let mask_rect = Rect::new(Point2D::new(1.0, 0.0), Size2D::new(-1.0, 1.0)); + push_results(output, + polygon_scratch, + Some(ClipRectToRegionMaskResult::new(&mask_rect, + &corner_rect, + border_radius))) + } - // C: - corner_rect.origin = Point2D::new(complex_region.rect.origin.x, - complex_region.rect.max_y() - border_radius); - if !util::rect_is_empty(&corner_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); - let mask_rect = Rect::new(Point2D::new(0.0, 1.0), Size2D::new(1.0, -1.0)); - push_results(output, - polygon_scratch, - Some(ClipRectToRegionMaskResult::new(&mask_rect, - &corner_rect, - border_radius))) - } + // C: + corner_rect.origin = Point2D::new(complex_region.rect.origin.x, + complex_region.rect.max_y() - border_radius); + if !util::rect_is_empty(&corner_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); + let mask_rect = Rect::new(Point2D::new(0.0, 1.0), Size2D::new(1.0, -1.0)); + push_results(output, + polygon_scratch, + Some(ClipRectToRegionMaskResult::new(&mask_rect, + &corner_rect, + border_radius))) + } - // D: - corner_rect.origin = Point2D::new(complex_region.rect.max_x() - border_radius, - complex_region.rect.max_y() - border_radius); - if !util::rect_is_empty(&corner_rect) { - intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); - let mask_rect = Rect::new(Point2D::new(1.0, 1.0), Size2D::new(-1.0, -1.0)); - push_results(output, - polygon_scratch, - Some(ClipRectToRegionMaskResult::new(&mask_rect, - &corner_rect, - border_radius))) - } + // D: + corner_rect.origin = Point2D::new(complex_region.rect.max_x() - border_radius, + complex_region.rect.max_y() - border_radius); + if !util::rect_is_empty(&corner_rect) { + intermediate_polygon.clip_to_rect(sh_clip_buffers, &corner_rect, polygon_scratch); + let mask_rect = Rect::new(Point2D::new(1.0, 1.0), Size2D::new(-1.0, -1.0)); + push_results(output, + polygon_scratch, + Some(ClipRectToRegionMaskResult::new(&mask_rect, + &corner_rect, + border_radius))) } } @@ -344,27 +328,44 @@ fn clip_to_region

(polygon: P, } /// NB: Clobbers both `polygon_scratch` and `polygon_output` in the typed clip buffers. -pub fn clip_rect_with_mode_and_to_region

(polygon: P, - sh_clip_buffers: &mut ShClipBuffers, - typed_clip_buffers: &mut TypedClipBuffers

, - clip_rect: &Rect, - clip_mode: BoxShadowClipMode, - clip_region: &ClipRegion) - where P: Polygon + Clone { - typed_clip_buffers.polygon_scratch.clear(); - clip_rect_with_mode(polygon, - sh_clip_buffers, - clip_rect, - clip_mode, - &mut typed_clip_buffers.polygon_scratch); - - for initial_clip_result in typed_clip_buffers.polygon_scratch.drain(..) { - clip_to_region(initial_clip_result, - sh_clip_buffers, - &mut typed_clip_buffers.polygon_output, - &mut typed_clip_buffers.clip_rect_to_region_result_scratch, - &mut typed_clip_buffers.clip_rect_to_region_result_output, - clip_region) +pub fn clip_rect_to_combined_region

(polygon: P, + sh_clip_buffers: &mut ShClipBuffers, + typed_clip_buffers: &mut TypedClipBuffers

, + clip_region: &CombinedClipRegion) + where P: Polygon + Debug + Clone { + polygon.clip_to_rect(sh_clip_buffers, + &clip_region.clip_in_rect, + &mut typed_clip_buffers.polygon_scratch); + + if let Some(ref clip_out_complex) = clip_region.clip_out_complex { + for initial_clip_result in typed_clip_buffers.polygon_scratch.drain(..) { + initial_clip_result.clip_out_rect(sh_clip_buffers, + &clip_out_complex.rect, + &mut typed_clip_buffers.polygon_output); + } + mem::swap(&mut typed_clip_buffers.polygon_output, + &mut typed_clip_buffers.polygon_scratch) + } + + typed_clip_buffers.clip_rect_to_region_result_output + .extend(typed_clip_buffers.polygon_scratch.drain(..).map(|clip_rect_result| { + ClipRectToRegionResult::new(clip_rect_result, None) + })); + + if let Some(ref clip_in_complex) = clip_region.clip_in_complex { + clip_to_complex_region(sh_clip_buffers, + &mut typed_clip_buffers.polygon_output, + &mut typed_clip_buffers.clip_rect_to_region_result_scratch, + &mut typed_clip_buffers.clip_rect_to_region_result_output, + clip_in_complex); + } + + for clip_in_complex in clip_region.clip_in_complex_stack { + clip_to_complex_region(sh_clip_buffers, + &mut typed_clip_buffers.polygon_output, + &mut typed_clip_buffers.clip_rect_to_region_result_scratch, + &mut typed_clip_buffers.clip_rect_to_region_result_output, + clip_in_complex) } } diff --git a/src/internal_types.rs b/src/internal_types.rs index da6ee590d2..8b1abdf87d 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -11,8 +11,9 @@ use std::collections::hash_state::DefaultState; use std::sync::Arc; use std::sync::mpsc::Sender; use texture_cache::TextureCacheItem; -use types::{FontKey, ImageKey, Epoch, ColorF, PipelineId, ImageFormat, DisplayListID}; -use types::{StackingContext, DisplayListBuilder, DisplayListMode, CompositionOp}; +use types::{DisplayListID, FontKey, ImageKey, Epoch, ColorF, PipelineId}; +use types::{ImageFormat, StackingContext, DisplayListBuilder, DisplayListMode, CompositionOp}; +use types::{ComplexClipRegion}; use util; const UV_FLOAT_TO_FIXED: f32 = 65535.0; @@ -21,6 +22,17 @@ const COLOR_FLOAT_TO_FIXED: f32 = 255.0; pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; pub const ORTHO_FAR_PLANE: f32 = 1000000.0; +static ZERO_RECT_F32: Rect = Rect { + origin: Point2D { + x: 0.0, + y: 0.0, + }, + size: Size2D { + width: 0.0, + height: 0.0, + }, +}; + #[derive(Clone, Copy, Debug)] pub struct IdNamespace(pub u32); @@ -826,3 +838,41 @@ pub enum BasicRotationAngle { Clockwise270, } +#[derive(Debug, Clone, Copy)] +pub struct CombinedClipRegion<'a> { + pub clip_in_rect: Rect, + pub clip_in_complex: Option, + pub clip_in_complex_stack: &'a [ComplexClipRegion], + pub clip_out_complex: Option, +} + +impl<'a> CombinedClipRegion<'a> { + pub fn from_clip_in_rect_and_stack<'b>(clip_in_rect: &Rect, + clip_in_complex_stack: &'b [ComplexClipRegion]) + -> CombinedClipRegion<'b> { + CombinedClipRegion { + clip_in_rect: *clip_in_rect, + clip_in_complex: None, + clip_in_complex_stack: clip_in_complex_stack, + clip_out_complex: None, + } + } + + pub fn clip_in_rect(&mut self, rect: &Rect) -> &mut CombinedClipRegion<'a> { + self.clip_in_rect = self.clip_in_rect.intersection(rect).unwrap_or(ZERO_RECT_F32); + self + } + + pub fn clip_in(&mut self, region: &ComplexClipRegion) -> &mut CombinedClipRegion<'a> { + debug_assert!(self.clip_in_complex.is_none()); + self.clip_in_complex = Some(*region); + self + } + + pub fn clip_out(&mut self, region: &ComplexClipRegion) -> &mut CombinedClipRegion<'a> { + debug_assert!(self.clip_out_complex.is_none()); + self.clip_out_complex = Some(*region); + self + } +} + diff --git a/src/render_backend.rs b/src/render_backend.rs index c71fc444e6..63dfe7359b 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -13,7 +13,7 @@ use internal_types::{ClipRectToRegionResult, DrawListIndex, DrawListItemIndex, D use internal_types::{CompositeInfo, BorderEdgeDirection, RenderTargetIndex, GlyphKey}; use internal_types::{FontTemplate, Glyph, PolygonPosColorUv, RectPosUv, TextureTarget}; use internal_types::{ResourceId, IdNamespace, TiledImageKey, BasicRotationAngle}; -use internal_types::{RectUv}; +use internal_types::{RectUv, CombinedClipRegion}; use layer::Layer; use optimizer; use render_api::RenderApi; @@ -39,6 +39,7 @@ use types::{GlyphInstance, DrawList, ImageFormat, BoxShadowClipMode, DisplayItem use types::{PipelineId, RenderNotifier, StackingContext, SpecificDisplayItem, ColorF}; use types::{RenderTargetID, MixBlendMode, CompositeDisplayItem, BorderSide, BorderStyle}; use types::{NodeIndex, CompositionOp, FilterOp, LowLevelFilterOp, BlurDirection}; +use types::{ComplexClipRegion, BorderRadius}; use util; use util::MatrixHelpers; use scoped_threadpool; @@ -1473,9 +1474,7 @@ impl DrawCommandBuilder { fn add_textured_rectangle(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_mode: BoxShadowClipMode, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, image_info: &TextureCacheItem, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, @@ -1483,8 +1482,6 @@ impl DrawCommandBuilder { self.add_axis_aligned_gradient_with_texture(sort_key, rect, clip, - clip_mode, - clip_region, image_info, resource_cache, clip_buffers, @@ -1495,17 +1492,13 @@ impl DrawCommandBuilder { fn add_color_rectangle(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_mode: BoxShadowClipMode, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, color: &ColorF) { self.add_axis_aligned_gradient(sort_key, rect, clip, - clip_mode, - clip_region, resource_cache, clip_buffers, &[*color, *color, *color, *color]) @@ -1532,8 +1525,7 @@ impl DrawCommandBuilder { fn add_image(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip_rect: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, stretch_size: &Size2D, image_key: ImageKey, resource_cache: &ResourceCache, @@ -1554,8 +1546,7 @@ impl DrawCommandBuilder { self.push_image_rect(color, image_info, - clip_rect, - clip_region, + clip, &sort_key, resource_cache, clip_buffers, @@ -1591,8 +1582,7 @@ impl DrawCommandBuilder { self.push_image_rect(color, image_info, - clip_rect, - clip_region, + clip, &sort_key, resource_cache, clip_buffers, @@ -1609,28 +1599,21 @@ impl DrawCommandBuilder { fn push_image_rect(&mut self, color: &ColorF, image_info: &TextureCacheItem, - clip_rect: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, sort_key: &DisplayItemKey, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, rect: &Rect, uv: &RectUv) { - clipper::clip_rect_with_mode_and_to_region( - RectPosUv { - pos: *rect, - uv: *uv - }, - &mut clip_buffers.sh_clip_buffers, - &mut clip_buffers.rect_pos_uv, - clip_rect, - BoxShadowClipMode::Inset, - clip_region); + clipper::clip_rect_to_combined_region(RectPosUv { + pos: *rect, + uv: *uv + }, + &mut clip_buffers.sh_clip_buffers, + &mut clip_buffers.rect_pos_uv, + clip); for clip_region in clip_buffers.rect_pos_uv.clip_rect_to_region_result_output.drain(..) { - let mask = mask_for_clip_region(resource_cache, - &clip_region, - false); - + let mask = mask_for_clip_region(resource_cache, &clip_region, false); let colors = [*color, *color, *color, *color]; let mut vertices = clip_region.make_packed_vertices_for_rect(&colors, mask, @@ -1732,9 +1715,7 @@ impl DrawCommandBuilder { fn add_axis_aligned_gradient(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_mode: BoxShadowClipMode, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, colors: &[ColorF; 4]) { @@ -1742,8 +1723,6 @@ impl DrawCommandBuilder { self.add_axis_aligned_gradient_with_texture(sort_key, rect, clip, - clip_mode, - clip_region, white_image, resource_cache, clip_buffers, @@ -1754,9 +1733,7 @@ impl DrawCommandBuilder { fn add_axis_aligned_gradient_with_texture(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_mode: BoxShadowClipMode, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, image_info: &TextureCacheItem, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, @@ -1772,20 +1749,16 @@ impl DrawCommandBuilder { bottom_right: Point2D::new(image_info.u1, image_info.v1), }; - clipper::clip_rect_with_mode_and_to_region( + clipper::clip_rect_to_combined_region( RectPosUv { pos: *rect, uv: uv, }, &mut clip_buffers.sh_clip_buffers, &mut clip_buffers.rect_pos_uv, - clip, - clip_mode, - clip_region); + clip); for clip_region in clip_buffers.rect_pos_uv.clip_rect_to_region_result_output.drain(..) { - let mask = mask_for_clip_region(resource_cache, - &clip_region, - false); + let mask = mask_for_clip_region(resource_cache, &clip_region, false); let mut vertices = clip_region.make_packed_vertices_for_rect(colors, mask, @@ -1801,8 +1774,7 @@ impl DrawCommandBuilder { fn add_gradient(&mut self, sort_key: &DisplayItemKey, - rect: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, start_point: &Point2D, end_point: &Point2D, stops: &[GradientStop], @@ -1861,19 +1833,14 @@ impl DrawCommandBuilder { }; { // scope for buffers - clipper::clip_rect_with_mode_and_to_region( - gradient_polygon, - &mut clip_buffers.sh_clip_buffers, - &mut clip_buffers.polygon_pos_color_uv, - &rect, - BoxShadowClipMode::Inset, - &clip_region); + clipper::clip_rect_to_combined_region(gradient_polygon, + &mut clip_buffers.sh_clip_buffers, + &mut clip_buffers.polygon_pos_color_uv, + clip); for clip_result in clip_buffers.polygon_pos_color_uv .clip_rect_to_region_result_output .drain(..) { - let mask = mask_for_clip_region(resource_cache, - &clip_result, - false); + let mask = mask_for_clip_region(resource_cache, &clip_result, false); let mut packed_vertices = Vec::new(); if clip_result.rect_result.vertices.len() >= 3 { @@ -1902,8 +1869,7 @@ impl DrawCommandBuilder { fn add_box_shadow(&mut self, sort_key: &DisplayItemKey, box_bounds: &Rect, - clip: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, box_offset: &Point2D, color: &ColorF, blur_radius: f32, @@ -1916,14 +1882,7 @@ impl DrawCommandBuilder { // Fast path. if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None { - self.add_color_rectangle(sort_key, - &rect, - clip, - BoxShadowClipMode::Inset, - clip_region, - resource_cache, - clip_buffers, - color); + self.add_color_rectangle(sort_key, &rect, clip, resource_cache, clip_buffers, color); return; } @@ -1936,13 +1895,14 @@ impl DrawCommandBuilder { spread_radius, border_radius, clip_mode, + clip, resource_cache, clip_buffers); // Draw the sides. self.add_box_shadow_sides(sort_key, box_bounds, - clip_region, + clip, box_offset, color, blur_radius, @@ -1953,17 +1913,26 @@ impl DrawCommandBuilder { clip_buffers); match clip_mode { - BoxShadowClipMode::None | BoxShadowClipMode::Outset => { + BoxShadowClipMode::None => { + // Fill the center area. + self.add_color_rectangle(sort_key, + box_bounds, + clip, + resource_cache, + clip_buffers, + color); + } + BoxShadowClipMode::Outset => { // Fill the center area. let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); let center_rect = Rect::new(metrics.tl_inner, Size2D::new(metrics.br_inner.x - metrics.tl_inner.x, metrics.br_inner.y - metrics.tl_inner.y)); + let mut clip = *clip; + clip.clip_out(&ComplexClipRegion::from_rect(&box_bounds)); self.add_color_rectangle(sort_key, ¢er_rect, - box_bounds, - clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, color); @@ -1972,13 +1941,12 @@ impl DrawCommandBuilder { // Fill in the outsides. self.fill_outside_area_of_inset_box_shadow(sort_key, box_bounds, - clip_region, + clip, box_offset, color, blur_radius, spread_radius, border_radius, - clip_mode, resource_cache, clip_buffers); } @@ -1994,6 +1962,7 @@ impl DrawCommandBuilder { spread_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, + clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers) { // Draw the corners. @@ -2010,47 +1979,53 @@ impl DrawCommandBuilder { let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); + + let clip = self.adjust_clip_for_box_shadow_clip_mode(clip, + box_bounds, + border_radius, + clip_mode); + self.add_box_shadow_corner(sort_key, &metrics.tl_outer, &metrics.tl_inner, - box_bounds, &color, blur_radius, border_radius, clip_mode, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Upright); self.add_box_shadow_corner(sort_key, &Point2D::new(metrics.tr_inner.x, metrics.tr_outer.y), &Point2D::new(metrics.tr_outer.x, metrics.tr_inner.y), - box_bounds, &color, blur_radius, border_radius, clip_mode, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise90); self.add_box_shadow_corner(sort_key, &metrics.br_inner, &metrics.br_outer, - box_bounds, &color, blur_radius, border_radius, clip_mode, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise180); self.add_box_shadow_corner(sort_key, &Point2D::new(metrics.bl_outer.x, metrics.bl_inner.y), &Point2D::new(metrics.bl_inner.x, metrics.bl_outer.y), - box_bounds, &color, blur_radius, border_radius, clip_mode, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise270); @@ -2059,7 +2034,7 @@ impl DrawCommandBuilder { fn add_box_shadow_sides(&mut self, sort_key: &DisplayItemKey, box_bounds: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, box_offset: &Point2D, color: &ColorF, blur_radius: f32, @@ -2071,6 +2046,11 @@ impl DrawCommandBuilder { let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); + let clip = self.adjust_clip_for_box_shadow_clip_mode(clip, + box_bounds, + border_radius, + clip_mode); + // Draw the sides. // // +--+------------------+--+ @@ -2101,48 +2081,44 @@ impl DrawCommandBuilder { self.add_box_shadow_edge(sort_key, &top_rect.origin, &top_rect.bottom_right(), - box_bounds, color, blur_radius, border_radius, clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise270); self.add_box_shadow_edge(sort_key, &right_rect.origin, &right_rect.bottom_right(), - box_bounds, color, blur_radius, border_radius, clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Upright); self.add_box_shadow_edge(sort_key, &bottom_rect.origin, &bottom_rect.bottom_right(), - box_bounds, color, blur_radius, border_radius, clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise90); self.add_box_shadow_edge(sort_key, &left_rect.origin, &left_rect.bottom_right(), - box_bounds, color, blur_radius, border_radius, clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, BasicRotationAngle::Clockwise180); @@ -2151,18 +2127,22 @@ impl DrawCommandBuilder { fn fill_outside_area_of_inset_box_shadow(&mut self, sort_key: &DisplayItemKey, box_bounds: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, box_offset: &Point2D, color: &ColorF, blur_radius: f32, spread_radius: f32, border_radius: f32, - clip_mode: BoxShadowClipMode, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers) { let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); + let clip = self.adjust_clip_for_box_shadow_clip_mode(clip, + box_bounds, + border_radius, + BoxShadowClipMode::Inset); + // Fill in the outside area of the box. // // +------------------------------+ @@ -2184,9 +2164,7 @@ impl DrawCommandBuilder { &Rect::new(box_bounds.origin, Size2D::new(box_bounds.size.width, metrics.tl_outer.y - box_bounds.origin.y)), - box_bounds, - clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, color); @@ -2196,9 +2174,7 @@ impl DrawCommandBuilder { &Rect::new(metrics.tr_outer, Size2D::new(box_bounds.max_x() - metrics.tr_outer.x, metrics.br_outer.y - metrics.tr_outer.y)), - box_bounds, - clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, color); @@ -2208,9 +2184,7 @@ impl DrawCommandBuilder { &Rect::new(Point2D::new(box_bounds.origin.x, metrics.bl_outer.y), Size2D::new(box_bounds.size.width, box_bounds.max_y() - metrics.br_outer.y)), - box_bounds, - clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, color); @@ -2220,20 +2194,41 @@ impl DrawCommandBuilder { &Rect::new(Point2D::new(box_bounds.origin.x, metrics.tl_outer.y), Size2D::new(metrics.tl_outer.x - box_bounds.origin.x, metrics.bl_outer.y - metrics.tl_outer.y)), - box_bounds, - clip_mode, - clip_region, + &clip, resource_cache, clip_buffers, color); } + fn adjust_clip_for_box_shadow_clip_mode<'a>(&mut self, + clip: &CombinedClipRegion<'a>, + box_bounds: &Rect, + border_radius: f32, + clip_mode: BoxShadowClipMode) + -> CombinedClipRegion<'a> { + let mut clip = *clip; + match clip_mode { + BoxShadowClipMode::None => {} + BoxShadowClipMode::Inset => { + clip.clip_in(&ComplexClipRegion { + rect: *box_bounds, + radii: BorderRadius::uniform(border_radius), + }); + } + BoxShadowClipMode::Outset => { + // TODO(pcwalton): Support border radii here too, once we have inverted rounded + // rect clip masks. + clip.clip_out(&ComplexClipRegion::from_rect(box_bounds)); + } + } + clip + } + #[inline] fn add_border_edge(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, direction: BorderEdgeDirection, color: &ColorF, border_style: BorderStyle, @@ -2272,8 +2267,6 @@ impl DrawCommandBuilder { self.add_color_rectangle(sort_key, &dash_rect, clip, - BoxShadowClipMode::Inset, - clip_region, resource_cache, clip_buffers, color); @@ -2318,8 +2311,6 @@ impl DrawCommandBuilder { Size2D::new(dot_rect.size.width / 2.0, dot_rect.size.height / 2.0)), clip, - BoxShadowClipMode::Inset, - clip_region, color_image, resource_cache, clip_buffers, @@ -2331,8 +2322,6 @@ impl DrawCommandBuilder { Size2D::new(-dot_rect.size.width / 2.0, dot_rect.size.height / 2.0)), clip, - BoxShadowClipMode::Inset, - clip_region, color_image, resource_cache, clip_buffers, @@ -2344,8 +2333,6 @@ impl DrawCommandBuilder { Size2D::new(-dot_rect.size.width / 2.0, -dot_rect.size.height / 2.0)), clip, - BoxShadowClipMode::Inset, - clip_region, color_image, resource_cache, clip_buffers, @@ -2357,8 +2344,6 @@ impl DrawCommandBuilder { Size2D::new(dot_rect.size.width / 2.0, -dot_rect.size.height / 2.0)), clip, - BoxShadowClipMode::Inset, - clip_region, color_image, resource_cache, clip_buffers, @@ -2387,16 +2372,12 @@ impl DrawCommandBuilder { self.add_color_rectangle(sort_key, &outer_rect, clip, - BoxShadowClipMode::Inset, - clip_region, resource_cache, clip_buffers, color); self.add_color_rectangle(sort_key, &inner_rect, clip, - BoxShadowClipMode::Inset, - clip_region, resource_cache, clip_buffers, color); @@ -2405,8 +2386,6 @@ impl DrawCommandBuilder { self.add_color_rectangle(sort_key, rect, clip, - BoxShadowClipMode::Inset, - clip_region, resource_cache, clip_buffers, color); @@ -2417,13 +2396,14 @@ impl DrawCommandBuilder { #[inline] fn add_border_corner(&mut self, sort_key: &DisplayItemKey, - clip: &Rect, + clip: &CombinedClipRegion, vertices_rect: &Rect, color0: &ColorF, color1: &ColorF, outer_radius: &Size2D, inner_radius: &Size2D, resource_cache: &ResourceCache, + clip_buffers: &mut clipper::ClipBuffers, rotation_angle: BasicRotationAngle) { if color0.a <= 0.0 && color1.a <= 0.0 { return @@ -2444,36 +2424,46 @@ impl DrawCommandBuilder { } }; + // FIXME(pcwalton): Either use RGBA8 textures instead of alpha masks here, or implement + // a mask combiner. let mask_uv = RectUv::from_image_and_rotation_angle(mask_image, rotation_angle); - if vertices_rect.intersects(clip) { + clipper::clip_rect_to_combined_region( + RectPosUv { + pos: *vertices_rect, + uv: mask_uv, + }, + &mut clip_buffers.sh_clip_buffers, + &mut clip_buffers.rect_pos_uv, + clip); + for clip_region in clip_buffers.rect_pos_uv.clip_rect_to_region_result_output.drain(..) { let v0; let v1; let muv0; let muv1; match rotation_angle { BasicRotationAngle::Upright => { - v0 = vertices_rect.origin; - muv0 = mask_uv.top_left; - v1 = vertices_rect.bottom_right(); - muv1 = mask_uv.bottom_right; + v0 = clip_region.rect_result.pos.origin; + muv0 = clip_region.rect_result.uv.top_left; + v1 = clip_region.rect_result.pos.bottom_right(); + muv1 = clip_region.rect_result.uv.bottom_right; } BasicRotationAngle::Clockwise90 => { - v0 = vertices_rect.top_right(); - muv0 = mask_uv.top_right; - v1 = vertices_rect.bottom_left(); - muv1 = mask_uv.bottom_left; + v0 = clip_region.rect_result.pos.top_right(); + muv0 = clip_region.rect_result.uv.top_right; + v1 = clip_region.rect_result.pos.bottom_left(); + muv1 = clip_region.rect_result.uv.bottom_left; } BasicRotationAngle::Clockwise180 => { - v0 = vertices_rect.bottom_right(); - muv0 = mask_uv.bottom_right; - v1 = vertices_rect.origin; - muv1 = mask_uv.top_left; + v0 = clip_region.rect_result.pos.bottom_right(); + muv0 = clip_region.rect_result.uv.bottom_right; + v1 = clip_region.rect_result.pos.origin; + muv1 = clip_region.rect_result.uv.top_left; } BasicRotationAngle::Clockwise270 => { - v0 = vertices_rect.bottom_left(); - muv0 = mask_uv.bottom_left; - v1 = vertices_rect.top_right(); - muv1 = mask_uv.top_right; + v0 = clip_region.rect_result.pos.bottom_left(); + muv0 = clip_region.rect_result.uv.bottom_left; + v1 = clip_region.rect_result.pos.top_right(); + muv1 = clip_region.rect_result.uv.top_right; } } @@ -2519,68 +2509,43 @@ impl DrawCommandBuilder { } } - fn add_masked_rectangle(&mut self, - sort_key: &DisplayItemKey, - v0: &Point2D, - v1: &Point2D, - clip: &Rect, - clip_mode: BoxShadowClipMode, - color0: &ColorF, - color1: &ColorF, - mask_image: &TextureCacheItem, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, - rotation_angle: BasicRotationAngle) { + fn add_color_image_rectangle(&mut self, + sort_key: &DisplayItemKey, + v0: &Point2D, + v1: &Point2D, + clip: &CombinedClipRegion, + color0: &ColorF, + color1: &ColorF, + color_image: &TextureCacheItem, + resource_cache: &ResourceCache, + clip_buffers: &mut ClipBuffers, + rotation_angle: BasicRotationAngle) { if color0.a <= 0.0 || color1.a <= 0.0 { return } - let white_image = resource_cache.get_dummy_color_image(); let vertices_rect = Rect::new(*v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)); - let mask_uv = RectUv::from_image_and_rotation_angle(mask_image, rotation_angle); - - clipper::clip_rect_with_mode(RectPosUv { - pos: vertices_rect, - uv: mask_uv, - }, - &mut clip_buffers.sh_clip_buffers, - clip, - clip_mode, - &mut clip_buffers.rect_pos_uv.polygon_output); - for clip_result in clip_buffers.rect_pos_uv.polygon_output.drain(..) { - let mut vertices = [ - PackedVertex::from_components(clip_result.pos.origin.x, clip_result.pos.origin.y, - color0, - 0.0, 0.0, - clip_result.uv.top_left.x, clip_result.uv.top_left.y, - white_image.texture_index, - mask_image.texture_index), - PackedVertex::from_components(clip_result.pos.max_x(), clip_result.pos.origin.y, - color0, - 0.0, 0.0, - clip_result.uv.top_right.x, - clip_result.uv.top_right.y, - white_image.texture_index, - mask_image.texture_index), - PackedVertex::from_components(clip_result.pos.origin.x, clip_result.pos.max_y(), - color1, - 0.0, 0.0, - clip_result.uv.bottom_left.x, - clip_result.uv.bottom_left.y, - white_image.texture_index, - mask_image.texture_index), - PackedVertex::from_components(clip_result.pos.max_x(), clip_result.pos.max_y(), - color1, - 0.0, 0.0, - clip_result.uv.bottom_right.x, - clip_result.uv.bottom_right.y, - white_image.texture_index, - mask_image.texture_index), - ]; + let color_uv = RectUv::from_image_and_rotation_angle(color_image, rotation_angle); + + clipper::clip_rect_to_combined_region(RectPosUv { + pos: vertices_rect, + uv: color_uv, + }, + &mut clip_buffers.sh_clip_buffers, + &mut clip_buffers.rect_pos_uv, + clip); + for clip_region in clip_buffers.rect_pos_uv.clip_rect_to_region_result_output.drain(..) { + let mask = mask_for_clip_region(resource_cache, + &clip_region, + false); + let colors = [*color0, *color0, *color1, *color1]; + let mut vertices = clip_region.make_packed_vertices_for_rect(&colors, + mask, + color_image.texture_index); self.add_draw_item(sort_key, - white_image.texture_id, - mask_image.texture_id, + color_image.texture_id, + mask.texture_id, Primitive::Rectangles, &mut vertices); } @@ -2589,8 +2554,7 @@ impl DrawCommandBuilder { fn add_border(&mut self, sort_key: &DisplayItemKey, rect: &Rect, - clip: &Rect, - clip_region: &ClipRegion, + clip: &CombinedClipRegion, info: &BorderDisplayItem, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers) { @@ -2629,7 +2593,6 @@ impl DrawCommandBuilder { &Rect::new(Point2D::new(tl_outer.x, tl_inner.y), Size2D::new(left.width, bl_inner.y - tl_inner.y)), clip, - clip_region, BorderEdgeDirection::Vertical, &left_color, info.left.style, @@ -2641,7 +2604,6 @@ impl DrawCommandBuilder { Size2D::new(tr_inner.x - tl_inner.x, tr_outer.y + top.width - tl_outer.y)), clip, - clip_region, BorderEdgeDirection::Horizontal, &top_color, info.top.style, @@ -2652,7 +2614,6 @@ impl DrawCommandBuilder { &Rect::new(Point2D::new(br_outer.x - right.width, tr_inner.y), Size2D::new(right.width, br_inner.y - tr_inner.y)), clip, - clip_region, BorderEdgeDirection::Vertical, &right_color, info.right.style, @@ -2664,7 +2625,6 @@ impl DrawCommandBuilder { Size2D::new(br_inner.x - bl_inner.x, br_outer.y - bl_outer.y + bottom.width)), clip, - clip_region, BorderEdgeDirection::Horizontal, &bottom_color, info.bottom.style, @@ -2682,6 +2642,7 @@ impl DrawCommandBuilder { &radius.top_left, &info.top_left_inner_radius(), resource_cache, + clip_buffers, BasicRotationAngle::Upright); self.add_border_corner(sort_key, @@ -2694,6 +2655,7 @@ impl DrawCommandBuilder { &radius.top_right, &info.top_right_inner_radius(), resource_cache, + clip_buffers, BasicRotationAngle::Clockwise90); self.add_border_corner(sort_key, @@ -2706,6 +2668,7 @@ impl DrawCommandBuilder { &radius.bottom_right, &info.bottom_right_inner_radius(), resource_cache, + clip_buffers, BasicRotationAngle::Clockwise180); self.add_border_corner(sort_key, @@ -2718,6 +2681,7 @@ impl DrawCommandBuilder { &radius.bottom_left, &info.bottom_left_inner_radius(), resource_cache, + clip_buffers, BasicRotationAngle::Clockwise270); } @@ -2726,83 +2690,78 @@ impl DrawCommandBuilder { sort_key: &DisplayItemKey, top_left: &Point2D, bottom_right: &Point2D, - box_bounds: &Rect, color: &ColorF, blur_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, + clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, rotation_angle: BasicRotationAngle) { - let (inverted, clip_rect) = match clip_mode { - BoxShadowClipMode::Outset => (false, *box_bounds), - BoxShadowClipMode::Inset => (true, *box_bounds), - BoxShadowClipMode::None => (false, MAX_RECT), + let inverted = match clip_mode { + BoxShadowClipMode::Outset | BoxShadowClipMode::None => false, + BoxShadowClipMode::Inset => true, }; - let mask_image = match BoxShadowRasterOp::create_corner(blur_radius, - border_radius, - inverted) { + let color_image = match BoxShadowRasterOp::create_corner(blur_radius, + border_radius, + inverted) { Some(raster_item) => { let raster_item = RasterItem::BoxShadow(raster_item); resource_cache.get_raster(&raster_item) } - None => resource_cache.get_dummy_mask_image(), + None => resource_cache.get_dummy_color_image(), }; - self.add_masked_rectangle(sort_key, - top_left, - bottom_right, - &clip_rect, - clip_mode, - color, - color, - &mask_image, - resource_cache, - clip_buffers, - rotation_angle) + self.add_color_image_rectangle(sort_key, + top_left, + bottom_right, + clip, + color, + color, + &color_image, + resource_cache, + clip_buffers, + rotation_angle) } fn add_box_shadow_edge(&mut self, sort_key: &DisplayItemKey, top_left: &Point2D, bottom_right: &Point2D, - box_bounds: &Rect, color: &ColorF, blur_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, - _: &ClipRegion, + clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, rotation_angle: BasicRotationAngle) { - let (inverted, clip_rect) = match clip_mode { - BoxShadowClipMode::Outset => (false, *box_bounds), - BoxShadowClipMode::Inset => (true, *box_bounds), - BoxShadowClipMode::None => (false, MAX_RECT), + let inverted = match clip_mode { + BoxShadowClipMode::Outset | BoxShadowClipMode::None => false, + BoxShadowClipMode::Inset => true, }; - let mask_image = match BoxShadowRasterOp::create_edge(blur_radius, - border_radius, - inverted) { + let color_image = match BoxShadowRasterOp::create_edge(blur_radius, + border_radius, + inverted) { Some(raster_item) => { let raster_item = RasterItem::BoxShadow(raster_item); resource_cache.get_raster(&raster_item) } - None => resource_cache.get_dummy_mask_image(), + None => resource_cache.get_dummy_color_image(), }; - self.add_masked_rectangle(sort_key, - top_left, - bottom_right, - &clip_rect, - clip_mode, - color, - color, - &mask_image, - resource_cache, - clip_buffers, - rotation_angle) + self.add_color_image_rectangle(sort_key, + top_left, + bottom_right, + clip, + color, + color, + &color_image, + resource_cache, + clip_buffers, + rotation_angle) } } @@ -2820,22 +2779,7 @@ impl BuildRequiredResources for AABBTreeNode { // Handle border radius for complex clipping regions. for complex_clip_region in display_item.clip.complex.iter() { - resource_list.add_radius_raster(&complex_clip_region.radii.top_left, - &Size2D::new(0.0, 0.0), - false, - ImageFormat::A8); - resource_list.add_radius_raster(&complex_clip_region.radii.top_right, - &Size2D::new(0.0, 0.0), - false, - ImageFormat::A8); - resource_list.add_radius_raster(&complex_clip_region.radii.bottom_left, - &Size2D::new(0.0, 0.0), - false, - ImageFormat::A8); - resource_list.add_radius_raster(&complex_clip_region.radii.bottom_right, - &Size2D::new(0.0, 0.0), - false, - ImageFormat::A8); + resource_list.add_radius_raster_for_border_radii(&complex_clip_region.radii); } match display_item.item { @@ -2856,6 +2800,8 @@ impl BuildRequiredResources for AABBTreeNode { SpecificDisplayItem::Composite(..) => {} SpecificDisplayItem::Clear(..) => {} SpecificDisplayItem::BoxShadow(ref info) => { + resource_list.add_radius_raster_for_border_radii( + &BorderRadius::uniform(info.border_radius)); resource_list.add_box_shadow_corner(info.blur_radius, info.border_radius, false); @@ -3027,7 +2973,10 @@ impl NodeCompiler for AABBTreeNode { node_scroll_layer_id == draw_context.scroll_layer_id { let clip_rect = display_item.clip.main.intersection(&draw_context.overflow); - if let Some(clip_rect) = clip_rect { + if let Some(ref clip_rect) = clip_rect { + let mut clip = CombinedClipRegion::from_clip_in_rect_and_stack( + clip_rect, + &display_item.clip.complex[..]); let builder = match draw_cmd_builders.entry(draw_context.render_target_index) { Vacant(entry) => { @@ -3042,8 +2991,7 @@ impl NodeCompiler for AABBTreeNode { SpecificDisplayItem::Image(ref info) => { builder.add_image(&key, &display_item.rect, - &clip_rect, - &display_item.clip, + &clip, &info.stretch_size, info.image_key, resource_cache, @@ -3063,18 +3011,16 @@ impl NodeCompiler for AABBTreeNode { SpecificDisplayItem::Rectangle(ref info) => { builder.add_color_rectangle(&key, &display_item.rect, - &clip_rect, - BoxShadowClipMode::Inset, - &display_item.clip, + &clip, resource_cache, &mut clip_buffers, &info.color); } SpecificDisplayItem::Iframe(..) => {} SpecificDisplayItem::Gradient(ref info) => { + clip.clip_in_rect(&display_item.rect); builder.add_gradient(&key, - &display_item.rect, - &display_item.clip, + &clip, &info.start_point, &info.end_point, &info.stops, @@ -3084,8 +3030,7 @@ impl NodeCompiler for AABBTreeNode { SpecificDisplayItem::BoxShadow(ref info) => { builder.add_box_shadow(&key, &info.box_bounds, - &clip_rect, - &display_item.clip, + &clip, &info.offset, &info.color, info.blur_radius, @@ -3098,8 +3043,7 @@ impl NodeCompiler for AABBTreeNode { SpecificDisplayItem::Border(ref info) => { builder.add_border(&key, &display_item.rect, - &clip_rect, - &display_item.clip, + &clip, info, resource_cache, &mut clip_buffers); diff --git a/src/resource_list.rs b/src/resource_list.rs index 30f31e2db7..306c27b7f7 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -6,7 +6,7 @@ use internal_types::{Glyph, GlyphKey, RasterItem, TiledImageKey}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_state::DefaultState; -use types::{FontKey, ImageFormat, ImageKey}; +use types::{BorderRadius, FontKey, ImageFormat, ImageKey}; type RequiredImageSet = HashSet>; type RequiredGlyphMap = HashMap, DefaultState>; @@ -75,6 +75,14 @@ impl ResourceList { } } + pub fn add_radius_raster_for_border_radii(&mut self, radii: &BorderRadius) { + let zero_size = Size2D::new(0.0, 0.0); + self.add_radius_raster(&radii.top_left, &zero_size, false, ImageFormat::A8); + self.add_radius_raster(&radii.top_right, &zero_size, false, ImageFormat::A8); + self.add_radius_raster(&radii.bottom_left, &zero_size, false, ImageFormat::A8); + self.add_radius_raster(&radii.bottom_right, &zero_size, false, ImageFormat::A8); + } + pub fn add_box_shadow_corner(&mut self, blur_radius: f32, border_radius: f32, inverted: bool) { if let Some(raster_item) = BoxShadowRasterOp::create_corner(blur_radius, border_radius, diff --git a/src/texture_cache.rs b/src/texture_cache.rs index 72c97f17ff..f304c317d2 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -501,7 +501,7 @@ impl TextureCache { 0, op.raster_size.to_nearest_px() as u32, op.raster_size.to_nearest_px() as u32, - ImageFormat::A8, + ImageFormat::RGBA8, false); // TODO(pcwalton): Handle large box shadows not fitting in texture cache page. diff --git a/src/types.rs b/src/types.rs index 3415276647..2c08ca7fb1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -131,6 +131,26 @@ pub struct BorderRadius { pub bottom_right: Size2D, } +impl BorderRadius { + pub fn zero() -> BorderRadius { + BorderRadius { + top_left: Size2D::new(0.0, 0.0), + top_right: Size2D::new(0.0, 0.0), + bottom_left: Size2D::new(0.0, 0.0), + bottom_right: Size2D::new(0.0, 0.0), + } + } + + pub fn uniform(radius: f32) -> BorderRadius { + BorderRadius { + top_left: Size2D::new(radius, radius), + top_right: Size2D::new(radius, radius), + bottom_left: Size2D::new(radius, radius), + bottom_right: Size2D::new(radius, radius), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub enum BorderStyle { None, @@ -615,7 +635,7 @@ impl ClipRegion { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct ComplexClipRegion { /// The boundaries of the rectangle. pub rect: Rect, @@ -630,6 +650,13 @@ impl ComplexClipRegion { radii: radii, } } + + pub fn from_rect(rect: &Rect) -> ComplexClipRegion { + ComplexClipRegion { + rect: *rect, + radii: BorderRadius::zero(), + } + } } #[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug)]