• 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 * first,SkImageFilter * second,SkXfermode::Mode mode,const CropRect * cropRect)43 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
44                                        SkXfermode::Mode mode,
45                                        const CropRect* cropRect) : INHERITED(first, second, cropRect) {
46     if (SkXfermode::kSrcOver_Mode != mode) {
47         SkXfermode::Mode modes[] = { mode, mode };
48         this->initModes(modes);
49     } else {
50         fModes = NULL;
51     }
52 }
53 
SkMergeImageFilter(SkImageFilter * filters[],int count,const SkXfermode::Mode modes[],const CropRect * cropRect)54 SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* filters[], int count,
55                                        const SkXfermode::Mode modes[],
56                                        const CropRect* cropRect) : INHERITED(count, filters, cropRect) {
57     SkASSERT(count >= 0);
58     this->initModes(modes);
59 }
60 
~SkMergeImageFilter()61 SkMergeImageFilter::~SkMergeImageFilter() {
62 
63     if (fModes != SkTCast<uint8_t*>(fStorage)) {
64         sk_free(fModes);
65     }
66 }
67 
onFilterImage(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const68 bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
69                                        const Context& ctx,
70                                        SkBitmap* result, SkIPoint* offset) const {
71     if (countInputs() < 1) {
72         return false;
73     }
74 
75     SkIRect bounds;
76     if (!this->applyCropRect(ctx, src, SkIPoint::Make(0, 0), &bounds)) {
77         return false;
78     }
79 
80     const int x0 = bounds.left();
81     const int y0 = bounds.top();
82 
83     SkAutoTUnref<SkBaseDevice> dst(proxy->createDevice(bounds.width(), bounds.height()));
84     if (NULL == dst) {
85         return false;
86     }
87     SkCanvas canvas(dst);
88     SkPaint paint;
89 
90     int inputCount = countInputs();
91     for (int i = 0; i < inputCount; ++i) {
92         SkBitmap tmp;
93         const SkBitmap* srcPtr;
94         SkIPoint pos = SkIPoint::Make(0, 0);
95         SkImageFilter* filter = getInput(i);
96         if (filter) {
97             if (!filter->filterImage(proxy, src, ctx, &tmp, &pos)) {
98                 return false;
99             }
100             srcPtr = &tmp;
101         } else {
102             srcPtr = &src;
103         }
104 
105         if (fModes) {
106             paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
107         } else {
108             paint.setXfermode(NULL);
109         }
110         canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
111     }
112 
113     offset->fX = bounds.left();
114     offset->fY = bounds.top();
115     *result = dst->accessBitmap(false);
116     return true;
117 }
118 
flatten(SkWriteBuffer & buffer) const119 void SkMergeImageFilter::flatten(SkWriteBuffer& buffer) const {
120     this->INHERITED::flatten(buffer);
121 
122     buffer.writeBool(fModes != NULL);
123     if (fModes) {
124         buffer.writeByteArray(fModes, countInputs() * sizeof(fModes[0]));
125     }
126 }
127 
SkMergeImageFilter(SkReadBuffer & buffer)128 SkMergeImageFilter::SkMergeImageFilter(SkReadBuffer& buffer)
129   : INHERITED(-1, buffer) {
130     bool hasModes = buffer.readBool();
131     if (hasModes) {
132         this->initAllocModes();
133         int nbInputs = countInputs();
134         size_t size = nbInputs * sizeof(fModes[0]);
135         SkASSERT(buffer.getArrayCount() == size);
136         if (buffer.validate(buffer.getArrayCount() == size) &&
137             buffer.readByteArray(fModes, size)) {
138             for (int i = 0; i < nbInputs; ++i) {
139                 buffer.validate(SkIsValidMode((SkXfermode::Mode)fModes[i]));
140             }
141         }
142     } else {
143         fModes = 0;
144     }
145 }
146