From 76b32fd2de14d03d4d53b67389561e1788338c77 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Tue, 10 Apr 2018 12:07:56 +0200 Subject: [PATCH] Improve border dot handling for small radii When rendering dotted borders with small radii, put a single dot in the corner and render the edge based on that. This fixes an issue where dots smoosh into each other with small radii. The resulting rendering isn't perfectly aligned for the moment, but this can be improved as we handle more complicated situations such as combinations of borders of different widths. --- webrender/res/ps_border_edge.glsl | 44 ++++++-- webrender/src/border.rs | 103 +++++++++++++----- .../border/dotted-corner-small-radius.png | Bin 15288 -> 15393 bytes 3 files changed, 112 insertions(+), 35 deletions(-) diff --git a/webrender/res/ps_border_edge.glsl b/webrender/res/ps_border_edge.glsl index a66713548a..5154e9bd3e 100644 --- a/webrender/res/ps_border_edge.glsl +++ b/webrender/res/ps_border_edge.glsl @@ -100,7 +100,9 @@ void write_clip_params(float style, float border_width, float edge_length, float edge_offset, - float center_line) { + float center_line, + bool start_corner_has_radius, + bool end_corner_has_radius) { // x = offset // y = dash on + off length // z = dash length @@ -121,13 +123,27 @@ void write_clip_params(float style, case BORDER_STYLE_DOTTED: { float diameter = border_width; float radius = 0.5 * diameter; - float dot_count = ceil(0.5 * edge_length / diameter); - float empty_space = edge_length - dot_count * diameter; + + // If this edge connects a corner with a radius to a corner without a radius, we + // act as if we have space for one more dot. This will position the dots so that + // there is a half dot on one of the ends. + float full_edge_length = edge_length + + (float(start_corner_has_radius ^^ end_corner_has_radius) * diameter); + + float dot_count = ceil(0.5 * full_edge_length / diameter); + float empty_space = full_edge_length - (dot_count * diameter); float distance_between_centers = diameter + empty_space / dot_count; - vClipParams = vec4(edge_offset - radius, + + // If the starting corner has a radius, we want to position the half dot right + // against that edge. + float starting_offset = + edge_offset + radius + (-diameter * float(start_corner_has_radius)); + + vClipParams = vec4(starting_offset, distance_between_centers, radius, center_line); + vClipSelect = 1.0; break; } @@ -138,6 +154,10 @@ void write_clip_params(float style, } } +bool hasRadius(vec2 radius) { + return any(notEqual(radius, vec2(0.0))); +} + void main(void) { Primitive prim = load_primitive(); Border border = fetch_border(prim.specific_prim_address); @@ -166,7 +186,9 @@ void main(void) { border.widths.x, segment_rect.size.y, segment_rect.p0.y, - segment_rect.p0.x + 0.5 * segment_rect.size.x); + segment_rect.p0.x + 0.5 * segment_rect.size.x, + hasRadius(border.radii[0].xy), + hasRadius(border.radii[1].zw)); edge_mask = vec4(1.0, 0.0, 1.0, 0.0); break; } @@ -181,7 +203,9 @@ void main(void) { border.widths.y, segment_rect.size.x, segment_rect.p0.x, - segment_rect.p0.y + 0.5 * segment_rect.size.y); + segment_rect.p0.y + 0.5 * segment_rect.size.y, + hasRadius(border.radii[0].xy), + hasRadius(border.radii[0].zw)); edge_mask = vec4(0.0, 1.0, 0.0, 1.0); break; } @@ -196,7 +220,9 @@ void main(void) { border.widths.z, segment_rect.size.y, segment_rect.p0.y, - segment_rect.p0.x + 0.5 * segment_rect.size.x); + segment_rect.p0.x + 0.5 * segment_rect.size.x, + hasRadius(border.radii[0].zw), + hasRadius(border.radii[1].xy)); edge_mask = vec4(1.0, 0.0, 1.0, 0.0); break; } @@ -211,7 +237,9 @@ void main(void) { border.widths.w, segment_rect.size.x, segment_rect.p0.x, - segment_rect.p0.y + 0.5 * segment_rect.size.y); + segment_rect.p0.y + 0.5 * segment_rect.size.y, + hasRadius(border.radii[1].zw), + hasRadius(border.radii[1].xy)); edge_mask = vec4(0.0, 1.0, 0.0, 1.0); break; } diff --git a/webrender/src/border.rs b/webrender/src/border.rs index badf524558..417809126b 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -94,6 +94,15 @@ impl BorderCornerKind { }; BorderCornerKind::Mask(clip_data, radius, LayerSize::new(width0, width1), kind) } + + fn get_radius(&self, original_radius: &LayerSize) -> LayerSize { + match *self { + BorderCornerKind::Solid => *original_radius, + BorderCornerKind::Clip(..) => *original_radius, + BorderCornerKind::Mask(_, ref radius, _, _) => *radius, + BorderCornerKind::None => *original_radius, + } + } } #[derive(Copy, Clone, Debug, PartialEq)] @@ -168,14 +177,23 @@ fn get_corner( *radius, *border_rect, ), - (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask( - BorderCornerClipKind::Dot, - width0, - width1, - corner, - *radius, - *border_rect, - ), + (BorderStyle::Dotted, BorderStyle::Dotted) => { + let mut radius = *radius; + if radius.width < width0 { + radius.width = 0.0; + } + if radius.height < width1 { + radius.height = 0.0; + } + BorderCornerKind::new_mask( + BorderCornerClipKind::Dot, + width0, + width1, + corner, + radius, + *border_rect, + ) + } // Draw border transitions with dots and/or dashes as // solid segments. The old border path didn't support @@ -266,13 +284,13 @@ impl<'a> DisplayListFlattener<'a> { &mut self, info: &LayerPrimitiveInfo, border: &NormalBorder, + radius: &BorderRadius, widths: &BorderWidths, clip_and_scroll: ScrollNodeAndClipChain, corner_instances: [BorderCornerInstance; 4], edges: [BorderEdgeKind; 4], clip_sources: Vec, ) { - let radius = &border.radius; let left = &border.left; let right = &border.right; let top = &border.top; @@ -569,9 +587,17 @@ impl<'a> DisplayListFlattener<'a> { let mut extra_clips = Vec::new(); let mut corner_instances = [BorderCornerInstance::Single; 4]; + let radius = &border.radius; + let radius = BorderRadius { + top_left: corners[0].get_radius(&radius.top_left), + top_right: corners[1].get_radius(&radius.top_right), + bottom_right: corners[2].get_radius(&radius.bottom_right), + bottom_left: corners[3].get_radius(&radius.bottom_left), + }; + for (i, corner) in corners.iter().enumerate() { match *corner { - BorderCornerKind::Mask(corner_data, corner_radius, widths, kind) => { + BorderCornerKind::Mask(corner_data, mut corner_radius, widths, kind) => { let clip_source = BorderCornerClipSource::new(corner_data, corner_radius, widths, kind); extra_clips.push(ClipSource::BorderCorner(clip_source)); @@ -589,6 +615,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_normal_border_primitive( info, &border, + &radius, widths, clip_and_scroll, corner_instances, @@ -690,23 +717,35 @@ impl BorderCornerClipSource { (ellipse, 1 + desired_count.ceil() as usize) } BorderCornerClipKind::Dot => { - // The centers of dots follow an ellipse along the middle of the - // border radius. - let inner_radius = (corner_radius - widths * 0.5).abs(); - let ellipse = Ellipse::new(inner_radius); - - // Allocate a "worst case" number of dot clips. This can be - // calculated by taking the minimum edge radius, since that - // will result in the maximum number of dots along the path. - let min_diameter = widths.width.min(widths.height); - - // Get the number of circles (assuming spacing of one diameter - // between dots). - let max_dot_count = 0.5 * ellipse.total_arc_length / min_diameter; - - // Add space for one extra dot since they are centered at the - // start of the arc. - (ellipse, 1 + max_dot_count.ceil() as usize) + let mut corner_radius = corner_radius; + if corner_radius.width < (widths.width / 2.0) { + corner_radius.width = 0.0; + } + if corner_radius.height < (widths.height / 2.0) { + corner_radius.height = 0.0; + } + + if corner_radius.width == 0. && corner_radius.height == 0. { + (Ellipse::new(corner_radius), 1) + } else { + // The centers of dots follow an ellipse along the middle of the + // border radius. + let inner_radius = (corner_radius - widths * 0.5).abs(); + let ellipse = Ellipse::new(inner_radius); + + // Allocate a "worst case" number of dot clips. This can be + // calculated by taking the minimum edge radius, since that + // will result in the maximum number of dots along the path. + let min_diameter = widths.width.min(widths.height); + + // Get the number of circles (assuming spacing of one diameter + // between dots). + let max_dot_count = 0.5 * ellipse.total_arc_length / min_diameter; + + // Add space for one extra dot since they are centered at the + // start of the arc. + (ellipse, 1 + max_dot_count.ceil() as usize) + } } }; @@ -744,6 +783,16 @@ impl BorderCornerClipSource { assert_eq!(request.close(), 2 + 2 * self.actual_clip_count); } + BorderCornerClipKind::Dot if self.max_clip_count == 1 => { + let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5); + let dot = BorderCornerDotClipData { + center: LayerPoint::new(self.widths.width / 2.0, self.widths.height / 2.0), + radius: 0.5 * dot_diameter, + }; + self.actual_clip_count = 1; + dot.write(&mut request); + assert_eq!(request.close(), 3); + } BorderCornerClipKind::Dot => { let mut forward_dots = Vec::new(); let mut back_dots = Vec::new(); diff --git a/wrench/reftests/border/dotted-corner-small-radius.png b/wrench/reftests/border/dotted-corner-small-radius.png index 4bcf6bba0057d89d7228e5a8420fd6b97504fc71..dfe415990a3c79c53bcc789c01a7e0d160270e18 100644 GIT binary patch literal 15393 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