tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cs_border_segment.glsl (14521B)


      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/. */
      4 
      5 #include shared,rect,ellipse
      6 
      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;
     13 
     14 // A point + tangent defining the line where the edge
     15 // transition occurs. Used for corners only.
     16 flat varying highp vec4 vColorLine;
     17 
     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;
     26 
     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;
     31 
     32 // An outer and inner elliptical radii for border
     33 // corner clipping.
     34 flat varying highp vec4 vClipRadii;
     35 
     36 // Reference point for determine edge clip lines.
     37 flat varying highp vec4 vEdgeReference;
     38 
     39 // Stores widths/2 and widths/3 to save doing this in FS.
     40 flat varying highp vec4 vPartialWidths;
     41 
     42 // Clipping parameters for dot or dash.
     43 flat varying mediump vec4 vClipParams1;
     44 flat varying mediump vec4 vClipParams2;
     45 
     46 // Local space position
     47 varying highp vec2 vPos;
     48 
     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
     54 #define SEGMENT_TOP             5
     55 #define SEGMENT_RIGHT           6
     56 #define SEGMENT_BOTTOM          7
     57 
     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
     69 
     70 #define CLIP_NONE        0
     71 #define CLIP_DASH_CORNER 1
     72 #define CLIP_DASH_EDGE   2
     73 #define CLIP_DOT         3
     74 
     75 #ifdef WR_VERTEX_SHADER
     76 
     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;
     86 
     87 vec2 get_outer_corner_scale(int segment) {
     88     vec2 p;
     89 
     90     switch (segment) {
     91         case SEGMENT_TOP_LEFT:
     92             p = vec2(0.0, 0.0);
     93             break;
     94         case SEGMENT_TOP_RIGHT:
     95             p = vec2(1.0, 0.0);
     96             break;
     97         case SEGMENT_BOTTOM_RIGHT:
     98             p = vec2(1.0, 1.0);
     99             break;
    100         case SEGMENT_BOTTOM_LEFT:
    101             p = vec2(0.0, 1.0);
    102             break;
    103         default:
    104             // The result is only used for non-default segment cases
    105             p = vec2(0.0);
    106             break;
    107     }
    108 
    109     return p;
    110 }
    111 
    112 // NOTE(emilio): If you change this algorithm, do the same change
    113 // in border.rs
    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;
    117 
    118     const float dark_scale = 0.66666666;
    119     const float light_scale = 1.0;
    120 
    121     if (is_black) {
    122         if (lighter) {
    123             return vec4(vec3(light_black), color.a);
    124         }
    125         return vec4(vec3(dark_black), color.a);
    126     }
    127 
    128     if (lighter) {
    129         return vec4(color.rgb * light_scale, color.a);
    130     }
    131     return vec4(color.rgb * dark_scale, color.a);
    132 }
    133 
    134 vec4[2] get_colors_for_side(vec4 color, int style) {
    135     vec4 result[2];
    136 
    137     bool is_black = color.rgb == vec3(0.0, 0.0, 0.0);
    138 
    139     switch (style) {
    140         case BORDER_STYLE_GROOVE:
    141             result[0] = mod_color(color, is_black, true);
    142             result[1] = mod_color(color, is_black, false);
    143             break;
    144         case BORDER_STYLE_RIDGE:
    145             result[0] = mod_color(color, is_black, false);
    146             result[1] = mod_color(color, is_black, true);
    147             break;
    148         default:
    149             result[0] = color;
    150             result[1] = color;
    151             break;
    152     }
    153 
    154     return result;
    155 }
    156 
    157 void main(void) {
    158     int segment = aFlags & 0xff;
    159     int style0 = (aFlags >> 8) & 0xff;
    160     int style1 = (aFlags >> 16) & 0xff;
    161     int clip_mode = (aFlags >> 24) & 0x0f;
    162 
    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;
    167 
    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);
    174     switch (segment) {
    175         case SEGMENT_TOP_LEFT:
    176             edge_axis = ivec2(0, 1);
    177             edge_reference = outer;
    178             break;
    179         case SEGMENT_TOP_RIGHT:
    180             edge_axis = ivec2(1, 0);
    181             edge_reference = vec2(outer.x - aWidths.x, outer.y);
    182             break;
    183         case SEGMENT_BOTTOM_RIGHT:
    184             edge_axis = ivec2(0, 1);
    185             edge_reference = outer - aWidths;
    186             break;
    187         case SEGMENT_BOTTOM_LEFT:
    188             edge_axis = ivec2(1, 0);
    189             edge_reference = vec2(outer.x, outer.y - aWidths.y);
    190             break;
    191         case SEGMENT_TOP:
    192         case SEGMENT_BOTTOM:
    193             edge_axis = ivec2(1, 1);
    194             break;
    195         case SEGMENT_LEFT:
    196         case SEGMENT_RIGHT:
    197         default:
    198             break;
    199     }
    200 
    201     vSegmentClipMode = vec2(float(segment), float(clip_mode));
    202     vStyleEdgeAxis = vec4(float(style0), float(style1), float(edge_axis.x), float(edge_axis.y));
    203 
    204     vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
    205     vPos = size * aPosition.xy;
    206 
    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;
    219 
    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;
    224 
    225         // Expand by a small amount to allow room for AA around
    226         // the dot if it's big enough.
    227         if (radius > 0.5)
    228             radius += 2.0;
    229 
    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);
    243     }
    244 
    245     gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
    246 }
    247 #endif
    248 
    249 #ifdef WR_FRAGMENT_SHADER
    250 vec4 evaluate_color_for_style_in_corner(
    251     vec2 clip_relative_pos,
    252     int style,
    253     vec4 color0,
    254     vec4 color1,
    255     vec4 clip_radii,
    256     float mix_factor,
    257     int segment,
    258     float aa_range
    259 ) {
    260     switch (style) {
    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(
    267                 clip_relative_pos,
    268                 clip_radii.xy - vPartialWidths.xy
    269             );
    270             float d_radii_b = distance_to_ellipse(
    271                 clip_relative_pos,
    272                 clip_radii.xy - 2.0 * vPartialWidths.xy
    273             );
    274             float d = min(-d_radii_a, d_radii_b);
    275             color0 *= distance_aa(aa_range, d);
    276             break;
    277         }
    278         case BORDER_STYLE_GROOVE:
    279         case BORDER_STYLE_RIDGE: {
    280             float d = distance_to_ellipse(
    281                 clip_relative_pos,
    282                 clip_radii.xy - vPartialWidths.zw
    283             );
    284             float alpha = distance_aa(aa_range, d);
    285             float swizzled_factor;
    286             switch (segment) {
    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;
    292             };
    293             vec4 c0 = mix(color1, color0, swizzled_factor);
    294             vec4 c1 = mix(color0, color1, swizzled_factor);
    295             color0 = mix(c0, c1, alpha);
    296             break;
    297         }
    298         default:
    299             break;
    300     }
    301 
    302     return color0;
    303 }
    304 
    305 vec4 evaluate_color_for_style_in_edge(
    306     vec2 pos_vec,
    307     int style,
    308     vec4 color0,
    309     vec4 color1,
    310     float aa_range,
    311     int edge_axis_id
    312 ) {
    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);
    315     switch (style) {
    316         case BORDER_STYLE_DOUBLE: {
    317             float d = -1.0;
    318             float partial_width = dot(vPartialWidths.xy, edge_axis);
    319             if (partial_width >= 1.0) {
    320                 vec2 ref = vec2(
    321                     dot(vEdgeReference.xy, edge_axis) + partial_width,
    322                     dot(vEdgeReference.zw, edge_axis) - partial_width
    323                 );
    324                 d = min(pos - ref.x, ref.y - pos);
    325             }
    326             color0 *= distance_aa(aa_range, d);
    327             break;
    328         }
    329         case BORDER_STYLE_GROOVE:
    330         case BORDER_STYLE_RIDGE: {
    331             float ref = dot(vEdgeReference.xy + vPartialWidths.zw, edge_axis);
    332             float d = pos - ref;
    333             float alpha = distance_aa(aa_range, d);
    334             color0 = mix(color0, color1, alpha);
    335             break;
    336         }
    337         default:
    338             break;
    339     }
    340 
    341     return color0;
    342 }
    343 
    344 void main(void) {
    345     float aa_range = compute_aa_range(vPos);
    346     vec4 color0, color1;
    347 
    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));
    352 
    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);
    357     }
    358 
    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)));
    362     float d = -1.0;
    363 
    364     switch (clip_mode) {
    365         case CLIP_DOT: {
    366             // Set clip distance based or dot position and radius.
    367             d = distance(vClipParams1.xy, vPos) - vClipParams1.z;
    368             break;
    369         }
    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:
    374             // +---+---+---+---+
    375             // |xxx|   |   |xxx|
    376             // +---+---+---+---+
    377             float pos = is_vertical ? vPos.y : vPos.x;
    378             bool in_dash = pos < half_dash || pos > 3.0 * half_dash;
    379             if (!in_dash) {
    380                 d = 1.;
    381             }
    382             break;
    383         }
    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,
    388                                         vClipParams1.zw,
    389                                         vPos);
    390             float d1 = distance_to_line(vClipParams2.xy,
    391                                         vClipParams2.zw,
    392                                         vPos);
    393             d = max(d0, -d1);
    394             break;
    395         }
    396         case CLIP_NONE:
    397         default:
    398             break;
    399     }
    400 
    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);
    405         d = max(d, d_radii);
    406 
    407         color0 = evaluate_color_for_style_in_corner(
    408             clip_relative_pos,
    409             style.x,
    410             vColor00,
    411             vColor01,
    412             vClipRadii,
    413             mix_factor,
    414             segment,
    415             aa_range
    416         );
    417         color1 = evaluate_color_for_style_in_corner(
    418             clip_relative_pos,
    419             style.y,
    420             vColor10,
    421             vColor11,
    422             vClipRadii,
    423             mix_factor,
    424             segment,
    425             aa_range
    426         );
    427     } else {
    428         color0 = evaluate_color_for_style_in_edge(
    429             vPos,
    430             style.x,
    431             vColor00,
    432             vColor01,
    433             aa_range,
    434             edge_axis.x
    435         );
    436         color1 = evaluate_color_for_style_in_edge(
    437             vPos,
    438             style.y,
    439             vColor10,
    440             vColor11,
    441             aa_range,
    442             edge_axis.y
    443         );
    444     }
    445 
    446     float alpha = distance_aa(aa_range, d);
    447     vec4 color = mix(color0, color1, mix_factor);
    448     oFragColor = color * alpha;
    449 }
    450 #endif