SkBitmapProcState.cpp revision d94697c21ae479df4190a1afbf08d85ce244a4ef
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBitmapProcState.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFilterProc.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPaint.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkShader.h"   // for tilemodes
133ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkUtilsArm.h"
14138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com#include "SkBitmapScaler.h"
15d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com#include "SkMipMap.h"
16602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com#include "SkScaledImageCache.h"
173ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com
183ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#if !SK_ARM_NEON_IS_NONE
193ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
203ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
213ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
223ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
233ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
243ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
253ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
263ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
273ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.comextern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
283ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#endif
293ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com
303ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#define   NAME_WRAP(x)  x
313ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkBitmapProcState_filter.h"
323ada0efdc8de8316df8113ec54ffd1a3f33ecd21digit@google.com#include "SkBitmapProcState_procs.h"
33b577b41c8ec26c21ae599e80a2707d42f03eaa60reed@android.com
34a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com///////////////////////////////////////////////////////////////////////////////
35a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com
36ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com// true iff the matrix contains, at most, scale and translate elements
37ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.comstatic bool matrix_only_scale_translate(const SkMatrix& m) {
38ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com    return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
39ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com}
40ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com
41c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com/**
42c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
43c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com *  go ahead and treat it as if it were, so that subsequent code can go fast.
44c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com */
45c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.comstatic bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
46ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com    SkASSERT(matrix_only_scale_translate(matrix));
47ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com
48ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com    if (matrix.getType() & SkMatrix::kScale_Mask) {
49ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        SkRect src, dst;
50ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        bitmap.getBounds(&src);
51f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com
52f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com        // Can't call mapRect(), since that will fix up inverted rectangles,
53f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com        // e.g. when scale is negative, and we don't want to return true for
54f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com        // those.
55f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com        matrix.mapPoints(SkTCast<SkPoint*>(&dst),
56f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com                         SkTCast<const SkPoint*>(&src),
57f707adc4f8b22fd1a59a900b64333480de653c5breed@google.com                         2);
58ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com
59ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        // Now round all 4 edges to device space, and then compare the device
60ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        // width/height to the original. Note: we must map all 4 and subtract
61ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        // rather than map the "width" and compare, since we care about the
62ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        // phase (in pixel space) that any translate in the matrix might impart.
63ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        SkIRect idst;
64ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        dst.round(&idst);
65ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        return idst.width() == bitmap.width() && idst.height() == bitmap.height();
66c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
67c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // if we got here, we're either kTranslate_Mask or identity
68c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    return true;
69c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com}
70c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
71c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.comstatic bool just_trans_general(const SkMatrix& matrix) {
72ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com    SkASSERT(matrix_only_scale_translate(matrix));
73c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
74ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com    if (matrix.getType() & SkMatrix::kScale_Mask) {
75c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        const SkScalar tol = SK_Scalar1 / 32768;
76989a95ea77230e8347da18876e1bd5f39a78ebb5skia.committer@gmail.com
77c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
78c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            return false;
79c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
80c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
81c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com            return false;
82c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
83c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
84c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    // if we got here, treat us as either kTranslate_Mask or identity
85c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    return true;
86c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com}
87c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
88c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com///////////////////////////////////////////////////////////////////////////////
89c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool valid_for_filtering(unsigned dimension) {
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // for filtering, width and height must fit in 14bits, since we use steal
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // 2 bits from each to store our 4bit subpixel data
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (dimension & ~0x3FFF) == 0;
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
96d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.comstatic SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
979cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    SkPoint v1, v2;
9858c856a54a75e703aa3c82a0cd4e1affd9bd8ffcrobertphillips@google.com
999cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    v1.fX = mat.getScaleX();
1009cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    v1.fY = mat.getSkewY();
10158c856a54a75e703aa3c82a0cd4e1affd9bd8ffcrobertphillips@google.com
1029cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    v2.fX = mat.getSkewX();
1039cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    v2.fY = mat.getScaleY();
10458c856a54a75e703aa3c82a0cd4e1affd9bd8ffcrobertphillips@google.com
1059cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
1069cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com}
1079cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com
1089c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com// TODO -- we may want to pass the clip into this function so we only scale
1099c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com// the portion of the image that we're going to need.  This will complicate
1109c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com// the interface to the cache, but might be well worth it.
1119c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1129c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.comvoid SkBitmapProcState::possiblyScaleImage() {
1139c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1149cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
1159cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // none or low (bilerp) does not need to look any further
1169c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        return;
1179c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    }
1181f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
119138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    // see if our platform has any specialized convolution code.
1201f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
1211f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
122138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    // Set up a pointer to a local (instead of storing the structure in the
1231f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com    // proc state) to avoid introducing a header dependency; this makes
124138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    // recompiles a lot less painful.
1251f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
126138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    SkConvolutionProcs simd;
127138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs = &simd;
1281f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
129138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs->fExtraHorizontalReads = 0;
130138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs->fConvolveVertically = NULL;
131138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs->fConvolve4RowsHorizontally = NULL;
132138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs->fConvolveHorizontally = NULL;
133138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    fConvolutionProcs->fApplySIMDPadding = NULL;
1341f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
135138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    this->platformConvolutionProcs();
136138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com
137138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    // STEP 1: Highest quality direct scale?
138138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com
1391f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com    // Check to see if the transformation matrix is simple, and if we're
1401f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com    // doing high quality scaling.  If so, do the bitmap scale here and
141138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com    // remove the scaling component from the matrix.
142138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com
1439cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
144138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
1459c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
1461f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
147602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        SkScalar invScaleX = fInvMatrix.getScaleX();
148602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        SkScalar invScaleY = fInvMatrix.getScaleY();
1497f1af501f206da48a7ff791af53432c9c1c89d08skia.committer@gmail.com
150602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        SkASSERT(NULL == fScaledCacheID);
151602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
152602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                         invScaleX, invScaleY,
153602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                         &fScaledBitmap);
154602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        if (NULL == fScaledCacheID) {
155602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com            int dest_width  = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX);
156602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com            int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY);
157602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com
158602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com            // All the criteria are met; let's make a new bitmap.
159602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com
160602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com            fScaledBitmap = SkBitmapScaler::Resize(fOrigBitmap,
161602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                   SkBitmapScaler::RESIZE_BEST,
162602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                   dest_width,
163602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                   dest_height,
164602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                   fConvolutionProcs);
165602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com            fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
166602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                            invScaleX,
167602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                            invScaleY,
168602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com                                                            fScaledBitmap);
169602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        }
170138ebc3e4061cf533ea2f7f3717239670fdc6e43humper@google.com        fScaledBitmap.lockPixels();
1711f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com
1729c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fBitmap = &fScaledBitmap;
1739c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1749c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // set the inv matrix type to translate-only;
1759c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1769c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fInvMatrix.setTranslate( 1/fInvMatrix.getScaleX() * fInvMatrix.getTranslateX(),
1779c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                                 1/fInvMatrix.getScaleY() * fInvMatrix.getTranslateY() );
1789c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1799c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // no need for any further filtering; we just did it!
1809c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1819cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        fFilterLevel = SkPaint::kNone_FilterLevel;
1829c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1839c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        return;
1849c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    }
1859c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
1869cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    /*
1879cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  If we get here, the caller has requested either Med or High filter-level
1889cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *
1899cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  If High, then our special-case for scale-only did not take, and so we
1909cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  have to make a choice:
1919cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *      1. fall back on mipmaps + bilerp
1929cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *      2. fall back on scanline bicubic filter
1939cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  For now, we compute the "scale" value from the matrix, and have a
1949cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  threshold to decide when bicubic is better, and when mips are better.
1959cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  No doubt a fancier decision tree could be used uere.
1969cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *
1979cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  If Medium, then we just try to build a mipmap and select a level,
1989cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  setting the filter-level to kLow to signal that we just need bilerp
1999cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  to process the selected level.
2009cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     */
2019c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
2029cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
2039cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com
2049cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
2059cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
2069cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // than this, then the mipmaps quality may be greater (certainly faster)
2079cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // so we only keep High quality if the scale is greater than this.
2089cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        //
2099cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // Since we're dealing with the inverse, we compare against its inverse.
2109cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        const SkScalar bicubicLimit = SkFloatToScalar(4.0f);
2119cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
2129cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        if (scaleSqd < bicubicLimitSqd) {  // use bicubic scanline
2139cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com            return;
2149cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        }
2159c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
2169cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // else set the filter-level to Medium, since we're scaling down and
2179cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        // want to reqeust mipmaps
2189cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        fFilterLevel = SkPaint::kMedium_FilterLevel;
2199cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    }
22058c856a54a75e703aa3c82a0cd4e1affd9bd8ffcrobertphillips@google.com
2219cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
2229c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
2239cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    /**
2249cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  Medium quality means use a mipmap for down-scaling, and just bilper
2259cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  for upscaling. Since we're examining the inverse matrix, we look for
2269cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     *  a scale > 1 to indicate down scaling by the CTM.
2279cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com     */
2289cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (scaleSqd > SK_Scalar1) {
229d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        const SkMipMap* mip = NULL;
230d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com
231d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        SkASSERT(NULL == fScaledCacheID);
232d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip);
233d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        if (!fScaledCacheID) {
234d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            SkASSERT(NULL == mip);
235d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            mip = SkMipMap::Build(fOrigBitmap);
236d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            if (mip) {
237d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap,
238d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                                                                   mip);
239d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                mip->unref();   // the cache took a ref
240d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                SkASSERT(fScaledCacheID);
241d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            }
242d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        } else {
243d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            SkASSERT(mip);
2449c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
245d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com
246d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com        if (mip) {
247d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
248d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            SkMipMap::Level level;
249d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com            if (mip->extractLevel(levelScale, &level)) {
250d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                SkScalar invScaleFixup = level.fScale;
251d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                fInvMatrix.postScale(invScaleFixup, invScaleFixup);
252d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com
253d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                fScaledBitmap.setConfig(fOrigBitmap.config(),
254d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                                        level.fWidth, level.fHeight,
255d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                                        level.fRowBytes);
256d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com                fScaledBitmap.setPixels(level.fPixels);
2579cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com                fBitmap = &fScaledBitmap;
2589cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com            }
2599c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
2609c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    }
2619cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com
262d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com    /*
263d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com     *  At this point, we may or may not have built a mipmap. Regardless, we
264d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com     *  now fall back on Low so will bilerp whatever fBitmap now points at.
265d94697c21ae479df4190a1afbf08d85ce244a4efreed@google.com     */
2669cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    fFilterLevel = SkPaint::kLow_FilterLevel;
2679c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com}
2689c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
2699c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.comvoid SkBitmapProcState::endContext() {
2709c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    SkDELETE(fBitmapFilter);
2719c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fBitmapFilter = NULL;
2729c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fScaledBitmap.reset();
2737f1af501f206da48a7ff791af53432c9c1c89d08skia.committer@gmail.com
274602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com    if (fScaledCacheID) {
275602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        SkScaledImageCache::Unlock(fScaledCacheID);
276602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com        fScaledCacheID = NULL;
277602a1d70257eb3fcb746d758577f042d8c94f6d9reed@google.com    }
2789c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com}
2799c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
28407d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
2859c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    bool trivialMatrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
2869c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
2878b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                       SkShader::kClamp_TileMode == fTileModeY;
288a44b4cc7976b06caf3a3f6b7913c2af92eb32217reed@android.com
2899c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvMatrix = inv;
2909c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    if (!(clampClamp || trivialMatrix)) {
2919c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
29307d1f008b365e94ef7c7347be19a03d00bd36805reed@android.com
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBitmap = &fOrigBitmap;
295fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
2969c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // initialize our filter quality to the one requested by the caller.
2979c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // We may downgrade it later if we determine that we either don't need
2989c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // or can't provide as high a quality filtering as the user requested.
299fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
3009cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    fFilterLevel = paint.getFilterLevel();
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3029c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com#ifndef SK_IGNORE_IMAGE_PRESCALE
3039c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // possiblyScaleImage will look to see if it can rescale the image as a
3049c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // preprocess; either by scaling up to the target size, or by selecting
3059c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // a nearby mipmap level.  If it does, it will adjust the working
3069c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // matrix as well as the working bitmap.  It may also adjust the filter
3079c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // quality to avoid re-filtering an already perfectly scaled image.
3089c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3099c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    this->possiblyScaleImage();
3109c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com#endif
3119c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3129c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // Now that all possible changes to the matrix have taken place, check
3139c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // to see if we're really close to a no-scale matrix.  If so, explicitly
3149c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // set it to be so.  Subsequent code may inspect this matrix to choose
3159c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // a faster path in this case.
3169c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3179c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // This code will only execute if the matrix has some scale component;
3189c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // if it's already pure translate then we won't do this inversion.
3199c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3209c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    if (matrix_only_scale_translate(fInvMatrix)) {
321ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com        SkMatrix forward;
3229c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (fInvMatrix.invert(&forward)) {
3239c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            if (clampClamp ? just_trans_clamp(forward, *fBitmap)
324ee056a82ae59373cae01ebbb4edcd3297d7c92cereed@google.com                            : just_trans_general(forward)) {
325ce1f3cc1e22a50caaaaded7b91d9492b3ae5901creed@google.com                SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
326ce1f3cc1e22a50caaaaded7b91d9492b3ae5901creed@google.com                SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
3279c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                fInvMatrix.setTranslate(tx, ty);
3289c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
329ce1f3cc1e22a50caaaaded7b91d9492b3ae5901creed@google.com            }
330c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com        }
331c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com    }
332c0e88e0d5d1260f81e7f6b66eeabfb25e6b95a4dreed@google.com
3339c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvProc        = fInvMatrix.getMapXYProc();
3349c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvType        = fInvMatrix.getType();
3359c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());
3369c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
3379c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());
3389c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fAlphaScale = SkAlpha255To256(paint.getAlpha());
341fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
3427a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fShaderProc32 = NULL;
3437a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fShaderProc16 = NULL;
3447a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fSampleProc32 = NULL;
3457a99eb1c63d4327d352af09ea59f039f014e4028reed@android.com    fSampleProc16 = NULL;
346fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
3479c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // recompute the triviality of the matrix here because we may have
3489c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // changed it!
3499c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3509c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
3519c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3529cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
3539c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // If this is still set, that means we wanted HQ sampling
3549c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // but couldn't do it as a preprocess.  Let's try to install
3559c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // the scanline version of the HQ sampler.  If that process fails,
3569c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // downgrade to bilerp.
3579c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3589c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // NOTE: Might need to be careful here in the future when we want
3599c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // to have the platform proc have a shot at this; it's possible that
3609c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // the chooseBitmapFilterProc will fail to install a shader but a
3619c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // platform-specific one might succeed, so it might be premature here
3629c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // to fall back to bilerp.  This needs thought.
3639c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3649c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        SkASSERT(fInvType > SkMatrix::kTranslate_Mask);
3659c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3669c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fShaderProc32 = this->chooseBitmapFilterProc();
3679c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (!fShaderProc32) {
3689cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com            fFilterLevel = SkPaint::kLow_FilterLevel;
3699c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
3709c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    }
3719c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3729cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kLow_FilterLevel == fFilterLevel) {
3739c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // Only try bilerp if the matrix is "interesting" and
3749c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // the image has a suitable size.
3759c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3769c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (fInvType <= SkMatrix::kTranslate_Mask ||
3779cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com                !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
3789cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com            fFilterLevel = SkPaint::kNone_FilterLevel;
3799c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
3809c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    }
3819c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3829c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // At this point, we know exactly what kind of sampling the per-scanline
3839c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // shader will perform.
3849c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
3859c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fMatrixProc = this->chooseMatrixProc(trivialMatrix);
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == fMatrixProc) {
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ///////////////////////////////////////////////////////////////////////
391fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3929c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // No need to do this if we're doing HQ sampling; if filter quality is
3939c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // still set to HQ by the time we get here, then we must have installed
3949c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    // the shader proc above and can skip all this.
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3969cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
397fa1bd5f86ceea6cfa8303594730125ad2853d87bskia.committer@gmail.com
3989c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        int index = 0;
3999c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (fAlphaScale < 256) {  // note: this distinction is not used for D16
4009c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            index |= 1;
4019c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
4029c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
4039c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            index |= 2;
4049c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
4059cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        if (fFilterLevel > SkPaint::kNone_FilterLevel) {
4069c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            index |= 4;
4079c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
4089c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // bits 3,4,5 encoding the source bitmap format
4099c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        switch (fBitmap->config()) {
4109c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            case SkBitmap::kARGB_8888_Config:
4119c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                index |= 0;
4129c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                break;
4139c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            case SkBitmap::kRGB_565_Config:
4149c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                index |= 8;
4159c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                break;
4169c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            case SkBitmap::kIndex8_Config:
4179c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                index |= 16;
4189c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                break;
4199c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            case SkBitmap::kARGB_4444_Config:
4209c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                index |= 24;
4219c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                break;
4229c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            case SkBitmap::kA8_Config:
4239c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                index |= 32;
4249c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                fPaintPMColor = SkPreMultiplyColor(paint.getColor());
4259c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                break;
4269c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            default:
4279c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                return false;
428aa9152abbca3a958a9379f4e5067a1c37486d677reed@android.com        }
429c9a1d4b519c2db8e43e54fef068c46462d2f8a4breed@android.com
4309c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    #if !SK_ARM_NEON_IS_ALWAYS
4319c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        static const SampleProc32 gSkBitmapProcStateSample32[] = {
4329c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_opaque_D32_nofilter_DXDY,
4339c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_alpha_D32_nofilter_DXDY,
4349c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_opaque_D32_nofilter_DX,
4359c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_alpha_D32_nofilter_DX,
4369c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_opaque_D32_filter_DXDY,
4379c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_alpha_D32_filter_DXDY,
4389c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_opaque_D32_filter_DX,
4399c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_alpha_D32_filter_DX,
4409c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4419c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_opaque_D32_nofilter_DXDY,
4429c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_alpha_D32_nofilter_DXDY,
4439c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_opaque_D32_nofilter_DX,
4449c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_alpha_D32_nofilter_DX,
4459c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_opaque_D32_filter_DXDY,
4469c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_alpha_D32_filter_DXDY,
4479c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_opaque_D32_filter_DX,
4489c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_alpha_D32_filter_DX,
4499c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4509c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_opaque_D32_nofilter_DXDY,
4519c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_alpha_D32_nofilter_DXDY,
4529c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_opaque_D32_nofilter_DX,
4539c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_alpha_D32_nofilter_DX,
4549c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_opaque_D32_filter_DXDY,
4559c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_alpha_D32_filter_DXDY,
4569c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_opaque_D32_filter_DX,
4579c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_alpha_D32_filter_DX,
4589c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4599c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_opaque_D32_nofilter_DXDY,
4609c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_alpha_D32_nofilter_DXDY,
4619c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_opaque_D32_nofilter_DX,
4629c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_alpha_D32_nofilter_DX,
4639c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_opaque_D32_filter_DXDY,
4649c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_alpha_D32_filter_DXDY,
4659c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_opaque_D32_filter_DX,
4669c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S4444_alpha_D32_filter_DX,
4679c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4689c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            // A8 treats alpha/opaque the same (equally efficient)
4699c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_nofilter_DXDY,
4709c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_nofilter_DXDY,
4719c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_nofilter_DX,
4729c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_nofilter_DX,
4739c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_filter_DXDY,
4749c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_filter_DXDY,
4759c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_filter_DX,
4769c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SA8_alpha_D32_filter_DX
4779c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        };
4789c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4799c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        static const SampleProc16 gSkBitmapProcStateSample16[] = {
4809c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_D16_nofilter_DXDY,
4819c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_D16_nofilter_DX,
4829c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_D16_filter_DXDY,
4839c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S32_D16_filter_DX,
4849c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4859c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_D16_nofilter_DXDY,
4869c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_D16_nofilter_DX,
4879c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_D16_filter_DXDY,
4889c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            S16_D16_filter_DX,
4899c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4909c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_D16_nofilter_DXDY,
4919c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_D16_nofilter_DX,
4929c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_D16_filter_DXDY,
4939c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            SI8_D16_filter_DX,
4949c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
4959c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            // Don't support 4444 -> 565
4969c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            NULL, NULL, NULL, NULL,
4979c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            // Don't support A8 -> 565
4989c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            NULL, NULL, NULL, NULL
4999c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        };
5009c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    #endif
5019c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
5029c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
5039c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        index >>= 1;    // shift away any opaque/alpha distinction
5049c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
5059c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com
5069c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        // our special-case shaderprocs
5079c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
5089c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            if (clampClamp) {
5099c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
5109c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            } else if (SkShader::kRepeat_TileMode == fTileModeX &&
5119c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                       SkShader::kRepeat_TileMode == fTileModeY) {
5129c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com                fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
5139c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            }
5149c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
5159c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
5169c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
5173e2345a8d56cb76bc43e4421a3e9e3681ecd9ebaskia.committer@gmail.com
5189c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        if (NULL == fShaderProc32) {
5199c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            fShaderProc32 = this->chooseShaderProc32();
5209c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        }
5211a8940e558ecc91502767525f69339fd45b71bd4humper@google.com    }
5221a8940e558ecc91502767525f69339fd45b71bd4humper@google.com
523b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com    // see if our platform has any accelerated overrides
524b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com    this->platformProcs();
525b088947f27496a9b9dc48a7cfb170f9d59589825humper@google.com
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5299a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.comstatic void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
5309a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    int x, int y,
5319a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    SkPMColor* SK_RESTRICT colors,
5329a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                                                    int count) {
5339a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
5349a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(s.fInvKy == 0);
5359a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(count > 0 && colors != NULL);
5369cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
53720c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
5389a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    const int maxX = s.fBitmap->width() - 1;
539f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    const int maxY = s.fBitmap->height() - 1;
540f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    int ix = s.fFilterOneX + x;
541f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    int iy = SkClampMax(s.fFilterOneY + y, maxY);
542f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com#ifdef SK_DEBUG
5439a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    {
5449a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        SkPoint pt;
5459c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
5469a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
547f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
548f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        int ix2 = SkScalarFloorToInt(pt.fX);
54920c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
550f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        SkASSERT(iy == iy2);
551f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com        SkASSERT(ix == ix2);
5529a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
553f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com#endif
554f7698de60e2cfecf84cb84f957e6fe69325fe67freed@google.com    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
55520c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
5569a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // clamp to the left
5579a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (ix < 0) {
5589a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        int n = SkMin32(-ix, count);
5599a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        sk_memset32(colors, row[0], n);
5609a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        count -= n;
5619a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        if (0 == count) {
5629a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com            return;
5639a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        }
5649a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        colors += n;
5659a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        SkASSERT(-ix == n);
5669a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        ix = 0;
5679a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
5689a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // copy the middle
5699a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (ix <= maxX) {
5709a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        int n = SkMin32(maxX - ix + 1, count);
5719a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        memcpy(colors, row + ix, n * sizeof(SkPMColor));
5729a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        count -= n;
5739a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        if (0 == count) {
5749a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com            return;
5759a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        }
5769a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        colors += n;
5779a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
5789a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    SkASSERT(count > 0);
5799a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    // clamp to the right
5809a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    sk_memset32(colors, row[maxX], count);
5819a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com}
5829a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
583a8d99307717c5fe02043969db0566c236a08c313reed@google.comstatic inline int sk_int_mod(int x, int n) {
584a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(n > 0);
585a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if ((unsigned)x >= (unsigned)n) {
586a8d99307717c5fe02043969db0566c236a08c313reed@google.com        if (x < 0) {
587a8d99307717c5fe02043969db0566c236a08c313reed@google.com            x = n + ~(~x % n);
588a8d99307717c5fe02043969db0566c236a08c313reed@google.com        } else {
589a8d99307717c5fe02043969db0566c236a08c313reed@google.com            x = x % n;
590a8d99307717c5fe02043969db0566c236a08c313reed@google.com        }
591a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
592a8d99307717c5fe02043969db0566c236a08c313reed@google.com    return x;
593a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
594a8d99307717c5fe02043969db0566c236a08c313reed@google.com
5958b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.comstatic inline int sk_int_mirror(int x, int n) {
5968b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    x = sk_int_mod(x, 2 * n);
5978b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    if (x >= n) {
5988b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        x = n + ~(x - n);
5998b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    }
6008b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    return x;
6018b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com}
6028b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
603a8d99307717c5fe02043969db0566c236a08c313reed@google.comstatic void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
604a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     int x, int y,
605a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     SkPMColor* SK_RESTRICT colors,
606a8d99307717c5fe02043969db0566c236a08c313reed@google.com                                                     int count) {
607a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
608a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(s.fInvKy == 0);
609a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkASSERT(count > 0 && colors != NULL);
6109cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
61120c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
612a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const int stopX = s.fBitmap->width();
613a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const int stopY = s.fBitmap->height();
614a8d99307717c5fe02043969db0566c236a08c313reed@google.com    int ix = s.fFilterOneX + x;
615a8d99307717c5fe02043969db0566c236a08c313reed@google.com    int iy = sk_int_mod(s.fFilterOneY + y, stopY);
616a8d99307717c5fe02043969db0566c236a08c313reed@google.com#ifdef SK_DEBUG
617a8d99307717c5fe02043969db0566c236a08c313reed@google.com    {
618a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkPoint pt;
6199c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com        s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
620a8d99307717c5fe02043969db0566c236a08c313reed@google.com                   SkIntToScalar(y) + SK_ScalarHalf, &pt);
621a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
622a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int ix2 = SkScalarFloorToInt(pt.fX);
62320c301bd1aa4578c6d0abb23ac2c72b5fbb436dbskia.committer@gmail.com
624a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkASSERT(iy == iy2);
625a8d99307717c5fe02043969db0566c236a08c313reed@google.com        SkASSERT(ix == ix2);
626a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
627a8d99307717c5fe02043969db0566c236a08c313reed@google.com#endif
628a8d99307717c5fe02043969db0566c236a08c313reed@google.com    const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
629a8d99307717c5fe02043969db0566c236a08c313reed@google.com
630a8d99307717c5fe02043969db0566c236a08c313reed@google.com    ix = sk_int_mod(ix, stopX);
631a8d99307717c5fe02043969db0566c236a08c313reed@google.com    for (;;) {
632a8d99307717c5fe02043969db0566c236a08c313reed@google.com        int n = SkMin32(stopX - ix, count);
633a8d99307717c5fe02043969db0566c236a08c313reed@google.com        memcpy(colors, row + ix, n * sizeof(SkPMColor));
634a8d99307717c5fe02043969db0566c236a08c313reed@google.com        count -= n;
635a8d99307717c5fe02043969db0566c236a08c313reed@google.com        if (0 == count) {
636a8d99307717c5fe02043969db0566c236a08c313reed@google.com            return;
637a8d99307717c5fe02043969db0566c236a08c313reed@google.com        }
638a8d99307717c5fe02043969db0566c236a08c313reed@google.com        colors += n;
639a8d99307717c5fe02043969db0566c236a08c313reed@google.com        ix = 0;
640a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
641a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
642a8d99307717c5fe02043969db0566c236a08c313reed@google.com
6438b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.comstatic void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
6448b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                                      int x, int y,
6458b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                                      SkPMColor* SK_RESTRICT colors,
6468b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                                      int count) {
6478b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
6488b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    SkASSERT(s.fInvKy == 0);
6498b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    SkASSERT(count > 0 && colors != NULL);
6508b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    SkASSERT(1 == s.fBitmap->width());
6518b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
652ad51132b1b494e9921c500167adc899e6cfc8684scroggo@google.com    int iY0;
653ad51132b1b494e9921c500167adc899e6cfc8684scroggo@google.com    int iY1   SK_INIT_TO_AVOID_WARNING;
654ad51132b1b494e9921c500167adc899e6cfc8684scroggo@google.com    int iSubY SK_INIT_TO_AVOID_WARNING;
6558b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
6569cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
6578b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
6588b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        uint32_t xy[2];
6598b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
6608b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        mproc(s, xy, 1, x, y);
6618b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
6628b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        iY0 = xy[0] >> 18;
6638b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        iY1 = xy[0] & 0x3FFF;
6648b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        iSubY = (xy[0] >> 14) & 0xF;
6658b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    } else {
6668b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        int yTemp;
6678b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
6688b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        if (s.fInvType > SkMatrix::kTranslate_Mask) {
6698b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            SkPoint pt;
6709c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            s.fInvProc(s.fInvMatrix,
6718b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                       SkIntToScalar(x) + SK_ScalarHalf,
67236df7ed46b41ac31cb2205bfd3ae37659d61e2fbskia.committer@gmail.com                       SkIntToScalar(y) + SK_ScalarHalf,
6738b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                       &pt);
6741e3052354ac155e3d9418cf7e8c8e009df524e01robertphillips@google.com            // When the matrix has a scale component the setup code in
67598ded84b80918ac1e40224c125922941f3b2eb03skia.committer@gmail.com            // chooseProcs multiples the inverse matrix by the inverse of the
6761e3052354ac155e3d9418cf7e8c8e009df524e01robertphillips@google.com            // bitmap's width and height. Since this method is going to do
6771e3052354ac155e3d9418cf7e8c8e009df524e01robertphillips@google.com            // its own tiling and sampling we need to undo that here.
678d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com            if (SkShader::kClamp_TileMode != s.fTileModeX ||
679d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com                SkShader::kClamp_TileMode != s.fTileModeY) {
680d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com                yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
681d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com            } else {
682d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com                yTemp = SkScalarFloorToInt(pt.fY);
683d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com            }
6848b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        } else {
6858b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            yTemp = s.fFilterOneY + y;
6868b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
6878b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
6888b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        const int stopY = s.fBitmap->height();
6898b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        switch (s.fTileModeY) {
6908b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kClamp_TileMode:
6918b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY0 = SkClampMax(yTemp, stopY-1);
6928b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
6938b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kRepeat_TileMode:
6948b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY0 = sk_int_mod(yTemp, stopY);
6958b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
6968b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kMirror_TileMode:
6978b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            default:
6988b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY0 = sk_int_mirror(yTemp, stopY);
6998b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
7008b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
7018b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7028b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com#ifdef SK_DEBUG
7038b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        {
7048b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            SkPoint pt;
7059c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            s.fInvProc(s.fInvMatrix,
7068b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                       SkIntToScalar(x) + SK_ScalarHalf,
70736df7ed46b41ac31cb2205bfd3ae37659d61e2fbskia.committer@gmail.com                       SkIntToScalar(y) + SK_ScalarHalf,
7088b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                       &pt);
709d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com            if (s.fInvType > SkMatrix::kTranslate_Mask &&
710d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com                (SkShader::kClamp_TileMode != s.fTileModeX ||
711d507775a8be5eca19c1c6212196bf4e56d29bab5robertphillips@google.com                 SkShader::kClamp_TileMode != s.fTileModeY)) {
7121e3052354ac155e3d9418cf7e8c8e009df524e01robertphillips@google.com                pt.fY *= s.fBitmap->height();
7131e3052354ac155e3d9418cf7e8c8e009df524e01robertphillips@google.com            }
7148b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            int iY2;
7158b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7168b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            switch (s.fTileModeY) {
7178b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kClamp_TileMode:
7188b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
7198b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
7208b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kRepeat_TileMode:
7218b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
7228b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
7238b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            case SkShader::kMirror_TileMode:
7248b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            default:
7258b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
7268b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com                break;
7278b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            }
7288b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7298b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            SkASSERT(iY0 == iY2);
7308b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
7318b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com#endif
7328b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    }
7338b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7348b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
7358b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    SkPMColor color;
7368b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7379cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
7388b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
7398b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7408b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        if (s.fAlphaScale < 256) {
7418b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
7428b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        } else {
7438b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            Filter_32_opaque(iSubY, *row0, *row1, &color);
7448b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
7458b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    } else {
7468b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        if (s.fAlphaScale < 256) {
7478b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            color = SkAlphaMulQ(*row0, s.fAlphaScale);
7488b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        } else {
7498b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            color = *row0;
7508b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
7518b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    }
7528b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7538b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    sk_memset32(colors, color, count);
7548b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com}
7558b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7566bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.comstatic void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
7576bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com                                 SkPMColor* SK_RESTRICT colors, int count) {
7586bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    // if we get called, the matrix is too tricky, so we just draw nothing
7596bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    sk_memset32(colors, 0, count);
7606bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com}
7616bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
7626bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.combool SkBitmapProcState::setupForTranslate() {
763a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkPoint pt;
7649c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com    fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
7656bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
7666bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    /*
7676bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  if the translate is larger than our ints, we can get random results, or
7686bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
7696bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     *  negate it.
7706bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com     */
7716bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    const SkScalar too_big = SkIntToScalar(1 << 30);
7726bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
7736bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return false;
7746bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    }
7756bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com
776a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // Since we know we're not filtered, we re-purpose these fields allow
777a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // us to go from device -> src coordinates w/ just an integer add,
778a8d99307717c5fe02043969db0566c236a08c313reed@google.com    // rather than running through the inverse-matrix
779a8d99307717c5fe02043969db0566c236a08c313reed@google.com    fFilterOneX = SkScalarFloorToInt(pt.fX);
780a8d99307717c5fe02043969db0566c236a08c313reed@google.com    fFilterOneY = SkScalarFloorToInt(pt.fY);
7816bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com    return true;
782a8d99307717c5fe02043969db0566c236a08c313reed@google.com}
783a8d99307717c5fe02043969db0566c236a08c313reed@google.com
7849a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.comSkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
7858b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7868b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
7878b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        return NULL;
7888b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    }
7898b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7908b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
7918b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
7928b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
7939cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        if (SkPaint::kNone_FilterLevel == fFilterLevel &&
7949c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            fInvType <= SkMatrix::kTranslate_Mask &&
7959c96d4b5ffdbf8c82f55b2058a2fea7225fe11d6humper@google.com            !this->setupForTranslate()) {
7968b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com            return DoNothing_shaderproc;
7978b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        }
7988b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com        return S32_D32_constX_shaderproc;
7998b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com    }
8008b8bf4d12ecf8fb340a1362c91a8a57395dd31a3robertphillips@google.com
8019a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (fAlphaScale < 256) {
8029a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
8039a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
8049a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    if (fInvType > SkMatrix::kTranslate_Mask) {
8059a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
8069a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
8079cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (SkPaint::kNone_FilterLevel != fFilterLevel) {
8089a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com        return NULL;
8099a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
8109a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
811a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
812a8d99307717c5fe02043969db0566c236a08c313reed@google.com    SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
813a8d99307717c5fe02043969db0566c236a08c313reed@google.com
814a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
8156bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        if (this->setupForTranslate()) {
8166bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com            return Clamp_S32_D32_nofilter_trans_shaderproc;
8176bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        }
8186bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return DoNothing_shaderproc;
8199a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    }
820a8d99307717c5fe02043969db0566c236a08c313reed@google.com    if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
8216bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        if (this->setupForTranslate()) {
8226bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com            return Repeat_S32_D32_nofilter_trans_shaderproc;
8236bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        }
8246bb92bc0b52d31f3ded38927cdefbeb13a3df87areed@google.com        return DoNothing_shaderproc;
825a8d99307717c5fe02043969db0566c236a08c313reed@google.com    }
8269a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com    return NULL;
8279a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com}
8289a4c746a1f0f91a5be2708a4c2018dfe14f62e48reed@google.com
8294c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com///////////////////////////////////////////////////////////////////////////////
8309fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8319fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com#ifdef SK_DEBUG
8329fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8339fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_scale_nofilter(uint32_t bitmapXY[], int count,
8349fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
8359fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    unsigned y = *bitmapXY++;
8369fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y < my);
837fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8389fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
8399fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
8409fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(xptr[i] < mx);
8419fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
8429fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
8439fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8449fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_scale_filter(uint32_t bitmapXY[], int count,
8459fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
8469fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    uint32_t YY = *bitmapXY++;
8479fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    unsigned y0 = YY >> 18;
848fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    unsigned y1 = YY & 0x3FFF;
8499fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y0 < my);
8509fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(y1 < my);
851fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
8529fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
8539fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XX = bitmapXY[i];
8549fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x0 = XX >> 18;
8559fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x1 = XX & 0x3FFF;
8569fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x0 < mx);
8579fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x1 < mx);
8589fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
8599fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
8609fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8619fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_affine_nofilter(uint32_t bitmapXY[], int count,
8629fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
8639fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
8649fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XY = bitmapXY[i];
8659fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x = XY & 0xFFFF;
8669fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y = XY >> 16;
8679fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x < mx);
8689fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y < my);
8699fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
8709fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
8719fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8729fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comstatic void check_affine_filter(uint32_t bitmapXY[], int count,
8739fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                 unsigned mx, unsigned my) {
8749fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    for (int i = 0; i < count; ++i) {
8759fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t YY = *bitmapXY++;
8769fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y0 = YY >> 18;
8779fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned y1 = YY & 0x3FFF;
8789fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y0 < my);
8799fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(y1 < my);
8809fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8819fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        uint32_t XX = *bitmapXY++;
8829fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x0 = XX >> 18;
8839fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        unsigned x1 = XX & 0x3FFF;
8849fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x0 < mx);
8859fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com        SkASSERT(x1 < mx);
8869fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
8879fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
8889fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8899fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comvoid SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
8909fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                        uint32_t bitmapXY[], int count,
8919fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com                                        int x, int y) {
8929fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(bitmapXY);
8939fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    SkASSERT(count > 0);
8949fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8959fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    state.fMatrixProc(state, bitmapXY, count, x, y);
8969fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8979fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
8989fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
8999fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    // There are four formats possible:
9009fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    //  scale -vs- affine
9019fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    //  filter -vs- nofilter
9029fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
9039cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
9049fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    } else {
9059cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com        proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
9069fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    }
9079fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
9089fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
9099fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
9109fe287bd07baa6d9e890b627c102bba562954f7dreed@google.comSkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
9119fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com    return DebugMatrixProc;
9129fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com}
9139fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
9149fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com#endif
9159fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com
9169fe287bd07baa6d9e890b627c102bba562954f7dreed@google.com///////////////////////////////////////////////////////////////////////////////
9174c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com/*
9184c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    The storage requirements for the different matrix procs are as follows,
9194c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    where each X or Y is 2 bytes, and N is the number of pixels/elements:
920fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9214c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    scale/translate     nofilter      Y(4bytes) + N * X
9224c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    affine/perspective  nofilter      N * (X Y)
9234c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    scale/translate     filter        Y Y + N * (X X)
9244c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    affine/perspective  filter        N * (Y Y X X)
9254c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com */
9264c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.comint SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
9274c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    int32_t size = static_cast<int32_t>(bufferSize);
9284c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com
9294c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    size &= ~3; // only care about 4-byte aligned chunks
9304c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
9314c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        size -= 4;   // the shared Y (or YY) coordinate
9324c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        if (size < 0) {
9334c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com            size = 0;
9344c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com        }
935258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 1;
9364c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    } else {
937258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 2;
9384c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com    }
9394c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com
9409cfc83cc8ac2ee50a7ce889e65a707941f48bdeareed@google.com    if (fFilterLevel != SkPaint::kNone_FilterLevel) {
941258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com        size >>= 1;
942258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    }
943258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com
944258cb228c636282a3e4f4ce87b1017498e207f33reed@android.com    return size;
9454c128c4917acf25c2cc5d1bd22282a4e1bb53d96reed@android.com}
946