SkBlendMode.cpp revision fb126fa96e0f49f5dc17a9a043acced68be99e93
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 "SkRasterPipeline.h"
10#include "../jumper/SkJumper.h"
11
12bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
13    switch (mode) {
14        case SkBlendMode::kDst:
15        case SkBlendMode::kSrcOver:
16        case SkBlendMode::kDstOver:
17        case SkBlendMode::kDstOut:
18        case SkBlendMode::kSrcATop:
19        case SkBlendMode::kXor:
20        case SkBlendMode::kPlus:
21            return true;
22        default:
23            break;
24    }
25    return false;
26}
27
28struct CoeffRec {
29    SkBlendModeCoeff    fSrc;
30    SkBlendModeCoeff    fDst;
31};
32
33const CoeffRec gCoeffs[] = {
34    { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero },
35    { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero },
36    { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  },
37    { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  },
38    { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  },
39    { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero },
40    { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   },
41    { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero },
42    { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  },
43    { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  },
44    { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   },
45    { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  },
46
47    { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  },
48    { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   },
49    { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  },    // screen
50};
51
52bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) {
53    if (mode > SkBlendMode::kScreen) {
54        return false;
55    }
56    if (src) {
57        *src = gCoeffs[static_cast<int>(mode)].fSrc;
58    }
59    if (dst) {
60        *dst = gCoeffs[static_cast<int>(mode)].fDst;
61    }
62    return true;
63}
64
65bool SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode, bool rgb_coverage) {
66    // The most important things we do here are:
67    //   - always use pre-scaling for plus mode;
68    //   - never use pre-scaling for srcover with 565 coverage.
69    return mode == SkBlendMode::kPlus ||
70          (mode == SkBlendMode::kSrcOver && !rgb_coverage);
71}
72
73void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) {
74    auto stage = SkRasterPipeline::srcover;
75    switch (mode) {
76        case SkBlendMode::kClear:    stage = SkRasterPipeline::clear; break;
77        case SkBlendMode::kSrc:      return;  // This stage is a no-op.
78        case SkBlendMode::kDst:      stage = SkRasterPipeline::move_dst_src; break;
79        case SkBlendMode::kSrcOver:  stage = SkRasterPipeline::srcover; break;
80        case SkBlendMode::kDstOver:  stage = SkRasterPipeline::dstover; break;
81        case SkBlendMode::kSrcIn:    stage = SkRasterPipeline::srcin; break;
82        case SkBlendMode::kDstIn:    stage = SkRasterPipeline::dstin; break;
83        case SkBlendMode::kSrcOut:   stage = SkRasterPipeline::srcout; break;
84        case SkBlendMode::kDstOut:   stage = SkRasterPipeline::dstout; break;
85        case SkBlendMode::kSrcATop:  stage = SkRasterPipeline::srcatop; break;
86        case SkBlendMode::kDstATop:  stage = SkRasterPipeline::dstatop; break;
87        case SkBlendMode::kXor:      stage = SkRasterPipeline::xor_; break;
88        case SkBlendMode::kPlus:     stage = SkRasterPipeline::plus_; break;
89        case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break;
90
91        case SkBlendMode::kScreen:     stage = SkRasterPipeline::screen; break;
92        case SkBlendMode::kOverlay:    stage = SkRasterPipeline::overlay; break;
93        case SkBlendMode::kDarken:     stage = SkRasterPipeline::darken; break;
94        case SkBlendMode::kLighten:    stage = SkRasterPipeline::lighten; break;
95        case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break;
96        case SkBlendMode::kColorBurn:  stage = SkRasterPipeline::colorburn; break;
97        case SkBlendMode::kHardLight:  stage = SkRasterPipeline::hardlight; break;
98        case SkBlendMode::kSoftLight:  stage = SkRasterPipeline::softlight; break;
99        case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break;
100        case SkBlendMode::kExclusion:  stage = SkRasterPipeline::exclusion; break;
101        case SkBlendMode::kMultiply:   stage = SkRasterPipeline::multiply; break;
102
103        case SkBlendMode::kHue:        stage = SkRasterPipeline::hue; break;
104        case SkBlendMode::kSaturation: stage = SkRasterPipeline::saturation; break;
105        case SkBlendMode::kColor:      stage = SkRasterPipeline::color; break;
106        case SkBlendMode::kLuminosity: stage = SkRasterPipeline::luminosity; break;
107    }
108    p->append(stage);
109}
110
111SkPM4f SkBlendMode_Apply(SkBlendMode mode, const SkPM4f& src, const SkPM4f& dst) {
112    // special-case simple/common modes...
113    switch (mode) {
114        case SkBlendMode::kClear:   return {{ 0, 0, 0, 0 }};
115        case SkBlendMode::kSrc:     return src;
116        case SkBlendMode::kDst:     return dst;
117        case SkBlendMode::kSrcOver:
118            return SkPM4f::From4f(src.to4f() + dst.to4f() * Sk4f(1 - src.a()));
119        default:
120            break;
121    }
122
123    SkRasterPipeline_<256> p;
124    SkPM4f                 src_storage = src,
125                           dst_storage = dst,
126                           res_storage;
127    SkJumper_MemoryCtx src_ctx = { &src_storage, 0 },
128                       dst_ctx = { &dst_storage, 0 },
129                       res_ctx = { &res_storage, 0 };
130
131    p.append(SkRasterPipeline::load_f32, &dst_ctx);
132    p.append(SkRasterPipeline::move_src_dst);
133    p.append(SkRasterPipeline::load_f32, &src_ctx);
134    SkBlendMode_AppendStages(mode, &p);
135    p.append(SkRasterPipeline::store_f32, &res_ctx);
136    p.run(0,0, 1,1);
137    return res_storage;
138}
139