1/*
2 * Copyright 2006 The Android Open Source Project
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 "include/core/SkColorFilter.h"
9#include "include/core/SkString.h"
10#include "include/private/SkColorData.h"
11#include "include/utils/SkRandom.h"
12#include "src/core/SkArenaAlloc.h"
13#include "src/core/SkBlendModePriv.h"
14#include "src/core/SkBlitRow.h"
15#include "src/core/SkColorSpacePriv.h"
16#include "src/core/SkColorSpaceXformSteps.h"
17#include "src/core/SkModeColorFilter.h"
18#include "src/core/SkRasterPipeline.h"
19#include "src/core/SkReadBuffer.h"
20#include "src/core/SkVM.h"
21#include "src/core/SkValidationUtils.h"
22#include "src/core/SkWriteBuffer.h"
23
24//////////////////////////////////////////////////////////////////////////////////////////////////
25
26SkModeColorFilter::SkModeColorFilter(SkColor color, SkBlendMode mode) {
27 fColor = color;
28 fMode = mode;
29}
30
31bool SkModeColorFilter::onAsAColorMode(SkColor* color, SkBlendMode* mode) const {
32 if (color) {
33 *color = fColor;
34 }
35 if (mode) {
36 *mode = fMode;
37 }
38 return true;
39}
40
41uint32_t SkModeColorFilter::getFlags() const {
42 uint32_t flags = 0;
43 switch (fMode) {
44 case SkBlendMode::kDst: //!< [Da, Dc]
45 case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc]
46 flags |= kAlphaUnchanged_Flag;
47 default:
48 break;
49 }
50 return flags;
51}
52
53void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const {
54 buffer.writeColor(fColor);
55 buffer.writeUInt((int)fMode);
56}
57
58sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
59 SkColor color = buffer.readColor();
60 SkBlendMode mode = (SkBlendMode)buffer.readUInt();
61 return SkColorFilters::Blend(color, mode);
62}
63
64bool SkModeColorFilter::onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
65 rec.fPipeline->append(SkRasterPipeline::move_src_dst);
66 SkColor4f color = SkColor4f::FromColor(fColor);
67 SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
68 rec.fDstCS, kUnpremul_SkAlphaType).apply(color.vec());
69 rec.fPipeline->append_constant_color(rec.fAlloc, color.premul().vec());
70 SkBlendMode_AppendStages(fMode, rec.fPipeline);
71 return true;
72}
73
74skvm::Color SkModeColorFilter::onProgram(skvm::Builder* p, skvm::Color c,
75 SkColorSpace* dstCS,
76 skvm::Uniforms* uniforms, SkArenaAlloc*) const {
77 skvm::Color dst = c,
78 src = p->uniformPremul(SkColor4f::FromColor(fColor), sk_srgb_singleton(),
79 uniforms, dstCS);
80 return p->blend(fMode, src,dst);
81}
82
83///////////////////////////////////////////////////////////////////////////////
84#if SK_SUPPORT_GPU
85#include "src/gpu/GrBlend.h"
86#include "src/gpu/SkGr.h"
87#include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
88#include "src/gpu/effects/generated/GrConstColorProcessor.h"
89
90std::unique_ptr<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor(
91 GrRecordingContext*, const GrColorInfo& dstColorInfo) const {
92 if (SkBlendMode::kDst == fMode) {
93 return nullptr;
94 }
95
96 auto constFP = GrConstColorProcessor::Make(SkColorToPMColor4f(fColor, dstColorInfo),
97 GrConstColorProcessor::InputMode::kIgnore);
98 auto fp = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode);
99 if (!fp) {
100 return nullptr;
101 }
102#ifdef SK_DEBUG
103 // With a solid color input this should always be able to compute the blended color
104 // (at least for coeff modes)
105 if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) {
106 SkASSERT(fp->hasConstantOutputForConstantInput());
107 }
108#endif
109 return fp;
110}
111
112#endif
113
114///////////////////////////////////////////////////////////////////////////////
115
116sk_sp<SkColorFilter> SkColorFilters::Blend(SkColor color, SkBlendMode mode) {
117 if (!SkIsValidMode(mode)) {
118 return nullptr;
119 }
120
121 unsigned alpha = SkColorGetA(color);
122
123 // first collaps some modes if possible
124
125 if (SkBlendMode::kClear == mode) {
126 color = 0;
127 mode = SkBlendMode::kSrc;
128 } else if (SkBlendMode::kSrcOver == mode) {
129 if (0 == alpha) {
130 mode = SkBlendMode::kDst;
131 } else if (255 == alpha) {
132 mode = SkBlendMode::kSrc;
133 }
134 // else just stay srcover
135 }
136
137 // weed out combinations that are noops, and just return null
138 if (SkBlendMode::kDst == mode ||
139 (0 == alpha && (SkBlendMode::kSrcOver == mode ||
140 SkBlendMode::kDstOver == mode ||
141 SkBlendMode::kDstOut == mode ||
142 SkBlendMode::kSrcATop == mode ||
143 SkBlendMode::kXor == mode ||
144 SkBlendMode::kDarken == mode)) ||
145 (0xFF == alpha && SkBlendMode::kDstIn == mode)) {
146 return nullptr;
147 }
148
149 return SkModeColorFilter::Make(color, mode);
150}
151