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