1/* 2 * Copyright 2012 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 "SkColorFilterImageFilter.h" 9 10#include "SkCanvas.h" 11#include "SkColorFilter.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 19sk_sp<SkImageFilter> SkColorFilterImageFilter::Make(sk_sp<SkColorFilter> cf, 20 sk_sp<SkImageFilter> input, 21 const CropRect* cropRect) { 22 if (!cf) { 23 return nullptr; 24 } 25 26 SkColorFilter* inputCF; 27 if (input && input->isColorFilterNode(&inputCF)) { 28 // This is an optimization, as it collapses the hierarchy by just combining the two 29 // colorfilters into a single one, which the new imagefilter will wrap. 30 sk_sp<SkColorFilter> newCF(SkColorFilter::MakeComposeFilter(cf,// can't move bc of fallthru 31 sk_sp<SkColorFilter>(inputCF))); 32 if (newCF) { 33 return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(std::move(newCF), 34 sk_ref_sp(input->getInput(0)), 35 cropRect)); 36 } 37 } 38 39 return sk_sp<SkImageFilter>(new SkColorFilterImageFilter(std::move(cf), 40 std::move(input), 41 cropRect)); 42} 43 44SkColorFilterImageFilter::SkColorFilterImageFilter(sk_sp<SkColorFilter> cf, 45 sk_sp<SkImageFilter> input, 46 const CropRect* cropRect) 47 : INHERITED(&input, 1, cropRect) 48 , fColorFilter(std::move(cf)) { 49} 50 51sk_sp<SkFlattenable> SkColorFilterImageFilter::CreateProc(SkReadBuffer& buffer) { 52 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 53 sk_sp<SkColorFilter> cf(buffer.readColorFilter()); 54 return Make(std::move(cf), common.getInput(0), &common.cropRect()); 55} 56 57void SkColorFilterImageFilter::flatten(SkWriteBuffer& buffer) const { 58 this->INHERITED::flatten(buffer); 59 buffer.writeFlattenable(fColorFilter.get()); 60} 61 62sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(SkSpecialImage* source, 63 const Context& ctx, 64 SkIPoint* offset) const { 65 SkIPoint inputOffset = SkIPoint::Make(0, 0); 66 sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); 67 68 SkIRect inputBounds; 69 if (fColorFilter->affectsTransparentBlack()) { 70 // If the color filter affects transparent black, the bounds are the entire clip. 71 inputBounds = ctx.clipBounds(); 72 } else if (!input) { 73 return nullptr; 74 } else { 75 inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), 76 input->width(), input->height()); 77 } 78 79 SkIRect bounds; 80 if (!this->applyCropRect(ctx, inputBounds, &bounds)) { 81 return nullptr; 82 } 83 84 sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); 85 if (!surf) { 86 return nullptr; 87 } 88 89 SkCanvas* canvas = surf->getCanvas(); 90 SkASSERT(canvas); 91 92 SkPaint paint; 93 94 paint.setBlendMode(SkBlendMode::kSrc); 95 paint.setColorFilter(fColorFilter); 96 97 // TODO: it may not be necessary to clear or drawPaint inside the input bounds 98 // (see skbug.com/5075) 99 if (fColorFilter->affectsTransparentBlack()) { 100 // The subsequent input->draw() call may not fill the entire canvas. For filters which 101 // affect transparent black, ensure that the filter is applied everywhere. 102 paint.setColor(SK_ColorTRANSPARENT); 103 canvas->drawPaint(paint); 104 paint.setColor(SK_ColorBLACK); 105 } else { 106 canvas->clear(0x0); 107 } 108 109 if (input) { 110 input->draw(canvas, 111 SkIntToScalar(inputOffset.fX - bounds.fLeft), 112 SkIntToScalar(inputOffset.fY - bounds.fTop), 113 &paint); 114 } 115 116 offset->fX = bounds.fLeft; 117 offset->fY = bounds.fTop; 118 return surf->makeImageSnapshot(); 119} 120 121sk_sp<SkImageFilter> SkColorFilterImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) 122const { 123 SkASSERT(1 == this->countInputs()); 124 125 sk_sp<SkImageFilter> input = xformer->apply(this->getInput(0)); 126 auto colorFilter = xformer->apply(fColorFilter.get()); 127 if (this->getInput(0) != input.get() || fColorFilter != colorFilter) { 128 return SkColorFilterImageFilter::Make(std::move(colorFilter), std::move(input), 129 this->getCropRectIfSet()); 130 } 131 return this->refMe(); 132} 133 134bool SkColorFilterImageFilter::onIsColorFilterNode(SkColorFilter** filter) const { 135 SkASSERT(1 == this->countInputs()); 136 if (!this->cropRectIsSet()) { 137 if (filter) { 138 *filter = SkRef(fColorFilter.get()); 139 } 140 return true; 141 } 142 return false; 143} 144 145bool SkColorFilterImageFilter::affectsTransparentBlack() const { 146 return fColorFilter->affectsTransparentBlack(); 147} 148 149#ifndef SK_IGNORE_TO_STRING 150void SkColorFilterImageFilter::toString(SkString* str) const { 151 str->appendf("SkColorFilterImageFilter: ("); 152 153 str->appendf("input: ("); 154 155 if (this->getInput(0)) { 156 this->getInput(0)->toString(str); 157 } 158 159 str->appendf(") color filter: "); 160 fColorFilter->toString(str); 161 162 str->append(")"); 163} 164#endif 165