Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions webrender/res/ps_border_edge.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
103 changes: 76 additions & 27 deletions webrender/src/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<ClipSource>,
) {
let radius = &border.radius;
let left = &border.left;
let right = &border.right;
let top = &border.top;
Expand Down Expand Up @@ -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));
Expand All @@ -589,6 +615,7 @@ impl<'a> DisplayListFlattener<'a> {
self.add_normal_border_primitive(
info,
&border,
&radius,
widths,
clip_and_scroll,
corner_instances,
Expand Down Expand Up @@ -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)
}
}
};

Expand Down Expand Up @@ -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();
Expand Down
Binary file modified wrench/reftests/border/dotted-corner-small-radius.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.