aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-13 19:39:03 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-13 19:39:03 +0000
commit4d0078aa5115fab8ccd8ef59519a8937ea4e8854 (patch)
tree7206ce8675f4a03b82ec3d975dd02f83c22f0578
parent4d73ac22a1b99402fc8cff78a4eb4b27aa8fe019 (diff)
Fix calling (and checking) the decal_ functions when the input is SkFractionalInt.
The bug was to cast to SkFixed from SkFractionalInt, when what we needed to do was shift the fractional guy down to fixed. This bug was only caught on an android device w/o neon, since other configs have assembly for their matrixproc that didn't have this bug. Review URL: https://codereview.appspot.com/6303074 git-svn-id: http://skia.googlecode.com/svn/trunk@4256 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--src/core/SkBitmapProcState_matrix.h17
-rw-r--r--src/core/SkBitmapProcState_matrixProcs.cpp29
2 files changed, 35 insertions, 11 deletions
diff --git a/src/core/SkBitmapProcState_matrix.h b/src/core/SkBitmapProcState_matrix.h
index 5ea780e9b7..469cbf3ad4 100644
--- a/src/core/SkBitmapProcState_matrix.h
+++ b/src/core/SkBitmapProcState_matrix.h
@@ -71,12 +71,9 @@ void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
const SkFractionalInt dx = s.fInvSxFractionalInt;
#ifdef CHECK_FOR_DECAL
- // test if we don't need to apply the tile proc
- SkFixed tmpFx = SkFractionalIntToFixed(fx);
- SkFixed tmpDx = SkFractionalIntToFixed(dx);
- if ((unsigned)(tmpFx >> 16) <= maxX &&
- (unsigned)((tmpFx + tmpDx * (count - 1)) >> 16) <= maxX) {
- decal_nofilter_scale(xy, tmpFx, tmpDx, count);
+ if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) {
+ decal_nofilter_scale(xy, SkFractionalIntToFixed(fx),
+ SkFractionalIntToFixed(dx), count);
} else
#endif
{
@@ -201,11 +198,9 @@ void SCALE_FILTER_NAME(const SkBitmapProcState& s,
}
#ifdef CHECK_FOR_DECAL
- // test if we don't need to apply the tile proc
- if (dx > 0 &&
- (unsigned)(fx >> 16) <= maxX &&
- (unsigned)((fx + dx * (count - 1)) >> 16) < maxX) {
- decal_filter_scale(xy, (SkFixed) fx, (SkFixed) dx, count);
+ if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) {
+ decal_filter_scale(xy, SkFractionalIntToFixed(fx),
+ SkFractionalIntToFixed(dx), count);
} else
#endif
{
diff --git a/src/core/SkBitmapProcState_matrixProcs.cpp b/src/core/SkBitmapProcState_matrixProcs.cpp
index c043e8610c..1e12f9a921 100644
--- a/src/core/SkBitmapProcState_matrixProcs.cpp
+++ b/src/core/SkBitmapProcState_matrixProcs.cpp
@@ -35,6 +35,35 @@ static inline int sk_int_mod(int x, int n) {
return x;
}
+/*
+ * The decal_ functions require that
+ * 1. dx > 0
+ * 2. [fx, fx+dx, fx+2dx, fx+3dx, ... fx+(count-1)dx] are all <= maxX
+ *
+ * In addition, we use SkFractionalInt to keep more fractional precision than
+ * just SkFixed, so we will abort the decal_ call if dx is very small, since
+ * the decal_ function just operates on SkFixed. If that were changed, we could
+ * skip the very_small test here.
+ */
+static inline bool can_truncate_to_fixed_for_decal(SkFractionalInt frX,
+ SkFractionalInt frDx,
+ int count, unsigned max) {
+ SkFixed dx = SkFractionalIntToFixed(frDx);
+
+ // if decal_ kept SkFractionalInt precision, this would just be dx <= 0
+ // I just made up the 1/256. Just don't want to perceive accumulated error
+ // if we truncate frDx and lose its low bits.
+ if (dx <= SK_Fixed1 / 256) {
+ return false;
+ }
+
+ // We cast to unsigned so we don't have to check for negative values, which
+ // will now appear as very large positive values, and thus fail our test!
+ SkFixed fx = SkFractionalIntToFixed(frX);
+ return (unsigned)SkFixedFloorToInt(fx) <= max &&
+ (unsigned)SkFixedFloorToInt(fx + dx * (count - 1)) < max;
+}
+
void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);