blob: c1e2d26fd51d816131b6cd3aac1402133c55a7e2 [file] [log] [blame]
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00001/*
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 "SkMorphologyImageFilter.h"
djsollen@google.com64a0ec32012-06-12 15:17:27 +00009#include "SkBitmap.h"
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000010#include "SkColorPriv.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkFlattenableBuffers.h"
12#include "SkRect.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000013#if SK_SUPPORT_GPU
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +000014#include "GrContext.h"
15#include "GrTexture.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000016#endif
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000017
18SkMorphologyImageFilter::SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer)
19 : INHERITED(buffer) {
tomhudson@google.com75589252012-04-10 17:42:21 +000020 fRadius.fWidth = buffer.readInt();
21 fRadius.fHeight = buffer.readInt();
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000022}
23
24SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX, int radiusY)
25 : fRadius(SkISize::Make(radiusX, radiusY)) {
26}
27
28
djsollen@google.com54924242012-03-29 15:18:04 +000029void SkMorphologyImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000030 this->INHERITED::flatten(buffer);
tomhudson@google.com75589252012-04-10 17:42:21 +000031 buffer.writeInt(fRadius.fWidth);
32 buffer.writeInt(fRadius.fHeight);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000033}
34
35static void erode(const SkPMColor* src, SkPMColor* dst,
36 int radius, int width, int height,
37 int srcStrideX, int srcStrideY,
38 int dstStrideX, int dstStrideY)
39{
senorblanco@chromium.org56dd6302012-04-10 17:25:44 +000040 radius = SkMin32(radius, width - 1);
41 const SkPMColor* upperSrc = src + radius * srcStrideX;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000042 for (int x = 0; x < width; ++x) {
43 const SkPMColor* lp = src;
44 const SkPMColor* up = upperSrc;
45 SkPMColor* dptr = dst;
46 for (int y = 0; y < height; ++y) {
47 int minB = 255, minG = 255, minR = 255, minA = 255;
48 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
49 int b = SkGetPackedB32(*p);
50 int g = SkGetPackedG32(*p);
51 int r = SkGetPackedR32(*p);
52 int a = SkGetPackedA32(*p);
53 if (b < minB) minB = b;
54 if (g < minG) minG = g;
55 if (r < minR) minR = r;
56 if (a < minA) minA = a;
57 }
58 *dptr = SkPackARGB32(minA, minR, minG, minB);
59 dptr += dstStrideY;
60 lp += srcStrideY;
61 up += srcStrideY;
62 }
63 if (x >= radius) src += srcStrideX;
64 if (x + radius < width - 1) upperSrc += srcStrideX;
65 dst += dstStrideX;
66 }
67}
68
69static void erodeX(const SkBitmap& src, SkBitmap* dst, int radiusX)
70{
71 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
72 radiusX, src.width(), src.height(),
73 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
74}
75
76static void erodeY(const SkBitmap& src, SkBitmap* dst, int radiusY)
77{
78 erode(src.getAddr32(0, 0), dst->getAddr32(0, 0),
79 radiusY, src.height(), src.width(),
80 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
81}
82
83static void dilate(const SkPMColor* src, SkPMColor* dst,
84 int radius, int width, int height,
85 int srcStrideX, int srcStrideY,
86 int dstStrideX, int dstStrideY)
87{
senorblanco@chromium.org56dd6302012-04-10 17:25:44 +000088 radius = SkMin32(radius, width - 1);
89 const SkPMColor* upperSrc = src + radius * srcStrideX;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +000090 for (int x = 0; x < width; ++x) {
91 const SkPMColor* lp = src;
92 const SkPMColor* up = upperSrc;
93 SkPMColor* dptr = dst;
94 for (int y = 0; y < height; ++y) {
95 int maxB = 0, maxG = 0, maxR = 0, maxA = 0;
96 for (const SkPMColor* p = lp; p <= up; p += srcStrideX) {
97 int b = SkGetPackedB32(*p);
98 int g = SkGetPackedG32(*p);
99 int r = SkGetPackedR32(*p);
100 int a = SkGetPackedA32(*p);
101 if (b > maxB) maxB = b;
102 if (g > maxG) maxG = g;
103 if (r > maxR) maxR = r;
104 if (a > maxA) maxA = a;
105 }
106 *dptr = SkPackARGB32(maxA, maxR, maxG, maxB);
107 dptr += dstStrideY;
108 lp += srcStrideY;
109 up += srcStrideY;
110 }
111 if (x >= radius) src += srcStrideX;
112 if (x + radius < width - 1) upperSrc += srcStrideX;
113 dst += dstStrideX;
114 }
115}
116
117static void dilateX(const SkBitmap& src, SkBitmap* dst, int radiusX)
118{
119 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
120 radiusX, src.width(), src.height(),
121 1, src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels());
122}
123
124static void dilateY(const SkBitmap& src, SkBitmap* dst, int radiusY)
125{
126 dilate(src.getAddr32(0, 0), dst->getAddr32(0, 0),
127 radiusY, src.height(), src.width(),
128 src.rowBytesAsPixels(), 1, dst->rowBytesAsPixels(), 1);
129}
130
131bool SkErodeImageFilter::onFilterImage(Proxy*,
132 const SkBitmap& src, const SkMatrix&,
133 SkBitmap* dst, SkIPoint*) {
134 if (src.config() != SkBitmap::kARGB_8888_Config) {
135 return false;
136 }
137
138 SkAutoLockPixels alp(src);
139 if (!src.getPixels()) {
140 return false;
141 }
142
143 dst->setConfig(src.config(), src.width(), src.height());
144 dst->allocPixels();
145
146 int width = radius().width();
147 int height = radius().height();
148
149 if (width < 0 || height < 0) {
150 return false;
151 }
152
153 if (width == 0 && height == 0) {
154 src.copyTo(dst, dst->config());
155 return true;
156 }
157
158 SkBitmap temp;
159 temp.setConfig(dst->config(), dst->width(), dst->height());
160 if (!temp.allocPixels()) {
161 return false;
162 }
163
164 if (width > 0 && height > 0) {
165 erodeX(src, &temp, width);
166 erodeY(temp, dst, height);
167 } else if (width > 0) {
168 erodeX(src, dst, width);
169 } else if (height > 0) {
170 erodeY(src, dst, height);
171 }
172 return true;
173}
174
175bool SkDilateImageFilter::onFilterImage(Proxy*,
176 const SkBitmap& src, const SkMatrix&,
177 SkBitmap* dst, SkIPoint*) {
178 if (src.config() != SkBitmap::kARGB_8888_Config) {
179 return false;
180 }
181
182 SkAutoLockPixels alp(src);
183 if (!src.getPixels()) {
184 return false;
185 }
186
187 dst->setConfig(src.config(), src.width(), src.height());
188 dst->allocPixels();
189
190 int width = radius().width();
191 int height = radius().height();
192
193 if (width < 0 || height < 0) {
194 return false;
195 }
196
197 if (width == 0 && height == 0) {
198 src.copyTo(dst, dst->config());
199 return true;
200 }
201
202 SkBitmap temp;
203 temp.setConfig(dst->config(), dst->width(), dst->height());
204 if (!temp.allocPixels()) {
205 return false;
206 }
207
208 if (width > 0 && height > 0) {
209 dilateX(src, &temp, width);
210 dilateY(temp, dst, height);
211 } else if (width > 0) {
212 dilateX(src, dst, width);
213 } else if (height > 0) {
214 dilateY(src, dst, height);
215 }
216 return true;
217}
218
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +0000219GrTexture* SkDilateImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000220#if SK_SUPPORT_GPU
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +0000221 return src->getContext()->applyMorphology(src, rect,
222 GrContext::kDilate_MorphologyType,
223 radius());
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000224#else
225 SkDEBUGFAIL("Should not call in GPU-less build");
226 return NULL;
227#endif
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000228}
229
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +0000230GrTexture* SkErodeImageFilter::onFilterImageGPU(GrTexture* src, const SkRect& rect) {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000231#if SK_SUPPORT_GPU
senorblanco@chromium.org302cffb2012-08-01 20:16:34 +0000232 return src->getContext()->applyMorphology(src, rect,
233 GrContext::kErode_MorphologyType,
234 radius());
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000235#else
236 SkDEBUGFAIL("Should not call in GPU-less build");
237 return NULL;
238#endif
senorblanco@chromium.org05054f12012-03-02 21:05:45 +0000239}
240
241SK_DEFINE_FLATTENABLE_REGISTRAR(SkDilateImageFilter)
242SK_DEFINE_FLATTENABLE_REGISTRAR(SkErodeImageFilter)