Skip to content

Commit 95993a9

Browse files
committed
Support 2 point conical gradient
This is a straight port from Skia
1 parent f046014 commit 95993a9

9 files changed

Lines changed: 463 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ 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 (`ConicalGradient`).
10+
811

912
## [0.11.4] - 2024-02-04
1013
### Fixed

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/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub use mask::{Mask, MaskType};
6363
pub use painter::{FillRule, Paint};
6464
pub use pixmap::{Pixmap, PixmapMut, PixmapRef, BYTES_PER_PIXEL};
6565
pub use shaders::{FilterQuality, GradientStop, PixmapPaint, SpreadMode};
66-
pub use shaders::{LinearGradient, Pattern, RadialGradient, Shader};
66+
pub use shaders::{LinearGradient, Pattern, RadialGradient, ConicalGradient, Shader};
6767

6868
pub use tiny_skia_path::{IntRect, IntSize, NonZeroRect, Point, Rect, Size, Transform};
6969
pub use tiny_skia_path::{LineCap, LineJoin, Stroke, StrokeDash};

src/pipeline/highp.rs

Lines changed: 88 additions & 7 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,16 +1024,34 @@ fn xy_to_2pt_conical_greater(p: &mut Pipeline) {
10171024
p.next_stage();
10181025
}
10191026

1020-
fn mask_2pt_conical_degenerates(p: &mut Pipeline) {
1021-
let ctx = &mut p.ctx.two_point_conical_gradient;
1027+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3625;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1028+
fn xy_to_2pt_conical_smaller(p: &mut Pipeline) {
1029+
let ctx = &p.ctx.two_point_conical_gradient;
10221030

1023-
let t = p.r;
1024-
let is_degenerate = t.cmp_le(f32x8::default()) | t.cmp_ne(t);
1025-
p.r = is_degenerate.blend(f32x8::default(), t);
1031+
let x = p.r;
1032+
let y = p.g;
1033+
p.r = -(x * x - y * y).sqrt() - x * f32x8::splat(ctx.p0);
1034+
1035+
p.next_stage();
1036+
}
1037+
1038+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3605;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1039+
fn xy_to_2pt_conical_strip(p: &mut Pipeline) {
1040+
let ctx = &p.ctx.two_point_conical_gradient;
1041+
1042+
let x = p.r;
1043+
let y = p.g;
1044+
p.r = x + (f32x8::splat(ctx.p0) - y * y).sqrt();
1045+
1046+
p.next_stage();
1047+
}
10261048

1049+
1050+
#[inline]
1051+
fn mask_2pt_conical_from_degenerate(is_degenerate: f32x8) -> u32x8 {
10271052
let is_not_degenerate = !is_degenerate.to_u32x8_bitcast();
10281053
let is_not_degenerate: [u32; 8] = bytemuck::cast(is_not_degenerate);
1029-
ctx.mask = bytemuck::cast([
1054+
bytemuck::cast([
10301055
if is_not_degenerate[0] != 0 { !0 } else { 0 },
10311056
if is_not_degenerate[1] != 0 { !0 } else { 0 },
10321057
if is_not_degenerate[2] != 0 { !0 } else { 0 },
@@ -1035,7 +1060,29 @@ fn mask_2pt_conical_degenerates(p: &mut Pipeline) {
10351060
if is_not_degenerate[5] != 0 { !0 } else { 0 },
10361061
if is_not_degenerate[6] != 0 { !0 } else { 0 },
10371062
if is_not_degenerate[7] != 0 { !0 } else { 0 },
1038-
]);
1063+
])
1064+
}
1065+
1066+
1067+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3641;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1068+
fn mask_2pt_conical_nan(p: &mut Pipeline) {
1069+
let ctx = &mut p.ctx.two_point_conical_gradient;
1070+
1071+
let t = p.r;
1072+
let is_degenerate = t.cmp_ne(t);
1073+
p.r = is_degenerate.blend(f32x8::default(), t);
1074+
ctx.mask = mask_2pt_conical_from_degenerate(is_degenerate);
1075+
1076+
p.next_stage();
1077+
}
1078+
1079+
fn mask_2pt_conical_degenerates(p: &mut Pipeline) {
1080+
let ctx = &mut p.ctx.two_point_conical_gradient;
1081+
1082+
let t = p.r;
1083+
let is_degenerate = t.cmp_le(f32x8::default()) | t.cmp_ne(t);
1084+
p.r = is_degenerate.blend(f32x8::default(), t);
1085+
ctx.mask = mask_2pt_conical_from_degenerate(is_degenerate);
10391086

10401087
p.next_stage();
10411088
}
@@ -1051,6 +1098,40 @@ fn apply_vector_mask(p: &mut Pipeline) {
10511098
p.next_stage();
10521099
}
10531100

1101+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3630;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1102+
fn alter_2pt_conical_compensate_focal(p: &mut Pipeline) {
1103+
let ctx = &p.ctx.two_point_conical_gradient;
1104+
1105+
p.r = p.r + f32x8::splat(ctx.p1);
1106+
1107+
p.next_stage();
1108+
}
1109+
1110+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3636;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1111+
fn alter_2pt_conical_unswap(p: &mut Pipeline) {
1112+
p.r = f32x8::splat(1.0) - p.r;
1113+
1114+
p.next_stage();
1115+
}
1116+
1117+
// From: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/opts/SkRasterPipeline_opts.h;l=3603;drc=d5c02fd369596fb4a6fa563f5506ff71ff7299ed
1118+
fn negate_x(p: &mut Pipeline) {
1119+
p.r = -p.r;
1120+
1121+
p.next_stage();
1122+
}
1123+
1124+
// Applies the matrix operation from: https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/shaders/gradients/SkConicalGradient.cpp;l=206;drc=075316994c97ee86961b369bb2bff246aaa9d6c4
1125+
fn apply_concentric_scale_bias(p: &mut Pipeline) {
1126+
let ctx = &p.ctx.two_point_conical_gradient;
1127+
1128+
// Apply t = t * scale + bias for concentric gradients
1129+
let x = p.r;
1130+
p.r = x * f32x8::splat(ctx.p0) + f32x8::splat(ctx.p1);
1131+
1132+
p.next_stage();
1133+
}
1134+
10541135
fn gamma_expand_2(p: &mut Pipeline) {
10551136
p.r = p.r * p.r;
10561137
p.g = p.g * p.g;

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)