• 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 #include "SkCanvas.h"
10 #include "SkDevice.h"
11 #include "SkFlattenableBuffers.h"
12 
13 ///////////////////////////////////////////////////////////////////////////////
14 
initAllocModes()15 void SkMergeImageFilter::initAllocModes() {
16     int inputCount = countInputs();
17     if (inputCount) {
18         size_t size = sizeof(uint8_t) * inputCount;
19         if (size <= sizeof(fStorage)) {
20             fModes = SkTCast<uint8_t*>(fStorage);
21         } else {
22             fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
23         }
24     } else {
25         fModes = NULL;
26     }
27 }
28 
initModes(const SkXfermode::Mode modes[])29 void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
30     if (modes) {
31         this->initAllocModes();
32         int inputCount = countInputs();
33         for (int i = 0; i < inputCount; ++i) {
34             fModes[i] = SkToU8(modes[i]);
35         }
36     } else {
37         fModes = NULL;
38     }
39 }
40 
SkMergeImageFilter(SkImageFilter * first,SkImageFilter * second,SkXfermode::Mode mode)41 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
42                                        SkXfermode::Mode mode) : INHERITED(first, second) {
43     if (SkXfermode::kSrcOver_Mode != mode) {
44         SkXfermode::Mode modes[] = { mode, mode };
45         this->initModes(modes);
46     } else {
47         fModes = NULL;
48     }
49 }
50 
SkMergeImageFilter(SkImageFilter * filters[],int count,const SkXfermode::Mode modes[])51 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
52                                        const SkXfermode::Mode modes[]) : INHERITED(count, filters) {
53     this->initModes(modes);
54 }
55 
~SkMergeImageFilter()56 SkMergeImageFilter::~SkMergeImageFilter() {
57 
58     if (fModes != SkTCast<uint8_t*>(fStorage)) {
59         sk_free(fModes);
60     }
61 }
62 
onFilterBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst)63 bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
64                                         SkIRect* dst) {
65     if (countInputs() < 1) {
66         return false;
67     }
68 
69     SkIRect totalBounds;
70 
71     int inputCount = countInputs();
72     for (int i = 0; i < inputCount; ++i) {
73         SkImageFilter* filter = getInput(i);
74         SkIRect r;
75         if (filter) {
76             if (!filter->filterBounds(src, ctm, &r)) {
77                 return false;
78             }
79         } else {
80             r = src;
81         }
82         if (0 == i) {
83             totalBounds = r;
84         } else {
85             totalBounds.join(r);
86         }
87     }
88 
89     // don't modify dst until now, so we don't accidentally change it in the
90     // loop, but then return false on the next filter.
91     *dst = totalBounds;
92     return true;
93 }
94 
onFilterImage(Proxy * proxy,const SkBitmap & src,const SkMatrix & ctm,SkBitmap * result,SkIPoint * loc)95 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
96                                        const SkMatrix& ctm,
97                                        SkBitmap* result, SkIPoint* loc) {
98     if (countInputs() < 1) {
99         return false;
100     }
101 
102     const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
103                                                 src.width(), src.height());
104     SkIRect bounds;
105     if (!this->filterBounds(srcBounds, ctm, &bounds)) {
106         return false;
107     }
108 
109     const int x0 = bounds.left();
110     const int y0 = bounds.top();
111 
112     SkAutoTUnref<SkDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
113     if (NULL == dst) {
114         return false;
115     }
116     SkCanvas canvas(dst);
117     SkPaint paint;
118 
119     int inputCount = countInputs();
120     for (int i = 0; i < inputCount; ++i) {
121         SkBitmap tmp;
122         const SkBitmap* srcPtr;
123         SkIPoint pos = *loc;
124         SkImageFilter* filter = getInput(i);
125         if (filter) {
126             if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
127                 return false;
128             }
129             srcPtr = &tmp;
130         } else {
131             srcPtr = &src;
132         }
133 
134         if (fModes) {
135             paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
136         } else {
137             paint.setXfermode(NULL);
138         }
139         canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
140     }
141 
142     loc->set(bounds.left(), bounds.top());
143     *result = dst->accessBitmap(false);
144     return true;
145 }
146 
flatten(SkFlattenableWriteBuffer & buffer) const147 void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
148     this->INHERITED::flatten(buffer);
149 
150     buffer.writeBool(fModes != NULL);
151     if (fModes) {
152         buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
153     }
154 }
155 
SkMergeImageFilter(SkFlattenableReadBuffer & buffer)156 SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
157     bool hasModes = buffer.readBool();
158     if (hasModes) {
159         this->initAllocModes();
160         SkASSERT(buffer.getArrayCount() == countInputs() * sizeof(fModes[0]));
161         buffer.readByteArray(fModes);
162     } else {
163         fModes = 0;
164     }
165 }
166