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