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 "SkMorphologyImageFilter.h"
9 #include "SkBitmap.h"
10 #include "SkColorPriv.h"
11 #include "SkDevice.h"
12 #include "SkOpts.h"
13 #include "SkReadBuffer.h"
14 #include "SkRect.h"
15 #include "SkWriteBuffer.h"
16 #if SK_SUPPORT_GPU
17 #include "GrContext.h"
18 #include "GrDrawContext.h"
19 #include "GrInvariantOutput.h"
20 #include "GrTexture.h"
21 #include "SkGr.h"
22 #include "effects/Gr1DKernelEffect.h"
23 #include "glsl/GrGLSLFragmentProcessor.h"
24 #include "glsl/GrGLSLFragmentShaderBuilder.h"
25 #include "glsl/GrGLSLProgramDataManager.h"
26 #include "glsl/GrGLSLUniformHandler.h"
27 #endif
28
SkMorphologyImageFilter(int radiusX,int radiusY,SkImageFilter * input,const CropRect * cropRect)29 SkMorphologyImageFilter::SkMorphologyImageFilter(int radiusX,
30 int radiusY,
31 SkImageFilter* input,
32 const CropRect* cropRect)
33 : INHERITED(1, &input, cropRect), fRadius(SkISize::Make(radiusX, radiusY)) {
34 }
35
flatten(SkWriteBuffer & buffer) const36 void SkMorphologyImageFilter::flatten(SkWriteBuffer& buffer) const {
37 this->INHERITED::flatten(buffer);
38 buffer.writeInt(fRadius.fWidth);
39 buffer.writeInt(fRadius.fHeight);
40 }
41
callProcX(SkMorphologyImageFilter::Proc procX,const SkBitmap & src,SkBitmap * dst,int radiusX,const SkIRect & bounds)42 static void callProcX(SkMorphologyImageFilter::Proc procX, const SkBitmap& src, SkBitmap* dst, int radiusX, const SkIRect& bounds)
43 {
44 procX(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
45 radiusX, bounds.width(), bounds.height(),
46 src.rowBytesAsPixels(), dst->rowBytesAsPixels());
47 }
48
callProcY(SkMorphologyImageFilter::Proc procY,const SkBitmap & src,SkBitmap * dst,int radiusY,const SkIRect & bounds)49 static void callProcY(SkMorphologyImageFilter::Proc procY, const SkBitmap& src, SkBitmap* dst, int radiusY, const SkIRect& bounds)
50 {
51 procY(src.getAddr32(bounds.left(), bounds.top()), dst->getAddr32(0, 0),
52 radiusY, bounds.height(), bounds.width(),
53 src.rowBytesAsPixels(), dst->rowBytesAsPixels());
54 }
55
filterImageGeneric(SkMorphologyImageFilter::Proc procX,SkMorphologyImageFilter::Proc procY,Proxy * proxy,const SkBitmap & source,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const56 bool SkMorphologyImageFilter::filterImageGeneric(SkMorphologyImageFilter::Proc procX,
57 SkMorphologyImageFilter::Proc procY,
58 Proxy* proxy,
59 const SkBitmap& source,
60 const Context& ctx,
61 SkBitmap* dst,
62 SkIPoint* offset) const {
63 SkBitmap src = source;
64 SkIPoint srcOffset = SkIPoint::Make(0, 0);
65 if (!this->filterInputDeprecated(0, proxy, source, ctx, &src, &srcOffset)) {
66 return false;
67 }
68
69 if (src.colorType() != kN32_SkColorType) {
70 return false;
71 }
72
73 SkIRect bounds;
74 if (!this->applyCropRectDeprecated(this->mapContext(ctx), proxy, src, &srcOffset,
75 &bounds, &src)) {
76 return false;
77 }
78
79 SkAutoLockPixels alp(src);
80 if (!src.getPixels()) {
81 return false;
82 }
83
84 SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
85 SkIntToScalar(this->radius().height()));
86 ctx.ctm().mapVectors(&radius, 1);
87 int width = SkScalarFloorToInt(radius.fX);
88 int height = SkScalarFloorToInt(radius.fY);
89
90 if (width < 0 || height < 0) {
91 return false;
92 }
93
94 SkIRect srcBounds = bounds;
95 srcBounds.offset(-srcOffset);
96
97 if (width == 0 && height == 0) {
98 src.extractSubset(dst, srcBounds);
99 offset->fX = bounds.left();
100 offset->fY = bounds.top();
101 return true;
102 }
103
104 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds.width(), bounds.height()));
105 if (!device) {
106 return false;
107 }
108 *dst = device->accessBitmap(false);
109 SkAutoLockPixels alp_dst(*dst);
110
111 if (width > 0 && height > 0) {
112 SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst->height()));
113 if (!tempDevice) {
114 return false;
115 }
116 SkBitmap temp = tempDevice->accessBitmap(false);
117 SkAutoLockPixels alp_temp(temp);
118 callProcX(procX, src, &temp, width, srcBounds);
119 SkIRect tmpBounds = SkIRect::MakeWH(srcBounds.width(), srcBounds.height());
120 callProcY(procY, temp, dst, height, tmpBounds);
121 } else if (width > 0) {
122 callProcX(procX, src, dst, width, srcBounds);
123 } else if (height > 0) {
124 callProcY(procY, src, dst, height, srcBounds);
125 }
126 offset->fX = bounds.left();
127 offset->fY = bounds.top();
128 return true;
129 }
130
onFilterImageDeprecated(Proxy * proxy,const SkBitmap & source,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const131 bool SkErodeImageFilter::onFilterImageDeprecated(Proxy* proxy,
132 const SkBitmap& source, const Context& ctx,
133 SkBitmap* dst, SkIPoint* offset) const {
134 return this->filterImageGeneric(SkOpts::erode_x, SkOpts::erode_y,
135 proxy, source, ctx, dst, offset);
136 }
137
onFilterImageDeprecated(Proxy * proxy,const SkBitmap & source,const Context & ctx,SkBitmap * dst,SkIPoint * offset) const138 bool SkDilateImageFilter::onFilterImageDeprecated(Proxy* proxy,
139 const SkBitmap& source, const Context& ctx,
140 SkBitmap* dst, SkIPoint* offset) const {
141 return this->filterImageGeneric(SkOpts::dilate_x, SkOpts::dilate_y,
142 proxy, source, ctx, dst, offset);
143 }
144
computeFastBounds(const SkRect & src,SkRect * dst) const145 void SkMorphologyImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
146 if (this->getInput(0)) {
147 this->getInput(0)->computeFastBounds(src, dst);
148 } else {
149 *dst = src;
150 }
151 dst->outset(SkIntToScalar(fRadius.width()), SkIntToScalar(fRadius.height()));
152 }
153
onFilterNodeBounds(const SkIRect & src,const SkMatrix & ctm,SkIRect * dst,MapDirection) const154 void SkMorphologyImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm,
155 SkIRect* dst, MapDirection) const {
156 *dst = src;
157 SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
158 SkIntToScalar(this->radius().height()));
159 ctm.mapVectors(&radius, 1);
160 dst->outset(SkScalarCeilToInt(radius.x()), SkScalarCeilToInt(radius.y()));
161 }
162
CreateProc(SkReadBuffer & buffer)163 SkFlattenable* SkErodeImageFilter::CreateProc(SkReadBuffer& buffer) {
164 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
165 const int width = buffer.readInt();
166 const int height = buffer.readInt();
167 return Create(width, height, common.getInput(0), &common.cropRect());
168 }
169
CreateProc(SkReadBuffer & buffer)170 SkFlattenable* SkDilateImageFilter::CreateProc(SkReadBuffer& buffer) {
171 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
172 const int width = buffer.readInt();
173 const int height = buffer.readInt();
174 return Create(width, height, common.getInput(0), &common.cropRect());
175 }
176
177 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const178 void SkErodeImageFilter::toString(SkString* str) const {
179 str->appendf("SkErodeImageFilter: (");
180 str->appendf("radius: (%d,%d)", this->radius().fWidth, this->radius().fHeight);
181 str->append(")");
182 }
183 #endif
184
185 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const186 void SkDilateImageFilter::toString(SkString* str) const {
187 str->appendf("SkDilateImageFilter: (");
188 str->appendf("radius: (%d,%d)", this->radius().fWidth, this->radius().fHeight);
189 str->append(")");
190 }
191 #endif
192
193 #if SK_SUPPORT_GPU
194
195 ///////////////////////////////////////////////////////////////////////////////
196 /**
197 * Morphology effects. Depending upon the type of morphology, either the
198 * component-wise min (Erode_Type) or max (Dilate_Type) of all pixels in the
199 * kernel is selected as the new color. The new color is modulated by the input
200 * color.
201 */
202 class GrMorphologyEffect : public Gr1DKernelEffect {
203
204 public:
205
206 enum MorphologyType {
207 kErode_MorphologyType,
208 kDilate_MorphologyType,
209 };
210
Create(GrTexture * tex,Direction dir,int radius,MorphologyType type)211 static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius,
212 MorphologyType type) {
213 return new GrMorphologyEffect(tex, dir, radius, type);
214 }
215
Create(GrTexture * tex,Direction dir,int radius,MorphologyType type,float bounds[2])216 static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius,
217 MorphologyType type, float bounds[2]) {
218 return new GrMorphologyEffect(tex, dir, radius, type, bounds);
219 }
220
221 virtual ~GrMorphologyEffect();
222
type() const223 MorphologyType type() const { return fType; }
useRange() const224 bool useRange() const { return fUseRange; }
range() const225 const float* range() const { return fRange; }
226
name() const227 const char* name() const override { return "Morphology"; }
228
229 protected:
230
231 MorphologyType fType;
232 bool fUseRange;
233 float fRange[2];
234
235 private:
236 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
237
238 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
239
240 bool onIsEqual(const GrFragmentProcessor&) const override;
241
242 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
243
244 GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
245 GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType,
246 float bounds[2]);
247
248 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
249
250 typedef Gr1DKernelEffect INHERITED;
251 };
252
253 ///////////////////////////////////////////////////////////////////////////////
254
255 class GrGLMorphologyEffect : public GrGLSLFragmentProcessor {
256 public:
257 void emitCode(EmitArgs&) override;
258
259 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*);
260
261 protected:
262 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
263
264 private:
265 GrGLSLProgramDataManager::UniformHandle fPixelSizeUni;
266 GrGLSLProgramDataManager::UniformHandle fRangeUni;
267
268 typedef GrGLSLFragmentProcessor INHERITED;
269 };
270
emitCode(EmitArgs & args)271 void GrGLMorphologyEffect::emitCode(EmitArgs& args) {
272 const GrMorphologyEffect& me = args.fFp.cast<GrMorphologyEffect>();
273
274 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
275 fPixelSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
276 kFloat_GrSLType, kDefault_GrSLPrecision,
277 "PixelSize");
278 const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni);
279 fRangeUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
280 kVec2f_GrSLType, kDefault_GrSLPrecision,
281 "Range");
282 const char* range = uniformHandler->getUniformCStr(fRangeUni);
283
284 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
285 SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
286 const char* func;
287 switch (me.type()) {
288 case GrMorphologyEffect::kErode_MorphologyType:
289 fragBuilder->codeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", args.fOutputColor);
290 func = "min";
291 break;
292 case GrMorphologyEffect::kDilate_MorphologyType:
293 fragBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", args.fOutputColor);
294 func = "max";
295 break;
296 default:
297 SkFAIL("Unexpected type");
298 func = ""; // suppress warning
299 break;
300 }
301
302 const char* dir;
303 switch (me.direction()) {
304 case Gr1DKernelEffect::kX_Direction:
305 dir = "x";
306 break;
307 case Gr1DKernelEffect::kY_Direction:
308 dir = "y";
309 break;
310 default:
311 SkFAIL("Unknown filter direction.");
312 dir = ""; // suppress warning
313 }
314
315 int width = GrMorphologyEffect::WidthFromRadius(me.radius());
316
317 // vec2 coord = coord2D;
318 fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
319 // coord.x -= radius * pixelSize;
320 fragBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, me.radius(), pixelSizeInc);
321 if (me.useRange()) {
322 // highBound = min(highBound, coord.x + (width-1) * pixelSize);
323 fragBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);",
324 range, dir, float(width - 1), pixelSizeInc);
325 // coord.x = max(lowBound, coord.x);
326 fragBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir);
327 }
328 fragBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width);
329 fragBuilder->codeAppendf("\t\t\t%s = %s(%s, ", args.fOutputColor, func, args.fOutputColor);
330 fragBuilder->appendTextureLookup(args.fSamplers[0], "coord");
331 fragBuilder->codeAppend(");\n");
332 // coord.x += pixelSize;
333 fragBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc);
334 if (me.useRange()) {
335 // coord.x = min(highBound, coord.x);
336 fragBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir);
337 }
338 fragBuilder->codeAppend("\t\t}\n");
339 SkString modulate;
340 GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
341 fragBuilder->codeAppend(modulate.c_str());
342 }
343
GenKey(const GrProcessor & proc,const GrGLSLCaps &,GrProcessorKeyBuilder * b)344 void GrGLMorphologyEffect::GenKey(const GrProcessor& proc,
345 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
346 const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
347 uint32_t key = static_cast<uint32_t>(m.radius());
348 key |= (m.type() << 8);
349 key |= (m.direction() << 9);
350 if (m.useRange()) {
351 key |= 1 << 10;
352 }
353 b->add32(key);
354 }
355
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & proc)356 void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman,
357 const GrProcessor& proc) {
358 const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
359 GrTexture& texture = *m.texture(0);
360
361 float pixelSize = 0.0f;
362 switch (m.direction()) {
363 case Gr1DKernelEffect::kX_Direction:
364 pixelSize = 1.0f / texture.width();
365 break;
366 case Gr1DKernelEffect::kY_Direction:
367 pixelSize = 1.0f / texture.height();
368 break;
369 default:
370 SkFAIL("Unknown filter direction.");
371 }
372 pdman.set1f(fPixelSizeUni, pixelSize);
373
374 if (m.useRange()) {
375 const float* range = m.range();
376 if (m.direction() && texture.origin() == kBottomLeft_GrSurfaceOrigin) {
377 pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]);
378 } else {
379 pdman.set2f(fRangeUni, range[0], range[1]);
380 }
381 }
382 }
383
384 ///////////////////////////////////////////////////////////////////////////////
385
GrMorphologyEffect(GrTexture * texture,Direction direction,int radius,MorphologyType type)386 GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
387 Direction direction,
388 int radius,
389 MorphologyType type)
390 : INHERITED(texture, direction, radius)
391 , fType(type), fUseRange(false) {
392 this->initClassID<GrMorphologyEffect>();
393 }
394
GrMorphologyEffect(GrTexture * texture,Direction direction,int radius,MorphologyType type,float range[2])395 GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
396 Direction direction,
397 int radius,
398 MorphologyType type,
399 float range[2])
400 : INHERITED(texture, direction, radius)
401 , fType(type), fUseRange(true) {
402 this->initClassID<GrMorphologyEffect>();
403 fRange[0] = range[0];
404 fRange[1] = range[1];
405 }
406
~GrMorphologyEffect()407 GrMorphologyEffect::~GrMorphologyEffect() {
408 }
409
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const410 void GrMorphologyEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
411 GrProcessorKeyBuilder* b) const {
412 GrGLMorphologyEffect::GenKey(*this, caps, b);
413 }
414
onCreateGLSLInstance() const415 GrGLSLFragmentProcessor* GrMorphologyEffect::onCreateGLSLInstance() const {
416 return new GrGLMorphologyEffect;
417 }
onIsEqual(const GrFragmentProcessor & sBase) const418 bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
419 const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>();
420 return (this->radius() == s.radius() &&
421 this->direction() == s.direction() &&
422 this->useRange() == s.useRange() &&
423 this->type() == s.type());
424 }
425
onComputeInvariantOutput(GrInvariantOutput * inout) const426 void GrMorphologyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
427 // This is valid because the color components of the result of the kernel all come
428 // exactly from existing values in the source texture.
429 this->updateInvariantOutputForModulation(inout);
430 }
431
432 ///////////////////////////////////////////////////////////////////////////////
433
434 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMorphologyEffect);
435
TestCreate(GrProcessorTestData * d)436 const GrFragmentProcessor* GrMorphologyEffect::TestCreate(GrProcessorTestData* d) {
437 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
438 GrProcessorUnitTest::kAlphaTextureIdx;
439 Direction dir = d->fRandom->nextBool() ? kX_Direction : kY_Direction;
440 static const int kMaxRadius = 10;
441 int radius = d->fRandom->nextRangeU(1, kMaxRadius);
442 MorphologyType type = d->fRandom->nextBool() ? GrMorphologyEffect::kErode_MorphologyType :
443 GrMorphologyEffect::kDilate_MorphologyType;
444
445 return GrMorphologyEffect::Create(d->fTextures[texIdx], dir, radius, type);
446 }
447
448 namespace {
449
450
apply_morphology_rect(GrDrawContext * drawContext,const GrClip & clip,GrTexture * texture,const SkIRect & srcRect,const SkIRect & dstRect,int radius,GrMorphologyEffect::MorphologyType morphType,float bounds[2],Gr1DKernelEffect::Direction direction)451 void apply_morphology_rect(GrDrawContext* drawContext,
452 const GrClip& clip,
453 GrTexture* texture,
454 const SkIRect& srcRect,
455 const SkIRect& dstRect,
456 int radius,
457 GrMorphologyEffect::MorphologyType morphType,
458 float bounds[2],
459 Gr1DKernelEffect::Direction direction) {
460 GrPaint paint;
461 paint.addColorFragmentProcessor(GrMorphologyEffect::Create(texture,
462 direction,
463 radius,
464 morphType,
465 bounds))->unref();
466 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
467 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
468 SkRect::Make(srcRect));
469 }
470
apply_morphology_rect_no_bounds(GrDrawContext * drawContext,const GrClip & clip,GrTexture * texture,const SkIRect & srcRect,const SkIRect & dstRect,int radius,GrMorphologyEffect::MorphologyType morphType,Gr1DKernelEffect::Direction direction)471 void apply_morphology_rect_no_bounds(GrDrawContext* drawContext,
472 const GrClip& clip,
473 GrTexture* texture,
474 const SkIRect& srcRect,
475 const SkIRect& dstRect,
476 int radius,
477 GrMorphologyEffect::MorphologyType morphType,
478 Gr1DKernelEffect::Direction direction) {
479 GrPaint paint;
480 paint.addColorFragmentProcessor(GrMorphologyEffect::Create(texture,
481 direction,
482 radius,
483 morphType))->unref();
484 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
485 drawContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
486 SkRect::Make(srcRect));
487 }
488
apply_morphology_pass(GrDrawContext * drawContext,const GrClip & clip,GrTexture * texture,const SkIRect & srcRect,const SkIRect & dstRect,int radius,GrMorphologyEffect::MorphologyType morphType,Gr1DKernelEffect::Direction direction)489 void apply_morphology_pass(GrDrawContext* drawContext,
490 const GrClip& clip,
491 GrTexture* texture,
492 const SkIRect& srcRect,
493 const SkIRect& dstRect,
494 int radius,
495 GrMorphologyEffect::MorphologyType morphType,
496 Gr1DKernelEffect::Direction direction) {
497 float bounds[2] = { 0.0f, 1.0f };
498 SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
499 SkIRect middleSrcRect = srcRect, middleDstRect = dstRect;
500 SkIRect upperSrcRect = srcRect, upperDstRect = dstRect;
501 if (direction == Gr1DKernelEffect::kX_Direction) {
502 bounds[0] = (SkIntToScalar(srcRect.left()) + 0.5f) / texture->width();
503 bounds[1] = (SkIntToScalar(srcRect.right()) - 0.5f) / texture->width();
504 lowerSrcRect.fRight = srcRect.left() + radius;
505 lowerDstRect.fRight = dstRect.left() + radius;
506 upperSrcRect.fLeft = srcRect.right() - radius;
507 upperDstRect.fLeft = dstRect.right() - radius;
508 middleSrcRect.inset(radius, 0);
509 middleDstRect.inset(radius, 0);
510 } else {
511 bounds[0] = (SkIntToScalar(srcRect.top()) + 0.5f) / texture->height();
512 bounds[1] = (SkIntToScalar(srcRect.bottom()) - 0.5f) / texture->height();
513 lowerSrcRect.fBottom = srcRect.top() + radius;
514 lowerDstRect.fBottom = dstRect.top() + radius;
515 upperSrcRect.fTop = srcRect.bottom() - radius;
516 upperDstRect.fTop = dstRect.bottom() - radius;
517 middleSrcRect.inset(0, radius);
518 middleDstRect.inset(0, radius);
519 }
520 if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) {
521 // radius covers srcRect; use bounds over entire draw
522 apply_morphology_rect(drawContext, clip, texture, srcRect, dstRect, radius,
523 morphType, bounds, direction);
524 } else {
525 // Draw upper and lower margins with bounds; middle without.
526 apply_morphology_rect(drawContext, clip, texture, lowerSrcRect, lowerDstRect, radius,
527 morphType, bounds, direction);
528 apply_morphology_rect(drawContext, clip, texture, upperSrcRect, upperDstRect, radius,
529 morphType, bounds, direction);
530 apply_morphology_rect_no_bounds(drawContext, clip, texture, middleSrcRect, middleDstRect,
531 radius, morphType, direction);
532 }
533 }
534
apply_morphology(const SkBitmap & input,const SkIRect & rect,GrMorphologyEffect::MorphologyType morphType,SkISize radius,SkBitmap * dst)535 bool apply_morphology(const SkBitmap& input,
536 const SkIRect& rect,
537 GrMorphologyEffect::MorphologyType morphType,
538 SkISize radius,
539 SkBitmap* dst) {
540 SkAutoTUnref<GrTexture> srcTexture(SkRef(input.getTexture()));
541 SkASSERT(srcTexture);
542 GrContext* context = srcTexture->getContext();
543
544 // setup new clip
545 GrClip clip(SkRect::MakeWH(SkIntToScalar(srcTexture->width()),
546 SkIntToScalar(srcTexture->height())));
547
548 SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height());
549 GrSurfaceDesc desc;
550 desc.fFlags = kRenderTarget_GrSurfaceFlag;
551 desc.fWidth = rect.width();
552 desc.fHeight = rect.height();
553 desc.fConfig = kSkia8888_GrPixelConfig;
554 SkIRect srcRect = rect;
555
556 if (radius.fWidth > 0) {
557 GrTexture* scratch = context->textureProvider()->createApproxTexture(desc);
558 if (nullptr == scratch) {
559 return false;
560 }
561 SkAutoTUnref<GrDrawContext> dstDrawContext(
562 context->drawContext(scratch->asRenderTarget()));
563 if (!dstDrawContext) {
564 return false;
565 }
566
567 apply_morphology_pass(dstDrawContext, clip, srcTexture,
568 srcRect, dstRect, radius.fWidth, morphType,
569 Gr1DKernelEffect::kX_Direction);
570 SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom,
571 dstRect.width(), radius.fHeight);
572 GrColor clearColor = GrMorphologyEffect::kErode_MorphologyType == morphType ?
573 SK_ColorWHITE :
574 SK_ColorTRANSPARENT;
575 dstDrawContext->clear(&clearRect, clearColor, false);
576
577 srcTexture.reset(scratch);
578 srcRect = dstRect;
579 }
580 if (radius.fHeight > 0) {
581 GrTexture* scratch = context->textureProvider()->createApproxTexture(desc);
582 if (nullptr == scratch) {
583 return false;
584 }
585 SkAutoTUnref<GrDrawContext> dstDrawContext(
586 context->drawContext(scratch->asRenderTarget()));
587 if (!dstDrawContext) {
588 return false;
589 }
590
591 apply_morphology_pass(dstDrawContext, clip, srcTexture,
592 srcRect, dstRect, radius.fHeight, morphType,
593 Gr1DKernelEffect::kY_Direction);
594
595 srcTexture.reset(scratch);
596 }
597 GrWrapTextureInBitmap(srcTexture, rect.width(), rect.height(), false, dst);
598 return true;
599 }
600
601 };
602
filterImageGPUGeneric(bool dilate,Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const603 bool SkMorphologyImageFilter::filterImageGPUGeneric(bool dilate,
604 Proxy* proxy,
605 const SkBitmap& src,
606 const Context& ctx,
607 SkBitmap* result,
608 SkIPoint* offset) const {
609 SkBitmap input = src;
610 SkIPoint srcOffset = SkIPoint::Make(0, 0);
611 if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) {
612 return false;
613 }
614 SkIRect bounds;
615 if (!this->applyCropRectDeprecated(this->mapContext(ctx), proxy, input, &srcOffset,
616 &bounds, &input)) {
617 return false;
618 }
619 SkVector radius = SkVector::Make(SkIntToScalar(this->radius().width()),
620 SkIntToScalar(this->radius().height()));
621 ctx.ctm().mapVectors(&radius, 1);
622 int width = SkScalarFloorToInt(radius.fX);
623 int height = SkScalarFloorToInt(radius.fY);
624
625 if (width < 0 || height < 0) {
626 return false;
627 }
628
629 SkIRect srcBounds = bounds;
630 srcBounds.offset(-srcOffset);
631 if (width == 0 && height == 0) {
632 input.extractSubset(result, srcBounds);
633 offset->fX = bounds.left();
634 offset->fY = bounds.top();
635 return true;
636 }
637
638 GrMorphologyEffect::MorphologyType type = dilate ? GrMorphologyEffect::kDilate_MorphologyType
639 : GrMorphologyEffect::kErode_MorphologyType;
640 if (!apply_morphology(input, srcBounds, type, SkISize::Make(width, height), result)) {
641 return false;
642 }
643 offset->fX = bounds.left();
644 offset->fY = bounds.top();
645 return true;
646 }
647
filterImageGPUDeprecated(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const648 bool SkDilateImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src,
649 const Context& ctx,
650 SkBitmap* result, SkIPoint* offset) const {
651 return this->filterImageGPUGeneric(true, proxy, src, ctx, result, offset);
652 }
653
filterImageGPUDeprecated(Proxy * proxy,const SkBitmap & src,const Context & ctx,SkBitmap * result,SkIPoint * offset) const654 bool SkErodeImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src,
655 const Context& ctx,
656 SkBitmap* result, SkIPoint* offset) const {
657 return this->filterImageGPUGeneric(false, proxy, src, ctx, result, offset);
658 }
659
660 #endif
661