Skip to content

Commit

Permalink
Auto merge of #2784 - gw3583:border-groove-ridge-double, r=kvark
Browse files Browse the repository at this point in the history
Support double, groove, ridge borders in new border brush path.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/2784)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed May 29, 2018
2 parents f13c425 + 43c4743 commit 52373cb
Show file tree
Hide file tree
Showing 12 changed files with 448 additions and 218 deletions.
10 changes: 0 additions & 10 deletions webrender/res/clip_shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,3 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
}

#endif //WR_VERTEX_SHADER

#ifdef WR_FRAGMENT_SHADER

//Note: identical to prim_shared
float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}

#endif //WR_FRAGMENT_SHADER
306 changes: 260 additions & 46 deletions webrender/res/cs_border_segment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,58 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include shared,prim_shared,ellipse,shared_border
#include shared,ellipse

flat varying vec4 vColor0;
flat varying vec4 vColor1;
// For edges, the colors are the same. For corners, these
// are the colors of each edge making up the corner.
flat varying vec4 vColor0[2];
flat varying vec4 vColor1[2];

// A point + tangent defining the line where the edge
// transition occurs. Used for corners only.
flat varying vec4 vColorLine;
flat varying int vFeatures;
flat varying vec2 vClipCenter;

// x = segment, y = styles, z = edge axes
flat varying ivec3 vConfig;

// xy = Local space position of the clip center.
// zw = Scale the rect origin by this to get the outer
// corner from the segment rectangle.
flat varying vec4 vClipCenter_Sign;

// An outer and inner elliptical radii for border
// corner clipping.
flat varying vec4 vClipRadii;
flat varying vec2 vClipSign;

// Reference point for determine edge clip lines.
flat varying vec4 vEdgeReference;

// Stores widths/2 and widths/3 to save doing this in FS.
flat varying vec4 vPartialWidths;

// Local space position
varying vec2 vPos;

#define CLIP_RADII 1
#define MIX_COLOR 2
#define SEGMENT_TOP_LEFT 0
#define SEGMENT_TOP_RIGHT 1
#define SEGMENT_BOTTOM_RIGHT 2
#define SEGMENT_BOTTOM_LEFT 3
#define SEGMENT_LEFT 4
#define SEGMENT_TOP 5
#define SEGMENT_RIGHT 6
#define SEGMENT_BOTTOM 7

// Border styles as defined in webrender_api/types.rs
#define BORDER_STYLE_NONE 0
#define BORDER_STYLE_SOLID 1
#define BORDER_STYLE_DOUBLE 2
#define BORDER_STYLE_DOTTED 3
#define BORDER_STYLE_DASHED 4
#define BORDER_STYLE_HIDDEN 5
#define BORDER_STYLE_GROOVE 6
#define BORDER_STYLE_RIDGE 7
#define BORDER_STYLE_INSET 8
#define BORDER_STYLE_OUTSET 9

#ifdef WR_VERTEX_SHADER

Expand All @@ -27,15 +65,6 @@ in int aFlags;
in vec2 aWidths;
in vec2 aRadii;

#define SEGMENT_TOP_LEFT 0
#define SEGMENT_TOP_RIGHT 1
#define SEGMENT_BOTTOM_RIGHT 2
#define SEGMENT_BOTTOM_LEFT 3
#define SEGMENT_LEFT 4
#define SEGMENT_TOP 5
#define SEGMENT_RIGHT 6
#define SEGMENT_BOTTOM 7

vec2 get_outer_corner_scale(int segment) {
vec2 p;

Expand All @@ -61,67 +90,252 @@ vec2 get_outer_corner_scale(int segment) {
return p;
}

void main(void) {
vec2 pos = aRect.xy + aRect.zw * aPosition.xy;
vec4 mod_color(vec4 color, float f) {
return vec4(clamp(color.rgb * f, vec3(0.0), vec3(color.a)), color.a);
}

vec4[2] get_colors_for_side(vec4 color, int style) {
vec4 result[2];
const vec2 f = vec2(1.3, 0.7);

switch (style) {
case BORDER_STYLE_GROOVE:
result[0] = mod_color(color, f.x);
result[1] = mod_color(color, f.y);
break;
case BORDER_STYLE_RIDGE:
result[0] = mod_color(color, f.y);
result[1] = mod_color(color, f.x);
break;
default:
result[0] = color;
result[1] = color;
break;
}

return result;
}

void main(void) {
int segment = aFlags & 0xff;
int style = (aFlags >> 8) & 0xff;
int style0 = (aFlags >> 8) & 0xff;
int style1 = (aFlags >> 16) & 0xff;

vec2 outer_scale = get_outer_corner_scale(segment);
vec2 outer = aRect.xy + outer_scale * aRect.zw;
vec2 outer = outer_scale * aRect.zw;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;

vColor0 = aColor0;
vColor1 = aColor1;
vPos = pos;

vFeatures = 0;
vClipSign = clip_sign;
vClipCenter = outer + clip_sign * aRadii;
vClipRadii = vec4(aRadii, aRadii - aWidths);
vColorLine = vec4(0.0);

// Set some flags used by the FS to determine the
// orientation of the two edges in this corner.
ivec2 edge_axis;
// Derive the positions for the edge clips, which must be handled
// differently between corners and edges.
vec2 edge_reference;
switch (segment) {
case SEGMENT_TOP_LEFT:
edge_axis = ivec2(0, 1);
edge_reference = outer;
break;
case SEGMENT_TOP_RIGHT:
edge_axis = ivec2(1, 0);
edge_reference = vec2(outer.x - aWidths.x, outer.y);
break;
case SEGMENT_BOTTOM_RIGHT:
edge_axis = ivec2(0, 1);
edge_reference = outer - aWidths;
break;
case SEGMENT_BOTTOM_LEFT:
vFeatures |= (CLIP_RADII | MIX_COLOR);
vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
edge_axis = ivec2(1, 0);
edge_reference = vec2(outer.x, outer.y - aWidths.y);
break;
case SEGMENT_TOP:
case SEGMENT_BOTTOM:
edge_axis = ivec2(1, 1);
edge_reference = vec2(0.0);
break;
case SEGMENT_LEFT:
case SEGMENT_RIGHT:
default:
edge_axis = ivec2(0, 0);
edge_reference = vec2(0.0);
break;
}

gl_Position = uTransform * vec4(aTaskOrigin + pos, 0.0, 1.0);
vConfig = ivec3(
segment,
style0 | (style1 << 16),
edge_axis.x | (edge_axis.y << 16)
);
vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
vPos = aRect.zw * aPosition.xy;

vColor0 = get_colors_for_side(aColor0, style0);
vColor1 = get_colors_for_side(aColor1, style1);
vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
vEdgeReference = vec4(edge_reference, edge_reference + aWidths);

gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
}
#endif

#ifdef WR_FRAGMENT_SHADER
vec4 evaluate_color_for_style_in_corner(
vec2 clip_relative_pos,
int style,
vec4 color[2],
vec4 clip_radii,
float mix_factor,
int segment,
float aa_range
) {
switch (style) {
case BORDER_STYLE_DOUBLE: {
// Get the distances from 0.33 of the radii, and
// also 0.67 of the radii. Use these to form a
// SDF subtraction which will clip out the inside
// third of the rounded edge.
float d_radii_a = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.xy,
aa_range
);
float d_radii_b = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - 2.0 * vPartialWidths.xy,
aa_range
);
float d = min(-d_radii_a, d_radii_b);
float alpha = distance_aa(aa_range, d);
return alpha * color[0];
}
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE: {
float d = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.zw,
aa_range
);
float alpha = distance_aa(aa_range, d);
float swizzled_factor;
switch (segment) {
case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
case SEGMENT_BOTTOM_RIGHT: swizzled_factor = 1.0; break;
case SEGMENT_BOTTOM_LEFT: swizzled_factor = 1.0 - mix_factor; break;
default: swizzled_factor = 0.0; break;
};
vec4 c0 = mix(color[1], color[0], swizzled_factor);
vec4 c1 = mix(color[0], color[1], swizzled_factor);
return mix(c0, c1, alpha);
}
default:
break;
}

return color[0];
}

vec4 evaluate_color_for_style_in_edge(
vec2 pos,
int style,
vec4 color[2],
float aa_range,
int edge_axis
) {
switch (style) {
case BORDER_STYLE_DOUBLE: {
float d0 = -1.0;
float d1 = -1.0;
if (vPartialWidths[edge_axis] > 1.0) {
vec2 ref = vec2(
vEdgeReference[edge_axis] + vPartialWidths[edge_axis],
vEdgeReference[edge_axis+2] - vPartialWidths[edge_axis]
);
d0 = pos[edge_axis] - ref.x;
d1 = ref.y - pos[edge_axis];
}
float d = min(d0, d1);
float alpha = distance_aa(aa_range, d);
return alpha * color[0];
}
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE: {
float ref = vEdgeReference[edge_axis] + vPartialWidths[edge_axis+2];
float d = pos[edge_axis] - ref;
float alpha = distance_aa(aa_range, d);
return mix(color[0], color[1], alpha);
}
default:
break;
}

return color[0];
}

void main(void) {
float aa_range = compute_aa_range(vPos);
float d = -1.0;
vec4 color0, color1;

int segment = vConfig.x;
ivec2 style = ivec2(vConfig.y & 0xffff, vConfig.y >> 16);
ivec2 edge_axis = ivec2(vConfig.z & 0xffff, vConfig.z >> 16);

// Apply color mix
float mix_factor = 0.0;
if ((vFeatures & MIX_COLOR) != 0) {
if (edge_axis.x != edge_axis.y) {
float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos);
mix_factor = distance_aa(aa_range, -d_line);
}

// Apply clip radii
if ((vFeatures & CLIP_RADII) != 0) {
vec2 p = vPos - vClipCenter;
if (vClipSign.x * p.x < 0.0 && vClipSign.y * p.y < 0.0) {
float d_radii_a = distance_to_ellipse(p, vClipRadii.xy, aa_range);
float d_radii_b = distance_to_ellipse(p, vClipRadii.zw, aa_range);
float d_radii = max(d_radii_a, -d_radii_b);
d = max(d, d_radii);
}
// Check if inside corner clip-region
vec2 clip_relative_pos = vPos - vClipCenter_Sign.xy;
bool in_clip_region = all(lessThan(vClipCenter_Sign.zw * clip_relative_pos, vec2(0.0)));

if (in_clip_region) {
float d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy, aa_range);
float d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw, aa_range);
float d_radii = max(d_radii_a, -d_radii_b);
d = max(d, d_radii);

color0 = evaluate_color_for_style_in_corner(
clip_relative_pos,
style.x,
vColor0,
vClipRadii,
mix_factor,
segment,
aa_range
);
color1 = evaluate_color_for_style_in_corner(
clip_relative_pos,
style.y,
vColor1,
vClipRadii,
mix_factor,
segment,
aa_range
);
} else {
color0 = evaluate_color_for_style_in_edge(
vPos,
style.x,
vColor0,
aa_range,
edge_axis.x
);
color1 = evaluate_color_for_style_in_edge(
vPos,
style.y,
vColor1,
aa_range,
edge_axis.y
);
}

float alpha = distance_aa(aa_range, d);
vec4 color = mix(vColor0, vColor1, mix_factor);
vec4 color = mix(color0, color1, mix_factor);
oFragColor = color * alpha;
}
#endif
5 changes: 0 additions & 5 deletions webrender/res/prim_shared.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ vec2 clamp_rect(vec2 pt, RectWithSize rect) {
return clamp(pt, rect.p0, rect.p0 + rect.size);
}

float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}

// TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever.
flat varying vec4 vClipMaskUvBounds;
varying vec3 vClipMaskUv;
Expand Down

0 comments on commit 52373cb

Please sign in to comment.