aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-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);