1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkBitmapProcState_MatrixTemplates_DEFINED
9#define SkBitmapProcState_MatrixTemplates_DEFINED
10
11#include "SkMath.h"
12#include "SkMathPriv.h"
13
14template <typename TileProc, bool tryDecal>
15void NoFilterProc_Scale(const SkBitmapProcState& s, uint32_t xy[],
16                        int count, int x, int y) {
17    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
18                             SkMatrix::kScale_Mask)) == 0);
19
20    // we store y, x, x, x, x, x
21
22    const unsigned maxX = s.fBitmap->width() - 1;
23    SkFractionalInt fx;
24    {
25        SkPoint pt;
26        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
27                                  SkIntToScalar(y) + SK_ScalarHalf, &pt);
28        fx = SkScalarToFractionalInt(pt.fY);
29        const unsigned maxY = s.fBitmap->height() - 1;
30        *xy++ = TileProc::Y(s, SkFractionalIntToFixed(fx), maxY);
31        fx = SkScalarToFractionalInt(pt.fX);
32    }
33
34    if (0 == maxX) {
35        // all of the following X values must be 0
36        memset(xy, 0, count * sizeof(uint16_t));
37        return;
38    }
39
40    const SkFractionalInt dx = s.fInvSxFractionalInt;
41
42    if (tryDecal && can_truncate_to_fixed_for_decal(fx, dx, count, maxX)) {
43        decal_nofilter_scale(xy, SkFractionalIntToFixed(fx),
44                             SkFractionalIntToFixed(dx), count);
45    } else {
46        int i;
47        for (i = (count >> 2); i > 0; --i) {
48            unsigned a, b;
49            a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx;
50            b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx;
51#ifdef SK_CPU_BENDIAN
52            *xy++ = (a << 16) | b;
53#else
54            *xy++ = (b << 16) | a;
55#endif
56            a = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx;
57            b = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx;
58#ifdef SK_CPU_BENDIAN
59            *xy++ = (a << 16) | b;
60#else
61            *xy++ = (b << 16) | a;
62#endif
63        }
64        uint16_t* xx = (uint16_t*)xy;
65        for (i = (count & 3); i > 0; --i) {
66            *xx++ = TileProc::X(s, SkFractionalIntToFixed(fx), maxX); fx += dx;
67        }
68    }
69}
70
71// note: we could special-case on a matrix which is skewed in X but not Y.
72// this would require a more general setup thatn SCALE does, but could use
73// SCALE's inner loop that only looks at dx
74
75template <typename TileProc>
76void NoFilterProc_Affine(const SkBitmapProcState& s, uint32_t xy[],
77                         int count, int x, int y) {
78    SkASSERT(s.fInvType & SkMatrix::kAffine_Mask);
79    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
80                             SkMatrix::kScale_Mask |
81                             SkMatrix::kAffine_Mask)) == 0);
82
83    SkPoint srcPt;
84    s.fInvProc(s.fInvMatrix,
85               SkIntToScalar(x) + SK_ScalarHalf,
86               SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
87
88    SkFractionalInt fx = SkScalarToFractionalInt(srcPt.fX);
89    SkFractionalInt fy = SkScalarToFractionalInt(srcPt.fY);
90    SkFractionalInt dx = s.fInvSxFractionalInt;
91    SkFractionalInt dy = s.fInvKyFractionalInt;
92    int maxX = s.fBitmap->width() - 1;
93    int maxY = s.fBitmap->height() - 1;
94
95    for (int i = count; i > 0; --i) {
96        *xy++ = (TileProc::Y(s, SkFractionalIntToFixed(fy), maxY) << 16) |
97                 TileProc::X(s, SkFractionalIntToFixed(fx), maxX);
98        fx += dx; fy += dy;
99    }
100}
101
102template <typename TileProc>
103void NoFilterProc_Persp(const SkBitmapProcState& s, uint32_t* SK_RESTRICT xy,
104                        int count, int x, int y) {
105    SkASSERT(s.fInvType & SkMatrix::kPerspective_Mask);
106
107    int maxX = s.fBitmap->width() - 1;
108    int maxY = s.fBitmap->height() - 1;
109
110    SkPerspIter   iter(s.fInvMatrix,
111                       SkIntToScalar(x) + SK_ScalarHalf,
112                       SkIntToScalar(y) + SK_ScalarHalf, count);
113
114    while ((count = iter.next()) != 0) {
115        const SkFixed* SK_RESTRICT srcXY = iter.getXY();
116        while (--count >= 0) {
117            *xy++ = (TileProc::Y(s, srcXY[1], maxY) << 16) |
118                     TileProc::X(s, srcXY[0], maxX);
119            srcXY += 2;
120        }
121    }
122}
123
124#endif
125