michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkMath.h" michael@0: #include "SkMathPriv.h" michael@0: michael@0: #define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale) michael@0: #define SCALE_FILTER_NAME MAKENAME(_filter_scale) michael@0: #define AFFINE_NOFILTER_NAME MAKENAME(_nofilter_affine) michael@0: #define AFFINE_FILTER_NAME MAKENAME(_filter_affine) michael@0: #define PERSP_NOFILTER_NAME MAKENAME(_nofilter_persp) michael@0: #define PERSP_FILTER_NAME MAKENAME(_filter_persp) michael@0: michael@0: #define PACK_FILTER_X_NAME MAKENAME(_pack_filter_x) michael@0: #define PACK_FILTER_Y_NAME MAKENAME(_pack_filter_y) michael@0: michael@0: #ifndef PREAMBLE michael@0: #define PREAMBLE(state) michael@0: #define PREAMBLE_PARAM_X michael@0: #define PREAMBLE_PARAM_Y michael@0: #define PREAMBLE_ARG_X michael@0: #define PREAMBLE_ARG_Y michael@0: #endif michael@0: michael@0: // declare functions externally to suppress warnings. michael@0: void SCALE_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y); michael@0: void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y); michael@0: void PERSP_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t* SK_RESTRICT xy, michael@0: int count, int x, int y); michael@0: void SCALE_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y); michael@0: void AFFINE_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y); michael@0: void PERSP_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t* SK_RESTRICT xy, int count, michael@0: int x, int y); michael@0: michael@0: void SCALE_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y) { michael@0: SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | michael@0: SkMatrix::kScale_Mask)) == 0); michael@0: michael@0: PREAMBLE(s); michael@0: // we store y, x, x, x, x, x michael@0: michael@0: const unsigned maxX = s.fBitmap->width() - 1; michael@0: SkFractionalInt fx; michael@0: { michael@0: SkPoint pt; michael@0: s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &pt); michael@0: fx = SkScalarToFractionalInt(pt.fY); michael@0: const unsigned maxY = s.fBitmap->height() - 1; michael@0: *xy++ = TILEY_PROCF(SkFractionalIntToFixed(fx), maxY); michael@0: fx = SkScalarToFractionalInt(pt.fX); michael@0: } michael@0: michael@0: if (0 == maxX) { michael@0: // all of the following X values must be 0 michael@0: memset(xy, 0, count * sizeof(uint16_t)); michael@0: return; michael@0: } michael@0: michael@0: const SkFractionalInt dx = s.fInvSxFractionalInt; michael@0: michael@0: #ifdef CHECK_FOR_DECAL michael@0: if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { michael@0: decal_nofilter_scale(xy, SkFractionalIntToFixed(fx), michael@0: SkFractionalIntToFixed(dx), count); michael@0: } else michael@0: #endif michael@0: { michael@0: int i; michael@0: for (i = (count >> 2); i > 0; --i) { michael@0: unsigned a, b; michael@0: a = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx; michael@0: b = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx; michael@0: #ifdef SK_CPU_BENDIAN michael@0: *xy++ = (a << 16) | b; michael@0: #else michael@0: *xy++ = (b << 16) | a; michael@0: #endif michael@0: a = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx; michael@0: b = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx; michael@0: #ifdef SK_CPU_BENDIAN michael@0: *xy++ = (a << 16) | b; michael@0: #else michael@0: *xy++ = (b << 16) | a; michael@0: #endif michael@0: } michael@0: uint16_t* xx = (uint16_t*)xy; michael@0: for (i = (count & 3); i > 0; --i) { michael@0: *xx++ = TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); fx += dx; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // note: we could special-case on a matrix which is skewed in X but not Y. michael@0: // this would require a more general setup thatn SCALE does, but could use michael@0: // SCALE's inner loop that only looks at dx michael@0: michael@0: void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y) { michael@0: SkASSERT(s.fInvType & SkMatrix::kAffine_Mask); michael@0: SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | michael@0: SkMatrix::kScale_Mask | michael@0: SkMatrix::kAffine_Mask)) == 0); michael@0: michael@0: PREAMBLE(s); michael@0: SkPoint srcPt; michael@0: s.fInvProc(s.fInvMatrix, michael@0: SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &srcPt); michael@0: michael@0: SkFractionalInt fx = SkScalarToFractionalInt(srcPt.fX); michael@0: SkFractionalInt fy = SkScalarToFractionalInt(srcPt.fY); michael@0: SkFractionalInt dx = s.fInvSxFractionalInt; michael@0: SkFractionalInt dy = s.fInvKyFractionalInt; michael@0: int maxX = s.fBitmap->width() - 1; michael@0: int maxY = s.fBitmap->height() - 1; michael@0: michael@0: for (int i = count; i > 0; --i) { michael@0: *xy++ = (TILEY_PROCF(SkFractionalIntToFixed(fy), maxY) << 16) | michael@0: TILEX_PROCF(SkFractionalIntToFixed(fx), maxX); michael@0: fx += dx; fy += dy; michael@0: } michael@0: } michael@0: michael@0: void PERSP_NOFILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t* SK_RESTRICT xy, michael@0: int count, int x, int y) { michael@0: SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask); michael@0: michael@0: PREAMBLE(s); michael@0: int maxX = s.fBitmap->width() - 1; michael@0: int maxY = s.fBitmap->height() - 1; michael@0: michael@0: SkPerspIter iter(s.fInvMatrix, michael@0: SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, count); michael@0: michael@0: while ((count = iter.next()) != 0) { michael@0: const SkFixed* SK_RESTRICT srcXY = iter.getXY(); michael@0: while (--count >= 0) { michael@0: *xy++ = (TILEY_PROCF(srcXY[1], maxY) << 16) | michael@0: TILEX_PROCF(srcXY[0], maxX); michael@0: srcXY += 2; michael@0: } michael@0: } michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max, michael@0: SkFixed one PREAMBLE_PARAM_Y) { michael@0: unsigned i = TILEY_PROCF(f, max); michael@0: i = (i << 4) | TILEY_LOW_BITS(f, max); michael@0: return (i << 14) | (TILEY_PROCF((f + one), max)); michael@0: } michael@0: michael@0: static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max, michael@0: SkFixed one PREAMBLE_PARAM_X) { michael@0: unsigned i = TILEX_PROCF(f, max); michael@0: i = (i << 4) | TILEX_LOW_BITS(f, max); michael@0: return (i << 14) | (TILEX_PROCF((f + one), max)); michael@0: } michael@0: michael@0: void SCALE_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y) { michael@0: SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | michael@0: SkMatrix::kScale_Mask)) == 0); michael@0: SkASSERT(s.fInvKy == 0); michael@0: michael@0: PREAMBLE(s); michael@0: michael@0: const unsigned maxX = s.fBitmap->width() - 1; michael@0: const SkFixed one = s.fFilterOneX; michael@0: const SkFractionalInt dx = s.fInvSxFractionalInt; michael@0: SkFractionalInt fx; michael@0: michael@0: { michael@0: SkPoint pt; michael@0: s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &pt); michael@0: const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1); michael@0: const unsigned maxY = s.fBitmap->height() - 1; michael@0: // compute our two Y values up front michael@0: *xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y); michael@0: // now initialize fx michael@0: fx = SkScalarToFractionalInt(pt.fX) - (SkFixedToFractionalInt(one) >> 1); michael@0: } michael@0: michael@0: #ifdef CHECK_FOR_DECAL michael@0: if (can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) { michael@0: decal_filter_scale(xy, SkFractionalIntToFixed(fx), michael@0: SkFractionalIntToFixed(dx), count); michael@0: } else michael@0: #endif michael@0: { michael@0: do { michael@0: SkFixed fixedFx = SkFractionalIntToFixed(fx); michael@0: *xy++ = PACK_FILTER_X_NAME(fixedFx, maxX, one PREAMBLE_ARG_X); michael@0: fx += dx; michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: michael@0: void AFFINE_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t xy[], int count, int x, int y) { michael@0: SkASSERT(s.fInvType & SkMatrix::kAffine_Mask); michael@0: SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | michael@0: SkMatrix::kScale_Mask | michael@0: SkMatrix::kAffine_Mask)) == 0); michael@0: michael@0: PREAMBLE(s); michael@0: SkPoint srcPt; michael@0: s.fInvProc(s.fInvMatrix, michael@0: SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, &srcPt); michael@0: michael@0: SkFixed oneX = s.fFilterOneX; michael@0: SkFixed oneY = s.fFilterOneY; michael@0: SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1); michael@0: SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1); michael@0: SkFixed dx = s.fInvSx; michael@0: SkFixed dy = s.fInvKy; michael@0: unsigned maxX = s.fBitmap->width() - 1; michael@0: unsigned maxY = s.fBitmap->height() - 1; michael@0: michael@0: do { michael@0: *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y); michael@0: fy += dy; michael@0: *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X); michael@0: fx += dx; michael@0: } while (--count != 0); michael@0: } michael@0: michael@0: void PERSP_FILTER_NAME(const SkBitmapProcState& s, michael@0: uint32_t* SK_RESTRICT xy, int count, michael@0: int x, int y) { michael@0: SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask); michael@0: michael@0: PREAMBLE(s); michael@0: unsigned maxX = s.fBitmap->width() - 1; michael@0: unsigned maxY = s.fBitmap->height() - 1; michael@0: SkFixed oneX = s.fFilterOneX; michael@0: SkFixed oneY = s.fFilterOneY; michael@0: michael@0: SkPerspIter iter(s.fInvMatrix, michael@0: SkIntToScalar(x) + SK_ScalarHalf, michael@0: SkIntToScalar(y) + SK_ScalarHalf, count); michael@0: michael@0: while ((count = iter.next()) != 0) { michael@0: const SkFixed* SK_RESTRICT srcXY = iter.getXY(); michael@0: do { michael@0: *xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY, michael@0: oneY PREAMBLE_ARG_Y); michael@0: *xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX, michael@0: oneX PREAMBLE_ARG_X); michael@0: srcXY += 2; michael@0: } while (--count != 0); michael@0: } michael@0: } michael@0: michael@0: static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = { michael@0: SCALE_NOFILTER_NAME, michael@0: SCALE_FILTER_NAME, michael@0: AFFINE_NOFILTER_NAME, michael@0: AFFINE_FILTER_NAME, michael@0: PERSP_NOFILTER_NAME, michael@0: PERSP_FILTER_NAME michael@0: }; michael@0: michael@0: #undef MAKENAME michael@0: #undef TILEX_PROCF michael@0: #undef TILEY_PROCF michael@0: #ifdef CHECK_FOR_DECAL michael@0: #undef CHECK_FOR_DECAL michael@0: #endif michael@0: michael@0: #undef SCALE_NOFILTER_NAME michael@0: #undef SCALE_FILTER_NAME michael@0: #undef AFFINE_NOFILTER_NAME michael@0: #undef AFFINE_FILTER_NAME michael@0: #undef PERSP_NOFILTER_NAME michael@0: #undef PERSP_FILTER_NAME michael@0: michael@0: #undef PREAMBLE michael@0: #undef PREAMBLE_PARAM_X michael@0: #undef PREAMBLE_PARAM_Y michael@0: #undef PREAMBLE_ARG_X michael@0: #undef PREAMBLE_ARG_Y michael@0: michael@0: #undef TILEX_LOW_BITS michael@0: #undef TILEY_LOW_BITS