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 SkColorFilter::MakeComposeFilter(outer, 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 MakeComposeFilter(std::move(outer), std::move(inner)); 180 } 181 182 sk_sp<SkColorFilter> SkColorFilter::MakeComposeFilter(sk_sp<SkColorFilter> outer, 183 sk_sp<SkColorFilter> inner) { 184 if (!outer) { 185 return inner; 186 } 187 if (!inner) { 188 return outer; 189 } 190 191 // Give the subclass a shot at a more optimal composition... 192 auto composition = outer->makeComposed(inner); 193 if (composition) { 194 return composition; 195 } 196 197 int count = inner->privateComposedFilterCount() + outer->privateComposedFilterCount(); 198 if (count > SK_MAX_COMPOSE_COLORFILTER_COUNT) { 199 return nullptr; 200 } 201 return sk_sp<SkColorFilter>(new SkComposeColorFilter(std::move(outer), std::move(inner),count)); 202 } 203 204 /////////////////////////////////////////////////////////////////////////////////////////////////// 205 206 #if SK_SUPPORT_GPU 207 #include "../gpu/effects/GrSRGBEffect.h" 208 #endif 209 210 class SkSRGBGammaColorFilter : public SkColorFilter { 211 public: 212 enum class Direction { 213 kLinearToSRGB, 214 kSRGBToLinear, 215 }; 216 SkSRGBGammaColorFilter(Direction dir) : fDir(dir) {} 217 218 #if SK_SUPPORT_GPU 219 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor( 220 GrContext*, const GrColorSpaceInfo&) const override { 221 // wish our caller would let us know if our input was opaque... 222 GrSRGBEffect::Alpha alpha = GrSRGBEffect::Alpha::kPremul; 223 switch (fDir) { 224 case Direction::kLinearToSRGB: 225 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kLinearToSRGB, alpha); 226 case Direction::kSRGBToLinear: 227 return GrSRGBEffect::Make(GrSRGBEffect::Mode::kSRGBToLinear, alpha); 228 } 229 return nullptr; 230 } 231 #endif 232 233 SK_TO_STRING_OVERRIDE() 234 235 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSRGBGammaColorFilter) 236 237 void onAppendStages(SkRasterPipeline* p, SkColorSpace*, SkArenaAlloc* alloc, 238 bool shaderIsOpaque) const override { 239 if (!shaderIsOpaque) { 240 p->append(SkRasterPipeline::unpremul); 241 } 242 switch (fDir) { 243 case Direction::kLinearToSRGB: 244 p->append(SkRasterPipeline::to_srgb); 245 break; 246 case Direction::kSRGBToLinear: 247 p->append(SkRasterPipeline::from_srgb); 248 break; 249 } 250 if (!shaderIsOpaque) { 251 p->append(SkRasterPipeline::premul); 252 } 253 } 254 255 protected: 256 void flatten(SkWriteBuffer& buffer) const override { 257 buffer.write32(static_cast<uint32_t>(fDir)); 258 } 259 260 private: 261 const Direction fDir; 262 263 friend class SkColorFilter; 264 typedef SkColorFilter INHERITED; 265 }; 266 267 sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) { 268 uint32_t dir = buffer.read32(); 269 if (dir <= 1) { 270 return sk_sp<SkFlattenable>(new SkSRGBGammaColorFilter(static_cast<Direction>(dir))); 271 } 272 buffer.validate(false); 273 return nullptr; 274 } 275 276 #ifndef SK_IGNORE_TO_STRING 277 void SkSRGBGammaColorFilter::toString(SkString* str) const { 278 str->append("srgbgamma"); 279 } 280 #endif 281 282 template <SkSRGBGammaColorFilter::Direction dir> 283 sk_sp<SkColorFilter> MakeSRGBGammaCF() { 284 static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); 285 return sk_ref_sp(gSingleton); 286 } 287 288 sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() { 289 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>(); 290 } 291 292 sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() { 293 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>(); 294 } 295 296 /////////////////////////////////////////////////////////////////////////////////////////////////// 297 298 #include "SkModeColorFilter.h" 299 300 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter) 301 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter) 302 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) 303 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter) 304 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 305