1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/Constants.h"
17 #include "DataSurfaceHelpers.h"
26 * Box blur involves looking at one pixel, and setting its value to the average
27 * of its neighbouring pixels.
28 * @param aInput The input buffer.
29 * @param aOutput The output buffer.
30 * @param aLeftLobe The number of pixels to blend on the left.
31 * @param aRightLobe The number of pixels to blend on the right.
32 * @param aWidth The number of columns in the buffers.
33 * @param aRows The number of rows in the buffers.
34 * @param aSkipRect An area to skip blurring in.
35 * XXX shouldn't we pass stride in separately here?
38 BoxBlurHorizontal(unsigned char* aInput
,
39 unsigned char* aOutput
,
44 const IntRect
& aSkipRect
)
46 MOZ_ASSERT(aWidth
> 0);
48 int32_t boxSize
= aLeftLobe
+ aRightLobe
+ 1;
49 bool skipRectCoversWholeRow
= 0 >= aSkipRect
.x
&&
50 aWidth
<= aSkipRect
.XMost();
52 memcpy(aOutput
, aInput
, aWidth
*aRows
);
55 uint32_t reciprocal
= uint32_t((uint64_t(1) << 32) / boxSize
);
57 for (int32_t y
= 0; y
< aRows
; y
++) {
58 // Check whether the skip rect intersects this row. If the skip
59 // rect covers the whole surface in this row, we can avoid
60 // this row entirely (and any others along the skip rect).
61 bool inSkipRectY
= y
>= aSkipRect
.y
&&
62 y
< aSkipRect
.YMost();
63 if (inSkipRectY
&& skipRectCoversWholeRow
) {
64 y
= aSkipRect
.YMost() - 1;
68 uint32_t alphaSum
= 0;
69 for (int32_t i
= 0; i
< boxSize
; i
++) {
70 int32_t pos
= i
- aLeftLobe
;
71 // See assertion above; if aWidth is zero, then we would have no
72 // valid position to clamp to.
74 pos
= min(pos
, aWidth
- 1);
75 alphaSum
+= aInput
[aWidth
* y
+ pos
];
77 for (int32_t x
= 0; x
< aWidth
; x
++) {
78 // Check whether we are within the skip rect. If so, go
79 // to the next point outside the skip rect.
80 if (inSkipRectY
&& x
>= aSkipRect
.x
&&
81 x
< aSkipRect
.XMost()) {
82 x
= aSkipRect
.XMost();
86 // Recalculate the neighbouring alpha values for
87 // our new point on the surface.
89 for (int32_t i
= 0; i
< boxSize
; i
++) {
90 int32_t pos
= x
+ i
- aLeftLobe
;
91 // See assertion above; if aWidth is zero, then we would have no
92 // valid position to clamp to.
94 pos
= min(pos
, aWidth
- 1);
95 alphaSum
+= aInput
[aWidth
* y
+ pos
];
98 int32_t tmp
= x
- aLeftLobe
;
99 int32_t last
= max(tmp
, 0);
100 int32_t next
= min(tmp
+ boxSize
, aWidth
- 1);
102 aOutput
[aWidth
* y
+ x
] = (uint64_t(alphaSum
) * reciprocal
) >> 32;
104 alphaSum
+= aInput
[aWidth
* y
+ next
] -
105 aInput
[aWidth
* y
+ last
];
111 * Identical to BoxBlurHorizontal, except it blurs top and bottom instead of
113 * XXX shouldn't we pass stride in separately here?
116 BoxBlurVertical(unsigned char* aInput
,
117 unsigned char* aOutput
,
122 const IntRect
& aSkipRect
)
124 MOZ_ASSERT(aRows
> 0);
126 int32_t boxSize
= aTopLobe
+ aBottomLobe
+ 1;
127 bool skipRectCoversWholeColumn
= 0 >= aSkipRect
.y
&&
128 aRows
<= aSkipRect
.YMost();
130 memcpy(aOutput
, aInput
, aWidth
*aRows
);
133 uint32_t reciprocal
= uint32_t((uint64_t(1) << 32) / boxSize
);
135 for (int32_t x
= 0; x
< aWidth
; x
++) {
136 bool inSkipRectX
= x
>= aSkipRect
.x
&&
137 x
< aSkipRect
.XMost();
138 if (inSkipRectX
&& skipRectCoversWholeColumn
) {
139 x
= aSkipRect
.XMost() - 1;
143 uint32_t alphaSum
= 0;
144 for (int32_t i
= 0; i
< boxSize
; i
++) {
145 int32_t pos
= i
- aTopLobe
;
146 // See assertion above; if aRows is zero, then we would have no
147 // valid position to clamp to.
149 pos
= min(pos
, aRows
- 1);
150 alphaSum
+= aInput
[aWidth
* pos
+ x
];
152 for (int32_t y
= 0; y
< aRows
; y
++) {
153 if (inSkipRectX
&& y
>= aSkipRect
.y
&&
154 y
< aSkipRect
.YMost()) {
155 y
= aSkipRect
.YMost();
160 for (int32_t i
= 0; i
< boxSize
; i
++) {
161 int32_t pos
= y
+ i
- aTopLobe
;
162 // See assertion above; if aRows is zero, then we would have no
163 // valid position to clamp to.
165 pos
= min(pos
, aRows
- 1);
166 alphaSum
+= aInput
[aWidth
* pos
+ x
];
169 int32_t tmp
= y
- aTopLobe
;
170 int32_t last
= max(tmp
, 0);
171 int32_t next
= min(tmp
+ boxSize
, aRows
- 1);
173 aOutput
[aWidth
* y
+ x
] = (uint64_t(alphaSum
) * reciprocal
) >> 32;
175 alphaSum
+= aInput
[aWidth
* next
+ x
] -
176 aInput
[aWidth
* last
+ x
];
181 static void ComputeLobes(int32_t aRadius
, int32_t aLobes
[3][2])
183 int32_t major
, minor
, final
;
185 /* See http://www.w3.org/TR/SVG/filters.html#feGaussianBlur for
186 * some notes about approximating the Gaussian blur with box-blurs.
187 * The comments below are in the terminology of that page.
189 int32_t z
= aRadius
/ 3;
190 switch (aRadius
% 3) {
192 // aRadius = z*3; choose d = 2*z + 1
193 major
= minor
= final
= z
;
197 // This is a tricky case since there is no value of d which will
198 // yield a radius of exactly aRadius. If d is odd, i.e. d=2*k + 1
199 // for some integer k, then the radius will be 3*k. If d is even,
200 // i.e. d=2*k, then the radius will be 3*k - 1.
201 // So we have to choose values that don't match the standard
207 // aRadius = z*3 + 2; choose d = 2*z + 2
208 major
= final
= z
+ 1;
212 // Mathematical impossibility!
214 major
= minor
= final
= 0;
216 MOZ_ASSERT(major
+ minor
+ final
== aRadius
);
218 aLobes
[0][0] = major
;
219 aLobes
[0][1] = minor
;
220 aLobes
[1][0] = minor
;
221 aLobes
[1][1] = major
;
222 aLobes
[2][0] = final
;
223 aLobes
[2][1] = final
;
227 SpreadHorizontal(unsigned char* aInput
,
228 unsigned char* aOutput
,
233 const IntRect
& aSkipRect
)
236 memcpy(aOutput
, aInput
, aStride
* aRows
);
240 bool skipRectCoversWholeRow
= 0 >= aSkipRect
.x
&&
241 aWidth
<= aSkipRect
.XMost();
242 for (int32_t y
= 0; y
< aRows
; y
++) {
243 // Check whether the skip rect intersects this row. If the skip
244 // rect covers the whole surface in this row, we can avoid
245 // this row entirely (and any others along the skip rect).
246 bool inSkipRectY
= y
>= aSkipRect
.y
&&
247 y
< aSkipRect
.YMost();
248 if (inSkipRectY
&& skipRectCoversWholeRow
) {
249 y
= aSkipRect
.YMost() - 1;
253 for (int32_t x
= 0; x
< aWidth
; x
++) {
254 // Check whether we are within the skip rect. If so, go
255 // to the next point outside the skip rect.
256 if (inSkipRectY
&& x
>= aSkipRect
.x
&&
257 x
< aSkipRect
.XMost()) {
258 x
= aSkipRect
.XMost();
263 int32_t sMin
= max(x
- aRadius
, 0);
264 int32_t sMax
= min(x
+ aRadius
, aWidth
- 1);
266 for (int32_t s
= sMin
; s
<= sMax
; ++s
) {
267 v
= max
<int32_t>(v
, aInput
[aStride
* y
+ s
]);
269 aOutput
[aStride
* y
+ x
] = v
;
275 SpreadVertical(unsigned char* aInput
,
276 unsigned char* aOutput
,
281 const IntRect
& aSkipRect
)
284 memcpy(aOutput
, aInput
, aStride
* aRows
);
288 bool skipRectCoversWholeColumn
= 0 >= aSkipRect
.y
&&
289 aRows
<= aSkipRect
.YMost();
290 for (int32_t x
= 0; x
< aWidth
; x
++) {
291 bool inSkipRectX
= x
>= aSkipRect
.x
&&
292 x
< aSkipRect
.XMost();
293 if (inSkipRectX
&& skipRectCoversWholeColumn
) {
294 x
= aSkipRect
.XMost() - 1;
298 for (int32_t y
= 0; y
< aRows
; y
++) {
299 // Check whether we are within the skip rect. If so, go
300 // to the next point outside the skip rect.
301 if (inSkipRectX
&& y
>= aSkipRect
.y
&&
302 y
< aSkipRect
.YMost()) {
303 y
= aSkipRect
.YMost();
308 int32_t sMin
= max(y
- aRadius
, 0);
309 int32_t sMax
= min(y
+ aRadius
, aRows
- 1);
311 for (int32_t s
= sMin
; s
<= sMax
; ++s
) {
312 v
= max
<int32_t>(v
, aInput
[aStride
* s
+ x
]);
314 aOutput
[aStride
* y
+ x
] = v
;
320 AlphaBoxBlur::RoundUpToMultipleOf4(int32_t aVal
)
322 CheckedInt
<int32_t> val(aVal
);
331 AlphaBoxBlur::AlphaBoxBlur(const Rect
& aRect
,
332 const IntSize
& aSpreadRadius
,
333 const IntSize
& aBlurRadius
,
334 const Rect
* aDirtyRect
,
335 const Rect
* aSkipRect
)
336 : mSpreadRadius(aSpreadRadius
),
337 mBlurRadius(aBlurRadius
),
338 mSurfaceAllocationSize(0)
341 rect
.Inflate(Size(aBlurRadius
+ aSpreadRadius
));
345 // If we get passed a dirty rect from layout, we can minimize the
346 // shadow size and make painting faster.
347 mHasDirtyRect
= true;
348 mDirtyRect
= *aDirtyRect
;
349 Rect requiredBlurArea
= mDirtyRect
.Intersect(rect
);
350 requiredBlurArea
.Inflate(Size(aBlurRadius
+ aSpreadRadius
));
351 rect
= requiredBlurArea
.Intersect(rect
);
353 mHasDirtyRect
= false;
356 mRect
= IntRect(int32_t(rect
.x
), int32_t(rect
.y
),
357 int32_t(rect
.width
), int32_t(rect
.height
));
358 if (mRect
.IsEmpty()) {
363 // If we get passed a skip rect, we can lower the amount of
364 // blurring/spreading we need to do. We convert it to IntRect to avoid
365 // expensive int<->float conversions if we were to use Rect instead.
366 Rect skipRect
= *aSkipRect
;
368 skipRect
.Deflate(Size(aBlurRadius
+ aSpreadRadius
));
369 mSkipRect
= IntRect(int32_t(skipRect
.x
), int32_t(skipRect
.y
),
370 int32_t(skipRect
.width
), int32_t(skipRect
.height
));
372 mSkipRect
= mSkipRect
.Intersect(mRect
);
373 if (mSkipRect
.IsEqualInterior(mRect
))
376 mSkipRect
-= mRect
.TopLeft();
378 mSkipRect
= IntRect(0, 0, 0, 0);
381 CheckedInt
<int32_t> stride
= RoundUpToMultipleOf4(mRect
.width
);
382 if (stride
.isValid()) {
383 mStride
= stride
.value();
385 // We need to leave room for an additional 3 bytes for a potential overrun
386 // in our blurring code.
387 size_t size
= BufferSizeFromStrideAndHeight(mStride
, mRect
.height
, 3);
389 mSurfaceAllocationSize
= size
;
394 AlphaBoxBlur::AlphaBoxBlur(const Rect
& aRect
,
398 : mRect(int32_t(aRect
.x
), int32_t(aRect
.y
),
399 int32_t(aRect
.width
), int32_t(aRect
.height
)),
401 mBlurRadius(CalculateBlurRadius(Point(aSigmaX
, aSigmaY
))),
403 mSurfaceAllocationSize(0)
406 if (aRect
.ToIntRect(&intRect
)) {
407 size_t minDataSize
= BufferSizeFromStrideAndHeight(intRect
.width
, intRect
.height
);
408 if (minDataSize
!= 0) {
409 mSurfaceAllocationSize
= minDataSize
;
415 AlphaBoxBlur::~AlphaBoxBlur()
420 AlphaBoxBlur::GetSize()
422 IntSize
size(mRect
.width
, mRect
.height
);
427 AlphaBoxBlur::GetStride()
433 AlphaBoxBlur::GetRect()
439 AlphaBoxBlur::GetDirtyRect()
449 AlphaBoxBlur::GetSurfaceAllocationSize() const
451 return mSurfaceAllocationSize
;
455 AlphaBoxBlur::Blur(uint8_t* aData
)
461 // no need to do all this if not blurring or spreading
462 if (mBlurRadius
!= IntSize(0,0) || mSpreadRadius
!= IntSize(0,0)) {
463 int32_t stride
= GetStride();
465 IntSize size
= GetSize();
467 if (mSpreadRadius
.width
> 0 || mSpreadRadius
.height
> 0) {
468 // No need to use CheckedInt here - we have validated it in the constructor.
469 size_t szB
= stride
* size
.height
;
470 unsigned char* tmpData
= new (std::nothrow
) uint8_t[szB
];
476 memset(tmpData
, 0, szB
);
478 SpreadHorizontal(aData
, tmpData
, mSpreadRadius
.width
, GetSize().width
, GetSize().height
, stride
, mSkipRect
);
479 SpreadVertical(tmpData
, aData
, mSpreadRadius
.height
, GetSize().width
, GetSize().height
, stride
, mSkipRect
);
484 int32_t horizontalLobes
[3][2];
485 ComputeLobes(mBlurRadius
.width
, horizontalLobes
);
486 int32_t verticalLobes
[3][2];
487 ComputeLobes(mBlurRadius
.height
, verticalLobes
);
489 // We want to allow for some extra space on the left for alignment reasons.
490 int32_t maxLeftLobe
= RoundUpToMultipleOf4(horizontalLobes
[0][0] + 1).value();
492 IntSize
integralImageSize(size
.width
+ maxLeftLobe
+ horizontalLobes
[1][1],
493 size
.height
+ verticalLobes
[0][0] + verticalLobes
[1][1] + 1);
495 if ((integralImageSize
.width
* integralImageSize
.height
) > (1 << 24)) {
496 // Fallback to old blurring code when the surface is so large it may
497 // overflow our integral image!
499 // No need to use CheckedInt here - we have validated it in the constructor.
500 size_t szB
= stride
* size
.height
;
501 uint8_t* tmpData
= new (std::nothrow
) uint8_t[szB
];
506 memset(tmpData
, 0, szB
);
509 uint8_t* b
= tmpData
;
510 if (mBlurRadius
.width
> 0) {
511 BoxBlurHorizontal(a
, b
, horizontalLobes
[0][0], horizontalLobes
[0][1], stride
, GetSize().height
, mSkipRect
);
512 BoxBlurHorizontal(b
, a
, horizontalLobes
[1][0], horizontalLobes
[1][1], stride
, GetSize().height
, mSkipRect
);
513 BoxBlurHorizontal(a
, b
, horizontalLobes
[2][0], horizontalLobes
[2][1], stride
, GetSize().height
, mSkipRect
);
518 // The result is in 'b' here.
519 if (mBlurRadius
.height
> 0) {
520 BoxBlurVertical(b
, a
, verticalLobes
[0][0], verticalLobes
[0][1], stride
, GetSize().height
, mSkipRect
);
521 BoxBlurVertical(a
, b
, verticalLobes
[1][0], verticalLobes
[1][1], stride
, GetSize().height
, mSkipRect
);
522 BoxBlurVertical(b
, a
, verticalLobes
[2][0], verticalLobes
[2][1], stride
, GetSize().height
, mSkipRect
);
526 // The result is in 'a' here.
528 memcpy(aData
, tmpData
, szB
);
532 size_t integralImageStride
= GetAlignedStride
<16>(integralImageSize
.width
* 4);
534 // We need to leave room for an additional 12 bytes for a maximum overrun
535 // of 3 pixels in the blurring code.
536 size_t bufLen
= BufferSizeFromStrideAndHeight(integralImageStride
, integralImageSize
.height
, 12);
540 // bufLen is a byte count, but here we want a multiple of 32-bit ints, so
542 AlignedArray
<uint32_t> integralImage((bufLen
/ 4) + ((bufLen
% 4) ? 1 : 0));
544 if (!integralImage
) {
548 if (Factory::HasSSE2()) {
549 BoxBlur_SSE2(aData
, horizontalLobes
[0][0], horizontalLobes
[0][1], verticalLobes
[0][0],
550 verticalLobes
[0][1], integralImage
, integralImageStride
);
551 BoxBlur_SSE2(aData
, horizontalLobes
[1][0], horizontalLobes
[1][1], verticalLobes
[1][0],
552 verticalLobes
[1][1], integralImage
, integralImageStride
);
553 BoxBlur_SSE2(aData
, horizontalLobes
[2][0], horizontalLobes
[2][1], verticalLobes
[2][0],
554 verticalLobes
[2][1], integralImage
, integralImageStride
);
558 BoxBlur_C(aData
, horizontalLobes
[0][0], horizontalLobes
[0][1], verticalLobes
[0][0],
559 verticalLobes
[0][1], integralImage
, integralImageStride
);
560 BoxBlur_C(aData
, horizontalLobes
[1][0], horizontalLobes
[1][1], verticalLobes
[1][0],
561 verticalLobes
[1][1], integralImage
, integralImageStride
);
562 BoxBlur_C(aData
, horizontalLobes
[2][0], horizontalLobes
[2][1], verticalLobes
[2][0],
563 verticalLobes
[2][1], integralImage
, integralImageStride
);
569 MOZ_ALWAYS_INLINE
void
570 GenerateIntegralRow(uint32_t *aDest
, const uint8_t *aSource
, uint32_t *aPreviousRow
,
571 const uint32_t &aSourceWidth
, const uint32_t &aLeftInflation
, const uint32_t &aRightInflation
)
573 uint32_t currentRowSum
= 0;
574 uint32_t pixel
= aSource
[0];
575 for (uint32_t x
= 0; x
< aLeftInflation
; x
++) {
576 currentRowSum
+= pixel
;
577 *aDest
++ = currentRowSum
+ *aPreviousRow
++;
579 for (uint32_t x
= aLeftInflation
; x
< (aSourceWidth
+ aLeftInflation
); x
+= 4) {
580 uint32_t alphaValues
= *(uint32_t*)(aSource
+ (x
- aLeftInflation
));
581 #if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN || defined __BIG_ENDIAN__
582 currentRowSum
+= (alphaValues
>> 24) & 0xff;
583 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
584 currentRowSum
+= (alphaValues
>> 16) & 0xff;
585 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
586 currentRowSum
+= (alphaValues
>> 8) & 0xff;
587 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
588 currentRowSum
+= alphaValues
& 0xff;
589 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
591 currentRowSum
+= alphaValues
& 0xff;
592 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
594 currentRowSum
+= alphaValues
& 0xff;
595 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
597 currentRowSum
+= alphaValues
& 0xff;
598 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
600 currentRowSum
+= alphaValues
& 0xff;
601 *aDest
++ = *aPreviousRow
++ + currentRowSum
;
604 pixel
= aSource
[aSourceWidth
- 1];
605 for (uint32_t x
= (aSourceWidth
+ aLeftInflation
); x
< (aSourceWidth
+ aLeftInflation
+ aRightInflation
); x
++) {
606 currentRowSum
+= pixel
;
607 *aDest
++ = currentRowSum
+ *aPreviousRow
++;
611 MOZ_ALWAYS_INLINE
void
612 GenerateIntegralImage_C(int32_t aLeftInflation
, int32_t aRightInflation
,
613 int32_t aTopInflation
, int32_t aBottomInflation
,
614 uint32_t *aIntegralImage
, size_t aIntegralImageStride
,
615 uint8_t *aSource
, int32_t aSourceStride
, const IntSize
&aSize
)
617 uint32_t stride32bit
= aIntegralImageStride
/ 4;
619 IntSize
integralImageSize(aSize
.width
+ aLeftInflation
+ aRightInflation
,
620 aSize
.height
+ aTopInflation
+ aBottomInflation
);
622 memset(aIntegralImage
, 0, aIntegralImageStride
);
624 GenerateIntegralRow(aIntegralImage
, aSource
, aIntegralImage
,
625 aSize
.width
, aLeftInflation
, aRightInflation
);
626 for (int y
= 1; y
< aTopInflation
+ 1; y
++) {
627 GenerateIntegralRow(aIntegralImage
+ (y
* stride32bit
), aSource
, aIntegralImage
+ (y
- 1) * stride32bit
,
628 aSize
.width
, aLeftInflation
, aRightInflation
);
631 for (int y
= aTopInflation
+ 1; y
< (aSize
.height
+ aTopInflation
); y
++) {
632 GenerateIntegralRow(aIntegralImage
+ (y
* stride32bit
), aSource
+ aSourceStride
* (y
- aTopInflation
),
633 aIntegralImage
+ (y
- 1) * stride32bit
, aSize
.width
, aLeftInflation
, aRightInflation
);
636 if (aBottomInflation
) {
637 for (int y
= (aSize
.height
+ aTopInflation
); y
< integralImageSize
.height
; y
++) {
638 GenerateIntegralRow(aIntegralImage
+ (y
* stride32bit
), aSource
+ ((aSize
.height
- 1) * aSourceStride
),
639 aIntegralImage
+ (y
- 1) * stride32bit
,
640 aSize
.width
, aLeftInflation
, aRightInflation
);
646 * Attempt to do an in-place box blur using an integral image.
649 AlphaBoxBlur::BoxBlur_C(uint8_t* aData
,
654 uint32_t *aIntegralImage
,
655 size_t aIntegralImageStride
)
657 IntSize size
= GetSize();
659 MOZ_ASSERT(size
.width
> 0);
661 // Our 'left' or 'top' lobe will include the current pixel. i.e. when
662 // looking at an integral image the value of a pixel at 'x,y' is calculated
663 // using the value of the integral image values above/below that.
666 int32_t boxSize
= (aLeftLobe
+ aRightLobe
) * (aTopLobe
+ aBottomLobe
);
668 MOZ_ASSERT(boxSize
> 0);
674 int32_t stride32bit
= aIntegralImageStride
/ 4;
676 int32_t leftInflation
= RoundUpToMultipleOf4(aLeftLobe
).value();
678 GenerateIntegralImage_C(leftInflation
, aRightLobe
, aTopLobe
, aBottomLobe
,
679 aIntegralImage
, aIntegralImageStride
, aData
,
682 uint32_t reciprocal
= uint32_t((uint64_t(1) << 32) / boxSize
);
684 uint32_t *innerIntegral
= aIntegralImage
+ (aTopLobe
* stride32bit
) + leftInflation
;
686 // Storing these locally makes this about 30% faster! Presumably the compiler
687 // can't be sure we're not altering the member variables in this loop.
688 IntRect skipRect
= mSkipRect
;
689 uint8_t *data
= aData
;
690 int32_t stride
= mStride
;
691 for (int32_t y
= 0; y
< size
.height
; y
++) {
692 bool inSkipRectY
= y
> skipRect
.y
&& y
< skipRect
.YMost();
694 uint32_t *topLeftBase
= innerIntegral
+ ((y
- aTopLobe
) * stride32bit
- aLeftLobe
);
695 uint32_t *topRightBase
= innerIntegral
+ ((y
- aTopLobe
) * stride32bit
+ aRightLobe
);
696 uint32_t *bottomRightBase
= innerIntegral
+ ((y
+ aBottomLobe
) * stride32bit
+ aRightLobe
);
697 uint32_t *bottomLeftBase
= innerIntegral
+ ((y
+ aBottomLobe
) * stride32bit
- aLeftLobe
);
699 for (int32_t x
= 0; x
< size
.width
; x
++) {
700 if (inSkipRectY
&& x
> skipRect
.x
&& x
< skipRect
.XMost()) {
701 x
= skipRect
.XMost() - 1;
702 // Trigger early jump on coming loop iterations, this will be reset
707 int32_t topLeft
= topLeftBase
[x
];
708 int32_t topRight
= topRightBase
[x
];
709 int32_t bottomRight
= bottomRightBase
[x
];
710 int32_t bottomLeft
= bottomLeftBase
[x
];
712 uint32_t value
= bottomRight
- topRight
- bottomLeft
;
715 data
[stride
* y
+ x
] = (uint64_t(reciprocal
) * value
+ (uint64_t(1) << 31)) >> 32;
721 * Compute the box blur size (which we're calling the blur radius) from
722 * the standard deviation.
724 * Much of this, the 3 * sqrt(2 * pi) / 4, is the known value for
725 * approximating a Gaussian using box blurs. This yields quite a good
726 * approximation for a Gaussian. Then we multiply this by 1.5 since our
727 * code wants the radius of the entire triple-box-blur kernel instead of
728 * the diameter of an individual box blur. For more details, see:
729 * http://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
730 * https://bugzilla.mozilla.org/show_bug.cgi?id=590039#c19
732 static const Float GAUSSIAN_SCALE_FACTOR
= Float((3 * sqrt(2 * M_PI
) / 4) * 1.5);
735 AlphaBoxBlur::CalculateBlurRadius(const Point
& aStd
)
737 IntSize
size(static_cast<int32_t>(floor(aStd
.x
* GAUSSIAN_SCALE_FACTOR
+ 0.5f
)),
738 static_cast<int32_t>(floor(aStd
.y
* GAUSSIAN_SCALE_FACTOR
+ 0.5f
)));