1fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com/* NEON optimized code (C) COPYRIGHT 2009 Motorola
26c5bf8d9fe6fe263f583a4c22d04e3be879ecfebcaryclark@google.com *
36c5bf8d9fe6fe263f583a4c22d04e3be879ecfebcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
46c5bf8d9fe6fe263f583a4c22d04e3be879ecfebcaryclark@google.com * found in the LICENSE file.
56c5bf8d9fe6fe263f583a4c22d04e3be879ecfebcaryclark@google.com */
6ed881c2704bc81fe46a68c0cf9e292287313baa6reed@android.com
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmapProcState.h"
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPerspIter.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkShader.h"
1007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#include "SkUtils.h"
11fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#include "SkUtilsArm.h"
12a8c09668f9e602f77422a344dfa4d13155c91fd3commit-bot@chromium.org#include "SkBitmapProcState_utils.h"
1399c114e0ac732ba01705e24d12f5e4dd7e144abdreed@google.com
1407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com/*  returns 0...(n-1) given any x (positive or negative).
15fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    As an example, if n (which is always positive) is 5...
17fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com          x: -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8
1907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    returns:  2  3  4  0  1  2  3  4  0  1  2  3  4  0  1  2  3
2007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com */
2107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic inline int sk_int_mod(int x, int n) {
2207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkASSERT(n > 0);
2307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if ((unsigned)x >= (unsigned)n) {
2407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (x < 0) {
2507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            x = n + ~(~x % n);
2607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        } else {
2707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            x = x % n;
2807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
2907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
3007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return x;
3107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com#include "SkBitmapProcState_matrix_template.h"
37d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
38d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com///////////////////////////////////////////////////////////////////////////////
39d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
40fce02aca62525c3041226501574f740f7ea3714bdigit@google.com// Compile neon code paths if needed
41fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#if !SK_ARM_NEON_IS_NONE
42fce02aca62525c3041226501574f740f7ea3714bdigit@google.com
43fce02aca62525c3041226501574f740f7ea3714bdigit@google.com// These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp
44fce02aca62525c3041226501574f740f7ea3714bdigit@google.comextern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[];
45fce02aca62525c3041226501574f740f7ea3714bdigit@google.comextern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
46fce02aca62525c3041226501574f740f7ea3714bdigit@google.com
47fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#endif // !SK_ARM_NEON_IS_NONE
48fce02aca62525c3041226501574f740f7ea3714bdigit@google.com
49fce02aca62525c3041226501574f740f7ea3714bdigit@google.com// Compile non-neon code path if needed
50fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#if !SK_ARM_NEON_IS_ALWAYS
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAKENAME(suffix)        ClampX_ClampY ## suffix
52c1992933f1d97edd3f2f4c7dcbd81ffea6f6c1d8reed@google.com#define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)
53c1992933f1d97edd3f2f4c7dcbd81ffea6f6c1d8reed@google.com#define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define CHECK_FOR_DECAL
57fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#include "SkBitmapProcState_matrix.h"
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
59d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstruct ClampTileProcs {
60d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
61d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SkClampMax(fx >> 16, max);
62d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
63d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
64d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SkClampMax(fy >> 16, max);
65d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
66d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
67d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
688c4953c6f176469ad287c3270ab146e292b23badcommit-bot@chromium.org// Referenced in opts_check_x86.cpp
69d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comvoid ClampX_ClampY_nofilter_scale(const SkBitmapProcState& s, uint32_t xy[],
70d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com                                  int count, int x, int y) {
71d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    return NoFilterProc_Scale<ClampTileProcs, true>(s, xy, count, x, y);
72d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com}
73d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comvoid ClampX_ClampY_nofilter_affine(const SkBitmapProcState& s, uint32_t xy[],
74d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com                                  int count, int x, int y) {
75d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    return NoFilterProc_Affine<ClampTileProcs>(s, xy, count, x, y);
76d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com}
77d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
78d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic SkBitmapProcState::MatrixProc ClampX_ClampY_Procs[] = {
79d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    // only clamp lives in the right coord space to check for decal
80d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    ClampX_ClampY_nofilter_scale,
81d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    ClampX_ClampY_filter_scale,
82d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    ClampX_ClampY_nofilter_affine,
83d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    ClampX_ClampY_filter_affine,
84d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Persp<ClampTileProcs>,
85d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    ClampX_ClampY_filter_persp
86d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
87d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAKENAME(suffix)        RepeatX_RepeatY ## suffix
8999c114e0ac732ba01705e24d12f5e4dd7e144abdreed@google.com#define TILEX_PROCF(fx, max)    SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1))
9099c114e0ac732ba01705e24d12f5e4dd7e144abdreed@google.com#define TILEY_PROCF(fy, max)    SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1))
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
93fce02aca62525c3041226501574f740f7ea3714bdigit@google.com#include "SkBitmapProcState_matrix.h"
94d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
95d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstruct RepeatTileProcs {
96d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned X(const SkBitmapProcState&, SkFixed fx, int max) {
97d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1));
98d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
99d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned Y(const SkBitmapProcState&, SkFixed fy, int max) {
100d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1));
101d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
102d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
103d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
104d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs[] = {
105d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Scale<RepeatTileProcs, false>,
106d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    RepeatX_RepeatY_filter_scale,
107d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Affine<RepeatTileProcs>,
108d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    RepeatX_RepeatY_filter_affine,
109d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Persp<RepeatTileProcs>,
110d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    RepeatX_RepeatY_filter_persp
111d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
112ed881c2704bc81fe46a68c0cf9e292287313baa6reed@android.com#endif
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAKENAME(suffix)        GeneralXY ## suffix
11505af1afd429808913683da75644e48bece12e820humper@google.com#define PREAMBLE(state)         SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; (void) tileProcX; \
11605af1afd429808913683da75644e48bece12e820humper@google.com                                SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; (void) tileProcY; \
11705af1afd429808913683da75644e48bece12e820humper@google.com                                SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX = (state).fTileLowBitsProcX; (void) tileLowBitsProcX; \
11805af1afd429808913683da75644e48bece12e820humper@google.com                                SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY = (state).fTileLowBitsProcY; (void) tileLowBitsProcY
119f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define PREAMBLE_PARAM_X        , SkBitmapProcState::FixedTileProc tileProcX, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX
120f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define PREAMBLE_PARAM_Y        , SkBitmapProcState::FixedTileProc tileProcY, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY
121f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define PREAMBLE_ARG_X          , tileProcX, tileLowBitsProcX
122f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define PREAMBLE_ARG_Y          , tileProcY, tileLowBitsProcY
12399c114e0ac732ba01705e24d12f5e4dd7e144abdreed@google.com#define TILEX_PROCF(fx, max)    SK_USHIFT16(tileProcX(fx) * ((max) + 1))
12499c114e0ac732ba01705e24d12f5e4dd7e144abdreed@google.com#define TILEY_PROCF(fy, max)    SK_USHIFT16(tileProcY(fy) * ((max) + 1))
125f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define TILEX_LOW_BITS(fx, max) tileLowBitsProcX(fx, (max) + 1)
126f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com#define TILEY_LOW_BITS(fy, max) tileLowBitsProcY(fy, (max) + 1)
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmapProcState_matrix.h"
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
129d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstruct GeneralTileProcs {
130d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned X(const SkBitmapProcState& s, SkFixed fx, int max) {
131d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SK_USHIFT16(s.fTileProcX(fx) * ((max) + 1));
132d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
133d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    static unsigned Y(const SkBitmapProcState& s, SkFixed fy, int max) {
134d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com        return SK_USHIFT16(s.fTileProcY(fy) * ((max) + 1));
135d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
136d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
137d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
138d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic SkBitmapProcState::MatrixProc GeneralXY_Procs[] = {
139d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Scale<GeneralTileProcs, false>,
140d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    GeneralXY_filter_scale,
141d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Affine<GeneralTileProcs>,
142d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    GeneralXY_filter_affine,
143d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    NoFilterProc_Persp<GeneralTileProcs>,
144d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    GeneralXY_filter_persp
145d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com};
146d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
147d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com///////////////////////////////////////////////////////////////////////////////
148d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com
149d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic inline U16CPU fixed_clamp(SkFixed x) {
15038bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    if (x < 0) {
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x = 0;
15238bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    }
15338bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    if (x >> 16) {
154cc0c8e6084e140c962ae9a6885992bafea8ec048reed@google.com        x = 0xFFFF;
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return x;
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
159d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic inline U16CPU fixed_repeat(SkFixed x) {
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return x & 0xFFFF;
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
163a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
164a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com// See http://code.google.com/p/skia/issues/detail?id=472
165a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600)
166a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#pragma optimize("", off)
167a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#endif
168a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com
169d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic inline U16CPU fixed_mirror(SkFixed x) {
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed s = x << 15 >> 31;
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (x ^ s) & 0xFFFF;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
175a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600)
176a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#pragma optimize("", on)
177a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com#endif
178a4b0d139e34e9d06bff0828adfb66fdfed9141c4reed@google.com
179d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comstatic SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m) {
180d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    if (SkShader::kClamp_TileMode == m) {
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return fixed_clamp;
182d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
183d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    if (SkShader::kRepeat_TileMode == m) {
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return fixed_repeat;
185d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    }
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(SkShader::kMirror_TileMode == m);
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fixed_mirror;
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
190f444e8ccda8905a8ce16bac368e09f205786db31reed@google.comstatic inline U16CPU fixed_clamp_lowbits(SkFixed x, int) {
191f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    return (x >> 12) & 0xF;
192f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com}
193f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com
194f444e8ccda8905a8ce16bac368e09f205786db31reed@google.comstatic inline U16CPU fixed_repeat_or_mirrow_lowbits(SkFixed x, int scale) {
195f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    return ((x * scale) >> 12) & 0xF;
196f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com}
197f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com
198f444e8ccda8905a8ce16bac368e09f205786db31reed@google.comstatic SkBitmapProcState::FixedTileLowBitsProc choose_tile_lowbits_proc(unsigned m) {
199f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    if (SkShader::kClamp_TileMode == m) {
200f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com        return fixed_clamp_lowbits;
201f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    } else {
202f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com        SkASSERT(SkShader::kMirror_TileMode == m ||
203f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com                 SkShader::kRepeat_TileMode == m);
204f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com        // mirror and repeat have the same behavior for the low bits.
205f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com        return fixed_repeat_or_mirrow_lowbits;
206f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    }
207f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com}
208f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com
20907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic inline U16CPU int_clamp(int x, int n) {
21038bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    if (x >= n) {
21107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        x = n - 1;
21238bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    }
21338bad32cf5297ec6908620fd174cd08c937d331acommit-bot@chromium.org    if (x < 0) {
21407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        x = 0;
21507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
21607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return x;
21707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
21907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic inline U16CPU int_repeat(int x, int n) {
22007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return sk_int_mod(x, n);
22107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
22207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
22307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic inline U16CPU int_mirror(int x, int n) {
22407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    x = sk_int_mod(x, 2 * n);
22507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (x >= n) {
22607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        x = n + ~(x - n);
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
22807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return x;
22907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#if 0
23207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void test_int_tileprocs() {
23307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    for (int i = -8; i <= 8; i++) {
23407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        SkDebugf(" int_mirror(%2d, 3) = %d\n", i, int_mirror(i, 3));
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
23607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
23707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#endif
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
23907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) {
24007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (SkShader::kClamp_TileMode == tm)
24107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        return int_clamp;
24207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (SkShader::kRepeat_TileMode == tm)
24307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        return int_repeat;
24407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkASSERT(SkShader::kMirror_TileMode == tm);
24507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return int_mirror;
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
250d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comvoid decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int i;
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
253d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    for (i = (count >> 2); i > 0; --i) {
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx+dx;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx+dx;
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
259ed881c2704bc81fe46a68c0cf9e292287313baa6reed@android.com    count &= 3;
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
261ed881c2704bc81fe46a68c0cf9e292287313baa6reed@android.com    uint16_t* xx = (uint16_t*)dst;
262ed881c2704bc81fe46a68c0cf9e292287313baa6reed@android.com    for (i = count; i > 0; --i) {
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *xx++ = SkToU16(fx >> 16); fx += dx;
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
267d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comvoid decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count) {
268d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    if (count & 1) {
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((fx >> (16 + 14)) == 0);
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
273d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    while ((count -= 2) >= 0) {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT((fx >> (16 + 14)) == 0);
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx;
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fx += dx;
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
28307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com///////////////////////////////////////////////////////////////////////////////
28407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com// stores the same as SCALE, but is cheaper to compute. Also since there is no
28507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com// scale, we don't need/have a FILTER version
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
28707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void fill_sequential(uint16_t xptr[], int start, int count) {
28807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#if 1
28907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (reinterpret_cast<intptr_t>(xptr) & 0x2) {
29007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        *xptr++ = start++;
29107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count -= 1;
29207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
29307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (count > 3) {
29407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr);
29507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1);
29607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3);
29707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        start += count & ~3;
29807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        int qcount = count >> 2;
29907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        do {
30007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            *xxptr++ = pattern0;
30107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            pattern0 += 0x40004;
30207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            *xxptr++ = pattern1;
30307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            pattern1 += 0x40004;
3044c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        } while (--qcount != 0);
30507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr = reinterpret_cast<uint16_t*>(xxptr);
30607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count &= 3;
30707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
30807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    while (--count >= 0) {
30907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        *xptr++ = start++;
31007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
31107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#else
31207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    for (int i = 0; i < count; i++) {
31307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        *xptr++ = start++;
31407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
31507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com#endif
31607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
31807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy,
31907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                                   int x, int y) {
32007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkPoint pt;
3219c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
32207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com               SkIntToScalar(y) + SK_ScalarHalf, &pt);
32307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    **xy = s.fIntTileProcY(SkScalarToFixed(pt.fY) >> 16,
32407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                           s.fBitmap->height());
32507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    *xy += 1;   // bump the ptr
32607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // return our starting X position
32707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return SkScalarToFixed(pt.fX) >> 16;
32807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
33007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void clampx_nofilter_trans(const SkBitmapProcState& s,
33107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                                  uint32_t xy[], int count, int x, int y) {
33207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
33307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
33407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
335fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    const int width = s.fBitmap->width();
33607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (1 == width) {
33707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        // all of the following X values must be 0
33807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
33907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        return;
34007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
341fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
34207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
34307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int n;
34407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
34507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // fill before 0 as needed
34607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (xpos < 0) {
34707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = -xpos;
34807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (n > count) {
34907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            n = count;
35007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
35107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        memset(xptr, 0, n * sizeof(uint16_t));
35207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count -= n;
35307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (0 == count) {
35407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            return;
35507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
35607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr += n;
35707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xpos = 0;
35807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
35907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
36007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // fill in 0..width-1 if needed
36107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (xpos < width) {
36207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = width - xpos;
36307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (n > count) {
36407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            n = count;
36507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
36607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fill_sequential(xptr, xpos, n);
36707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count -= n;
36807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (0 == count) {
36907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            return;
37007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
37107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr += n;
37207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
37307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
37407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // fill the remaining with the max value
375258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    sk_memset16(xptr, width - 1, count);
37607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
37707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
37807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void repeatx_nofilter_trans(const SkBitmapProcState& s,
37907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                                   uint32_t xy[], int count, int x, int y) {
38007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
38107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
38207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
383fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    const int width = s.fBitmap->width();
38407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (1 == width) {
38507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        // all of the following X values must be 0
38607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
38707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        return;
38807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
38907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
39007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
39107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int start = sk_int_mod(xpos, width);
39207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int n = width - start;
39307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (n > count) {
39407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = count;
39507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
39607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fill_sequential(xptr, start, n);
39707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    xptr += n;
39807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    count -= n;
39907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
40007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    while (count >= width) {
40107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fill_sequential(xptr, 0, width);
40207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr += width;
40307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count -= width;
40407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
40507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
40607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (count > 0) {
40707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fill_sequential(xptr, 0, count);
40807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
40907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
41007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
41107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void fill_backwards(uint16_t xptr[], int pos, int count) {
41207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    for (int i = 0; i < count; i++) {
41307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        SkASSERT(pos >= 0);
41407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr[i] = pos--;
41507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
41607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
41707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
41807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.comstatic void mirrorx_nofilter_trans(const SkBitmapProcState& s,
41907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                                   uint32_t xy[], int count, int x, int y) {
42007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
42107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
42207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
423fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    const int width = s.fBitmap->width();
42407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (1 == width) {
42507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        // all of the following X values must be 0
42607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
42707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        return;
42807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
42907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
43007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
43107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // need to know our start, and our initial phase (forward or backward)
43207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    bool forward;
43307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int n;
43407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int start = sk_int_mod(xpos, 2 * width);
43507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (start >= width) {
43607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        start = width + ~(start - width);
43707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        forward = false;
43807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = start + 1;  // [start .. 0]
43907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    } else {
44007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        forward = true;
44107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = width - start;  // [start .. width)
44207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
44307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (n > count) {
44407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        n = count;
44507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
44607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (forward) {
44707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fill_sequential(xptr, start, n);
44807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    } else {
44907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fill_backwards(xptr, start, n);
45007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
45107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    forward = !forward;
45207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    xptr += n;
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    count -= n;
454fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
45507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    while (count >= width) {
45607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (forward) {
45707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            fill_sequential(xptr, 0, width);
45807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        } else {
45907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            fill_backwards(xptr, width - 1, width);
46007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
46107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        forward = !forward;
46207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        xptr += width;
46307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        count -= width;
46407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
465fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
46607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (count > 0) {
46707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        if (forward) {
46807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            fill_sequential(xptr, 0, count);
46907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        } else {
47007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            fill_backwards(xptr, width - 1, count);
47107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
47207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
47307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com}
47407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
47507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com///////////////////////////////////////////////////////////////////////////////
47607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
477d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.comSkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc(bool trivial_matrix) {
47807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com//    test_int_tileprocs();
47907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // check for our special case when there is no scale/affine/perspective
4808d9153fca25897bf40ca0ebac8b03616612cc7b4humper    if (trivial_matrix && SkPaint::kNone_FilterLevel == fFilterLevel) {
48107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fIntTileProcY = choose_int_tile_proc(fTileModeY);
48207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        switch (fTileModeX) {
48307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            case SkShader::kClamp_TileMode:
48407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                return clampx_nofilter_trans;
48507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            case SkShader::kRepeat_TileMode:
48607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                return repeatx_nofilter_trans;
48707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com            case SkShader::kMirror_TileMode:
48807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com                return mirrorx_nofilter_trans;
48907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        }
49007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
491fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
49207d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    int index = 0;
4939cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
49407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        index = 1;
49507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
49607d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    if (fInvType & SkMatrix::kPerspective_Mask) {
49707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        index += 4;
49807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    } else if (fInvType & SkMatrix::kAffine_Mask) {
499a2b2c4ba5351b8cee0f03b5a9eeeb430862bbc7dreed@android.com        index += 2;
50007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
501fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
502d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    if (SkShader::kClamp_TileMode == fTileModeX && SkShader::kClamp_TileMode == fTileModeY) {
50307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        // clamp gets special version of filterOne
50407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fFilterOneX = SK_Fixed1;
50507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com        fFilterOneY = SK_Fixed1;
506157d94465a47a57e30e5cf49cd57dccd903e27e2digit@google.com        return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];
50707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
508fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
50907d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    // all remaining procs use this form for filterOne
51007d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fFilterOneX = SK_Fixed1 / fBitmap->width();
51107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fFilterOneY = SK_Fixed1 / fBitmap->height();
512fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
513d9ae2314f58ccac54068a2e50a4a159cf3929c1areed@google.com    if (SkShader::kRepeat_TileMode == fTileModeX && SkShader::kRepeat_TileMode == fTileModeY) {
514157d94465a47a57e30e5cf49cd57dccd903e27e2digit@google.com        return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];
51507d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    }
516fce02aca62525c3041226501574f740f7ea3714bdigit@google.com
51707d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fTileProcX = choose_tile_proc(fTileModeX);
51807d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    fTileProcY = choose_tile_proc(fTileModeY);
519f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    fTileLowBitsProcX = choose_tile_lowbits_proc(fTileModeX);
520f444e8ccda8905a8ce16bac368e09f205786db31reed@google.com    fTileLowBitsProcY = choose_tile_lowbits_proc(fTileModeY);
52107d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com    return GeneralXY_Procs[index];
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
523