Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: src/utils/SkNinePatch.cpp

Issue 2206663002: Delete SkNinePatch (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Keep in gypi Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/utils/SkNinePatch.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
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
8
9 #include "SkNinePatch.h"
10 #include "SkCanvas.h"
11 #include "SkShader.h"
12
13 static const uint16_t g3x3Indices[] = {
14 0, 5, 1, 0, 4, 5,
15 1, 6, 2, 1, 5, 6,
16 2, 7, 3, 2, 6, 7,
17
18 4, 9, 5, 4, 8, 9,
19 5, 10, 6, 5, 9, 10,
20 6, 11, 7, 6, 10, 11,
21
22 8, 13, 9, 8, 12, 13,
23 9, 14, 10, 9, 13, 14,
24 10, 15, 11, 10, 14, 15
25 };
26
27 static int fillIndices(uint16_t indices[], int xCount, int yCount) {
28 uint16_t* startIndices = indices;
29
30 int n = 0;
31 for (int y = 0; y < yCount; y++) {
32 for (int x = 0; x < xCount; x++) {
33 *indices++ = n;
34 *indices++ = n + xCount + 2;
35 *indices++ = n + 1;
36
37 *indices++ = n;
38 *indices++ = n + xCount + 1;
39 *indices++ = n + xCount + 2;
40
41 n += 1;
42 }
43 n += 1;
44 }
45 return static_cast<int>(indices - startIndices);
46 }
47
48 // Computes the delta between vertices along a single axis
49 static SkScalar computeVertexDelta(bool isStretchyVertex,
50 SkScalar currentVertex,
51 SkScalar prevVertex,
52 SkScalar stretchFactor) {
53 // the standard delta between vertices if no stretching is required
54 SkScalar delta = currentVertex - prevVertex;
55
56 // if the stretch factor is negative or zero we need to shrink the 9-patch
57 // to fit within the target bounds. This means that we will eliminate all
58 // stretchy areas and scale the fixed areas to fit within the target bounds.
59 if (stretchFactor <= 0) {
60 if (isStretchyVertex)
61 delta = 0; // collapse stretchable areas
62 else
63 delta = SkScalarMul(delta, -stretchFactor); // scale fixed areas
64 // if the stretch factor is positive then we use the standard delta for
65 // fixed and scale the stretchable areas to fill the target bounds.
66 } else if (isStretchyVertex) {
67 delta = SkScalarMul(delta, stretchFactor);
68 }
69
70 return delta;
71 }
72
73 static void fillRow(SkPoint verts[], SkPoint texs[],
74 const SkScalar vy, const SkScalar ty,
75 const SkRect& bounds, const int32_t xDivs[], int numXDivs,
76 const SkScalar stretchX, int width) {
77 SkScalar vx = bounds.fLeft;
78 verts->set(vx, vy); verts++;
79 texs->set(0, ty); texs++;
80
81 SkScalar prev = 0;
82 for (int x = 0; x < numXDivs; x++) {
83
84 const SkScalar tx = SkIntToScalar(xDivs[x]);
85 vx += computeVertexDelta(x & 1, tx, prev, stretchX);
86 prev = tx;
87
88 verts->set(vx, vy); verts++;
89 texs->set(tx, ty); texs++;
90 }
91 verts->set(bounds.fRight, vy); verts++;
92 texs->set(SkIntToScalar(width), ty); texs++;
93 }
94
95 struct Mesh {
96 const SkPoint* fVerts;
97 const SkPoint* fTexs;
98 const SkColor* fColors;
99 const uint16_t* fIndices;
100 };
101
102 void SkNinePatch::DrawMesh(SkCanvas* canvas, const SkRect& bounds,
103 const SkBitmap& bitmap,
104 const int32_t xDivs[], int numXDivs,
105 const int32_t yDivs[], int numYDivs,
106 const SkPaint* paint) {
107 if (bounds.isEmpty() || bitmap.width() == 0 || bitmap.height() == 0) {
108 return;
109 }
110
111 // should try a quick-reject test before calling lockPixels
112 SkAutoLockPixels alp(bitmap);
113 // after the lock, it is valid to check
114 if (!bitmap.readyToDraw()) {
115 return;
116 }
117
118 // check for degenerate divs (just an optimization, not required)
119 {
120 int i;
121 int zeros = 0;
122 for (i = 0; i < numYDivs && yDivs[i] == 0; i++) {
123 zeros += 1;
124 }
125 numYDivs -= zeros;
126 yDivs += zeros;
127 for (i = numYDivs - 1; i >= 0 && yDivs[i] == bitmap.height(); --i) {
128 numYDivs -= 1;
129 }
130 }
131
132 Mesh mesh;
133
134 const int numXStretch = (numXDivs + 1) >> 1;
135 const int numYStretch = (numYDivs + 1) >> 1;
136
137 if (numXStretch < 1 && numYStretch < 1) {
138 canvas->drawBitmapRect(bitmap, bounds, paint);
139 return;
140 }
141
142 if (false) {
143 int i;
144 for (i = 0; i < numXDivs; i++) {
145 SkDebugf("--- xdivs[%d] %d\n", i, xDivs[i]);
146 }
147 for (i = 0; i < numYDivs; i++) {
148 SkDebugf("--- ydivs[%d] %d\n", i, yDivs[i]);
149 }
150 }
151
152 SkScalar stretchX = 0, stretchY = 0;
153
154 if (numXStretch > 0) {
155 int stretchSize = 0;
156 for (int i = 1; i < numXDivs; i += 2) {
157 stretchSize += xDivs[i] - xDivs[i-1];
158 }
159 const SkScalar fixed = SkIntToScalar(bitmap.width() - stretchSize);
160 if (bounds.width() >= fixed)
161 stretchX = (bounds.width() - fixed) / stretchSize;
162 else // reuse stretchX, but keep it negative as a signal
163 stretchX = -bounds.width() / fixed;
164 }
165
166 if (numYStretch > 0) {
167 int stretchSize = 0;
168 for (int i = 1; i < numYDivs; i += 2) {
169 stretchSize += yDivs[i] - yDivs[i-1];
170 }
171 const SkScalar fixed = SkIntToScalar(bitmap.height() - stretchSize);
172 if (bounds.height() >= fixed)
173 stretchY = (bounds.height() - fixed) / stretchSize;
174 else // reuse stretchX, but keep it negative as a signal
175 stretchY = -bounds.height() / fixed;
176 }
177
178 #if 0
179 SkDebugf("---- drawasamesh [%d %d] -> [%g %g] <%d %d> (%g %g)\n",
180 bitmap.width(), bitmap.height(),
181 SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
182 numXDivs + 1, numYDivs + 1,
183 SkScalarToFloat(stretchX), SkScalarToFloat(stretchY));
184 #endif
185
186 const int vCount = (numXDivs + 2) * (numYDivs + 2);
187 // number of celss * 2 (tris per cell) * 3 (verts per tri)
188 const int indexCount = (numXDivs + 1) * (numYDivs + 1) * 2 * 3;
189 // allocate 2 times, one for verts, one for texs, plus indices
190 SkAutoMalloc storage(vCount * sizeof(SkPoint) * 2 +
191 indexCount * sizeof(uint16_t));
192 SkPoint* verts = (SkPoint*)storage.get();
193 SkPoint* texs = verts + vCount;
194 uint16_t* indices = (uint16_t*)(texs + vCount);
195
196 mesh.fVerts = verts;
197 mesh.fTexs = texs;
198 mesh.fColors = nullptr;
199 mesh.fIndices = nullptr;
200
201 // we use <= for YDivs, since the prebuild indices work for 3x2 and 3x1 too
202 if (numXDivs == 2 && numYDivs <= 2) {
203 mesh.fIndices = g3x3Indices;
204 } else {
205 SkDEBUGCODE(int n =) fillIndices(indices, numXDivs + 1, numYDivs + 1);
206 SkASSERT(n == indexCount);
207 mesh.fIndices = indices;
208 }
209
210 SkScalar vy = bounds.fTop;
211 fillRow(verts, texs, vy, 0, bounds, xDivs, numXDivs,
212 stretchX, bitmap.width());
213 verts += numXDivs + 2;
214 texs += numXDivs + 2;
215 for (int y = 0; y < numYDivs; y++) {
216 const SkScalar ty = SkIntToScalar(yDivs[y]);
217 if (stretchY >= 0) {
218 if (y & 1) {
219 vy += stretchY;
220 } else {
221 vy += ty;
222 }
223 } else { // shrink fixed sections, and collaps stretchy sections
224 if (y & 1) {
225 ;// do nothing
226 } else {
227 vy += SkScalarMul(ty, -stretchY);
228 }
229 }
230 fillRow(verts, texs, vy, ty, bounds, xDivs, numXDivs,
231 stretchX, bitmap.width());
232 verts += numXDivs + 2;
233 texs += numXDivs + 2;
234 }
235 fillRow(verts, texs, bounds.fBottom, SkIntToScalar(bitmap.height()),
236 bounds, xDivs, numXDivs, stretchX, bitmap.width());
237
238 SkPaint p;
239 if (paint) {
240 p = *paint;
241 }
242 p.setShader(SkShader::MakeBitmapShader(bitmap,
243 SkShader::kClamp_TileMode,
244 SkShader::kClamp_TileMode));
245 canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vCount,
246 mesh.fVerts, mesh.fTexs, mesh.fColors, nullptr,
247 mesh.fIndices, indexCount, p);
248 }
249
250 ///////////////////////////////////////////////////////////////////////////////
251
252 static void drawNineViaRects(SkCanvas* canvas, const SkRect& dst,
253 const SkBitmap& bitmap, const SkIRect& margins,
254 const SkPaint* paint) {
255 const int32_t srcX[4] = {
256 0, margins.fLeft, bitmap.width() - margins.fRight, bitmap.width()
257 };
258 const int32_t srcY[4] = {
259 0, margins.fTop, bitmap.height() - margins.fBottom, bitmap.height()
260 };
261 SkScalar dstX[4] = {
262 dst.fLeft, dst.fLeft + SkIntToScalar(margins.fLeft),
263 dst.fRight - SkIntToScalar(margins.fRight), dst.fRight
264 };
265 SkScalar dstY[4] = {
266 dst.fTop, dst.fTop + SkIntToScalar(margins.fTop),
267 dst.fBottom - SkIntToScalar(margins.fBottom), dst.fBottom
268 };
269
270 if (dstX[1] > dstX[2]) {
271 dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * SkIntToScalar(margins.fLeft) /
272 (SkIntToScalar(margins.fLeft) + SkIntToScalar(margins.fRight));
273 dstX[2] = dstX[1];
274 }
275
276 if (dstY[1] > dstY[2]) {
277 dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * SkIntToScalar(margins.fTop) /
278 (SkIntToScalar(margins.fTop) + SkIntToScalar(margins.fBottom));
279 dstY[2] = dstY[1];
280 }
281
282 SkIRect s;
283 SkRect d;
284 for (int y = 0; y < 3; y++) {
285 s.fTop = srcY[y];
286 s.fBottom = srcY[y+1];
287 d.fTop = dstY[y];
288 d.fBottom = dstY[y+1];
289 for (int x = 0; x < 3; x++) {
290 s.fLeft = srcX[x];
291 s.fRight = srcX[x+1];
292 d.fLeft = dstX[x];
293 d.fRight = dstX[x+1];
294 canvas->drawBitmapRect(bitmap, s, d, paint);
295 }
296 }
297 }
298
299 void SkNinePatch::DrawNine(SkCanvas* canvas, const SkRect& bounds,
300 const SkBitmap& bitmap, const SkIRect& margins,
301 const SkPaint* paint) {
302 /** Our vertices code has numerical precision problems if the transformed
303 coordinates land directly on a 1/2 pixel boundary. To work around that
304 for now, we only take the vertices case if we are in opengl. Also,
305 when not in GL, the vertices impl is slower (more math) than calling
306 the viaRects code.
307 */
308 if (false /* is our canvas backed by a gpu?*/) {
309 int32_t xDivs[2];
310 int32_t yDivs[2];
311
312 xDivs[0] = margins.fLeft;
313 xDivs[1] = bitmap.width() - margins.fRight;
314 yDivs[0] = margins.fTop;
315 yDivs[1] = bitmap.height() - margins.fBottom;
316
317 if (xDivs[0] > xDivs[1]) {
318 xDivs[0] = bitmap.width() * margins.fLeft /
319 (margins.fLeft + margins.fRight);
320 xDivs[1] = xDivs[0];
321 }
322 if (yDivs[0] > yDivs[1]) {
323 yDivs[0] = bitmap.height() * margins.fTop /
324 (margins.fTop + margins.fBottom);
325 yDivs[1] = yDivs[0];
326 }
327
328 SkNinePatch::DrawMesh(canvas, bounds, bitmap,
329 xDivs, 2, yDivs, 2, paint);
330 } else {
331 drawNineViaRects(canvas, bounds, bitmap, margins, paint);
332 }
333 }
OLDNEW
« no previous file with comments | « include/utils/SkNinePatch.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698