Skip to content

Border edge checks #2630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 9, 2018
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
50 changes: 27 additions & 23 deletions webrender/src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -975,23 +975,17 @@ impl AlphaBatchBuilder {
let border_cpu =
&ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0];
// TODO(gw): Select correct blend mode for edges and corners!!
let corner_kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::BorderCorner,
);
let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures);
let edge_kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::BorderEdge,
);
let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures);

// Work around borrow ck on borrowing batch_list twice.
{
let batch =
self.batch_list.get_suitable_batch(corner_key, &task_relative_bounding_rect);
for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate()
{

if border_cpu.corner_instances.iter().any(|&kind| kind != BorderCornerInstance::None) {
let corner_kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::BorderCorner,
);
let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures);
let batch = self.batch_list
.get_suitable_batch(corner_key, &task_relative_bounding_rect);

for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() {
let sub_index = i as i32;
match *instance_kind {
BorderCornerInstance::None => {}
Expand All @@ -1018,12 +1012,22 @@ impl AlphaBatchBuilder {
}
}

let batch = self.batch_list.get_suitable_batch(edge_key, &task_relative_bounding_rect);
for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() {
match *instance_kind {
BorderEdgeKind::None => {},
_ => {
batch.push(base_instance.build(border_segment as i32, 0, 0));
if border_cpu.edges.iter().any(|&kind| kind != BorderEdgeKind::None) {
let edge_kind = BatchKind::Transformable(
transform_kind,
TransformBatchKind::BorderEdge,
);
let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures);
let batch = self.batch_list
.get_suitable_batch(edge_key, &task_relative_bounding_rect);

for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() {
match *instance_kind {
BorderEdgeKind::None => {},
BorderEdgeKind::Solid |
BorderEdgeKind::Clip => {
batch.push(base_instance.build(border_segment as i32, 0, 0));
}
}
}
}
Expand Down
228 changes: 107 additions & 121 deletions webrender/src/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,134 +103,116 @@ pub enum BorderEdgeKind {
Clip,
}

trait NormalBorderHelpers {
fn get_corner(
&self,
edge0: &BorderSide,
width0: f32,
edge1: &BorderSide,
width1: f32,
radius: &LayerSize,
corner: BorderCorner,
border_rect: &LayerRect,
) -> BorderCornerKind;
fn get_corner(
edge0: &BorderSide,
width0: f32,
edge1: &BorderSide,
width1: f32,
radius: &LayerSize,
corner: BorderCorner,
border_rect: &LayerRect,
) -> BorderCornerKind {
// If both widths are zero, a corner isn't formed.
if width0 == 0.0 && width1 == 0.0 {
return BorderCornerKind::None;
}

fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32);
}
// If both edges are transparent, no corner is formed.
if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
return BorderCornerKind::None;
}

impl NormalBorderHelpers for NormalBorder {
fn get_corner(
&self,
edge0: &BorderSide,
width0: f32,
edge1: &BorderSide,
width1: f32,
radius: &LayerSize,
corner: BorderCorner,
border_rect: &LayerRect,
) -> BorderCornerKind {
// If both widths are zero, a corner isn't formed.
if width0 == 0.0 && width1 == 0.0 {
return BorderCornerKind::None;
match (edge0.style, edge1.style) {
// If both edges are none or hidden, no corner is needed.
(BorderStyle::None, BorderStyle::None) |
(BorderStyle::None, BorderStyle::Hidden) |
(BorderStyle::Hidden, BorderStyle::None) |
(BorderStyle::Hidden, BorderStyle::Hidden) => {
BorderCornerKind::None
}

// If both edges are transparent, no corner is formed.
if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
return BorderCornerKind::None;
// If one of the edges is none or hidden, we just draw one style.
(BorderStyle::None, _) |
(_, BorderStyle::None) |
(BorderStyle::Hidden, _) |
(_, BorderStyle::Hidden) => {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}

match (edge0.style, edge1.style) {
// If both edges are none or hidden, no corner is needed.
(BorderStyle::None, BorderStyle::None) |
(BorderStyle::None, BorderStyle::Hidden) |
(BorderStyle::Hidden, BorderStyle::None) |
(BorderStyle::Hidden, BorderStyle::Hidden) => {
BorderCornerKind::None
}

// If one of the edges is none or hidden, we just draw one style.
(BorderStyle::None, _) |
(_, BorderStyle::None) |
(BorderStyle::Hidden, _) |
(_, BorderStyle::Hidden) => {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}

// If both borders are solid, we can draw them with a simple rectangle if
// both the colors match and there is no radius.
(BorderStyle::Solid, BorderStyle::Solid) => {
if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
BorderCornerKind::Solid
} else {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}
}

// Inset / outset borders just modify the color of edges, so can be
// drawn with the normal border corner shader.
(BorderStyle::Outset, BorderStyle::Outset) |
(BorderStyle::Inset, BorderStyle::Inset) |
(BorderStyle::Double, BorderStyle::Double) |
(BorderStyle::Groove, BorderStyle::Groove) |
(BorderStyle::Ridge, BorderStyle::Ridge) => {
// If both borders are solid, we can draw them with a simple rectangle if
// both the colors match and there is no radius.
(BorderStyle::Solid, BorderStyle::Solid) => {
if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
BorderCornerKind::Solid
} else {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}

// Dashed and dotted border corners get drawn into a clip mask.
(BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask(
BorderCornerClipKind::Dash,
width0,
width1,
corner,
*radius,
*border_rect,
),
(BorderStyle::Dotted, BorderStyle::Dotted) => 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
// this anyway, so we might as well start using the new
// border path here, since the dashing in the edges is
// much higher quality anyway.
(BorderStyle::Dotted, _) |
(_, BorderStyle::Dotted) |
(BorderStyle::Dashed, _) |
(_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single),

// Everything else can be handled by drawing the corner twice,
// where the shader outputs zero alpha for the side it's not
// drawing. This is somewhat inefficient in terms of pixels
// written, but it's a fairly rare case, and we can optimize
// this case later.
_ => BorderCornerKind::Clip(BorderCornerInstance::Double),
}
}

fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32) {
if width == 0.0 {
return (BorderEdgeKind::None, 0.0);
// Inset / outset borders just modify the color of edges, so can be
// drawn with the normal border corner shader.
(BorderStyle::Outset, BorderStyle::Outset) |
(BorderStyle::Inset, BorderStyle::Inset) |
(BorderStyle::Double, BorderStyle::Double) |
(BorderStyle::Groove, BorderStyle::Groove) |
(BorderStyle::Ridge, BorderStyle::Ridge) => {
BorderCornerKind::Clip(BorderCornerInstance::Single)
}

match edge.style {
BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),
// Dashed and dotted border corners get drawn into a clip mask.
(BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask(
BorderCornerClipKind::Dash,
width0,
width1,
corner,
*radius,
*border_rect,
),
(BorderStyle::Dotted, BorderStyle::Dotted) => 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
// this anyway, so we might as well start using the new
// border path here, since the dashing in the edges is
// much higher quality anyway.
(BorderStyle::Dotted, _) |
(_, BorderStyle::Dotted) |
(BorderStyle::Dashed, _) |
(_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single),

// Everything else can be handled by drawing the corner twice,
// where the shader outputs zero alpha for the side it's not
// drawing. This is somewhat inefficient in terms of pixels
// written, but it's a fairly rare case, and we can optimize
// this case later.
_ => BorderCornerKind::Clip(BorderCornerInstance::Double),
}
}

fn get_edge(edge: &BorderSide, width: f32, height: f32) -> (BorderEdgeKind, f32) {
if width == 0.0 || height <= 0.0 {
return (BorderEdgeKind::None, 0.0);
}

BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => {
(BorderEdgeKind::Solid, width)
}
match edge.style {
BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),

BorderStyle::Double |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Dashed |
BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => {
(BorderEdgeKind::Solid, width)
}

BorderStyle::Double |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Dashed |
BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
}
}

Expand Down Expand Up @@ -431,7 +413,7 @@ impl<'a> DisplayListFlattener<'a> {
}

let corners = [
border.get_corner(
get_corner(
left,
widths.left,
top,
Expand All @@ -440,7 +422,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::TopLeft,
&info.rect,
),
border.get_corner(
get_corner(
right,
widths.right,
top,
Expand All @@ -449,7 +431,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::TopRight,
&info.rect,
),
border.get_corner(
get_corner(
right,
widths.right,
bottom,
Expand All @@ -458,7 +440,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::BottomRight,
&info.rect,
),
border.get_corner(
get_corner(
left,
widths.left,
bottom,
Expand All @@ -469,10 +451,14 @@ impl<'a> DisplayListFlattener<'a> {
),
];

let (left_edge, left_len) = border.get_edge(left, widths.left);
let (top_edge, top_len) = border.get_edge(top, widths.top);
let (right_edge, right_len) = border.get_edge(right, widths.right);
let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom);
let (left_edge, left_len) = get_edge(left, widths.left,
info.rect.size.height - radius.top_left.height - radius.bottom_left.height);
let (top_edge, top_len) = get_edge(top, widths.top,
info.rect.size.width - radius.top_left.width - radius.top_right.width);
let (right_edge, right_len) = get_edge(right, widths.right,
info.rect.size.height - radius.top_right.height - radius.bottom_right.height);
let (bottom_edge, bottom_len) = get_edge(bottom, widths.bottom,
info.rect.size.width - radius.bottom_right.width - radius.bottom_left.width);

let edges = [left_edge, top_edge, right_edge, bottom_edge];

Expand Down