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.fRectTypes) { 170 fRectTypes.push_back_n(fNumRectsInLattice); 171 fColors.push_back_n(fNumRectsInLattice); 172 173 const SkCanvas::Lattice::RectType* flags = lattice.fRectTypes; 174 const SkColor* colors = lattice.fColors; 175 176 bool hasPadRow = (yCount != origYCount); 177 bool hasPadCol = (xCount != origXCount); 178 if (hasPadRow) { 179 // The first row of rects are all empty, skip the first row of flags. 180 flags += origXCount + 1; 181 colors += origXCount + 1; 182 } 183 184 int i = 0; 185 for (int y = 0; y < yCount + 1; y++) { 186 for (int x = 0; x < origXCount + 1; x++) { 187 if (0 == x && hasPadCol) { 188 // The first column of rects are all empty. Skip a rect. 189 flags++; 190 colors++; 191 continue; 192 } 193 194 fRectTypes[i] = *flags; 195 fColors[i] = SkCanvas::Lattice::kFixedColor == *flags ? *colors : 0; 196 flags++; 197 colors++; 198 i++; 199 } 200 } 201 202 for (int j = 0; j < fRectTypes.count(); j++) { 203 if (SkCanvas::Lattice::kTransparent == fRectTypes[j]) { 204 fNumRectsToDraw--; 205 } 206 } 207 } 208 } 209 210 bool SkLatticeIter::Valid(int width, int height, const SkIRect& center) { 211 return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center); 212 } 213 214 SkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst) { 215 SkASSERT(SkIRect::MakeWH(w, h).contains(c)); 216 217 fSrcX.reset(4); 218 fSrcY.reset(4); 219 fDstX.reset(4); 220 fDstY.reset(4); 221 222 fSrcX[0] = 0; 223 fSrcX[1] = SkIntToScalar(c.fLeft); 224 fSrcX[2] = SkIntToScalar(c.fRight); 225 fSrcX[3] = SkIntToScalar(w); 226 227 fSrcY[0] = 0; 228 fSrcY[1] = SkIntToScalar(c.fTop); 229 fSrcY[2] = SkIntToScalar(c.fBottom); 230 fSrcY[3] = SkIntToScalar(h); 231 232 fDstX[0] = dst.fLeft; 233 fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft); 234 fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight); 235 fDstX[3] = dst.fRight; 236 237 fDstY[0] = dst.fTop; 238 fDstY[1] = dst.fTop + SkIntToScalar(c.fTop); 239 fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom); 240 fDstY[3] = dst.fBottom; 241 242 if (fDstX[1] > fDstX[2]) { 243 fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width()); 244 fDstX[2] = fDstX[1]; 245 } 246 247 if (fDstY[1] > fDstY[2]) { 248 fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height()); 249 fDstY[2] = fDstY[1]; 250 } 251 252 fCurrX = fCurrY = 0; 253 fNumRectsInLattice = 9; 254 fNumRectsToDraw = 9; 255 } 256 257 bool SkLatticeIter::next(SkRect* src, SkRect* dst, bool* isFixedColor, SkColor* fixedColor) { 258 int currRect = fCurrX + fCurrY * (fSrcX.count() - 1); 259 if (currRect == fNumRectsInLattice) { 260 return false; 261 } 262 263 const int x = fCurrX; 264 const int y = fCurrY; 265 SkASSERT(x >= 0 && x < fSrcX.count() - 1); 266 SkASSERT(y >= 0 && y < fSrcY.count() - 1); 267 268 if (fSrcX.count() - 1 == ++fCurrX) { 269 fCurrX = 0; 270 fCurrY += 1; 271 } 272 273 if (fRectTypes.count() > 0 274 && SkToBool(SkCanvas::Lattice::kTransparent == fRectTypes[currRect])) { 275 return this->next(src, dst, isFixedColor, fixedColor); 276 } 277 278 src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]); 279 dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]); 280 if (isFixedColor && fixedColor) { 281 *isFixedColor = fRectTypes.count() > 0 282 && SkToBool(SkCanvas::Lattice::kFixedColor == fRectTypes[currRect]); 283 if (*isFixedColor) { 284 *fixedColor = fColors[currRect]; 285 } 286 } 287 return true; 288 } 289 290 void SkLatticeIter::mapDstScaleTranslate(const SkMatrix& matrix) { 291 SkASSERT(matrix.isScaleTranslate()); 292 SkScalar tx = matrix.getTranslateX(); 293 SkScalar sx = matrix.getScaleX(); 294 for (int i = 0; i < fDstX.count(); i++) { 295 fDstX[i] = fDstX[i] * sx + tx; 296 } 297 298 SkScalar ty = matrix.getTranslateY(); 299 SkScalar sy = matrix.getScaleY(); 300 for (int i = 0; i < fDstY.count(); i++) { 301 fDstY[i] = fDstY[i] * sy + ty; 302 } 303 } 304