SkPatchUtils.cpp revision 795c5ea6572ca8b58961ed64d628cc407005f1b3
1ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov/*
2ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Copyright 2014 Google Inc.
3ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov *
4ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Use of this source code is governed by a BSD-style license that can be
5ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * found in the LICENSE file.
6ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov */
7ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
8ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov#include "SkPatchUtils.h"
9ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
10b3c9d1c33caf325aada244204215eb790c228c12dandov#include "SkColorPriv.h"
11b3c9d1c33caf325aada244204215eb790c228c12dandov#include "SkGeometry.h"
12b3c9d1c33caf325aada244204215eb790c228c12dandov
13b3c9d1c33caf325aada244204215eb790c228c12dandov/**
14b3c9d1c33caf325aada244204215eb790c228c12dandov * Evaluator to sample the values of a cubic bezier using forward differences.
15b3c9d1c33caf325aada244204215eb790c228c12dandov * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
16b3c9d1c33caf325aada244204215eb790c228c12dandov * adding precalculated values.
17b3c9d1c33caf325aada244204215eb790c228c12dandov * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
18b3c9d1c33caf325aada244204215eb790c228c12dandov * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
19b3c9d1c33caf325aada244204215eb790c228c12dandov * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
20b3c9d1c33caf325aada244204215eb790c228c12dandov * obtaining this value (mh) we could just add this constant step to our first sampled point
21b3c9d1c33caf325aada244204215eb790c228c12dandov * to compute the next one.
22b3c9d1c33caf325aada244204215eb790c228c12dandov *
23b3c9d1c33caf325aada244204215eb790c228c12dandov * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
24b3c9d1c33caf325aada244204215eb790c228c12dandov * apply again forward differences and get linear function to which we can apply again forward
25b3c9d1c33caf325aada244204215eb790c228c12dandov * differences to get a constant difference. This is why we keep an array of size 4, the 0th
26b3c9d1c33caf325aada244204215eb790c228c12dandov * position keeps the sampled value while the next ones keep the quadratic, linear and constant
27b3c9d1c33caf325aada244204215eb790c228c12dandov * difference values.
28b3c9d1c33caf325aada244204215eb790c228c12dandov */
29b3c9d1c33caf325aada244204215eb790c228c12dandov
30b3c9d1c33caf325aada244204215eb790c228c12dandovclass FwDCubicEvaluator {
319d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
32b3c9d1c33caf325aada244204215eb790c228c12dandovpublic:
339d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
34b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
35b3c9d1c33caf325aada244204215eb790c228c12dandov     * Receives the 4 control points of the cubic bezier.
36b3c9d1c33caf325aada244204215eb790c228c12dandov     */
379d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
385ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark    explicit FwDCubicEvaluator(const SkPoint points[4])
395ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark            : fCoefs(points) {
40b3c9d1c33caf325aada244204215eb790c228c12dandov        memcpy(fPoints, points, 4 * sizeof(SkPoint));
419d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
42b3c9d1c33caf325aada244204215eb790c228c12dandov        this->restart(1);
43b3c9d1c33caf325aada244204215eb790c228c12dandov    }
449d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
45b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
46b3c9d1c33caf325aada244204215eb790c228c12dandov     * Restarts the forward differences evaluator to the first value of t = 0.
47b3c9d1c33caf325aada244204215eb790c228c12dandov     */
48b3c9d1c33caf325aada244204215eb790c228c12dandov    void restart(int divisions)  {
49b3c9d1c33caf325aada244204215eb790c228c12dandov        fDivisions = divisions;
50b3c9d1c33caf325aada244204215eb790c228c12dandov        fCurrent    = 0;
51b3c9d1c33caf325aada244204215eb790c228c12dandov        fMax        = fDivisions + 1;
525ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        Sk2s h  = Sk2s(1.f / fDivisions);
535ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        Sk2s h2 = h * h;
545ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        Sk2s h3 = h2 * h;
555ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        Sk2s fwDiff3 = Sk2s(6) * fCoefs.fA * h3;
565ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        fFwDiff[3] = to_point(fwDiff3);
575ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        fFwDiff[2] = to_point(fwDiff3 + times_2(fCoefs.fB) * h2);
585ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        fFwDiff[1] = to_point(fCoefs.fA * h3 + fCoefs.fB * h2 + fCoefs.fC * h);
595ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark        fFwDiff[0] = to_point(fCoefs.fD);
60b3c9d1c33caf325aada244204215eb790c228c12dandov    }
619d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
62b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
63b3c9d1c33caf325aada244204215eb790c228c12dandov     * Check if the evaluator is still within the range of 0<=t<=1
64b3c9d1c33caf325aada244204215eb790c228c12dandov     */
65b3c9d1c33caf325aada244204215eb790c228c12dandov    bool done() const {
66b3c9d1c33caf325aada244204215eb790c228c12dandov        return fCurrent > fMax;
67b3c9d1c33caf325aada244204215eb790c228c12dandov    }
689d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
69b3c9d1c33caf325aada244204215eb790c228c12dandov    /**
70b3c9d1c33caf325aada244204215eb790c228c12dandov     * Call next to obtain the SkPoint sampled and move to the next one.
71b3c9d1c33caf325aada244204215eb790c228c12dandov     */
72b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint next() {
73b3c9d1c33caf325aada244204215eb790c228c12dandov        SkPoint point = fFwDiff[0];
74b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[0]    += fFwDiff[1];
75b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[1]    += fFwDiff[2];
76b3c9d1c33caf325aada244204215eb790c228c12dandov        fFwDiff[2]    += fFwDiff[3];
77b3c9d1c33caf325aada244204215eb790c228c12dandov        fCurrent++;
78b3c9d1c33caf325aada244204215eb790c228c12dandov        return point;
79b3c9d1c33caf325aada244204215eb790c228c12dandov    }
809d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
81b3c9d1c33caf325aada244204215eb790c228c12dandov    const SkPoint* getCtrlPoints() const {
82b3c9d1c33caf325aada244204215eb790c228c12dandov        return fPoints;
83b3c9d1c33caf325aada244204215eb790c228c12dandov    }
849d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
85b3c9d1c33caf325aada244204215eb790c228c12dandovprivate:
865ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark    SkCubicCoeff fCoefs;
87b3c9d1c33caf325aada244204215eb790c228c12dandov    int fMax, fCurrent, fDivisions;
885ba2b9612ae4bc3a244bf45f1ec55c3a5a41e181caryclark    SkPoint fFwDiff[4], fPoints[4];
89b3c9d1c33caf325aada244204215eb790c228c12dandov};
90b3c9d1c33caf325aada244204215eb790c228c12dandov
91b3c9d1c33caf325aada244204215eb790c228c12dandov////////////////////////////////////////////////////////////////////////////////
92b3c9d1c33caf325aada244204215eb790c228c12dandov
93ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov// size in pixels of each partition per axis, adjust this knob
94b3c9d1c33caf325aada244204215eb790c228c12dandovstatic const int kPartitionSize = 10;
95ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
96ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov/**
97ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov * Calculate the approximate arc length given a bezier curve's control points.
98ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov */
99ecfff21bde1f0ca3c36533eded325066b5f2d42ddandovstatic SkScalar approx_arc_length(SkPoint* points, int count) {
100ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    if (count < 2) {
101ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov        return 0;
102ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    }
103ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    SkScalar arcLength = 0;
104ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    for (int i = 0; i < count - 1; i++) {
105ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov        arcLength += SkPoint::Distance(points[i], points[i + 1]);
106ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    }
107ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    return arcLength;
108ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov}
109ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov
110b3c9d1c33caf325aada244204215eb790c228c12dandovstatic SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
111b3c9d1c33caf325aada244204215eb790c228c12dandov                      SkScalar c11) {
112b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar a = c00 * (1.f - tx) + c10 * tx;
113b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar b = c01 * (1.f - tx) + c11 * tx;
114b3c9d1c33caf325aada244204215eb790c228c12dandov    return a * (1.f - ty) + b * ty;
115b3c9d1c33caf325aada244204215eb790c228c12dandov}
116b3c9d1c33caf325aada244204215eb790c228c12dandov
117b3c9d1c33caf325aada244204215eb790c228c12dandovSkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) {
1189d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
119ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    // Approximate length of each cubic.
120b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint pts[kNumPtsCubic];
121b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getTopCubic(cubics, pts);
122b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
123b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar topLength = approx_arc_length(pts, kNumPtsCubic);
1249d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
125b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getBottomCubic(cubics, pts);
126b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
127b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic);
1289d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
129b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getLeftCubic(cubics, pts);
130b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
131b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic);
1329d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
133b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getRightCubic(cubics, pts);
134b3c9d1c33caf325aada244204215eb790c228c12dandov    matrix->mapPoints(pts, kNumPtsCubic);
135b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic);
1369d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
137ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    // Level of detail per axis, based on the larger side between top and bottom or left and right
138ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitionSize);
139ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov    int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitionSize);
1409d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
141b3c9d1c33caf325aada244204215eb790c228c12dandov    return SkISize::Make(SkMax32(8, lodX), SkMax32(8, lodY));
142b3c9d1c33caf325aada244204215eb790c228c12dandov}
143b3c9d1c33caf325aada244204215eb790c228c12dandov
144b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) {
145b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kTopP0_CubicCtrlPts];
146b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kTopP1_CubicCtrlPts];
147b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kTopP2_CubicCtrlPts];
148b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kTopP3_CubicCtrlPts];
149b3c9d1c33caf325aada244204215eb790c228c12dandov}
150b3c9d1c33caf325aada244204215eb790c228c12dandov
151b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) {
152b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kBottomP0_CubicCtrlPts];
153b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kBottomP1_CubicCtrlPts];
154b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kBottomP2_CubicCtrlPts];
155b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kBottomP3_CubicCtrlPts];
156b3c9d1c33caf325aada244204215eb790c228c12dandov}
157b3c9d1c33caf325aada244204215eb790c228c12dandov
158b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) {
159b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kLeftP0_CubicCtrlPts];
160b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kLeftP1_CubicCtrlPts];
161b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kLeftP2_CubicCtrlPts];
162b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kLeftP3_CubicCtrlPts];
163b3c9d1c33caf325aada244204215eb790c228c12dandov}
164b3c9d1c33caf325aada244204215eb790c228c12dandov
165b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
166b3c9d1c33caf325aada244204215eb790c228c12dandov    points[0] = cubics[kRightP0_CubicCtrlPts];
167b3c9d1c33caf325aada244204215eb790c228c12dandov    points[1] = cubics[kRightP1_CubicCtrlPts];
168b3c9d1c33caf325aada244204215eb790c228c12dandov    points[2] = cubics[kRightP2_CubicCtrlPts];
169b3c9d1c33caf325aada244204215eb790c228c12dandov    points[3] = cubics[kRightP3_CubicCtrlPts];
170b3c9d1c33caf325aada244204215eb790c228c12dandov}
171b3c9d1c33caf325aada244204215eb790c228c12dandov
172b3c9d1c33caf325aada244204215eb790c228c12dandovbool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
173b3c9d1c33caf325aada244204215eb790c228c12dandov                   const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) {
17496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (lodX < 1 || lodY < 1 || nullptr == cubics || nullptr == data) {
175b3c9d1c33caf325aada244204215eb790c228c12dandov        return false;
176b3c9d1c33caf325aada244204215eb790c228c12dandov    }
17745f7842de7148a544008483a7829071d3dffba51dandov
17845f7842de7148a544008483a7829071d3dffba51dandov    // check for overflow in multiplication
17945f7842de7148a544008483a7829071d3dffba51dandov    const int64_t lodX64 = (lodX + 1),
18045f7842de7148a544008483a7829071d3dffba51dandov                   lodY64 = (lodY + 1),
18145f7842de7148a544008483a7829071d3dffba51dandov                   mult64 = lodX64 * lodY64;
18245f7842de7148a544008483a7829071d3dffba51dandov    if (mult64 > SK_MaxS32) {
18345f7842de7148a544008483a7829071d3dffba51dandov        return false;
18445f7842de7148a544008483a7829071d3dffba51dandov    }
18545f7842de7148a544008483a7829071d3dffba51dandov    data->fVertexCount = SkToS32(mult64);
18645f7842de7148a544008483a7829071d3dffba51dandov
18745f7842de7148a544008483a7829071d3dffba51dandov    // it is recommended to generate draw calls of no more than 65536 indices, so we never generate
18845f7842de7148a544008483a7829071d3dffba51dandov    // more than 60000 indices. To accomplish that we resize the LOD and vertex count
18945f7842de7148a544008483a7829071d3dffba51dandov    if (data->fVertexCount > 10000 || lodX > 200 || lodY > 200) {
19045f7842de7148a544008483a7829071d3dffba51dandov        SkScalar weightX = static_cast<SkScalar>(lodX) / (lodX + lodY);
19145f7842de7148a544008483a7829071d3dffba51dandov        SkScalar weightY = static_cast<SkScalar>(lodY) / (lodX + lodY);
19245f7842de7148a544008483a7829071d3dffba51dandov
19345f7842de7148a544008483a7829071d3dffba51dandov        // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of
19445f7842de7148a544008483a7829071d3dffba51dandov        // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6)
19545f7842de7148a544008483a7829071d3dffba51dandov        lodX = static_cast<int>(weightX * 200);
19645f7842de7148a544008483a7829071d3dffba51dandov        lodY = static_cast<int>(weightY * 200);
19745f7842de7148a544008483a7829071d3dffba51dandov        data->fVertexCount = (lodX + 1) * (lodY + 1);
19845f7842de7148a544008483a7829071d3dffba51dandov    }
199b3c9d1c33caf325aada244204215eb790c228c12dandov    data->fIndexCount = lodX * lodY * 6;
200385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary
201385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    data->fPoints = new SkPoint[data->fVertexCount];
202385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary    data->fIndices = new uint16_t[data->fIndexCount];
203385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary
204b3c9d1c33caf325aada244204215eb790c228c12dandov    // if colors is not null then create array for colors
205b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPMColor colorsPM[kNumCorners];
20649f085dddff10473b6ebf832a974288300224e60bsalomon    if (colors) {
207b3c9d1c33caf325aada244204215eb790c228c12dandov        // premultiply colors to avoid color bleeding.
208b3c9d1c33caf325aada244204215eb790c228c12dandov        for (int i = 0; i < kNumCorners; i++) {
209b3c9d1c33caf325aada244204215eb790c228c12dandov            colorsPM[i] = SkPreMultiplyColor(colors[i]);
210b3c9d1c33caf325aada244204215eb790c228c12dandov        }
211385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary        data->fColors = new uint32_t[data->fVertexCount];
212b3c9d1c33caf325aada244204215eb790c228c12dandov    }
2139d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
214b3c9d1c33caf325aada244204215eb790c228c12dandov    // if texture coordinates are not null then create array for them
21549f085dddff10473b6ebf832a974288300224e60bsalomon    if (texCoords) {
216385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanary        data->fTexCoords = new SkPoint[data->fVertexCount];
217b3c9d1c33caf325aada244204215eb790c228c12dandov    }
2189d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
219b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPoint pts[kNumPtsCubic];
220b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getBottomCubic(cubics, pts);
221b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fBottom(pts);
222b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getTopCubic(cubics, pts);
223b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fTop(pts);
224b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getLeftCubic(cubics, pts);
225b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fLeft(pts);
226b3c9d1c33caf325aada244204215eb790c228c12dandov    SkPatchUtils::getRightCubic(cubics, pts);
227b3c9d1c33caf325aada244204215eb790c228c12dandov    FwDCubicEvaluator fRight(pts);
2289d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
229b3c9d1c33caf325aada244204215eb790c228c12dandov    fBottom.restart(lodX);
230b3c9d1c33caf325aada244204215eb790c228c12dandov    fTop.restart(lodX);
2319d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
232b3c9d1c33caf325aada244204215eb790c228c12dandov    SkScalar u = 0.0f;
233b3c9d1c33caf325aada244204215eb790c228c12dandov    int stride = lodY + 1;
234b3c9d1c33caf325aada244204215eb790c228c12dandov    for (int x = 0; x <= lodX; x++) {
235b3c9d1c33caf325aada244204215eb790c228c12dandov        SkPoint bottom = fBottom.next(), top = fTop.next();
236b3c9d1c33caf325aada244204215eb790c228c12dandov        fLeft.restart(lodY);
237b3c9d1c33caf325aada244204215eb790c228c12dandov        fRight.restart(lodY);
238b3c9d1c33caf325aada244204215eb790c228c12dandov        SkScalar v = 0.f;
239b3c9d1c33caf325aada244204215eb790c228c12dandov        for (int y = 0; y <= lodY; y++) {
240b3c9d1c33caf325aada244204215eb790c228c12dandov            int dataIndex = x * (lodY + 1) + y;
2419d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
242b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint left = fLeft.next(), right = fRight.next();
2439d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
244b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
245b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * top.y() + v * bottom.y());
246b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
247b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - u) * left.y() + u * right.y());
248b3c9d1c33caf325aada244204215eb790c228c12dandov            SkPoint s2 = SkPoint::Make(
249b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
250b3c9d1c33caf325aada244204215eb790c228c12dandov                                                     + u * fTop.getCtrlPoints()[3].x())
251b3c9d1c33caf325aada244204215eb790c228c12dandov                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
252b3c9d1c33caf325aada244204215eb790c228c12dandov                                              + u * fBottom.getCtrlPoints()[3].x()),
253b3c9d1c33caf325aada244204215eb790c228c12dandov                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
254b3c9d1c33caf325aada244204215eb790c228c12dandov                                                     + u * fTop.getCtrlPoints()[3].y())
255b3c9d1c33caf325aada244204215eb790c228c12dandov                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
256b3c9d1c33caf325aada244204215eb790c228c12dandov                                              + u * fBottom.getCtrlPoints()[3].y()));
257b3c9d1c33caf325aada244204215eb790c228c12dandov            data->fPoints[dataIndex] = s0 + s1 - s2;
2589d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
25949f085dddff10473b6ebf832a974288300224e60bsalomon            if (colors) {
260b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t a = uint8_t(bilerp(u, v,
261b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])),
262b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])),
263b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])),
264b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner]))));
265b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t r = uint8_t(bilerp(u, v,
266b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])),
267b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])),
268b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])),
269b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner]))));
270b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t g = uint8_t(bilerp(u, v,
271b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])),
272b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])),
273b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])),
274b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner]))));
275b3c9d1c33caf325aada244204215eb790c228c12dandov                uint8_t b = uint8_t(bilerp(u, v,
276b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])),
277b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])),
278b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])),
279b3c9d1c33caf325aada244204215eb790c228c12dandov                                   SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner]))));
280b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
281b3c9d1c33caf325aada244204215eb790c228c12dandov            }
2829d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
28349f085dddff10473b6ebf832a974288300224e60bsalomon            if (texCoords) {
284b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fTexCoords[dataIndex] = SkPoint::Make(
285b3c9d1c33caf325aada244204215eb790c228c12dandov                                            bilerp(u, v, texCoords[kTopLeft_Corner].x(),
286b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kTopRight_Corner].x(),
287b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomLeft_Corner].x(),
288b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomRight_Corner].x()),
289b3c9d1c33caf325aada244204215eb790c228c12dandov                                            bilerp(u, v, texCoords[kTopLeft_Corner].y(),
290b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kTopRight_Corner].y(),
291b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomLeft_Corner].y(),
292b3c9d1c33caf325aada244204215eb790c228c12dandov                                                   texCoords[kBottomRight_Corner].y()));
2939d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
294b3c9d1c33caf325aada244204215eb790c228c12dandov            }
2959d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
296b3c9d1c33caf325aada244204215eb790c228c12dandov            if(x < lodX && y < lodY) {
297b3c9d1c33caf325aada244204215eb790c228c12dandov                int i = 6 * (x * lodY + y);
298b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i] = x * stride + y;
299b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 1] = x * stride + 1 + y;
300b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
301b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 3] = data->fIndices[i];
302b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 4] = data->fIndices[i + 2];
303b3c9d1c33caf325aada244204215eb790c228c12dandov                data->fIndices[i + 5] = (x + 1) * stride + y;
304b3c9d1c33caf325aada244204215eb790c228c12dandov            }
305b3c9d1c33caf325aada244204215eb790c228c12dandov            v = SkScalarClampMax(v + 1.f / lodY, 1);
306b3c9d1c33caf325aada244204215eb790c228c12dandov        }
307b3c9d1c33caf325aada244204215eb790c228c12dandov        u = SkScalarClampMax(u + 1.f / lodX, 1);
308b3c9d1c33caf325aada244204215eb790c228c12dandov    }
309b3c9d1c33caf325aada244204215eb790c228c12dandov    return true;
310b3c9d1c33caf325aada244204215eb790c228c12dandov
311ecfff21bde1f0ca3c36533eded325066b5f2d42ddandov}
312795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
313795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed///////////////////////////////////////////////////////////////////////////////////////////////////
314795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
315795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reedsk_sp<SkVertices> SkPatchUtils::MakeVertices(const SkPoint cubics[12], const SkColor srcColors[4],
316795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                            const SkPoint srcTexCoords[4], int lodX, int lodY) {
317795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (lodX < 1 || lodY < 1 || nullptr == cubics) {
318795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        return nullptr;
319795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
320795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
321795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    // check for overflow in multiplication
322795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    const int64_t lodX64 = (lodX + 1),
323795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    lodY64 = (lodY + 1),
324795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    mult64 = lodX64 * lodY64;
325795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (mult64 > SK_MaxS32) {
326795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        return nullptr;
327795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
328795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
329795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    int vertexCount = SkToS32(mult64);
330795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    // it is recommended to generate draw calls of no more than 65536 indices, so we never generate
331795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    // more than 60000 indices. To accomplish that we resize the LOD and vertex count
332795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (vertexCount > 10000 || lodX > 200 || lodY > 200) {
333795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        float weightX = static_cast<float>(lodX) / (lodX + lodY);
334795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        float weightY = static_cast<float>(lodY) / (lodX + lodY);
335795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
336795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of
337795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6)
338795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        lodX = static_cast<int>(weightX * 200);
339795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        lodY = static_cast<int>(weightY * 200);
340795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        vertexCount = (lodX + 1) * (lodY + 1);
341795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
342795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    const int indexCount = lodX * lodY * 6;
343795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    uint32_t flags = 0;
344795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (srcTexCoords) {
345795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        flags |= SkVertices::kHasTexCoords_BuilderFlag;
346795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
347795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (srcColors) {
348795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        flags |= SkVertices::kHasColors_BuilderFlag;
349795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
350795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
351795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkVertices::Builder builder(SkCanvas::kTriangles_VertexMode, vertexCount, indexCount, flags);
352795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPoint* pos = builder.positions();
353795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPoint* texs = builder.texCoords();
354795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkColor* colors = builder.colors();
355795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    uint16_t* indices = builder.indices();
356795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
357795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    // if colors is not null then create array for colors
358795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPMColor colorsPM[kNumCorners];
359795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    if (srcColors) {
360795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        // premultiply colors to avoid color bleeding.
361795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        for (int i = 0; i < kNumCorners; i++) {
362795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            colorsPM[i] = SkPreMultiplyColor(srcColors[i]);
363795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        }
364795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        srcColors = colorsPM;
365795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
366795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
367795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPoint pts[kNumPtsCubic];
368795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPatchUtils::getBottomCubic(cubics, pts);
369795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    FwDCubicEvaluator fBottom(pts);
370795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPatchUtils::getTopCubic(cubics, pts);
371795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    FwDCubicEvaluator fTop(pts);
372795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPatchUtils::getLeftCubic(cubics, pts);
373795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    FwDCubicEvaluator fLeft(pts);
374795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkPatchUtils::getRightCubic(cubics, pts);
375795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    FwDCubicEvaluator fRight(pts);
376795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
377795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    fBottom.restart(lodX);
378795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    fTop.restart(lodX);
379795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
380795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    SkScalar u = 0.0f;
381795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    int stride = lodY + 1;
382795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    for (int x = 0; x <= lodX; x++) {
383795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        SkPoint bottom = fBottom.next(), top = fTop.next();
384795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        fLeft.restart(lodY);
385795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        fRight.restart(lodY);
386795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        SkScalar v = 0.f;
387795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        for (int y = 0; y <= lodY; y++) {
388795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            int dataIndex = x * (lodY + 1) + y;
389795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
390795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            SkPoint left = fLeft.next(), right = fRight.next();
391795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
392795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
393795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       (1.0f - v) * top.y() + v * bottom.y());
394795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
395795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       (1.0f - u) * left.y() + u * right.y());
396795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            SkPoint s2 = SkPoint::Make(
397795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
398795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                     + u * fTop.getCtrlPoints()[3].x())
399795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
400795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                              + u * fBottom.getCtrlPoints()[3].x()),
401795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
402795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                     + u * fTop.getCtrlPoints()[3].y())
403795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
404795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                              + u * fBottom.getCtrlPoints()[3].y()));
405795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            pos[dataIndex] = s0 + s1 - s2;
406795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
407795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            if (colors) {
408795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                uint8_t a = uint8_t(bilerp(u, v,
409795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])),
410795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])),
411795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])),
412795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner]))));
413795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                uint8_t r = uint8_t(bilerp(u, v,
414795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])),
415795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])),
416795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])),
417795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner]))));
418795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                uint8_t g = uint8_t(bilerp(u, v,
419795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])),
420795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])),
421795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])),
422795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner]))));
423795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                uint8_t b = uint8_t(bilerp(u, v,
424795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])),
425795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])),
426795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])),
427795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                           SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner]))));
428795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                colors[dataIndex] = SkPackARGB32(a,r,g,b);
429795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            }
430795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
431795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            if (texs) {
432795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                texs[dataIndex] = SkPoint::Make(bilerp(u, v, srcTexCoords[kTopLeft_Corner].x(),
433795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kTopRight_Corner].x(),
434795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kBottomLeft_Corner].x(),
435795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kBottomRight_Corner].x()),
436795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                bilerp(u, v, srcTexCoords[kTopLeft_Corner].y(),
437795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kTopRight_Corner].y(),
438795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kBottomLeft_Corner].y(),
439795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                                                       srcTexCoords[kBottomRight_Corner].y()));
440795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
441795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            }
442795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed
443795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            if(x < lodX && y < lodY) {
444795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                int i = 6 * (x * lodY + y);
445795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i] = x * stride + y;
446795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i + 1] = x * stride + 1 + y;
447795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i + 2] = (x + 1) * stride + 1 + y;
448795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i + 3] = indices[i];
449795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i + 4] = indices[i + 2];
450795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed                indices[i + 5] = (x + 1) * stride + y;
451795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            }
452795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed            v = SkScalarClampMax(v + 1.f / lodY, 1);
453795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        }
454795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed        u = SkScalarClampMax(u + 1.f / lodX, 1);
455795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    }
456795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed    return builder.detach();
457795c5ea6572ca8b58961ed64d628cc407005f1b3Mike Reed}
458