1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/utils/SkPatchUtils.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkVertices.h" 11cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 12cb93a386Sopenharmony_ci#include "include/private/SkTPin.h" 13cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 14cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 15cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h" 16cb93a386Sopenharmony_ci#include "src/core/SkConvertPixels.h" 17cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace { 20cb93a386Sopenharmony_ci enum CubicCtrlPts { 21cb93a386Sopenharmony_ci kTopP0_CubicCtrlPts = 0, 22cb93a386Sopenharmony_ci kTopP1_CubicCtrlPts = 1, 23cb93a386Sopenharmony_ci kTopP2_CubicCtrlPts = 2, 24cb93a386Sopenharmony_ci kTopP3_CubicCtrlPts = 3, 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci kRightP0_CubicCtrlPts = 3, 27cb93a386Sopenharmony_ci kRightP1_CubicCtrlPts = 4, 28cb93a386Sopenharmony_ci kRightP2_CubicCtrlPts = 5, 29cb93a386Sopenharmony_ci kRightP3_CubicCtrlPts = 6, 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci kBottomP0_CubicCtrlPts = 9, 32cb93a386Sopenharmony_ci kBottomP1_CubicCtrlPts = 8, 33cb93a386Sopenharmony_ci kBottomP2_CubicCtrlPts = 7, 34cb93a386Sopenharmony_ci kBottomP3_CubicCtrlPts = 6, 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci kLeftP0_CubicCtrlPts = 0, 37cb93a386Sopenharmony_ci kLeftP1_CubicCtrlPts = 11, 38cb93a386Sopenharmony_ci kLeftP2_CubicCtrlPts = 10, 39cb93a386Sopenharmony_ci kLeftP3_CubicCtrlPts = 9, 40cb93a386Sopenharmony_ci }; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci // Enum for corner also clockwise. 43cb93a386Sopenharmony_ci enum Corner { 44cb93a386Sopenharmony_ci kTopLeft_Corner = 0, 45cb93a386Sopenharmony_ci kTopRight_Corner, 46cb93a386Sopenharmony_ci kBottomRight_Corner, 47cb93a386Sopenharmony_ci kBottomLeft_Corner 48cb93a386Sopenharmony_ci }; 49cb93a386Sopenharmony_ci} // namespace 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci/** 52cb93a386Sopenharmony_ci * Evaluator to sample the values of a cubic bezier using forward differences. 53cb93a386Sopenharmony_ci * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only 54cb93a386Sopenharmony_ci * adding precalculated values. 55cb93a386Sopenharmony_ci * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h 56cb93a386Sopenharmony_ci * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first 57cb93a386Sopenharmony_ci * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After 58cb93a386Sopenharmony_ci * obtaining this value (mh) we could just add this constant step to our first sampled point 59cb93a386Sopenharmony_ci * to compute the next one. 60cb93a386Sopenharmony_ci * 61cb93a386Sopenharmony_ci * For the cubic case the first difference gives as a result a quadratic polynomial to which we can 62cb93a386Sopenharmony_ci * apply again forward differences and get linear function to which we can apply again forward 63cb93a386Sopenharmony_ci * differences to get a constant difference. This is why we keep an array of size 4, the 0th 64cb93a386Sopenharmony_ci * position keeps the sampled value while the next ones keep the quadratic, linear and constant 65cb93a386Sopenharmony_ci * difference values. 66cb93a386Sopenharmony_ci */ 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciclass FwDCubicEvaluator { 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_cipublic: 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci /** 73cb93a386Sopenharmony_ci * Receives the 4 control points of the cubic bezier. 74cb93a386Sopenharmony_ci */ 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci explicit FwDCubicEvaluator(const SkPoint points[4]) 77cb93a386Sopenharmony_ci : fCoefs(points) { 78cb93a386Sopenharmony_ci memcpy(fPoints, points, 4 * sizeof(SkPoint)); 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci this->restart(1); 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci /** 84cb93a386Sopenharmony_ci * Restarts the forward differences evaluator to the first value of t = 0. 85cb93a386Sopenharmony_ci */ 86cb93a386Sopenharmony_ci void restart(int divisions) { 87cb93a386Sopenharmony_ci fDivisions = divisions; 88cb93a386Sopenharmony_ci fCurrent = 0; 89cb93a386Sopenharmony_ci fMax = fDivisions + 1; 90cb93a386Sopenharmony_ci Sk2s h = Sk2s(1.f / fDivisions); 91cb93a386Sopenharmony_ci Sk2s h2 = h * h; 92cb93a386Sopenharmony_ci Sk2s h3 = h2 * h; 93cb93a386Sopenharmony_ci Sk2s fwDiff3 = Sk2s(6) * fCoefs.fA * h3; 94cb93a386Sopenharmony_ci fFwDiff[3] = to_point(fwDiff3); 95cb93a386Sopenharmony_ci fFwDiff[2] = to_point(fwDiff3 + times_2(fCoefs.fB) * h2); 96cb93a386Sopenharmony_ci fFwDiff[1] = to_point(fCoefs.fA * h3 + fCoefs.fB * h2 + fCoefs.fC * h); 97cb93a386Sopenharmony_ci fFwDiff[0] = to_point(fCoefs.fD); 98cb93a386Sopenharmony_ci } 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci /** 101cb93a386Sopenharmony_ci * Check if the evaluator is still within the range of 0<=t<=1 102cb93a386Sopenharmony_ci */ 103cb93a386Sopenharmony_ci bool done() const { 104cb93a386Sopenharmony_ci return fCurrent > fMax; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci /** 108cb93a386Sopenharmony_ci * Call next to obtain the SkPoint sampled and move to the next one. 109cb93a386Sopenharmony_ci */ 110cb93a386Sopenharmony_ci SkPoint next() { 111cb93a386Sopenharmony_ci SkPoint point = fFwDiff[0]; 112cb93a386Sopenharmony_ci fFwDiff[0] += fFwDiff[1]; 113cb93a386Sopenharmony_ci fFwDiff[1] += fFwDiff[2]; 114cb93a386Sopenharmony_ci fFwDiff[2] += fFwDiff[3]; 115cb93a386Sopenharmony_ci fCurrent++; 116cb93a386Sopenharmony_ci return point; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci const SkPoint* getCtrlPoints() const { 120cb93a386Sopenharmony_ci return fPoints; 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ciprivate: 124cb93a386Sopenharmony_ci SkCubicCoeff fCoefs; 125cb93a386Sopenharmony_ci int fMax, fCurrent, fDivisions; 126cb93a386Sopenharmony_ci SkPoint fFwDiff[4], fPoints[4]; 127cb93a386Sopenharmony_ci}; 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci// size in pixels of each partition per axis, adjust this knob 132cb93a386Sopenharmony_cistatic const int kPartitionSize = 10; 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci/** 135cb93a386Sopenharmony_ci * Calculate the approximate arc length given a bezier curve's control points. 136cb93a386Sopenharmony_ci * Returns -1 if bad calc (i.e. non-finite) 137cb93a386Sopenharmony_ci */ 138cb93a386Sopenharmony_cistatic SkScalar approx_arc_length(const SkPoint points[], int count) { 139cb93a386Sopenharmony_ci if (count < 2) { 140cb93a386Sopenharmony_ci return 0; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci SkScalar arcLength = 0; 143cb93a386Sopenharmony_ci for (int i = 0; i < count - 1; i++) { 144cb93a386Sopenharmony_ci arcLength += SkPoint::Distance(points[i], points[i + 1]); 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ci return SkScalarIsFinite(arcLength) ? arcLength : -1; 147cb93a386Sopenharmony_ci} 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_cistatic SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01, 150cb93a386Sopenharmony_ci SkScalar c11) { 151cb93a386Sopenharmony_ci SkScalar a = c00 * (1.f - tx) + c10 * tx; 152cb93a386Sopenharmony_ci SkScalar b = c01 * (1.f - tx) + c11 * tx; 153cb93a386Sopenharmony_ci return a * (1.f - ty) + b * ty; 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_cistatic Sk4f bilerp(SkScalar tx, SkScalar ty, 157cb93a386Sopenharmony_ci const Sk4f& c00, const Sk4f& c10, const Sk4f& c01, const Sk4f& c11) { 158cb93a386Sopenharmony_ci Sk4f a = c00 * (1.f - tx) + c10 * tx; 159cb93a386Sopenharmony_ci Sk4f b = c01 * (1.f - tx) + c11 * tx; 160cb93a386Sopenharmony_ci return a * (1.f - ty) + b * ty; 161cb93a386Sopenharmony_ci} 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ciSkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) { 164cb93a386Sopenharmony_ci // Approximate length of each cubic. 165cb93a386Sopenharmony_ci SkPoint pts[kNumPtsCubic]; 166cb93a386Sopenharmony_ci SkPatchUtils::GetTopCubic(cubics, pts); 167cb93a386Sopenharmony_ci matrix->mapPoints(pts, kNumPtsCubic); 168cb93a386Sopenharmony_ci SkScalar topLength = approx_arc_length(pts, kNumPtsCubic); 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci SkPatchUtils::GetBottomCubic(cubics, pts); 171cb93a386Sopenharmony_ci matrix->mapPoints(pts, kNumPtsCubic); 172cb93a386Sopenharmony_ci SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci SkPatchUtils::GetLeftCubic(cubics, pts); 175cb93a386Sopenharmony_ci matrix->mapPoints(pts, kNumPtsCubic); 176cb93a386Sopenharmony_ci SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci SkPatchUtils::GetRightCubic(cubics, pts); 179cb93a386Sopenharmony_ci matrix->mapPoints(pts, kNumPtsCubic); 180cb93a386Sopenharmony_ci SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic); 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci if (topLength < 0 || bottomLength < 0 || leftLength < 0 || rightLength < 0) { 183cb93a386Sopenharmony_ci return {0, 0}; // negative length is a sentinel for bad length (i.e. non-finite) 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci // Level of detail per axis, based on the larger side between top and bottom or left and right 187cb93a386Sopenharmony_ci int lodX = static_cast<int>(std::max(topLength, bottomLength) / kPartitionSize); 188cb93a386Sopenharmony_ci int lodY = static_cast<int>(std::max(leftLength, rightLength) / kPartitionSize); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci return SkISize::Make(std::max(8, lodX), std::max(8, lodY)); 191cb93a386Sopenharmony_ci} 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_civoid SkPatchUtils::GetTopCubic(const SkPoint cubics[12], SkPoint points[4]) { 194cb93a386Sopenharmony_ci points[0] = cubics[kTopP0_CubicCtrlPts]; 195cb93a386Sopenharmony_ci points[1] = cubics[kTopP1_CubicCtrlPts]; 196cb93a386Sopenharmony_ci points[2] = cubics[kTopP2_CubicCtrlPts]; 197cb93a386Sopenharmony_ci points[3] = cubics[kTopP3_CubicCtrlPts]; 198cb93a386Sopenharmony_ci} 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_civoid SkPatchUtils::GetBottomCubic(const SkPoint cubics[12], SkPoint points[4]) { 201cb93a386Sopenharmony_ci points[0] = cubics[kBottomP0_CubicCtrlPts]; 202cb93a386Sopenharmony_ci points[1] = cubics[kBottomP1_CubicCtrlPts]; 203cb93a386Sopenharmony_ci points[2] = cubics[kBottomP2_CubicCtrlPts]; 204cb93a386Sopenharmony_ci points[3] = cubics[kBottomP3_CubicCtrlPts]; 205cb93a386Sopenharmony_ci} 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_civoid SkPatchUtils::GetLeftCubic(const SkPoint cubics[12], SkPoint points[4]) { 208cb93a386Sopenharmony_ci points[0] = cubics[kLeftP0_CubicCtrlPts]; 209cb93a386Sopenharmony_ci points[1] = cubics[kLeftP1_CubicCtrlPts]; 210cb93a386Sopenharmony_ci points[2] = cubics[kLeftP2_CubicCtrlPts]; 211cb93a386Sopenharmony_ci points[3] = cubics[kLeftP3_CubicCtrlPts]; 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_civoid SkPatchUtils::GetRightCubic(const SkPoint cubics[12], SkPoint points[4]) { 215cb93a386Sopenharmony_ci points[0] = cubics[kRightP0_CubicCtrlPts]; 216cb93a386Sopenharmony_ci points[1] = cubics[kRightP1_CubicCtrlPts]; 217cb93a386Sopenharmony_ci points[2] = cubics[kRightP2_CubicCtrlPts]; 218cb93a386Sopenharmony_ci points[3] = cubics[kRightP3_CubicCtrlPts]; 219cb93a386Sopenharmony_ci} 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_cistatic void skcolor_to_float(SkPMColor4f* dst, const SkColor* src, int count, SkColorSpace* dstCS) { 222cb93a386Sopenharmony_ci SkImageInfo srcInfo = SkImageInfo::Make(count, 1, kBGRA_8888_SkColorType, 223cb93a386Sopenharmony_ci kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()); 224cb93a386Sopenharmony_ci SkImageInfo dstInfo = SkImageInfo::Make(count, 1, kRGBA_F32_SkColorType, 225cb93a386Sopenharmony_ci kPremul_SkAlphaType, sk_ref_sp(dstCS)); 226cb93a386Sopenharmony_ci SkAssertResult(SkConvertPixels(dstInfo, dst, 0, srcInfo, src, 0)); 227cb93a386Sopenharmony_ci} 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_cistatic void float_to_skcolor(SkColor* dst, const SkPMColor4f* src, int count, SkColorSpace* srcCS) { 230cb93a386Sopenharmony_ci SkImageInfo srcInfo = SkImageInfo::Make(count, 1, kRGBA_F32_SkColorType, 231cb93a386Sopenharmony_ci kPremul_SkAlphaType, sk_ref_sp(srcCS)); 232cb93a386Sopenharmony_ci SkImageInfo dstInfo = SkImageInfo::Make(count, 1, kBGRA_8888_SkColorType, 233cb93a386Sopenharmony_ci kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()); 234cb93a386Sopenharmony_ci SkAssertResult(SkConvertPixels(dstInfo, dst, 0, srcInfo, src, 0)); 235cb93a386Sopenharmony_ci} 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_cisk_sp<SkVertices> SkPatchUtils::MakeVertices(const SkPoint cubics[12], const SkColor srcColors[4], 238cb93a386Sopenharmony_ci const SkPoint srcTexCoords[4], int lodX, int lodY, 239cb93a386Sopenharmony_ci SkColorSpace* colorSpace) { 240cb93a386Sopenharmony_ci if (lodX < 1 || lodY < 1 || nullptr == cubics) { 241cb93a386Sopenharmony_ci return nullptr; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci // check for overflow in multiplication 245cb93a386Sopenharmony_ci const int64_t lodX64 = (lodX + 1), 246cb93a386Sopenharmony_ci lodY64 = (lodY + 1), 247cb93a386Sopenharmony_ci mult64 = lodX64 * lodY64; 248cb93a386Sopenharmony_ci if (mult64 > SK_MaxS32) { 249cb93a386Sopenharmony_ci return nullptr; 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci // Treat null interpolation space as sRGB. 253cb93a386Sopenharmony_ci if (!colorSpace) { 254cb93a386Sopenharmony_ci colorSpace = sk_srgb_singleton(); 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci int vertexCount = SkToS32(mult64); 258cb93a386Sopenharmony_ci // it is recommended to generate draw calls of no more than 65536 indices, so we never generate 259cb93a386Sopenharmony_ci // more than 60000 indices. To accomplish that we resize the LOD and vertex count 260cb93a386Sopenharmony_ci if (vertexCount > 10000 || lodX > 200 || lodY > 200) { 261cb93a386Sopenharmony_ci float weightX = static_cast<float>(lodX) / (lodX + lodY); 262cb93a386Sopenharmony_ci float weightY = static_cast<float>(lodY) / (lodX + lodY); 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of 265cb93a386Sopenharmony_ci // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6) 266cb93a386Sopenharmony_ci // Need a min of 1 since we later divide by lod 267cb93a386Sopenharmony_ci lodX = std::max(1, sk_float_floor2int_no_saturate(weightX * 200)); 268cb93a386Sopenharmony_ci lodY = std::max(1, sk_float_floor2int_no_saturate(weightY * 200)); 269cb93a386Sopenharmony_ci vertexCount = (lodX + 1) * (lodY + 1); 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci const int indexCount = lodX * lodY * 6; 272cb93a386Sopenharmony_ci uint32_t flags = 0; 273cb93a386Sopenharmony_ci if (srcTexCoords) { 274cb93a386Sopenharmony_ci flags |= SkVertices::kHasTexCoords_BuilderFlag; 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci if (srcColors) { 277cb93a386Sopenharmony_ci flags |= SkVertices::kHasColors_BuilderFlag; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci SkSTArenaAlloc<2048> alloc; 281cb93a386Sopenharmony_ci SkPMColor4f* cornerColors = srcColors ? alloc.makeArray<SkPMColor4f>(4) : nullptr; 282cb93a386Sopenharmony_ci SkPMColor4f* tmpColors = srcColors ? alloc.makeArray<SkPMColor4f>(vertexCount) : nullptr; 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vertexCount, indexCount, flags); 285cb93a386Sopenharmony_ci SkPoint* pos = builder.positions(); 286cb93a386Sopenharmony_ci SkPoint* texs = builder.texCoords(); 287cb93a386Sopenharmony_ci uint16_t* indices = builder.indices(); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci if (cornerColors) { 290cb93a386Sopenharmony_ci skcolor_to_float(cornerColors, srcColors, kNumCorners, colorSpace); 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci SkPoint pts[kNumPtsCubic]; 294cb93a386Sopenharmony_ci SkPatchUtils::GetBottomCubic(cubics, pts); 295cb93a386Sopenharmony_ci FwDCubicEvaluator fBottom(pts); 296cb93a386Sopenharmony_ci SkPatchUtils::GetTopCubic(cubics, pts); 297cb93a386Sopenharmony_ci FwDCubicEvaluator fTop(pts); 298cb93a386Sopenharmony_ci SkPatchUtils::GetLeftCubic(cubics, pts); 299cb93a386Sopenharmony_ci FwDCubicEvaluator fLeft(pts); 300cb93a386Sopenharmony_ci SkPatchUtils::GetRightCubic(cubics, pts); 301cb93a386Sopenharmony_ci FwDCubicEvaluator fRight(pts); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci fBottom.restart(lodX); 304cb93a386Sopenharmony_ci fTop.restart(lodX); 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_ci SkScalar u = 0.0f; 307cb93a386Sopenharmony_ci int stride = lodY + 1; 308cb93a386Sopenharmony_ci for (int x = 0; x <= lodX; x++) { 309cb93a386Sopenharmony_ci SkPoint bottom = fBottom.next(), top = fTop.next(); 310cb93a386Sopenharmony_ci fLeft.restart(lodY); 311cb93a386Sopenharmony_ci fRight.restart(lodY); 312cb93a386Sopenharmony_ci SkScalar v = 0.f; 313cb93a386Sopenharmony_ci for (int y = 0; y <= lodY; y++) { 314cb93a386Sopenharmony_ci int dataIndex = x * (lodY + 1) + y; 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci SkPoint left = fLeft.next(), right = fRight.next(); 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(), 319cb93a386Sopenharmony_ci (1.0f - v) * top.y() + v * bottom.y()); 320cb93a386Sopenharmony_ci SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(), 321cb93a386Sopenharmony_ci (1.0f - u) * left.y() + u * right.y()); 322cb93a386Sopenharmony_ci SkPoint s2 = SkPoint::Make( 323cb93a386Sopenharmony_ci (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x() 324cb93a386Sopenharmony_ci + u * fTop.getCtrlPoints()[3].x()) 325cb93a386Sopenharmony_ci + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x() 326cb93a386Sopenharmony_ci + u * fBottom.getCtrlPoints()[3].x()), 327cb93a386Sopenharmony_ci (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y() 328cb93a386Sopenharmony_ci + u * fTop.getCtrlPoints()[3].y()) 329cb93a386Sopenharmony_ci + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y() 330cb93a386Sopenharmony_ci + u * fBottom.getCtrlPoints()[3].y())); 331cb93a386Sopenharmony_ci pos[dataIndex] = s0 + s1 - s2; 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci if (cornerColors) { 334cb93a386Sopenharmony_ci bilerp(u, v, Sk4f::Load(cornerColors[kTopLeft_Corner].vec()), 335cb93a386Sopenharmony_ci Sk4f::Load(cornerColors[kTopRight_Corner].vec()), 336cb93a386Sopenharmony_ci Sk4f::Load(cornerColors[kBottomLeft_Corner].vec()), 337cb93a386Sopenharmony_ci Sk4f::Load(cornerColors[kBottomRight_Corner].vec())) 338cb93a386Sopenharmony_ci .store(tmpColors[dataIndex].vec()); 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci if (texs) { 342cb93a386Sopenharmony_ci texs[dataIndex] = SkPoint::Make(bilerp(u, v, srcTexCoords[kTopLeft_Corner].x(), 343cb93a386Sopenharmony_ci srcTexCoords[kTopRight_Corner].x(), 344cb93a386Sopenharmony_ci srcTexCoords[kBottomLeft_Corner].x(), 345cb93a386Sopenharmony_ci srcTexCoords[kBottomRight_Corner].x()), 346cb93a386Sopenharmony_ci bilerp(u, v, srcTexCoords[kTopLeft_Corner].y(), 347cb93a386Sopenharmony_ci srcTexCoords[kTopRight_Corner].y(), 348cb93a386Sopenharmony_ci srcTexCoords[kBottomLeft_Corner].y(), 349cb93a386Sopenharmony_ci srcTexCoords[kBottomRight_Corner].y())); 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci if(x < lodX && y < lodY) { 354cb93a386Sopenharmony_ci int i = 6 * (x * lodY + y); 355cb93a386Sopenharmony_ci indices[i] = x * stride + y; 356cb93a386Sopenharmony_ci indices[i + 1] = x * stride + 1 + y; 357cb93a386Sopenharmony_ci indices[i + 2] = (x + 1) * stride + 1 + y; 358cb93a386Sopenharmony_ci indices[i + 3] = indices[i]; 359cb93a386Sopenharmony_ci indices[i + 4] = indices[i + 2]; 360cb93a386Sopenharmony_ci indices[i + 5] = (x + 1) * stride + y; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci v = SkTPin(v + 1.f / lodY, 0.0f, 1.0f); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci u = SkTPin(u + 1.f / lodX, 0.0f, 1.0f); 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci if (tmpColors) { 368cb93a386Sopenharmony_ci float_to_skcolor(builder.colors(), tmpColors, vertexCount, colorSpace); 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci return builder.detach(); 371cb93a386Sopenharmony_ci} 372