1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkLatticeIter.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRect.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Divs must be in increasing order with no duplicates.
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool valid_divs(const int* divs, int count, int start, int end) {
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int prev = start - 1;
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; i++) {
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (prev >= divs[i] || divs[i] >= end) {
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        prev = divs[i];
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkLatticeIter::Valid(int width, int height, const SkCanvas::Lattice& lattice) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkIRect totalBounds = SkIRect::MakeWH(width, height);
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(lattice.fBounds);
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkIRect latticeBounds = *lattice.fBounds;
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!totalBounds.contains(latticeBounds)) {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool zeroXDivs = lattice.fXCount <= 0 || (1 == lattice.fXCount &&
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              latticeBounds.fLeft == lattice.fXDivs[0]);
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool zeroYDivs = lattice.fYCount <= 0 || (1 == lattice.fYCount &&
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              latticeBounds.fTop == lattice.fYDivs[0]);
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (zeroXDivs && zeroYDivs) {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return valid_divs(lattice.fXDivs, lattice.fXCount, latticeBounds.fLeft, latticeBounds.fRight)
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        && valid_divs(lattice.fYDivs, lattice.fYCount, latticeBounds.fTop, latticeBounds.fBottom);
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Count the number of pixels that are in "scalable" patches.
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int count_scalable_pixels(const int32_t* divs, int numDivs, bool firstIsScalable,
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 int start, int end) {
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == numDivs) {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return firstIsScalable ? end - start : 0;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int i;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (firstIsScalable) {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        count = divs[0] - start;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        i = 1;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        count = 0;
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        i = 0;
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (; i < numDivs; i += 2) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Alternatively, we could use |top| and |bottom| as variable names, instead of
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // |left| and |right|.
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int left = divs[i];
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int right = (i + 1 < numDivs) ? divs[i + 1] : end;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        count += right - left;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return count;
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/**
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *  Set points for the src and dst rects on subsequent draw calls.
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void set_points(float* dst, float* src, const int* divs, int divCount, int srcFixed,
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       int srcScalable, float srcStart, float srcEnd, float dstStart, float dstEnd,
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       bool isScalable) {
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float dstLen = dstEnd - dstStart;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float scale;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (srcFixed <= dstLen) {
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // This is the "normal" case, where we scale the "scalable" patches and leave
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // the other patches fixed.
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        scale = (dstLen - ((float) srcFixed)) / ((float) srcScalable);
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // In this case, we eliminate the "scalable" patches and scale the "fixed" patches.
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        scale = dstLen / ((float) srcFixed);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src[0] = srcStart;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dst[0] = dstStart;
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < divCount; i++) {
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        src[i + 1] = (float) (divs[i]);
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float srcDelta = src[i + 1] - src[i];
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float dstDelta;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (srcFixed <= dstLen) {
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dstDelta = isScalable ? scale * srcDelta : srcDelta;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            dstDelta = isScalable ? 0.0f : scale * srcDelta;
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst[i + 1] = dst[i] + dstDelta;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Alternate between "scalable" and "fixed" patches.
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        isScalable = !isScalable;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src[divCount + 1] = srcEnd;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dst[divCount + 1] = dstEnd;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkLatticeIter::SkLatticeIter(const SkCanvas::Lattice& lattice, const SkRect& dst) {
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int* xDivs = lattice.fXDivs;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int origXCount = lattice.fXCount;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int* yDivs = lattice.fYDivs;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int origYCount = lattice.fYCount;
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(lattice.fBounds);
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkIRect src = *lattice.fBounds;
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // In the x-dimension, the first rectangle always starts at x = 0 and is "scalable".
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // If xDiv[0] is 0, it indicates that the first rectangle is degenerate, so the
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // first real rectangle "scalable" in the x-direction.
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The same interpretation applies to the y-dimension.
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // As we move left to right across the image, alternating patches will be "fixed" or
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // "scalable" in the x-direction.  Similarly, as move top to bottom, alternating
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // patches will be "fixed" or "scalable" in the y-direction.
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int xCount = origXCount;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int yCount = origYCount;
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool xIsScalable = (xCount > 0 && src.fLeft == xDivs[0]);
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (xIsScalable) {
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Once we've decided that the first patch is "scalable", we don't need the
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // xDiv.  It is always implied that we start at the edge of the bounds.
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        xDivs++;
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        xCount--;
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool yIsScalable = (yCount > 0 && src.fTop == yDivs[0]);
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (yIsScalable) {
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Once we've decided that the first patch is "scalable", we don't need the
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // yDiv.  It is always implied that we start at the edge of the bounds.
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        yDivs++;
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        yCount--;
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Count "scalable" and "fixed" pixels in each dimension.
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int xCountScalable = count_scalable_pixels(xDivs, xCount, xIsScalable, src.fLeft, src.fRight);
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int xCountFixed = src.width() - xCountScalable;
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int yCountScalable = count_scalable_pixels(yDivs, yCount, yIsScalable, src.fTop, src.fBottom);
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int yCountFixed = src.height() - yCountScalable;
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX.reset(xCount + 2);
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX.reset(xCount + 2);
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    set_points(fDstX.begin(), fSrcX.begin(), xDivs, xCount, xCountFixed, xCountScalable,
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               src.fLeft, src.fRight, dst.fLeft, dst.fRight, xIsScalable);
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY.reset(yCount + 2);
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY.reset(yCount + 2);
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    set_points(fDstY.begin(), fSrcY.begin(), yDivs, yCount, yCountFixed, yCountScalable,
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               src.fTop, src.fBottom, dst.fTop, dst.fBottom, yIsScalable);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCurrX = fCurrY = 0;
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNumRectsInLattice = (xCount + 1) * (yCount + 1);
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNumRectsToDraw = fNumRectsInLattice;
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (lattice.fRectTypes) {
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRectTypes.push_back_n(fNumRectsInLattice);
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fColors.push_back_n(fNumRectsInLattice);
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkCanvas::Lattice::RectType* flags = lattice.fRectTypes;
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkColor* colors = lattice.fColors;
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool hasPadRow = (yCount != origYCount);
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool hasPadCol = (xCount != origXCount);
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (hasPadRow) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // The first row of rects are all empty, skip the first row of flags.
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flags += origXCount + 1;
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            colors += origXCount + 1;
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int i = 0;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int y = 0; y < yCount + 1; y++) {
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int x = 0; x < origXCount + 1; x++) {
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (0 == x && hasPadCol) {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // The first column of rects are all empty.  Skip a rect.
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    flags++;
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    colors++;
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fRectTypes[i] = *flags;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fColors[i] = SkCanvas::Lattice::kFixedColor == *flags ? *colors : 0;
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                flags++;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                colors++;
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                i++;
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int j = 0; j < fRectTypes.count(); j++) {
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkCanvas::Lattice::kTransparent == fRectTypes[j]) {
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fNumRectsToDraw--;
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkLatticeIter::Valid(int width, int height, const SkIRect& center) {
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center);
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst) {
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(SkIRect::MakeWH(w, h).contains(c));
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX.reset(4);
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY.reset(4);
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX.reset(4);
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY.reset(4);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX[0] = 0;
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX[1] = SkIntToScalar(c.fLeft);
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX[2] = SkIntToScalar(c.fRight);
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcX[3] = SkIntToScalar(w);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY[0] = 0;
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY[1] = SkIntToScalar(c.fTop);
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY[2] = SkIntToScalar(c.fBottom);
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSrcY[3] = SkIntToScalar(h);
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX[0] = dst.fLeft;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft);
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight);
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstX[3] = dst.fRight;
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY[0] = dst.fTop;
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY[1] = dst.fTop + SkIntToScalar(c.fTop);
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom);
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDstY[3] = dst.fBottom;
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDstX[1] > fDstX[2]) {
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width());
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstX[2] = fDstX[1];
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDstY[1] > fDstY[2]) {
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height());
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstY[2] = fDstY[1];
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCurrX = fCurrY = 0;
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNumRectsInLattice = 9;
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNumRectsToDraw = 9;
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkLatticeIter::next(SkRect* src, SkRect* dst, bool* isFixedColor, SkColor* fixedColor) {
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int currRect = fCurrX + fCurrY * (fSrcX.count() - 1);
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (currRect == fNumRectsInLattice) {
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int x = fCurrX;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int y = fCurrY;
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(x >= 0 && x < fSrcX.count() - 1);
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(y >= 0 && y < fSrcY.count() - 1);
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fSrcX.count() - 1 == ++fCurrX) {
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCurrX = 0;
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCurrY += 1;
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fRectTypes.count() > 0
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        && SkToBool(SkCanvas::Lattice::kTransparent == fRectTypes[currRect])) {
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return this->next(src, dst, isFixedColor, fixedColor);
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]);
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]);
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (isFixedColor && fixedColor) {
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *isFixedColor = fRectTypes.count() > 0
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     && SkToBool(SkCanvas::Lattice::kFixedColor == fRectTypes[currRect]);
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (*isFixedColor) {
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *fixedColor = fColors[currRect];
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkLatticeIter::mapDstScaleTranslate(const SkMatrix& matrix) {
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(matrix.isScaleTranslate());
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar tx = matrix.getTranslateX();
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar sx = matrix.getScaleX();
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fDstX.count(); i++) {
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstX[i] = fDstX[i] * sx + tx;
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar ty = matrix.getTranslateY();
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar sy = matrix.getScaleY();
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fDstY.count(); i++) {
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDstY[i] = fDstY[i] * sy + ty;
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
304