1c573a40ed5024b463e47088d307e3164a486dba5msarett/*
2c573a40ed5024b463e47088d307e3164a486dba5msarett * Copyright 2015 Google Inc.
3c573a40ed5024b463e47088d307e3164a486dba5msarett *
4c573a40ed5024b463e47088d307e3164a486dba5msarett * Use of this source code is governed by a BSD-style license that can be
5c573a40ed5024b463e47088d307e3164a486dba5msarett * found in the LICENSE file.
6c573a40ed5024b463e47088d307e3164a486dba5msarett */
7c573a40ed5024b463e47088d307e3164a486dba5msarett
8c573a40ed5024b463e47088d307e3164a486dba5msarett#include "SkLatticeIter.h"
9c573a40ed5024b463e47088d307e3164a486dba5msarett#include "SkRect.h"
10c573a40ed5024b463e47088d307e3164a486dba5msarett
11c573a40ed5024b463e47088d307e3164a486dba5msarett/**
12c573a40ed5024b463e47088d307e3164a486dba5msarett *  Divs must be in increasing order with no duplicates.
13c573a40ed5024b463e47088d307e3164a486dba5msarett */
1471df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarettstatic bool valid_divs(const int* divs, int count, int start, int end) {
1571df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    int prev = start - 1;
16c573a40ed5024b463e47088d307e3164a486dba5msarett    for (int i = 0; i < count; i++) {
1771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        if (prev >= divs[i] || divs[i] >= end) {
18c573a40ed5024b463e47088d307e3164a486dba5msarett            return false;
19c573a40ed5024b463e47088d307e3164a486dba5msarett        }
20815486c42f1ca66c81e12d8ccc9fb142e3c10544Brian Salomon        prev = divs[i];
21c573a40ed5024b463e47088d307e3164a486dba5msarett    }
22c573a40ed5024b463e47088d307e3164a486dba5msarett
23c573a40ed5024b463e47088d307e3164a486dba5msarett    return true;
24c573a40ed5024b463e47088d307e3164a486dba5msarett}
25c573a40ed5024b463e47088d307e3164a486dba5msarett
26c573a40ed5024b463e47088d307e3164a486dba5msarettbool SkLatticeIter::Valid(int width, int height, const SkCanvas::Lattice& lattice) {
2771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    SkIRect totalBounds = SkIRect::MakeWH(width, height);
2871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    SkASSERT(lattice.fBounds);
2971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    const SkIRect latticeBounds = *lattice.fBounds;
3071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    if (!totalBounds.contains(latticeBounds)) {
3171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        return false;
3271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    }
3371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett
3471df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    bool zeroXDivs = lattice.fXCount <= 0 || (1 == lattice.fXCount &&
3571df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                              latticeBounds.fLeft == lattice.fXDivs[0]);
3671df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    bool zeroYDivs = lattice.fYCount <= 0 || (1 == lattice.fYCount &&
3771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                              latticeBounds.fTop == lattice.fYDivs[0]);
380764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    if (zeroXDivs && zeroYDivs) {
390764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        return false;
400764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    }
410764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
4271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    return valid_divs(lattice.fXDivs, lattice.fXCount, latticeBounds.fLeft, latticeBounds.fRight)
4371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        && valid_divs(lattice.fYDivs, lattice.fYCount, latticeBounds.fTop, latticeBounds.fBottom);
44c573a40ed5024b463e47088d307e3164a486dba5msarett}
45c573a40ed5024b463e47088d307e3164a486dba5msarett
46c573a40ed5024b463e47088d307e3164a486dba5msarett/**
47c573a40ed5024b463e47088d307e3164a486dba5msarett *  Count the number of pixels that are in "scalable" patches.
48c573a40ed5024b463e47088d307e3164a486dba5msarett */
49c573a40ed5024b463e47088d307e3164a486dba5msarettstatic int count_scalable_pixels(const int32_t* divs, int numDivs, bool firstIsScalable,
5071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                                 int start, int end) {
51c573a40ed5024b463e47088d307e3164a486dba5msarett    if (0 == numDivs) {
5271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        return firstIsScalable ? end - start : 0;
53c573a40ed5024b463e47088d307e3164a486dba5msarett    }
54c573a40ed5024b463e47088d307e3164a486dba5msarett
55c573a40ed5024b463e47088d307e3164a486dba5msarett    int i;
56c573a40ed5024b463e47088d307e3164a486dba5msarett    int count;
57c573a40ed5024b463e47088d307e3164a486dba5msarett    if (firstIsScalable) {
5871df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        count = divs[0] - start;
59c573a40ed5024b463e47088d307e3164a486dba5msarett        i = 1;
60c573a40ed5024b463e47088d307e3164a486dba5msarett    } else {
61c573a40ed5024b463e47088d307e3164a486dba5msarett        count = 0;
62c573a40ed5024b463e47088d307e3164a486dba5msarett        i = 0;
63c573a40ed5024b463e47088d307e3164a486dba5msarett    }
64c573a40ed5024b463e47088d307e3164a486dba5msarett
65c573a40ed5024b463e47088d307e3164a486dba5msarett    for (; i < numDivs; i += 2) {
66c573a40ed5024b463e47088d307e3164a486dba5msarett        // Alternatively, we could use |top| and |bottom| as variable names, instead of
67c573a40ed5024b463e47088d307e3164a486dba5msarett        // |left| and |right|.
68c573a40ed5024b463e47088d307e3164a486dba5msarett        int left = divs[i];
6971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        int right = (i + 1 < numDivs) ? divs[i + 1] : end;
70c573a40ed5024b463e47088d307e3164a486dba5msarett        count += right - left;
71c573a40ed5024b463e47088d307e3164a486dba5msarett    }
72c573a40ed5024b463e47088d307e3164a486dba5msarett
73c573a40ed5024b463e47088d307e3164a486dba5msarett    return count;
74c573a40ed5024b463e47088d307e3164a486dba5msarett}
75c573a40ed5024b463e47088d307e3164a486dba5msarett
76c573a40ed5024b463e47088d307e3164a486dba5msarett/**
77c573a40ed5024b463e47088d307e3164a486dba5msarett *  Set points for the src and dst rects on subsequent draw calls.
78c573a40ed5024b463e47088d307e3164a486dba5msarett */
79a172bd75619900fc0abda81670e772f07ba4a1d9Leon Scroggins IIIstatic void set_points(float* dst, int* src, const int* divs, int divCount, int srcFixed,
80a172bd75619900fc0abda81670e772f07ba4a1d9Leon Scroggins III                       int srcScalable, int srcStart, int srcEnd, float dstStart, float dstEnd,
8171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett                       bool isScalable) {
8271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    float dstLen = dstEnd - dstStart;
83c573a40ed5024b463e47088d307e3164a486dba5msarett    float scale;
84c573a40ed5024b463e47088d307e3164a486dba5msarett    if (srcFixed <= dstLen) {
85c573a40ed5024b463e47088d307e3164a486dba5msarett        // This is the "normal" case, where we scale the "scalable" patches and leave
86c573a40ed5024b463e47088d307e3164a486dba5msarett        // the other patches fixed.
87c573a40ed5024b463e47088d307e3164a486dba5msarett        scale = (dstLen - ((float) srcFixed)) / ((float) srcScalable);
88c573a40ed5024b463e47088d307e3164a486dba5msarett    } else {
89c573a40ed5024b463e47088d307e3164a486dba5msarett        // In this case, we eliminate the "scalable" patches and scale the "fixed" patches.
90c573a40ed5024b463e47088d307e3164a486dba5msarett        scale = dstLen / ((float) srcFixed);
91c573a40ed5024b463e47088d307e3164a486dba5msarett    }
92c573a40ed5024b463e47088d307e3164a486dba5msarett
9371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    src[0] = srcStart;
94c573a40ed5024b463e47088d307e3164a486dba5msarett    dst[0] = dstStart;
95c573a40ed5024b463e47088d307e3164a486dba5msarett    for (int i = 0; i < divCount; i++) {
96a172bd75619900fc0abda81670e772f07ba4a1d9Leon Scroggins III        src[i + 1] = divs[i];
97a172bd75619900fc0abda81670e772f07ba4a1d9Leon Scroggins III        int srcDelta = src[i + 1] - src[i];
98c573a40ed5024b463e47088d307e3164a486dba5msarett        float dstDelta;
99c573a40ed5024b463e47088d307e3164a486dba5msarett        if (srcFixed <= dstLen) {
100c573a40ed5024b463e47088d307e3164a486dba5msarett            dstDelta = isScalable ? scale * srcDelta : srcDelta;
101c573a40ed5024b463e47088d307e3164a486dba5msarett        } else {
102c573a40ed5024b463e47088d307e3164a486dba5msarett            dstDelta = isScalable ? 0.0f : scale * srcDelta;
103c573a40ed5024b463e47088d307e3164a486dba5msarett        }
104c573a40ed5024b463e47088d307e3164a486dba5msarett        dst[i + 1] = dst[i] + dstDelta;
105c573a40ed5024b463e47088d307e3164a486dba5msarett
106c573a40ed5024b463e47088d307e3164a486dba5msarett        // Alternate between "scalable" and "fixed" patches.
107c573a40ed5024b463e47088d307e3164a486dba5msarett        isScalable = !isScalable;
108c573a40ed5024b463e47088d307e3164a486dba5msarett    }
109c573a40ed5024b463e47088d307e3164a486dba5msarett
11071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    src[divCount + 1] = srcEnd;
11171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    dst[divCount + 1] = dstEnd;
112c573a40ed5024b463e47088d307e3164a486dba5msarett}
113c573a40ed5024b463e47088d307e3164a486dba5msarett
11471df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarettSkLatticeIter::SkLatticeIter(const SkCanvas::Lattice& lattice, const SkRect& dst) {
115c573a40ed5024b463e47088d307e3164a486dba5msarett    const int* xDivs = lattice.fXDivs;
1160764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    const int origXCount = lattice.fXCount;
117c573a40ed5024b463e47088d307e3164a486dba5msarett    const int* yDivs = lattice.fYDivs;
1180764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    const int origYCount = lattice.fYCount;
11971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    SkASSERT(lattice.fBounds);
12071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    const SkIRect src = *lattice.fBounds;
121c573a40ed5024b463e47088d307e3164a486dba5msarett
122c573a40ed5024b463e47088d307e3164a486dba5msarett    // In the x-dimension, the first rectangle always starts at x = 0 and is "scalable".
123c573a40ed5024b463e47088d307e3164a486dba5msarett    // If xDiv[0] is 0, it indicates that the first rectangle is degenerate, so the
124c573a40ed5024b463e47088d307e3164a486dba5msarett    // first real rectangle "scalable" in the x-direction.
125c573a40ed5024b463e47088d307e3164a486dba5msarett    //
126c573a40ed5024b463e47088d307e3164a486dba5msarett    // The same interpretation applies to the y-dimension.
127c573a40ed5024b463e47088d307e3164a486dba5msarett    //
128c573a40ed5024b463e47088d307e3164a486dba5msarett    // As we move left to right across the image, alternating patches will be "fixed" or
129c573a40ed5024b463e47088d307e3164a486dba5msarett    // "scalable" in the x-direction.  Similarly, as move top to bottom, alternating
130c573a40ed5024b463e47088d307e3164a486dba5msarett    // patches will be "fixed" or "scalable" in the y-direction.
1310764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    int xCount = origXCount;
1320764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    int yCount = origYCount;
13371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    bool xIsScalable = (xCount > 0 && src.fLeft == xDivs[0]);
134c573a40ed5024b463e47088d307e3164a486dba5msarett    if (xIsScalable) {
135c573a40ed5024b463e47088d307e3164a486dba5msarett        // Once we've decided that the first patch is "scalable", we don't need the
13671df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        // xDiv.  It is always implied that we start at the edge of the bounds.
137c573a40ed5024b463e47088d307e3164a486dba5msarett        xDivs++;
138c573a40ed5024b463e47088d307e3164a486dba5msarett        xCount--;
139c573a40ed5024b463e47088d307e3164a486dba5msarett    }
14071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    bool yIsScalable = (yCount > 0 && src.fTop == yDivs[0]);
141c573a40ed5024b463e47088d307e3164a486dba5msarett    if (yIsScalable) {
142c573a40ed5024b463e47088d307e3164a486dba5msarett        // Once we've decided that the first patch is "scalable", we don't need the
14371df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett        // yDiv.  It is always implied that we start at the edge of the bounds.
144c573a40ed5024b463e47088d307e3164a486dba5msarett        yDivs++;
145c573a40ed5024b463e47088d307e3164a486dba5msarett        yCount--;
146c573a40ed5024b463e47088d307e3164a486dba5msarett    }
147c573a40ed5024b463e47088d307e3164a486dba5msarett
148c573a40ed5024b463e47088d307e3164a486dba5msarett    // Count "scalable" and "fixed" pixels in each dimension.
14971df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    int xCountScalable = count_scalable_pixels(xDivs, xCount, xIsScalable, src.fLeft, src.fRight);
15071df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    int xCountFixed = src.width() - xCountScalable;
15171df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    int yCountScalable = count_scalable_pixels(yDivs, yCount, yIsScalable, src.fTop, src.fBottom);
15271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett    int yCountFixed = src.height() - yCountScalable;
153c573a40ed5024b463e47088d307e3164a486dba5msarett
154c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX.reset(xCount + 2);
155c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX.reset(xCount + 2);
156c573a40ed5024b463e47088d307e3164a486dba5msarett    set_points(fDstX.begin(), fSrcX.begin(), xDivs, xCount, xCountFixed, xCountScalable,
15771df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett               src.fLeft, src.fRight, dst.fLeft, dst.fRight, xIsScalable);
158c573a40ed5024b463e47088d307e3164a486dba5msarett
159c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY.reset(yCount + 2);
160c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY.reset(yCount + 2);
161c573a40ed5024b463e47088d307e3164a486dba5msarett    set_points(fDstY.begin(), fSrcY.begin(), yDivs, yCount, yCountFixed, yCountScalable,
16271df2d7bc1bbc83ad4cf005f9027df4cb3b88a9bmsarett               src.fTop, src.fBottom, dst.fTop, dst.fBottom, yIsScalable);
163c573a40ed5024b463e47088d307e3164a486dba5msarett
164c573a40ed5024b463e47088d307e3164a486dba5msarett    fCurrX = fCurrY = 0;
1650764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    fNumRectsInLattice = (xCount + 1) * (yCount + 1);
1660764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    fNumRectsToDraw = fNumRectsInLattice;
1670764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
168ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev    if (lattice.fRectTypes) {
169ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        fRectTypes.push_back_n(fNumRectsInLattice);
170ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        fColors.push_back_n(fNumRectsInLattice);
1710764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
172ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        const SkCanvas::Lattice::RectType* flags = lattice.fRectTypes;
173ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        const SkColor* colors = lattice.fColors;
1740764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
1750764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        bool hasPadRow = (yCount != origYCount);
1760764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        bool hasPadCol = (xCount != origXCount);
1770764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        if (hasPadRow) {
1780764efe6a9ae65ad83992f614f57ca9db5b1f191msarett            // The first row of rects are all empty, skip the first row of flags.
1790764efe6a9ae65ad83992f614f57ca9db5b1f191msarett            flags += origXCount + 1;
180ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev            colors += origXCount + 1;
1810764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        }
1820764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
1830764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        int i = 0;
1840764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        for (int y = 0; y < yCount + 1; y++) {
1850764efe6a9ae65ad83992f614f57ca9db5b1f191msarett            for (int x = 0; x < origXCount + 1; x++) {
1860764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                if (0 == x && hasPadCol) {
1870764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                    // The first column of rects are all empty.  Skip a rect.
1880764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                    flags++;
189ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev                    colors++;
1900764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                    continue;
1910764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                }
1920764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
193ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev                fRectTypes[i] = *flags;
19434adefa453d70629bc1fa4db96243c5d8eb61aebCary Clark                fColors[i] = SkCanvas::Lattice::kFixedColor == *flags ? *colors : 0;
1950764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                flags++;
196ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev                colors++;
1970764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                i++;
1980764efe6a9ae65ad83992f614f57ca9db5b1f191msarett            }
1990764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        }
2000764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
201ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        for (int j = 0; j < fRectTypes.count(); j++) {
202ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev            if (SkCanvas::Lattice::kTransparent == fRectTypes[j]) {
2030764efe6a9ae65ad83992f614f57ca9db5b1f191msarett                fNumRectsToDraw--;
2040764efe6a9ae65ad83992f614f57ca9db5b1f191msarett            }
2050764efe6a9ae65ad83992f614f57ca9db5b1f191msarett        }
2060764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    }
207c573a40ed5024b463e47088d307e3164a486dba5msarett}
208c573a40ed5024b463e47088d307e3164a486dba5msarett
209c573a40ed5024b463e47088d307e3164a486dba5msarettbool SkLatticeIter::Valid(int width, int height, const SkIRect& center) {
210c573a40ed5024b463e47088d307e3164a486dba5msarett    return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center);
211c573a40ed5024b463e47088d307e3164a486dba5msarett}
212c573a40ed5024b463e47088d307e3164a486dba5msarett
213c573a40ed5024b463e47088d307e3164a486dba5msarettSkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst) {
214c573a40ed5024b463e47088d307e3164a486dba5msarett    SkASSERT(SkIRect::MakeWH(w, h).contains(c));
215c573a40ed5024b463e47088d307e3164a486dba5msarett
216c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX.reset(4);
217c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY.reset(4);
218c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX.reset(4);
219c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY.reset(4);
220c573a40ed5024b463e47088d307e3164a486dba5msarett
221c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX[0] = 0;
222c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX[1] = SkIntToScalar(c.fLeft);
223c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX[2] = SkIntToScalar(c.fRight);
224c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcX[3] = SkIntToScalar(w);
225c573a40ed5024b463e47088d307e3164a486dba5msarett
226c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY[0] = 0;
227c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY[1] = SkIntToScalar(c.fTop);
228c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY[2] = SkIntToScalar(c.fBottom);
229c573a40ed5024b463e47088d307e3164a486dba5msarett    fSrcY[3] = SkIntToScalar(h);
230c573a40ed5024b463e47088d307e3164a486dba5msarett
231c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX[0] = dst.fLeft;
232c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft);
233c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight);
234c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstX[3] = dst.fRight;
235c573a40ed5024b463e47088d307e3164a486dba5msarett
236c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY[0] = dst.fTop;
237c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY[1] = dst.fTop + SkIntToScalar(c.fTop);
238c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom);
239c573a40ed5024b463e47088d307e3164a486dba5msarett    fDstY[3] = dst.fBottom;
240c573a40ed5024b463e47088d307e3164a486dba5msarett
241c573a40ed5024b463e47088d307e3164a486dba5msarett    if (fDstX[1] > fDstX[2]) {
242c573a40ed5024b463e47088d307e3164a486dba5msarett        fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width());
243c573a40ed5024b463e47088d307e3164a486dba5msarett        fDstX[2] = fDstX[1];
244c573a40ed5024b463e47088d307e3164a486dba5msarett    }
245c573a40ed5024b463e47088d307e3164a486dba5msarett
246c573a40ed5024b463e47088d307e3164a486dba5msarett    if (fDstY[1] > fDstY[2]) {
247c573a40ed5024b463e47088d307e3164a486dba5msarett        fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height());
248c573a40ed5024b463e47088d307e3164a486dba5msarett        fDstY[2] = fDstY[1];
249c573a40ed5024b463e47088d307e3164a486dba5msarett    }
250c573a40ed5024b463e47088d307e3164a486dba5msarett
251c573a40ed5024b463e47088d307e3164a486dba5msarett    fCurrX = fCurrY = 0;
2520764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    fNumRectsInLattice = 9;
2530764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    fNumRectsToDraw = 9;
254c573a40ed5024b463e47088d307e3164a486dba5msarett}
255c573a40ed5024b463e47088d307e3164a486dba5msarett
256a172bd75619900fc0abda81670e772f07ba4a1d9Leon Scroggins IIIbool SkLatticeIter::next(SkIRect* src, SkRect* dst, bool* isFixedColor, SkColor* fixedColor) {
2570764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    int currRect = fCurrX + fCurrY * (fSrcX.count() - 1);
2580764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    if (currRect == fNumRectsInLattice) {
259c573a40ed5024b463e47088d307e3164a486dba5msarett        return false;
260c573a40ed5024b463e47088d307e3164a486dba5msarett    }
261c573a40ed5024b463e47088d307e3164a486dba5msarett
262c573a40ed5024b463e47088d307e3164a486dba5msarett    const int x = fCurrX;
263c573a40ed5024b463e47088d307e3164a486dba5msarett    const int y = fCurrY;
264c573a40ed5024b463e47088d307e3164a486dba5msarett    SkASSERT(x >= 0 && x < fSrcX.count() - 1);
265c573a40ed5024b463e47088d307e3164a486dba5msarett    SkASSERT(y >= 0 && y < fSrcY.count() - 1);
266c573a40ed5024b463e47088d307e3164a486dba5msarett
267c573a40ed5024b463e47088d307e3164a486dba5msarett    if (fSrcX.count() - 1 == ++fCurrX) {
268c573a40ed5024b463e47088d307e3164a486dba5msarett        fCurrX = 0;
269c573a40ed5024b463e47088d307e3164a486dba5msarett        fCurrY += 1;
270c573a40ed5024b463e47088d307e3164a486dba5msarett    }
2710764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
272ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev    if (fRectTypes.count() > 0
273ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        && SkToBool(SkCanvas::Lattice::kTransparent == fRectTypes[currRect])) {
274ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        return this->next(src, dst, isFixedColor, fixedColor);
2750764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    }
2760764efe6a9ae65ad83992f614f57ca9db5b1f191msarett
2770764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]);
2780764efe6a9ae65ad83992f614f57ca9db5b1f191msarett    dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]);
279ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev    if (isFixedColor && fixedColor) {
280ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        *isFixedColor = fRectTypes.count() > 0
281ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev                     && SkToBool(SkCanvas::Lattice::kFixedColor == fRectTypes[currRect]);
282ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        if (*isFixedColor) {
283ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev            *fixedColor = fColors[currRect];
284ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev        }
285ca8c0953e8da1def5e6c12dde6d4368b4bf16077Stan Iliev    }
286c573a40ed5024b463e47088d307e3164a486dba5msarett    return true;
287c573a40ed5024b463e47088d307e3164a486dba5msarett}
28810e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett
28910e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarettvoid SkLatticeIter::mapDstScaleTranslate(const SkMatrix& matrix) {
29010e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    SkASSERT(matrix.isScaleTranslate());
29110e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    SkScalar tx = matrix.getTranslateX();
29210e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    SkScalar sx = matrix.getScaleX();
29310e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    for (int i = 0; i < fDstX.count(); i++) {
29410e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett        fDstX[i] = fDstX[i] * sx + tx;
29510e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    }
29610e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett
29710e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    SkScalar ty = matrix.getTranslateY();
29810e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    SkScalar sy = matrix.getScaleY();
29910e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    for (int i = 0; i < fDstY.count(); i++) {
30010e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett        fDstY[i] = fDstY[i] * sy + ty;
30110e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett    }
30210e3d9bf59bdec92c05367ae0b71e1ce1ee4a690msarett}
303