1935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com/* NEON optimized code (C) COPYRIGHT 2009 Motorola
296164722b5b534463cbceb6e3a8b98821748dee6caryclark@google.com *
396164722b5b534463cbceb6e3a8b98821748dee6caryclark@google.com * Use of this source code is governed by a BSD-style license that can be
496164722b5b534463cbceb6e3a8b98821748dee6caryclark@google.com * found in the LICENSE file.
596164722b5b534463cbceb6e3a8b98821748dee6caryclark@google.com */
6365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com
7bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmapProcState.h"
8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPerspIter.h"
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkShader.h"
102cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#include "SkUtils.h"
11d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#include "SkUtilsArm.h"
122cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
1399cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com// Helper to ensure that when we shift down, we do it w/o sign-extension
1499cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com// so the caller doesn't have to manually mask off the top 16 bits
1599cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com//
1699cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.comstatic unsigned SK_USHIFT16(unsigned x) {
1799cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com    return x >> 16;
1899cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com}
1999cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com
202cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com/*  returns 0...(n-1) given any x (positive or negative).
21935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
222cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    As an example, if n (which is always positive) is 5...
23935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
242cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com          x: -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8
252cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    returns:  2  3  4  0  1  2  3  4  0  1  2  3  4  0  1  2  3
262cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com */
272cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic inline int sk_int_mod(int x, int n) {
282cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkASSERT(n > 0);
292cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if ((unsigned)x >= (unsigned)n) {
302cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (x < 0) {
312cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            x = n + ~(~x % n);
322cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        } else {
332cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            x = x % n;
342cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
352cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
362cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return x;
372cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
39f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com/*
40f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  The decal_ functions require that
41f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  1. dx > 0
42f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  2. [fx, fx+dx, fx+2dx, fx+3dx, ... fx+(count-1)dx] are all <= maxX
43f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *
44f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  In addition, we use SkFractionalInt to keep more fractional precision than
45f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  just SkFixed, so we will abort the decal_ call if dx is very small, since
46f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  the decal_ function just operates on SkFixed. If that were changed, we could
47f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com *  skip the very_small test here.
48f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com */
49f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.comstatic inline bool can_truncate_to_fixed_for_decal(SkFractionalInt frX,
50f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com                                                   SkFractionalInt frDx,
51f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com                                                   int count, unsigned max) {
52f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    SkFixed dx = SkFractionalIntToFixed(frDx);
53935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
54f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    // if decal_ kept SkFractionalInt precision, this would just be dx <= 0
55f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    // I just made up the 1/256. Just don't want to perceive accumulated error
56f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    // if we truncate frDx and lose its low bits.
57f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    if (dx <= SK_Fixed1 / 256) {
58f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com        return false;
59f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    }
60f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com
61f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    // We cast to unsigned so we don't have to check for negative values, which
62f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    // will now appear as very large positive values, and thus fail our test!
63f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    SkFixed fx = SkFractionalIntToFixed(frX);
64f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com    return (unsigned)SkFixedFloorToInt(fx) <= max &&
65f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com           (unsigned)SkFixedFloorToInt(fx + dx * (count - 1)) < max;
66f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com}
67f58e53a4731829e374adb565acd58ea7b1b0c721reed@google.com
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count);
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
71d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com// Compile neon code paths if needed
72d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#if !SK_ARM_NEON_IS_NONE
73d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com
74d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com// These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp
75d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.comextern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[];
76d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.comextern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
77d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com
78d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#endif // !SK_ARM_NEON_IS_NONE
79d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com
80d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com// Compile non-neon code path if needed
81d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#if !SK_ARM_NEON_IS_ALWAYS
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define MAKENAME(suffix)        ClampX_ClampY ## suffix
83de8a82d9e8e55a0b6a72e62ad02324d7fa508e17reed@google.com#define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)
84de8a82d9e8e55a0b6a72e62ad02324d7fa508e17reed@google.com#define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define CHECK_FOR_DECAL
88d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#include "SkBitmapProcState_matrix.h"
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define MAKENAME(suffix)        RepeatX_RepeatY ## suffix
9199cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com#define TILEX_PROCF(fx, max)    SK_USHIFT16(((fx) & 0xFFFF) * ((max) + 1))
9299cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com#define TILEY_PROCF(fy, max)    SK_USHIFT16(((fy) & 0xFFFF) * ((max) + 1))
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
95d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com#include "SkBitmapProcState_matrix.h"
96365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com#endif
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define MAKENAME(suffix)        GeneralXY ## suffix
99e3b9fcf6f0c014270d3ea1c00e638ca9799415fehumper@google.com#define PREAMBLE(state)         SkBitmapProcState::FixedTileProc tileProcX = (state).fTileProcX; (void) tileProcX; \
100e3b9fcf6f0c014270d3ea1c00e638ca9799415fehumper@google.com                                SkBitmapProcState::FixedTileProc tileProcY = (state).fTileProcY; (void) tileProcY; \
101e3b9fcf6f0c014270d3ea1c00e638ca9799415fehumper@google.com                                SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX = (state).fTileLowBitsProcX; (void) tileLowBitsProcX; \
102e3b9fcf6f0c014270d3ea1c00e638ca9799415fehumper@google.com                                SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY = (state).fTileLowBitsProcY; (void) tileLowBitsProcY
10306dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define PREAMBLE_PARAM_X        , SkBitmapProcState::FixedTileProc tileProcX, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcX
10406dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define PREAMBLE_PARAM_Y        , SkBitmapProcState::FixedTileProc tileProcY, SkBitmapProcState::FixedTileLowBitsProc tileLowBitsProcY
10506dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define PREAMBLE_ARG_X          , tileProcX, tileLowBitsProcX
10606dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define PREAMBLE_ARG_Y          , tileProcY, tileLowBitsProcY
10799cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com#define TILEX_PROCF(fx, max)    SK_USHIFT16(tileProcX(fx) * ((max) + 1))
10899cc86fb17ba491fa316a6b1c5ac273d4af3e30breed@google.com#define TILEY_PROCF(fy, max)    SK_USHIFT16(tileProcY(fy) * ((max) + 1))
10906dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define TILEX_LOW_BITS(fx, max) tileLowBitsProcX(fx, (max) + 1)
11006dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com#define TILEY_LOW_BITS(fy, max) tileLowBitsProcY(fy, (max) + 1)
111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBitmapProcState_matrix.h"
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline U16CPU fixed_clamp(SkFixed x)
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
115833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    if (x < 0) {
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x = 0;
117833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    }
118833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    if (x >> 16) {
1190f2d191fd66c02bf03d6ecb9613c7feba177c00creed@google.com        x = 0xFFFF;
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return x;
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline U16CPU fixed_repeat(SkFixed x)
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return x & 0xFFFF;
127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1296398808ce504aed077deb601402117056723c852reed@google.com// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
1306398808ce504aed077deb601402117056723c852reed@google.com// See http://code.google.com/p/skia/issues/detail?id=472
1316398808ce504aed077deb601402117056723c852reed@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600)
1326398808ce504aed077deb601402117056723c852reed@google.com#pragma optimize("", off)
1336398808ce504aed077deb601402117056723c852reed@google.com#endif
1346398808ce504aed077deb601402117056723c852reed@google.com
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline U16CPU fixed_mirror(SkFixed x)
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkFixed s = x << 15 >> 31;
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return (x ^ s) & 0xFFFF;
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1426398808ce504aed077deb601402117056723c852reed@google.com#if defined(_MSC_VER) && (_MSC_VER >= 1600)
1436398808ce504aed077deb601402117056723c852reed@google.com#pragma optimize("", on)
1446398808ce504aed077deb601402117056723c852reed@google.com#endif
1456398808ce504aed077deb601402117056723c852reed@google.com
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic SkBitmapProcState::FixedTileProc choose_tile_proc(unsigned m)
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (SkShader::kClamp_TileMode == m)
149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return fixed_clamp;
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (SkShader::kRepeat_TileMode == m)
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return fixed_repeat;
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(SkShader::kMirror_TileMode == m);
153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return fixed_mirror;
154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
15606dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.comstatic inline U16CPU fixed_clamp_lowbits(SkFixed x, int) {
15706dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    return (x >> 12) & 0xF;
15806dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com}
15906dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com
16006dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.comstatic inline U16CPU fixed_repeat_or_mirrow_lowbits(SkFixed x, int scale) {
16106dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    return ((x * scale) >> 12) & 0xF;
16206dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com}
16306dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com
16406dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.comstatic SkBitmapProcState::FixedTileLowBitsProc choose_tile_lowbits_proc(unsigned m) {
16506dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    if (SkShader::kClamp_TileMode == m) {
16606dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com        return fixed_clamp_lowbits;
16706dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    } else {
16806dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com        SkASSERT(SkShader::kMirror_TileMode == m ||
16906dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com                 SkShader::kRepeat_TileMode == m);
17006dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com        // mirror and repeat have the same behavior for the low bits.
17106dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com        return fixed_repeat_or_mirrow_lowbits;
17206dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    }
17306dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com}
17406dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com
1752cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic inline U16CPU int_clamp(int x, int n) {
176833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    if (x >= n) {
1772cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        x = n - 1;
178833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    }
179833a06de0bfa633045e2650165dfb169acd7547ecommit-bot@chromium.org    if (x < 0) {
1802cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        x = 0;
1812cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
1822cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return x;
1832cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1852cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic inline U16CPU int_repeat(int x, int n) {
1862cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return sk_int_mod(x, n);
1872cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
1882cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
1892cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic inline U16CPU int_mirror(int x, int n) {
1902cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    x = sk_int_mod(x, 2 * n);
1912cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (x >= n) {
1922cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        x = n + ~(x - n);
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
1942cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return x;
1952cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1972cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#if 0
1982cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void test_int_tileprocs() {
1992cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    for (int i = -8; i <= 8; i++) {
2002cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        SkDebugf(" int_mirror(%2d, 3) = %d\n", i, int_mirror(i, 3));
201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2022cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
2032cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#endif
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2052cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic SkBitmapProcState::IntTileProc choose_int_tile_proc(unsigned tm) {
2062cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (SkShader::kClamp_TileMode == tm)
2072cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        return int_clamp;
2082cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (SkShader::kRepeat_TileMode == tm)
2092cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        return int_repeat;
2102cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkASSERT(SkShader::kMirror_TileMode == tm);
2112cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return int_mirror;
212bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
214bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com//////////////////////////////////////////////////////////////////////////////
215bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
216bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
217bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
218bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int i;
219bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
220bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (i = (count >> 2); i > 0; --i)
221bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    {
222bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
223bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx+dx;
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *dst++ = pack_two_shorts(fx >> 16, (fx + dx) >> 16);
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx+dx;
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
227365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com    count &= 3;
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
229365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com    uint16_t* xx = (uint16_t*)dst;
230365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com    for (i = count; i > 0; --i) {
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *xx++ = SkToU16(fx >> 16); fx += dx;
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count)
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
237365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com
238365fb6723fd3507f35b4c80f1cbfc231cb7a4171reed@android.com
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (count & 1)
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    {
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT((fx >> (16 + 14)) == 0);
242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx;
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    while ((count -= 2) >= 0)
246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    {
247bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT((fx >> (16 + 14)) == 0);
248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
249bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx;
250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
251bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        *dst++ = (fx >> 12 << 14) | ((fx >> 16) + 1);
252bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fx += dx;
253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
255bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2562cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com///////////////////////////////////////////////////////////////////////////////
2572cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com// stores the same as SCALE, but is cheaper to compute. Also since there is no
2582cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com// scale, we don't need/have a FILTER version
259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2602cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void fill_sequential(uint16_t xptr[], int start, int count) {
2612cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#if 1
2622cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (reinterpret_cast<intptr_t>(xptr) & 0x2) {
2632cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        *xptr++ = start++;
2642cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count -= 1;
2652cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
2662cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (count > 3) {
2672cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        uint32_t* xxptr = reinterpret_cast<uint32_t*>(xptr);
2682cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        uint32_t pattern0 = PACK_TWO_SHORTS(start + 0, start + 1);
2692cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        uint32_t pattern1 = PACK_TWO_SHORTS(start + 2, start + 3);
2702cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        start += count & ~3;
2712cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        int qcount = count >> 2;
2722cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        do {
2732cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            *xxptr++ = pattern0;
2742cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            pattern0 += 0x40004;
2752cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            *xxptr++ = pattern1;
2762cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            pattern1 += 0x40004;
277cf87e774356ef088b6d221da46a8702d16e19219reed@android.com        } while (--qcount != 0);
2782cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr = reinterpret_cast<uint16_t*>(xxptr);
2792cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count &= 3;
2802cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
2812cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    while (--count >= 0) {
2822cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        *xptr++ = start++;
2832cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
2842cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#else
2852cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    for (int i = 0; i < count; i++) {
2862cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        *xptr++ = start++;
2872cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
2882cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com#endif
2892cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2912cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic int nofilter_trans_preamble(const SkBitmapProcState& s, uint32_t** xy,
2922cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                                   int x, int y) {
2932cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkPoint pt;
2946212e31697a0aec85cda4f10e1a3c484563d0c3fhumper@google.com    s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
2952cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com               SkIntToScalar(y) + SK_ScalarHalf, &pt);
2962cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    **xy = s.fIntTileProcY(SkScalarToFixed(pt.fY) >> 16,
2972cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                           s.fBitmap->height());
2982cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    *xy += 1;   // bump the ptr
2992cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // return our starting X position
3002cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return SkScalarToFixed(pt.fX) >> 16;
3012cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
3032cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void clampx_nofilter_trans(const SkBitmapProcState& s,
3042cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                                  uint32_t xy[], int count, int x, int y) {
3052cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
3062cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3072cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
308935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com    const int width = s.fBitmap->width();
3092cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (1 == width) {
3102cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        // all of the following X values must be 0
3112cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
3122cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        return;
3132cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
314935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
3152cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
3162cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int n;
3172cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3182cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // fill before 0 as needed
3192cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (xpos < 0) {
3202cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = -xpos;
3212cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (n > count) {
3222cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            n = count;
3232cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
3242cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        memset(xptr, 0, n * sizeof(uint16_t));
3252cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count -= n;
3262cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (0 == count) {
3272cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            return;
3282cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
3292cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr += n;
3302cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xpos = 0;
3312cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3322cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3332cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // fill in 0..width-1 if needed
3342cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (xpos < width) {
3352cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = width - xpos;
3362cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (n > count) {
3372cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            n = count;
3382cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
3392cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fill_sequential(xptr, xpos, n);
3402cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count -= n;
3412cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (0 == count) {
3422cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            return;
3432cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
3442cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr += n;
3452cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3462cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3472cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // fill the remaining with the max value
348d3450806b91dab28b36faf3a15bd54b05b133b24reed@android.com    sk_memset16(xptr, width - 1, count);
3492cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
3502cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3512cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void repeatx_nofilter_trans(const SkBitmapProcState& s,
3522cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                                   uint32_t xy[], int count, int x, int y) {
3532cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
3542cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3552cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
356935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com    const int width = s.fBitmap->width();
3572cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (1 == width) {
3582cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        // all of the following X values must be 0
3592cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
3602cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        return;
3612cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3622cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3632cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
3642cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int start = sk_int_mod(xpos, width);
3652cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int n = width - start;
3662cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (n > count) {
3672cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = count;
3682cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3692cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    fill_sequential(xptr, start, n);
3702cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    xptr += n;
3712cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    count -= n;
3722cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3732cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    while (count >= width) {
3742cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fill_sequential(xptr, 0, width);
3752cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr += width;
3762cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count -= width;
3772cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3782cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3792cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (count > 0) {
3802cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fill_sequential(xptr, 0, count);
3812cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3822cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
3832cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3842cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void fill_backwards(uint16_t xptr[], int pos, int count) {
3852cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    for (int i = 0; i < count; i++) {
3862cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        SkASSERT(pos >= 0);
3872cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr[i] = pos--;
3882cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
3892cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
3902cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3912cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comstatic void mirrorx_nofilter_trans(const SkBitmapProcState& s,
3922cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                                   uint32_t xy[], int count, int x, int y) {
3932cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    SkASSERT((s.fInvType & ~SkMatrix::kTranslate_Mask) == 0);
3942cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
3952cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int xpos = nofilter_trans_preamble(s, &xy, x, y);
396935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com    const int width = s.fBitmap->width();
3972cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (1 == width) {
3982cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        // all of the following X values must be 0
3992cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        memset(xy, 0, count * sizeof(uint16_t));
4002cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        return;
4012cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4022cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
4032cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    uint16_t* xptr = reinterpret_cast<uint16_t*>(xy);
4042cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // need to know our start, and our initial phase (forward or backward)
4052cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    bool forward;
4062cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int n;
4072cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int start = sk_int_mod(xpos, 2 * width);
4082cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (start >= width) {
4092cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        start = width + ~(start - width);
4102cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        forward = false;
4112cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = start + 1;  // [start .. 0]
4122cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    } else {
4132cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        forward = true;
4142cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = width - start;  // [start .. width)
4152cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4162cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (n > count) {
4172cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        n = count;
4182cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4192cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (forward) {
4202cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fill_sequential(xptr, start, n);
4212cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    } else {
4222cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fill_backwards(xptr, start, n);
4232cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4242cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    forward = !forward;
4252cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    xptr += n;
426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    count -= n;
427935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4282cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    while (count >= width) {
4292cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (forward) {
4302cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            fill_sequential(xptr, 0, width);
4312cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        } else {
4322cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            fill_backwards(xptr, width - 1, width);
4332cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
4342cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        forward = !forward;
4352cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        xptr += width;
4362cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        count -= width;
4372cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
438935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4392cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (count > 0) {
4402cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        if (forward) {
4412cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            fill_sequential(xptr, 0, count);
4422cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        } else {
4432cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            fill_backwards(xptr, width - 1, count);
4442cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
4452cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4462cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com}
4472cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
4482cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com///////////////////////////////////////////////////////////////////////////////
4492cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com
4502cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comSkBitmapProcState::MatrixProc
4512cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.comSkBitmapProcState::chooseMatrixProc(bool trivial_matrix) {
4522cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com//    test_int_tileprocs();
4532cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // check for our special case when there is no scale/affine/perspective
4542cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (trivial_matrix) {
4554d112c5bcdd40d9786a685dc142653e31ffbcbabreed@google.com        SkASSERT(SkPaint::kNone_FilterLevel == fFilterLevel);
4562cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fIntTileProcY = choose_int_tile_proc(fTileModeY);
4572cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        switch (fTileModeX) {
4582cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            case SkShader::kClamp_TileMode:
4592cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                return clampx_nofilter_trans;
4602cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            case SkShader::kRepeat_TileMode:
4612cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                return repeatx_nofilter_trans;
4622cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com            case SkShader::kMirror_TileMode:
4632cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com                return mirrorx_nofilter_trans;
4642cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        }
4652cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
466935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4672cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    int index = 0;
4684d112c5bcdd40d9786a685dc142653e31ffbcbabreed@google.com    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
4692cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        index = 1;
4702cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
4712cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (fInvType & SkMatrix::kPerspective_Mask) {
4722cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        index += 4;
4732cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    } else if (fInvType & SkMatrix::kAffine_Mask) {
474b90adab1299ac35eab54240064e3eeb6240f849creed@android.com        index += 2;
4752cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
476935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4772cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (SkShader::kClamp_TileMode == fTileModeX &&
4782cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        SkShader::kClamp_TileMode == fTileModeY)
4792cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    {
4802cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        // clamp gets special version of filterOne
4812cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fFilterOneX = SK_Fixed1;
4822cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        fFilterOneY = SK_Fixed1;
48359c3235e42ec788faa4d7ef41884bdcc098be257digit@google.com        return SK_ARM_NEON_WRAP(ClampX_ClampY_Procs)[index];
4842cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
485935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4862cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    // all remaining procs use this form for filterOne
4872cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    fFilterOneX = SK_Fixed1 / fBitmap->width();
4882cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    fFilterOneY = SK_Fixed1 / fBitmap->height();
489935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
4902cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    if (SkShader::kRepeat_TileMode == fTileModeX &&
4912cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com        SkShader::kRepeat_TileMode == fTileModeY)
4922cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    {
49359c3235e42ec788faa4d7ef41884bdcc098be257digit@google.com        return SK_ARM_NEON_WRAP(RepeatX_RepeatY_Procs)[index];
4942cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    }
495d7ded5043a6f308c4a5c80b841a3f4a0d00ef06fdigit@google.com
4962cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    fTileProcX = choose_tile_proc(fTileModeX);
4972cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    fTileProcY = choose_tile_proc(fTileModeY);
49806dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    fTileLowBitsProcX = choose_tile_lowbits_proc(fTileModeX);
49906dcb2ea66610f55813ff5d6f967ae9cc599bb9creed@google.com    fTileLowBitsProcY = choose_tile_lowbits_proc(fTileModeY);
5002cd2edb95aa867542962a21a503c2bfcf57d14b6reed@android.com    return GeneralXY_Procs[index];
501bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
502