summaryrefslogtreecommitdiffstats
path: root/gfx/wr/webrender/res/ellipse.glsl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/wr/webrender/res/ellipse.glsl
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wr/webrender/res/ellipse.glsl')
-rw-r--r--gfx/wr/webrender/res/ellipse.glsl81
1 files changed, 81 insertions, 0 deletions
diff --git a/gfx/wr/webrender/res/ellipse.glsl b/gfx/wr/webrender/res/ellipse.glsl
new file mode 100644
index 0000000000..04dc890b51
--- /dev/null
+++ b/gfx/wr/webrender/res/ellipse.glsl
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+// Preprocess the radii for computing the distance approximation. This should
+// be used in the vertex shader if possible to avoid doing expensive division
+// in the fragment shader. When dealing with a point (zero radii), approximate
+// it as an ellipse with very small radii so that we don't need to branch.
+vec2 inverse_radii_squared(vec2 radii) {
+ return any(lessThanEqual(radii, vec2(0.0)))
+ ? vec2(1.0 / (1.0e-3 * 1.0e-3))
+ : 1.0 / (radii * radii);
+}
+
+#ifdef WR_FRAGMENT_SHADER
+
+// One iteration of Newton's method on the 2D equation of an ellipse:
+//
+// E(x, y) = x^2/a^2 + y^2/b^2 - 1
+//
+// The Jacobian of this equation is:
+//
+// J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ]
+//
+// We approximate the distance with:
+//
+// E(x, y) / ||J(E(x, y))||
+//
+// See G. Taubin, "Distance Approximations for Rasterizing Implicit
+// Curves", section 3.
+float distance_to_ellipse_approx(vec2 p, vec2 inv_radii_sq) {
+ float g = dot(p * p, inv_radii_sq) - 1.0;
+ vec2 dG = 2.0 * p * inv_radii_sq;
+ return g * inversesqrt(dot(dG, dG));
+}
+
+// Slower but more accurate version that uses the exact distance when dealing
+// with a 0-radius point distance and otherwise uses the faster approximation
+// when dealing with non-zero radii.
+float distance_to_ellipse(vec2 p, vec2 radii) {
+ return any(lessThanEqual(radii, vec2(0.0)))
+ ? length(p)
+ : distance_to_ellipse_approx(p, 1.0 / (radii * radii));
+}
+
+float clip_against_ellipse_if_needed(
+ vec2 pos,
+ vec4 ellipse_center_radius,
+ vec2 sign_modifier
+) {
+ vec2 p = pos - ellipse_center_radius.xy;
+ // If we're not within the distance bounds of both of the radii (in the
+ // corner), then return a large magnitude negative value to cause us to
+ // clamp off the anti-aliasing.
+ return all(lessThan(sign_modifier * p, vec2(0.0)))
+ ? distance_to_ellipse_approx(p, ellipse_center_radius.zw)
+ : -1.0e6;
+}
+
+float rounded_rect(vec2 pos,
+ vec4 clip_center_radius_tl,
+ vec4 clip_center_radius_tr,
+ vec4 clip_center_radius_br,
+ vec4 clip_center_radius_bl,
+ float aa_range) {
+ // Clip against each ellipse. If the fragment is in a corner, one of the
+ // clip_against_ellipse_if_needed calls below will update it. If outside
+ // any ellipse, the clip routine will return a negative value so that max()
+ // will choose the greatest amount of applicable anti-aliasing.
+ float current_distance =
+ max(max(clip_against_ellipse_if_needed(pos, clip_center_radius_tl, vec2(1.0)),
+ clip_against_ellipse_if_needed(pos, clip_center_radius_tr, vec2(-1.0, 1.0))),
+ max(clip_against_ellipse_if_needed(pos, clip_center_radius_br, vec2(-1.0)),
+ clip_against_ellipse_if_needed(pos, clip_center_radius_bl, vec2(1.0, -1.0))));
+
+ // Apply AA
+ // See comment in ps_border_corner about the choice of constants.
+
+ return distance_aa(aa_range, current_distance);
+}
+#endif