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