1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include shared,rect,ellipse
7 // For edges, the colors are the same. For corners, these
8 // are the colors of each edge making up the corner.
9 flat varying mediump vec4 vColor00;
10 flat varying mediump vec4 vColor01;
11 flat varying mediump vec4 vColor10;
12 flat varying mediump vec4 vColor11;
14 // A point + tangent defining the line where the edge
15 // transition occurs. Used for corners only.
16 flat varying highp vec4 vColorLine;
18 // x: segment, y: clip mode
19 // We cast these to/from floats rather than using an ivec due to a driver bug
20 // on Adreno 3xx. See bug 1730458.
21 flat varying mediump vec2 vSegmentClipMode;
22 // x, y: styles, z, w: edge axes
23 // We cast these to/from floats rather than using an ivec (and bitshifting)
24 // due to a driver bug on Adreno 3xx. See bug 1730458.
25 flat varying mediump vec4 vStyleEdgeAxis;
27 // xy = Local space position of the clip center.
28 // zw = Scale the rect origin by this to get the outer
29 // corner from the segment rectangle.
30 flat varying highp vec4 vClipCenter_Sign;
32 // An outer and inner elliptical radii for border
34 flat varying highp vec4 vClipRadii;
36 // Reference point for determine edge clip lines.
37 flat varying highp vec4 vEdgeReference;
39 // Stores widths/2 and widths/3 to save doing this in FS.
40 flat varying highp vec4 vPartialWidths;
42 // Clipping parameters for dot or dash.
43 flat varying mediump vec4 vClipParams1;
44 flat varying mediump vec4 vClipParams2;
46 // Local space position
47 varying highp vec2 vPos;
49 #define SEGMENT_TOP_LEFT 0
50 #define SEGMENT_TOP_RIGHT 1
51 #define SEGMENT_BOTTOM_RIGHT 2
52 #define SEGMENT_BOTTOM_LEFT 3
53 #define SEGMENT_LEFT 4
55 #define SEGMENT_RIGHT 6
56 #define SEGMENT_BOTTOM 7
58 // Border styles as defined in webrender_api/types.rs
59 #define BORDER_STYLE_NONE 0
60 #define BORDER_STYLE_SOLID 1
61 #define BORDER_STYLE_DOUBLE 2
62 #define BORDER_STYLE_DOTTED 3
63 #define BORDER_STYLE_DASHED 4
64 #define BORDER_STYLE_HIDDEN 5
65 #define BORDER_STYLE_GROOVE 6
66 #define BORDER_STYLE_RIDGE 7
67 #define BORDER_STYLE_INSET 8
68 #define BORDER_STYLE_OUTSET 9
71 #define CLIP_DASH_CORNER 1
72 #define CLIP_DASH_EDGE 2
75 #ifdef WR_VERTEX_SHADER
77 PER_INSTANCE in vec2 aTaskOrigin;
78 PER_INSTANCE in vec4 aRect;
79 PER_INSTANCE in vec4 aColor0;
80 PER_INSTANCE in vec4 aColor1;
81 PER_INSTANCE in int aFlags;
82 PER_INSTANCE in vec2 aWidths;
83 PER_INSTANCE in vec2 aRadii;
84 PER_INSTANCE in vec4 aClipParams1;
85 PER_INSTANCE in vec4 aClipParams2;
87 vec2 get_outer_corner_scale(int segment) {
91 case SEGMENT_TOP_LEFT:
94 case SEGMENT_TOP_RIGHT:
97 case SEGMENT_BOTTOM_RIGHT:
100 case SEGMENT_BOTTOM_LEFT:
104 // The result is only used for non-default segment cases
112 // NOTE(emilio): If you change this algorithm, do the same change
114 vec4 mod_color(vec4 color, bool is_black, bool lighter) {
115 const float light_black = 0.7;
116 const float dark_black = 0.3;
118 const float dark_scale = 0.66666666;
119 const float light_scale = 1.0;
123 return vec4(vec3(light_black), color.a);
125 return vec4(vec3(dark_black), color.a);
129 return vec4(color.rgb * light_scale, color.a);
131 return vec4(color.rgb * dark_scale, color.a);
134 vec4[2] get_colors_for_side(vec4 color, int style) {
137 bool is_black = color.rgb == vec3(0.0, 0.0, 0.0);
140 case BORDER_STYLE_GROOVE:
141 result[0] = mod_color(color, is_black, true);
142 result[1] = mod_color(color, is_black, false);
144 case BORDER_STYLE_RIDGE:
145 result[0] = mod_color(color, is_black, false);
146 result[1] = mod_color(color, is_black, true);
158 int segment = aFlags & 0xff;
159 int style0 = (aFlags >> 8) & 0xff;
160 int style1 = (aFlags >> 16) & 0xff;
161 int clip_mode = (aFlags >> 24) & 0x0f;
163 vec2 size = aRect.zw - aRect.xy;
164 vec2 outer_scale = get_outer_corner_scale(segment);
165 vec2 outer = outer_scale * size;
166 vec2 clip_sign = 1.0 - 2.0 * outer_scale;
168 // Set some flags used by the FS to determine the
169 // orientation of the two edges in this corner.
170 ivec2 edge_axis = ivec2(0, 0);
171 // Derive the positions for the edge clips, which must be handled
172 // differently between corners and edges.
173 vec2 edge_reference = vec2(0.0);
175 case SEGMENT_TOP_LEFT:
176 edge_axis = ivec2(0, 1);
177 edge_reference = outer;
179 case SEGMENT_TOP_RIGHT:
180 edge_axis = ivec2(1, 0);
181 edge_reference = vec2(outer.x - aWidths.x, outer.y);
183 case SEGMENT_BOTTOM_RIGHT:
184 edge_axis = ivec2(0, 1);
185 edge_reference = outer - aWidths;
187 case SEGMENT_BOTTOM_LEFT:
188 edge_axis = ivec2(1, 0);
189 edge_reference = vec2(outer.x, outer.y - aWidths.y);
193 edge_axis = ivec2(1, 1);
201 vSegmentClipMode = vec2(float(segment), float(clip_mode));
202 vStyleEdgeAxis = vec4(float(style0), float(style1), float(edge_axis.x), float(edge_axis.y));
204 vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
205 vPos = size * aPosition.xy;
207 vec4[2] color0 = get_colors_for_side(aColor0, style0);
208 vColor00 = color0[0];
209 vColor01 = color0[1];
210 vec4[2] color1 = get_colors_for_side(aColor1, style1);
211 vColor10 = color1[0];
212 vColor11 = color1[1];
213 vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
214 vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
215 vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
216 vEdgeReference = vec4(edge_reference, edge_reference + aWidths);
217 vClipParams1 = aClipParams1;
218 vClipParams2 = aClipParams2;
220 // For the case of dot and dash clips, optimize the number of pixels that
221 // are hit to just include the dot itself.
222 if (clip_mode == CLIP_DOT) {
223 float radius = aClipParams1.z;
225 // Expand by a small amount to allow room for AA around
226 // the dot if it's big enough.
230 vPos = vClipParams1.xy + radius * (2.0 * aPosition.xy - 1.0);
231 vPos = clamp(vPos, vec2(0.0), size);
232 } else if (clip_mode == CLIP_DASH_CORNER) {
233 vec2 center = (aClipParams1.xy + aClipParams2.xy) * 0.5;
234 // This is a gross approximation which works out because dashes don't have
235 // a strong curvature and we will overshoot by inflating the geometry by
236 // this amount on each side (sqrt(2) * length(dash) would be enough and we
237 // compute 2 * approx_length(dash)).
238 float dash_length = length(aClipParams1.xy - aClipParams2.xy);
239 float width = max(aWidths.x, aWidths.y);
240 // expand by a small amout for AA just like we do for dots.
241 vec2 r = vec2(max(dash_length, width)) + 2.0;
242 vPos = clamp(vPos, center - r, center + r);
245 gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
249 #ifdef WR_FRAGMENT_SHADER
250 vec4 evaluate_color_for_style_in_corner(
251 vec2 clip_relative_pos,
261 case BORDER_STYLE_DOUBLE: {
262 // Get the distances from 0.33 of the radii, and
263 // also 0.67 of the radii. Use these to form a
264 // SDF subtraction which will clip out the inside
265 // third of the rounded edge.
266 float d_radii_a = distance_to_ellipse(
268 clip_radii.xy - vPartialWidths.xy
270 float d_radii_b = distance_to_ellipse(
272 clip_radii.xy - 2.0 * vPartialWidths.xy
274 float d = min(-d_radii_a, d_radii_b);
275 color0 *= distance_aa(aa_range, d);
278 case BORDER_STYLE_GROOVE:
279 case BORDER_STYLE_RIDGE: {
280 float d = distance_to_ellipse(
282 clip_radii.xy - vPartialWidths.zw
284 float alpha = distance_aa(aa_range, d);
285 float swizzled_factor;
287 case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
288 case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
289 case SEGMENT_BOTTOM_RIGHT: swizzled_factor = 1.0; break;
290 case SEGMENT_BOTTOM_LEFT: swizzled_factor = 1.0 - mix_factor; break;
291 default: swizzled_factor = 0.0; break;
293 vec4 c0 = mix(color1, color0, swizzled_factor);
294 vec4 c1 = mix(color0, color1, swizzled_factor);
295 color0 = mix(c0, c1, alpha);
305 vec4 evaluate_color_for_style_in_edge(
313 vec2 edge_axis = edge_axis_id != 0 ? vec2(0.0, 1.0) : vec2(1.0, 0.0);
314 float pos = dot(pos_vec, edge_axis);
316 case BORDER_STYLE_DOUBLE: {
318 float partial_width = dot(vPartialWidths.xy, edge_axis);
319 if (partial_width >= 1.0) {
321 dot(vEdgeReference.xy, edge_axis) + partial_width,
322 dot(vEdgeReference.zw, edge_axis) - partial_width
324 d = min(pos - ref.x, ref.y - pos);
326 color0 *= distance_aa(aa_range, d);
329 case BORDER_STYLE_GROOVE:
330 case BORDER_STYLE_RIDGE: {
331 float ref = dot(vEdgeReference.xy + vPartialWidths.zw, edge_axis);
333 float alpha = distance_aa(aa_range, d);
334 color0 = mix(color0, color1, alpha);
345 float aa_range = compute_aa_range(vPos);
348 int segment = int(vSegmentClipMode.x);
349 int clip_mode = int(vSegmentClipMode.y);
350 ivec2 style = ivec2(int(vStyleEdgeAxis.x), int(vStyleEdgeAxis.y));
351 ivec2 edge_axis = ivec2(int(vStyleEdgeAxis.z), int(vStyleEdgeAxis.w));
353 float mix_factor = 0.0;
354 if (edge_axis.x != edge_axis.y) {
355 float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos);
356 mix_factor = distance_aa(aa_range, -d_line);
359 // Check if inside corner clip-region
360 vec2 clip_relative_pos = vPos - vClipCenter_Sign.xy;
361 bool in_clip_region = all(lessThan(vClipCenter_Sign.zw * clip_relative_pos, vec2(0.0)));
366 // Set clip distance based or dot position and radius.
367 d = distance(vClipParams1.xy, vPos) - vClipParams1.z;
370 case CLIP_DASH_EDGE: {
371 bool is_vertical = vClipParams1.x == 0.;
372 float half_dash = is_vertical ? vClipParams1.y : vClipParams1.x;
373 // We want to draw something like:
377 float pos = is_vertical ? vPos.y : vPos.x;
378 bool in_dash = pos < half_dash || pos > 3.0 * half_dash;
384 case CLIP_DASH_CORNER: {
385 // Get SDF for the two line/tangent clip lines,
386 // do SDF subtract to get clip distance.
387 float d0 = distance_to_line(vClipParams1.xy,
390 float d1 = distance_to_line(vClipParams2.xy,
401 if (in_clip_region) {
402 float d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy);
403 float d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw);
404 float d_radii = max(d_radii_a, -d_radii_b);
407 color0 = evaluate_color_for_style_in_corner(
417 color1 = evaluate_color_for_style_in_corner(
428 color0 = evaluate_color_for_style_in_edge(
436 color1 = evaluate_color_for_style_in_edge(
446 float alpha = distance_aa(aa_range, d);
447 vec4 color = mix(color0, color1, mix_factor);
448 oFragColor = color * alpha;