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