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 "SkArenaAlloc.h" 9 #include "SkColorFilter.h" 10 #include "SkColorSpaceXformer.h" 11 #include "SkNx.h" 12 #include "SkPM4f.h" 13 #include "SkRasterPipeline.h" 14 #include "SkReadBuffer.h" 15 #include "SkRefCnt.h" 16 #include "SkString.h" 17 #include "SkTDArray.h" 18 #include "SkUnPreMultiply.h" 19 #include "SkWriteBuffer.h" 20 #include "../jumper/SkJumper.h" 21 22 #if SK_SUPPORT_GPU 23 #include "GrFragmentProcessor.h" 24 #endif 25 26 bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const { 27 return false; 28 } 29 30 bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const { 31 return false; 32 } 33 34 bool SkColorFilter::asComponentTable(SkBitmap*) const { 35 return false; 36 } 37 38 #if SK_SUPPORT_GPU 39 sk_sp<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const { 40 return nullptr; 41 } 42 #endif 43 44 void SkColorFilter::appendStages(SkRasterPipeline* p, 45 SkColorSpace* dstCS, 46 SkArenaAlloc* alloc, 47 bool shaderIsOpaque) const { 48 this->onAppendStages(p, dstCS, alloc, shaderIsOpaque); 49 } 50 51 SkColor SkColorFilter::filterColor(SkColor c) const { 52 const float inv255 = 1.0f / 255; 53 SkColor4f c4 = this->filterColor4f({ 54 SkColorGetR(c) * inv255, 55 SkColorGetG(c) * inv255, 56 SkColorGetB(c) * inv255, 57 SkColorGetA(c) * inv255, 58 }); 59 return SkColorSetARGB(sk_float_round2int(c4.fA*255), 60 sk_float_round2int(c4.fR*255), 61 sk_float_round2int(c4.fG*255), 62 sk_float_round2int(c4.fB*255)); 63 } 64 65 #include "SkRasterPipeline.h" 66 SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c) const { 67 SkPM4f dst, src = c.premul(); 68 69 SkSTArenaAlloc<128> alloc; 70 SkRasterPipeline pipeline(&alloc); 71 72 pipeline.append_uniform_color(&alloc, src); 73 this->onAppendStages(&pipeline, nullptr, &alloc, c.fA == 1); 74 SkPM4f* dstPtr = &dst; 75 pipeline.append(SkRasterPipeline::store_f32, &dstPtr); 76 pipeline.run(0,0, 1); 77 78 return dst.unpremul(); 79 } 80 81 /////////////////////////////////////////////////////////////////////////////////////////////////// 82 83 /* 84 * Since colorfilters may be used on the GPU backend, and in that case we may string together 85 * many GrFragmentProcessors, we might exceed some internal instruction/resource limit. 86 * 87 * Since we don't yet know *what* those limits might be when we construct the final shader, 88 * we just set an arbitrary limit during construction. If later we find smarter ways to know what 89 * the limnits are, we can change this constant (or remove it). 90 */ 91 #define SK_MAX_COMPOSE_COLORFILTER_COUNT 4 92 93 class SkComposeColorFilter : public SkColorFilter { 94 public: 95 uint32_t getFlags() const override { 96 // Can only claim alphaunchanged and SkPM4f support if both our proxys do. 97 return fOuter->getFlags() & fInner->getFlags(); 98 } 99 100 #ifndef SK_IGNORE_TO_STRING 101 void toString(SkString* str) const override { 102 SkString outerS, innerS; 103 fOuter->toString(&outerS); 104 fInner->toString(&innerS); 105 // These strings can be long. SkString::appendf has limitations. 106 str->append(SkStringPrintf("SkComposeColorFilter: outer(%s) inner(%s)", outerS.c_str(), 107 innerS.c_str())); 108 } 109 #endif 110 111 void onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkArenaAlloc* scratch, 112 bool shaderIsOpaque) const override { 113 bool innerIsOpaque = shaderIsOpaque; 114 if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) { 115 innerIsOpaque = false; 116 } 117 fInner->appendStages(p, dst, scratch, shaderIsOpaque); 118 fOuter->appendStages(p, dst, scratch, innerIsOpaque); 119 } 120 121 #if SK_SUPPORT_GPU 122 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* context, 123 SkColorSpace* dstColorSpace) const override { 124 sk_sp<GrFragmentProcessor> innerFP(fInner->asFragmentProcessor(context, dstColorSpace)); 125 sk_sp<GrFragmentProcessor> outerFP(fOuter->asFragmentProcessor(context, dstColorSpace)); 126 if (!innerFP || !outerFP) { 127 return nullptr; 128 } 129 sk_sp<GrFragmentProcessor> series[] = { std::move(innerFP), std::move(outerFP) }; 130 return GrFragmentProcessor::RunInSeries(series, 2); 131 } 132 #endif 133 134 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeColorFilter) 135 136 protected: 137 void flatten(SkWriteBuffer& buffer) const override { 138 buffer.writeFlattenable(fOuter.get()); 139 buffer.writeFlattenable(fInner.get()); 140 } 141 142 private: 143 SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner, 144 int composedFilterCount) 145 : fOuter(std::move(outer)) 146 , fInner(std::move(inner)) 147 , fComposedFilterCount(composedFilterCount) 148 { 149 SkASSERT(composedFilterCount >= 2); 150 SkASSERT(composedFilterCount <= SK_MAX_COMPOSE_COLORFILTER_COUNT); 151 } 152 153 int privateComposedFilterCount() const override { 154 return fComposedFilterCount; 155 } 156 157 sk_sp<SkColorFilter> onMakeColorSpace(SkColorSpaceXformer* xformer) const override { 158 auto outer = xformer->apply(fOuter.get()); 159 auto inner = xformer->apply(fInner.get()); 160 if (outer != fOuter || inner != fInner) { 161 return SkColorFilter::MakeComposeFilter(outer, inner); 162 } 163 return this->INHERITED::onMakeColorSpace(xformer); 164 } 165 166 sk_sp<SkColorFilter> fOuter; 167 sk_sp<SkColorFilter> fInner; 168 const int fComposedFilterCount; 169 170 friend class SkColorFilter; 171 172 typedef SkColorFilter INHERITED; 173 }; 174 175 sk_sp<SkFlattenable> SkComposeColorFilter::CreateProc(SkReadBuffer& buffer) { 176 sk_sp<SkColorFilter> outer(buffer.readColorFilter()); 177 sk_sp<SkColorFilter> inner(buffer.readColorFilter()); 178 return MakeComposeFilter(std::move(outer), std::move(inner)); 179 } 180 181 sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer, 182 sk_sp<SkColorFilter> inner) { 183 if (!outer) { 184 return inner; 185 } 186 if (!inner) { 187 return outer; 188 } 189 190 // Give the subclass a shot at a more optimal composition... 191 auto composition = outer->makeComposed(inner); 192 if (composition) { 193 return composition; 194 } 195 196 int count = inner->privateComposedFilterCount() + outer->privateComposedFilterCount(); 197 if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) { 198 return nullptr; 199 } 200 return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count)); 201 } 202 203 /////////////////////////////////////////////////////////////////////////////////////////////////// 204 205 #if SK_SUPPORT_GPU 206 #include "../gpu/effects/GrSRGBEffect.h" 207 #endif 208 209 class SkSRGBGammaColorFilter : public SkColorFilter { 210 public: 211 enum class Direction { 212 kLinearToSRGB, 213 kSRGBToLinear, 214 }; 215 SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {} 216 217 #if SK_SUPPORT_GPU 218 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext* x, SkColorSpace* cs) const override { 219 // wish our caller would let us know if our input was opaque... 220 GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul; 221 switch (fDir) { 222 case Direction::kLinearToSRGB: 223 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha); 224 case Direction::kSRGBToLinear: 225 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha); 226 } 227 return nullptr; 228 } 229 #endif 230 231 SK_TO_STRING_OVERRIDE() 232 233 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter) 234 235 void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc, 236 bool shaderIsOpaque) const override { 237 if (!shaderIsOpaque) { 238 p->append(SkRasterPipeline::unpremul); 239 } 240 switch (fDir) { 241 case Direction::kLinearToSRGB: 242 p->append(SkRasterPipeline::to_srgb); 243 break; 244 case Direction::kSRGBToLinear: 245 p->append_from_srgb(shaderIsOpaque ? kOpaque_SkAlphaType : kUnpremul_SkAlphaType); 246 break; 247 } 248 if (!shaderIsOpaque) { 249 p->append(SkRasterPipeline::premul); 250 } 251 } 252 253 protected: 254 void flatten(SkWriteBuffer& buffer) const override { 255 buffer.write32(static_cast<uint32_t>(fDir)); 256 } 257 258 private: 259 const Direction fDir; 260 261 friend class SkColorFilter; 262 typedef SkColorFilter INHERITED; 263 }; 264 265 sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) { 266 uint32_t dir = buffer.read32(); 267 if (dir <= 1) { 268 return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir))); 269 } 270 buffer.validate(false); 271 return nullptr; 272 } 273 274 #ifndef SK_IGNORE_TO_STRING 275 void SkSRGBGammaColorFilter::toString(SkString* str) const { 276 str->append("srgbgamma"); 277 } 278 #endif 279 280 template <SkSRGBGammaColorFilter::Direction dir> 281 sk_sp<SkColorFilter> MakeSRGBGammaCF() { 282 static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); 283 return sk_ref_sp(gSingleton); 284 } 285 286 sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() { 287 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>(); 288 } 289 290 sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() { 291 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>(); 292 } 293 294 /////////////////////////////////////////////////////////////////////////////////////////////////// 295 296 #include "SkModeColorFilter.h" 297 298 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter) 299 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter) 300 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) 301 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter) 302 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 303