tiny_skia/blend_mode.rs
1use crate::pipeline;
2
3/// A blending mode.
4#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Debug)]
5pub enum BlendMode {
6 /// Replaces destination with zero: fully transparent.
7 Clear,
8 /// Replaces destination.
9 Source,
10 /// Preserves destination.
11 Destination,
12 /// Source over destination.
13 #[default]
14 SourceOver,
15 /// Destination over source.
16 DestinationOver,
17 /// Source trimmed inside destination.
18 SourceIn,
19 /// Destination trimmed by source.
20 DestinationIn,
21 /// Source trimmed outside destination.
22 SourceOut,
23 /// Destination trimmed outside source.
24 DestinationOut,
25 /// Source inside destination blended with destination.
26 SourceAtop,
27 /// Destination inside source blended with source.
28 DestinationAtop,
29 /// Each of source and destination trimmed outside the other.
30 Xor,
31 /// Sum of colors.
32 Plus,
33 /// Product of premultiplied colors; darkens destination.
34 Modulate,
35 /// Multiply inverse of pixels, inverting result; brightens destination.
36 Screen,
37 /// Multiply or screen, depending on destination.
38 Overlay,
39 /// Darker of source and destination.
40 Darken,
41 /// Lighter of source and destination.
42 Lighten,
43 /// Brighten destination to reflect source.
44 ColorDodge,
45 /// Darken destination to reflect source.
46 ColorBurn,
47 /// Multiply or screen, depending on source.
48 HardLight,
49 /// Lighten or darken, depending on source.
50 SoftLight,
51 /// Subtract darker from lighter with higher contrast.
52 Difference,
53 /// Subtract darker from lighter with lower contrast.
54 Exclusion,
55 /// Multiply source with destination, darkening image.
56 Multiply,
57 /// Hue of source with saturation and luminosity of destination.
58 Hue,
59 /// Saturation of source with hue and luminosity of destination.
60 Saturation,
61 /// Hue and saturation of source with luminosity of destination.
62 Color,
63 /// Luminosity of source with hue and saturation of destination.
64 Luminosity,
65}
66
67impl BlendMode {
68 pub(crate) fn should_pre_scale_coverage(self) -> bool {
69 // The most important things we do here are:
70 // 1) never pre-scale with rgb coverage if the blend mode involves a source-alpha term;
71 // 2) always pre-scale Plus.
72 //
73 // When we pre-scale with rgb coverage, we scale each of source r,g,b, with a distinct value,
74 // and source alpha with one of those three values. This process destructively updates the
75 // source-alpha term, so we can't evaluate blend modes that need its original value.
76 //
77 // Plus always requires pre-scaling as a specific quirk of its implementation in
78 // RasterPipeline. This lets us put the clamp inside the blend mode itself rather
79 // than as a separate stage that'd come after the lerp.
80 //
81 // This function is a finer-grained breakdown of SkBlendMode_SupportsCoverageAsAlpha().
82 matches!(
83 self,
84 BlendMode::Destination | // d --> no sa term, ok!
85 BlendMode::DestinationOver | // d + s*inv(da) --> no sa term, ok!
86 BlendMode::Plus | // clamp(s+d) --> no sa term, ok!
87 BlendMode::DestinationOut | // d * inv(sa)
88 BlendMode::SourceAtop | // s*da + d*inv(sa)
89 BlendMode::SourceOver | // s + d*inv(sa)
90 BlendMode::Xor // s*inv(da) + d*inv(sa)
91 )
92 }
93
94 pub(crate) fn to_stage(self) -> Option<pipeline::Stage> {
95 match self {
96 BlendMode::Clear => Some(pipeline::Stage::Clear),
97 BlendMode::Source => None, // This stage is a no-op.
98 BlendMode::Destination => Some(pipeline::Stage::MoveDestinationToSource),
99 BlendMode::SourceOver => Some(pipeline::Stage::SourceOver),
100 BlendMode::DestinationOver => Some(pipeline::Stage::DestinationOver),
101 BlendMode::SourceIn => Some(pipeline::Stage::SourceIn),
102 BlendMode::DestinationIn => Some(pipeline::Stage::DestinationIn),
103 BlendMode::SourceOut => Some(pipeline::Stage::SourceOut),
104 BlendMode::DestinationOut => Some(pipeline::Stage::DestinationOut),
105 BlendMode::SourceAtop => Some(pipeline::Stage::SourceAtop),
106 BlendMode::DestinationAtop => Some(pipeline::Stage::DestinationAtop),
107 BlendMode::Xor => Some(pipeline::Stage::Xor),
108 BlendMode::Plus => Some(pipeline::Stage::Plus),
109 BlendMode::Modulate => Some(pipeline::Stage::Modulate),
110 BlendMode::Screen => Some(pipeline::Stage::Screen),
111 BlendMode::Overlay => Some(pipeline::Stage::Overlay),
112 BlendMode::Darken => Some(pipeline::Stage::Darken),
113 BlendMode::Lighten => Some(pipeline::Stage::Lighten),
114 BlendMode::ColorDodge => Some(pipeline::Stage::ColorDodge),
115 BlendMode::ColorBurn => Some(pipeline::Stage::ColorBurn),
116 BlendMode::HardLight => Some(pipeline::Stage::HardLight),
117 BlendMode::SoftLight => Some(pipeline::Stage::SoftLight),
118 BlendMode::Difference => Some(pipeline::Stage::Difference),
119 BlendMode::Exclusion => Some(pipeline::Stage::Exclusion),
120 BlendMode::Multiply => Some(pipeline::Stage::Multiply),
121 BlendMode::Hue => Some(pipeline::Stage::Hue),
122 BlendMode::Saturation => Some(pipeline::Stage::Saturation),
123 BlendMode::Color => Some(pipeline::Stage::Color),
124 BlendMode::Luminosity => Some(pipeline::Stage::Luminosity),
125 }
126 }
127}