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/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/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); } 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)]