diff --git a/res/es2_common.fs.glsl b/res/es2_common.fs.glsl index 2ceeeb6983..09a5cf5a2f 100644 --- a/res/es2_common.fs.glsl +++ b/res/es2_common.fs.glsl @@ -21,6 +21,8 @@ varying vec2 vDestTextureSize; varying vec2 vSourceTextureSize; varying float vBlurRadius; varying vec4 vTileParams; +varying vec4 vClipInRect; +varying vec4 vClipOutRect; vec4 Texture(sampler2D sampler, vec2 texCoord) { return texture2D(sampler, texCoord); diff --git a/res/es2_common.vs.glsl b/res/es2_common.vs.glsl index 3cf624a9a7..8f98b5076a 100644 --- a/res/es2_common.vs.glsl +++ b/res/es2_common.vs.glsl @@ -4,6 +4,7 @@ uniform mat4 uTransform; uniform vec4 uOffsets[32]; +uniform vec4 uClipRects[64]; uniform mat4 uMatrixPalette[32]; uniform vec2 uDirection; uniform vec4 uBlendParams; @@ -32,3 +33,5 @@ varying vec2 vDestTextureSize; varying vec2 vSourceTextureSize; varying float vBlurRadius; varying vec4 vTileParams; +varying vec4 vClipInRect; +varying vec4 vClipOutRect; diff --git a/res/gl3_common.fs.glsl b/res/gl3_common.fs.glsl index 992583152a..1a2d0acf9e 100644 --- a/res/gl3_common.fs.glsl +++ b/res/gl3_common.fs.glsl @@ -19,6 +19,8 @@ in vec2 vDestTextureSize; in vec2 vSourceTextureSize; in float vBlurRadius; in vec4 vTileParams; +in vec4 vClipInRect; +in vec4 vClipOutRect; out vec4 oFragColor; diff --git a/res/gl3_common.vs.glsl b/res/gl3_common.vs.glsl index 9a7bfad3cd..62271e6101 100644 --- a/res/gl3_common.vs.glsl +++ b/res/gl3_common.vs.glsl @@ -4,6 +4,7 @@ uniform mat4 uTransform; uniform vec4 uOffsets[32]; +uniform vec4 uClipRects[64]; uniform mat4 uMatrixPalette[32]; uniform vec2 uDirection; uniform vec4 uBlendParams; @@ -32,3 +33,5 @@ out vec2 vDestTextureSize; out vec2 vSourceTextureSize; out float vBlurRadius; out vec4 vTileParams; +out vec4 vClipInRect; +out vec4 vClipOutRect; diff --git a/res/quad.fs.glsl b/res/quad.fs.glsl index fd9a81610b..c2ab664b82 100644 --- a/res/quad.fs.glsl +++ b/res/quad.fs.glsl @@ -1,6 +1,24 @@ +// GLSL point in rect test. +// See: https://stackoverflow.com/questions/12751080/glsl-point-inside-box-test +bool PointInRect(vec2 p, vec2 p0, vec2 p1) +{ + vec2 s = step(p0, p) - step(p1, p); + return s.x * s.y != 0.0; +} + void main(void) { - // Apply image tiling parameters (offset and scale) to color UVs. + // Clip in rect + if (!PointInRect(vPosition, vClipInRect.xy, vClipInRect.zw)) { + discard; + } + + // Clip out rect + if (PointInRect(vPosition, vClipOutRect.xy, vClipOutRect.zw)) { + discard; + } + + // Apply image tiling parameters (offset and scale) to color UVs. vec2 colorTexCoord = vTileParams.xy + fract(vColorTexCoord.xy) * vTileParams.zw; vec2 maskTexCoord = vMaskTexCoord.xy; @@ -24,4 +42,3 @@ void main(void) // Write the final fragment color. SetFragColor(diffuse * vec4(vColor.rgb, vColor.a * alpha)); } - diff --git a/res/quad.vs.glsl b/res/quad.vs.glsl index 8fb4222939..740a97492e 100644 --- a/res/quad.vs.glsl +++ b/res/quad.vs.glsl @@ -34,6 +34,11 @@ void main(void) mat4 matrix = uMatrixPalette[int(aMisc.x)]; vec4 localPos = vec4(aPosition.xy, 0.0, 1.0); + + vClipInRect = uClipRects[int(aMisc.y)]; + vClipOutRect = uClipRects[int(aMisc.z)]; + vPosition = localPos.xy; + localPos.xy += offsetParams.xy; localPos.xy = SnapToPixels(localPos.xy); diff --git a/src/batch.rs b/src/batch.rs index cc909cbeed..4f15e88c01 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -1,12 +1,16 @@ use device::{ProgramId, TextureId}; -use internal_types::{AxisDirection, PackedVertex, PackedVertexForTextureCacheUpdate, Primitive}; +use euclid::{Point2D, Rect, Size2D}; +use internal_types::{MAX_RECT, AxisDirection, PackedVertex, PackedVertexForTextureCacheUpdate, Primitive}; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; use std::u16; +use webrender_traits::{ComplexClipRegion}; pub const MAX_MATRICES_PER_BATCH: usize = 32; +pub const MAX_CLIP_RECTS_PER_BATCH: usize = 64; pub const MAX_TILE_PARAMS_PER_BATCH: usize = 64; // TODO(gw): Constrain to max FS uniform vectors... pub const INVALID_TILE_PARAM: u8 = 0; +pub const INVALID_CLIP_RECT_PARAM: usize = 0; static ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; @@ -77,6 +81,7 @@ pub struct Batch { pub first_vertex: u32, pub index_count: u16, pub tile_params: Vec, + pub clip_rects: Vec>, } impl Batch { @@ -91,39 +96,116 @@ impl Batch { } ]; + let default_clip_rects = vec![ + Rect::new(Point2D::new(0.0, 0.0), Size2D::new(0.0, 0.0)), + ]; + Batch { color_texture_id: color_texture_id, mask_texture_id: mask_texture_id, first_vertex: first_vertex, index_count: 0, tile_params: default_tile_params, + clip_rects: default_clip_rects, } } + // TODO: This is quite inefficient - perhaps have a hashmap in addition to the vec... + fn clip_rect_index(&self, clip_rect: &Rect) -> Option { + self.clip_rects.iter().rposition(|existing_rect| { + existing_rect.origin.x == clip_rect.origin.x && + existing_rect.origin.y == clip_rect.origin.y && + existing_rect.size.width == clip_rect.size.width && + existing_rect.size.height == clip_rect.size.height + }) + } + pub fn can_add_to_batch(&self, color_texture_id: TextureId, mask_texture_id: TextureId, index_count: u16, - needs_tile_params: bool) -> bool { + needs_tile_params: bool, + clip_in_rect: &Rect, + clip_out_rect: &Option>) -> bool { let color_texture_ok = color_texture_id == self.color_texture_id; let mask_texture_ok = mask_texture_id == self.mask_texture_id; let index_count_ok = (self.index_count as u32 + index_count as u32) < u16::MAX as u32; let tile_params_ok = !needs_tile_params || self.tile_params.len() < MAX_TILE_PARAMS_PER_BATCH; - color_texture_ok && mask_texture_ok && index_count_ok && tile_params_ok + let used_clip_count = self.clip_rects.len(); + + let clip_rects_ok = if used_clip_count + 2 < MAX_CLIP_RECTS_PER_BATCH { + true + } else { + let mut new_clip_count = 0; + + if self.clip_rect_index(clip_in_rect).is_none() { + new_clip_count += 1; + } + + if let &Some(ref clip_out_rect) = clip_out_rect { + if self.clip_rect_index(clip_out_rect).is_none() { + new_clip_count += 1; + } + } + + used_clip_count + new_clip_count < MAX_CLIP_RECTS_PER_BATCH + }; + + color_texture_ok && + mask_texture_ok && + index_count_ok && + tile_params_ok && + clip_rects_ok } - pub fn add_draw_item(&mut self, index_count: u16, tile_params: Option) -> u8 { - //println!("index_count before={} after={}", index_count, self.index_count + index_count); + pub fn add_draw_item(&mut self, + index_count: u16, + tile_params: Option, + clip_in_rect: &Rect, + clip_out_rect: &Option>) -> (u8, u8, u8) { self.index_count += index_count; - tile_params.map_or(INVALID_TILE_PARAM, |tile_params| { + let tile_params_index = tile_params.map_or(INVALID_TILE_PARAM, |tile_params| { let index = self.tile_params.len(); debug_assert!(index < MAX_TILE_PARAMS_PER_BATCH); self.tile_params.push(tile_params); index as u8 - }) + }); + + let clip_in_rect_index = match self.clip_rect_index(clip_in_rect) { + Some(clip_in_rect_index) => { + clip_in_rect_index + } + None => { + let new_index = self.clip_rects.len(); + debug_assert!(new_index < MAX_CLIP_RECTS_PER_BATCH); + self.clip_rects.push(*clip_in_rect); + new_index + } + } as u8; + + let clip_out_rect_index = match clip_out_rect { + &Some(ref clip_out_rect) => { + match self.clip_rect_index(clip_out_rect) { + Some(clip_out_rect_index) => { + clip_out_rect_index + } + None => { + let new_index = self.clip_rects.len(); + debug_assert!(new_index < MAX_CLIP_RECTS_PER_BATCH); + self.clip_rects.push(*clip_out_rect); + new_index + } + } + } + &None => { + INVALID_CLIP_RECT_PARAM + } + } as u8; + + (tile_params_index, clip_in_rect_index, clip_out_rect_index) } } @@ -131,6 +213,14 @@ pub struct BatchBuilder<'a> { vertex_buffer: &'a mut VertexBuffer, batches: Vec, current_matrix_index: u8, + + clip_in_rect_stack: Vec>, + cached_clip_in_rect: Option>, + + clip_out_rect: Option>, + + // TODO(gw): Support nested complex clip regions! + pub complex_clip: Option, } impl<'a> BatchBuilder<'a> { @@ -139,6 +229,10 @@ impl<'a> BatchBuilder<'a> { vertex_buffer: vertex_buffer, batches: Vec::new(), current_matrix_index: 0, + clip_in_rect_stack: Vec::new(), + cached_clip_in_rect: Some(MAX_RECT), + clip_out_rect: None, + complex_clip: None, } } @@ -151,83 +245,127 @@ impl<'a> BatchBuilder<'a> { self.current_matrix_index += 1; } + // TODO(gw): This is really inefficient to call this every push/pop... + fn update_clip_in_rect(&mut self) { + self.cached_clip_in_rect = Some(MAX_RECT); + + for rect in &self.clip_in_rect_stack { + self.cached_clip_in_rect = self.cached_clip_in_rect.unwrap().intersection(rect); + if self.cached_clip_in_rect.is_none() { + return; + } + } + } + + pub fn push_clip_in_rect(&mut self, rect: &Rect) { + self.clip_in_rect_stack.push(*rect); + self.update_clip_in_rect(); + } + + pub fn pop_clip_in_rect(&mut self) { + self.clip_in_rect_stack.pop(); + self.update_clip_in_rect(); + } + + pub fn set_clip_out_rect(&mut self, rect: Option>) -> Option> { + let old_rect = self.clip_out_rect.take(); + self.clip_out_rect = rect; + old_rect + } + + pub fn push_complex_clip(&mut self, clip: &Vec) { + // TODO(gw): Handle nested complex clips! + debug_assert!(clip.len() == 0 || clip.len() == 1); + if clip.len() == 1 { + self.complex_clip = Some(clip[0]); + } else { + self.complex_clip = None; + } + } + + pub fn pop_complex_clip(&mut self) { + self.complex_clip = None; + } + pub fn add_draw_item(&mut self, color_texture_id: TextureId, mask_texture_id: TextureId, primitive: Primitive, vertices: &mut [PackedVertex], - tile_params: Option) { - let index_count = match primitive { - Primitive::Rectangles | Primitive::Glyphs => { - (vertices.len() / 4 * 6) as u16 - } - Primitive::Triangles => vertices.len() as u16, - Primitive::TriangleFan => ((vertices.len() - 2) * 3) as u16, - }; - - let need_new_batch = match self.batches.last_mut() { - Some(batch) => { - !batch.can_add_to_batch(color_texture_id, - mask_texture_id, - index_count, - tile_params.is_some()) - } - None => { - true - } - }; + tile_params: Option,) { + if let Some(ref clip_in_rect) = self.cached_clip_in_rect { + let index_count = match primitive { + Primitive::Rectangles => { + (vertices.len() / 4 * 6) as u16 + } + Primitive::Triangles => vertices.len() as u16, + }; + + let need_new_batch = match self.batches.last_mut() { + Some(batch) => { + !batch.can_add_to_batch(color_texture_id, + mask_texture_id, + index_count, + tile_params.is_some(), + clip_in_rect, + &self.clip_out_rect) + } + None => { + true + } + }; - let index_offset = self.vertex_buffer.vertices.len(); + let index_offset = self.vertex_buffer.vertices.len(); - if need_new_batch { - self.batches.push(Batch::new(color_texture_id, - mask_texture_id, - self.vertex_buffer.indices.len() as u32)); - } + if need_new_batch { + self.batches.push(Batch::new(color_texture_id, + mask_texture_id, + self.vertex_buffer.indices.len() as u32)); + } - match primitive { - Primitive::Rectangles | Primitive::Glyphs => { - for i in (0..vertices.len()).step_by(4) { - let index_base = (index_offset + i) as u16; - debug_assert!(index_base as usize == index_offset + i); - self.vertex_buffer.indices.push(index_base + 0); - self.vertex_buffer.indices.push(index_base + 1); - self.vertex_buffer.indices.push(index_base + 2); - self.vertex_buffer.indices.push(index_base + 2); - self.vertex_buffer.indices.push(index_base + 3); - self.vertex_buffer.indices.push(index_base + 1); + match primitive { + Primitive::Rectangles => { + for i in (0..vertices.len()).step_by(4) { + let index_base = (index_offset + i) as u16; + debug_assert!(index_base as usize == index_offset + i); + self.vertex_buffer.indices.push(index_base + 0); + self.vertex_buffer.indices.push(index_base + 1); + self.vertex_buffer.indices.push(index_base + 2); + self.vertex_buffer.indices.push(index_base + 2); + self.vertex_buffer.indices.push(index_base + 3); + self.vertex_buffer.indices.push(index_base + 1); + } } - } - Primitive::Triangles => { - for i in (0..vertices.len()).step_by(3) { - let index_base = (index_offset + i) as u16; - debug_assert!(index_base as usize == index_offset + i); - self.vertex_buffer.indices.push(index_base + 0); - self.vertex_buffer.indices.push(index_base + 1); - self.vertex_buffer.indices.push(index_base + 2); + Primitive::Triangles => { + for i in (0..vertices.len()).step_by(3) { + let index_base = (index_offset + i) as u16; + debug_assert!(index_base as usize == index_offset + i); + self.vertex_buffer.indices.push(index_base + 0); + self.vertex_buffer.indices.push(index_base + 1); + self.vertex_buffer.indices.push(index_base + 2); + } } } - Primitive::TriangleFan => { - for i in 1..vertices.len() - 1 { - self.vertex_buffer.indices.push(index_offset as u16); // center vertex - self.vertex_buffer.indices.push((index_offset + i + 0) as u16); - self.vertex_buffer.indices.push((index_offset + i + 1) as u16); - } + + let (tile_params_index, + clip_in_rect_index, + clip_out_rect_index) = self.batches.last_mut().unwrap().add_draw_item(index_count, + tile_params, + clip_in_rect, + &self.clip_out_rect); + + for vertex in vertices.iter_mut() { + vertex.matrix_index = self.current_matrix_index; + vertex.tile_params_index = tile_params_index; + vertex.clip_in_rect_index = clip_in_rect_index; + vertex.clip_out_rect_index = clip_out_rect_index; } - } - let tile_params_index = self.batches.last_mut().unwrap().add_draw_item(index_count, - tile_params); + self.vertex_buffer.vertices.extend_from_slice(vertices); - for vertex in vertices.iter_mut() { - vertex.matrix_index = self.current_matrix_index; - vertex.tile_params_index = tile_params_index; + // TODO(gw): Handle exceeding u16 index buffer! + debug_assert!(self.vertex_buffer.vertices.len() < 65535); } - - self.vertex_buffer.vertices.extend_from_slice(vertices); - - // TODO(gw): Handle exceeding u16 index buffer! - debug_assert!(self.vertex_buffer.vertices.len() < 65535); } } @@ -301,66 +439,3 @@ impl RasterBatch { self.vertices.extend_from_slice(vertices); } } - -/* -#[derive(Debug)] -pub struct CompositeBatch { - op: CompositionOp, - // TODO(gw): Convert these to a vertex buffer in backend thread... - rects: Vec>, -} - -impl CompositeBatch { - fn new(op: CompositionOp) -> CompositeBatch { - CompositeBatch { - op: op, - rects: Vec::new(), - } - } - - fn can_add_to_batch(&self, op: CompositionOp) -> bool { - self.op == op - } - - fn add_composite_item(&mut self, rect: Rect) { - self.rects.push(rect); - } -} - -/// A batch builder for composition operations. -#[derive(Debug)] -pub struct CompositeBatchBuilder { - batches: Vec, -} - -impl CompositeBatchBuilder { - pub fn new() -> CompositeBatchBuilder { - CompositeBatchBuilder { - batches: Vec::new(), - } - } - - pub fn finalize(self) -> Vec { - self.batches - } - - pub fn add_composite_item(&mut self, - op: CompositionOp, - rect: Rect) { - let need_new_batch = match self.batches.last_mut() { - Some(batch) => { - !batch.can_add_to_batch(op) - } - None => { - true - } - }; - - if need_new_batch { - self.batches.push(CompositeBatch::new(op)); - } - - self.batches.last_mut().unwrap().add_composite_item(rect); - } -} -*/ \ No newline at end of file diff --git a/src/batch_builder.rs b/src/batch_builder.rs index 1e2719498c..5d60c68d38 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -1,67 +1,288 @@ use app_units::Au; use batch::{BatchBuilder, TileParams}; -use clipper::{self, ClipBuffers, Polygon}; use device::TextureId; use euclid::{Rect, Point2D, Size2D}; use fnv::FnvHasher; -use internal_types::{CombinedClipRegion, RectColors, RectColorsUv, RectPolygon}; -use internal_types::{RectUv, Primitive, BorderRadiusRasterOp, RasterItem, ClipRectToRegionResult}; -use internal_types::{GlyphKey, PackedVertex, WorkVertex}; -use internal_types::{PolygonPosColorUv, AxisDirection}; +use internal_types::{RectColors, RectPolygon}; +use internal_types::{RectUv, BorderRadiusRasterOp, RasterItem}; +use internal_types::{GlyphKey, PackedVertex}; +use internal_types::{AxisDirection, Primitive}; use internal_types::{BasicRotationAngle, BoxShadowRasterOp, RectSide}; use renderer::BLUR_INFLATION_FACTOR; use resource_cache::ResourceCache; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_state::DefaultState; +use std::f32; use tessellator::{self, BorderCornerTessellation}; use texture_cache::{TextureCacheItem}; use util; +use util::RectVaryings; use webrender_traits::{ColorF, ImageFormat, BorderStyle, BoxShadowClipMode}; -use webrender_traits::{BorderRadius, BorderSide, FontKey, GlyphInstance, ImageKey}; -use webrender_traits::{BorderDisplayItem, GradientStop, ComplexClipRegion, ImageRendering}; +use webrender_traits::{BorderSide, FontKey, GlyphInstance, ImageKey}; +use webrender_traits::{BorderDisplayItem, GradientStop, ImageRendering}; use webrender_traits::{WebGLContextId}; const BORDER_DASH_SIZE: f32 = 3.0; +enum ClipState { + None, + ClipIn, + ClipOut(Option>) +} + impl<'a> BatchBuilder<'a> { - #[inline] - fn add_textured_rectangle(&mut self, - rect: &Rect, - clip: &CombinedClipRegion, - image_info: &TextureCacheItem, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, - color: &ColorF) { - self.add_axis_aligned_gradient_with_texture(rect, - clip, - image_info, - resource_cache, - clip_buffers, - &[*color, *color, *color, *color]) + + // Colors are in the order: top left, top right, bottom right, bottom left. + pub fn add_simple_rectangle(&mut self, + color_texture_id: TextureId, + pos_rect: &Rect, + uv_rect: &RectUv, + mask_texture_id: TextureId, + muv_rect: &RectUv, + colors: &[ColorF; 4], + tile_params: Option) { + if pos_rect.size.width == 0.0 || pos_rect.size.height == 0.0 { + return + } + + let mut vertices = [ + PackedVertex::from_points(&pos_rect.origin, + &colors[0], + &uv_rect.top_left, + &muv_rect.top_left), + + PackedVertex::from_points(&pos_rect.top_right(), + &colors[1], + &uv_rect.top_right, + &muv_rect.top_right), + + PackedVertex::from_points(&pos_rect.bottom_left(), + &colors[3], + &uv_rect.bottom_left, + &muv_rect.bottom_left), + + PackedVertex::from_points(&pos_rect.bottom_right(), + &colors[2], + &uv_rect.bottom_right, + &muv_rect.bottom_right), + ]; + + self.add_draw_item(color_texture_id, + mask_texture_id, + Primitive::Rectangles, + &mut vertices, + tile_params); + } + + // Colors are in the order: top left, top right, bottom right, bottom left. + pub fn add_complex_clipped_rectangle(&mut self, + color_texture_id: TextureId, + pos_rect: &Rect, + uv_rect: &RectUv, + colors: &[ColorF; 4], + tile_params: Option, + resource_cache: &ResourceCache) { + if pos_rect.size.width == 0.0 || pos_rect.size.height == 0.0 { + return + } + + match self.complex_clip { + Some(complex_clip) => { + + let tl_x0 = complex_clip.rect.origin.x; + let tl_y0 = complex_clip.rect.origin.y; + + let tr_x0 = complex_clip.rect.origin.x + complex_clip.rect.size.width - complex_clip.radii.top_right.width; + let tr_y0 = complex_clip.rect.origin.y; + + let bl_x0 = complex_clip.rect.origin.x; + let bl_y0 = complex_clip.rect.origin.y + complex_clip.rect.size.height - complex_clip.radii.bottom_left.height; + + let br_x0 = complex_clip.rect.origin.x + complex_clip.rect.size.width - complex_clip.radii.bottom_right.width; + let br_y0 = complex_clip.rect.origin.y + complex_clip.rect.size.height - complex_clip.radii.bottom_right.height; + + let tl_clip = Rect::new(Point2D::new(tl_x0, tl_y0), complex_clip.radii.top_left); + let tr_clip = Rect::new(Point2D::new(tr_x0, tr_y0), complex_clip.radii.top_right); + let bl_clip = Rect::new(Point2D::new(bl_x0, bl_y0), complex_clip.radii.bottom_left); + let br_clip = Rect::new(Point2D::new(br_x0, br_y0), complex_clip.radii.bottom_right); + + // gen all vertices for each line + let mut x_points = [ + 0.0, + complex_clip.radii.top_left.width, + complex_clip.rect.size.width - complex_clip.radii.top_right.width, + complex_clip.radii.bottom_left.width, + complex_clip.rect.size.width - complex_clip.radii.bottom_right.width, + complex_clip.rect.size.width, + ]; + + // gen all vertices for each line + let mut y_points = [ + 0.0, + complex_clip.radii.top_left.height, + complex_clip.radii.top_right.height, + complex_clip.rect.size.height - complex_clip.radii.bottom_left.height, + complex_clip.rect.size.height - complex_clip.radii.bottom_right.height, + complex_clip.rect.size.height, + ]; + + x_points.sort_by(|a, b| { + a.partial_cmp(b).unwrap() + }); + y_points.sort_by(|a, b| { + a.partial_cmp(b).unwrap() + }); + + for xi in 0..x_points.len()-1 { + for yi in 0..y_points.len()-1 { + let x0 = complex_clip.rect.origin.x + x_points[xi+0]; + let y0 = complex_clip.rect.origin.y + y_points[yi+0]; + let x1 = complex_clip.rect.origin.x + x_points[xi+1]; + let y1 = complex_clip.rect.origin.y + y_points[yi+1]; + + if x0 != x1 && y0 != y1 { + + let sub_clip_rect = Rect::new(Point2D::new(x0, y0), + Size2D::new(x1-x0, y1-y0)); + + if let Some(clipped_pos_rect) = sub_clip_rect.intersection(&pos_rect) { + // TODO(gw): There must be a more efficient way to to + // this (classifying which clip mask we need). + let (mask_info, angle) = if sub_clip_rect.intersects(&tl_clip) { + (Some(&tl_clip), BasicRotationAngle::Upright) + } else if sub_clip_rect.intersects(&tr_clip) { + (Some(&tr_clip), BasicRotationAngle::Clockwise90) + } else if sub_clip_rect.intersects(&bl_clip) { + (Some(&bl_clip), BasicRotationAngle::Clockwise270) + } else if sub_clip_rect.intersects(&br_clip) { + (Some(&br_clip), BasicRotationAngle::Clockwise180) + } else { + (None, BasicRotationAngle::Upright) + }; + + let (mask_texture_id, muv_rect) = match mask_info { + Some(clip_rect) => { + let mask_image = resource_cache.get_raster(&RasterItem::BorderRadius(BorderRadiusRasterOp { + outer_radius_x: Au::from_f32_px(clip_rect.size.width), + outer_radius_y: Au::from_f32_px(clip_rect.size.height), + inner_radius_x: Au(0), + inner_radius_y: Au(0), + inverted: false, + index: None, + image_format: ImageFormat::A8, + })); + + let mut x0_f = (x0 - clip_rect.origin.x) / clip_rect.size.width; + let mut x1_f = (x1 - clip_rect.origin.x) / clip_rect.size.width; + let mut y0_f = (y0 - clip_rect.origin.y) / clip_rect.size.height; + let mut y1_f = (y1 - clip_rect.origin.y) / clip_rect.size.height; + + match angle { + BasicRotationAngle::Upright => {} + BasicRotationAngle::Clockwise90 => { + x0_f = 1.0 - x0_f; + x1_f = 1.0 - x1_f; + } + BasicRotationAngle::Clockwise180 => { + x0_f = 1.0 - x0_f; + x1_f = 1.0 - x1_f; + y0_f = 1.0 - y0_f; + y1_f = 1.0 - y1_f; + } + BasicRotationAngle::Clockwise270 => { + y0_f = 1.0 - y0_f; + y1_f = 1.0 - y1_f; + } + } + + let mu0 = mask_image.uv_rect.top_left.x; + let mu1 = mask_image.uv_rect.top_right.x; + let mv0 = mask_image.uv_rect.top_left.y; + let mv1 = mask_image.uv_rect.bottom_left.y; + + let mu_size = mu1 - mu0; + let mv_size = mv1 - mv0; + let mu1 = mu0 + x1_f * mu_size; + let mu0 = mu0 + x0_f * mu_size; + let mv1 = mv0 + y1_f * mv_size; + let mv0 = mv0 + y0_f * mv_size; + + let muv_rect = RectUv { + top_left: Point2D::new(mu0, mv0), + top_right: Point2D::new(mu1, mv0), + bottom_left: Point2D::new(mu0, mv1), + bottom_right: Point2D::new(mu1, mv1), + }; + + (mask_image.texture_id, muv_rect) + } + None => { + let mask_image = resource_cache.get_dummy_mask_image(); + (mask_image.texture_id, mask_image.uv_rect) + } + }; + + // TODO(gw): Needless conversions here - just to make it + // easier to operate with existing bilerp code - clean this up! + let rect_colors = RectColors::from_elements(colors); + let rect_colors = util::bilerp_rect(&clipped_pos_rect, + &pos_rect, + &rect_colors); + + // TODO(gw): Need to correctly interpolate the tile params + // if present too! + + self.add_simple_rectangle(color_texture_id, + &clipped_pos_rect, + uv_rect, + mask_texture_id, + &muv_rect, + &[rect_colors.top_left, + rect_colors.top_right, + rect_colors.bottom_right, + rect_colors.bottom_left, + ], + tile_params.clone()); + } + } + } + } + } + None => { + let dummy_mask_image = resource_cache.get_dummy_mask_image(); + + self.add_simple_rectangle(color_texture_id, + pos_rect, + uv_rect, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + colors, + tile_params); + } + } } #[inline] pub fn add_color_rectangle(&mut self, rect: &Rect, - clip: &CombinedClipRegion, resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, color: &ColorF) { - self.add_axis_aligned_gradient(rect, - clip, - resource_cache, - clip_buffers, - &[*color, *color, *color, *color]) + let white_image = resource_cache.get_dummy_color_image(); + self.add_complex_clipped_rectangle(white_image.texture_id, + rect, + &white_image.uv_rect, + &[*color, *color, *color, *color], + None, + resource_cache); } pub fn add_webgl_rectangle(&mut self, rect: &Rect, - clip: &CombinedClipRegion, resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, webgl_context_id: &WebGLContextId) { let texture_id = resource_cache.get_webgl_texture(webgl_context_id); + let color = ColorF::new(1.0, 1.0, 1.0, 1.0); let uv = RectUv { top_left: Point2D::new(0.0, 1.0), @@ -70,42 +291,20 @@ impl<'a> BatchBuilder<'a> { bottom_right: Point2D::new(1.0, 0.0), }; - clipper::clip_rect_to_combined_region( - RectPolygon { - pos: *rect, - varyings: uv, - }, - &mut clip_buffers.sh_clip_buffers, - &mut clip_buffers.rect_pos_uv, - clip); - - let tile_params = TileParams { - u0: 0.0, - v0: 0.0, - u_size: 1.0, - v_size: 1.0, - }; - - 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 mut vertices = clip_region.make_packed_vertices_for_rect(mask); - - self.add_draw_item(texture_id, - mask.texture_id, - Primitive::Rectangles, - &mut vertices, - Some(tile_params.clone())); - } + self.add_complex_clipped_rectangle(texture_id, + rect, + &uv, + &[color, color, color, color], + None, + resource_cache); } pub fn add_image(&mut self, rect: &Rect, - clip: &CombinedClipRegion, stretch_size: &Size2D, image_key: ImageKey, image_rendering: ImageRendering, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers) { + resource_cache: &ResourceCache) { // Should be caught higher up debug_assert!(stretch_size.width > 0.0 && stretch_size.height > 0.0); let image_info = resource_cache.get_image(image_key, image_rendering); @@ -129,44 +328,30 @@ impl<'a> BatchBuilder<'a> { v_size: uv_size.y, }; - clipper::clip_rect_to_combined_region(RectPolygon { - pos: *rect, - varyings: 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 mut vertices = clip_region.make_packed_vertices_for_rect(mask); - - self.add_draw_item(image_info.texture_id, - mask.texture_id, - Primitive::Rectangles, - &mut vertices, - Some(tile_params.clone())); - } + let color = ColorF::new(1.0, 1.0, 1.0, 1.0); + + self.add_complex_clipped_rectangle(image_info.texture_id, + rect, + &uv, + &[color, color, color, color], + Some(tile_params), + resource_cache); } pub fn add_text(&mut self, - rect: &Rect, - clip: &CombinedClipRegion, + _rect: &Rect, font_key: FontKey, size: Au, blur_radius: Au, color: &ColorF, glyphs: &[GlyphInstance], resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, device_pixel_ratio: f32) { let dummy_mask_image = resource_cache.get_dummy_mask_image(); // Logic below to pick the primary render item depends on len > 0! assert!(glyphs.len() > 0); - let need_text_clip = !clip.clip_in_rect.contains(&rect.origin) || - !clip.clip_in_rect.contains(&rect.bottom_right()); - let mut glyph_key = GlyphKey::new(font_key, size, blur_radius, glyphs[0].index); let blur_offset = blur_radius.to_f32_px() * (BLUR_INFLATION_FACTOR as f32) / 2.0; @@ -200,19 +385,7 @@ impl<'a> BatchBuilder<'a> { } let mut vertex_buffer = Vec::new(); - for (texture_id, mut rect_buffer) in text_batches { - let rect_buffer = if need_text_clip { - let mut clipped_rects = Vec::new(); - for rect in rect_buffer.drain(..) { - rect.clip_to_rect(&mut clip_buffers.sh_clip_buffers, - &clip.clip_in_rect, - &mut clipped_rects); - } - clipped_rects - } else { - rect_buffer - }; - + for (texture_id, rect_buffer) in text_batches { vertex_buffer.clear(); for rect in rect_buffer { @@ -249,72 +422,19 @@ impl<'a> BatchBuilder<'a> { self.add_draw_item(texture_id, dummy_mask_image.texture_id, - Primitive::Glyphs, - &mut vertex_buffer, - None); - } - } - - // Colors are in the order: top left, top right, bottom right, bottom left. - #[inline] - fn add_axis_aligned_gradient(&mut self, - rect: &Rect, - clip: &CombinedClipRegion, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, - colors: &[ColorF; 4]) { - let white_image = resource_cache.get_dummy_color_image(); - self.add_axis_aligned_gradient_with_texture(rect, - clip, - white_image, - resource_cache, - clip_buffers, - colors); - } - - // Colors are in the order: top left, top right, bottom right, bottom left. - fn add_axis_aligned_gradient_with_texture(&mut self, - rect: &Rect, - clip: &CombinedClipRegion, - image_info: &TextureCacheItem, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, - colors: &[ColorF; 4]) { - if rect.size.width == 0.0 || rect.size.height == 0.0 { - return - } - - clipper::clip_rect_to_combined_region( - RectPolygon { - pos: *rect, - varyings: RectColorsUv { - colors: RectColors::new(colors), - uv: image_info.uv_rect, - }, - }, - &mut clip_buffers.sh_clip_buffers, - &mut clip_buffers.rect_pos_colors_uv, - clip); - for clip_region in clip_buffers.rect_pos_colors_uv - .clip_rect_to_region_result_output - .drain(..) { - let mask = mask_for_clip_region(resource_cache, &clip_region, false); - let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - self.add_draw_item(image_info.texture_id, - mask.texture_id, Primitive::Rectangles, - &mut vertices, + &mut vertex_buffer, None); } } fn add_axis_aligned_gradient_with_stops(&mut self, - clip: &CombinedClipRegion, rect: &Rect, direction: AxisDirection, stops: &[GradientStop], - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers) { + resource_cache: &ResourceCache) { + let white_image = resource_cache.get_dummy_color_image(); + for i in 0..(stops.len() - 1) { let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); let piece_rect; @@ -345,48 +465,45 @@ impl<'a> BatchBuilder<'a> { ]; } } - self.add_axis_aligned_gradient(&piece_rect, - clip, - resource_cache, - clip_buffers, - &piece_colors) + + self.add_complex_clipped_rectangle(white_image.texture_id, + &piece_rect, + &white_image.uv_rect, + &piece_colors, + None, + resource_cache); } } pub fn add_gradient(&mut self, - clip: &CombinedClipRegion, start_point: &Point2D, end_point: &Point2D, stops: &[GradientStop], - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers) { + resource_cache: &ResourceCache) { // Fast paths for axis-aligned gradients: // // FIXME(pcwalton): Determine the start and end points properly! if start_point.x == end_point.x { let rect = Rect::new(Point2D::new(-10000.0, start_point.y), Size2D::new(20000.0, end_point.y - start_point.y)); - self.add_axis_aligned_gradient_with_stops(clip, - &rect, + self.add_axis_aligned_gradient_with_stops(&rect, AxisDirection::Vertical, stops, - resource_cache, - clip_buffers); + resource_cache); return } if start_point.y == end_point.y { let rect = Rect::new(Point2D::new(start_point.x, -10000.0), Size2D::new(end_point.x - start_point.x, 20000.0)); - self.add_axis_aligned_gradient_with_stops(clip, - &rect, + self.add_axis_aligned_gradient_with_stops(&rect, AxisDirection::Horizontal, stops, - resource_cache, - clip_buffers); + resource_cache); return } let white_image = resource_cache.get_dummy_color_image(); + let dummy_mask_image = resource_cache.get_dummy_mask_image(); debug_assert!(stops.len() >= 2); @@ -429,66 +546,56 @@ impl<'a> BatchBuilder<'a> { let x3 = start_x + perp_xn * len_scale; let y3 = start_y + perp_yn * len_scale; - let gradient_polygon = PolygonPosColorUv { - vertices: vec![ - WorkVertex::new(x0, y0, color0, 0.0, 0.0), - WorkVertex::new(x1, y1, color1, 0.0, 0.0), - WorkVertex::new(x2, y2, color1, 0.0, 0.0), - WorkVertex::new(x3, y3, color0, 0.0, 0.0), - ], - }; + // TODO(gw): Non-axis-aligned gradients are still added via rotated rectangles. + // This means they can't currently be clipped by complex clip regions. + // To fix this, use a bit of trigonometry to supply the rectangles as + // axis-aligned, and then the complex clipping will just work! - { // scope for buffers - 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 mut packed_vertices = Vec::new(); - if clip_result.rect_result.vertices.len() >= 3 { - for vert in clip_result.rect_result.vertices.iter() { - packed_vertices.push(clip_result.make_packed_vertex( - &vert.position(), - &(vert.color(), vert.uv()), - &mask)); - } - } + let mut vertices = [ + PackedVertex::from_points(&Point2D::new(x0, y0), + &color0, + &white_image.uv_rect.top_left, + &dummy_mask_image.uv_rect.top_left), + + PackedVertex::from_points(&Point2D::new(x1, y1), + &color1, + &white_image.uv_rect.top_left, + &dummy_mask_image.uv_rect.top_left), + + PackedVertex::from_points(&Point2D::new(x3, y3), + &color0, + &white_image.uv_rect.top_left, + &dummy_mask_image.uv_rect.top_left), + + PackedVertex::from_points(&Point2D::new(x2, y2), + &color1, + &white_image.uv_rect.top_left, + &dummy_mask_image.uv_rect.top_left), + ]; - if packed_vertices.len() > 0 { - self.add_draw_item(white_image.texture_id, - mask.texture_id, - Primitive::TriangleFan, - &mut packed_vertices, - None); - } - } - } + self.add_draw_item(white_image.texture_id, + dummy_mask_image.texture_id, + Primitive::Rectangles, + &mut vertices, + None); } } pub fn add_box_shadow(&mut self, box_bounds: &Rect, - 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) { + resource_cache: &ResourceCache) { let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); // Fast path. if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None { self.add_color_rectangle(&rect, - clip, resource_cache, - clip_buffers, color); return; } @@ -501,29 +608,23 @@ impl<'a> BatchBuilder<'a> { spread_radius, border_radius, clip_mode, - clip, - resource_cache, - clip_buffers); + resource_cache); // Draw the sides. self.add_box_shadow_sides(box_bounds, - clip, box_offset, color, blur_radius, spread_radius, border_radius, clip_mode, - resource_cache, - clip_buffers); + resource_cache); match clip_mode { BoxShadowClipMode::None => { // Fill the center area. self.add_color_rectangle(box_bounds, - clip, resource_cache, - clip_buffers, color); } BoxShadowClipMode::Outset => { @@ -535,27 +636,26 @@ impl<'a> BatchBuilder<'a> { 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::new(*box_bounds, - BorderRadius::uniform(border_radius))); + + debug_assert!(border_radius == 0.0); // todo(gw): !!! + let old_clip_out_rect = self.set_clip_out_rect(Some(*box_bounds)); + self.add_color_rectangle(¢er_rect, - &clip, resource_cache, - clip_buffers, color); + + self.set_clip_out_rect(old_clip_out_rect); } } BoxShadowClipMode::Inset => { // Fill in the outsides. self.fill_outside_area_of_inset_box_shadow(box_bounds, - clip, box_offset, color, blur_radius, spread_radius, border_radius, - resource_cache, - clip_buffers); + resource_cache); } } } @@ -568,9 +668,7 @@ impl<'a> BatchBuilder<'a> { spread_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, - clip: &CombinedClipRegion, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers) { + resource_cache: &ResourceCache) { // Draw the corners. // // +--+------------------+--+ @@ -586,10 +684,9 @@ impl<'a> BatchBuilder<'a> { let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); - let mut clip = self.adjust_clip_for_box_shadow_clip_mode(clip, - box_bounds, - border_radius, - clip_mode); + let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, + border_radius, + clip_mode); // Prevent overlap of the box shadow corners when the size of the blur is larger than the // size of the box. @@ -606,9 +703,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &mut clip, resource_cache, - clip_buffers, BasicRotationAngle::Upright); self.add_box_shadow_corner(&Point2D::new(metrics.tr_outer.x - metrics.edge_size, metrics.tr_outer.y), @@ -621,9 +716,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &mut clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise90); self.add_box_shadow_corner(&Point2D::new(metrics.br_outer.x - metrics.edge_size, metrics.br_outer.y - metrics.edge_size), @@ -635,9 +728,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &mut clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise180); self.add_box_shadow_corner(&Point2D::new(metrics.bl_outer.x, metrics.bl_outer.y - metrics.edge_size), @@ -650,30 +741,27 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &mut clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise270); + + self.undo_clip_state(clip_state); } fn add_box_shadow_sides(&mut self, box_bounds: &Rect, - 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) { + resource_cache: &ResourceCache) { 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); + let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, + border_radius, + clip_mode); // Draw the sides. // @@ -709,9 +797,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise90); self.add_box_shadow_edge(&right_rect.origin, &right_rect.bottom_right(), @@ -720,9 +806,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise180); self.add_box_shadow_edge(&bottom_rect.origin, &bottom_rect.bottom_right(), @@ -731,9 +815,7 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &clip, resource_cache, - clip_buffers, BasicRotationAngle::Clockwise270); self.add_box_shadow_edge(&left_rect.origin, &left_rect.bottom_right(), @@ -742,29 +824,26 @@ impl<'a> BatchBuilder<'a> { blur_radius, border_radius, clip_mode, - &clip, resource_cache, - clip_buffers, BasicRotationAngle::Upright); + + self.undo_clip_state(clip_state); } fn fill_outside_area_of_inset_box_shadow(&mut self, box_bounds: &Rect, - clip: &CombinedClipRegion, box_offset: &Point2D, color: &ColorF, blur_radius: f32, spread_radius: f32, border_radius: f32, - resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers) { + resource_cache: &ResourceCache) { 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); + let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, + border_radius, + BoxShadowClipMode::Inset); // Fill in the outside area of the box. // @@ -786,71 +865,73 @@ impl<'a> BatchBuilder<'a> { self.add_color_rectangle(&Rect::new(box_bounds.origin, Size2D::new(box_bounds.size.width, metrics.tl_outer.y - box_bounds.origin.y)), - &clip, resource_cache, - clip_buffers, color); // B: self.add_color_rectangle(&Rect::new(metrics.tr_outer, Size2D::new(box_bounds.max_x() - metrics.tr_outer.x, metrics.br_outer.y - metrics.tr_outer.y)), - &clip, resource_cache, - clip_buffers, color); // C: self.add_color_rectangle(&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)), - &clip, resource_cache, - clip_buffers, color); // D: self.add_color_rectangle(&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)), - &clip, resource_cache, - clip_buffers, color); + + self.undo_clip_state(clip_state); } - fn adjust_clip_for_box_shadow_clip_mode<'b>(&mut self, - clip: &CombinedClipRegion<'b>, - box_bounds: &Rect, - border_radius: f32, - clip_mode: BoxShadowClipMode) - -> CombinedClipRegion<'b> { - let mut clip = *clip; + fn undo_clip_state(&mut self, clip_state: ClipState) { + match clip_state { + ClipState::None => {} + ClipState::ClipIn => { + self.pop_clip_in_rect(); + } + ClipState::ClipOut(old_rect) => { + self.set_clip_out_rect(old_rect); + } + } + } + + fn adjust_clip_for_box_shadow_clip_mode(&mut self, + box_bounds: &Rect, + border_radius: f32, + clip_mode: BoxShadowClipMode) -> ClipState { + //debug_assert!(border_radius == 0.0); // TODO(gw): !!! + match clip_mode { - BoxShadowClipMode::None => {} + BoxShadowClipMode::None => { + ClipState::None + } BoxShadowClipMode::Inset => { - clip.clip_in(&ComplexClipRegion { - rect: *box_bounds, - radii: BorderRadius::uniform(border_radius), - }); + self.push_clip_in_rect(box_bounds); + ClipState::ClipIn } BoxShadowClipMode::Outset => { - clip.clip_out(&ComplexClipRegion::new(*box_bounds, - BorderRadius::uniform(border_radius))); + let old_clip_out_rect = self.set_clip_out_rect(Some(*box_bounds)); + ClipState::ClipOut(old_clip_out_rect) } } - clip } #[inline] fn add_border_edge(&mut self, rect: &Rect, - clip: &CombinedClipRegion, side: RectSide, color: &ColorF, border_style: BorderStyle, - resource_cache: &ResourceCache, - clip_buffers: &mut clipper::ClipBuffers) { + resource_cache: &ResourceCache) { if color.a <= 0.0 { return } @@ -858,6 +939,9 @@ impl<'a> BatchBuilder<'a> { return } + let dummy_mask_image = resource_cache.get_dummy_mask_image(); + let colors = [*color, *color, *color, *color]; + match border_style { BorderStyle::Dashed => { let (extent, step) = match side { @@ -884,9 +968,7 @@ impl<'a> BatchBuilder<'a> { }; self.add_color_rectangle(&dash_rect, - clip, resource_cache, - clip_buffers, color); origin += step + step; @@ -925,48 +1007,48 @@ impl<'a> BatchBuilder<'a> { let color_image = resource_cache.get_raster(&raster_item); // Top left: - self.add_textured_rectangle(&Rect::new( - dot_rect.origin, - Size2D::new(dot_rect.size.width / 2.0, - dot_rect.size.height / 2.0)), - clip, - color_image, - resource_cache, - clip_buffers, - color); + self.add_simple_rectangle(color_image.texture_id, + &Rect::new(dot_rect.origin, + Size2D::new(dot_rect.size.width / 2.0, + dot_rect.size.height / 2.0)), + &color_image.uv_rect, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + &colors, + None); // Top right: - self.add_textured_rectangle(&Rect::new( - dot_rect.top_right(), - Size2D::new(-dot_rect.size.width / 2.0, - dot_rect.size.height / 2.0)), - clip, - color_image, - resource_cache, - clip_buffers, - color); + self.add_simple_rectangle(color_image.texture_id, + &Rect::new(dot_rect.top_right(), + Size2D::new(-dot_rect.size.width / 2.0, + dot_rect.size.height / 2.0)), + &color_image.uv_rect, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + &colors, + None); // Bottom right: - self.add_textured_rectangle(&Rect::new( - dot_rect.bottom_right(), - Size2D::new(-dot_rect.size.width / 2.0, - -dot_rect.size.height / 2.0)), - clip, - color_image, - resource_cache, - clip_buffers, - color); + self.add_simple_rectangle(color_image.texture_id, + &Rect::new(dot_rect.bottom_right(), + Size2D::new(-dot_rect.size.width / 2.0, + -dot_rect.size.height / 2.0)), + &color_image.uv_rect, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + &colors, + None); // Bottom left: - self.add_textured_rectangle(&Rect::new( - dot_rect.bottom_left(), - Size2D::new(dot_rect.size.width / 2.0, - -dot_rect.size.height / 2.0)), - clip, - color_image, - resource_cache, - clip_buffers, - color); + self.add_simple_rectangle(color_image.texture_id, + &Rect::new(dot_rect.bottom_left(), + Size2D::new(dot_rect.size.width / 2.0, + -dot_rect.size.height / 2.0)), + &color_image.uv_rect, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + &colors, + None); origin += step + step; } @@ -989,14 +1071,10 @@ impl<'a> BatchBuilder<'a> { } }; self.add_color_rectangle(&outer_rect, - clip, resource_cache, - clip_buffers, color); self.add_color_rectangle(&inner_rect, - clip, resource_cache, - clip_buffers, color); } BorderStyle::Groove | BorderStyle::Ridge => { @@ -1017,14 +1095,16 @@ impl<'a> BatchBuilder<'a> { } }; let (tl_color, br_color) = groove_ridge_border_colors(color, border_style); - self.add_color_rectangle(&tl_rect, clip, resource_cache, clip_buffers, &tl_color); - self.add_color_rectangle(&br_rect, clip, resource_cache, clip_buffers, &br_color); + self.add_color_rectangle(&tl_rect, + resource_cache, + &tl_color); + self.add_color_rectangle(&br_rect, + resource_cache, + &br_color); } _ => { self.add_color_rectangle(rect, - clip, resource_cache, - clip_buffers, color); } } @@ -1059,7 +1139,6 @@ impl<'a> BatchBuilder<'a> { /// ┊color0 ┊ /// fn add_border_corner(&mut self, - clip: &CombinedClipRegion, border_style: BorderStyle, corner_bounds: &Rect, radius_extent: &Point2D, @@ -1068,7 +1147,6 @@ impl<'a> BatchBuilder<'a> { outer_radius: &Size2D, inner_radius: &Size2D, resource_cache: &ResourceCache, - clip_buffers: &mut clipper::ClipBuffers, rotation_angle: BasicRotationAngle, device_pixel_ratio: f32) { if color0.a <= 0.0 && color1.a <= 0.0 { @@ -1099,42 +1177,34 @@ impl<'a> BatchBuilder<'a> { }; // Draw the corner parts: - self.add_solid_border_corner(clip, - &outer_corner_rect, + self.add_solid_border_corner(&outer_corner_rect, radius_extent, &color0_outer, &color1_outer, outer_radius, inner_radius, resource_cache, - clip_buffers, rotation_angle, device_pixel_ratio); - self.add_solid_border_corner(clip, - &inner_corner_rect, + self.add_solid_border_corner(&inner_corner_rect, radius_extent, &color0_inner, &color1_inner, outer_radius, inner_radius, resource_cache, - clip_buffers, rotation_angle, device_pixel_ratio); // Draw the solid parts: if util::rect_is_well_formed_and_nonempty(&color0_rect) { self.add_color_rectangle(&color0_rect, - clip, resource_cache, - clip_buffers, &color0_outer) } if util::rect_is_well_formed_and_nonempty(&color1_rect) { self.add_color_rectangle(&color1_rect, - clip, resource_cache, - clip_buffers, &color1_outer) } } @@ -1165,8 +1235,6 @@ impl<'a> BatchBuilder<'a> { let p1 = Point2D::new(corner_bounds.origin.x + width_1_3, corner_bounds.origin.y); let p2 = Point2D::new(corner_bounds.origin.x + width_2_3, corner_bounds.origin.y); let p3 = Point2D::new(corner_bounds.origin.x, corner_bounds.origin.y + height_1_3); - let p4 = Point2D::new(corner_bounds.origin.x + width_1_3, - corner_bounds.origin.y + height_1_3); let p5 = Point2D::new(corner_bounds.origin.x + width_2_3, corner_bounds.origin.y + height_1_3); let p6 = Point2D::new(corner_bounds.origin.x, corner_bounds.origin.y + height_2_3); @@ -1206,52 +1274,42 @@ impl<'a> BatchBuilder<'a> { } } - self.add_solid_border_corner(clip, - &outer_corner_rect, + self.add_solid_border_corner(&outer_corner_rect, radius_extent, color0, color1, outer_radius, &Size2D::new(0.0, 0.0), resource_cache, - clip_buffers, rotation_angle, device_pixel_ratio); self.add_color_rectangle(&outer_side_rect_1, - clip, resource_cache, - clip_buffers, &color0); - self.add_solid_border_corner(clip, - &inner_corner_rect, + self.add_solid_border_corner(&inner_corner_rect, radius_extent, color0, color1, &Size2D::new(0.0, 0.0), inner_radius, resource_cache, - clip_buffers, rotation_angle, device_pixel_ratio); self.add_color_rectangle(&outer_side_rect_0, - clip, resource_cache, - clip_buffers, &color1); } _ => { - self.add_solid_border_corner(clip, - corner_bounds, + self.add_solid_border_corner(corner_bounds, radius_extent, color0, color1, outer_radius, inner_radius, resource_cache, - clip_buffers, rotation_angle, device_pixel_ratio) } @@ -1259,7 +1317,6 @@ impl<'a> BatchBuilder<'a> { } fn add_solid_border_corner(&mut self, - clip: &CombinedClipRegion, corner_bounds: &Rect, radius_extent: &Point2D, color0: &ColorF, @@ -1267,7 +1324,6 @@ impl<'a> BatchBuilder<'a> { outer_radius: &Size2D, inner_radius: &Size2D, resource_cache: &ResourceCache, - clip_buffers: &mut clipper::ClipBuffers, rotation_angle: BasicRotationAngle, device_pixel_ratio: f32) { // TODO: Check for zero width/height borders! @@ -1306,12 +1362,10 @@ impl<'a> BatchBuilder<'a> { }; self.add_border_corner_piece(tessellated_rect, - clip, mask_image, color0, color1, resource_cache, - clip_buffers, rotation_angle); } @@ -1320,115 +1374,103 @@ impl<'a> BatchBuilder<'a> { pos: inner_corner_rect, varyings: RectUv::zero(), }, - clip, dummy_mask_image, color0, color1, resource_cache, - clip_buffers, rotation_angle); // Draw the two solid rects. if util::rect_is_well_formed_and_nonempty(&color0_rect) { - self.add_color_rectangle(&color0_rect, clip, resource_cache, clip_buffers, color0) + self.add_color_rectangle(&color0_rect, + resource_cache, + color0) } if util::rect_is_well_formed_and_nonempty(&color1_rect) { - self.add_color_rectangle(&color1_rect, clip, resource_cache, clip_buffers, color1) + self.add_color_rectangle(&color1_rect, + resource_cache, + color1) } } /// Draws one rectangle making up a border corner. fn add_border_corner_piece(&mut self, - tessellated_rect: RectPolygon, - clip: &CombinedClipRegion, + rect_pos_uv: RectPolygon, mask_image: &TextureCacheItem, color0: &ColorF, color1: &ColorF, resource_cache: &ResourceCache, - clip_buffers: &mut clipper::ClipBuffers, rotation_angle: BasicRotationAngle) { - if !tessellated_rect.is_well_formed_and_nonempty() { + if !rect_pos_uv.is_well_formed_and_nonempty() { return } let white_image = resource_cache.get_dummy_color_image(); - clipper::clip_rect_to_combined_region(tessellated_rect, - &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 rect_pos_uv = &clip_region.rect_result; - let v0; - let v1; - let muv0; - let muv1; - let muv2; - let muv3; - match rotation_angle { - BasicRotationAngle::Upright => { - v0 = rect_pos_uv.pos.origin; - v1 = rect_pos_uv.pos.bottom_right(); - muv0 = rect_pos_uv.varyings.top_left; - muv1 = rect_pos_uv.varyings.top_right; - muv2 = rect_pos_uv.varyings.bottom_right; - muv3 = rect_pos_uv.varyings.bottom_left; - } - BasicRotationAngle::Clockwise90 => { - v0 = rect_pos_uv.pos.top_right(); - v1 = rect_pos_uv.pos.bottom_left(); - muv0 = rect_pos_uv.varyings.top_right; - muv1 = rect_pos_uv.varyings.top_left; - muv2 = rect_pos_uv.varyings.bottom_left; - muv3 = rect_pos_uv.varyings.bottom_right; - } - BasicRotationAngle::Clockwise180 => { - v0 = rect_pos_uv.pos.bottom_right(); - v1 = rect_pos_uv.pos.origin; - muv0 = rect_pos_uv.varyings.bottom_right; - muv1 = rect_pos_uv.varyings.bottom_left; - muv2 = rect_pos_uv.varyings.top_left; - muv3 = rect_pos_uv.varyings.top_right; - } - BasicRotationAngle::Clockwise270 => { - v0 = rect_pos_uv.pos.bottom_left(); - v1 = rect_pos_uv.pos.top_right(); - muv0 = rect_pos_uv.varyings.bottom_left; - muv1 = rect_pos_uv.varyings.bottom_right; - muv2 = rect_pos_uv.varyings.top_right; - muv3 = rect_pos_uv.varyings.top_left; - } + let v0; + let v1; + let muv0; + let muv1; + let muv2; + let muv3; + match rotation_angle { + BasicRotationAngle::Upright => { + v0 = rect_pos_uv.pos.origin; + v1 = rect_pos_uv.pos.bottom_right(); + muv0 = rect_pos_uv.varyings.top_left; + muv1 = rect_pos_uv.varyings.top_right; + muv2 = rect_pos_uv.varyings.bottom_right; + muv3 = rect_pos_uv.varyings.bottom_left; + } + BasicRotationAngle::Clockwise90 => { + v0 = rect_pos_uv.pos.top_right(); + v1 = rect_pos_uv.pos.bottom_left(); + muv0 = rect_pos_uv.varyings.top_right; + muv1 = rect_pos_uv.varyings.top_left; + muv2 = rect_pos_uv.varyings.bottom_left; + muv3 = rect_pos_uv.varyings.bottom_right; + } + BasicRotationAngle::Clockwise180 => { + v0 = rect_pos_uv.pos.bottom_right(); + v1 = rect_pos_uv.pos.origin; + muv0 = rect_pos_uv.varyings.bottom_right; + muv1 = rect_pos_uv.varyings.bottom_left; + muv2 = rect_pos_uv.varyings.top_left; + muv3 = rect_pos_uv.varyings.top_right; + } + BasicRotationAngle::Clockwise270 => { + v0 = rect_pos_uv.pos.bottom_left(); + v1 = rect_pos_uv.pos.top_right(); + muv0 = rect_pos_uv.varyings.bottom_left; + muv1 = rect_pos_uv.varyings.bottom_right; + muv2 = rect_pos_uv.varyings.top_right; + muv3 = rect_pos_uv.varyings.top_left; } - - let mut vertices = [ - PackedVertex::from_components(v0.x, v0.y, color0, 0.0, 0.0, muv0.x, muv0.y), - PackedVertex::from_components(v1.x, v1.y, color0, 0.0, 0.0, muv2.x, muv2.y), - PackedVertex::from_components(v0.x, v1.y, color0, 0.0, 0.0, muv3.x, muv3.y), - PackedVertex::from_components(v0.x, v0.y, color1, 0.0, 0.0, muv0.x, muv0.y), - PackedVertex::from_components(v1.x, v0.y, color1, 0.0, 0.0, muv1.x, muv1.y), - PackedVertex::from_components(v1.x, v1.y, color1, 0.0, 0.0, muv2.x, muv2.y), - ]; - - self.add_draw_item(white_image.texture_id, - mask_image.texture_id, - Primitive::Triangles, - &mut vertices, - None); } + + let mut vertices = [ + PackedVertex::from_components(v0.x, v0.y, color0, 0.0, 0.0, muv0.x, muv0.y), + PackedVertex::from_components(v1.x, v1.y, color0, 0.0, 0.0, muv2.x, muv2.y), + PackedVertex::from_components(v0.x, v1.y, color0, 0.0, 0.0, muv3.x, muv3.y), + PackedVertex::from_components(v0.x, v0.y, color1, 0.0, 0.0, muv0.x, muv0.y), + PackedVertex::from_components(v1.x, v0.y, color1, 0.0, 0.0, muv1.x, muv1.y), + PackedVertex::from_components(v1.x, v1.y, color1, 0.0, 0.0, muv2.x, muv2.y), + ]; + + self.add_draw_item(white_image.texture_id, + mask_image.texture_id, + Primitive::Triangles, + &mut vertices, + None); } fn add_color_image_rectangle(&mut self, 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 @@ -1437,39 +1479,21 @@ impl<'a> BatchBuilder<'a> { let vertices_rect = Rect::new(*v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)); let color_uv = RectUv::from_image_and_rotation_angle(color_image, rotation_angle, false); - let colors = RectColors::new(&[*color0, *color0, *color1, *color1]); - clipper::clip_rect_to_combined_region(RectPolygon { - pos: vertices_rect, - varyings: RectColorsUv { - colors: colors, - uv: color_uv, - }, - }, - &mut clip_buffers.sh_clip_buffers, - &mut clip_buffers.rect_pos_colors_uv, - clip); - for clip_region in clip_buffers.rect_pos_colors_uv - .clip_rect_to_region_result_output - .drain(..) { - let mask = mask_for_clip_region(resource_cache, - &clip_region, - false); - let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - - self.add_draw_item(color_image.texture_id, - mask.texture_id, - Primitive::Rectangles, - &mut vertices, - None); - } + let dummy_mask_image = resource_cache.get_dummy_mask_image(); + + self.add_simple_rectangle(color_image.texture_id, + &vertices_rect, + &color_uv, + dummy_mask_image.texture_id, + &dummy_mask_image.uv_rect, + &[*color0, *color0, *color1, *color1], + None); } pub fn add_border(&mut self, rect: &Rect, - clip: &CombinedClipRegion, info: &BorderDisplayItem, resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, device_pixel_ratio: f32) { // TODO: If any border segment is alpha, place all in alpha pass. // Is it ever worth batching at a per-segment level? @@ -1504,45 +1528,36 @@ impl<'a> BatchBuilder<'a> { // Edges self.add_border_edge(&Rect::new(Point2D::new(tl_outer.x, tl_inner.y), Size2D::new(left.width, bl_inner.y - tl_inner.y)), - clip, RectSide::Left, &left_color, info.left.style, - resource_cache, - clip_buffers); + resource_cache); self.add_border_edge(&Rect::new(Point2D::new(tl_inner.x, tl_outer.y), Size2D::new(tr_inner.x - tl_inner.x, tr_outer.y + top.width - tl_outer.y)), - clip, RectSide::Top, &top_color, info.top.style, - resource_cache, - clip_buffers); + resource_cache); self.add_border_edge(&Rect::new(Point2D::new(br_outer.x - right.width, tr_inner.y), Size2D::new(right.width, br_inner.y - tr_inner.y)), - clip, RectSide::Right, &right_color, info.right.style, - resource_cache, - clip_buffers); + resource_cache); self.add_border_edge(&Rect::new(Point2D::new(bl_inner.x, bl_outer.y - bottom.width), Size2D::new(br_inner.x - bl_inner.x, br_outer.y - bl_outer.y + bottom.width)), - clip, RectSide::Bottom, &bottom_color, info.bottom.style, - resource_cache, - clip_buffers); + resource_cache); // Corners - self.add_border_corner(clip, - info.left.style, + self.add_border_corner(info.left.style, &Rect::new(tl_outer, Size2D::new(tl_inner.x - tl_outer.x, tl_inner.y - tl_outer.y)), @@ -1553,12 +1568,10 @@ impl<'a> BatchBuilder<'a> { &radius.top_left, &info.top_left_inner_radius(), resource_cache, - clip_buffers, BasicRotationAngle::Upright, device_pixel_ratio); - self.add_border_corner(clip, - info.top.style, + self.add_border_corner(info.top.style, &Rect::new(Point2D::new(tr_inner.x, tr_outer.y), Size2D::new(tr_outer.x - tr_inner.x, tr_inner.y - tr_outer.y)), @@ -1569,12 +1582,10 @@ impl<'a> BatchBuilder<'a> { &radius.top_right, &info.top_right_inner_radius(), resource_cache, - clip_buffers, BasicRotationAngle::Clockwise90, device_pixel_ratio); - self.add_border_corner(clip, - info.right.style, + self.add_border_corner(info.right.style, &Rect::new(br_inner, Size2D::new(br_outer.x - br_inner.x, br_outer.y - br_inner.y)), @@ -1585,12 +1596,10 @@ impl<'a> BatchBuilder<'a> { &radius.bottom_right, &info.bottom_right_inner_radius(), resource_cache, - clip_buffers, BasicRotationAngle::Clockwise180, device_pixel_ratio); - self.add_border_corner(clip, - info.bottom.style, + self.add_border_corner(info.bottom.style, &Rect::new(Point2D::new(bl_outer.x, bl_inner.y), Size2D::new(bl_inner.x - bl_outer.x, bl_outer.y - bl_inner.y)), @@ -1601,7 +1610,6 @@ impl<'a> BatchBuilder<'a> { &radius.bottom_left, &info.bottom_left_inner_radius(), resource_cache, - clip_buffers, BasicRotationAngle::Clockwise270, device_pixel_ratio); } @@ -1617,16 +1625,14 @@ impl<'a> BatchBuilder<'a> { blur_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, - clip: &mut CombinedClipRegion, resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, rotation_angle: BasicRotationAngle) { let corner_area_rect = Rect::new(*corner_area_top_left, Size2D::new(corner_area_bottom_right.x - corner_area_top_left.x, corner_area_bottom_right.y - corner_area_top_left.y)); - let old_clip_in_rect = clip.clip_in_rect; - clip.clip_in_rect(&corner_area_rect); + + self.push_clip_in_rect(&corner_area_rect); let inverted = match clip_mode { BoxShadowClipMode::Outset | BoxShadowClipMode::None => false, @@ -1646,15 +1652,13 @@ impl<'a> BatchBuilder<'a> { self.add_color_image_rectangle(top_left, bottom_right, - clip, color, color, &color_image, resource_cache, - clip_buffers, rotation_angle); - clip.clip_in_rect = old_clip_in_rect + self.pop_clip_in_rect(); } fn add_box_shadow_edge(&mut self, @@ -1665,9 +1669,7 @@ impl<'a> BatchBuilder<'a> { blur_radius: f32, border_radius: f32, clip_mode: BoxShadowClipMode, - clip: &CombinedClipRegion, resource_cache: &ResourceCache, - clip_buffers: &mut ClipBuffers, rotation_angle: BasicRotationAngle) { if top_left.x >= bottom_right.x || top_left.y >= bottom_right.y { return @@ -1691,12 +1693,10 @@ impl<'a> BatchBuilder<'a> { self.add_color_image_rectangle(top_left, bottom_right, - clip, color, color, &color_image, resource_cache, - clip_buffers, rotation_angle) } } @@ -1735,43 +1735,6 @@ impl BorderSideHelpers for BorderSide { } } -/// NB: Only returns non-tessellated border radius images! -fn mask_for_border_radius<'a>(resource_cache: &'a ResourceCache, - border_radius: f32, - inverted: bool) - -> &'a TextureCacheItem { - if border_radius == 0.0 { - return resource_cache.get_dummy_mask_image() - } - - let border_radius = Au::from_f32_px(border_radius); - resource_cache.get_raster(&RasterItem::BorderRadius(BorderRadiusRasterOp { - outer_radius_x: border_radius, - outer_radius_y: border_radius, - inner_radius_x: Au(0), - inner_radius_y: Au(0), - inverted: inverted, - index: None, - image_format: ImageFormat::A8, - })) -} - -fn mask_for_clip_region<'a,P>(resource_cache: &'a ResourceCache, - clip_region: &ClipRectToRegionResult

, - inverted: bool) - -> &'a TextureCacheItem { - match clip_region.mask_result { - None => { - resource_cache.get_dummy_mask_image() - } - Some(ref mask_result) => { - mask_for_border_radius(resource_cache, - mask_result.border_radius, - inverted) - } - } -} - #[derive(Debug)] struct BoxShadowMetrics { edge_size: f32, diff --git a/src/clipper.rs b/src/clipper.rs deleted file mode 100644 index 1bb2ed324d..0000000000 --- a/src/clipper.rs +++ /dev/null @@ -1,528 +0,0 @@ -use euclid::{Point2D, Rect, Size2D}; -use internal_types::{ClipRectToRegionMaskResult, ClipRectToRegionResult, CombinedClipRegion}; -use internal_types::{PolygonPosColorUv, RectColorsUv, RectPolygon, RectUv, WorkVertex}; -//use simd::f32x4; -use std::fmt::Debug; -use std::mem; -use webrender_traits::{ColorF, ComplexClipRegion}; -use util::{self, RectVaryings, VaryingElement}; - -pub static MAX_RECT: Rect = Rect { - origin: Point2D { - x: -1000.0, - y: -1000.0, - }, - size: Size2D { - width: 10000.0, - height: 10000.0, - }, -}; - -/// Computes whether the point c is inside the clipping edge ab. -/// -/// NB: Assumes clockwise winding for the clipping polygon that the edge comes from. -fn is_inside(a: &Point2D, b: &Point2D, c: &WorkVertex) -> bool { - let ba = *b - *a; - let cb = c.position() - *b; - ba.x * cb.y >= ba.y * cb.x -} - -fn intersection(a: &Point2D, b: &Point2D, p: &WorkVertex, q: &WorkVertex) -> WorkVertex { - let d1 = *b - *a; - let d2 = Point2D::new(q.x - p.x, q.y - p.y); - let dot = d1.x * d2.y - d1.y * d2.x; - if dot < 0.001 && dot > -0.001 { - return *p - } - let c = Point2D::new(p.x, p.y) - *a; - let t = (c.x * d2.y - c.y * d2.x) / dot; - let (x, y) = (a.x + t * d1.x, a.y + t * d1.y); - - let d1 = ((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y)).sqrt(); - let d2 = ((p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y)).sqrt(); - let ratio = d1 / d2; - - // de-simd'd code: - let u = p.u + ratio * (q.u - p.u); - let v = p.v + ratio * (q.v - p.v); - let r = p.r + ratio * (q.r - p.r); - let g = p.g + ratio * (q.g - p.g); - let b = p.b + ratio * (q.b - p.b); - let a = p.a + ratio * (q.a - p.a); - - let color = ColorF::new(r, g, b, a); - WorkVertex::new(x, y, &color, u, v) - - /* - let mut p_uv = f32x4::new(p.u, p.v, 0.0, 0.0); - let q_uv = f32x4::new(q.u, q.v, 0.0, 0.0); - let simd_ratio = f32x4::new(ratio, ratio, ratio, ratio); - let mut p_rgba = f32x4::new(p.r, p.g, p.b, p.a); - let q_rgba = f32x4::new(q.r, q.g, q.b, q.a); - p_uv = p_uv + simd_ratio * (q_uv - p_uv); - p_rgba = p_rgba + simd_ratio * (q_rgba - p_rgba);* - - let color = ColorF::new(p_rgba.extract(0), - p_rgba.extract(1), - p_rgba.extract(2), - p_rgba.extract(3)); - - WorkVertex::new(x, y, &color, p_uv.extract(0), p_uv.extract(1)) - */ -} - -// We reuse these buffers for clipping algorithms -pub struct TypedClipBuffers

{ - pub polygon_scratch: Vec

, - pub polygon_output: Vec

, - pub clip_rect_to_region_result_scratch: Vec>, - pub clip_rect_to_region_result_output: Vec>, -} - -impl

TypedClipBuffers

{ - pub fn new() -> TypedClipBuffers

{ - TypedClipBuffers { - polygon_scratch: Vec::new(), - polygon_output: Vec::new(), - clip_rect_to_region_result_scratch: Vec::new(), - clip_rect_to_region_result_output: Vec::new(), - } - } -} - -pub struct ClipBuffers { - pub sh_clip_buffers: ShClipBuffers, - pub rect_pos_uv: TypedClipBuffers>, - pub rect_pos_colors_uv: TypedClipBuffers>, - pub polygon_pos_color_uv: TypedClipBuffers, -} - -impl ClipBuffers { - pub fn new() -> ClipBuffers { - ClipBuffers { - sh_clip_buffers: ShClipBuffers::new(), - rect_pos_uv: TypedClipBuffers::new(), - rect_pos_colors_uv: TypedClipBuffers::new(), - polygon_pos_color_uv: TypedClipBuffers::new(), - } - } -} - -/// Clip buffers for the Sutherland-Hodgman clipping routine. -pub struct ShClipBuffers { - pub input: Vec, - pub result: Vec, -} - -impl ShClipBuffers { - pub fn new() -> ShClipBuffers { - ShClipBuffers { - input: Vec::new(), - result: Vec::new(), - } - } -} - -/// Clips the given polygon to a clip polygon. -/// -/// NB: Assumes clockwise winding for the clip polygon. -pub fn clip_polygon<'a>(buffers: &'a mut ShClipBuffers, - polygon: &[WorkVertex], - clip_polygon: &[Point2D]) - -> &'a [WorkVertex] { - let ShClipBuffers {ref mut input, ref mut result} = *buffers; - input.clear(); - result.clear(); - for vert in polygon { - result.push(vert.clone()); - } - let clip_len = clip_polygon.len(); - - for i in 0..clip_len { - input.clone_from(&result); - let input_len = input.len(); - result.clear(); - - let a = &clip_polygon[(i + clip_len-1) % clip_len]; - let b = &clip_polygon[i]; - - for j in 0..input.len() { - let p = &input[(j + input_len-1) % input_len]; - let q = &input[j]; - - let p_is_inside = is_inside(a, b, p); - - if is_inside(a, b, q) { - if !p_is_inside { - result.push(intersection(a, b, p, q)); - } - result.push(q.clone()); - } else if p_is_inside { - result.push(intersection(a, b, p, q)); - } - } - } - - result -} - -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 - } - - // 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 - } - - // 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 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))) - } - - // 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))) - } - - // 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))) - } - } - - fn size_max(size: &Size2D) -> f32 { - f32::max(size.width, size.height) - } - - fn push_results

(output: &mut Vec>, - clip_rect_results: &mut Vec

, - mask_result: Option) - where P: Polygon { - output.extend(clip_rect_results.drain(..).map(|clip_rect_result| { - ClipRectToRegionResult::new(clip_rect_result, mask_result) - })) - } -} - -/// NB: Clobbers both `polygon_scratch` and `polygon_output` in the typed clip buffers. -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) - } -} - -pub trait Polygon : Sized { - fn clip_to_rect(&self, - sh_clip_buffers: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec); - fn clip_out_rect(&self, - sh_clip_buffers: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec); - fn intersects_rect(&self, rect: &Rect) -> bool; -} - -impl RectPolygon where Varyings: RectVaryings, - Varyings::Element: VaryingElement { - fn push_clipped_rect(&self, - clipped_rect: &Rect, - output: &mut Vec>) { - if util::rect_is_empty(&clipped_rect) { - return - } - - output.push(RectPolygon { - pos: *clipped_rect, - varyings: util::bilerp_rect(clipped_rect, &self.pos, &self.varyings), - }); - } -} - -impl Polygon for RectPolygon where Varyings: RectVaryings + Clone, - Varyings::Element: VaryingElement { - fn clip_to_rect(&self, - _: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec>) { - for clipped_rect in self.pos.intersection(clip_rect).iter() { - self.push_clipped_rect(clipped_rect, output) - } - } - - fn clip_out_rect(&self, - _: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec>) { - let clip_rect = match self.pos.intersection(clip_rect) { - Some(clip_rect) => clip_rect, - None => { - output.push((*self).clone()); - return - } - }; - - self.push_clipped_rect(&Rect::new(self.pos.origin, - Size2D::new(self.pos.size.width, - clip_rect.origin.y - self.pos.origin.y)), - output); - self.push_clipped_rect(&Rect::new(Point2D::new(self.pos.origin.x, clip_rect.origin.y), - Size2D::new(clip_rect.origin.x - self.pos.origin.x, - clip_rect.size.height)), - output); - self.push_clipped_rect(&Rect::new(Point2D::new(clip_rect.max_x(), clip_rect.origin.y), - Size2D::new(self.pos.max_x() - clip_rect.max_x(), - clip_rect.size.height)), - output); - self.push_clipped_rect(&Rect::new(Point2D::new(self.pos.origin.x, clip_rect.max_y()), - Size2D::new(self.pos.size.width, - self.pos.max_y() - clip_rect.max_y())), - output); - } - - fn intersects_rect(&self, rect: &Rect) -> bool { - self.pos.intersects(rect) - } -} - -impl PolygonPosColorUv { - fn clip_to_polygon(&self, - clip_buffers: &mut ShClipBuffers, - clip_vertices: &[Point2D], - output: &mut Vec) { - let clipped_vertices = clip_polygon(clip_buffers, - &self.vertices[..], - clip_vertices).to_vec(); - output.push(PolygonPosColorUv { - vertices: clipped_vertices, - }) - } -} - -impl Polygon for PolygonPosColorUv { - fn clip_to_rect(&self, - clip_buffers: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec) { - self.clip_to_polygon(clip_buffers, - &[ - clip_rect.origin, - clip_rect.top_right(), - clip_rect.bottom_right(), - clip_rect.bottom_left(), - ], - output) - } - - fn clip_out_rect(&self, - clip_buffers: &mut ShClipBuffers, - clip_rect: &Rect, - output: &mut Vec) { - // - // +-----------------------+ - // | 8 | 9 - // | | - // | +---------+------+ - // | | 4 | 1 | 5, 10 - // | | | | - // | +---------+ | - // | 3 2 | - // | | - // +-----------------------+ - // 7 6 - // - - self.clip_to_polygon(clip_buffers, - &[ - clip_rect.top_right(), // 1 - clip_rect.bottom_right(), // 2 - clip_rect.bottom_left(), // 3 - clip_rect.origin, // 4 - Point2D::new(MAX_RECT.max_x(), clip_rect.origin.y), // 5 - MAX_RECT.bottom_right(), // 6 - MAX_RECT.bottom_left(), // 7 - MAX_RECT.origin, // 8 - MAX_RECT.top_right(), // 9 - Point2D::new(MAX_RECT.max_x(), clip_rect.origin.y), // 10 - ], - output) - } - - fn intersects_rect(&self, rect: &Rect) -> bool { - self.vertices.iter().any(|vertex| rect.contains(&Point2D::new(vertex.x, vertex.y))) - } -} diff --git a/src/frame.rs b/src/frame.rs index f6de894f20..756474ef68 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -167,6 +167,7 @@ impl RenderTarget { for batch in &batch_list.batches { batch_info.draw_calls.push(DrawCall { tile_params: batch.tile_params.clone(), // TODO(gw): Move this instead? + clip_rects: batch.clip_rects.clone(), // Ditto vertex_buffer_id: vertex_buffer_id, color_texture_id: batch.color_texture_id, mask_texture_id: batch.mask_texture_id, @@ -650,7 +651,8 @@ impl Frame { // may already be set for draw lists from other iframe(s) that weren't updated // as part of this new stacking context. let item_index = DrawListItemIndex(item_index as u32); - let rect = sc_info.world_transform.transform_rect(&item.rect); + let world_space_rect = item.rect.translate(&sc_info.world_origin); + let rect = sc_info.world_transform.transform_rect(&world_space_rect); layer.insert(&rect, *draw_list_group_id, draw_list_id, diff --git a/src/internal_types.rs b/src/internal_types.rs index dbcdf311d9..719563300b 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -9,10 +9,10 @@ use std::collections::HashMap; use std::collections::hash_state::DefaultState; use std::sync::Arc; use texture_cache::TextureCacheItem; -use util::{self, RectVaryings, VaryingElement}; +use util::{self, RectVaryings}; use webrender_traits::{FontKey, Epoch, ColorF, PipelineId}; use webrender_traits::{ImageFormat, ScrollLayerId}; -use webrender_traits::{ComplexClipRegion, MixBlendMode, NativeFontHandle, DisplayItem}; +use webrender_traits::{MixBlendMode, NativeFontHandle, DisplayItem}; const UV_FLOAT_TO_FIXED: f32 = 65535.0; const COLOR_FLOAT_TO_FIXED: f32 = 255.0; @@ -21,14 +21,14 @@ pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0; pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; pub const ORTHO_FAR_PLANE: f32 = 1000000.0; -static ZERO_RECT_F32: Rect = Rect { +pub static MAX_RECT: Rect = Rect { origin: Point2D { - x: 0.0, - y: 0.0, + x: -1000.0, + y: -1000.0, }, size: Size2D { - width: 0.0, - height: 0.0, + width: 10000.0, + height: 10000.0, }, }; @@ -137,8 +137,8 @@ pub struct PackedVertex { pub mu: u16, pub mv: u16, pub matrix_index: u8, - pub unused0: u8, - pub unused1: u8, + pub clip_in_rect_index: u8, + pub clip_out_rect_index: u8, pub tile_params_index: u8, } @@ -160,8 +160,8 @@ impl PackedVertex { mu: (mu * UV_FLOAT_TO_FIXED) as u16, mv: (mv * UV_FLOAT_TO_FIXED) as u16, matrix_index: 0, - unused0: 0, - unused1: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, tile_params_index: 0, } } @@ -183,8 +183,8 @@ impl PackedVertex { mu: mu, mv: mv, matrix_index: 0, - unused0: 0, - unused1: 0, + clip_in_rect_index: 0, + clip_out_rect_index: 0, tile_params_index: 0, } } @@ -326,6 +326,7 @@ pub struct ClearInfo { #[derive(Clone, Debug)] pub struct DrawCall { pub tile_params: Vec, + pub clip_rects: Vec>, pub vertex_buffer_id: VertexBufferId, pub color_texture_id: TextureId, pub mask_texture_id: TextureId, @@ -428,99 +429,6 @@ pub enum ResultMsg { NewFrame(RendererFrame, BackendProfileCounters), } -#[derive(Debug, Clone, Copy)] -pub struct ClipRectToRegionMaskResult { - /// The bounding box of the mask, in texture coordinates. - pub muv_rect: Rect, - - /// The bounding rect onto which the mask will be applied, in framebuffer coordinates. - pub position_rect: Rect, - - /// The border radius in question, for lookup in the texture cache. - pub border_radius: f32, -} - -impl ClipRectToRegionMaskResult { - pub fn new(muv_rect: &Rect, position_rect: &Rect, border_radius: f32) - -> ClipRectToRegionMaskResult { - ClipRectToRegionMaskResult { - muv_rect: *muv_rect, - position_rect: *position_rect, - border_radius: border_radius, - } - } -} - -#[derive(Clone, Debug)] -pub struct ClipRectToRegionResult

{ - pub rect_result: P, - pub mask_result: Option, -} - -impl

ClipRectToRegionResult

{ - pub fn new(rect_result: P, mask_result: Option) - -> ClipRectToRegionResult

{ - ClipRectToRegionResult { - rect_result: rect_result, - mask_result: mask_result, - } - } - - pub fn muv_for_position(&self, position: &Point2D, mask: &TextureCacheItem) - -> Point2D { - let mask_uv_size = Size2D::new(mask.uv_rect.bottom_right.x - mask.uv_rect.top_left.x, - mask.uv_rect.bottom_right.y - mask.uv_rect.top_left.y); - let mask_result = match self.mask_result { - None => return Point2D::new(0.0, 0.0), - Some(ref mask_result) => mask_result, - }; - - let muv_rect = - Rect::new(Point2D::new( - mask.uv_rect.top_left.x + mask_result.muv_rect.origin.x * mask_uv_size.width, - mask.uv_rect.top_left.y + mask_result.muv_rect.origin.y * mask_uv_size.height), - Size2D::new(mask_result.muv_rect.size.width * mask_uv_size.width, - mask_result.muv_rect.size.height * mask_uv_size.height)); - let position_rect = &mask_result.position_rect; - - Point2D::new(util::lerp(muv_rect.origin.x, - muv_rect.max_x(), - (position.x - position_rect.origin.x) / position_rect.size.width), - util::lerp(muv_rect.origin.y, - muv_rect.max_y(), - (position.y - position_rect.origin.y) / position_rect.size.height)) - } - - pub fn make_packed_vertex(&self, - position: &Point2D, - varying_element: &VE, - mask: &TextureCacheItem) - -> PackedVertex - where VE: VaryingElement { - varying_element.make_packed_vertex(position, &self.muv_for_position(position, mask)) - } -} - -impl ClipRectToRegionResult> - where Varyings: RectVaryings, Varyings::Element: VaryingElement { - pub fn make_packed_vertices_for_rect(&self, mask: &TextureCacheItem) -> [PackedVertex; 4] { - [ - self.make_packed_vertex(&self.rect_result.pos.origin, - &self.rect_result.varyings.top_left(), - mask), - self.make_packed_vertex(&self.rect_result.pos.top_right(), - &self.rect_result.varyings.top_right(), - mask), - self.make_packed_vertex(&self.rect_result.pos.bottom_left(), - &self.rect_result.varyings.bottom_left(), - mask), - self.make_packed_vertex(&self.rect_result.pos.bottom_right(), - &self.rect_result.varyings.bottom_right(), - mask), - ] - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum AxisDirection { Horizontal, @@ -583,8 +491,6 @@ pub struct DrawListItemIndex(pub u32); pub enum Primitive { Triangles, Rectangles, // 4 vertices per rect - TriangleFan, // simple triangle fan (typically from clipper) - Glyphs, // font glyphs (some platforms may specialize shader) } #[derive(Debug)] @@ -637,17 +543,6 @@ pub struct RectColors { pub bottom_left: ColorF, } -impl RectColors { - pub fn new(colors: &[ColorF; 4]) -> RectColors { - RectColors { - top_left: colors[0], - top_right: colors[1], - bottom_right: colors[2], - bottom_left: colors[3], - } - } -} - #[derive(Clone, Copy, Debug)] pub struct RectUv { pub top_left: Point2D, @@ -666,81 +561,69 @@ impl RectUv { } } - pub fn from_image_and_rotation_angle(image: &TextureCacheItem, - rotation_angle: BasicRotationAngle, - flip_90_degree_rotations: bool) - -> RectUv { + pub fn from_uv_rect_rotation_angle(uv_rect: &RectUv, + rotation_angle: BasicRotationAngle, + flip_90_degree_rotations: bool) -> RectUv { match (rotation_angle, flip_90_degree_rotations) { (BasicRotationAngle::Upright, _) => { RectUv { - top_left: image.uv_rect.top_left, - top_right: image.uv_rect.top_right, - bottom_right: image.uv_rect.bottom_right, - bottom_left: image.uv_rect.bottom_left, + top_left: uv_rect.top_left, + top_right: uv_rect.top_right, + bottom_right: uv_rect.bottom_right, + bottom_left: uv_rect.bottom_left, } } (BasicRotationAngle::Clockwise90, true) => { RectUv { - top_right: image.uv_rect.top_left, - top_left: image.uv_rect.top_right, - bottom_left: image.uv_rect.bottom_right, - bottom_right: image.uv_rect.bottom_left, + top_right: uv_rect.top_left, + top_left: uv_rect.top_right, + bottom_left: uv_rect.bottom_right, + bottom_right: uv_rect.bottom_left, } } (BasicRotationAngle::Clockwise90, false) => { RectUv { - top_right: image.uv_rect.top_left, - bottom_right: image.uv_rect.top_right, - bottom_left: image.uv_rect.bottom_right, - top_left: image.uv_rect.bottom_left, + top_right: uv_rect.top_left, + bottom_right: uv_rect.top_right, + bottom_left: uv_rect.bottom_right, + top_left: uv_rect.bottom_left, } } (BasicRotationAngle::Clockwise180, _) => { RectUv { - bottom_right: image.uv_rect.top_left, - bottom_left: image.uv_rect.top_right, - top_left: image.uv_rect.bottom_right, - top_right: image.uv_rect.bottom_left, + bottom_right: uv_rect.top_left, + bottom_left: uv_rect.top_right, + top_left: uv_rect.bottom_right, + top_right: uv_rect.bottom_left, } } (BasicRotationAngle::Clockwise270, true) => { RectUv { - bottom_left: image.uv_rect.top_left, - bottom_right: image.uv_rect.top_right, - top_right: image.uv_rect.bottom_right, - top_left: image.uv_rect.bottom_left, + bottom_left: uv_rect.top_left, + bottom_right: uv_rect.top_right, + top_right: uv_rect.bottom_right, + top_left: uv_rect.bottom_left, } } (BasicRotationAngle::Clockwise270, false) => { RectUv { - bottom_left: image.uv_rect.top_left, - top_left: image.uv_rect.top_right, - top_right: image.uv_rect.bottom_right, - bottom_right: image.uv_rect.bottom_left, + bottom_left: uv_rect.top_left, + top_left: uv_rect.top_right, + top_right: uv_rect.bottom_right, + bottom_right: uv_rect.bottom_left, } } } } -/* - pub fn to_rect(&self) -> Rect { - fn min(x: f32, y: f32) -> f32 { - if x < y { x } else { y } - } - fn max(x: f32, y: f32) -> f32 { - if x > y { x } else { y } - } - - let min_x = min(min(min(self.top_left.x, self.top_right.x), self.bottom_right.x), - self.bottom_left.x); - let min_y = min(min(min(self.top_left.y, self.top_right.y), self.bottom_right.y), - self.bottom_left.y); - let max_x = max(max(max(self.top_left.x, self.top_right.x), self.bottom_right.x), - self.bottom_left.x); - let max_y = max(max(max(self.top_left.y, self.top_right.y), self.bottom_right.y), - self.bottom_left.y); - Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x - min_x, max_y - min_y)) - }*/ + pub fn from_image_and_rotation_angle(image: &TextureCacheItem, + rotation_angle: BasicRotationAngle, + flip_90_degree_rotations: bool) + -> RectUv { + RectUv::from_uv_rect_rotation_angle(&image.uv_rect, + rotation_angle, + flip_90_degree_rotations) + } } #[derive(Clone, Debug)] @@ -997,44 +880,6 @@ 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 - } -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum LowLevelFilterOp { Blur(Au, AxisDirection), diff --git a/src/lib.rs b/src/lib.rs index e8246e5b61..027fea688f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ extern crate lazy_static; mod aabbtree; mod batch; mod batch_builder; -mod clipper; mod debug_font_data; mod debug_render; mod device; @@ -67,6 +66,5 @@ pub use renderer::Renderer; #[doc(hidden)] pub mod bench { // to make private modules available to the benchmarks - pub use clipper::{clip_polygon, ClipBuffers, Polygon}; pub use internal_types::WorkVertex; } diff --git a/src/node_compiler.rs b/src/node_compiler.rs index 3da92f81a5..e4c25f5cf6 100644 --- a/src/node_compiler.rs +++ b/src/node_compiler.rs @@ -1,10 +1,9 @@ use aabbtree::AABBTreeNode; use batch::{BatchBuilder, VertexBuffer}; -use clipper::{ClipBuffers}; use fnv::FnvHasher; use frame::DrawListGroup; use internal_types::{DrawListItemIndex, CompiledNode, StackingContextInfo}; -use internal_types::{CombinedClipRegion, BatchList, StackingContextIndex}; +use internal_types::{BatchList, StackingContextIndex}; use internal_types::{DrawListGroupId}; use resource_cache::ResourceCache; use std::collections::HashMap; @@ -27,7 +26,6 @@ impl NodeCompiler for AABBTreeNode { draw_list_groups: &HashMap>) { let mut compiled_node = CompiledNode::new(); let mut vertex_buffer = VertexBuffer::new(); - let mut clip_buffers = ClipBuffers::new(); for draw_list_group_segment in &self.draw_list_group_segments { let mut builder = BatchBuilder::new(&mut vertex_buffer); @@ -59,76 +57,63 @@ impl NodeCompiler for AABBTreeNode { }); if let Some(ref clip_rect) = clip_rect { - let mut clip = CombinedClipRegion::from_clip_in_rect_and_stack( - clip_rect, - &display_item.clip.complex[..]); + builder.push_clip_in_rect(clip_rect); + builder.push_complex_clip(&display_item.clip.complex); match display_item.item { SpecificDisplayItem::WebGL(ref info) => { builder.add_webgl_rectangle(&display_item.rect, - &clip, resource_cache, - &mut clip_buffers, &info.context_id); } SpecificDisplayItem::Image(ref info) => { builder.add_image(&display_item.rect, - &clip, &info.stretch_size, info.image_key, info.image_rendering, - resource_cache, - &mut clip_buffers); + resource_cache); } SpecificDisplayItem::Text(ref info) => { builder.add_text(&display_item.rect, - &clip, info.font_key, info.size, info.blur_radius, &info.color, &info.glyphs, resource_cache, - &mut clip_buffers, device_pixel_ratio); } SpecificDisplayItem::Rectangle(ref info) => { builder.add_color_rectangle(&display_item.rect, - &clip, resource_cache, - &mut clip_buffers, &info.color); } SpecificDisplayItem::Gradient(ref info) => { - clip.clip_in_rect(&display_item.rect); - builder.add_gradient(&clip, - &info.start_point, + builder.add_gradient(&info.start_point, &info.end_point, &info.stops, - resource_cache, - &mut clip_buffers); + resource_cache); } SpecificDisplayItem::BoxShadow(ref info) => { builder.add_box_shadow(&info.box_bounds, - &clip, &info.offset, &info.color, info.blur_radius, info.spread_radius, info.border_radius, info.clip_mode, - resource_cache, - &mut clip_buffers); + resource_cache); } SpecificDisplayItem::Border(ref info) => { builder.add_border(&display_item.rect, - &clip, info, resource_cache, - &mut clip_buffers, device_pixel_ratio); } } + + builder.pop_complex_clip(); + builder.pop_clip_in_rect(); } } } diff --git a/src/renderer.rs b/src/renderer.rs index 9201a2a43e..e04ec4b574 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -100,6 +100,7 @@ pub struct Renderer { u_quad_transform_array: UniformLocation, u_quad_offset_array: UniformLocation, u_tile_params: UniformLocation, + u_clip_rects: UniformLocation, u_atlas_params: UniformLocation, blit_program_id: ProgramId, @@ -157,6 +158,7 @@ impl Renderer { let u_quad_transform_array = device.get_uniform_location(quad_program_id, "uMatrixPalette"); let u_quad_offset_array = device.get_uniform_location(quad_program_id, "uOffsets"); let u_tile_params = device.get_uniform_location(quad_program_id, "uTileParams"); + let u_clip_rects = device.get_uniform_location(quad_program_id, "uClipRects"); let u_atlas_params = device.get_uniform_location(quad_program_id, "uAtlasParams"); let u_blend_params = device.get_uniform_location(blend_program_id, "uBlendParams"); @@ -248,9 +250,9 @@ impl Renderer { u_quad_transform_array: u_quad_transform_array, u_atlas_params: u_atlas_params, u_tile_params: u_tile_params, + u_clip_rects: u_clip_rects, notifier: notifier, viewport_size: Size2D::new(width, height), - //framebuffer_size: *framebuffer_size, debug: debug_renderer, backend_profile_counters: BackendProfileCounters::new(), profile_counters: RendererProfileCounters::new(), @@ -983,6 +985,20 @@ impl Renderer { &floats); } + if draw_call.clip_rects.len() > 0 { + // TODO(gw): Avoid alloc here... + let mut floats = Vec::new(); + for rect in &draw_call.clip_rects { + floats.push(rect.origin.x); + floats.push(rect.origin.y); + floats.push(rect.origin.x + rect.size.width); + floats.push(rect.origin.y + rect.size.height); + } + + self.device.set_uniform_vec4_array(self.u_clip_rects, + &floats); + } + self.device.bind_mask_texture(draw_call.mask_texture_id); self.device.bind_color_texture(draw_call.color_texture_id); diff --git a/src/util.rs b/src/util.rs index 1a69a4bccf..5d43103adb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ use euclid::{Matrix4, Point2D, Rect, Size2D}; -use internal_types::{PackedVertex, RectColors, RectColorsUv, RectUv}; +use internal_types::{RectColors, RectColorsUv, RectUv}; use std::num::Zero; use time::precise_time_ns; use webrender_traits::ColorF; @@ -156,48 +156,24 @@ impl RectVaryings for RectColorsUv { pub trait VaryingElement : Sized { fn scale(&self, factor: f32) -> Self; fn accumulate(values: &[Self; 4]) -> Self; - fn make_packed_vertex(&self, position: &Point2D, muv: &Point2D) -> PackedVertex; } -impl VaryingElement for Point2D { - fn scale(&self, factor: f32) -> Point2D { - *self * factor - } - fn accumulate(values: &[Point2D; 4]) -> Point2D { - values[0] + values[1] + values[2] + values[3] - } - fn make_packed_vertex(&self, position: &Point2D, muv: &Point2D) -> PackedVertex { - static WHITE: ColorF = ColorF { - r: 1.0, - g: 1.0, - b: 1.0, - a: 1.0, - }; - PackedVertex::from_points(position, &WHITE, self, muv) - } -} - -impl VaryingElement for (ColorF, Point2D) { - fn scale(&self, factor: f32) -> (ColorF, Point2D) { - let color = ColorF { - r: self.0.r * factor, - g: self.0.g * factor, - b: self.0.b * factor, - a: self.0.a * factor, - }; - (color, self.1 * factor) - } - fn accumulate(values: &[(ColorF, Point2D); 4]) -> (ColorF, Point2D) { - let color = ColorF { - r: values[0].0.r + values[1].0.r + values[2].0.r + values[3].0.r, - g: values[0].0.g + values[1].0.g + values[2].0.g + values[3].0.g, - b: values[0].0.b + values[1].0.b + values[2].0.b + values[3].0.b, - a: values[0].0.a + values[1].0.a + values[2].0.a + values[3].0.a, - }; - (color, values[0].1 + values[1].1 + values[2].1 + values[3].1) +impl VaryingElement for ColorF { + fn scale(&self, factor: f32) -> ColorF { + ColorF { + r: self.r * factor, + g: self.g * factor, + b: self.b * factor, + a: self.a * factor, + } } - fn make_packed_vertex(&self, position: &Point2D, muv: &Point2D) -> PackedVertex { - PackedVertex::from_points(position, &self.0, &self.1, muv) + fn accumulate(values: &[ColorF; 4]) -> ColorF { + ColorF { + r: values[0].r + values[1].r + values[2].r + values[3].r, + g: values[0].g + values[1].g + values[2].g + values[3].g, + b: values[0].b + values[1].b + values[2].b + values[3].b, + a: values[0].a + values[1].a + values[2].a + values[3].a, + } } }