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