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