OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkNinePatchIter.h" | 8 #include "SkNinePatchIter.h" |
9 #include "SkRect.h" | 9 #include "SkRect.h" |
10 | 10 |
| 11 /** |
| 12 * Divs must be in increasing order with no duplicates. |
| 13 */ |
| 14 static bool valid_divs(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 SkNinePatchIter::Valid(int width, int height, const SkCanvas::NinePatchDivs
& divs) { |
| 30 return valid_divs(divs.fXDivs, divs.fXCount, width) && |
| 31 valid_divs(divs.fYDivs, divs.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, int* divs, int divCount, int srcF
ixed, |
| 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 SkNinePatchIter::SkNinePatchIter(int srcWidth, int srcHeight, const SkCanvas::Ni
nePatchDivs& divs, |
| 104 const SkRect& dst) |
| 105 { |
| 106 int* xDivs = divs.fXDivs; |
| 107 int xCount = divs.fXCount; |
| 108 int* yDivs = divs.fYDivs; |
| 109 int yCount = divs.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 |
11 bool SkNinePatchIter::Valid(int width, int height, const SkIRect& center) { | 164 bool SkNinePatchIter::Valid(int width, int height, const SkIRect& center) { |
12 return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center); | 165 return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center); |
13 } | 166 } |
14 | 167 |
15 SkNinePatchIter::SkNinePatchIter(int w, int h, const SkIRect& c, const SkRect& d
st) { | 168 SkNinePatchIter::SkNinePatchIter(int w, int h, const SkIRect& c, const SkRect& d
st) { |
16 SkASSERT(SkIRect::MakeWH(w, h).contains(c)); | 169 SkASSERT(SkIRect::MakeWH(w, h).contains(c)); |
17 | 170 |
| 171 fSrcX.reset(4); |
| 172 fSrcY.reset(4); |
| 173 fDstX.reset(4); |
| 174 fDstY.reset(4); |
| 175 |
18 fSrcX[0] = 0; | 176 fSrcX[0] = 0; |
19 fSrcX[1] = SkIntToScalar(c.fLeft); | 177 fSrcX[1] = SkIntToScalar(c.fLeft); |
20 fSrcX[2] = SkIntToScalar(c.fRight); | 178 fSrcX[2] = SkIntToScalar(c.fRight); |
21 fSrcX[3] = SkIntToScalar(w); | 179 fSrcX[3] = SkIntToScalar(w); |
22 | 180 |
23 fSrcY[0] = 0; | 181 fSrcY[0] = 0; |
24 fSrcY[1] = SkIntToScalar(c.fTop); | 182 fSrcY[1] = SkIntToScalar(c.fTop); |
25 fSrcY[2] = SkIntToScalar(c.fBottom); | 183 fSrcY[2] = SkIntToScalar(c.fBottom); |
26 fSrcY[3] = SkIntToScalar(h); | 184 fSrcY[3] = SkIntToScalar(h); |
27 | 185 |
(...skipping 21 matching lines...) Expand all Loading... |
49 fDone = false; | 207 fDone = false; |
50 } | 208 } |
51 | 209 |
52 bool SkNinePatchIter::next(SkRect* src, SkRect* dst) { | 210 bool SkNinePatchIter::next(SkRect* src, SkRect* dst) { |
53 if (fDone) { | 211 if (fDone) { |
54 return false; | 212 return false; |
55 } | 213 } |
56 | 214 |
57 const int x = fCurrX; | 215 const int x = fCurrX; |
58 const int y = fCurrY; | 216 const int y = fCurrY; |
59 SkASSERT(x >= 0 && x < 3); | 217 SkASSERT(x >= 0 && x < fSrcX.count() - 1); |
60 SkASSERT(y >= 0 && y < 3); | 218 SkASSERT(y >= 0 && y < fSrcY.count() - 1); |
61 | 219 |
62 src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]); | 220 src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]); |
63 dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]); | 221 dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]); |
64 if (3 == ++fCurrX) { | 222 if (fSrcX.count() - 1 == ++fCurrX) { |
65 fCurrX = 0; | 223 fCurrX = 0; |
66 fCurrY += 1; | 224 fCurrY += 1; |
67 if (fCurrY >= 3) { | 225 if (fCurrY >= fSrcY.count() - 1) { |
68 fDone = true; | 226 fDone = true; |
69 } | 227 } |
70 } | 228 } |
71 return true; | 229 return true; |
72 } | 230 } |
OLD | NEW |