| 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" |
| (...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 | 664 |
| 665 if ( x > 0.5f ) { | 665 if ( x > 0.5f ) { |
| 666 return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x); | 666 return 0.5625f - (x3 / 6.0f - 3.0f * x2 * 0.25f + 1.125f * x); |
| 667 } | 667 } |
| 668 if ( x > -0.5f ) { | 668 if ( x > -0.5f ) { |
| 669 return 0.5f - (0.75f * x - x3 / 3.0f); | 669 return 0.5f - (0.75f * x - x3 / 3.0f); |
| 670 } | 670 } |
| 671 return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); | 671 return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x); |
| 672 } | 672 } |
| 673 | 673 |
| 674 /* compute_profile allocates and fills in an array of floating | 674 /* ComputeBlurProfile allocates and fills in an array of floating |
| 675 point values between 0 and 255 for the profile signature of | 675 point values between 0 and 255 for the profile signature of |
| 676 a blurred half-plane with the given blur radius. Since we're | 676 a blurred half-plane with the given blur radius. Since we're |
| 677 going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) | 677 going to be doing screened multiplications (i.e., 1 - (1-x)(1-y)) |
| 678 all the time, we actually fill in the profile pre-inverted | 678 all the time, we actually fill in the profile pre-inverted |
| 679 (already done 255-x). | 679 (already done 255-x). |
| 680 | 680 |
| 681 It's the responsibility of the caller to delete the | 681 It's the responsibility of the caller to delete the |
| 682 memory returned in profile_out. | 682 memory returned in profile_out. |
| 683 */ | 683 */ |
| 684 | 684 |
| 685 static void compute_profile(SkScalar sigma, unsigned int **profile_out) { | 685 void SkBlurMask::ComputeBlurProfile(SkScalar sigma, uint8_t **profile_out) { |
| 686 int size = SkScalarCeilToInt(6*sigma); | 686 int size = SkScalarCeilToInt(6*sigma); |
| 687 | 687 |
| 688 int center = size >> 1; | 688 int center = size >> 1; |
| 689 unsigned int *profile = SkNEW_ARRAY(unsigned int, size); | 689 uint8_t *profile = SkNEW_ARRAY(uint8_t, size); |
| 690 | 690 |
| 691 float invr = 1.f/(2*sigma); | 691 float invr = 1.f/(2*sigma); |
| 692 | 692 |
| 693 profile[0] = 255; | 693 profile[0] = 255; |
| 694 for (int x = 1 ; x < size ; ++x) { | 694 for (int x = 1 ; x < size ; ++x) { |
| 695 float scaled_x = (center - x - .5f) * invr; | 695 float scaled_x = (center - x - .5f) * invr; |
| 696 float gi = gaussianIntegral(scaled_x); | 696 float gi = gaussianIntegral(scaled_x); |
| 697 profile[x] = 255 - (uint8_t) (255.f * gi); | 697 profile[x] = 255 - (uint8_t) (255.f * gi); |
| 698 } | 698 } |
| 699 | 699 |
| 700 *profile_out = profile; | 700 *profile_out = profile; |
| 701 } | 701 } |
| 702 | 702 |
| 703 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for | 703 // TODO MAYBE: Maintain a profile cache to avoid recomputing this for |
| 704 // commonly used radii. Consider baking some of the most common blur radii | 704 // commonly used radii. Consider baking some of the most common blur radii |
| 705 // directly in as static data? | 705 // directly in as static data? |
| 706 | 706 |
| 707 // Implementation adapted from Michael Herf's approach: | 707 // Implementation adapted from Michael Herf's approach: |
| 708 // http://stereopsis.com/shadowrect/ | 708 // http://stereopsis.com/shadowrect/ |
| 709 | 709 |
| 710 static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b
lurred_width, int sharp_width ) { | 710 uint8_t SkBlurMask::ProfileLookup( uint8_t *profile, int loc, int blurred_width,
int sharp_width ) { |
| 711 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far
are we from the original edge? | 711 int dx = SkAbs32(((loc << 1) + 1) - blurred_width) - sharp_width; // how far
are we from the original edge? |
| 712 int ox = dx >> 1; | 712 int ox = dx >> 1; |
| 713 if (ox < 0) { | 713 if (ox < 0) { |
| 714 ox = 0; | 714 ox = 0; |
| 715 } | 715 } |
| 716 | 716 |
| 717 return profile[ox]; | 717 return profile[ox]; |
| 718 } | 718 } |
| 719 | 719 |
| 720 void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, uint8_t *profile, unsig
ned int profile_size, |
| 721 unsigned int width, float sigma) { |
| 722 SkAutoTMalloc<uint8_t> horizontalScanline(width); |
| 723 |
| 724 unsigned int sw = width - profile_size; |
| 725 // nearest odd number less than the profile size represents the center |
| 726 // of the (2x scaled) profile |
| 727 int center = ( profile_size & ~1 ) - 1; |
| 728 |
| 729 int w = sw - center; |
| 730 |
| 731 for (unsigned int x = 0 ; x < width ; ++x) { |
| 732 if (profile_size <= sw) { |
| 733 pixels[x] = ProfileLookup(profile, x, width, w); |
| 734 } else { |
| 735 float span = float(sw)/(2*sigma); |
| 736 float giX = 1.5f - (x+.5f)/(2*sigma); |
| 737 pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegra
l(giX + span))); |
| 738 } |
| 739 } |
| 740 } |
| 741 |
| 720 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, | 742 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, |
| 721 SkScalar radius, Style style, | 743 SkScalar radius, Style style, |
| 722 SkIPoint *margin, SkMask::CreateMode createMode) { | 744 SkIPoint *margin, SkMask::CreateMode createMode) { |
| 723 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), | 745 return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), |
| 724 dst, src, | 746 dst, src, |
| 725 style, margin, createMode); | 747 style, margin, createMode); |
| 726 } | 748 } |
| 727 | 749 |
| 728 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, | 750 bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, |
| 729 const SkRect &src, Style style, | 751 const SkRect &src, Style style, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 750 if (createMode == SkMask::kJustComputeBounds_CreateMode) { | 772 if (createMode == SkMask::kJustComputeBounds_CreateMode) { |
| 751 if (style == kInner_Style) { | 773 if (style == kInner_Style) { |
| 752 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), | 774 dst->fBounds.set(SkScalarRoundToInt(src.fLeft), |
| 753 SkScalarRoundToInt(src.fTop), | 775 SkScalarRoundToInt(src.fTop), |
| 754 SkScalarRoundToInt(src.fRight), | 776 SkScalarRoundToInt(src.fRight), |
| 755 SkScalarRoundToInt(src.fBottom)); // restore trimme
d bounds | 777 SkScalarRoundToInt(src.fBottom)); // restore trimme
d bounds |
| 756 dst->fRowBytes = sw; | 778 dst->fRowBytes = sw; |
| 757 } | 779 } |
| 758 return true; | 780 return true; |
| 759 } | 781 } |
| 760 unsigned int *profile = NULL; | 782 uint8_t *profile = NULL; |
| 761 | 783 |
| 762 compute_profile(sigma, &profile); | 784 ComputeBlurProfile(sigma, &profile); |
| 763 SkAutoTDeleteArray<unsigned int> ada(profile); | 785 SkAutoTDeleteArray<uint8_t> ada(profile); |
| 764 | 786 |
| 765 size_t dstSize = dst->computeImageSize(); | 787 size_t dstSize = dst->computeImageSize(); |
| 766 if (0 == dstSize) { | 788 if (0 == dstSize) { |
| 767 return false; // too big to allocate, abort | 789 return false; // too big to allocate, abort |
| 768 } | 790 } |
| 769 | 791 |
| 770 uint8_t* dp = SkMask::AllocImage(dstSize); | 792 uint8_t* dp = SkMask::AllocImage(dstSize); |
| 771 | 793 |
| 772 dst->fImage = dp; | 794 dst->fImage = dp; |
| 773 | 795 |
| 774 int dstHeight = dst->fBounds.height(); | 796 int dstHeight = dst->fBounds.height(); |
| 775 int dstWidth = dst->fBounds.width(); | 797 int dstWidth = dst->fBounds.width(); |
| 776 | 798 |
| 777 // nearest odd number less than the profile size represents the center | 799 // nearest odd number less than the profile size represents the center |
| 778 // of the (2x scaled) profile | 800 // of the (2x scaled) profile |
| 779 int center = ( profile_size & ~1 ) - 1; | 801 int center = ( profile_size & ~1 ) - 1; |
| 780 | 802 |
| 781 int w = sw - center; | 803 int w = sw - center; |
| 782 int h = sh - center; | 804 int h = sh - center; |
| 783 | 805 |
| 784 uint8_t *outptr = dp; | 806 uint8_t *outptr = dp; |
| 785 | 807 |
| 786 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); | 808 SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); |
| 787 | 809 |
| 788 for (int x = 0 ; x < dstWidth ; ++x) { | 810 for (int x = 0 ; x < dstWidth ; ++x) { |
| 789 if (profile_size <= sw) { | 811 if (profile_size <= sw) { |
| 790 horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); | 812 horizontalScanline[x] = ProfileLookup(profile, x, dstWidth, w); |
| 791 } else { | 813 } else { |
| 792 float span = float(sw)/(2*sigma); | 814 float span = float(sw)/(2*sigma); |
| 793 float giX = 1.5f - (x+.5f)/(2*sigma); | 815 float giX = 1.5f - (x+.5f)/(2*sigma); |
| 794 horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - ga
ussianIntegral(giX + span))); | 816 horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - ga
ussianIntegral(giX + span))); |
| 795 } | 817 } |
| 796 } | 818 } |
| 797 | 819 |
| 798 for (int y = 0 ; y < dstHeight ; ++y) { | 820 for (int y = 0 ; y < dstHeight ; ++y) { |
| 799 unsigned int profile_y; | 821 uint8_t profile_y; |
| 800 if (profile_size <= sh) { | 822 if (profile_size <= sh) { |
| 801 profile_y = profile_lookup(profile, y, dstHeight, h); | 823 profile_y = ProfileLookup(profile, y, dstHeight, h); |
| 802 } else { | 824 } else { |
| 803 float span = float(sh)/(2*sigma); | 825 float span = float(sh)/(2*sigma); |
| 804 float giY = 1.5f - (y+.5f)/(2*sigma); | 826 float giY = 1.5f - (y+.5f)/(2*sigma); |
| 805 profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegr
al(giY + span))); | 827 profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegr
al(giY + span))); |
| 806 } | 828 } |
| 807 | 829 |
| 808 for (int x = 0 ; x < dstWidth ; x++) { | 830 for (int x = 0 ; x < dstWidth ; x++) { |
| 809 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profi
le_y); | 831 unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profi
le_y); |
| 810 *(outptr++) = maskval; | 832 *(outptr++) = maskval; |
| 811 } | 833 } |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 992 (void)autoCall.detach(); | 1014 (void)autoCall.detach(); |
| 993 } | 1015 } |
| 994 | 1016 |
| 995 if (style == kInner_Style) { | 1017 if (style == kInner_Style) { |
| 996 dst->fBounds = src.fBounds; // restore trimmed bounds | 1018 dst->fBounds = src.fBounds; // restore trimmed bounds |
| 997 dst->fRowBytes = src.fRowBytes; | 1019 dst->fRowBytes = src.fRowBytes; |
| 998 } | 1020 } |
| 999 | 1021 |
| 1000 return true; | 1022 return true; |
| 1001 } | 1023 } |
| OLD | NEW |