Index: src/effects/SkLightingImageFilter.cpp |
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp |
index 19da3ed5e8fa2389e6760ae67ba45ec9bec850d3..4be9f17db5f2be984ecc889fe81c8ff2cb6510ba 100644 |
--- a/src/effects/SkLightingImageFilter.cpp |
+++ b/src/effects/SkLightingImageFilter.cpp |
@@ -185,35 +185,55 @@ inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) { |
surfaceScale); |
} |
-template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, |
- const SkImageFilterLight* light, |
- const SkBitmap& src, |
- SkBitmap* dst, |
- SkScalar surfaceScale, |
- const SkIRect& bounds) { |
+ |
+class UncheckedPixelFetcher { |
+public: |
+ static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { |
+ return SkGetPackedA32(*src.getAddr32(x, y)); |
+ } |
+}; |
+ |
+// The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds. |
+class DecalPixelFetcher { |
+public: |
+ static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { |
+ if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) { |
+ return 0; |
+ } else { |
+ return SkGetPackedA32(*src.getAddr32(x, y)); |
+ } |
+ } |
+}; |
+ |
+template <class LightingType, class LightType, class PixelFetcher> |
+void lightBitmap(const LightingType& lightingType, |
+ const SkImageFilterLight* light, |
+ const SkBitmap& src, |
+ SkBitmap* dst, |
+ SkScalar surfaceScale, |
+ const SkIRect& bounds) { |
SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height()); |
const LightType* l = static_cast<const LightType*>(light); |
int left = bounds.left(), right = bounds.right(); |
int bottom = bounds.bottom(); |
int y = bounds.top(); |
+ SkIRect srcBounds = src.bounds(); |
SkPMColor* dptr = dst->getAddr32(0, 0); |
{ |
int x = left; |
- const SkPMColor* row1 = src.getAddr32(x, y); |
- const SkPMColor* row2 = src.getAddr32(x, y + 1); |
int m[9]; |
- m[4] = SkGetPackedA32(*row1++); |
- m[5] = SkGetPackedA32(*row1++); |
- m[7] = SkGetPackedA32(*row2++); |
- m[8] = SkGetPackedA32(*row2++); |
+ m[4] = PixelFetcher::Fetch(src, x, y, srcBounds); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
+ m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds); |
+ m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
for (++x; x < right - 1; ++x) |
{ |
shiftMatrixLeft(m); |
- m[5] = SkGetPackedA32(*row1++); |
- m[8] = SkGetPackedA32(*row2++); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
+ m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
@@ -226,24 +246,21 @@ template <class LightingType, class LightType> void lightBitmap(const LightingTy |
for (++y; y < bottom - 1; ++y) { |
int x = left; |
- const SkPMColor* row0 = src.getAddr32(x, y - 1); |
- const SkPMColor* row1 = src.getAddr32(x, y); |
- const SkPMColor* row2 = src.getAddr32(x, y + 1); |
int m[9]; |
- m[1] = SkGetPackedA32(*row0++); |
- m[2] = SkGetPackedA32(*row0++); |
- m[4] = SkGetPackedA32(*row1++); |
- m[5] = SkGetPackedA32(*row1++); |
- m[7] = SkGetPackedA32(*row2++); |
- m[8] = SkGetPackedA32(*row2++); |
+ m[1] = PixelFetcher::Fetch(src, x, y - 1, srcBounds); |
+ m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds); |
+ m[4] = PixelFetcher::Fetch(src, x, y, srcBounds); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
+ m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds); |
+ m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
for (++x; x < right - 1; ++x) { |
shiftMatrixLeft(m); |
- m[2] = SkGetPackedA32(*row0++); |
- m[5] = SkGetPackedA32(*row1++); |
- m[8] = SkGetPackedA32(*row2++); |
+ m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
+ m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
@@ -256,21 +273,19 @@ template <class LightingType, class LightType> void lightBitmap(const LightingTy |
{ |
int x = left; |
- const SkPMColor* row0 = src.getAddr32(x, bottom - 2); |
- const SkPMColor* row1 = src.getAddr32(x, bottom - 1); |
int m[9]; |
- m[1] = SkGetPackedA32(*row0++); |
- m[2] = SkGetPackedA32(*row0++); |
- m[4] = SkGetPackedA32(*row1++); |
- m[5] = SkGetPackedA32(*row1++); |
+ m[1] = PixelFetcher::Fetch(src, x, bottom - 2, srcBounds); |
+ m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds); |
+ m[4] = PixelFetcher::Fetch(src, x, bottom - 1, srcBounds); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds); |
SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
for (++x; x < right - 1; ++x) |
{ |
shiftMatrixLeft(m); |
- m[2] = SkGetPackedA32(*row0++); |
- m[5] = SkGetPackedA32(*row1++); |
+ m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds); |
+ m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds); |
surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
*dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, |
l->lightColor(surfaceToLight)); |
@@ -282,6 +297,22 @@ template <class LightingType, class LightType> void lightBitmap(const LightingTy |
} |
} |
+template <class LightingType, class LightType> |
+void lightBitmap(const LightingType& lightingType, |
+ const SkImageFilterLight* light, |
+ const SkBitmap& src, |
+ SkBitmap* dst, |
+ SkScalar surfaceScale, |
+ const SkIRect& bounds) { |
+ if (src.bounds().contains(bounds)) { |
+ lightBitmap<LightingType, LightType, UncheckedPixelFetcher>( |
+ lightingType, light, src, dst, surfaceScale, bounds); |
+ } else { |
+ lightBitmap<LightingType, LightType, DecalPixelFetcher>( |
+ lightingType, light, src, dst, surfaceScale, bounds); |
+ } |
+} |
+ |
SkPoint3 readPoint3(SkReadBuffer& buffer) { |
SkPoint3 point; |
point.fX = buffer.readScalar(); |
@@ -1187,8 +1218,10 @@ bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy, |
if (src.colorType() != kN32_SkColorType) { |
return false; |
} |
+ SkIRect srcBounds = src.bounds(); |
+ srcBounds.offset(srcOffset); |
SkIRect bounds; |
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) { |
+ if (!this->applyCropRect(ctx, srcBounds, &bounds)) { |
return false; |
} |
@@ -1331,8 +1364,10 @@ bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy, |
return false; |
} |
+ SkIRect srcBounds = src.bounds(); |
+ srcBounds.offset(srcOffset); |
SkIRect bounds; |
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) { |
+ if (!this->applyCropRect(ctx, srcBounds, &bounds)) { |
return false; |
} |