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 | |
26 | SkModeColorFilter::SkModeColorFilter(SkColor color, SkBlendMode mode) { |
27 | fColor = color; |
28 | fMode = mode; |
29 | } |
30 | |
31 | bool 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 | |
41 | uint32_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 | |
53 | void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const { |
54 | buffer.writeColor(fColor); |
55 | buffer.writeUInt((int)fMode); |
56 | } |
57 | |
58 | sk_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 | |
64 | bool 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 | |
74 | skvm::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 | |
90 | std::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 | |
116 | sk_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 | |