text: /*
      Copyright 2011 Google Inc.
  
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
  
      http://www.apache.org/licenses/LICENSE-2.0
  
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.
   */
  
  
  #define SCALE_NOFILTER_NAME     MAKENAME(_nofilter_scale)
  #define SCALE_FILTER_NAME       MAKENAME(_filter_scale)
  #define AFFINE_NOFILTER_NAME    MAKENAME(_nofilter_affine)
  #define AFFINE_FILTER_NAME      MAKENAME(_filter_affine)
  #define PERSP_NOFILTER_NAME     MAKENAME(_nofilter_persp)
  #define PERSP_FILTER_NAME       MAKENAME(_filter_persp)
  
  #define PACK_FILTER_X_NAME  MAKENAME(_pack_filter_x)
  #define PACK_FILTER_Y_NAME  MAKENAME(_pack_filter_y)
  
  #ifndef PREAMBLE
      #define PREAMBLE(state)
      #define PREAMBLE_PARAM_X
      #define PREAMBLE_PARAM_Y
      #define PREAMBLE_ARG_X
      #define PREAMBLE_ARG_Y
  #endif
  
  void SCALE_NOFILTER_NAME(const SkBitmapProcState& s,
                                  uint32_t xy[], int count, int x, int y) {
      SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
                               SkMatrix::kScale_Mask)) == 0);
  
      PREAMBLE(s);
      // we store y, x, x, x, x, x
  
      const unsigned maxX = s.fBitmap->width() - 1;
      SkFixed fx;
      {
          SkPoint pt;
          s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
          fx = SkScalarToFixed(pt.fY);
          const unsigned maxY = s.fBitmap->height() - 1;
          *xy++ = TILEY_PROCF(fx, maxY);
          fx = SkScalarToFixed(pt.fX);
      }
      
      if (0 == maxX) {
          // all of the following X values must be 0
          memset(xy, 0, count * sizeof(uint16_t));
          return;
      }
  
      const SkFixed dx = s.fInvSx;
  
  #ifdef CHECK_FOR_DECAL
      // test if we don't need to apply the tile proc
      if ((unsigned)(fx >> 16) <= maxX &&
          (unsigned)((fx + dx * (count - 1)) >> 16) <= maxX) {
          decal_nofilter_scale(xy, fx, dx, count);
      } else
  #endif
      {
          int i;
          for (i = (count >> 2); i > 0; --i) {
              unsigned a, b;
              a = TILEX_PROCF(fx, maxX); fx += dx;
              b = TILEX_PROCF(fx, maxX); fx += dx;
  #ifdef SK_CPU_BENDIAN
              *xy++ = (a << 16) | b;
  #else
              *xy++ = (b << 16) | a;
  #endif
              a = TILEX_PROCF(fx, maxX); fx += dx;
              b = TILEX_PROCF(fx, maxX); fx += dx;
  #ifdef SK_CPU_BENDIAN
              *xy++ = (a << 16) | b;
  #else
              *xy++ = (b << 16) | a;
  #endif
          }
          uint16_t* xx = (uint16_t*)xy;
          for (i = (count & 3); i > 0; --i) {
              *xx++ = TILEX_PROCF(fx, maxX); fx += dx;
          }
      }
  }
  
  // note: we could special-case on a matrix which is skewed in X but not Y.
  // this would require a more general setup thatn SCALE does, but could use
  // SCALE's inner loop that only looks at dx
  
  void AFFINE_NOFILTER_NAME(const SkBitmapProcState& s,
                                   uint32_t xy[], int count, int x, int y) {
      SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
      SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
                               SkMatrix::kScale_Mask |
                               SkMatrix::kAffine_Mask)) == 0);
      
      PREAMBLE(s);
      SkPoint srcPt;
      s.fInvProc(*s.fInvMatrix,
                 SkIntToScalar(x) + SK_ScalarHalf,
                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
      
      SkFixed fx = SkScalarToFixed(srcPt.fX);
      SkFixed fy = SkScalarToFixed(srcPt.fY);
      SkFixed dx = s.fInvSx;
      SkFixed dy = s.fInvKy;
      int maxX = s.fBitmap->width() - 1;
      int maxY = s.fBitmap->height() - 1;
      
      for (int i = count; i > 0; --i) {
          *xy++ = (TILEY_PROCF(fy, maxY) << 16) | TILEX_PROCF(fx, maxX);
          fx += dx; fy += dy;
      }
  }
  
  void PERSP_NOFILTER_NAME(const SkBitmapProcState& s,
                                  uint32_t* SK_RESTRICT xy,
                                  int count, int x, int y) {
      SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
      
      PREAMBLE(s);
      int maxX = s.fBitmap->width() - 1;
      int maxY = s.fBitmap->height() - 1;
      
      SkPerspIter   iter(*s.fInvMatrix,
                         SkIntToScalar(x) + SK_ScalarHalf,
                         SkIntToScalar(y) + SK_ScalarHalf, count);
      
      while ((count = iter.next()) != 0) {
          const SkFixed* SK_RESTRICT srcXY = iter.getXY();
          while (--count >= 0) {
              *xy++ = (TILEY_PROCF(srcXY[1], maxY) << 16) |
                       TILEX_PROCF(srcXY[0], maxX);
              srcXY += 2;
          }
      }
  }
  
  //////////////////////////////////////////////////////////////////////////////
  
  static inline uint32_t PACK_FILTER_Y_NAME(SkFixed f, unsigned max,
                                            SkFixed one PREAMBLE_PARAM_Y) {
      unsigned i = TILEY_PROCF(f, max);
      i = (i << 4) | TILEY_LOW_BITS(f, max);
      return (i << 14) | (TILEY_PROCF((f + one), max));
  }
  
  static inline uint32_t PACK_FILTER_X_NAME(SkFixed f, unsigned max,
                                            SkFixed one PREAMBLE_PARAM_X) {
      unsigned i = TILEX_PROCF(f, max);
      i = (i << 4) | TILEX_LOW_BITS(f, max);
      return (i << 14) | (TILEX_PROCF((f + one), max));
  }
  
  void SCALE_FILTER_NAME(const SkBitmapProcState& s,
                                uint32_t xy[], int count, int x, int y) {
      SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
                               SkMatrix::kScale_Mask)) == 0);
      SkASSERT(s.fInvKy == 0);
  
      PREAMBLE(s);
      
      const unsigned maxX = s.fBitmap->width() - 1;
      const SkFixed one = s.fFilterOneX;
      const SkFixed dx = s.fInvSx;
      SkFixed fx;
  
      {
          SkPoint pt;
          s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
          const SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
          const unsigned maxY = s.fBitmap->height() - 1;
          // compute our two Y values up front
          *xy++ = PACK_FILTER_Y_NAME(fy, maxY, s.fFilterOneY PREAMBLE_ARG_Y);
          // now initialize fx
          fx = SkScalarToFixed(pt.fX) - (one >> 1);
      }
  
  #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, fx, dx, count);
      } else
  #endif
      {
          do {
              *xy++ = PACK_FILTER_X_NAME(fx, maxX, one PREAMBLE_ARG_X);
              fx += dx;
          } while (--count != 0);
      }
  }
  
  void AFFINE_FILTER_NAME(const SkBitmapProcState& s,
                                 uint32_t xy[], int count, int x, int y) {
      SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
      SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
                               SkMatrix::kScale_Mask |
                               SkMatrix::kAffine_Mask)) == 0);
      
      PREAMBLE(s);
      SkPoint srcPt;
      s.fInvProc(*s.fInvMatrix,
                 SkIntToScalar(x) + SK_ScalarHalf,
                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
      
      SkFixed oneX = s.fFilterOneX;
      SkFixed oneY = s.fFilterOneY;
      SkFixed fx = SkScalarToFixed(srcPt.fX) - (oneX >> 1);
      SkFixed fy = SkScalarToFixed(srcPt.fY) - (oneY >> 1);
      SkFixed dx = s.fInvSx;
      SkFixed dy = s.fInvKy;
      unsigned maxX = s.fBitmap->width() - 1;
      unsigned maxY = s.fBitmap->height() - 1;
      
      do {
          *xy++ = PACK_FILTER_Y_NAME(fy, maxY, oneY PREAMBLE_ARG_Y);
          fy += dy;
          *xy++ = PACK_FILTER_X_NAME(fx, maxX, oneX PREAMBLE_ARG_X);
          fx += dx;
      } while (--count != 0);
  }
  
  void PERSP_FILTER_NAME(const SkBitmapProcState& s,
                                uint32_t* SK_RESTRICT xy, int count,
                                int x, int y) {
      SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
      
      PREAMBLE(s);
      unsigned maxX = s.fBitmap->width() - 1;
      unsigned maxY = s.fBitmap->height() - 1;
      SkFixed oneX = s.fFilterOneX;
      SkFixed oneY = s.fFilterOneY;
      
      SkPerspIter   iter(*s.fInvMatrix,
                         SkIntToScalar(x) + SK_ScalarHalf,
                         SkIntToScalar(y) + SK_ScalarHalf, count);
      
      while ((count = iter.next()) != 0) {
          const SkFixed* SK_RESTRICT srcXY = iter.getXY();
          do {
              *xy++ = PACK_FILTER_Y_NAME(srcXY[1] - (oneY >> 1), maxY,
                                         oneY PREAMBLE_ARG_Y);
              *xy++ = PACK_FILTER_X_NAME(srcXY[0] - (oneX >> 1), maxX,
                                         oneX PREAMBLE_ARG_X);
              srcXY += 2;
          } while (--count != 0);
      }
  }
  
  static SkBitmapProcState::MatrixProc MAKENAME(_Procs)[] = {
      SCALE_NOFILTER_NAME,
      SCALE_FILTER_NAME,
      AFFINE_NOFILTER_NAME,
      AFFINE_FILTER_NAME,
      PERSP_NOFILTER_NAME,
      PERSP_FILTER_NAME
  };
  
  #undef MAKENAME
  #undef TILEX_PROCF
  #undef TILEY_PROCF
  #ifdef CHECK_FOR_DECAL
      #undef CHECK_FOR_DECAL
  #endif
  
  #undef SCALE_NOFILTER_NAME
  #undef SCALE_FILTER_NAME
  #undef AFFINE_NOFILTER_NAME
  #undef AFFINE_FILTER_NAME
  #undef PERSP_NOFILTER_NAME
  #undef PERSP_FILTER_NAME
  
  #undef PREAMBLE
  #undef PREAMBLE_PARAM_X
  #undef PREAMBLE_PARAM_Y
  #undef PREAMBLE_ARG_X
  #undef PREAMBLE_ARG_Y
  
  #undef TILEX_LOW_BITS
  #undef TILEY_LOW_BITS
  