• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode,bool rgb_coverage)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.
SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode)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 
SkBlendMode_AsCoeff(SkBlendMode mode,SkBlendModeCoeff * src,SkBlendModeCoeff * dst)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 
SkBlendMode_AppendStages(SkBlendMode mode,SkRasterPipeline * p)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 
SkBlendMode_Apply(SkBlendMode mode,const SkPMColor4f & src,const SkPMColor4f & dst)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 
SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode cm)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