code:
/* NEON optimized code (C) COPYRIGHT 2009 Motorola */
/*
 * Modifications done in-house at Motorola
 *
 * this is a clone of SkBitmapProcState_matrix.h
 * and has been tuned to work with the NEON unit.
 *
 * Still going back and forth between whether this approach
 * (clone the entire SkBitmapProcState_matrix.h file or
 * if I should put just the modified routines in here and
 * then use a construct like #define DONT_DO_THIS_FUNCTION or
 * something like that...
 *
 * This is for the RepeatX_RepeatY part of the world
 */

#if	!defined(__ARM_HAVE_NEON)
#error	this file can be used only when the NEON unit is enabled
#endif

#include <arm_neon.h>

/*
 * This has been modified on the knowledge that (at the time)
 * we had the following macro definitions in the parent file
 *
 * #define MAKENAME(suffix)        RepeatX_RepeatY ## suffix
 * #define TILEX_PROCF(fx, max)    (((fx) & 0xFFFF) * ((max) + 1) >> 16)
 * #define TILEY_PROCF(fy, max)    (((fy) & 0xFFFF) * ((max) + 1) >> 16)
 * #define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
 * #define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
 */

/* SkClampMax(val,max) -- bound to 0..max */

#define SCALE_NOFILTER_NAME     MAKENAME(_nofilter_scale_neon)
#define SCALE_FILTER_NAME       MAKENAME(_filter_scale)
#define AFFINE_NOFILTER_NAME    MAKENAME(_nofilter_affine_neon)
#define AFFINE_FILTER_NAME      MAKENAME(_filter_affine)
#define PERSP_NOFILTER_NAME     MAKENAME(_nofilter_persp_neon)
#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

static 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;

#if	defined(__ARM_HAVE_NEON)
	/* RBE: very much like done in decal_nofilter ,
	 * but some processing of the 'fx' information
         * TILEX_PROCF(fx, max)    (((fx) & 0xFFFF) * ((max) + 1) >> 16)
	 */
	if (count >= 8) {
	    /* SkFixed is 16.16 fixed point */
	    SkFixed dx2 = dx+dx;
	    SkFixed dx4 = dx2+dx2;
	    SkFixed dx8 = dx4+dx4;

	    /* now build fx/fx+dx/fx+2dx/fx+3dx */
	    SkFixed fx1, fx2, fx3;
	    int32x2_t lower, upper;
	    int32x4_t lbase, hbase;
	    int16_t *dst16 = (int16_t *)xy;

	    fx1 = fx+dx;
	    fx2 = fx1+dx;
	    fx3 = fx2+dx;

	    lbase = vdupq_n_s32(fx);
	    lbase = vsetq_lane_s32(fx1, lbase, 1);
	    lbase = vsetq_lane_s32(fx2, lbase, 2);
	    lbase = vsetq_lane_s32(fx3, lbase, 3);
	    hbase = vaddq_s32(lbase, vdupq_n_s32(dx4));

	    /* store & bump */
	    do
	    {
	        int32x4_t lout;
		int32x4_t hout;
		int16x8_t hi16;

         	/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
		/* mask to low 16 [would like to use uzp tricks) */
	        lout = vandq_s32(lbase, vdupq_n_s32(0xffff));
	        hout = vandq_s32(hbase, vdupq_n_s32(0xffff));
		/* bare multiplication, not SkFixedMul */
		lout = vmulq_s32(lout, vdupq_n_s32(maxX+1));
		hout = vmulq_s32(hout, vdupq_n_s32(maxX+1));

		/* extraction, using uzp */
		/* this is ok -- we want all hi(lout)s then all hi(hout)s */
		asm ("vuzpq.16 %q0, %q1" : "+w" (lout), "+w" (hout));
		hi16 = vreinterpretq_s16_s32(hout);
		vst1q_s16(dst16, hi16);

		/* bump our base on to the next */
		lbase = vaddq_s32 (lbase, vdupq_n_s32(dx8));
		hbase = vaddq_s32 (hbase, vdupq_n_s32(dx8));
		dst16 += 8;
		count -= 8;
		fx += dx8;
	    } while (count >= 8);
	    xy = (uint32_t *) dst16;
	}
#else
	/* simple, portable way of looking at 4 at a crack;
	 * so gets some loop unrolling, but not full SIMD speed
	 */
        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
        }
	/* loop doesn't adjust count */
	count -= (count>>2);
#endif
        uint16_t* xx = (uint16_t*)xy;
        for (i = count; 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

static 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;

#if 1
    int ocount = count;
    uint32_t *oxy = xy;
    SkFixed bfx = fx, bfy=fy, bdx=dx, bdy=dy;
#endif

#if	defined(__ARM_HAVE_NEON)

	if (0) { extern void rbe(void); rbe(); }

	/* RBE: benchmarks show this eats up time; can we neonize it? */
	/* RBE: very much like done in decal_nofilter ,
	 * but some processing of the 'fx' information
         * TILEX_PROCF(fx, max)    (((fx) & 0xFFFF) * ((max) + 1) >> 16)
	 */
	if (count >= 4) {
	    /* SkFixed is 16.16 fixed point */
	    SkFixed dx4 = dx*4;
	    SkFixed dy4 = dy*4;

	    /* now build fx/fx+dx/fx+2dx/fx+3dx */
	    int32x2_t lower, upper;
	    int32x4_t xbase, ybase;
	    int16_t *dst16 = (int16_t *)xy;

	    /* synthesize 4x for both X and Y */
	    xbase = vdupq_n_s32(fx);
	    xbase = vsetq_lane_s32(fx+dx, xbase, 1);
	    xbase = vsetq_lane_s32(fx+dx+dx, xbase, 2);
	    xbase = vsetq_lane_s32(fx+dx+dx+dx, xbase, 3);

	    ybase = vdupq_n_s32(fy);
	    ybase = vsetq_lane_s32(fy+dy, ybase, 1);
	    ybase = vsetq_lane_s32(fy+dy+dy, ybase, 2);
	    ybase = vsetq_lane_s32(fy+dy+dy+dy, ybase, 3);

	    /* store & bump */
	    do {
	        int32x4_t xout;
            int32x4_t yout;
            int16x8_t hi16;

         	/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
		/* mask to low 16 [would like to use uzp tricks) */
	        xout = vandq_s32(xbase, vdupq_n_s32(0xffff));
	        yout = vandq_s32(ybase, vdupq_n_s32(0xffff));
		/* bare multiplication, not SkFixedMul */
		xout = vmulq_s32(xout, vdupq_n_s32(maxX+1));
		yout = vmulq_s32(yout, vdupq_n_s32(maxY+1));

		/* put hi16 from xout over low16 from yout */
		yout = vsriq_n_s32(yout, xout, 16);

		/* and then yout has the interleaved upper 16's */
		hi16 = vreinterpretq_s16_s32(yout);
		vst1q_s16(dst16, hi16);

		/* bump preserved base & on to the next */
		xbase = vaddq_s32 (xbase, vdupq_n_s32(dx4));
		ybase = vaddq_s32 (ybase, vdupq_n_s32(dy4));
		dst16 += 8;	/* 8 x16 aka 4x32 */
		count -= 4;
		fx += dx4;
		fy += dy4;
	    } while (count >= 4);
	    xy = (uint32_t *) dst16;
	}

#if 0
    /* diagnostics... see whether we agree with the NEON code */
    int bad = 0;
    uint32_t *myxy = oxy;
    int myi = (-1);
    SkFixed ofx = bfx, ofy= bfy, odx= bdx, ody= bdy;
    for (myi = ocount; myi > 0; --myi) {
	uint32_t val = (TILEY_PROCF(ofy, maxY) << 16) | TILEX_PROCF(ofx, maxX);
	if (val != *myxy++) {
		bad++;
		break;
	}
        ofx += odx; ofy += ody;
    }
    if (bad) {
        SkDebugf("repeat-nofilter-affine fails\n");
        SkDebugf("count %d myi %d\n", ocount, myi);
        SkDebugf(" bfx %08x, bdx %08x, bfy %08x bdy %08x\n",
                bfx, bdx, bfy, bdy);
        SkDebugf("maxX %08x maxY %08x\n", maxX, maxY);
    }
#endif
#endif

    for (int i = count; i > 0; --i) {
	/* fx, fy, dx, dy are all 32 bit 16.16 fixed point */
	/* (((fx) & 0xFFFF) * ((max) + 1) >> 16) */
        *xy++ = (TILEY_PROCF(fy, maxY) << 16) | TILEX_PROCF(fx, maxX);
        fx += dx; fy += dy;
    }
}

static 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();

#if	defined(__ARM_HAVE_NEON)
	/* RBE: */
	/* TILEX_PROCF(fx, max) (((fx) & 0xFFFF) * ((max) + 1) >> 16) */
	/* it's a little more complicated than what I did for the
	 * clamp case -- where I could immediately snip to the top
	 * 16 bits and do my min/max games there.
	 * ... might only be able to get 4x unrolling here
	 */

	/* vld2 to get a set of 32x4's ... */
	/* do the tile[xy]_procf operations */
	/* which includes doing vuzp to get hi16's */
	/* store it */
	/* -- inner loop (other than vld2) can be had from above */

	/* srcXY is a batch of 32 bit numbers X0,Y0,X1,Y1...
	 * but we immediately discard the low 16 bits...
	 * so what we're going to do is vld4, which will give us
	 * xlo,xhi,ylo,yhi distribution and we can ignore the 'lo'
	 * parts....
	 */
	if (0) { extern void rbe(void); rbe(); }
	if (count >= 8) {
	    int32_t *mysrc = (int32_t *) srcXY;
	    int16_t *mydst = (int16_t *) xy;
	    do {
		int32x4_t x, y, x2, y2;
		int16x8_t hi, hi2;

		/* read array of x,y,x,y,x,y */
	        /* vld2 does the de-interleaving for us */
		/* isolate reg-bound scopes; gcc will minimize register
		 * motion if possible; this ensures that we don't lose
		 * a register across a debugging call because it happens
		 * to be bound into a call-clobbered register
		 */
		{
		    register int32x4_t q0 asm("q0");
		    register int32x4_t q1 asm("q1");
		    asm ("vld2.32	{q0-q1},[%2]  /* x=%q0 y=%q1 */"
		        : "=w" (q0), "=w" (q1)
		        : "r" (mysrc)
		        );
		    x = q0; y = q1;
		}

		/* offset == 256 bits == 32 bytes == 8 longs */
		{
		    register int32x4_t q2 asm("q2");
		    register int32x4_t q3 asm("q3");
		    asm ("vld2.32	{q2-q3},[%2]  /* x=%q0 y=%q1 */"
		        : "=w" (q2), "=w" (q3)
		        : "r" (mysrc+8)
		        );
		    x2 = q2; y2 = q3;
		}

         	/* TILEX_PROCF(fx, max) (((fx)&0xFFFF)*((max)+1)>> 16) */
		/* mask to low 16 [would like to use uzp tricks) */
		/* bare multiplication, not SkFixedMul */
	        x = vandq_s32(x, vdupq_n_s32(0xffff));
		x = vmulq_s32(x, vdupq_n_s32(maxX+1));
	        y = vandq_s32(y, vdupq_n_s32(0xffff));
		y = vmulq_s32(y, vdupq_n_s32(maxY+1));

	        x2 = vandq_s32(x2, vdupq_n_s32(0xffff));
		x2 = vmulq_s32(x2, vdupq_n_s32(maxX+1));
	        y2 = vandq_s32(y2, vdupq_n_s32(0xffff));
		y2 = vmulq_s32(y2, vdupq_n_s32(maxY+1));

		/* now collect interleaved high 16's */
		/* (hi-x, hi-y)4  (hi-x2; hi-y2)4 */

		/* extraction, using uzp, leaves hi16's in y */
		y = vsriq_n_s32(y, x, 16);
		hi = vreinterpretq_s16_s32(y);
		vst1q_s16(mydst, hi);

		/* and likewise for the second 8 entries */
		y2 = vsriq_n_s32(y2, x2, 16);
		hi2 = vreinterpretq_s16_s32(y2);
		vst1q_s16(mydst+8, hi2);

		/* XXX: gcc isn't interleaving these with the NEON ops
		 * but i think that all the scoreboarding works out */
		count -= 8;	/* 8 iterations */
		mysrc += 16;	/* 16 longs */
		mydst += 16;	/* 16 shorts, aka 8 longs */
	    } while (count >= 8);
	    /* get xy and srcXY fixed up */
	    srcXY = (const SkFixed *) mysrc;
	    xy = (uint32_t *) mydst;
	}
#endif
        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));
}

static 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);
    }
}

static 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);
}

static void PERSP_FILTER_NAME(const SkBitmapProcState& s,
                              uint32_t* SK_RESTRICT xy, int count,
                              int x, int y) {
    SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);

    extern void rbe(void);

    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


code:
/*
 **
 ** Copyright 2009, The Android Open Source Project
 **
 ** 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.
 */

#include "SkBitmapProcState.h"

void S32_opaque_D32_filter_DX_SSE2(const SkBitmapProcState& s,
                                   const uint32_t* xy,
                                   int count, uint32_t* colors);
void S32_alpha_D32_filter_DX_SSE2(const SkBitmapProcState& s,
                                  const uint32_t* xy,
                                  int count, uint32_t* colors);
void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count,
                  SkPMColor color);

license: mit


code:
#include "SkUtils.h"

#if DSTSIZE==32
    #define DSTTYPE SkPMColor
#elif DSTSIZE==16
    #define DSTTYPE uint16_t
#else
    #error "need DSTSIZE to be 32 or 16"
#endif

#if (DSTSIZE == 32)
    #define BITMAPPROC_MEMSET(ptr, value, n) sk_memset32(ptr, value, n)
#elif (DSTSIZE == 16)
    #define BITMAPPROC_MEMSET(ptr, value, n) sk_memset16(ptr, value, n)
#else
    #error "unsupported DSTSIZE"
#endif

void MAKENAME(_nofilter_DXDY)(const SkBitmapProcState& s,
                              const uint32_t* SK_RESTRICT xy,
                              int count, DSTTYPE* SK_RESTRICT colors) {
    SkASSERT(count > 0 && colors != NULL);
    SkASSERT(s.fDoFilter == false);
    SkDEBUGCODE(CHECKSTATE(s);)

#ifdef PREAMBLE
    PREAMBLE(s);
#endif
    const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();
    int i, rb = s.fBitmap->rowBytes();

    uint32_t XY;
    SRCTYPE src;

    for (i = (count >> 1); i > 0; --i) {
        XY = *xy++;
        SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&
                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());
        src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];
        *colors++ = RETURNDST(src);

        XY = *xy++;
        SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&
                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());
        src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];
        *colors++ = RETURNDST(src);
    }
    if (count & 1) {
        XY = *xy++;
        SkASSERT((XY >> 16) < (unsigned)s.fBitmap->height() &&
                 (XY & 0xFFFF) < (unsigned)s.fBitmap->width());
        src = ((const SRCTYPE*)(srcAddr + (XY >> 16) * rb))[XY & 0xFFFF];
        *colors++ = RETURNDST(src);
    }

#ifdef POSTAMBLE
    POSTAMBLE(s);
#endif
}

void MAKENAME(_nofilter_DX)(const SkBitmapProcState& s,
                            const uint32_t* SK_RESTRICT xy,
                            int count, DSTTYPE* SK_RESTRICT colors) {
    SkASSERT(count > 0 && colors != NULL);
    SkASSERT(s.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask));
    SkASSERT(s.fDoFilter == false);
    SkDEBUGCODE(CHECKSTATE(s);)

#ifdef PREAMBLE
    PREAMBLE(s);
#endif
    const SRCTYPE* SK_RESTRICT srcAddr = (const SRCTYPE*)s.fBitmap->getPixels();

    // buffer is y32, x16, x16, x16, x16, x16
    // bump srcAddr to the proper row, since we're told Y never changes
    SkASSERT((unsigned)xy[0] < (unsigned)s.fBitmap->height());
    srcAddr = (const SRCTYPE*)((const char*)srcAddr +
                                                xy[0] * s.fBitmap->rowBytes());
    xy += 1;

    SRCTYPE src;

    if (1 == s.fBitmap->width()) {
        src = srcAddr[0];
        DSTTYPE dstValue = RETURNDST(src);
        BITMAPPROC_MEMSET(colors, dstValue, count);
    } else {
        int i;
        for (i = (count >> 2); i > 0; --i) {
            uint32_t xx0 = *xy++;
            uint32_t xx1 = *xy++;
            SRCTYPE x0 = srcAddr[UNPACK_PRIMARY_SHORT(xx0)];
            SRCTYPE x1 = srcAddr[UNPACK_SECONDARY_SHORT(xx0)];
            SRCTYPE x2 = srcAddr[UNPACK_PRIMARY_SHORT(xx1)];
            SRCTYPE x3 = srcAddr[UNPACK_SECONDARY_SHORT(xx1)];

            *colors++ = RETURNDST(x0);
            *colors++ = RETURNDST(x1);
            *colors++ = RETURNDST(x2);
            *colors++ = RETURNDST(x3);
        }
        const uint16_t* SK_RESTRICT xx = (const uint16_t*)(xy);
        for (i = (count & 3); i > 0; --i) {
            SkASSERT(*xx < (unsigned)s.fBitmap->width());
            src = srcAddr[*xx++]; *colors++ = RETURNDST(src);
        }
    }

#ifdef POSTAMBLE
    POSTAMBLE(s);
#endif
}

///////////////////////////////////////////////////////////////////////////////

void MAKENAME(_filter_DX)(const SkBitmapProcState& s,
                          const uint32_t* SK_RESTRICT xy,
                           int count, DSTTYPE* SK_RESTRICT colors) {
    SkASSERT(count > 0 && colors != NULL);
    SkASSERT(s.fDoFilter);
    SkDEBUGCODE(CHECKSTATE(s);)

#ifdef PREAMBLE
    PREAMBLE(s);
#endif
    const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();
    unsigned rb = s.fBitmap->rowBytes();
    unsigned subY;
    const SRCTYPE* SK_RESTRICT row0;
    const SRCTYPE* SK_RESTRICT row1;

    // setup row ptrs and update proc_table
    {
        uint32_t XY = *xy++;
        unsigned y0 = XY >> 14;
        row0 = (const SRCTYPE*)(srcAddr + (y0 >> 4) * rb);
        row1 = (const SRCTYPE*)(srcAddr + (XY & 0x3FFF) * rb);
        subY = y0 & 0xF;
    }

    do {
        uint32_t XX = *xy++;    // x0:14 | 4 | x1:14
        unsigned x0 = XX >> 14;
        unsigned x1 = XX & 0x3FFF;
        unsigned subX = x0 & 0xF;
        x0 >>= 4;

        FILTER_PROC(subX, subY,
                    SRC_TO_FILTER(row0[x0]),
                    SRC_TO_FILTER(row0[x1]),
                    SRC_TO_FILTER(row1[x0]),
                    SRC_TO_FILTER(row1[x1]),
                    colors);
        colors += 1;

    } while (--count != 0);

#ifdef POSTAMBLE
    POSTAMBLE(s);
#endif
}
void MAKENAME(_filter_DXDY)(const SkBitmapProcState& s,
                            const uint32_t* SK_RESTRICT xy,
                            int count, DSTTYPE* SK_RESTRICT colors) {
    SkASSERT(count > 0 && colors != NULL);
    SkASSERT(s.fDoFilter);
    SkDEBUGCODE(CHECKSTATE(s);)

#ifdef PREAMBLE
        PREAMBLE(s);
#endif
    const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();
    int rb = s.fBitmap->rowBytes();

    do {
        uint32_t data = *xy++;
        unsigned y0 = data >> 14;
        unsigned y1 = data & 0x3FFF;
        unsigned subY = y0 & 0xF;
        y0 >>= 4;

        data = *xy++;
        unsigned x0 = data >> 14;
        unsigned x1 = data & 0x3FFF;
        unsigned subX = x0 & 0xF;
        x0 >>= 4;

        const SRCTYPE* SK_RESTRICT row0 = (const SRCTYPE*)(srcAddr + y0 * rb);
        const SRCTYPE* SK_RESTRICT row1 = (const SRCTYPE*)(srcAddr + y1 * rb);

        FILTER_PROC(subX, subY,
                    SRC_TO_FILTER(row0[x0]),
                    SRC_TO_FILTER(row0[x1]),
                    SRC_TO_FILTER(row1[x0]),
                    SRC_TO_FILTER(row1[x1]),
                    colors);
        colors += 1;
    } while (--count != 0);

#ifdef POSTAMBLE
    POSTAMBLE(s);
#endif
}

#undef MAKENAME
#undef DSTSIZE
#undef DSTTYPE
#undef SRCTYPE
#undef CHECKSTATE
#undef RETURNDST
#undef SRC_TO_FILTER
#undef FILTER_TO_DST

#ifdef PREAMBLE
    #undef PREAMBLE
#endif
#ifdef POSTAMBLE
    #undef POSTAMBLE
#endif

#undef FILTER_PROC_TYPE
#undef GET_FILTER_TABLE
#undef GET_FILTER_ROW
#undef GET_FILTER_ROW_PROC
#undef GET_FILTER_PROC
#undef BITMAPPROC_MEMSET


code:
/*
    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_FILTER_NAME       MAKENAME(_filter_DX_shaderproc)

static void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y,
                              DSTTYPE* SK_RESTRICT colors, int count) {
    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
                             SkMatrix::kScale_Mask)) == 0);
    SkASSERT(s.fInvKy == 0);
    SkASSERT(count > 0 && colors != NULL);
    SkASSERT(s.fDoFilter);
    SkDEBUGCODE(CHECKSTATE(s);)

    const unsigned maxX = s.fBitmap->width() - 1;
    const SkFixed oneX = s.fFilterOneX;
    const SkFixed dx = s.fInvSx;
    SkFixed fx;
    const SRCTYPE* SK_RESTRICT row0;
    const SRCTYPE* SK_RESTRICT row1;
    unsigned subY;

    {
        SkPoint pt;
        s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
        SkFixed fy = SkScalarToFixed(pt.fY) - (s.fFilterOneY >> 1);
        const unsigned maxY = s.fBitmap->height() - 1;
        // compute our two Y values up front
        subY = TILEY_LOW_BITS(fy, maxY);
        int y0 = TILEY_PROCF(fy, maxY);
        int y1 = TILEY_PROCF((fy + s.fFilterOneY), maxY);

        const char* SK_RESTRICT srcAddr = (const char*)s.fBitmap->getPixels();
        unsigned rb = s.fBitmap->rowBytes();
        row0 = (const SRCTYPE*)(srcAddr + y0 * rb);
        row1 = (const SRCTYPE*)(srcAddr + y1 * rb);
        // now initialize fx
        fx = SkScalarToFixed(pt.fX) - (oneX >> 1);
    }

#ifdef PREAMBLE
    PREAMBLE(s);
#endif

    do {
        unsigned subX = TILEX_LOW_BITS(fx, maxX);
        unsigned x0 = TILEX_PROCF(fx, maxX);
        unsigned x1 = TILEX_PROCF((fx + oneX), maxX);

        FILTER_PROC(subX, subY,
                    SRC_TO_FILTER(row0[x0]),
                    SRC_TO_FILTER(row0[x1]),
                    SRC_TO_FILTER(row1[x0]),
                    SRC_TO_FILTER(row1[x1]),
                    colors);
        colors += 1;

        fx += dx;
    } while (--count != 0);

#ifdef POSTAMBLE
    POSTAMBLE(s);
#endif
}

///////////////////////////////////////////////////////////////////////////////

#undef TILEX_PROCF
#undef TILEY_PROCF
#undef TILEX_LOW_BITS
#undef TILEY_LOW_BITS
#undef MAKENAME
#undef SRCTYPE
#undef DSTTYPE
#undef CHECKSTATE
#undef SRC_TO_FILTER
#undef FILTER_TO_DST
#undef PREAMBLE
#undef POSTAMBLE

#undef SCALE_FILTER_NAME


code:
/* libs/graphics/sgl/SkBitmapSampler.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#ifndef SkBitmapSampler_DEFINED
#define SkBitmapSampler_DEFINED

#include "SkBitmap.h"
#include "SkPaint.h"
#include "SkShader.h"

typedef int (*SkTileModeProc)(int value, unsigned max);

class SkBitmapSampler {
public:
    SkBitmapSampler(const SkBitmap&, bool filter, SkShader::TileMode tmx, SkShader::TileMode tmy);
    virtual ~SkBitmapSampler() {}

    const SkBitmap&     getBitmap() const { return fBitmap; }
    bool                getFilterBitmap() const { return fFilterBitmap; }
    SkShader::TileMode  getTileModeX() const { return fTileModeX; }
    SkShader::TileMode  getTileModeY() const { return fTileModeY; }

    /** Given a pixel center at [x,y], return the color sample
    */
    virtual SkPMColor sample(SkFixed x, SkFixed y) const = 0;

    virtual void setPaint(const SkPaint& paint);

    // This is the factory for finding an optimal subclass
    static SkBitmapSampler* Create(const SkBitmap&, bool filter,
                                   SkShader::TileMode tmx, SkShader::TileMode tmy);

protected:
    const SkBitmap&     fBitmap;
    uint16_t            fMaxX, fMaxY;
    bool                fFilterBitmap;
    SkShader::TileMode  fTileModeX;
    SkShader::TileMode  fTileModeY;
    SkTileModeProc      fTileProcX;
    SkTileModeProc      fTileProcY;

    // illegal
    SkBitmapSampler& operator=(const SkBitmapSampler&);
};

static inline int fixed_clamp(SkFixed x)
{
#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
    if (x >> 16)
        x = 0xFFFF;
    if (x < 0)
        x = 0;
#else
    if (x >> 16)
    {
        if (x < 0)
            x = 0;
        else
            x = 0xFFFF;
    }
#endif
    return x;
}

//////////////////////////////////////////////////////////////////////////////////////

static inline int fixed_repeat(SkFixed x)
{
    return x & 0xFFFF;
}

static inline int fixed_mirror(SkFixed x)
{
    SkFixed s = x << 15 >> 31;
    // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
    return (x ^ s) & 0xFFFF;
}

static inline bool is_pow2(int count)
{
    SkASSERT(count > 0);
    return (count & (count - 1)) == 0;
}

static inline int do_clamp(int index, unsigned max)
{
    SkASSERT((int)max >= 0);

#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
    if (index > (int)max)
        index = max;
    if (index < 0)
        index = 0;
#else
    if ((unsigned)index > max)
    {
        if (index < 0)
            index = 0;
        else
            index = max;
    }
#endif
    return index;
}

static inline int do_repeat_mod(int index, unsigned max)
{
    SkASSERT((int)max >= 0);

    if ((unsigned)index > max)
    {
        if (index < 0)
            index = max - (~index % (max + 1));
        else
            index = index % (max + 1);
    }
    return index;
}

static inline int do_repeat_pow2(int index, unsigned max)
{
    SkASSERT((int)max >= 0 && is_pow2(max + 1));

    return index & max;
}

static inline int do_mirror_mod(int index, unsigned max)
{
    SkASSERT((int)max >= 0);

    // have to handle negatives so that
    // -1 -> 0, -2 -> 1, -3 -> 2, etc.
    // so we can't just cal abs
    index ^= index >> 31;

    if ((unsigned)index > max)
    {
        int mod = (max + 1) << 1;
        index = index % mod;
        if ((unsigned)index > max)
            index = mod - index - 1;
    }
    return index;
}

static inline int do_mirror_pow2(int index, unsigned max)
{
    SkASSERT((int)max >= 0 && is_pow2(max + 1));

    int s = (index & (max + 1)) - 1;
    s = ~(s >> 31);
    // at this stage, s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
    return (index ^ s) & max;
}

#endif


code:
/* libs/graphics/sgl/SkBitmapSamplerTemplate.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

/*  this guy is pulled in multiple times, with the following symbols defined each time:

    #define BITMAP_CLASSNAME_PREFIX(name)           ARGB32##name
    #defube BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y)   *bitmap.getAddr32(x, y)
*/

class BITMAP_CLASSNAME_PREFIX(_Point_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Sampler)(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
        : SkBitmapSampler(bm, false, tmx, tmy)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = fTileProcX(SkFixedFloor(x), fMaxX);
        y = fTileProcY(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

class BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler)(const SkBitmap& bm)
        : SkBitmapSampler(bm, false, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = do_clamp(SkFixedFloor(x), fMaxX);
        y = do_clamp(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler)(const SkBitmap& bm)
        : SkBitmapSampler(bm, false, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = do_repeat_pow2(SkFixedFloor(x), fMaxX);
        y = do_repeat_pow2(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler)(const SkBitmap& bm)
        : SkBitmapSampler(bm, false, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = do_repeat_mod(SkFixedFloor(x), fMaxX);
        y = do_repeat_mod(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler)(const SkBitmap& bm)
        : SkBitmapSampler(bm, false, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = do_mirror_pow2(SkFixedFloor(x), fMaxX);
        y = do_mirror_pow2(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler) : public SkBitmapSampler {
public:
    BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler)(const SkBitmap& bm)
        : SkBitmapSampler(bm, false, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
    {
    }

    virtual SkPMColor sample(SkFixed x, SkFixed y) const
    {
        x = do_mirror_mod(SkFixedFloor(x), fMaxX);
        y = do_mirror_mod(SkFixedFloor(y), fMaxY);
        return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
    }
};

#undef BITMAP_CLASSNAME_PREFIX
#undef BITMAP_PIXEL_TO_PMCOLOR


code:
/* libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#include "SkFilterProc.h"

class BILERP_BITMAP16_SHADER_CLASS : public HasSpan16_Sampler_BitmapShader {
public:
    BILERP_BITMAP16_SHADER_CLASS(const SkBitmap& src)
        : HasSpan16_Sampler_BitmapShader(src, true,
                                         SkShader::kClamp_TileMode,
                                         SkShader::kClamp_TileMode)
    {
    }

    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
    {
        SkASSERT(count > 0);

        U8CPU alpha = this->getPaintAlpha();

        const SkMatrix& inv = this->getTotalInverse();
        const SkBitmap& srcBitmap = this->getSrcBitmap();
        unsigned        srcMaxX = srcBitmap.width() - 1;
        unsigned        srcMaxY = srcBitmap.height() - 1;
        unsigned        srcRB = srcBitmap.rowBytes();

        BILERP_BITMAP16_SHADER_PREAMBLE(srcBitmap);

        const SkFilterProc* proc_table = SkGetBilinearFilterProcTable();
        const BILERP_BITMAP16_SHADER_TYPE* srcPixels = (const BILERP_BITMAP16_SHADER_TYPE*)srcBitmap.getPixels();

        if (this->getInverseClass() == kPerspective_MatrixClass)
        {
            SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, count);
            while ((count = iter.next()) != 0)
            {
                const SkFixed* srcXY = iter.getXY();
                while (--count >= 0)
                {
                    SkFixed fx = *srcXY++ - SK_FixedHalf;
                    SkFixed fy = *srcXY++ - SK_FixedHalf;
                    int ix = fx >> 16;
                    int iy = fy >> 16;
                    int x = SkClampMax(ix, srcMaxX);
                    int y = SkClampMax(iy, srcMaxY);

                    const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;

                    p00 = p01 = ((const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels + y * srcRB)) + x;
                    if ((unsigned)ix < srcMaxX)
                        p01 += 1;
                    p10 = p00;
                    p11 = p01;
                    if ((unsigned)iy < srcMaxY)
                    {
                        p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p10 + srcRB);
                        p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p11 + srcRB);
                    }

                    SkFilterProc proc = SkGetBilinearFilterProc(proc_table, fx, fy);
                    uint32_t c = proc(SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p00)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p01)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p10)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p11)));

                    *dstC++ = expanded_rgb16_to_8888(c, alpha);
                }
            }
        }
        else    // linear case
        {
            SkFixed fx, fy, dx, dy;

            // now init fx, fy, dx, dy
            {
                SkPoint srcPt;
                this->getInverseMapPtProc()(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);

                fx = SkScalarToFixed(srcPt.fX) - SK_FixedHalf;
                fy = SkScalarToFixed(srcPt.fY) - SK_FixedHalf;

                if (this->getInverseClass() == kFixedStepInX_MatrixClass)
                    (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
                else
                {
                    dx = SkScalarToFixed(inv.getScaleX());
                    dy = SkScalarToFixed(inv.getSkewY());
                }
            }

            do {
                int ix = fx >> 16;
                int iy = fy >> 16;

                const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;

                p00 = p01 = ((const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels +
                                                                   SkClampMax(iy, srcMaxY) * srcRB)) +
                                                                   SkClampMax(ix, srcMaxX);
                if ((unsigned)ix < srcMaxX)
                    p01 += 1;
                p10 = p00;
                p11 = p01;
                if ((unsigned)iy < srcMaxY)
                {
                    p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p10 + srcRB);
                    p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p11 + srcRB);
                }

                SkFilterProc proc = SkGetBilinearFilterProc(proc_table, fx, fy);
                uint32_t c = proc(SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p00)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p01)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p10)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p11)));
                *dstC++ = expanded_rgb16_to_8888(c, alpha);

                fx += dx;
                fy += dy;
            } while (--count != 0);
        }
        BILERP_BITMAP16_SHADER_POSTAMBLE(srcBitmap);
    }

    virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count)
    {
        SkASSERT(count > 0);

        const SkMatrix& inv = this->getTotalInverse();
        const SkBitmap& srcBitmap = this->getSrcBitmap();
        unsigned        srcMaxX = srcBitmap.width() - 1;
        unsigned        srcMaxY = srcBitmap.height() - 1;
        unsigned        srcRB = srcBitmap.rowBytes();

        BILERP_BITMAP16_SHADER_PREAMBLE(srcBitmap);

        const SkFilterProc* proc_table = SkGetBilinearFilterProcTable();
        const BILERP_BITMAP16_SHADER_TYPE* srcPixels = (const BILERP_BITMAP16_SHADER_TYPE*)srcBitmap.getPixels();

        if (this->getInverseClass() == kPerspective_MatrixClass)
        {
            SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, count);
            while ((count = iter.next()) != 0)
            {
                const SkFixed* srcXY = iter.getXY();
                while (--count >= 0)
                {
                    SkFixed fx = *srcXY++ - SK_FixedHalf;
                    SkFixed fy = *srcXY++ - SK_FixedHalf;
                    int ix = fx >> 16;
                    int iy = fy >> 16;

                    const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;

                    p00 = p01 = ((const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels +
                                                                      SkClampMax(iy, srcMaxY) * srcRB)) +
                                                                      SkClampMax(ix, srcMaxX);
                    if ((unsigned)ix < srcMaxX)
                        p01 += 1;
                    p10 = p00;
                    p11 = p01;
                    if ((unsigned)iy < srcMaxY)
                    {
                        p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p10 + srcRB);
                        p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p11 + srcRB);
                    }

                    SkFilterProc proc = SkGetBilinearFilterProc(proc_table, fx, fy);
                    uint32_t c = proc(SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p00)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p01)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p10)),
                                      SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p11)));
                    *dstC++ = SkCompact_rgb_16(c);
                }
            }
        }
        else    // linear case
        {
            SkFixed fx, fy, dx, dy;

            // now init fx, fy, dx, dy
            {
                SkPoint srcPt;
                this->getInverseMapPtProc()(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);

                fx = SkScalarToFixed(srcPt.fX) - SK_FixedHalf;
                fy = SkScalarToFixed(srcPt.fY) - SK_FixedHalf;

                if (this->getInverseClass() == kFixedStepInX_MatrixClass)
                    (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
                else
                {
                    dx = SkScalarToFixed(inv.getScaleX());
                    dy = SkScalarToFixed(inv.getSkewY());
                }
            }

            do {
                int ix = fx >> 16;
                int iy = fy >> 16;

                const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;

                p00 = p01 = ((const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels +
                                                                  SkClampMax(iy, srcMaxY) * srcRB)) +
                                                                  SkClampMax(ix, srcMaxX);
                if ((unsigned)ix < srcMaxX)
                    p01 += 1;
                p10 = p00;
                p11 = p01;
                if ((unsigned)iy < srcMaxY)
                {
                    p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p10 + srcRB);
                    p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p11 + srcRB);
                }

                SkFilterProc proc = SkGetBilinearFilterProc(proc_table, fx, fy);
                uint32_t c = proc(SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p00)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p01)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p10)),
                                  SkExpand_rgb_16(BILERP_BITMAP16_SHADER_PIXEL(*p11)));
                *dstC++ = SkCompact_rgb_16(c);

                fx += dx;
                fy += dy;
            } while (--count != 0);
        }
        BILERP_BITMAP16_SHADER_POSTAMBLE(srcBitmap);
    }
};

#undef BILERP_BITMAP16_SHADER_CLASS
#undef BILERP_BITMAP16_SHADER_TYPE
#undef BILERP_BITMAP16_SHADER_PREAMBLE
#undef BILERP_BITMAP16_SHADER_PIXEL
#undef BILERP_BITMAP16_SHADER_POSTAMBLE


code:
/* libs/graphics/sgl/SkBitmapShaderTemplate.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#ifndef NOFILTER_BITMAP_SHADER_PREAMBLE
    #define NOFILTER_BITMAP_SHADER_PREAMBLE(bitmap, rb)
#endif
#ifndef NOFILTER_BITMAP_SHADER_POSTAMBLE
    #define NOFILTER_BITMAP_SHADER_POSTAMBLE(bitmap)
#endif
#ifndef NOFILTER_BITMAP_SHADER_PREAMBLE16
    #define NOFILTER_BITMAP_SHADER_PREAMBLE16(bitmap, rb)
#endif
#ifndef NOFILTER_BITMAP_SHADER_POSTAMBLE16
    #define NOFILTER_BITMAP_SHADER_POSTAMBLE16(bitmap)
#endif

class NOFILTER_BITMAP_SHADER_CLASS : public HasSpan16_Sampler_BitmapShader {
public:
    NOFILTER_BITMAP_SHADER_CLASS(const SkBitmap& src)
        : HasSpan16_Sampler_BitmapShader(src, false,
                                         NOFILTER_BITMAP_SHADER_TILEMODE,
                                         NOFILTER_BITMAP_SHADER_TILEMODE)
    {
    }

    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
    {
        if (!this->INHERITED::setContext(device, paint, matrix))
            return false;

#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
        this->computeUnitInverse();
#endif
        return true;
    }

    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
    {
        SkASSERT(count > 0);

#ifdef NOFILTER_BITMAP_SHADER_SPRITEPROC32
        if ((this->getTotalInverse().getType() & ~SkMatrix::kTranslate_Mask) == 0)
        {
            NOFILTER_BITMAP_SHADER_SPRITEPROC32(this, x, y, dstC, count);
            return;
        }
#endif

        unsigned        scale = SkAlpha255To256(this->getPaintAlpha());
#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
        const SkMatrix& inv = this->getUnitInverse();
        SkMatrix::MapPtProc invProc = this->getUnitInverseProc();
#else
        const SkMatrix& inv = this->getTotalInverse();
        SkMatrix::MapPtProc invProc = this->getInverseMapPtProc();
#endif
        const SkBitmap& srcBitmap = this->getSrcBitmap();
        unsigned        srcMaxX = srcBitmap.width() - 1;
        unsigned        srcMaxY = srcBitmap.height() - 1;
        unsigned        srcRB = srcBitmap.rowBytes();
        SkFixed         fx, fy, dx, dy;

        const NOFILTER_BITMAP_SHADER_TYPE* srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)srcBitmap.getPixels();
        NOFILTER_BITMAP_SHADER_PREAMBLE(srcBitmap, srcRB);

        if (this->getInverseClass() == kPerspective_MatrixClass)
        {
            SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, count);
            while ((count = iter.next()) != 0)
            {
                const SkFixed* srcXY = iter.getXY();

/*  Do I need this?
#ifndef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
            fx >>= level;
            fy >>= level;
#endif
*/
                if (256 == scale)
                {
                    while (--count >= 0)
                    {
                        fx = *srcXY++;
                        fy = *srcXY++;
                        unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                        unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                        *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
                    }
                }
                else
                {
                    while (--count >= 0)
                    {
                        fx = *srcXY++;
                        fy = *srcXY++;
                        unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                        unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                        uint32_t c = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
                        *dstC++ = SkAlphaMulQ(c, scale);
                    }
                }
            }
            return;
        }

        // now init fx, fy, dx, dy
        {
            SkPoint srcPt;
            invProc(inv, SkIntToScalar(x) + SK_ScalarHalf,
                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);

            fx = SkScalarToFixed(srcPt.fX);
            fy = SkScalarToFixed(srcPt.fY);

            if (this->getInverseClass() == kFixedStepInX_MatrixClass)
                (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
            else
            {
                dx = SkScalarToFixed(inv.getScaleX());
                dy = SkScalarToFixed(inv.getSkewY());
            }
        }

#ifndef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
        {   int level = this->getMipLevel() >> 16;
            fx >>= level;
            fy >>= level;
            dx >>= level;
            dy >>= level;
        }
#endif

        if (dy == 0)
        {
            int y_index = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
//          SkDEBUGF(("fy = %g, srcMaxY = %d, y_index = %d\n", SkFixedToFloat(fy), srcMaxY, y_index));
            srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)((const char*)srcPixels + y_index * srcRB);
            if (scale == 256)
                while (--count >= 0)
                {
                    unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                    fx += dx;
                    *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_X(srcPixels, x);
                }
            else
                while (--count >= 0)
                {
                    unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                    SkPMColor c = NOFILTER_BITMAP_SHADER_SAMPLE_X(srcPixels, x);
                    fx += dx;
                    *dstC++ = SkAlphaMulQ(c, scale);
                }
        }
        else    // dy != 0
        {
            if (scale == 256)
                while (--count >= 0)
                {
                    unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                    unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                    fx += dx;
                    fy += dy;
                    *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
                }
            else
                while (--count >= 0)
                {
                    unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                    unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                    SkPMColor c = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
                    fx += dx;
                    fy += dy;
                    *dstC++ = SkAlphaMulQ(c, scale);
                }
        }

        NOFILTER_BITMAP_SHADER_POSTAMBLE(srcBitmap);
    }

    virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count)
    {
        SkASSERT(count > 0);
        SkASSERT(this->getFlags() & SkShader::kHasSpan16_Flag);

#ifdef NOFILTER_BITMAP_SHADER_SPRITEPROC16
        if ((this->getTotalInverse().getType() & ~SkMatrix::kTranslate_Mask) == 0)
        {
            NOFILTER_BITMAP_SHADER_SPRITEPROC16(this, x, y, dstC, count);
            return;
        }
#endif

#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
        const SkMatrix& inv = this->getUnitInverse();
        SkMatrix::MapPtProc invProc = this->getUnitInverseProc();
#else
        const SkMatrix& inv = this->getTotalInverse();
        SkMatrix::MapPtProc invProc = this->getInverseMapPtProc();
#endif
        const SkBitmap& srcBitmap = this->getSrcBitmap();
        unsigned        srcMaxX = srcBitmap.width() - 1;
        unsigned        srcMaxY = srcBitmap.height() - 1;
        unsigned        srcRB = srcBitmap.rowBytes();
        SkFixed         fx, fy, dx, dy;

        const NOFILTER_BITMAP_SHADER_TYPE* srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)srcBitmap.getPixels();
        NOFILTER_BITMAP_SHADER_PREAMBLE16(srcBitmap, srcRB);

        if (this->getInverseClass() == kPerspective_MatrixClass)
        {
            SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
                                    SkIntToScalar(y) + SK_ScalarHalf, count);
            while ((count = iter.next()) != 0)
            {
                const SkFixed* srcXY = iter.getXY();

                while (--count >= 0)
                {
                    fx = *srcXY++;
                    fy = *srcXY++;
                    unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                    unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                    *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY16(srcPixels, x, y, srcRB);
                }
            }
            return;
        }

        // now init fx, fy, dx, dy
        {
            SkPoint srcPt;
            invProc(inv, SkIntToScalar(x) + SK_ScalarHalf,
                         SkIntToScalar(y) + SK_ScalarHalf, &srcPt);

            fx = SkScalarToFixed(srcPt.fX);
            fy = SkScalarToFixed(srcPt.fY);

            if (this->getInverseClass() == kFixedStepInX_MatrixClass)
                (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
            else
            {
                dx = SkScalarToFixed(inv.getScaleX());
                dy = SkScalarToFixed(inv.getSkewY());
            }
        }

#ifndef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
        {   int level = this->getMipLevel() >> 16;
            fx >>= level;
            fy >>= level;
            dx >>= level;
            dy >>= level;
        }
#endif

        if (dy == 0)
        {
            srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)((const char*)srcPixels + NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY) * srcRB);
            do {
                unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                fx += dx;
                *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_X16(srcPixels, x);
            } while (--count != 0);
        }
        else    // dy != 0
        {
            do {
                unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
                unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
                fx += dx;
                fy += dy;
                *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY16(srcPixels, x, y, srcRB);
            } while (--count != 0);
        }

        NOFILTER_BITMAP_SHADER_POSTAMBLE16(srcBitmap);
    }
private:
    typedef HasSpan16_Sampler_BitmapShader INHERITED;
};

#undef NOFILTER_BITMAP_SHADER_CLASS
#undef NOFILTER_BITMAP_SHADER_TYPE
#undef NOFILTER_BITMAP_SHADER_PREAMBLE
#undef NOFILTER_BITMAP_SHADER_POSTAMBLE
#undef NOFILTER_BITMAP_SHADER_SAMPLE_X      //(x)
#undef NOFILTER_BITMAP_SHADER_SAMPLE_XY     //(x, y, rowBytes)
#undef NOFILTER_BITMAP_SHADER_TILEMODE
#undef NOFILTER_BITMAP_SHADER_TILEPROC

#undef NOFILTER_BITMAP_SHADER_PREAMBLE16
#undef NOFILTER_BITMAP_SHADER_POSTAMBLE16
#undef NOFILTER_BITMAP_SHADER_SAMPLE_X16        //(x)
#undef NOFILTER_BITMAP_SHADER_SAMPLE_XY16       //(x, y, rowBytes)

#undef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
#undef NOFILTER_BITMAP_SHADER_SPRITEPROC16
#undef NOFILTER_BITMAP_SHADER_SPRITEPROC32


code:
#ifndef SkBitmap_RLEPixels_DEFINED
#define SkBitmap_RLEPixels_DEFINED

#include "SkChunkAlloc.h"

class SkBitmap_RLEPixels {
public:
    SkBitmap_RLEPixels(int width, int height);
    ~SkBitmap_RLEPixels();

    uint8_t* yptrs() const { return fYPtrs; }
    uint8_t* allocChunk(size_t chunk);

private:
    SkChunkAlloc    fChunk;
    uint8_t**       fYPtrs;
};

#endif


code:
/* libs/graphics/sgl/SkBlitBWMaskTemplate.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#include "SkBitmap.h"
#include "SkMask.h"

#ifndef ClearLow3Bits_DEFINED
#define ClearLow3Bits_DEFINED
    #define ClearLow3Bits(x)    ((unsigned)(x) >> 3 << 3)
#endif

/*
    SK_BLITBWMASK_NAME          name of function(const SkBitmap& bitmap, const SkMask& mask, const SkIRect& clip, SK_BLITBWMASK_ARGS)
    SK_BLITBWMASK_ARGS          list of additional arguments to SK_BLITBWMASK_NAME, beginning with a comma
    SK_BLITBWMASK_BLIT8         name of function(U8CPU byteMask, SK_BLITBWMASK_DEVTYPE* dst, int x, int y)
    SK_BLITBWMASK_GETADDR       either getAddr32 or getAddr16 or getAddr8
    SK_BLITBWMASK_DEVTYPE       either U32 or U16 or U8
*/

static void SK_BLITBWMASK_NAME(const SkBitmap& bitmap, const SkMask& srcMask, const SkIRect& clip SK_BLITBWMASK_ARGS)
{
    SkASSERT(clip.fRight <= srcMask.fBounds.fRight);

    int cx = clip.fLeft;
    int cy = clip.fTop;
    int maskLeft = srcMask.fBounds.fLeft;
    unsigned mask_rowBytes = srcMask.fRowBytes;
    unsigned bitmap_rowBytes = bitmap.rowBytes();
    unsigned height = clip.height();

    SkASSERT(mask_rowBytes != 0);
    SkASSERT(bitmap_rowBytes != 0);
    SkASSERT(height != 0);

    const uint8_t* bits = srcMask.getAddr1(cx, cy);
    SK_BLITBWMASK_DEVTYPE* device = bitmap.SK_BLITBWMASK_GETADDR(cx, cy);

    if (cx == maskLeft && clip.fRight == srcMask.fBounds.fRight)
    {
        do {
            SK_BLITBWMASK_DEVTYPE* dst = device;
            unsigned rb = mask_rowBytes;
            do {
                U8CPU mask = *bits++;
                SK_BLITBWMASK_BLIT8(mask, dst);
                dst += 8;
            } while (--rb != 0);
            device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
        } while (--height != 0);
    }
    else
    {
        int left_edge = cx - maskLeft;
        SkASSERT(left_edge >= 0);
        int rite_edge = clip.fRight - maskLeft;
        SkASSERT(rite_edge > left_edge);

        int left_mask = 0xFF >> (left_edge & 7);
        int rite_mask = 0xFF << (8 - (rite_edge & 7));
        int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);

        // check for empty right mask, so we don't read off the end (or go slower than we need to)
        if (rite_mask == 0)
        {
            SkASSERT(full_runs >= 0);
            full_runs -= 1;
            rite_mask = 0xFF;
        }
        if (left_mask == 0xFF)
            full_runs -= 1;

        // back up manually so we can keep in sync with our byte-aligned src
        // and not trigger an assert from the getAddr## function
        device -= left_edge & 7;
        // have cx reflect our actual starting x-coord
        cx -= left_edge & 7;

        if (full_runs < 0)
        {
            left_mask &= rite_mask;
            SkASSERT(left_mask != 0);
            do {
                U8CPU mask = *bits & left_mask;
                SK_BLITBWMASK_BLIT8(mask, device);
                bits += mask_rowBytes;
                device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
            } while (--height != 0);
        }
        else
        {
            do {
                int runs = full_runs;
                SK_BLITBWMASK_DEVTYPE* dst = device;
                const uint8_t* b = bits;
                U8CPU   mask;

                mask = *b++ & left_mask;
                SK_BLITBWMASK_BLIT8(mask, dst);
                dst += 8;

                while (--runs >= 0)
                {
                    mask = *b++;
                    SK_BLITBWMASK_BLIT8(mask, dst);
                    dst += 8;
                }

                mask = *b & rite_mask;
                SK_BLITBWMASK_BLIT8(mask, dst);

                bits += mask_rowBytes;
                device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
            } while (--height != 0);
        }
    }
}

#undef SK_BLITBWMASK_NAME
#undef SK_BLITBWMASK_ARGS
#undef SK_BLITBWMASK_BLIT8
#undef SK_BLITBWMASK_GETADDR
#undef SK_BLITBWMASK_DEVTYPE
#undef SK_BLITBWMASK_DOROWSETUP


code:
#ifndef SkBlitRow_DEFINED
#define SkBlitRow_DEFINED

#include "SkBitmap.h"
#include "SkColor.h"

class SkBlitRow {
public:
    enum Flags16 {
        //! If set, the alpha parameter will be != 255
        kGlobalAlpha_Flag   = 0x01,
        //! If set, the src colors may have alpha != 255
        kSrcPixelAlpha_Flag = 0x02,
        //! If set, the resulting 16bit colors should be dithered
        kDither_Flag        = 0x04
    };

    /** Function pointer that reads a scanline of src SkPMColors, and writes
        a corresponding scanline of 16bit colors (specific format based on the
        config passed to the Factory.

        The x,y params are useful just for dithering

        @param alpha A global alpha to be applied to all of the src colors
        @param x The x coordinate of the beginning of the scanline
        @param y THe y coordinate of the scanline
     */
    typedef void (*Proc)(uint16_t* dst,
                         const SkPMColor* src,
                         int count, U8CPU alpha, int x, int y);

   /** Function pointer that blends a single color with a row of 32-bit colors
       onto a 32-bit destination
   */
   typedef void (*ColorProc)(SkPMColor* dst, const SkPMColor* src, int count,
                             SkPMColor color);

    //! Public entry-point to return a blit function ptr
    static Proc Factory(unsigned flags, SkBitmap::Config);

    ///////////// D32 version

    enum Flags32 {
        kGlobalAlpha_Flag32     = 1 << 0,
        kSrcPixelAlpha_Flag32   = 1 << 1,
    };

    /** Function pointer that blends 32bit colors onto a 32bit destination.
        @param dst  array of dst 32bit colors
        @param src  array of src 32bit colors (w/ or w/o alpha)
        @param count number of colors to blend
        @param alpha global alpha to be applied to all src colors
     */
    typedef void (*Proc32)(uint32_t* dst,
                         const SkPMColor* src,
                         int count, U8CPU alpha);

    static Proc32 Factory32(unsigned flags32);

    /** Blend a single color onto a row of S32 pixels, writing the result
        into a row of D32 pixels. src and dst may be the same memory, but
        if they are not, they may not overlap.
     */
    static void Color32(SkPMColor dst[], const SkPMColor src[],
                        int count, SkPMColor color);

    static ColorProc ColorProcFactory();

    /** These static functions are called by the Factory and Factory32
        functions, and should return either NULL, or a
        platform-specific function-ptr to be used in place of the
        system default.
     */

    static Proc32 PlatformProcs32(unsigned flags);
    static Proc PlatformProcs565(unsigned flags);
    static Proc PlatformProcs4444(unsigned flags);
    static ColorProc PlatformColorProc();

private:
    enum {
        kFlags16_Mask = 7,
        kFlags32_Mask = 3
    };
};

/**
 *  Factory for blitmask procs
 */
class SkBlitMask {
public:
    /**
     *  Function pointer that blits the mask into a device (dst) colorized
     *  by color. The number of pixels to blit is specified by width and height,
     *  but each scanline is offset by dstRB (rowbytes) and srcRB respectively.
     */
    typedef void (*Proc)(void* dst, size_t dstRB, SkBitmap::Config dstConfig,
                        const uint8_t* mask, size_t maskRB, SkColor color,
                        int width, int height);

    /* Public entry-point to return a blitmask function ptr
     */
    static Proc Factory(SkBitmap::Config dstConfig, SkColor color);

    /* return either platform specific optimized blitmask function-ptr,
     * or NULL if no optimized
     */
    static Proc PlatformProcs(SkBitmap::Config dstConfig, SkColor color);
};

#endif


code:
/*
 **
 ** Copyright 2009, The Android Open Source Project
 **
 ** 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.
 */

#include "SkBlitRow.h"

void S32_Blend_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
                              const SkPMColor* SK_RESTRICT src,
                              int count, U8CPU alpha);

void S32A_Opaque_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
                                const SkPMColor* SK_RESTRICT src,
                                int count, U8CPU alpha);

void S32A_Blend_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
                               const SkPMColor* SK_RESTRICT src,
                               int count, U8CPU alpha);
void SkARGB32_BlitMask_SSE2(void* device, size_t dstRB,
                            SkBitmap::Config dstConfig, const uint8_t* mask,
                            size_t maskRB, SkColor color,
                            int width, int height);


code:
/* libs/graphics/sgl/SkBlitter.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#ifndef SkBlitter_DEFINED
#define SkBlitter_DEFINED

#include "SkBitmap.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkRefCnt.h"
#include "SkRegion.h"
#include "SkMask.h"

class SkBlitter {
public:
    virtual ~SkBlitter();

    virtual void blitH(int x, int y, int width);
    virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
                           const int16_t* runs);
    virtual void blitV(int x, int y, int height, SkAlpha alpha);
    virtual void blitRect(int x, int y, int width, int height);
    virtual void blitMask(const SkMask&, const SkIRect& clip);

    /*  If the blitter just sets a single value for each pixel, return the
        bitmap it draws into, and assign value. If not, return NULL and ignore
        the value parameter.
    */
    virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);

    // not virtual, just helpers
    void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
    void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
    void blitRegion(const SkRegion& clip);

    // factories
    static SkBlitter* Choose(const SkBitmap& device,
                             const SkMatrix& matrix,
                             const SkPaint& paint) {
        return Choose(device, matrix, paint, NULL, 0);
    }

    static SkBlitter* Choose(const SkBitmap& device,
                             const SkMatrix& matrix,
                             const SkPaint& paint,
                             void* storage, size_t storageSize);

    static SkBlitter* ChooseSprite(const SkBitmap& device,
                                   const SkPaint&,
                                   const SkBitmap& src,
                                   int left, int top,
                                   void* storage, size_t storageSize);

private:
};

/** This blitter silently never draws anything.
*/
class SkNullBlitter : public SkBlitter {
public:
    virtual void blitH(int x, int y, int width);
    virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]);
    virtual void blitV(int x, int y, int height, SkAlpha alpha);
    virtual void blitRect(int x, int y, int width, int height);
    virtual void blitMask(const SkMask&, const SkIRect& clip);
    virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
};

/** Wraps another (real) blitter, and ensures that the real blitter is only
    called with coordinates that have been clipped by the specified clipRect.
    This means the caller need not perform the clipping ahead of time.
*/
class SkRectClipBlitter : public SkBlitter {
public:
    void init(SkBlitter* blitter, const SkIRect& clipRect) {
        SkASSERT(!clipRect.isEmpty());
        fBlitter = blitter;
        fClipRect = clipRect;
    }

    // overrides
    virtual void blitH(int x, int y, int width);
    virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]);
    virtual void blitV(int x, int y, int height, SkAlpha alpha);
    virtual void blitRect(int x, int y, int width, int height);
    virtual void blitMask(const SkMask&, const SkIRect& clip);
    virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);

private:
    SkBlitter*  fBlitter;
    SkIRect     fClipRect;
};

/** Wraps another (real) blitter, and ensures that the real blitter is only
called with coordinates that have been clipped by the specified clipRgn.
This means the caller need not perform the clipping ahead of time.
*/
class SkRgnClipBlitter : public SkBlitter {
public:
    void init(SkBlitter* blitter, const SkRegion* clipRgn) {
        SkASSERT(clipRgn && !clipRgn->isEmpty());
        fBlitter = blitter;
        fRgn = clipRgn;
    }

    // overrides
    virtual void blitH(int x, int y, int width);
    virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]);
    virtual void blitV(int x, int y, int height, SkAlpha alpha);
    virtual void blitRect(int x, int y, int width, int height);
    virtual void blitMask(const SkMask&, const SkIRect& clip);
    virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);

private:
    SkBlitter*      fBlitter;
    const SkRegion* fRgn;
};

class SkBlitterClipper {
public:
    SkBlitter*  apply(SkBlitter* blitter, const SkRegion* clip,
                      const SkIRect* bounds = NULL);

private:
    SkNullBlitter       fNullBlitter;
    SkRectClipBlitter   fRectBlitter;
    SkRgnClipBlitter    fRgnBlitter;
};

#endif


code:
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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.
 */

#ifndef SkBlurDrawLooper_DEFINED
#define SkBlurDrawLooper_DEFINED

#include "SkDrawLooper.h"
#include "SkColor.h"

class SkMaskFilter;
class SkColorFilter;

/** \class SkBlurDrawLooper
    This class draws a shadow of the object (possibly offset), and then draws
    the original object in its original position.
    should there be an option to just draw the shadow/blur layer? webkit?
*/
class SK_API SkBlurDrawLooper : public SkDrawLooper {
public:
    enum BlurFlags {
        kNone_BlurFlag = 0x00,
        /**
            The blur layer's dx/dy/radius aren't affected by the canvas
            transform.
        */
        kIgnoreTransform_BlurFlag   = 0x01,
        kOverrideColor_BlurFlag     = 0x02,
        kHighQuality_BlurFlag       = 0x04,
        /** mask for all blur flags */
        kAll_BlurFlag = 0x07
    };

    SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, SkColor color,
                     uint32_t flags = kNone_BlurFlag);
    virtual ~SkBlurDrawLooper();

    // overrides from SkDrawLooper
    virtual void init(SkCanvas*);
    virtual bool next(SkCanvas*, SkPaint* paint);

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
        return SkNEW_ARGS(SkBlurDrawLooper, (buffer));
    }

protected:
    SkBlurDrawLooper(SkFlattenableReadBuffer&);
    // overrides from SkFlattenable
    virtual void flatten(SkFlattenableWriteBuffer& );
    virtual Factory getFactory() { return CreateProc; }

private:
    SkMaskFilter*   fBlur;
    SkColorFilter*  fColorFilter;
    SkScalar        fDx, fDy;
    SkColor         fBlurColor;
    uint32_t        fBlurFlags;

    enum State {
        kBeforeEdge,
        kAfterEdge,
        kDone
    };
    State   fState;

    typedef SkDrawLooper INHERITED;
};

#endif


code:
/* libs/graphics/effects/SkBlurMask.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#ifndef SkBlurMask_DEFINED
#define SkBlurMask_DEFINED

#include "SkShader.h"

class SkBlurMask {
public:
    enum Style {
        kNormal_Style,  //!< fuzzy inside and outside
        kSolid_Style,   //!< solid inside, fuzzy outside
        kOuter_Style,   //!< nothing inside, fuzzy outside
        kInner_Style,   //!< fuzzy inside, nothing outside

        kStyleCount
    };

    enum Quality {
        kLow_Quality,   //!< box blur
        kHigh_Quality   //!< three pass box blur (similar to gaussian)
    };

    static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style, Quality quality);
};

#endif


code:
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.
 */

#ifndef SkBlurMaskFilter_DEFINED
#define SkBlurMaskFilter_DEFINED

// we include this since our callers will need to at least be able to ref/unref
#include "SkMaskFilter.h"
#include "SkScalar.h"

class SK_API SkBlurMaskFilter {
public:
    enum BlurStyle {
        kNormal_BlurStyle,  //!< fuzzy inside and outside
        kSolid_BlurStyle,   //!< solid inside, fuzzy outside
        kOuter_BlurStyle,   //!< nothing inside, fuzzy outside
        kInner_BlurStyle,   //!< fuzzy inside, nothing outside

        kBlurStyleCount
    };

    enum BlurFlags {
        kNone_BlurFlag = 0x00,
        /** The blur layer's radius is not affected by transforms */
        kIgnoreTransform_BlurFlag   = 0x01,
        /** Use a smother, higher qulity blur algorithm */
        kHighQuality_BlurFlag       = 0x02,
        /** mask for all blur flags */
        kAll_BlurFlag = 0x03
    };

    /** Create a blur maskfilter.
        @param radius   The radius to extend the blur from the original mask. Must be > 0.
        @param style    The BlurStyle to use
        @param flags    Flags to use - defaults to none
        @return The new blur maskfilter
    */
    static SkMaskFilter* Create(SkScalar radius, BlurStyle style,
                                uint32_t flags = kNone_BlurFlag);

    /** Create an emboss maskfilter
        @param direction    array of 3 scalars [x, y, z] specifying the direction of the light source
        @param ambient      0...1 amount of ambient light
        @param specular     coefficient for specular highlights (e.g. 8)
        @param blurRadius   amount to blur before applying lighting (e.g. 3)
        @return the emboss maskfilter
    */
    static SkMaskFilter* CreateEmboss(  const SkScalar direction[3],
                                        SkScalar ambient, SkScalar specular,
                                        SkScalar blurRadius);

private:
    SkBlurMaskFilter(); // can't be instantiated
};

#endif


code:
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.
 */

#ifndef SkBorderView_DEFINED
#define SkBorderView_DEFINED

#include "SkView.h"
#include "SkWidgetViews.h"
#include "SkAnimator.h"

class SkBorderView : public SkWidgetView {
public:
    SkBorderView();
    ~SkBorderView();
    void setSkin(const char skin[]);
    SkScalar getLeft() const { return fLeft; }
    SkScalar getRight() const { return fRight; }
    SkScalar getTop() const { return fTop; }
    SkScalar getBottom() const { return fBottom; }
protected:
    //overrides
    virtual void onInflate(const SkDOM& dom,  const SkDOM::Node* node);
    virtual void onSizeChange();
    virtual void onDraw(SkCanvas* canvas);
    virtual bool onEvent(const SkEvent& evt);
private:
    SkAnimator fAnim;
    SkScalar fLeft, fRight, fTop, fBottom;  //margin on each side
    SkRect fMargin;

    typedef SkWidgetView INHERITED;
};

#endif


code:
/* libs/graphics/animator/SkBoundable.h
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/

#ifndef SkBoundable_DEFINED
#define SkBoundable_DEFINED

#include "SkDrawable.h"
#include "SkRect.h"

class SkBoundable : public SkDrawable {
public:
    SkBoundable();
    virtual void clearBounder();
    virtual void enableBounder();
    virtual void getBounds(SkRect* );
    bool hasBounds() { return fBounds.fLeft != (int16_t)0x8000U; }
    void setBounds(SkIRect& bounds) { fBounds = bounds; }
protected:
    void clearBounds() { fBounds.fLeft = (int16_t) SkToU16(0x8000); }; // mark bounds as unset
    SkIRect fBounds;
private:
    typedef SkDrawable INHERITED;
};

class SkBoundableAuto {
public:
    SkBoundableAuto(SkBoundable* boundable, SkAnimateMaker& maker);
    ~SkBoundableAuto();
private:
    SkBoundable* fBoundable;
    SkAnimateMaker& fMaker;
    SkBoundableAuto& operator= (const SkBoundableAuto& );
};

#endif // SkBoundable_DEFINED


code:
#ifndef SkBoundaryPatch_DEFINED
#define SkBoundaryPatch_DEFINED

#include "SkPoint.h"
#include "SkRefCnt.h"

class SkBoundary : public SkRefCnt {
public:
    // These must be 0, 1, 2, 3 for efficiency in the subclass implementations
    enum Edge {
        kTop    = 0,
        kRight  = 1,
        kBottom = 2,
        kLeft   = 3
    };
    // Edge index goes clockwise around the boundary, beginning at the "top"
    virtual SkPoint eval(Edge, SkScalar unitInterval) = 0;
};

class SkBoundaryPatch {
public:
    SkBoundaryPatch();
    ~SkBoundaryPatch();

    SkBoundary* getBoundary() const { return fBoundary; }
    SkBoundary* setBoundary(SkBoundary*);

    SkPoint eval(SkScalar unitU, SkScalar unitV);
    bool evalPatch(SkPoint verts[], int rows, int cols);

private:
    SkBoundary* fBoundary;
};

////////////////////////////////////////////////////////////////////////

class SkLineBoundary : public SkBoundary {
public:
    SkPoint fPts[4];

    // override
    virtual SkPoint eval(Edge, SkScalar);
};

class SkCubicBoundary : public SkBoundary {
public:
    // the caller sets the first 12 entries. The 13th is used by the impl.
    SkPoint fPts[13];

    // override
    virtual SkPoint eval(Edge, SkScalar);
};

#endif


code:
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.
 */

#ifndef SkBounder_DEFINED
#define SkBounder_DEFINED

#include "SkTypes.h"
#include "SkRefCnt.h"
#include "SkPoint.h"

struct SkGlyph;
struct SkIRect;
struct SkPoint;
struct SkRect;
class SkPaint;
class SkPath;
class SkRegion;

/** \class SkBounder

    Base class for intercepting the device bounds of shapes before they are drawn.
    Install a subclass of this in your canvas.
*/
class SkBounder : public SkRefCnt {
public:
    SkBounder();

    /* Call to perform a clip test before calling onIRect.
       Returns the result from onIRect.
    */
    bool doIRect(const SkIRect&);
    bool doIRectGlyph(const SkIRect& , int x, int y, const SkGlyph&);

protected:
    /** Override in your subclass. This is called with the device bounds of an
        object (text, geometry, image) just before it is drawn. If your method
        returns false, the drawing for that shape is aborted. If your method
        returns true, drawing continues. The bounds your method receives have already
        been transformed in to device coordinates, and clipped to the current clip.
    */
    virtual bool onIRect(const SkIRect&) {
        return false;
    }

    /** Passed to onIRectGlyph with the information about the current glyph.
        LSB and RSB are fixed-point (16.16) coordinates of the start and end
        of the glyph's advance
     */
    struct GlyphRec {
        SkIPoint    fLSB;   //!< fixed-point left-side-bearing of the glyph
        SkIPoint    fRSB;   //!< fixed-point right-side-bearing of the glyph
        uint16_t    fGlyphID;
        uint16_t    fFlags; //!< currently set to 0
    };

    /** Optionally, override in your subclass to receive the glyph ID when
        text drawing supplies the device bounds of the object.
    */
    virtual bool onIRectGlyph(const SkIRect& r, const GlyphRec&) {
        return onIRect(r);
    }

    /** Called after each shape has been drawn. The default implementation does
        nothing, but your override could use this notification to signal itself
        that the offscreen being rendered into needs to be updated to the screen.
    */
    virtual void commit();

private:
    bool doHairline(const SkPoint&, const SkPoint&, const SkPaint&);
    bool doRect(const SkRect&, const SkPaint&);
    bool doPath(const SkPath&, const SkPaint&, bool doFill);
    void setClip(const SkRegion* clip) { fClip = clip; }

    const SkRegion* fClip;
    friend class SkAutoBounderCommit;
    friend class SkDraw;
    friend class SkDrawIter;
    friend struct Draw1Glyph;
    friend class SkMaskFilter;
};

#endif


code:
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.
 */

#ifndef SkBuffer_DEFINED
#define SkBuffer_DEFINED

#include "SkScalar.h"

/** \class SkRBuffer

    Light weight class for reading data from a memory block.
    The RBuffer is given the buffer to read from, with either a specified size
    or no size (in which case no range checking is performed). It is iillegal
    to attempt to read a value from an empty RBuffer (data == null).
*/
class SkRBuffer : SkNoncopyable {
public:
    SkRBuffer() : fData(0), fPos(0), fStop(0) {}
    /** Initialize RBuffer with a data pointer, but no specified length.
        This signals the RBuffer to not perform range checks during reading.
    */
    SkRBuffer(const void* data) {
        fData = (const char*)data;
        fPos = (const char*)data;
        fStop = 0;  // no bounds checking
    }
    /** Initialize RBuffer with a data point and length.
    */
    SkRBuffer(const void* data, size_t size) {
        SkASSERT(data != 0 || size == 0);
        fData = (const char*)data;
        fPos = (const char*)data;
        fStop = (const char*)data + size;
    }

    /** Return the number of bytes that have been read from the beginning
        of the data pointer.
    */
    size_t  pos() const { return fPos - fData; }
    /** Return the total size of the data pointer. Only defined if the length was
        specified in the constructor or in a call to reset().
    */
    size_t  size() const { return fStop - fData; }
    /** Return true if the buffer has read to the end of the data pointer.
        Only defined if the length was specified in the constructor or in a call
        to reset(). Always returns true if the length was not specified.
    */
    bool    eof() const { return fPos >= fStop; }

    /** Read the specified number of bytes from the data pointer. If buffer is not
        null, copy those bytes into buffer.
    */
    void read(void* buffer, size_t size) {
        if (size) {
            this->readNoSizeCheck(buffer, size);
        }
    }

    const void* skip(size_t size); // return start of skipped data
    size_t  skipToAlign4();

    void*       readPtr() { void* ptr; read(&ptr, sizeof(ptr)); return ptr; }
    SkScalar    readScalar() { SkScalar x; read(&x, 4); return x; }
    uint32_t    readU32() { uint32_t x; read(&x, 4); return x; }
    int32_t     readS32() { int32_t x; read(&x, 4); return x; }
    uint16_t    readU16() { uint16_t x; read(&x, 2); return x; }
    int16_t     readS16() { int16_t x; read(&x, 2); return x; }
    uint8_t     readU8() { uint8_t x; read(&x, 1); return x; }
    bool        readBool() { return this->readU8() != 0; }

protected:
    void    readNoSizeCheck(void* buffer, size_t size);

    const char* fData;
    const char* fPos;
    const char* fStop;
};

/** \class SkWBuffer

    Light weight class for writing data to a memory block.
    The WBuffer is given the buffer to write into, with either a specified size
    or no size, in which case no range checking is performed. An empty WBuffer
    is legal, in which case no data is ever written, but the relative pos()
    is updated.
*/
class SkWBuffer : SkNoncopyable {
public:
    SkWBuffer() : fData(0), fPos(0), fStop(0) {}
    SkWBuffer(void* data) { reset(data); }
    SkWBuffer(void* data, size_t size) { reset(data, size); }

    void reset(void* data) {
        fData = (char*)data;
        fPos = (char*)data;
        fStop = 0;  // no bounds checking
    }

    void reset(void* data, size_t size) {
        SkASSERT(data != 0 || size == 0);
        fData = (char*)data;
        fPos = (char*)data;
        fStop = (char*)data + size;
    }

    size_t  pos() const { return fPos - fData; }
    void*   skip(size_t size); // return start of skipped data

    void write(const void* buffer, size_t size) {
        if (size) {
            this->writeNoSizeCheck(buffer, size);
        }
    }

    size_t  padToAlign4();

    void    writePtr(const void* x) { this->writeNoSizeCheck(&x, sizeof(x)); }
    void    writeScalar(SkScalar x) { this->writeNoSizeCheck(&x, 4); }
    void    write32(int32_t x) { this->writeNoSizeCheck(&x, 4); }
    void    write16(int16_t x) { this->writeNoSizeCheck(&x, 2); }
    void    write8(int8_t x) { this->writeNoSizeCheck(&x, 1); }
    void    writeBool(bool x) { this->write8(x); }

protected:
    void    writeNoSizeCheck(const void* buffer, size_t size);

    char* fData;
    char* fPos;
    char* fStop;
};

#endif


code:
#ifndef SkCGUtils_DEFINED
#define SkCGUtils_DEFINED

#include "SkTypes.h"

#ifdef SK_BUILD_FOR_MAC
#include <ApplicationServices/ApplicationServices.h>
#endif

#ifdef SK_BUILD_FOR_IOS
#include <CoreGraphics/CoreGraphics.h>
#endif

class SkBitmap;
class SkStream;

/**
 *  Create an imageref from the specified bitmap using the specified colorspace.
 *  If space is NULL, then CGColorSpaceCreateDeviceRGB() is used.
 */
CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
                                            CGColorSpaceRef space);

/**
 *  Create an imageref from the specified bitmap using the colorspace returned
 *  by CGColorSpaceCreateDeviceRGB()
 */
static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
    return SkCreateCGImageRefWithColorspace(bm, NULL);
}

/**
 *  Draw the bitmap into the specified CG context. The bitmap will be converted
 *  to a CGImage using the generic RGB colorspace. (x,y) specifies the position
 *  of the top-left corner of the bitmap. The bitmap is converted using the
 *  colorspace returned by CGColorSpaceCreateDeviceRGB()
 */
void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y);

bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output);

#endif


code:
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * 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.
 */

//  Inspired by Rob Johnson's most excellent QuickDraw GX sample code

#ifndef SkCamera_DEFINED
#define SkCamera_DEFINED

#include "Sk64.h"
#include "SkMatrix.h"

class SkCanvas;

#ifdef SK_SCALAR_IS_FIXED
    typedef SkFract SkUnitScalar;
    #define SK_UnitScalar1          SK_Fract1
    #define SkUnitScalarMul(a, b)   SkFractMul(a, b)
    #define SkUnitScalarDiv(a, b)   SkFractDiv(a, b)
#else
    typedef float   SkUnitScalar;
    #define SK_UnitScalar1          SK_Scalar1
    #define SkUnitScalarMul(a, b)   SkScalarMul(a, b)
    #define SkUnitScalarDiv(a, b)   SkScalarDiv(a, b)
#endif

struct SkUnit3D {
    SkUnitScalar    fX, fY, fZ;

    void set(SkUnitScalar x, SkUnitScalar y, SkUnitScalar z)
    {
        fX = x; fY = y; fZ = z;
    }
    static SkUnitScalar Dot(const SkUnit3D&, const SkUnit3D&);
    static void Cross(const SkUnit3D&, const SkUnit3D&, SkUnit3D* cross);
};

struct SkPoint3D {
    SkScalar    fX, fY, fZ;

    void set(SkScalar x, SkScalar y, SkScalar z)
    {
        fX = x; fY = y; fZ = z;
    }
    SkScalar    normalize(SkUnit3D*) const;
};
typedef SkPoint3D SkVector3D;

struct SkMatrix3D {
    SkScalar    fMat[3][4];

    void reset();

    void setRow(int row, SkScalar a, SkScalar b, SkScalar c, SkScalar d = 0)
    {
        SkASSERT((unsigned)row < 3);
        fMat[row][0] = a;
        fMat[row][1] = b;
        fMat[row][2] = c;
        fMat[row][3] = d;
    }

    void setRotateX(SkScalar deg);
    void setRotateY(SkScalar deg);
    void setRotateZ(SkScalar deg);
    void setTranslate(SkScalar x, SkScalar y, SkScalar z);

    void preRotateX(SkScalar deg);
    void preRotateY(SkScalar deg);
    void preRotateZ(SkScalar deg);
    void preTranslate(SkScalar x, SkScalar y, SkScalar z);

    void setConcat(const SkMatrix3D& a, const SkMatrix3D& b);
    void mapPoint(const SkPoint3D& src, SkPoint3D* dst) const;
    void mapVector(const SkVector3D& src, SkVector3D* dst) const;

    void mapPoint(SkPoint3D* v) const
    {
        this->mapPoint(*v, v);
    }
    void mapVector(SkVector3D* v) const
    {
        this->mapVector(*v, v);
    }
};

class SkPatch3D {
public:
    SkPatch3D();

    void    reset();
    void    transform(const SkMatrix3D&, SkPatch3D* dst = NULL) const;

    // dot a unit vector with the patch's normal
    SkScalar dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const;
    SkScalar dotWith(const SkVector3D& v) const
    {
        return this->dotWith(v.fX, v.fY, v.fZ);
    }

    // depreicated, but still here for animator (for now)
    void rotate(SkScalar x, SkScalar y, SkScalar z) {}
    void rotateDegrees(SkScalar x, SkScalar y, SkScalar z) {}

private:
public: // make public for SkDraw3D for now
    SkVector3D  fU, fV;
    SkPoint3D   fOrigin;

    friend class SkCamera3D;
};

class SkCamera3D {
public:
    SkCamera3D();

    void reset();
    void update();
    void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const;

    SkPoint3D   fLocation;
    SkPoint3D   fAxis;
    SkPoint3D   fZenith;
    SkPoint3D   fObserver;

private:
    mutable SkMatrix    fOrientation;
    mutable bool        fNeedToUpdate;

    void doUpdate() const;
};

class Sk3DView : SkNoncopyable {
public:
    Sk3DView();
    ~Sk3DView();

    void save();
    void restore();

    void translate(SkScalar x, SkScalar y, SkScalar z);
    void rotateX(SkScalar deg);
    void rotateY(SkScalar deg);
    void rotateZ(SkScalar deg);

#ifdef ANDROID
    void setCameraLocation(SkScalar x, SkScalar y, SkScalar z);
#endif

    void getMatrix(SkMatrix*) const;
    void applyToCanvas(SkCanvas*) const;

    SkScalar dotWithNormal(SkScalar dx, SkScalar dy, SkScalar dz) const;

private:
    struct Rec {
        Rec*        fNext;
        SkMatrix3D  fMatrix;
    };
    Rec*        fRec;
    Rec         fInitialRec;
    SkCamera3D  fCamera;
};

#endif