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