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