• 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 "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
13 #include "SkValidationUtils.h"
14 
15 ///////////////////////////////////////////////////////////////////////////////
16 
initAllocModes()17 void SkMergeImageFilter::initAllocModes() {
18     int inputCount = countInputs();
19     if (inputCount) {
20         size_t size = sizeof(uint8_t) * inputCount;
21         if (size <= sizeof(fStorage)) {
22             fModes = SkTCast<uint8_t*>(fStorage);
23         } else {
24             fModes = SkTCast<uint8_t*>(sk_malloc_throw(size));
25         }
26     } else {
27         fModes = NULL;
28     }
29 }
30 
initModes(const SkXfermode::Mode modes[])31 void SkMergeImageFilter::initModes(const SkXfermode::Mode modes[]) {
32     if (modes) {
33         this->initAllocModes();
34         int inputCount = countInputs();
35         for (int i = 0; i < inputCount; ++i) {
36             fModes[i] = SkToU8(modes[i]);
37         }
38     } else {
39         fModes = NULL;
40     }
41 }
42 
SkMergeImageFilter(SkImageFilter * filters[],int count,const SkXfermode::Mode modes[],const CropRect * cropRect)43 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
44                                        const SkXfermode::Mode modes[],
45                                        const CropRect* cropRect)
46   : INHERITED(count, filters, cropRect) {
47     SkASSERT(count >= 0);
48     this->initModes(modes);
49 }
50 
~SkMergeImageFilter()51 SkMergeImageFilter::~SkMergeImageFilter() {
52 
53     if (fModes != SkTCast<uint8_t*>(fStorage)) {
54         sk_free(fModes);
55     }
56 }
57 
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const58 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
59                                        const Context& ctx,
60                                        SkBitmap* result, SkIPoint* offset) const {
61     if (countInputs() < 1) {
62         return false;
63     }
64 
65     SkIRect bounds;
66     if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
67         return false;
68     }
69 
70     const int x0 = bounds.left();
71     const int y0 = bounds.top();
72 
73     SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
74     if (NULL == dst) {
75         return false;
76     }
77     SkCanvas canvas(dst);
78     SkPaint paint;
79 
80     int inputCount = countInputs();
81     for (int i = 0; i < inputCount; ++i) {
82         SkBitmap tmp;
83         const SkBitmap* srcPtr;
84         SkIPoint pos = SkIPoint::Make(0, 0);
85         SkImageFilter* filter = getInput(i);
86         if (filter) {
87             if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
88                 return false;
89             }
90             srcPtr = &tmp;
91         } else {
92             srcPtr = &src;
93         }
94 
95         if (fModes) {
96             paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
97         } else {
98             paint.setXfermode(NULL);
99         }
100         canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
101     }
102 
103     offset->fX = bounds.left();
104     offset->fY = bounds.top();
105     *result = dst->accessBitmap(false);
106     return true;
107 }
108 
CreateProc(SkReadBuffer & buffer)109 SkFlattenable* SkMergeImageFilter::CreateProc(SkReadBuffer& buffer) {
110     Common common;
111     if (!common.unflatten(buffer, -1)) {
112         return NULL;
113     }
114 
115     const int count = common.inputCount();
116     bool hasModes = buffer.readBool();
117     if (hasModes) {
118         SkAutoSTArray<4, SkXfermode::Mode> modes(count);
119         SkAutoSTArray<4, uint8_t> modes8(count);
120         if (!buffer.readByteArray(modes8.get(), count)) {
121             return NULL;
122         }
123         for (int i = 0; i < count; ++i) {
124             modes[i] = (SkXfermode::Mode)modes8[i];
125             buffer.validate(SkIsValidMode(modes[i]));
126         }
127         if (!buffer.isValid()) {
128             return NULL;
129         }
130         return Create(common.inputs(), count, modes.get(), &common.cropRect());
131     }
132     return Create(common.inputs(), count, NULL, &common.cropRect());
133 }
134 
flatten(SkWriteBuffer & buffer) const135 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
136     this->INHERITED::flatten(buffer);
137     buffer.writeBool(fModes != NULL);
138     if (fModes) {
139         buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
140     }
141 }
142 
143 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const144 void SkMergeImageFilter::toString(SkString* str) const {
145     str->appendf("SkMergeImageFilter: (");
146 
147     for (int i = 0; i < this->countInputs(); ++i) {
148         SkImageFilter* filter = this->getInput(i);
149         str->appendf("%d: (", i);
150         filter->toString(str);
151         str->appendf(")");
152     }
153 
154     str->append(")");
155 }
156 #endif
157