| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkBlurMask.h" | 10 #include "SkBlurMask.h" |
| 11 #include "SkMath.h" | 11 #include "SkMath.h" |
| 12 #include "SkResourceCache.h" |
| 12 #include "SkTemplates.h" | 13 #include "SkTemplates.h" |
| 13 #include "SkEndian.h" | 14 #include "SkEndian.h" |
| 14 | 15 |
| 15 | 16 |
| 16 // This constant approximates the scaling done in the software path's | 17 // This constant approximates the scaling done in the software path's |
| 17 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). | 18 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). |
| 18 // IMHO, it actually should be 1: we blur "less" than we should do | 19 // IMHO, it actually should be 1: we blur "less" than we should do |
| 19 // according to the CSS and canvas specs, simply because Safari does the same. | 20 // according to the CSS and canvas specs, simply because Safari does the same. |
| 20 // Firefox used to do the same too, until 4.0 where they fixed it. So at some | 21 // Firefox used to do the same too, until 4.0 where they fixed it. So at some |
| 21 // point we should probably get rid of these scaling constants and rebaseline | 22 // point we should probably get rid of these scaling constants and rebaseline |
| (...skipping 450 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 472 | 473 |
| 473 /////////////////////////////////////////////////////////////////////////////// | 474 /////////////////////////////////////////////////////////////////////////////// |
| 474 | 475 |
| 475 // we use a local function to wrap the class static method to work around | 476 // we use a local function to wrap the class static method to work around |
| 476 // a bug in gcc98 | 477 // a bug in gcc98 |
| 477 void SkMask_FreeImage(uint8_t* image); | 478 void SkMask_FreeImage(uint8_t* image); |
| 478 void SkMask_FreeImage(uint8_t* image) { | 479 void SkMask_FreeImage(uint8_t* image) { |
| 479 SkMask::FreeImage(image); | 480 SkMask::FreeImage(image); |
| 480 } | 481 } |
| 481 | 482 |
| 483 SkBitmap createBitmap(const SkImageInfo& info, size_t rowBytes) { |
| 484 SkBitmap bitmap; |
| 485 SkBitmap::Allocator* allocator = SkResourceCache::GetAllocator(); |
| 486 bitmap.setInfo(info, rowBytes); |
| 487 bitmap.allocPixels(allocator, NULL); |
| 488 return bitmap; |
| 489 } |
| 490 |
| 482 bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, | 491 bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, |
| 483 SkScalar sigma, SkBlurStyle style, SkBlurQuality qualit
y, | 492 SkScalar sigma, SkBlurStyle style, SkBlurQuality qualit
y, |
| 484 SkIPoint* margin, bool force_quality) { | 493 SkIPoint* margin, bool force_quality) { |
| 485 | 494 |
| 486 if (src.fFormat != SkMask::kA8_Format) { | 495 if (src.fFormat != SkMask::kA8_Format) { |
| 487 return false; | 496 return false; |
| 488 } | 497 } |
| 489 | 498 |
| 490 // Force high quality off for small radii (performance) | 499 // Force high quality off for small radii (performance) |
| 491 if (!force_quality && sigma <= SkIntToScalar(2)) { | 500 if (!force_quality && sigma <= SkIntToScalar(2)) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 | 543 |
| 535 if (src.fImage) { | 544 if (src.fImage) { |
| 536 size_t dstSize = dst->computeImageSize(); | 545 size_t dstSize = dst->computeImageSize(); |
| 537 if (0 == dstSize) { | 546 if (0 == dstSize) { |
| 538 return false; // too big to allocate, abort | 547 return false; // too big to allocate, abort |
| 539 } | 548 } |
| 540 | 549 |
| 541 int sw = src.fBounds.width(); | 550 int sw = src.fBounds.width(); |
| 542 int sh = src.fBounds.height(); | 551 int sh = src.fBounds.height(); |
| 543 const uint8_t* sp = src.fImage; | 552 const uint8_t* sp = src.fImage; |
| 544 uint8_t* dp = SkMask::AllocImage(dstSize); | 553 SkBitmap bitmap; |
| 545 SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); | 554 bitmap = createBitmap(SkImageInfo::MakeA8(dst->fBounds.width(),dst->fBou
nds.height()), dst->fRowBytes); |
| 555 SkAutoLockPixels alp(bitmap); |
| 556 uint8_t* dp = bitmap.getAddr8(0, 0); |
| 546 | 557 |
| 547 // build the blurry destination | 558 // build the blurry destination |
| 548 SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); | 559 SkAutoTMalloc<uint8_t> tmpBuffer(dstSize); |
| 549 uint8_t* tp = tmpBuffer.get(); | 560 uint8_t* tp = tmpBuffer.get(); |
| 550 int w = sw, h = sh; | 561 int w = sw, h = sh; |
| 551 | 562 |
| 552 if (outerWeight == 255) { | 563 if (outerWeight == 255) { |
| 553 int loRadius, hiRadius; | 564 int loRadius, hiRadius; |
| 554 get_adjusted_radii(passRadius, &loRadius, &hiRadius); | 565 get_adjusted_radii(passRadius, &loRadius, &hiRadius); |
| 555 if (kHigh_SkBlurQuality == quality) { | 566 if (kHigh_SkBlurQuality == quality) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 575 h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerW
eight); | 586 h = boxBlurInterp(tp, h, dp, ry, h, w, false, outerW
eight); |
| 576 h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerW
eight); | 587 h = boxBlurInterp(dp, h, tp, ry, h, w, false, outerW
eight); |
| 577 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe
ight); | 588 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe
ight); |
| 578 } else { | 589 } else { |
| 579 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWe
ight); | 590 w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, true, outerWe
ight); |
| 580 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe
ight); | 591 h = boxBlurInterp(tp, h, dp, ry, h, w, true, outerWe
ight); |
| 581 } | 592 } |
| 582 } | 593 } |
| 583 | 594 |
| 584 dst->fImage = dp; | 595 dst->fImage = dp; |
| 596 dst->fBitmap = bitmap; |
| 585 // if need be, alloc the "real" dst (same size as src) and copy/merge | 597 // if need be, alloc the "real" dst (same size as src) and copy/merge |
| 586 // the blur into it (applying the src) | 598 // the blur into it (applying the src) |
| 587 if (style == kInner_SkBlurStyle) { | 599 if (style == kInner_SkBlurStyle) { |
| 588 // now we allocate the "real" dst, mirror the size of src | 600 // now we allocate the "real" dst, mirror the size of src |
| 589 size_t srcSize = src.computeImageSize(); | 601 size_t srcSize = src.computeImageSize(); |
| 590 if (0 == srcSize) { | 602 if (0 == srcSize) { |
| 591 return false; // too big to allocate, abort | 603 return false; // too big to allocate, abort |
| 592 } | 604 } |
| 593 dst->fImage = SkMask::AllocImage(srcSize); | 605 dst->fBitmap = createBitmap(SkImageInfo::MakeA8(sw, sh), src.fRowByt
es); |
| 606 SkAutoLockPixels alp(dst->fBitmap); |
| 607 dst->fImage = dst->fBitmap.getAddr8(0, 0); |
| 594 merge_src_with_blur(dst->fImage, src.fRowBytes, | 608 merge_src_with_blur(dst->fImage, src.fRowBytes, |
| 595 sp, src.fRowBytes, | 609 sp, src.fRowBytes, |
| 596 dp + passCount * (rx + ry * dst->fRowBytes), | 610 dp + passCount * (rx + ry * dst->fRowBytes), |
| 597 dst->fRowBytes, sw, sh); | 611 dst->fRowBytes, sw, sh); |
| 598 SkMask::FreeImage(dp); | |
| 599 } else if (style != kNormal_SkBlurStyle) { | 612 } else if (style != kNormal_SkBlurStyle) { |
| 600 clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), | 613 clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), |
| 601 dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); | 614 dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); |
| 602 } | 615 } |
| 603 (void)autoCall.detach(); | |
| 604 } | 616 } |
| 605 | 617 |
| 606 if (style == kInner_SkBlurStyle) { | 618 if (style == kInner_SkBlurStyle) { |
| 607 dst->fBounds = src.fBounds; // restore trimmed bounds | 619 dst->fBounds = src.fBounds; // restore trimmed bounds |
| 608 dst->fRowBytes = src.fRowBytes; | 620 dst->fRowBytes = src.fRowBytes; |
| 609 } | 621 } |
| 610 | 622 |
| 611 return true; | 623 return true; |
| 612 } | 624 } |
| 613 | 625 |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 uint8_t *profile = NULL; | 784 uint8_t *profile = NULL; |
| 773 | 785 |
| 774 ComputeBlurProfile(sigma, &profile); | 786 ComputeBlurProfile(sigma, &profile); |
| 775 SkAutoTDeleteArray<uint8_t> ada(profile); | 787 SkAutoTDeleteArray<uint8_t> ada(profile); |
| 776 | 788 |
| 777 size_t dstSize = dst->computeImageSize(); | 789 size_t dstSize = dst->computeImageSize(); |
| 778 if (0 == dstSize) { | 790 if (0 == dstSize) { |
| 779 return false; // too big to allocate, abort | 791 return false; // too big to allocate, abort |
| 780 } | 792 } |
| 781 | 793 |
| 782 uint8_t* dp = SkMask::AllocImage(dstSize); | |
| 783 | |
| 784 dst->fImage = dp; | |
| 785 | |
| 786 int dstHeight = dst->fBounds.height(); | 794 int dstHeight = dst->fBounds.height(); |
| 787 int dstWidth = dst->fBounds.width(); | 795 int dstWidth = dst->fBounds.width(); |
| 788 | 796 |
| 797 SkBitmap bitmap = createBitmap(SkImageInfo::MakeA8(dstWidth, dstHeight), dst
->fRowBytes); |
| 798 SkAutoLockPixels alp(bitmap); |
| 799 uint8_t* dp = bitmap.getAddr8(0, 0); |
| 800 dst->fImage = dp; |
| 801 dst->fBitmap = bitmap; |
| 802 |
| 789 uint8_t *outptr = dp; | 803 uint8_t *outptr = dp; |
| 790 | 804 |
| 791 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); | 805 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); |
| 792 SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); | 806 SkAutoTMalloc<uint8_t> verticalScanline(dstHeight); |
| 793 | 807 |
| 794 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma); | 808 ComputeBlurredScanline(horizontalScanline, profile, dstWidth, sigma); |
| 795 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma); | 809 ComputeBlurredScanline(verticalScanline, profile, dstHeight, sigma); |
| 796 | 810 |
| 797 for (int y = 0 ; y < dstHeight ; ++y) { | 811 for (int y = 0 ; y < dstHeight ; ++y) { |
| 798 for (int x = 0 ; x < dstWidth ; x++) { | 812 for (int x = 0 ; x < dstWidth ; x++) { |
| 799 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verti
calScanline[y]); | 813 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], verti
calScanline[y]); |
| 800 *(outptr++) = maskval; | 814 *(outptr++) = maskval; |
| 801 } | 815 } |
| 802 } | 816 } |
| 803 | 817 |
| 804 if (style == kInner_SkBlurStyle) { | 818 if (style == kInner_SkBlurStyle) { |
| 805 // now we allocate the "real" dst, mirror the size of src | 819 // now we allocate the "real" dst, mirror the size of src |
| 806 size_t srcSize = (size_t)(src.width() * src.height()); | 820 size_t srcSize = (size_t)(src.width() * src.height()); |
| 807 if (0 == srcSize) { | 821 if (0 == srcSize) { |
| 808 return false; // too big to allocate, abort | 822 return false; // too big to allocate, abort |
| 809 } | 823 } |
| 810 dst->fImage = SkMask::AllocImage(srcSize); | |
| 811 for (int y = 0 ; y < sh ; y++) { | |
| 812 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; | |
| 813 uint8_t *inner_scanline = dst->fImage + y*sw; | |
| 814 memcpy(inner_scanline, blur_scanline, sw); | |
| 815 } | |
| 816 SkMask::FreeImage(dp); | |
| 817 | |
| 818 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), | 824 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), |
| 819 SkScalarRoundToInt(src.fTop), | 825 SkScalarRoundToInt(src.fTop), |
| 820 SkScalarRoundToInt(src.fRight), | 826 SkScalarRoundToInt(src.fRight), |
| 821 SkScalarRoundToInt(src.fBottom)); // restore trimmed bo
unds | 827 SkScalarRoundToInt(src.fBottom)); // restore trimmed bo
unds |
| 822 dst->fRowBytes = sw; | 828 dst->fRowBytes = sw; |
| 823 | 829 |
| 830 dst->fBitmap = createBitmap(SkImageInfo::MakeA8(dst->fBounds.width(), |
| 831 dst->fBounds.height()), dst->fRowBytes); |
| 832 SkAutoLockPixels alp(dst->fBitmap); |
| 833 dst->fImage = dst->fBitmap.getAddr8(0, 0); |
| 834 for (int y = 0 ; y < sh ; y++) { |
| 835 uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; |
| 836 uint8_t *inner_scanline = dst->fImage + y*sw; |
| 837 memcpy(inner_scanline, blur_scanline, sw); |
| 838 } |
| 824 } else if (style == kOuter_SkBlurStyle) { | 839 } else if (style == kOuter_SkBlurStyle) { |
| 825 for (int y = pad ; y < dstHeight-pad ; y++) { | 840 for (int y = pad ; y < dstHeight-pad ; y++) { |
| 826 uint8_t *dst_scanline = dp + y*dstWidth + pad; | 841 uint8_t *dst_scanline = dp + y*dstWidth + pad; |
| 827 memset(dst_scanline, 0, sw); | 842 memset(dst_scanline, 0, sw); |
| 828 } | 843 } |
| 829 } else if (style == kSolid_SkBlurStyle) { | 844 } else if (style == kSolid_SkBlurStyle) { |
| 830 for (int y = pad ; y < dstHeight-pad ; y++) { | 845 for (int y = pad ; y < dstHeight-pad ; y++) { |
| 831 uint8_t *dst_scanline = dp + y*dstWidth + pad; | 846 uint8_t *dst_scanline = dp + y*dstWidth + pad; |
| 832 memset(dst_scanline, 0xff, sw); | 847 memset(dst_scanline, 0xff, sw); |
| 833 } | 848 } |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 (void)autoCall.detach(); | 1002 (void)autoCall.detach(); |
| 988 } | 1003 } |
| 989 | 1004 |
| 990 if (style == kInner_SkBlurStyle) { | 1005 if (style == kInner_SkBlurStyle) { |
| 991 dst->fBounds = src.fBounds; // restore trimmed bounds | 1006 dst->fBounds = src.fBounds; // restore trimmed bounds |
| 992 dst->fRowBytes = src.fRowBytes; | 1007 dst->fRowBytes = src.fRowBytes; |
| 993 } | 1008 } |
| 994 | 1009 |
| 995 return true; | 1010 return true; |
| 996 } | 1011 } |
| OLD | NEW |