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 26bool SkColorFilter::asColorMode(SkColor*, SkBlendMode*) const { 27 return false; 28} 29 30bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) const { 31 return false; 32} 33 34bool SkColorFilter::asComponentTable(SkBitmap*) const { 35 return false; 36} 37 38#if SK_SUPPORT_GPU 39std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor( 40 GrContext*, const GrColorSpaceInfo&) const { 41 return nullptr; 42} 43#endif 44 45void SkColorFilter::appendStages(SkRasterPipeline* p, 46 SkColorSpace* dstCS, 47 SkArenaAlloc* alloc, 48 bool shaderIsOpaque) const { 49 this->onAppendStages(p, dstCS, alloc, shaderIsOpaque); 50} 51 52SkColor 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" 67SkColor4f 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 94class SkComposeColorFilter : public SkColorFilter { 95public: 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 137protected: 138 void flatten(SkWriteBuffer& buffer) const override { 139 buffer.writeFlattenable(fOuter.get()); 140 buffer.writeFlattenable(fInner.get()); 141 } 142 143private: 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 176sk_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 182sk_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 210class SkSRGBGammaColorFilter : public SkColorFilter { 211public: 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 255protected: 256 void flatten(SkWriteBuffer& buffer) const override { 257 buffer.write32(static_cast<uint32_t>(fDir)); 258 } 259 260private: 261 const Direction fDir; 262 263 friend class SkColorFilter; 264 typedef SkColorFilter INHERITED; 265}; 266 267sk_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 277void SkSRGBGammaColorFilter::toString(SkString* str) const { 278 str->append("srgbgamma"); 279} 280#endif 281 282template <SkSRGBGammaColorFilter::Direction dir> 283sk_sp<SkColorFilter> MakeSRGBGammaCF() { 284 static SkColorFilter* gSingleton = new SkSRGBGammaColorFilter(dir); 285 return sk_ref_sp(gSingleton); 286} 287 288sk_sp<SkColorFilter> SkColorFilter::MakeLinearToSRGBGamma() { 289 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kLinearToSRGB>(); 290} 291 292sk_sp<SkColorFilter> SkColorFilter::MakeSRGBToLinearGamma() { 293 return MakeSRGBGammaCF<SkSRGBGammaColorFilter::Direction::kSRGBToLinear>(); 294} 295 296/////////////////////////////////////////////////////////////////////////////////////////////////// 297 298#include "SkModeColorFilter.h" 299 300SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter) 301SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeColorFilter) 302SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter) 303SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSRGBGammaColorFilter) 304SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 305