1 /* 2 * Copyright 2013 Google Inc. 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 "SkComposeImageFilter.h" 9 #include "SkColorSpaceXformer.h" 10 #include "SkImageFilterPriv.h" 11 #include "SkReadBuffer.h" 12 #include "SkSpecialImage.h" 13 #include "SkWriteBuffer.h" 14 15 sk_sp<SkImageFilter> SkComposeImageFilter::Make(sk_sp<SkImageFilter> outer, 16 sk_sp<SkImageFilter> inner) { 17 if (!outer) { 18 return inner; 19 } 20 if (!inner) { 21 return outer; 22 } 23 sk_sp<SkImageFilter> inputs[2] = { std::move(outer), std::move(inner) }; 24 return sk_sp<SkImageFilter>(new SkComposeImageFilter(inputs)); 25 } 26 27 SkRect SkComposeImageFilter::computeFastBounds(const SkRect& src) const { 28 SkImageFilter* outer = this->getInput(0); 29 SkImageFilter* inner = this->getInput(1); 30 31 return outer->computeFastBounds(inner->computeFastBounds(src)); 32 } 33 34 sk_sp<SkSpecialImage> SkComposeImageFilter::onFilterImage(SkSpecialImage* source, 35 const Context& ctx, 36 SkIPoint* offset) const { 37 // The bounds passed to the inner filter must be filtered by the outer 38 // filter, so that the inner filter produces the pixels that the outer 39 // filter requires as input. This matters if the outer filter moves pixels. 40 SkIRect innerClipBounds; 41 innerClipBounds = this->getInput(0)->filterBounds(ctx.clipBounds(), ctx.ctm()); 42 Context innerContext(ctx.ctm(), innerClipBounds, ctx.cache(), ctx.outputProperties()); 43 SkIPoint innerOffset = SkIPoint::Make(0, 0); 44 sk_sp<SkSpecialImage> inner(this->filterInput(1, source, innerContext, &innerOffset)); 45 if (!inner) { 46 return nullptr; 47 } 48 49 SkMatrix outerMatrix(ctx.ctm()); 50 outerMatrix.postTranslate(SkIntToScalar(-innerOffset.x()), SkIntToScalar(-innerOffset.y())); 51 SkIRect clipBounds = ctx.clipBounds(); 52 clipBounds.offset(-innerOffset.x(), -innerOffset.y()); 53 Context outerContext(outerMatrix, clipBounds, ctx.cache(), ctx.outputProperties()); 54 55 SkIPoint outerOffset = SkIPoint::Make(0, 0); 56 sk_sp<SkSpecialImage> outer(this->filterInput(0, inner.get(), outerContext, &outerOffset)); 57 if (!outer) { 58 return nullptr; 59 } 60 61 *offset = innerOffset + outerOffset; 62 return outer; 63 } 64 65 sk_sp<SkImageFilter> SkComposeImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 66 SkASSERT(2 == this->countInputs() && this->getInput(0) && this->getInput(1)); 67 68 auto input0 = xformer->apply(this->getInput(0)); 69 auto input1 = xformer->apply(this->getInput(1)); 70 if (input0.get() != this->getInput(0) || input1.get() != this->getInput(1)) { 71 return SkComposeImageFilter::Make(std::move(input0), std::move(input1)); 72 } 73 return this->refMe(); 74 } 75 76 SkIRect SkComposeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 77 MapDirection direction) const { 78 SkImageFilter* outer = this->getInput(0); 79 SkImageFilter* inner = this->getInput(1); 80 81 return outer->filterBounds(inner->filterBounds(src, ctm, direction), ctm, direction); 82 } 83 84 sk_sp<SkFlattenable> SkComposeImageFilter::CreateProc(SkReadBuffer& buffer) { 85 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); 86 return SkComposeImageFilter::Make(common.getInput(0), common.getInput(1)); 87 } 88 89 #ifndef SK_IGNORE_TO_STRING 90 void SkComposeImageFilter::toString(SkString* str) const { 91 SkImageFilter* outer = getInput(0); 92 SkImageFilter* inner = getInput(1); 93 94 str->appendf("SkComposeImageFilter: ("); 95 96 str->appendf("outer: "); 97 outer->toString(str); 98 99 str->appendf("inner: "); 100 inner->toString(str); 101 102 str->appendf(")"); 103 } 104 #endif 105