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#include "SkBitmapProcState.h"
9#include "SkBitmapProcState_filter.h"
10#include "SkColorPriv.h"
11#include "SkFilterProc.h"
12#include "SkPaint.h"
13#include "SkShader.h"   // for tilemodes
14
15// returns expanded * 5bits
16static inline uint32_t Filter_565_Expanded(unsigned x, unsigned y,
17                                           uint32_t a00, uint32_t a01,
18                                           uint32_t a10, uint32_t a11) {
19    SkASSERT((unsigned)x <= 0xF);
20    SkASSERT((unsigned)y <= 0xF);
21
22    a00 = SkExpand_rgb_16(a00);
23    a01 = SkExpand_rgb_16(a01);
24    a10 = SkExpand_rgb_16(a10);
25    a11 = SkExpand_rgb_16(a11);
26
27    int xy = x * y >> 3;
28    return  a00 * (32 - 2*y - 2*x + xy) +
29            a01 * (2*x - xy) +
30            a10 * (2*y - xy) +
31            a11 * xy;
32}
33
34// turn an expanded 565 * 5bits into SkPMColor
35// g:11 | r:10 | x:1 | b:10
36static inline SkPMColor SkExpanded_565_To_PMColor(uint32_t c) {
37    unsigned r = (c >> 13) & 0xFF;
38    unsigned g = (c >> 24);
39    unsigned b = (c >> 2) & 0xFF;
40    return SkPackARGB32(0xFF, r, g, b);
41}
42
43// returns answer in SkPMColor format
44static inline SkPMColor Filter_4444_D32(unsigned x, unsigned y,
45                                        uint32_t a00, uint32_t a01,
46                                        uint32_t a10, uint32_t a11) {
47    SkASSERT((unsigned)x <= 0xF);
48    SkASSERT((unsigned)y <= 0xF);
49
50    a00 = SkExpand_4444(a00);
51    a01 = SkExpand_4444(a01);
52    a10 = SkExpand_4444(a10);
53    a11 = SkExpand_4444(a11);
54
55    int xy = x * y >> 4;
56    uint32_t result =   a00 * (16 - y - x + xy) +
57                        a01 * (x - xy) +
58                        a10 * (y - xy) +
59                        a11 * xy;
60
61    return SkCompact_8888(result);
62}
63
64static inline U8CPU Filter_8(unsigned x, unsigned y,
65                             U8CPU a00, U8CPU a01,
66                             U8CPU a10, U8CPU a11) {
67    SkASSERT((unsigned)x <= 0xF);
68    SkASSERT((unsigned)y <= 0xF);
69
70    int xy = x * y;
71    unsigned result =   a00 * (256 - 16*y - 16*x + xy) +
72                        a01 * (16*x - xy) +
73                        a10 * (16*y - xy) +
74                        a11 * xy;
75
76    return result >> 8;
77}
78
79/*****************************************************************************
80 *
81 *  D32 functions
82 *
83 */
84
85// SRC == 8888
86
87#define FILTER_PROC(x, y, a, b, c, d, dst)   Filter_32_opaque(x, y, a, b, c, d, dst)
88
89#define MAKENAME(suffix)        S32_opaque_D32 ## suffix
90#define DSTSIZE                 32
91#define SRCTYPE                 SkPMColor
92#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
93                                SkASSERT(state.fAlphaScale == 256)
94#define RETURNDST(src)          src
95#define SRC_TO_FILTER(src)      src
96#include "SkBitmapProcState_sample.h"
97
98#undef FILTER_PROC
99#define FILTER_PROC(x, y, a, b, c, d, dst)   Filter_32_alpha(x, y, a, b, c, d, dst, alphaScale)
100
101#define MAKENAME(suffix)        S32_alpha_D32 ## suffix
102#define DSTSIZE                 32
103#define SRCTYPE                 SkPMColor
104#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
105                                SkASSERT(state.fAlphaScale < 256)
106#define PREAMBLE(state)         unsigned alphaScale = state.fAlphaScale
107#define RETURNDST(src)          SkAlphaMulQ(src, alphaScale)
108#define SRC_TO_FILTER(src)      src
109#include "SkBitmapProcState_sample.h"
110
111// SRC == 565
112
113#undef FILTER_PROC
114#define FILTER_PROC(x, y, a, b, c, d, dst) \
115    do {                                                        \
116        uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d);   \
117        *(dst) = SkExpanded_565_To_PMColor(tmp);                \
118    } while (0)
119
120#define MAKENAME(suffix)        S16_opaque_D32 ## suffix
121#define DSTSIZE                 32
122#define SRCTYPE                 uint16_t
123#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
124                                SkASSERT(state.fAlphaScale == 256)
125#define RETURNDST(src)          SkPixel16ToPixel32(src)
126#define SRC_TO_FILTER(src)      src
127#include "SkBitmapProcState_sample.h"
128
129#undef FILTER_PROC
130#define FILTER_PROC(x, y, a, b, c, d, dst) \
131    do {                                                                    \
132        uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d);               \
133        *(dst) = SkAlphaMulQ(SkExpanded_565_To_PMColor(tmp), alphaScale);   \
134    } while (0)
135
136#define MAKENAME(suffix)        S16_alpha_D32 ## suffix
137#define DSTSIZE                 32
138#define SRCTYPE                 uint16_t
139#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config); \
140                                SkASSERT(state.fAlphaScale < 256)
141#define PREAMBLE(state)         unsigned alphaScale = state.fAlphaScale
142#define RETURNDST(src)          SkAlphaMulQ(SkPixel16ToPixel32(src), alphaScale)
143#define SRC_TO_FILTER(src)      src
144#include "SkBitmapProcState_sample.h"
145
146// SRC == Index8
147
148#undef FILTER_PROC
149#define FILTER_PROC(x, y, a, b, c, d, dst)   Filter_32_opaque(x, y, a, b, c, d, dst)
150
151#define MAKENAME(suffix)        SI8_opaque_D32 ## suffix
152#define DSTSIZE                 32
153#define SRCTYPE                 uint8_t
154#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
155                                SkASSERT(state.fAlphaScale == 256)
156#define PREAMBLE(state)         const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
157#define RETURNDST(src)          table[src]
158#define SRC_TO_FILTER(src)      table[src]
159#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
160#include "SkBitmapProcState_sample.h"
161
162#undef FILTER_PROC
163#define FILTER_PROC(x, y, a, b, c, d, dst)   Filter_32_alpha(x, y, a, b, c, d, dst, alphaScale)
164
165#define MAKENAME(suffix)        SI8_alpha_D32 ## suffix
166#define DSTSIZE                 32
167#define SRCTYPE                 uint8_t
168#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
169                                SkASSERT(state.fAlphaScale < 256)
170#define PREAMBLE(state)         unsigned alphaScale = state.fAlphaScale; \
171                                const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
172#define RETURNDST(src)          SkAlphaMulQ(table[src], alphaScale)
173#define SRC_TO_FILTER(src)      table[src]
174#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
175#include "SkBitmapProcState_sample.h"
176
177// SRC == 4444
178
179#undef FILTER_PROC
180#define FILTER_PROC(x, y, a, b, c, d, dst)  *(dst) = Filter_4444_D32(x, y, a, b, c, d)
181
182#define MAKENAME(suffix)        S4444_opaque_D32 ## suffix
183#define DSTSIZE                 32
184#define SRCTYPE                 SkPMColor16
185#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
186                                SkASSERT(state.fAlphaScale == 256)
187#define RETURNDST(src)          SkPixel4444ToPixel32(src)
188#define SRC_TO_FILTER(src)      src
189#include "SkBitmapProcState_sample.h"
190
191#undef FILTER_PROC
192#define FILTER_PROC(x, y, a, b, c, d, dst)  \
193    do {                                                    \
194        uint32_t tmp = Filter_4444_D32(x, y, a, b, c, d);   \
195        *(dst) = SkAlphaMulQ(tmp, alphaScale);              \
196    } while (0)
197
198#define MAKENAME(suffix)        S4444_alpha_D32 ## suffix
199#define DSTSIZE                 32
200#define SRCTYPE                 SkPMColor16
201#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_4444_Config); \
202                                SkASSERT(state.fAlphaScale < 256)
203#define PREAMBLE(state)         unsigned alphaScale = state.fAlphaScale
204#define RETURNDST(src)          SkAlphaMulQ(SkPixel4444ToPixel32(src), alphaScale)
205#define SRC_TO_FILTER(src)      src
206#include "SkBitmapProcState_sample.h"
207
208// SRC == A8
209
210#undef FILTER_PROC
211#define FILTER_PROC(x, y, a, b, c, d, dst) \
212    do {                                                        \
213        unsigned tmp = Filter_8(x, y, a, b, c, d);              \
214        *(dst) = SkAlphaMulQ(pmColor, SkAlpha255To256(tmp));    \
215    } while (0)
216
217#define MAKENAME(suffix)        SA8_alpha_D32 ## suffix
218#define DSTSIZE                 32
219#define SRCTYPE                 uint8_t
220#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kA8_Config); \
221                                SkASSERT(state.fAlphaScale == 256)
222#define PREAMBLE(state)         const SkPMColor pmColor = state.fPaintPMColor;
223#define RETURNDST(src)          SkAlphaMulQ(pmColor, SkAlpha255To256(src))
224#define SRC_TO_FILTER(src)      src
225#include "SkBitmapProcState_sample.h"
226
227/*****************************************************************************
228 *
229 *  D16 functions
230 *
231 */
232
233// SRC == 8888
234
235#undef FILTER_PROC
236#define FILTER_PROC(x, y, a, b, c, d, dst) \
237    do {                                                \
238        SkPMColor dstColor;                             \
239        Filter_32_opaque(x, y, a, b, c, d, &dstColor);  \
240        (*dst) = SkPixel32ToPixel16(dstColor);          \
241    } while (0)
242
243#define MAKENAME(suffix)        S32_D16 ## suffix
244#define DSTSIZE                 16
245#define SRCTYPE                 SkPMColor
246#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kARGB_8888_Config); \
247                                SkASSERT(state.fBitmap->isOpaque())
248#define RETURNDST(src)          SkPixel32ToPixel16(src)
249#define SRC_TO_FILTER(src)      src
250#include "SkBitmapProcState_sample.h"
251
252// SRC == 565
253
254#undef FILTER_PROC
255#define FILTER_PROC(x, y, a, b, c, d, dst) \
256    do {                                                        \
257        uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d);   \
258        *(dst) = SkCompact_rgb_16((tmp) >> 5);                  \
259    } while (0)
260
261#define MAKENAME(suffix)        S16_D16 ## suffix
262#define DSTSIZE                 16
263#define SRCTYPE                 uint16_t
264#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
265#define RETURNDST(src)          src
266#define SRC_TO_FILTER(src)      src
267#include "SkBitmapProcState_sample.h"
268
269// SRC == Index8
270
271#undef FILTER_PROC
272#define FILTER_PROC(x, y, a, b, c, d, dst) \
273    do {                                                        \
274        uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d);   \
275        *(dst) = SkCompact_rgb_16((tmp) >> 5);                  \
276    } while (0)
277
278#define MAKENAME(suffix)        SI8_D16 ## suffix
279#define DSTSIZE                 16
280#define SRCTYPE                 uint8_t
281#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config); \
282                                SkASSERT(state.fBitmap->isOpaque())
283#define PREAMBLE(state)         const uint16_t* SK_RESTRICT table = state.fBitmap->getColorTable()->lock16BitCache()
284#define RETURNDST(src)          table[src]
285#define SRC_TO_FILTER(src)      table[src]
286#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlock16BitCache()
287#include "SkBitmapProcState_sample.h"
288
289///////////////////////////////////////////////////////////////////////////////
290
291#undef FILTER_PROC
292#define FILTER_PROC(x, y, a, b, c, d, dst) \
293    do {                                                        \
294        uint32_t tmp = Filter_565_Expanded(x, y, a, b, c, d);   \
295        *(dst) = SkCompact_rgb_16((tmp) >> 5);                  \
296    } while (0)
297
298
299// clamp
300
301#define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)
302#define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)
303#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
304#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
305
306#define MAKENAME(suffix)        Clamp_S16_D16 ## suffix
307#define SRCTYPE                 uint16_t
308#define DSTTYPE                 uint16_t
309#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
310#define SRC_TO_FILTER(src)      src
311#include "SkBitmapProcState_shaderproc.h"
312
313
314#define TILEX_PROCF(fx, max)    (((fx) & 0xFFFF) * ((max) + 1) >> 16)
315#define TILEY_PROCF(fy, max)    (((fy) & 0xFFFF) * ((max) + 1) >> 16)
316#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
317#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
318
319#define MAKENAME(suffix)        Repeat_S16_D16 ## suffix
320#define SRCTYPE                 uint16_t
321#define DSTTYPE                 uint16_t
322#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
323#define SRC_TO_FILTER(src)      src
324#include "SkBitmapProcState_shaderproc.h"
325
326
327#define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)
328#define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)
329#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
330#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
331
332#undef FILTER_PROC
333#define FILTER_PROC(x, y, a, b, c, d, dst)   Filter_32_opaque(x, y, a, b, c, d, dst)
334#define MAKENAME(suffix)        Clamp_SI8_opaque_D32 ## suffix
335#define SRCTYPE                 uint8_t
336#define DSTTYPE                 uint32_t
337#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kIndex8_Config)
338#define PREAMBLE(state)         const SkPMColor* SK_RESTRICT table = state.fBitmap->getColorTable()->lockColors()
339#define SRC_TO_FILTER(src)      table[src]
340#define POSTAMBLE(state)        state.fBitmap->getColorTable()->unlockColors(false)
341#include "SkBitmapProcState_shaderproc.h"
342
343///////////////////////////////////////////////////////////////////////////////
344
345static bool valid_for_filtering(unsigned dimension) {
346    // for filtering, width and height must fit in 14bits, since we use steal
347    // 2 bits from each to store our 4bit subpixel data
348    return (dimension & ~0x3FFF) == 0;
349}
350
351bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
352    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
353        return false;
354    }
355
356    const SkMatrix* m;
357    bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
358    bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
359                       SkShader::kClamp_TileMode == fTileModeY;
360
361    if (clamp_clamp || trivial_matrix) {
362        m = &inv;
363    } else {
364        fUnitInvMatrix = inv;
365        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
366        m = &fUnitInvMatrix;
367    }
368
369    fBitmap = &fOrigBitmap;
370    if (fOrigBitmap.hasMipMap()) {
371        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
372                                                SkScalarToFixed(m->getScaleX()),
373                                                SkScalarToFixed(m->getSkewY()));
374
375        if (shift > 0) {
376            if (m != &fUnitInvMatrix) {
377                fUnitInvMatrix = *m;
378                m = &fUnitInvMatrix;
379            }
380
381            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
382            fUnitInvMatrix.postScale(scale, scale);
383
384            // now point here instead of fOrigBitmap
385            fBitmap = &fMipBitmap;
386        }
387    }
388
389    fInvMatrix      = m;
390    fInvProc        = m->getMapXYProc();
391    fInvType        = m->getType();
392    fInvSx          = SkScalarToFixed(m->getScaleX());
393    fInvKy          = SkScalarToFixed(m->getSkewY());
394
395    fAlphaScale = SkAlpha255To256(paint.getAlpha());
396
397    // pick-up filtering from the paint, but only if the matrix is
398    // more complex than identity/translate (i.e. no need to pay the cost
399    // of filtering if we're not scaled etc.).
400    // note: we explicitly check inv, since m might be scaled due to unitinv
401    //       trickery, but we don't want to see that for this test
402    fDoFilter = paint.isFilterBitmap() &&
403                (inv.getType() > SkMatrix::kTranslate_Mask &&
404                 valid_for_filtering(fBitmap->width() | fBitmap->height()));
405
406    fShaderProc32 = NULL;
407    fShaderProc16 = NULL;
408    fSampleProc32 = NULL;
409    fSampleProc16 = NULL;
410
411    fMatrixProc = this->chooseMatrixProc(trivial_matrix);
412    if (NULL == fMatrixProc) {
413        return false;
414    }
415
416    ///////////////////////////////////////////////////////////////////////
417
418    int index = 0;
419    if (fAlphaScale < 256) {  // note: this distinction is not used for D16
420        index |= 1;
421    }
422    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
423        index |= 2;
424    }
425    if (fDoFilter) {
426        index |= 4;
427    }
428    // bits 3,4,5 encoding the source bitmap format
429    switch (fBitmap->config()) {
430        case SkBitmap::kARGB_8888_Config:
431            index |= 0;
432            break;
433        case SkBitmap::kRGB_565_Config:
434            index |= 8;
435            break;
436        case SkBitmap::kIndex8_Config:
437            index |= 16;
438            break;
439        case SkBitmap::kARGB_4444_Config:
440            index |= 24;
441            break;
442        case SkBitmap::kA8_Config:
443            index |= 32;
444            fPaintPMColor = SkPreMultiplyColor(paint.getColor());
445            break;
446        default:
447            return false;
448    }
449
450    static const SampleProc32 gSample32[] = {
451        S32_opaque_D32_nofilter_DXDY,
452        S32_alpha_D32_nofilter_DXDY,
453        S32_opaque_D32_nofilter_DX,
454        S32_alpha_D32_nofilter_DX,
455        S32_opaque_D32_filter_DXDY,
456        S32_alpha_D32_filter_DXDY,
457        S32_opaque_D32_filter_DX,
458        S32_alpha_D32_filter_DX,
459
460        S16_opaque_D32_nofilter_DXDY,
461        S16_alpha_D32_nofilter_DXDY,
462        S16_opaque_D32_nofilter_DX,
463        S16_alpha_D32_nofilter_DX,
464        S16_opaque_D32_filter_DXDY,
465        S16_alpha_D32_filter_DXDY,
466        S16_opaque_D32_filter_DX,
467        S16_alpha_D32_filter_DX,
468
469        SI8_opaque_D32_nofilter_DXDY,
470        SI8_alpha_D32_nofilter_DXDY,
471        SI8_opaque_D32_nofilter_DX,
472        SI8_alpha_D32_nofilter_DX,
473        SI8_opaque_D32_filter_DXDY,
474        SI8_alpha_D32_filter_DXDY,
475        SI8_opaque_D32_filter_DX,
476        SI8_alpha_D32_filter_DX,
477
478        S4444_opaque_D32_nofilter_DXDY,
479        S4444_alpha_D32_nofilter_DXDY,
480        S4444_opaque_D32_nofilter_DX,
481        S4444_alpha_D32_nofilter_DX,
482        S4444_opaque_D32_filter_DXDY,
483        S4444_alpha_D32_filter_DXDY,
484        S4444_opaque_D32_filter_DX,
485        S4444_alpha_D32_filter_DX,
486
487        // A8 treats alpha/opauqe the same (equally efficient)
488        SA8_alpha_D32_nofilter_DXDY,
489        SA8_alpha_D32_nofilter_DXDY,
490        SA8_alpha_D32_nofilter_DX,
491        SA8_alpha_D32_nofilter_DX,
492        SA8_alpha_D32_filter_DXDY,
493        SA8_alpha_D32_filter_DXDY,
494        SA8_alpha_D32_filter_DX,
495        SA8_alpha_D32_filter_DX
496    };
497
498    static const SampleProc16 gSample16[] = {
499        S32_D16_nofilter_DXDY,
500        S32_D16_nofilter_DX,
501        S32_D16_filter_DXDY,
502        S32_D16_filter_DX,
503
504        S16_D16_nofilter_DXDY,
505        S16_D16_nofilter_DX,
506        S16_D16_filter_DXDY,
507        S16_D16_filter_DX,
508
509        SI8_D16_nofilter_DXDY,
510        SI8_D16_nofilter_DX,
511        SI8_D16_filter_DXDY,
512        SI8_D16_filter_DX,
513
514        // Don't support 4444 -> 565
515        NULL, NULL, NULL, NULL,
516        // Don't support A8 -> 565
517        NULL, NULL, NULL, NULL
518    };
519
520    fSampleProc32 = gSample32[index];
521    index >>= 1;    // shift away any opaque/alpha distinction
522    fSampleProc16 = gSample16[index];
523
524    // our special-case shaderprocs
525    if (S16_D16_filter_DX == fSampleProc16) {
526        if (clamp_clamp) {
527            fShaderProc16 = Clamp_S16_D16_filter_DX_shaderproc;
528        } else if (SkShader::kRepeat_TileMode == fTileModeX &&
529                   SkShader::kRepeat_TileMode == fTileModeY) {
530            fShaderProc16 = Repeat_S16_D16_filter_DX_shaderproc;
531        }
532    } else if (SI8_opaque_D32_filter_DX == fSampleProc32 && clamp_clamp) {
533        fShaderProc32 = Clamp_SI8_opaque_D32_filter_DX_shaderproc;
534    }
535
536    // see if our platform has any accelerated overrides
537    this->platformProcs();
538    return true;
539}
540
541///////////////////////////////////////////////////////////////////////////////
542/*
543    The storage requirements for the different matrix procs are as follows,
544    where each X or Y is 2 bytes, and N is the number of pixels/elements:
545
546    scale/translate     nofilter      Y(4bytes) + N * X
547    affine/perspective  nofilter      N * (X Y)
548    scale/translate     filter        Y Y + N * (X X)
549    affine/perspective  filter        N * (Y Y X X)
550 */
551int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
552    int32_t size = static_cast<int32_t>(bufferSize);
553
554    size &= ~3; // only care about 4-byte aligned chunks
555    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
556        size -= 4;   // the shared Y (or YY) coordinate
557        if (size < 0) {
558            size = 0;
559        }
560        size >>= 1;
561    } else {
562        size >>= 2;
563    }
564
565    if (fDoFilter) {
566        size >>= 1;
567    }
568
569    return size;
570}
571
572