OLD | NEW |
(Empty) | |
| 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 len) { |
| 15 if (count <= 0) { |
| 16 return false; |
| 17 } |
| 18 |
| 19 int prev = -1; |
| 20 for (int i = 0; i < count; i++) { |
| 21 if (prev >= divs[i] || divs[i] > len) { |
| 22 return false; |
| 23 } |
| 24 } |
| 25 |
| 26 return true; |
| 27 } |
| 28 |
| 29 bool SkLatticeIter::Valid(int width, int height, const SkCanvas::Lattice& lattic
e) { |
| 30 return valid_divs(lattice.fXDivs, lattice.fXCount, width) && |
| 31 valid_divs(lattice.fYDivs, lattice.fYCount, height); |
| 32 } |
| 33 |
| 34 /** |
| 35 * Count the number of pixels that are in "scalable" patches. |
| 36 */ |
| 37 static int count_scalable_pixels(const int32_t* divs, int numDivs, bool firstIsS
calable, |
| 38 int length) { |
| 39 if (0 == numDivs) { |
| 40 return firstIsScalable ? length : 0; |
| 41 } |
| 42 |
| 43 int i; |
| 44 int count; |
| 45 if (firstIsScalable) { |
| 46 count = divs[0]; |
| 47 i = 1; |
| 48 } else { |
| 49 count = 0; |
| 50 i = 0; |
| 51 } |
| 52 |
| 53 for (; i < numDivs; i += 2) { |
| 54 // Alternatively, we could use |top| and |bottom| as variable names, ins
tead of |
| 55 // |left| and |right|. |
| 56 int left = divs[i]; |
| 57 int right = (i + 1 < numDivs) ? divs[i + 1] : length; |
| 58 count += right - left; |
| 59 } |
| 60 |
| 61 return count; |
| 62 } |
| 63 |
| 64 /** |
| 65 * Set points for the src and dst rects on subsequent draw calls. |
| 66 */ |
| 67 static void set_points(float* dst, float* src, const int* divs, int divCount, in
t srcFixed, |
| 68 int srcScalable, float dstStart, float dstStop, bool isSc
alable) { |
| 69 |
| 70 float dstLen = dstStop - dstStart; |
| 71 int srcLen = srcFixed + srcScalable; |
| 72 float scale; |
| 73 if (srcFixed <= dstLen) { |
| 74 // This is the "normal" case, where we scale the "scalable" patches and
leave |
| 75 // the other patches fixed. |
| 76 scale = (dstLen - ((float) srcFixed)) / ((float) srcScalable); |
| 77 } else { |
| 78 // In this case, we eliminate the "scalable" patches and scale the "fixe
d" patches. |
| 79 scale = dstLen / ((float) srcFixed); |
| 80 } |
| 81 |
| 82 src[0] = 0.0f; |
| 83 dst[0] = dstStart; |
| 84 for (int i = 0; i < divCount; i++) { |
| 85 src[i + 1] = (float) (divs[i]); |
| 86 float srcDelta = src[i + 1] - src[i]; |
| 87 float dstDelta; |
| 88 if (srcFixed <= dstLen) { |
| 89 dstDelta = isScalable ? scale * srcDelta : srcDelta; |
| 90 } else { |
| 91 dstDelta = isScalable ? 0.0f : scale * srcDelta; |
| 92 } |
| 93 dst[i + 1] = dst[i] + dstDelta; |
| 94 |
| 95 // Alternate between "scalable" and "fixed" patches. |
| 96 isScalable = !isScalable; |
| 97 } |
| 98 |
| 99 src[divCount + 1] = (float) srcLen; |
| 100 dst[divCount + 1] = dstStop; |
| 101 } |
| 102 |
| 103 SkLatticeIter::SkLatticeIter(int srcWidth, int srcHeight, const SkCanvas::Lattic
e& lattice, |
| 104 const SkRect& dst) |
| 105 { |
| 106 const int* xDivs = lattice.fXDivs; |
| 107 int xCount = lattice.fXCount; |
| 108 const int* yDivs = lattice.fYDivs; |
| 109 int yCount = lattice.fYCount; |
| 110 |
| 111 // In the x-dimension, the first rectangle always starts at x = 0 and is "sc
alable". |
| 112 // If xDiv[0] is 0, it indicates that the first rectangle is degenerate, so
the |
| 113 // first real rectangle "scalable" in the x-direction. |
| 114 // |
| 115 // The same interpretation applies to the y-dimension. |
| 116 // |
| 117 // As we move left to right across the image, alternating patches will be "f
ixed" or |
| 118 // "scalable" in the x-direction. Similarly, as move top to bottom, alterna
ting |
| 119 // patches will be "fixed" or "scalable" in the y-direction. |
| 120 SkASSERT(xCount > 0 && yCount > 0); |
| 121 bool xIsScalable = (0 == xDivs[0]); |
| 122 if (xIsScalable) { |
| 123 // Once we've decided that the first patch is "scalable", we don't need
the |
| 124 // xDiv. It is always implied that we start at zero. |
| 125 xDivs++; |
| 126 xCount--; |
| 127 } |
| 128 bool yIsScalable = (0 == yDivs[0]); |
| 129 if (yIsScalable) { |
| 130 // Once we've decided that the first patch is "scalable", we don't need
the |
| 131 // yDiv. It is always implied that we start at zero. |
| 132 yDivs++; |
| 133 yCount--; |
| 134 } |
| 135 |
| 136 // We never need the final xDiv/yDiv if it is equal to the width/height. Th
is is implied. |
| 137 if (xCount > 0 && srcWidth == xDivs[xCount - 1]) { |
| 138 xCount--; |
| 139 } |
| 140 if (yCount > 0 && srcHeight == yDivs[yCount - 1]) { |
| 141 yCount--; |
| 142 } |
| 143 |
| 144 // Count "scalable" and "fixed" pixels in each dimension. |
| 145 int xCountScalable = count_scalable_pixels(xDivs, xCount, xIsScalable, srcWi
dth); |
| 146 int xCountFixed = srcWidth - xCountScalable; |
| 147 int yCountScalable = count_scalable_pixels(yDivs, yCount, yIsScalable, srcHe
ight); |
| 148 int yCountFixed = srcHeight - yCountScalable; |
| 149 |
| 150 fSrcX.reset(xCount + 2); |
| 151 fDstX.reset(xCount + 2); |
| 152 set_points(fDstX.begin(), fSrcX.begin(), xDivs, xCount, xCountFixed, xCountS
calable, |
| 153 dst.fLeft, dst.fRight, xIsScalable); |
| 154 |
| 155 fSrcY.reset(yCount + 2); |
| 156 fDstY.reset(yCount + 2); |
| 157 set_points(fDstY.begin(), fSrcY.begin(), yDivs, yCount, yCountFixed, yCountS
calable, |
| 158 dst.fTop, dst.fBottom, yIsScalable); |
| 159 |
| 160 fCurrX = fCurrY = 0; |
| 161 fDone = false; |
| 162 } |
| 163 |
| 164 bool SkLatticeIter::Valid(int width, int height, const SkIRect& center) { |
| 165 return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center); |
| 166 } |
| 167 |
| 168 SkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst)
{ |
| 169 SkASSERT(SkIRect::MakeWH(w, h).contains(c)); |
| 170 |
| 171 fSrcX.reset(4); |
| 172 fSrcY.reset(4); |
| 173 fDstX.reset(4); |
| 174 fDstY.reset(4); |
| 175 |
| 176 fSrcX[0] = 0; |
| 177 fSrcX[1] = SkIntToScalar(c.fLeft); |
| 178 fSrcX[2] = SkIntToScalar(c.fRight); |
| 179 fSrcX[3] = SkIntToScalar(w); |
| 180 |
| 181 fSrcY[0] = 0; |
| 182 fSrcY[1] = SkIntToScalar(c.fTop); |
| 183 fSrcY[2] = SkIntToScalar(c.fBottom); |
| 184 fSrcY[3] = SkIntToScalar(h); |
| 185 |
| 186 fDstX[0] = dst.fLeft; |
| 187 fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft); |
| 188 fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight); |
| 189 fDstX[3] = dst.fRight; |
| 190 |
| 191 fDstY[0] = dst.fTop; |
| 192 fDstY[1] = dst.fTop + SkIntToScalar(c.fTop); |
| 193 fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom); |
| 194 fDstY[3] = dst.fBottom; |
| 195 |
| 196 if (fDstX[1] > fDstX[2]) { |
| 197 fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width()); |
| 198 fDstX[2] = fDstX[1]; |
| 199 } |
| 200 |
| 201 if (fDstY[1] > fDstY[2]) { |
| 202 fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height()); |
| 203 fDstY[2] = fDstY[1]; |
| 204 } |
| 205 |
| 206 fCurrX = fCurrY = 0; |
| 207 fDone = false; |
| 208 } |
| 209 |
| 210 bool SkLatticeIter::next(SkRect* src, SkRect* dst) { |
| 211 if (fDone) { |
| 212 return false; |
| 213 } |
| 214 |
| 215 const int x = fCurrX; |
| 216 const int y = fCurrY; |
| 217 SkASSERT(x >= 0 && x < fSrcX.count() - 1); |
| 218 SkASSERT(y >= 0 && y < fSrcY.count() - 1); |
| 219 |
| 220 src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]); |
| 221 dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]); |
| 222 if (fSrcX.count() - 1 == ++fCurrX) { |
| 223 fCurrX = 0; |
| 224 fCurrY += 1; |
| 225 if (fCurrY >= fSrcY.count() - 1) { |
| 226 fDone = true; |
| 227 } |
| 228 } |
| 229 return true; |
| 230 } |
OLD | NEW |