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