• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkMergeImageFilter.h"
9 
10 #include "SkCanvas.h"
11 #include "SkColorSpaceXformer.h"
12 #include "SkReadBuffer.h"
13 #include "SkSpecialImage.h"
14 #include "SkSpecialSurface.h"
15 #include "SkWriteBuffer.h"
16 #include "SkValidationUtils.h"
17 
Make(sk_sp<SkImageFilter> * const filters,int count,const CropRect * cropRect)18 sk_sp<SkImageFilter> SkMergeImageFilter::Make(sk_sp<SkImageFilter>* const filters, int count,
19                                                const CropRect* cropRect) {
20     return sk_sp<SkImageFilter>(new SkMergeImageFilter(filters, count, cropRect));
21 }
22 
23 ///////////////////////////////////////////////////////////////////////////////
24 
SkMergeImageFilter(sk_sp<SkImageFilter> * const filters,int count,const CropRect * cropRect)25 SkMergeImageFilter::SkMergeImageFilter(sk_sp<SkImageFilter>* const filters, int count,
26                                        const CropRect* cropRect)
27     : INHERITED(filters, count, cropRect) {
28     SkASSERT(count >= 0);
29 }
30 
onFilterImage(SkSpecialImage * source,const Context & ctx,SkIPoint * offset) const31 sk_sp<SkSpecialImage> SkMergeImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx,
32                                                         SkIPoint* offset) const {
33     int inputCount = this->countInputs();
34     if (inputCount < 1) {
35         return nullptr;
36     }
37 
38     SkIRect bounds;
39     bounds.setEmpty();
40 
41     std::unique_ptr<sk_sp<SkSpecialImage>[]> inputs(new sk_sp<SkSpecialImage>[inputCount]);
42     std::unique_ptr<SkIPoint[]> offsets(new SkIPoint[inputCount]);
43 
44     // Filter all of the inputs.
45     for (int i = 0; i < inputCount; ++i) {
46         offsets[i].setZero();
47         inputs[i] = this->filterInput(i, source, ctx, &offsets[i]);
48         if (!inputs[i]) {
49             continue;
50         }
51         const SkIRect inputBounds = SkIRect::MakeXYWH(offsets[i].fX, offsets[i].fY,
52                                                       inputs[i]->width(), inputs[i]->height());
53         bounds.join(inputBounds);
54     }
55     if (bounds.isEmpty()) {
56         return nullptr;
57     }
58 
59     // Apply the crop rect to the union of the inputs' bounds.
60     // Note that the crop rect can only reduce the bounds, since this
61     // filter does not affect transparent black.
62     bool embiggen = false;
63     this->getCropRect().applyTo(bounds, ctx.ctm(), embiggen, &bounds);
64     if (!bounds.intersect(ctx.clipBounds())) {
65         return nullptr;
66     }
67 
68     const int x0 = bounds.left();
69     const int y0 = bounds.top();
70 
71     sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
72     if (!surf) {
73         return nullptr;
74     }
75 
76     SkCanvas* canvas = surf->getCanvas();
77     SkASSERT(canvas);
78 
79     canvas->clear(0x0);
80 
81     // Composite all of the filter inputs.
82     for (int i = 0; i < inputCount; ++i) {
83         if (!inputs[i]) {
84             continue;
85         }
86 
87         inputs[i]->draw(canvas,
88                         SkIntToScalar(offsets[i].x() - x0), SkIntToScalar(offsets[i].y() - y0),
89                         nullptr);
90     }
91 
92     offset->fX = bounds.left();
93     offset->fY = bounds.top();
94     return surf->makeImageSnapshot();
95 }
96 
onMakeColorSpace(SkColorSpaceXformer * xformer) const97 sk_sp<SkImageFilter> SkMergeImageFilter::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
98     SkSTArray<5, sk_sp<SkImageFilter>> inputs(this->countInputs());
99     bool changed = false;
100     for (int i = 0; i < this->countInputs(); i++) {
101         inputs.push_back(xformer->apply(this->getInput(i)));
102         changed |= (inputs[i].get() != this->getInput(i));
103     }
104 
105     if (changed) {
106         return SkMergeImageFilter::Make(inputs.begin(), this->countInputs(),
107                                         this->getCropRectIfSet());
108     }
109     return this->refMe();
110 }
111 
CreateProc(SkReadBuffer & buffer)112 sk_sp<SkFlattenable> SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
113     Common common;
114     if (!common.unflatten(buffer, -1)) {
115         return nullptr;
116     }
117 
118     const int count = common.inputCount();
119     if (buffer.isVersionLT(SkReadBuffer::kNoModesInMergeImageFilter_Verison)) {
120         bool hasModes = buffer.readBool();
121         if (hasModes) {
122             // Older pictures may have stored blendmodes, but by inspection we think these were
123             // all src-over, so we have removed support for storing these.
124             SkAutoSTArray<4, uint8_t> modes8(count);
125             if (!buffer.readByteArray(modes8.get(), count)) {
126                 return nullptr;
127             }
128             if (!buffer.isValid()) {
129                 return nullptr;
130             }
131         }
132     }
133     return Make(common.inputs(), count, &common.cropRect());
134 }
135 
flatten(SkWriteBuffer & buffer) const136 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
137     this->INHERITED::flatten(buffer);
138 }
139 
140 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const141 void SkMergeImageFilter::toString(SkString* str) const {
142     str->appendf("SkMergeImageFilter: (");
143 
144     for (int i = 0; i < this->countInputs(); ++i) {
145         SkImageFilter* filter = this->getInput(i);
146         str->appendf("%d: (", i);
147         filter->toString(str);
148         str->appendf(")");
149     }
150 
151     str->append(")");
152 }
153 #endif
154