1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9class ARGB32_Clamp_Bilinear_BitmapShader : public SkBitmapShader {
10public:
11    ARGB32_Clamp_Bilinear_BitmapShader(const SkBitmap& src)
12        : SkBitmapShader(src, true,
13                         SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)
14    {}
15
16    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
17};
18
19SkPMColor sample_bilerp(SkFixed fx, SkFixed fy, unsigned srcMaxX, unsigned srcMaxY,
20                        const SkPMColor* srcPixels, int srcRB, const SkFilterPtrProc* proc_table);
21SkPMColor sample_bilerp(SkFixed fx, SkFixed fy, unsigned srcMaxX, unsigned srcMaxY,
22                        const SkPMColor* srcPixels, int srcRB, const SkFilterPtrProc* proc_table)
23{
24    int ix = fx >> 16;
25    int iy = fy >> 16;
26
27    const SkPMColor *p00, *p01, *p10, *p11;
28
29    p00 = p01 = ((const SkPMColor*)((const char*)srcPixels
30                                    + SkClampMax(iy, srcMaxY) * srcRB))
31                                    + SkClampMax(ix, srcMaxX);
32
33    if ((unsigned)ix < srcMaxX)
34        p01 += 1;
35    p10 = p00;
36    p11 = p01;
37    if ((unsigned)iy < srcMaxY)
38    {
39        p10 = (const SkPMColor*)((const char*)p10 + srcRB);
40        p11 = (const SkPMColor*)((const char*)p11 + srcRB);
41    }
42
43    SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(proc_table, fx, fy);
44    return proc(p00, p01, p10, p11);
45}
46
47static inline SkPMColor sample_bilerpx(SkFixed fx, unsigned srcMaxX, const SkPMColor* srcPixels,
48                                       int srcRB, const SkFilterPtrProc* proc_table)
49{
50    int ix = fx >> 16;
51
52    const SkPMColor *p00, *p01, *p10, *p11;
53
54    p00 = p01 = srcPixels + SkClampMax(ix, srcMaxX);
55    if ((unsigned)ix < srcMaxX)
56        p01 += 1;
57
58    p10 = (const SkPMColor*)((const char*)p00 + srcRB);
59    p11 = (const SkPMColor*)((const char*)p01 + srcRB);
60
61    SkFilterPtrProc proc = SkGetBilinearFilterPtrXProc(proc_table, fx);
62    return proc(p00, p01, p10, p11);
63}
64
65void ARGB32_Clamp_Bilinear_BitmapShader::shadeSpan(int x, int y, SkPMColor dstC[], int count)
66{
67    SkASSERT(count > 0);
68
69    unsigned srcScale = SkAlpha255To256(this->getPaintAlpha());
70
71    const SkMatrix& inv = this->getTotalInverse();
72    const SkBitmap& srcBitmap = this->getSrcBitmap();
73    unsigned        srcMaxX = srcBitmap.width() - 1;
74    unsigned        srcMaxY = srcBitmap.height() - 1;
75    unsigned        srcRB = srcBitmap.rowBytes();
76
77    const SkFilterPtrProc* proc_table = SkGetBilinearFilterPtrProcTable();
78    const SkPMColor* srcPixels = (const SkPMColor*)srcBitmap.getPixels();
79
80    if (this->getInverseClass() == kPerspective_MatrixClass)
81    {
82        SkPerspIter   iter(inv, SkIntToScalar(x) + SK_ScalarHalf,
83                                SkIntToScalar(y) + SK_ScalarHalf, count);
84
85        if (256 == srcScale)
86        {
87            while ((count = iter.next()) != 0)
88            {
89                const SkFixed* srcXY = iter.getXY();
90                while (--count >= 0)
91                {
92                    SkFixed fx = *srcXY++ - SK_FixedHalf;
93                    SkFixed fy = *srcXY++ - SK_FixedHalf;
94                    *dstC++ = sample_bilerp(fx, fy, srcMaxX, srcMaxY, srcPixels, srcRB, proc_table);
95                }
96            }
97        }
98        else    // scale by srcScale
99        {
100            while ((count = iter.next()) != 0)
101            {
102                const SkFixed* srcXY = iter.getXY();
103                while (--count >= 0)
104                {
105                    SkFixed fx = *srcXY++ - SK_FixedHalf;
106                    SkFixed fy = *srcXY++ - SK_FixedHalf;
107                    SkPMColor c = sample_bilerp(fx, fy, srcMaxX, srcMaxY, srcPixels, srcRB, proc_table);
108                    *dstC++ = SkAlphaMulQ(c, srcScale);
109                }
110            }
111        }
112    }
113    else    // linear case
114    {
115        SkFixed fx, fy, dx, dy;
116
117        // now init fx, fy, dx, dy
118        {
119            SkPoint srcPt;
120            this->getInverseMapPtProc()(inv, SkIntToScalar(x) + SK_ScalarHalf,
121                                             SkIntToScalar(y) + SK_ScalarHalf,
122                                             &srcPt);
123
124            fx = SkScalarToFixed(srcPt.fX) - SK_FixedHalf;
125            fy = SkScalarToFixed(srcPt.fY) - SK_FixedHalf;
126
127            if (this->getInverseClass() == kFixedStepInX_MatrixClass)
128                (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
129            else
130            {
131                dx = SkScalarToFixed(inv.getScaleX());
132                dy = SkScalarToFixed(inv.getSkewY());
133            }
134        }
135
136        if (dy == 0 && (unsigned)(fy >> 16) < srcMaxY)
137        {
138            srcPixels = (const SkPMColor*)((const char*)srcPixels + (fy >> 16) * srcRB);
139            proc_table = SkGetBilinearFilterPtrProcYTable(proc_table, fy);
140            if (256 == srcScale)
141            {
142                do {
143                    *dstC++ = sample_bilerpx(fx, srcMaxX, srcPixels, srcRB, proc_table);
144                    fx += dx;
145                } while (--count != 0);
146            }
147            else
148            {
149                do {
150                    SkPMColor c = sample_bilerpx(fx, srcMaxX, srcPixels, srcRB, proc_table);
151                    *dstC++ = SkAlphaMulQ(c, srcScale);
152                    fx += dx;
153                } while (--count != 0);
154            }
155        }
156        else    // dy is != 0
157        {
158            if (256 == srcScale)
159            {
160                do {
161                    *dstC++ = sample_bilerp(fx, fy, srcMaxX, srcMaxY, srcPixels, srcRB, proc_table);
162                    fx += dx;
163                    fy += dy;
164                } while (--count != 0);
165            }
166            else
167            {
168                do {
169                    SkPMColor c = sample_bilerp(fx, fy, srcMaxX, srcMaxY, srcPixels, srcRB, proc_table);
170                    *dstC++ = SkAlphaMulQ(c, srcScale);
171                    fx += dx;
172                    fy += dy;
173                } while (--count != 0);
174            }
175        }
176    }
177}
178