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
This commit is contained in:
reed@google.com 2012-06-13 19:39:03 +00:00
parent 4d73ac22a1
commit 4d0078aa51
2 changed files with 35 additions and 11 deletions

View File

@ -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
{

View File

@ -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);