| 1 | /* | 
|---|
| 2 | * Copyright 2017 Google Inc. | 
|---|
| 3 | * | 
|---|
| 4 | * Use of this source code is governed by a BSD-style license that can be | 
|---|
| 5 | * found in the LICENSE file. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #include "src/core/SkBlendModePriv.h" | 
|---|
| 9 | #include "src/core/SkCoverageModePriv.h" | 
|---|
| 10 | #include "src/core/SkRasterPipeline.h" | 
|---|
| 11 |  | 
|---|
| 12 | bool SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode, bool rgb_coverage) { | 
|---|
| 13 | // The most important things we do here are: | 
|---|
| 14 | //   1) never pre-scale with rgb coverage if the blend mode involves a source-alpha term; | 
|---|
| 15 | //   2) always pre-scale Plus. | 
|---|
| 16 | // | 
|---|
| 17 | // When we pre-scale with rgb coverage, we scale each of source r,g,b, with a distinct value, | 
|---|
| 18 | // and source alpha with one of those three values.  This process destructively updates the | 
|---|
| 19 | // source-alpha term, so we can't evaluate blend modes that need its original value. | 
|---|
| 20 | // | 
|---|
| 21 | // Plus always requires pre-scaling as a specific quirk of its implementation in | 
|---|
| 22 | // SkRasterPipeline.  This lets us put the clamp inside the blend mode itself rather | 
|---|
| 23 | // than as a separate stage that'd come after the lerp. | 
|---|
| 24 | // | 
|---|
| 25 | // This function is a finer-grained breakdown of SkBlendMode_SupportsCoverageAsAlpha(). | 
|---|
| 26 | switch (mode) { | 
|---|
| 27 | case SkBlendMode::kDst:        // d              --> no sa term, ok! | 
|---|
| 28 | case SkBlendMode::kDstOver:    // d + s*inv(da)  --> no sa term, ok! | 
|---|
| 29 | case SkBlendMode::kPlus:       // clamp(s+d)     --> no sa term, ok! | 
|---|
| 30 | return true; | 
|---|
| 31 |  | 
|---|
| 32 | case SkBlendMode::kDstOut:     // d * inv(sa) | 
|---|
| 33 | case SkBlendMode::kSrcATop:    // s*da + d*inv(sa) | 
|---|
| 34 | case SkBlendMode::kSrcOver:    // s + d*inv(sa) | 
|---|
| 35 | case SkBlendMode::kXor:        // s*inv(da) + d*inv(sa) | 
|---|
| 36 | return !rgb_coverage; | 
|---|
| 37 |  | 
|---|
| 38 | default: break; | 
|---|
| 39 | } | 
|---|
| 40 | return false; | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | // Users of this function may want to switch to the rgb-coverage aware version above. | 
|---|
| 44 | bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) { | 
|---|
| 45 | return SkBlendMode_ShouldPreScaleCoverage(mode, false); | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 | struct CoeffRec { | 
|---|
| 49 | SkBlendModeCoeff    fSrc; | 
|---|
| 50 | SkBlendModeCoeff    fDst; | 
|---|
| 51 | }; | 
|---|
| 52 |  | 
|---|
| 53 | const CoeffRec gCoeffs[] = { | 
|---|
| 54 | { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero }, | 
|---|
| 55 | { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero }, | 
|---|
| 56 | { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  }, | 
|---|
| 57 | { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  }, | 
|---|
| 58 | { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  }, | 
|---|
| 59 | { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero }, | 
|---|
| 60 | { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   }, | 
|---|
| 61 | { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero }, | 
|---|
| 62 | { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  }, | 
|---|
| 63 | { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  }, | 
|---|
| 64 | { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   }, | 
|---|
| 65 | { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  }, | 
|---|
| 66 |  | 
|---|
| 67 | { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  }, | 
|---|
| 68 | { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   }, | 
|---|
| 69 | { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  },    // screen | 
|---|
| 70 | }; | 
|---|
| 71 |  | 
|---|
| 72 | bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) { | 
|---|
| 73 | if (mode > SkBlendMode::kScreen) { | 
|---|
| 74 | return false; | 
|---|
| 75 | } | 
|---|
| 76 | if (src) { | 
|---|
| 77 | *src = gCoeffs[static_cast<int>(mode)].fSrc; | 
|---|
| 78 | } | 
|---|
| 79 | if (dst) { | 
|---|
| 80 | *dst = gCoeffs[static_cast<int>(mode)].fDst; | 
|---|
| 81 | } | 
|---|
| 82 | return true; | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) { | 
|---|
| 86 | auto stage = SkRasterPipeline::srcover; | 
|---|
| 87 | switch (mode) { | 
|---|
| 88 | case SkBlendMode::kClear:    stage = SkRasterPipeline::clear; break; | 
|---|
| 89 | case SkBlendMode::kSrc:      return;  // This stage is a no-op. | 
|---|
| 90 | case SkBlendMode::kDst:      stage = SkRasterPipeline::move_dst_src; break; | 
|---|
| 91 | case SkBlendMode::kSrcOver:  stage = SkRasterPipeline::srcover; break; | 
|---|
| 92 | case SkBlendMode::kDstOver:  stage = SkRasterPipeline::dstover; break; | 
|---|
| 93 | case SkBlendMode::kSrcIn:    stage = SkRasterPipeline::srcin; break; | 
|---|
| 94 | case SkBlendMode::kDstIn:    stage = SkRasterPipeline::dstin; break; | 
|---|
| 95 | case SkBlendMode::kSrcOut:   stage = SkRasterPipeline::srcout; break; | 
|---|
| 96 | case SkBlendMode::kDstOut:   stage = SkRasterPipeline::dstout; break; | 
|---|
| 97 | case SkBlendMode::kSrcATop:  stage = SkRasterPipeline::srcatop; break; | 
|---|
| 98 | case SkBlendMode::kDstATop:  stage = SkRasterPipeline::dstatop; break; | 
|---|
| 99 | case SkBlendMode::kXor:      stage = SkRasterPipeline::xor_; break; | 
|---|
| 100 | case SkBlendMode::kPlus:     stage = SkRasterPipeline::plus_; break; | 
|---|
| 101 | case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break; | 
|---|
| 102 |  | 
|---|
| 103 | case SkBlendMode::kScreen:     stage = SkRasterPipeline::screen; break; | 
|---|
| 104 | case SkBlendMode::kOverlay:    stage = SkRasterPipeline::overlay; break; | 
|---|
| 105 | case SkBlendMode::kDarken:     stage = SkRasterPipeline::darken; break; | 
|---|
| 106 | case SkBlendMode::kLighten:    stage = SkRasterPipeline::lighten; break; | 
|---|
| 107 | case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break; | 
|---|
| 108 | case SkBlendMode::kColorBurn:  stage = SkRasterPipeline::colorburn; break; | 
|---|
| 109 | case SkBlendMode::kHardLight:  stage = SkRasterPipeline::hardlight; break; | 
|---|
| 110 | case SkBlendMode::kSoftLight:  stage = SkRasterPipeline::softlight; break; | 
|---|
| 111 | case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break; | 
|---|
| 112 | case SkBlendMode::kExclusion:  stage = SkRasterPipeline::exclusion; break; | 
|---|
| 113 | case SkBlendMode::kMultiply:   stage = SkRasterPipeline::multiply; break; | 
|---|
| 114 |  | 
|---|
| 115 | case SkBlendMode::kHue:        stage = SkRasterPipeline::hue; break; | 
|---|
| 116 | case SkBlendMode::kSaturation: stage = SkRasterPipeline::saturation; break; | 
|---|
| 117 | case SkBlendMode::kColor:      stage = SkRasterPipeline::color; break; | 
|---|
| 118 | case SkBlendMode::kLuminosity: stage = SkRasterPipeline::luminosity; break; | 
|---|
| 119 | } | 
|---|
| 120 | p->append(stage); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f& src, const SkPMColor4f& dst) { | 
|---|
| 124 | // special-case simple/common modes... | 
|---|
| 125 | switch (mode) { | 
|---|
| 126 | case SkBlendMode::kClear:   return SK_PMColor4fTRANSPARENT; | 
|---|
| 127 | case SkBlendMode::kSrc:     return src; | 
|---|
| 128 | case SkBlendMode::kDst:     return dst; | 
|---|
| 129 | case SkBlendMode::kSrcOver: { | 
|---|
| 130 | Sk4f r = Sk4f::Load(src.vec()) + Sk4f::Load(dst.vec()) * Sk4f(1 - src.fA); | 
|---|
| 131 | return { r[0], r[1], r[2], r[3] }; | 
|---|
| 132 | } | 
|---|
| 133 | default: | 
|---|
| 134 | break; | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | SkRasterPipeline_<256> p; | 
|---|
| 138 | SkPMColor4f            src_storage = src, | 
|---|
| 139 | dst_storage = dst, | 
|---|
| 140 | res_storage; | 
|---|
| 141 | SkRasterPipeline_MemoryCtx src_ctx = { &src_storage, 0 }, | 
|---|
| 142 | dst_ctx = { &dst_storage, 0 }, | 
|---|
| 143 | res_ctx = { &res_storage, 0 }; | 
|---|
| 144 |  | 
|---|
| 145 | p.append(SkRasterPipeline::load_f32, &dst_ctx); | 
|---|
| 146 | p.append(SkRasterPipeline::move_src_dst); | 
|---|
| 147 | p.append(SkRasterPipeline::load_f32, &src_ctx); | 
|---|
| 148 | SkBlendMode_AppendStages(mode, &p); | 
|---|
| 149 | p.append(SkRasterPipeline::store_f32, &res_ctx); | 
|---|
| 150 | p.run(0,0, 1,1); | 
|---|
| 151 | return res_storage; | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 155 |  | 
|---|
| 156 | const SkBlendMode gUncorrelatedCoverageToBlend[] = { | 
|---|
| 157 | SkBlendMode::kSrcOver,  // or DstOver | 
|---|
| 158 | SkBlendMode::kSrcIn,    // or kDstIn | 
|---|
| 159 | SkBlendMode::kSrcOut, | 
|---|
| 160 | SkBlendMode::kDstOut, | 
|---|
| 161 | SkBlendMode::kXor, | 
|---|
| 162 | }; | 
|---|
| 163 |  | 
|---|
| 164 | SkBlendMode SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode cm) { | 
|---|
| 165 | unsigned index = static_cast<unsigned>(cm); | 
|---|
| 166 | SkASSERT(index < SK_ARRAY_COUNT(gUncorrelatedCoverageToBlend)); | 
|---|
| 167 | return gUncorrelatedCoverageToBlend[index]; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|