OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkImageFilter.h" | 8 #include "SkImageFilter.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 } | 59 } |
60 if (fFlags & CropRect::kHasHeight_CropEdge) { | 60 if (fFlags & CropRect::kHasHeight_CropEdge) { |
61 str->appendf("%.2f", fRect.height()); | 61 str->appendf("%.2f", fRect.height()); |
62 } else { | 62 } else { |
63 str->appendf("X"); | 63 str->appendf("X"); |
64 } | 64 } |
65 str->appendf(") "); | 65 str->appendf(") "); |
66 } | 66 } |
67 #endif | 67 #endif |
68 | 68 |
69 bool SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds, const Context&
ctx, | 69 void SkImageFilter::CropRect::applyTo(const SkIRect& imageBounds, |
| 70 const SkMatrix& ctm, |
70 SkIRect* cropped) const { | 71 SkIRect* cropped) const { |
71 *cropped = imageBounds; | 72 *cropped = imageBounds; |
72 if (fFlags) { | 73 if (fFlags) { |
73 SkRect devCropR; | 74 SkRect devCropR; |
74 ctx.ctm().mapRect(&devCropR, fRect); | 75 ctm.mapRect(&devCropR, fRect); |
75 const SkIRect devICropR = devCropR.roundOut(); | 76 const SkIRect devICropR = devCropR.roundOut(); |
76 | 77 |
77 // Compute the left/top first, in case we have to read them to compute r
ight/bottom | 78 // Compute the left/top first, in case we have to read them to compute r
ight/bottom |
78 if (fFlags & kHasLeft_CropEdge) { | 79 if (fFlags & kHasLeft_CropEdge) { |
79 cropped->fLeft = devICropR.fLeft; | 80 cropped->fLeft = devICropR.fLeft; |
80 } | 81 } |
81 if (fFlags & kHasTop_CropEdge) { | 82 if (fFlags & kHasTop_CropEdge) { |
82 cropped->fTop = devICropR.fTop; | 83 cropped->fTop = devICropR.fTop; |
83 } | 84 } |
84 if (fFlags & kHasWidth_CropEdge) { | 85 if (fFlags & kHasWidth_CropEdge) { |
85 cropped->fRight = cropped->fLeft + devICropR.width(); | 86 cropped->fRight = cropped->fLeft + devICropR.width(); |
86 } | 87 } |
87 if (fFlags & kHasHeight_CropEdge) { | 88 if (fFlags & kHasHeight_CropEdge) { |
88 cropped->fBottom = cropped->fTop + devICropR.height(); | 89 cropped->fBottom = cropped->fTop + devICropR.height(); |
89 } | 90 } |
90 } | 91 } |
91 // Intersect against the clip bounds, in case the crop rect has | |
92 // grown the bounds beyond the original clip. This can happen for | |
93 // example in tiling, where the clip is much smaller than the filtered | |
94 // primitive. If we didn't do this, we would be processing the filter | |
95 // at the full crop rect size in every tile. | |
96 return cropped->intersect(ctx.clipBounds()); | |
97 } | 92 } |
98 | 93 |
99 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 94 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
100 | 95 |
101 static int32_t next_image_filter_unique_id() { | 96 static int32_t next_image_filter_unique_id() { |
102 static int32_t gImageFilterUniqueID; | 97 static int32_t gImageFilterUniqueID; |
103 | 98 |
104 // Never return 0. | 99 // Never return 0. |
105 int32_t id; | 100 int32_t id; |
106 do { | 101 do { |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src, | 262 bool SkImageFilter::filterInput(int index, Proxy* proxy, const SkBitmap& src, |
268 const Context& ctx, | 263 const Context& ctx, |
269 SkBitmap* result, SkIPoint* offset) const { | 264 SkBitmap* result, SkIPoint* offset) const { |
270 SkImageFilter* input = this->getInput(index); | 265 SkImageFilter* input = this->getInput(index); |
271 if (!input) { | 266 if (!input) { |
272 return true; | 267 return true; |
273 } | 268 } |
274 return input->filterImage(proxy, src, this->mapContext(ctx), result, offset)
; | 269 return input->filterImage(proxy, src, this->mapContext(ctx), result, offset)
; |
275 } | 270 } |
276 | 271 |
277 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRec
t* dst) const { | 272 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRec
t* dst, |
| 273 MapDirection direction) const { |
278 SkASSERT(dst); | 274 SkASSERT(dst); |
279 return this->onFilterBounds(src, ctm, dst); | 275 SkIRect bounds; |
| 276 if (kReverse_MapDirection == direction) { |
| 277 this->onFilterNodeBounds(src, ctm, &bounds, direction); |
| 278 return this->onFilterBounds(bounds, ctm, dst, direction); |
| 279 } else { |
| 280 SkIRect temp; |
| 281 if (!this->onFilterBounds(src, ctm, &bounds, direction)) { |
| 282 return false; |
| 283 } |
| 284 this->onFilterNodeBounds(bounds, ctm, &temp, direction); |
| 285 this->getCropRect().applyTo(temp, ctm, dst); |
| 286 return true; |
| 287 } |
280 } | 288 } |
281 | 289 |
282 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { | 290 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { |
283 if (0 == fInputCount) { | 291 if (0 == fInputCount) { |
284 *dst = src; | 292 *dst = src; |
285 return; | 293 return; |
286 } | 294 } |
287 if (this->getInput(0)) { | 295 if (this->getInput(0)) { |
288 this->getInput(0)->computeFastBounds(src, dst); | 296 this->getInput(0)->computeFastBounds(src, dst); |
289 } else { | 297 } else { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, | 397 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, |
390 const SkIPoint& srcOffset, SkIRect* dstBounds, | 398 const SkIPoint& srcOffset, SkIRect* dstBounds, |
391 SkIRect* srcBounds) const { | 399 SkIRect* srcBounds) const { |
392 SkIRect storage; | 400 SkIRect storage; |
393 if (!srcBounds) { | 401 if (!srcBounds) { |
394 srcBounds = &storage; | 402 srcBounds = &storage; |
395 } | 403 } |
396 src.getBounds(srcBounds); | 404 src.getBounds(srcBounds); |
397 srcBounds->offset(srcOffset); | 405 srcBounds->offset(srcOffset); |
398 this->onFilterNodeBounds(*srcBounds, ctx.ctm(), dstBounds, kForward_MapDirec
tion); | 406 this->onFilterNodeBounds(*srcBounds, ctx.ctm(), dstBounds, kForward_MapDirec
tion); |
399 return fCropRect.applyTo(*dstBounds, ctx, dstBounds); | 407 fCropRect.applyTo(*dstBounds, ctx.ctm(), dstBounds); |
| 408 // Intersect against the clip bounds, in case the crop rect has |
| 409 // grown the bounds beyond the original clip. This can happen for |
| 410 // example in tiling, where the clip is much smaller than the filtered |
| 411 // primitive. If we didn't do this, we would be processing the filter |
| 412 // at the full crop rect size in every tile. |
| 413 return dstBounds->intersect(ctx.clipBounds()); |
400 } | 414 } |
401 | 415 |
402 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitm
ap& src, | 416 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitm
ap& src, |
403 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap
* dst) const { | 417 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap
* dst) const { |
404 SkIRect srcBounds; | 418 SkIRect srcBounds; |
405 src.getBounds(&srcBounds); | 419 src.getBounds(&srcBounds); |
406 srcBounds.offset(*srcOffset); | 420 srcBounds.offset(*srcOffset); |
407 SkIRect dstBounds; | 421 SkIRect dstBounds; |
408 this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirec
tion); | 422 this->onFilterNodeBounds(srcBounds, ctx.ctm(), &dstBounds, kForward_MapDirec
tion); |
409 if (!fCropRect.applyTo(dstBounds, ctx, bounds)) { | 423 fCropRect.applyTo(dstBounds, ctx.ctm(), bounds); |
| 424 if (!bounds->intersect(ctx.clipBounds())) { |
410 return false; | 425 return false; |
411 } | 426 } |
412 | 427 |
413 if (srcBounds.contains(*bounds)) { | 428 if (srcBounds.contains(*bounds)) { |
414 *dst = src; | 429 *dst = src; |
415 return true; | 430 return true; |
416 } else { | 431 } else { |
417 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), b
ounds->height())); | 432 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), b
ounds->height())); |
418 if (!device) { | 433 if (!device) { |
419 return false; | 434 return false; |
420 } | 435 } |
421 SkCanvas canvas(device); | 436 SkCanvas canvas(device); |
422 canvas.clear(0x00000000); | 437 canvas.clear(0x00000000); |
423 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bo
unds->y()); | 438 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bo
unds->y()); |
424 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); | 439 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); |
425 *dst = device->accessBitmap(false); | 440 *dst = device->accessBitmap(false); |
426 return true; | 441 return true; |
427 } | 442 } |
428 } | 443 } |
429 | 444 |
430 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, | 445 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, |
431 SkIRect* dst) const { | 446 SkIRect* dst, MapDirection direction) const { |
432 if (fInputCount < 1) { | 447 if (fInputCount < 1) { |
433 *dst = src; | 448 *dst = src; |
434 return true; | 449 return true; |
435 } | 450 } |
436 | 451 |
437 SkIRect bounds, totalBounds; | 452 SkIRect totalBounds; |
438 this->onFilterNodeBounds(src, ctm, &bounds, kReverse_MapDirection); | |
439 for (int i = 0; i < fInputCount; ++i) { | 453 for (int i = 0; i < fInputCount; ++i) { |
440 SkImageFilter* filter = this->getInput(i); | 454 SkImageFilter* filter = this->getInput(i); |
441 SkIRect rect = bounds; | 455 SkIRect rect = src; |
442 if (filter && !filter->filterBounds(bounds, ctm, &rect)) { | 456 if (filter && !filter->filterBounds(src, ctm, &rect, direction)) { |
443 return false; | 457 return false; |
444 } | 458 } |
445 if (0 == i) { | 459 if (0 == i) { |
446 totalBounds = rect; | 460 totalBounds = rect; |
447 } else { | 461 } else { |
448 totalBounds.join(rect); | 462 totalBounds.join(rect); |
449 } | 463 } |
450 } | 464 } |
451 | 465 |
452 // don't modify dst until now, so we don't accidentally change it in the | 466 // don't modify dst until now, so we don't accidentally change it in the |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 } | 672 } |
659 return dev; | 673 return dev; |
660 } | 674 } |
661 | 675 |
662 bool SkImageFilter::DeviceProxy::filterImage(const SkImageFilter* filter, const
SkBitmap& src, | 676 bool SkImageFilter::DeviceProxy::filterImage(const SkImageFilter* filter, const
SkBitmap& src, |
663 const SkImageFilter::Context& ctx, | 677 const SkImageFilter::Context& ctx, |
664 SkBitmap* result, SkIPoint* offset) { | 678 SkBitmap* result, SkIPoint* offset) { |
665 return fDevice->filterImage(filter, src, ctx, result, offset); | 679 return fDevice->filterImage(filter, src, ctx, result, offset); |
666 } | 680 } |
667 | 681 |
OLD | NEW |