Skip to content

Commit 6943c20

Browse files
authored
Add support for 2 point conical gradients (#164)
1 parent 9f5dd32 commit 6943c20

File tree

12 files changed

+491
-104
lines changed

12 files changed

+491
-104
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [Unreleased]
8+
### Added
9+
- 2-point conical gradient support for (`RadialGradient`).
10+
Thanks to [@wmedrano](https://github.com/wmedrano)
11+
12+
### Changed
13+
- The `RadialGradient::new` requires a start radius now. Set the second argument
14+
to 0.0 to preserve the old behavior.
15+
816

917
## [0.11.4] - 2024-02-04
1018
### Fixed

benches/src/gradients.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ fn simple_radial_tiny_skia(bencher: &mut Bencher) {
538538
paint.anti_alias = false;
539539
paint.shader = RadialGradient::new(
540540
Point::from_xy(500.0, 500.0),
541+
0.0,
541542
Point::from_xy(500.0, 500.0),
542543
500.0,
543544
vec![
@@ -692,6 +693,7 @@ fn two_point_radial_tiny_skia(bencher: &mut Bencher) {
692693
paint.anti_alias = false;
693694
paint.shader = RadialGradient::new(
694695
Point::from_xy(400.0, 400.0),
696+
0.0,
695697
Point::from_xy(500.0, 500.0),
696698
500.0,
697699
vec![

path/src/scalar.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub trait Scalar {
2424
fn invert(self) -> Self;
2525
fn bound(self, min: Self, max: Self) -> Self;
2626
fn is_nearly_equal(self, other: Self) -> bool;
27+
fn is_nearly_equal_within_tolerance(self, other: Self, tolerance: Self) -> bool;
2728
fn is_nearly_zero(self) -> bool;
2829
fn is_nearly_zero_within_tolerance(self, tolerance: Self) -> bool;
2930
fn almost_dequal_ulps(self, other: Self) -> bool;
@@ -56,6 +57,10 @@ impl Scalar for f32 {
5657
(self - other).abs() <= SCALAR_NEARLY_ZERO
5758
}
5859

60+
fn is_nearly_equal_within_tolerance(self, other: Self, tolerance: Self) -> bool {
61+
(self - other).abs() <= tolerance
62+
}
63+
5964
fn is_nearly_zero(self) -> bool {
6065
self.is_nearly_zero_within_tolerance(SCALAR_NEARLY_ZERO)
6166
}

src/pipeline/highp.rs

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,16 @@ pub const STAGES: &[StageFn; super::STAGES_COUNT] = &[
116116
xy_to_radius,
117117
xy_to_2pt_conical_focal_on_circle,
118118
xy_to_2pt_conical_well_behaved,
119+
xy_to_2pt_conical_smaller,
119120
xy_to_2pt_conical_greater,
121+
xy_to_2pt_conical_strip,
122+
mask_2pt_conical_nan,
120123
mask_2pt_conical_degenerates,
121124
apply_vector_mask,
125+
alter_2pt_conical_compensate_focal,
126+
alter_2pt_conical_unswap,
127+
negate_x,
128+
apply_concentric_scale_bias,
122129
gamma_expand_2,
123130
gamma_expand_dst_2,
124131
gamma_compress_2,
@@ -1017,25 +1024,44 @@ fn xy_to_2pt_conical_greater(p: &mut Pipeline) {
10171024
p.next_stage();
10181025
}
10191026

1027+
fn xy_to_2pt_conical_smaller(p: &mut Pipeline) {
1028+
let ctx = &p.ctx.two_point_conical_gradient;
1029+
1030+
let x = p.r;
1031+
let y = p.g;
1032+
p.r = -(x * x - y * y).sqrt() - x * f32x8::splat(ctx.p0);
1033+
1034+
p.next_stage();
1035+
}
1036+
1037+
fn xy_to_2pt_conical_strip(p: &mut Pipeline) {
1038+
let ctx = &p.ctx.two_point_conical_gradient;
1039+
1040+
let x = p.r;
1041+
let y = p.g;
1042+
p.r = x + (f32x8::splat(ctx.p0) - y * y).sqrt();
1043+
1044+
p.next_stage();
1045+
}
1046+
1047+
fn mask_2pt_conical_nan(p: &mut Pipeline) {
1048+
let ctx = &mut p.ctx.two_point_conical_gradient;
1049+
1050+
let t = p.r;
1051+
let is_degenerate = t.cmp_ne(t);
1052+
p.r = is_degenerate.blend(f32x8::default(), t);
1053+
ctx.mask = cond_to_mask(!is_degenerate.to_u32x8_bitcast());
1054+
1055+
p.next_stage();
1056+
}
1057+
10201058
fn mask_2pt_conical_degenerates(p: &mut Pipeline) {
10211059
let ctx = &mut p.ctx.two_point_conical_gradient;
10221060

10231061
let t = p.r;
10241062
let is_degenerate = t.cmp_le(f32x8::default()) | t.cmp_ne(t);
10251063
p.r = is_degenerate.blend(f32x8::default(), t);
1026-
1027-
let is_not_degenerate = !is_degenerate.to_u32x8_bitcast();
1028-
let is_not_degenerate: [u32; 8] = bytemuck::cast(is_not_degenerate);
1029-
ctx.mask = bytemuck::cast([
1030-
if is_not_degenerate[0] != 0 { !0 } else { 0 },
1031-
if is_not_degenerate[1] != 0 { !0 } else { 0 },
1032-
if is_not_degenerate[2] != 0 { !0 } else { 0 },
1033-
if is_not_degenerate[3] != 0 { !0 } else { 0 },
1034-
if is_not_degenerate[4] != 0 { !0 } else { 0 },
1035-
if is_not_degenerate[5] != 0 { !0 } else { 0 },
1036-
if is_not_degenerate[6] != 0 { !0 } else { 0 },
1037-
if is_not_degenerate[7] != 0 { !0 } else { 0 },
1038-
]);
1064+
ctx.mask = cond_to_mask(!is_degenerate.to_u32x8_bitcast());
10391065

10401066
p.next_stage();
10411067
}
@@ -1051,6 +1077,36 @@ fn apply_vector_mask(p: &mut Pipeline) {
10511077
p.next_stage();
10521078
}
10531079

1080+
fn alter_2pt_conical_compensate_focal(p: &mut Pipeline) {
1081+
let ctx = &p.ctx.two_point_conical_gradient;
1082+
1083+
p.r = p.r + f32x8::splat(ctx.p1);
1084+
1085+
p.next_stage();
1086+
}
1087+
1088+
fn alter_2pt_conical_unswap(p: &mut Pipeline) {
1089+
p.r = f32x8::splat(1.0) - p.r;
1090+
1091+
p.next_stage();
1092+
}
1093+
1094+
fn negate_x(p: &mut Pipeline) {
1095+
p.r = -p.r;
1096+
1097+
p.next_stage();
1098+
}
1099+
1100+
fn apply_concentric_scale_bias(p: &mut Pipeline) {
1101+
let ctx = &p.ctx.two_point_conical_gradient;
1102+
1103+
// Apply t = t * scale + bias for concentric gradients
1104+
let x = p.r;
1105+
p.r = x * f32x8::splat(ctx.p0) + f32x8::splat(ctx.p1);
1106+
1107+
p.next_stage();
1108+
}
1109+
10541110
fn gamma_expand_2(p: &mut Pipeline) {
10551111
p.r = p.r * p.r;
10561112
p.g = p.g * p.g;
@@ -1141,6 +1197,21 @@ pub fn just_return(_: &mut Pipeline) {
11411197
// Ends the loop.
11421198
}
11431199

1200+
#[inline(always)]
1201+
fn cond_to_mask(cond: u32x8) -> u32x8 {
1202+
let cond: [u32; 8] = bytemuck::cast(cond);
1203+
bytemuck::cast([
1204+
if cond[0] != 0 { !0 } else { 0 },
1205+
if cond[1] != 0 { !0 } else { 0 },
1206+
if cond[2] != 0 { !0 } else { 0 },
1207+
if cond[3] != 0 { !0 } else { 0 },
1208+
if cond[4] != 0 { !0 } else { 0 },
1209+
if cond[5] != 0 { !0 } else { 0 },
1210+
if cond[6] != 0 { !0 } else { 0 },
1211+
if cond[7] != 0 { !0 } else { 0 },
1212+
])
1213+
}
1214+
11441215
#[inline(always)]
11451216
fn load_8888(
11461217
data: &[PremultipliedColorU8; STAGE_WIDTH],

src/pipeline/lowp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,16 @@ pub const STAGES: &[StageFn; super::STAGES_COUNT] = &[
129129
xy_to_radius,
130130
null_fn, // XYTo2PtConicalFocalOnCircle
131131
null_fn, // XYTo2PtConicalWellBehaved
132+
null_fn, // XYTo2PtConicalSmaller
132133
null_fn, // XYTo2PtConicalGreater
134+
null_fn, // XYTo2PtConicalStrip
135+
null_fn, // Mask2PtConicalNan
133136
null_fn, // Mask2PtConicalDegenerates
134137
null_fn, // ApplyVectorMask
138+
null_fn, // Alter2PtConicalCompensateFocal
139+
null_fn, // Alter2PtConicalUnswap
140+
null_fn, // NegateX
141+
null_fn, // ApplyConcentricScaleBias
135142
null_fn, // GammaExpand2
136143
null_fn, // GammaExpandDestination2
137144
null_fn, // GammaCompress2

src/pipeline/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,16 @@ pub enum Stage {
127127
XYToRadius,
128128
XYTo2PtConicalFocalOnCircle,
129129
XYTo2PtConicalWellBehaved,
130+
XYTo2PtConicalSmaller,
130131
XYTo2PtConicalGreater,
132+
XYTo2PtConicalStrip,
133+
Mask2PtConicalNan,
131134
Mask2PtConicalDegenerates,
132135
ApplyVectorMask,
136+
Alter2PtConicalCompensateFocal,
137+
Alter2PtConicalUnswap,
138+
NegateX,
139+
ApplyConcentricScaleBias,
133140
GammaExpand2,
134141
GammaExpandDestination2,
135142
GammaCompress2,
@@ -327,6 +334,7 @@ pub struct TwoPointConicalGradientCtx {
327334
// This context is used only in highp, where we use Tx4.
328335
pub mask: u32x8,
329336
pub p0: f32,
337+
pub p1: f32,
330338
}
331339

332340
#[derive(Copy, Clone, Default, Debug)]

0 commit comments

Comments
 (0)