Skip to main content

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}