1 /* 2 * Copyright 2013 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 "SkXfermodeImageFilter.h" 9 #include "SkArithmeticImageFilter.h" 10 #include "SkCanvas.h" 11 #include "SkColorPriv.h" 12 #include "SkColorSpaceXformer.h" 13 #include "SkReadBuffer.h" 14 #include "SkSpecialImage.h" 15 #include "SkSpecialSurface.h" 16 #include "SkWriteBuffer.h" 17 #if SK_SUPPORT_GPU 18 #include "GrClip.h" 19 #include "GrContext.h" 20 #include "GrRenderTargetContext.h" 21 #include "GrTextureProxy.h" 22 23 #include "effects/GrConstColorProcessor.h" 24 #include "effects/GrTextureDomain.h" 25 #include "effects/GrSimpleTextureEffect.h" 26 #include "SkGr.h" 27 #endif 28 #include "SkClipOpPriv.h" 29 30 class SkXfermodeImageFilter_Base : public SkImageFilter { 31 public: 32 SkXfermodeImageFilter_Base(SkBlendMode mode, sk_sp<SkImageFilter> inputs[2], 33 const CropRect* cropRect); 34 35 SK_TO_STRING_OVERRIDE() 36 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkXfermodeImageFilter_Base) 37 38 protected: 39 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&, 40 SkIPoint* offset) const override; 41 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override; 42 43 #if SK_SUPPORT_GPU 44 sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source, 45 sk_sp<SkSpecialImage> background, 46 const SkIPoint& backgroundOffset, 47 sk_sp<SkSpecialImage> foreground, 48 const SkIPoint& foregroundOffset, 49 const SkIRect& bounds, 50 const OutputProperties& outputProperties) const; 51 #endif 52 53 void flatten(SkWriteBuffer&) const override; 54 55 void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const; 56 #if SK_SUPPORT_GPU 57 sk_sp<GrFragmentProcessor> makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const; 58 #endif 59 60 private: 61 static sk_sp<SkFlattenable> LegacyArithmeticCreateProc(SkReadBuffer& buffer); 62 63 SkBlendMode fMode; 64 65 friend class SkXfermodeImageFilter; 66 67 typedef SkImageFilter INHERITED; 68 }; 69 70 /////////////////////////////////////////////////////////////////////////////// 71 72 sk_sp<SkImageFilter> SkXfermodeImageFilter::Make(SkBlendMode mode, 73 sk_sp<SkImageFilter> background, 74 sk_sp<SkImageFilter> foreground, 75 const SkImageFilter::CropRect* cropRect) { 76 sk_sp<SkImageFilter> inputs[2] = { std::move(background), std::move(foreground) }; 77 return sk_sp<SkImageFilter>(new SkXfermodeImageFilter_Base(mode, inputs, cropRect)); 78 } 79 80 SkXfermodeImageFilter_Base::SkXfermodeImageFilter_Base(SkBlendMode mode, 81 sk_sp<SkImageFilter> inputs[2], 82 const CropRect* cropRect) 83 : INHERITED(inputs, 2, cropRect) 84 , fMode(mode) 85 {} 86 87 static unsigned unflatten_blendmode(SkReadBuffer& buffer) { 88 unsigned mode = buffer.read32(); 89 (void)buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode); 90 return mode; 91 } 92 93 sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::CreateProc(SkReadBuffer& buffer) { 94 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); 95 unsigned mode = unflatten_blendmode(buffer); 96 if (!buffer.isValid()) { 97 return nullptr; 98 } 99 return SkXfermodeImageFilter::Make((SkBlendMode)mode, common.getInput(0), 100 common.getInput(1), &common.cropRect()); 101 } 102 103 void SkXfermodeImageFilter_Base::flatten(SkWriteBuffer& buffer) const { 104 this->INHERITED::flatten(buffer); 105 buffer.write32((unsigned)fMode); 106 } 107 108 sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::onFilterImage(SkSpecialImage* source, 109 const Context& ctx, 110 SkIPoint* offset) const { 111 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); 112 sk_sp<SkSpecialImage> background(this->filterInput(0, source, ctx, &backgroundOffset)); 113 114 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); 115 sk_sp<SkSpecialImage> foreground(this->filterInput(1, source, ctx, &foregroundOffset)); 116 117 SkIRect foregroundBounds = SkIRect::EmptyIRect(); 118 if (foreground) { 119 foregroundBounds = SkIRect::MakeXYWH(foregroundOffset.x(), foregroundOffset.y(), 120 foreground->width(), foreground->height()); 121 } 122 123 SkIRect srcBounds = SkIRect::EmptyIRect(); 124 if (background) { 125 srcBounds = SkIRect::MakeXYWH(backgroundOffset.x(), backgroundOffset.y(), 126 background->width(), background->height()); 127 } 128 129 srcBounds.join(foregroundBounds); 130 if (srcBounds.isEmpty()) { 131 return nullptr; 132 } 133 134 SkIRect bounds; 135 if (!this->applyCropRect(ctx, srcBounds, &bounds)) { 136 return nullptr; 137 } 138 139 offset->fX = bounds.left(); 140 offset->fY = bounds.top(); 141 142 #if SK_SUPPORT_GPU 143 if (source->isTextureBacked()) { 144 return this->filterImageGPU(source, 145 background, backgroundOffset, 146 foreground, foregroundOffset, 147 bounds, ctx.outputProperties()); 148 } 149 #endif 150 151 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 152 if (!surf) { 153 return nullptr; 154 } 155 156 SkCanvas* canvas = surf->getCanvas(); 157 SkASSERT(canvas); 158 159 canvas->clear(0x0); // can't count on background to fully clear the background 160 canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 161 162 if (background) { 163 SkPaint paint; 164 paint.setBlendMode(SkBlendMode::kSrc); 165 background->draw(canvas, 166 SkIntToScalar(backgroundOffset.fX), SkIntToScalar(backgroundOffset.fY), 167 &paint); 168 } 169 170 this->drawForeground(canvas, foreground.get(), foregroundBounds); 171 172 return surf->makeImageSnapshot(); 173 } 174 175 sk_sp<SkImageFilter> SkXfermodeImageFilter_Base::onMakeColorSpace(SkColorSpaceXformer* xformer) 176 const { 177 SkASSERT(2 == this->countInputs()); 178 auto background = xformer->apply(this->getInput(0)); 179 auto foreground = xformer->apply(this->getInput(1)); 180 if (background.get() != this->getInput(0) || foreground.get() != this->getInput(1)) { 181 return SkXfermodeImageFilter::Make(fMode, std::move(background), std::move(foreground), 182 this->getCropRectIfSet()); 183 } 184 return this->refMe(); 185 } 186 187 void SkXfermodeImageFilter_Base::drawForeground(SkCanvas* canvas, SkSpecialImage* img, 188 const SkIRect& fgBounds) const { 189 SkPaint paint; 190 paint.setBlendMode(fMode); 191 if (img) { 192 img->draw(canvas, SkIntToScalar(fgBounds.fLeft), SkIntToScalar(fgBounds.fTop), &paint); 193 } 194 195 SkAutoCanvasRestore acr(canvas, true); 196 canvas->clipRect(SkRect::Make(fgBounds), kDifference_SkClipOp); 197 paint.setColor(0); 198 canvas->drawPaint(paint); 199 } 200 201 #ifndef SK_IGNORE_TO_STRING 202 void SkXfermodeImageFilter_Base::toString(SkString* str) const { 203 str->appendf("SkXfermodeImageFilter: ("); 204 str->appendf("blendmode: (%d)", (int)fMode); 205 if (this->getInput(0)) { 206 str->appendf("foreground: ("); 207 this->getInput(0)->toString(str); 208 str->appendf(")"); 209 } 210 if (this->getInput(1)) { 211 str->appendf("background: ("); 212 this->getInput(1)->toString(str); 213 str->appendf(")"); 214 } 215 str->append(")"); 216 } 217 #endif 218 219 #if SK_SUPPORT_GPU 220 221 #include "effects/GrXfermodeFragmentProcessor.h" 222 223 sk_sp<SkSpecialImage> SkXfermodeImageFilter_Base::filterImageGPU( 224 SkSpecialImage* source, 225 sk_sp<SkSpecialImage> background, 226 const SkIPoint& backgroundOffset, 227 sk_sp<SkSpecialImage> foreground, 228 const SkIPoint& foregroundOffset, 229 const SkIRect& bounds, 230 const OutputProperties& outputProperties) const { 231 SkASSERT(source->isTextureBacked()); 232 233 GrContext* context = source->getContext(); 234 235 sk_sp<GrTextureProxy> backgroundProxy, foregroundProxy; 236 237 if (background) { 238 backgroundProxy = background->asTextureProxyRef(context); 239 } 240 241 if (foreground) { 242 foregroundProxy = foreground->asTextureProxyRef(context); 243 } 244 245 GrPaint paint; 246 sk_sp<GrFragmentProcessor> bgFP; 247 248 if (backgroundProxy) { 249 SkMatrix bgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(backgroundOffset.fX), 250 -SkIntToScalar(backgroundOffset.fY)); 251 sk_sp<GrColorSpaceXform> bgXform = GrColorSpaceXform::Make(background->getColorSpace(), 252 outputProperties.colorSpace()); 253 bgFP = GrTextureDomainEffect::Make( 254 std::move(backgroundProxy), 255 std::move(bgXform), bgMatrix, 256 GrTextureDomain::MakeTexelDomain(background->subset()), 257 GrTextureDomain::kDecal_Mode, 258 GrSamplerParams::kNone_FilterMode); 259 } else { 260 bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), 261 GrConstColorProcessor::kIgnore_InputMode); 262 } 263 264 if (foregroundProxy) { 265 SkMatrix fgMatrix = SkMatrix::MakeTrans(-SkIntToScalar(foregroundOffset.fX), 266 -SkIntToScalar(foregroundOffset.fY)); 267 sk_sp<GrColorSpaceXform> fgXform = GrColorSpaceXform::Make(foreground->getColorSpace(), 268 outputProperties.colorSpace()); 269 sk_sp<GrFragmentProcessor> foregroundFP(GrTextureDomainEffect::Make( 270 std::move(foregroundProxy), 271 std::move(fgXform), fgMatrix, 272 GrTextureDomain::MakeTexelDomain(foreground->subset()), 273 GrTextureDomain::kDecal_Mode, 274 GrSamplerParams::kNone_FilterMode)); 275 paint.addColorFragmentProcessor(std::move(foregroundFP)); 276 277 sk_sp<GrFragmentProcessor> xferFP = this->makeFGFrag(std::move(bgFP)); 278 279 // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed 280 if (xferFP) { 281 paint.addColorFragmentProcessor(std::move(xferFP)); 282 } 283 } else { 284 paint.addColorFragmentProcessor(std::move(bgFP)); 285 } 286 287 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 288 289 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext( 290 SkBackingFit::kApprox, bounds.width(), bounds.height(), 291 GrRenderableConfigForColorSpace(outputProperties.colorSpace()), 292 sk_ref_sp(outputProperties.colorSpace()))); 293 if (!renderTargetContext) { 294 return nullptr; 295 } 296 paint.setGammaCorrect(renderTargetContext->isGammaCorrect()); 297 298 SkMatrix matrix; 299 matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 300 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, 301 SkRect::Make(bounds)); 302 303 return SkSpecialImage::MakeDeferredFromGpu(context, 304 SkIRect::MakeWH(bounds.width(), bounds.height()), 305 kNeedNewImageUniqueID_SpecialImage, 306 renderTargetContext->asTextureProxyRef(), 307 renderTargetContext->refColorSpace()); 308 } 309 310 sk_sp<GrFragmentProcessor> 311 SkXfermodeImageFilter_Base::makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const { 312 return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(bgFP), fMode); 313 } 314 315 #endif 316 /////////////////////////////////////////////////////////////////////////////////////////////////// 317 318 sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc(SkReadBuffer& buffer) { 319 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); 320 // skip the unused mode (srcover) field 321 SkDEBUGCODE(unsigned mode =) unflatten_blendmode(buffer); 322 if (!buffer.isValid()) { 323 return nullptr; 324 } 325 SkASSERT(SkBlendMode::kSrcOver == (SkBlendMode)mode); 326 float k[4]; 327 for (int i = 0; i < 4; ++i) { 328 k[i] = buffer.readScalar(); 329 } 330 const bool enforcePMColor = buffer.readBool(); 331 return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0), 332 common.getInput(1), &common.cropRect()); 333 } 334 335 /////////////////////////////////////////////////////////////////////////////////////////////////// 336 337 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermodeImageFilter) 338 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkXfermodeImageFilter_Base) 339 // manually register the legacy serialized name "SkXfermodeImageFilter" 340 SkFlattenable::Register("SkXfermodeImageFilter", SkXfermodeImageFilter_Base::CreateProc, 341 SkFlattenable::kSkImageFilter_Type); 342 // manually register the legacy serialized name "SkArithmeticImageFilter" from when that filter 343 // was implemented as a xfermode image filter. 344 SkFlattenable::Register("SkArithmeticImageFilter", 345 SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc, 346 SkFlattenable::kSkImageFilter_Type); 347 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 348