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 "SkBlendModePriv.h" 10 #include "SkBlitRow.h" 11 #include "SkColorFilter.h" 12 #include "SkColorData.h" 13 #include "SkColorSpaceXformer.h" 14 #include "SkModeColorFilter.h" 15 #include "SkPM4f.h" 16 #include "SkPM4fPriv.h" 17 #include "SkRandom.h" 18 #include "SkRasterPipeline.h" 19 #include "SkReadBuffer.h" 20 #include "SkString.h" 21 #include "SkUtils.h" 22 #include "SkValidationUtils.h" 23 #include "SkWriteBuffer.h" 24 25 ////////////////////////////////////////////////////////////////////////////////////////////////// 26 27 SkModeColorFilter::SkModeColorFilter(SkColor color, SkBlendMode mode) { 28 fColor = color; 29 fMode = mode; 30 // cache 31 fPMColor = SkPreMultiplyColor(fColor); 32 } 33 34 #ifndef SK_IGNORE_TO_STRING 35 void SkModeColorFilter::toString(SkString* str) const { 36 str->append("SkModeColorFilter: color: 0x"); 37 str->appendHex(fColor); 38 str->append(" mode: "); 39 str->append(SkBlendMode_Name(fMode)); 40 } 41 #endif 42 43 bool SkModeColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const { 44 if (color) { 45 *color = fColor; 46 } 47 if (mode) { 48 *mode = fMode; 49 } 50 return true; 51 } 52 53 uint32_t SkModeColorFilter::getFlags() const { 54 uint32_t flags = 0; 55 switch (fMode) { 56 case SkBlendMode::kDst: //!< [Da, Dc] 57 case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc] 58 flags |= kAlphaUnchanged_Flag; 59 default: 60 break; 61 } 62 return flags; 63 } 64 65 void SkModeColorFilter::flatten(SkWriteBuffer& buffer) const { 66 buffer.writeColor(fColor); 67 buffer.writeUInt((int)fMode); 68 } 69 70 sk_sp<SkFlattenable> SkModeColorFilter::CreateProc(SkReadBuffer& buffer) { 71 SkColor color = buffer.readColor(); 72 SkBlendMode mode = (SkBlendMode)buffer.readUInt(); 73 return SkColorFilter::MakeModeFilter(color, mode); 74 } 75 76 void SkModeColorFilter::onAppendStages(SkRasterPipeline* p, 77 SkColorSpace* dst, 78 SkArenaAlloc* scratch, 79 bool shaderIsOpaque) const { 80 p->append(SkRasterPipeline::move_src_dst); 81 p->append_constant_color(scratch, SkPM4f_from_SkColor(fColor, dst)); 82 SkBlendMode_AppendStages(fMode, p); 83 } 84 85 sk_sp<SkColorFilter> SkModeColorFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 86 SkColor color = xformer->apply(fColor); 87 if (color != fColor) { 88 return SkColorFilter::MakeModeFilter(color, fMode); 89 } 90 return this->INHERITED::onMakeColorSpace(xformer); 91 } 92 93 /////////////////////////////////////////////////////////////////////////////// 94 #if SK_SUPPORT_GPU 95 #include "GrBlend.h" 96 #include "effects/GrXfermodeFragmentProcessor.h" 97 #include "effects/GrConstColorProcessor.h" 98 #include "SkGr.h" 99 100 std::unique_ptr<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor( 101 GrContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const { 102 if (SkBlendMode::kDst == fMode) { 103 return nullptr; 104 } 105 106 auto constFP = GrConstColorProcessor::Make(SkColorToPremulGrColor4f(fColor, dstColorSpaceInfo), 107 GrConstColorProcessor::InputMode::kIgnore); 108 auto fp = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode); 109 if (!fp) { 110 return nullptr; 111 } 112 #ifdef SK_DEBUG 113 // With a solid color input this should always be able to compute the blended color 114 // (at least for coeff modes) 115 if ((unsigned)fMode <= (unsigned)SkBlendMode::kLastCoeffMode) { 116 SkASSERT(fp->hasConstantOutputForConstantInput()); 117 } 118 #endif 119 return fp; 120 } 121 122 #endif 123 124 /////////////////////////////////////////////////////////////////////////////// 125 126 sk_sp<SkColorFilter> SkColorFilter::MakeModeFilter(SkColor color, SkBlendMode mode) { 127 if (!SkIsValidMode(mode)) { 128 return nullptr; 129 } 130 131 unsigned alpha = SkColorGetA(color); 132 133 // first collaps some modes if possible 134 135 if (SkBlendMode::kClear == mode) { 136 color = 0; 137 mode = SkBlendMode::kSrc; 138 } else if (SkBlendMode::kSrcOver == mode) { 139 if (0 == alpha) { 140 mode = SkBlendMode::kDst; 141 } else if (255 == alpha) { 142 mode = SkBlendMode::kSrc; 143 } 144 // else just stay srcover 145 } 146 147 // weed out combinations that are noops, and just return null 148 if (SkBlendMode::kDst == mode || 149 (0 == alpha && (SkBlendMode::kSrcOver == mode || 150 SkBlendMode::kDstOver == mode || 151 SkBlendMode::kDstOut == mode || 152 SkBlendMode::kSrcATop == mode || 153 SkBlendMode::kXor == mode || 154 SkBlendMode::kDarken == mode)) || 155 (0xFF == alpha && SkBlendMode::kDstIn == mode)) { 156 return nullptr; 157 } 158 159 return SkModeColorFilter::Make(color, mode); 160 } 161