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

Side by Side Diff: tests/PathOpsExtendedTest.cpp

Issue 13094010: Add implementation of path ops (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « tests/PathOpsExtendedTest.h ('k') | tests/PathOpsOpCubicThreadedTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2012 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 "PathOpsExtendedTest.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkMatrix.h"
12 #include "SkPaint.h"
13 #include "SkStream.h"
14
15 #include <algorithm>
16 #include <errno.h>
17 #include <pthread.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/sysctl.h>
21
22 bool gShowTestProgress = false;
23 bool gAllowExtendedTest = false;
24
25 static const char marker[] =
26 "</div>\n"
27 "\n"
28 "<script type=\"text/javascript\">\n"
29 "\n"
30 "var testDivs = [\n";
31
32 static const char* opStrs[] = {
33 "kDifference_PathOp",
34 "kIntersect_PathOp",
35 "kUnion_PathOp",
36 "kXor_PathOp",
37 };
38
39 static const char* opSuffixes[] = {
40 "d",
41 "i",
42 "u",
43 "x",
44 };
45
46 static const char preferredFilename[] = "/flash/debug/XX.txt";
47 static const char backupFilename[] = "../../experimental/Intersection/debugXX.tx t";
48
49 static bool gShowPath = false;
50 static bool gComparePaths = true;
51 static bool gShowOutputProgress = false;
52 static bool gComparePathsAssert = true;
53 static bool gPathStrAssert = true;
54 static bool gUsePhysicalFiles = false;
55
56 #if FORCE_RELEASE
57 static bool gRunTestsInOneThread = false;
58 #else
59 static bool gRunTestsInOneThread = true;
60 #endif
61
62 static void showPathContour(SkPath::Iter& iter) {
63 uint8_t verb;
64 SkPoint pts[4];
65 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
66 switch (verb) {
67 case SkPath::kMove_Verb:
68 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", pts[0].fX, pts[0].fY);
69 continue;
70 case SkPath::kLine_Verb:
71 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", pts[1].fX, pts[1].fY);
72 break;
73 case SkPath::kQuad_Verb:
74 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
75 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
76 break;
77 case SkPath::kCubic_Verb:
78 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n ",
79 pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3 ].fY);
80 break;
81 case SkPath::kClose_Verb:
82 SkDebugf("path.close();\n");
83 break;
84 default:
85 SkDEBUGFAIL("bad verb");
86 return;
87 }
88 }
89 }
90
91 void showPath(const SkPath& path, const char* str) {
92 SkDebugf("%s\n", !str ? "original:" : str);
93 showPath(path);
94 }
95
96 void showPath(const SkPath& path) {
97 SkPath::Iter iter(path, true);
98 #define SUPPORT_RECT_CONTOUR_DETECTION 0
99 #if SUPPORT_RECT_CONTOUR_DETECTION
100 int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
101 if (rectCount > 0) {
102 SkTDArray<SkRect> rects;
103 SkTDArray<SkPath::Direction> directions;
104 rects.setCount(rectCount);
105 directions.setCount(rectCount);
106 path.rectContours(rects.begin(), directions.begin());
107 for (int contour = 0; contour < rectCount; ++contour) {
108 const SkRect& rect = rects[contour];
109 SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLe ft, rect.fTop,
110 rect.fRight, rect.fBottom, directions[contour] == SkPath::kC CW_Direction
111 ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
112 }
113 return;
114 }
115 #endif
116 iter.setPath(path, true);
117 showPathContour(iter);
118 }
119
120 void showPathData(const SkPath& path) {
121 SkPath::Iter iter(path, true);
122 uint8_t verb;
123 SkPoint pts[4];
124 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
125 switch (verb) {
126 case SkPath::kMove_Verb:
127 continue;
128 case SkPath::kLine_Verb:
129 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}},\n", pts[0].fX, pts[0]. fY, pts[1].fX, pts[1].fY);
130 break;
131 case SkPath::kQuad_Verb:
132 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}},\n",
133 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2 ].fY);
134 break;
135 case SkPath::kCubic_Verb:
136 SkDebugf("{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,% 1.9g}},\n",
137 pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2 ].fY, pts[3].fX, pts[3].fY);
138 break;
139 case SkPath::kClose_Verb:
140 break;
141 default:
142 SkDEBUGFAIL("bad verb");
143 return;
144 }
145 }
146 }
147
148 void showOp(const SkPathOp op) {
149 switch (op) {
150 case kDifference_PathOp:
151 SkDebugf("op difference\n");
152 break;
153 case kIntersect_PathOp:
154 SkDebugf("op intersect\n");
155 break;
156 case kUnion_PathOp:
157 SkDebugf("op union\n");
158 break;
159 case kXOR_PathOp:
160 SkDebugf("op xor\n");
161 break;
162 default:
163 SkASSERT(0);
164 }
165 }
166
167 static void showPath(const SkPath& path, const char* str, const SkMatrix& scale) {
168 SkPath scaled;
169 SkMatrix inverse;
170 bool success = scale.invert(&inverse);
171 if (!success) SkASSERT(0);
172 path.transform(inverse, &scaled);
173 showPath(scaled, str);
174 }
175
176 const int bitWidth = 64;
177 const int bitHeight = 64;
178
179 static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
180 SkRect larger = one.getBounds();
181 larger.join(two.getBounds());
182 SkScalar largerWidth = larger.width();
183 if (largerWidth < 4) {
184 largerWidth = 4;
185 }
186 SkScalar largerHeight = larger.height();
187 if (largerHeight < 4) {
188 largerHeight = 4;
189 }
190 SkScalar hScale = (bitWidth - 2) / largerWidth;
191 SkScalar vScale = (bitHeight - 2) / largerHeight;
192 scale.reset();
193 scale.preScale(hScale, vScale);
194 }
195
196 static int pathsDrawTheSame(SkBitmap& bits, const SkPath& scaledOne, const SkPat h& scaledTwo,
197 int& error2x2) {
198 if (bits.width() == 0) {
199 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
200 bits.allocPixels();
201 }
202 SkCanvas canvas(bits);
203 canvas.drawColor(SK_ColorWHITE);
204 SkPaint paint;
205 canvas.save();
206 const SkRect& bounds1 = scaledOne.getBounds();
207 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
208 canvas.drawPath(scaledOne, paint);
209 canvas.restore();
210 canvas.save();
211 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
212 canvas.drawPath(scaledTwo, paint);
213 canvas.restore();
214 int errors2 = 0;
215 int errors = 0;
216 for (int y = 0; y < bitHeight - 1; ++y) {
217 uint32_t* addr1 = bits.getAddr32(0, y);
218 uint32_t* addr2 = bits.getAddr32(0, y + 1);
219 uint32_t* addr3 = bits.getAddr32(bitWidth, y);
220 uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
221 for (int x = 0; x < bitWidth - 1; ++x) {
222 // count 2x2 blocks
223 bool err = addr1[x] != addr3[x];
224 if (err) {
225 errors2 += addr1[x + 1] != addr3[x + 1]
226 && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
227 errors++;
228 }
229 }
230 }
231 if (errors2 >= 6 || errors > 160) {
232 SkDebugf("%s errors2=%d errors=%d\n", __FUNCTION__, errors2, errors);
233 }
234 error2x2 = errors2;
235 return errors;
236 }
237
238 static int pathsDrawTheSame(const SkPath& one, const SkPath& two, SkBitmap& bits , SkPath& scaledOne,
239 SkPath& scaledTwo, int& error2x2) {
240 SkMatrix scale;
241 scaleMatrix(one, two, scale);
242 one.transform(scale, &scaledOne);
243 two.transform(scale, &scaledTwo);
244 return pathsDrawTheSame(bits, scaledOne, scaledTwo, error2x2);
245 }
246
247 bool drawAsciiPaths(const SkPath& one, const SkPath& two, bool drawPaths) {
248 if (!drawPaths) {
249 return true;
250 }
251 const SkRect& bounds1 = one.getBounds();
252 const SkRect& bounds2 = two.getBounds();
253 SkRect larger = bounds1;
254 larger.join(bounds2);
255 SkBitmap bits;
256 char out[256];
257 int bitWidth = SkScalarCeil(larger.width()) + 2;
258 if (bitWidth * 2 + 1 >= (int) sizeof(out)) {
259 return false;
260 }
261 int bitHeight = SkScalarCeil(larger.height()) + 2;
262 if (bitHeight >= (int) sizeof(out)) {
263 return false;
264 }
265 bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
266 bits.allocPixels();
267 SkCanvas canvas(bits);
268 canvas.drawColor(SK_ColorWHITE);
269 SkPaint paint;
270 canvas.save();
271 canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
272 canvas.drawPath(one, paint);
273 canvas.restore();
274 canvas.save();
275 canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
276 canvas.drawPath(two, paint);
277 canvas.restore();
278 for (int y = 0; y < bitHeight; ++y) {
279 uint32_t* addr1 = bits.getAddr32(0, y);
280 int x;
281 char* outPtr = out;
282 for (x = 0; x < bitWidth; ++x) {
283 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
284 }
285 *outPtr++ = '|';
286 for (x = bitWidth; x < bitWidth * 2; ++x) {
287 *outPtr++ = addr1[x] == (uint32_t) -1 ? '_' : 'x';
288 }
289 *outPtr++ = '\0';
290 SkDebugf("%s\n", out);
291 }
292 return true;
293 }
294
295 static void showSimplifiedPath(const SkPath& one, const SkPath& two,
296 const SkPath& scaledOne, const SkPath& scaledTwo) {
297 showPath(one, "original:");
298 showPath(two, "simplified:");
299 drawAsciiPaths(scaledOne, scaledTwo, true);
300 }
301
302 static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const S kPath& two,
303 SkBitmap& bitmap) {
304 int errors2x2;
305 SkPath scaledOne, scaledTwo;
306 int errors = pathsDrawTheSame(one, two, bitmap, scaledOne, scaledTwo, errors 2x2);
307 if (errors2x2 == 0) {
308 return 0;
309 }
310 const int MAX_ERRORS = 9;
311 if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
312 showSimplifiedPath(one, two, scaledOne, scaledTwo);
313 }
314 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
315 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
316 showSimplifiedPath(one, two, scaledOne, scaledTwo);
317 REPORTER_ASSERT(reporter, 0);
318 }
319 return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
320 }
321
322 static void showPathOpPath(const SkPath& one, const SkPath& two, const SkPath& a , const SkPath& b,
323 const SkPath& scaledOne, const SkPath& scaledTwo, const SkPathOp shapeOp ,
324 const SkMatrix& scale) {
325 SkASSERT((unsigned) shapeOp < sizeof(opStrs) / sizeof(opStrs[0]));
326 showPath(a, "minuend:");
327 SkDebugf("op: %s\n", opStrs[shapeOp]);
328 showPath(b, "subtrahend:");
329 // the region often isn't very helpful since it approximates curves with a l ot of line-tos
330 if (0) showPath(scaledOne, "region:", scale);
331 showPath(two, "op result:");
332 drawAsciiPaths(scaledOne, scaledTwo, true);
333 }
334
335 static int comparePaths(skiatest::Reporter* reporter, const SkPath& one, const S kPath& scaledOne,
336 const SkPath& two, const SkPath& scaledTwo, SkBitmap& bi tmap,
337 const SkPath& a, const SkPath& b, const SkPathOp shapeOp ,
338 const SkMatrix& scale) {
339 int errors2x2;
340 int errors = pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
341 if (errors2x2 == 0) {
342 return 0;
343 }
344 const int MAX_ERRORS = 8;
345 if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) {
346 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
347 }
348 if (errors2x2 > MAX_ERRORS && gComparePathsAssert) {
349 SkDebugf("%s errors=%d\n", __FUNCTION__, errors);
350 showPathOpPath(one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
351 REPORTER_ASSERT(reporter, 0);
352 }
353 return errors2x2 > MAX_ERRORS ? errors2x2 : 0;
354 }
355
356 bool testSimplify(SkPath& path, bool useXor, SkPath& out, State4& state, const c har* pathStr) {
357 SkPath::FillType fillType = useXor ? SkPath::kEvenOdd_FillType : SkPath::kWi nding_FillType;
358 path.setFillType(fillType);
359 if (gShowPath) {
360 showPath(path);
361 }
362 Simplify(path, &out);
363 if (!gComparePaths) {
364 return true;
365 }
366 int result = comparePaths(state.reporter, path, out, state.bitmap);
367 if (result && gPathStrAssert) {
368 SkDebugf("addTest %s\n", state.filename);
369 char temp[8192];
370 bzero(temp, sizeof(temp));
371 SkMemoryWStream stream(temp, sizeof(temp));
372 const char* pathPrefix = NULL;
373 const char* nameSuffix = NULL;
374 if (fillType == SkPath::kEvenOdd_FillType) {
375 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
376 nameSuffix = "x";
377 }
378 const char testFunction[] = "testSimplifyx(path);";
379 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, str eam);
380 SkDebugf(temp);
381 REPORTER_ASSERT(state.reporter, 0);
382 }
383 return result == 0;
384 }
385
386 bool testSimplify(skiatest::Reporter* reporter, const SkPath& path) {
387 SkPath out;
388 Simplify(path, &out);
389 SkBitmap bitmap;
390 int result = comparePaths(reporter, path, out, bitmap);
391 if (result && gPathStrAssert) {
392 REPORTER_ASSERT(reporter, 0);
393 }
394 return result == 0;
395 }
396
397 bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
398 const SkPathOp shapeOp) {
399 #if FORCE_RELEASE == 0
400 showPathData(a);
401 showOp(shapeOp);
402 showPathData(b);
403 #endif
404 SkPath out;
405 Op(a, b, shapeOp, &out);
406 SkPath pathOut, scaledPathOut;
407 SkRegion rgnA, rgnB, openClip, rgnOut;
408 openClip.setRect(-16000, -16000, 16000, 16000);
409 rgnA.setPath(a, openClip);
410 rgnB.setPath(b, openClip);
411 rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
412 rgnOut.getBoundaryPath(&pathOut);
413
414 SkMatrix scale;
415 scaleMatrix(a, b, scale);
416 SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
417 SkPath scaledA, scaledB;
418 scaledA.addPath(a, scale);
419 scaledA.setFillType(a.getFillType());
420 scaledB.addPath(b, scale);
421 scaledB.setFillType(b.getFillType());
422 scaledRgnA.setPath(scaledA, openClip);
423 scaledRgnB.setPath(scaledB, openClip);
424 scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) shapeOp);
425 scaledRgnOut.getBoundaryPath(&scaledPathOut);
426 SkBitmap bitmap;
427 SkPath scaledOut;
428 scaledOut.addPath(out, scale);
429 scaledOut.setFillType(out.getFillType());
430 int result = comparePaths(reporter, pathOut, scaledPathOut, out, scaledOut, bitmap, a, b,
431 shapeOp, scale);
432 if (result && gPathStrAssert) {
433 REPORTER_ASSERT(reporter, 0);
434 }
435 return result == 0;
436 }
437
438 const int maxThreadsAllocated = 64;
439 static int maxThreads = 1;
440 static int threadIndex;
441 State4 threadState[maxThreadsAllocated];
442 static int testNumber;
443 static const char* testName;
444 static bool debugThreads = false;
445
446 State4* State4::queue = NULL;
447 pthread_mutex_t State4::addQueue = PTHREAD_MUTEX_INITIALIZER;
448 pthread_cond_t State4::checkQueue = PTHREAD_COND_INITIALIZER;
449
450 State4::State4() {
451 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 150 * 2, 100);
452 bitmap.allocPixels();
453 }
454
455 void createThread(State4* statePtr, void* (*testFun)(void* )) {
456 SkDEBUGCODE(int threadError =) pthread_create(&statePtr->threadID, NULL, tes tFun,
457 (void*) statePtr);
458 SkASSERT(!threadError);
459 }
460
461 int dispatchTest4(void* (*testFun)(void* ), int a, int b, int c, int d) {
462 int testsRun = 0;
463 State4* statePtr;
464 if (!gRunTestsInOneThread) {
465 pthread_mutex_lock(&State4::addQueue);
466 if (threadIndex < maxThreads) {
467 statePtr = &threadState[threadIndex];
468 statePtr->testsRun = 0;
469 statePtr->a = a;
470 statePtr->b = b;
471 statePtr->c = c;
472 statePtr->d = d;
473 statePtr->done = false;
474 statePtr->index = threadIndex;
475 statePtr->last = false;
476 if (debugThreads) SkDebugf("%s %d create done=%d last=%d\n", __FUNCT ION__,
477 statePtr->index, statePtr->done, statePtr->last);
478 pthread_cond_init(&statePtr->initialized, NULL);
479 ++threadIndex;
480 createThread(statePtr, testFun);
481 } else {
482 while (!State4::queue) {
483 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__);
484 pthread_cond_wait(&State4::checkQueue, &State4::addQueue);
485 }
486 statePtr = State4::queue;
487 testsRun += statePtr->testsRun;
488 statePtr->testsRun = 0;
489 statePtr->a = a;
490 statePtr->b = b;
491 statePtr->c = c;
492 statePtr->d = d;
493 statePtr->done = false;
494 State4::queue = NULL;
495 for (int index = 0; index < maxThreads; ++index) {
496 if (threadState[index].done) {
497 State4::queue = &threadState[index];
498 }
499 }
500 if (debugThreads) SkDebugf("%s %d init done=%d last=%d queued=%d\n", __FUNCTION__,
501 statePtr->index, statePtr->done, statePtr->last,
502 State4::queue ? State4::queue->index : -1);
503 pthread_cond_signal(&statePtr->initialized);
504 }
505 pthread_mutex_unlock(&State4::addQueue);
506 } else {
507 statePtr = &threadState[0];
508 testsRun += statePtr->testsRun;
509 statePtr->testsRun = 0;
510 statePtr->a = a;
511 statePtr->b = b;
512 statePtr->c = c;
513 statePtr->d = d;
514 statePtr->done = false;
515 statePtr->index = threadIndex;
516 statePtr->last = false;
517 (*testFun)(statePtr);
518 }
519 return testsRun;
520 }
521
522 void initializeTests(skiatest::Reporter* reporter, const char* test, size_t test NameSize) {
523 testName = test;
524 if (!gRunTestsInOneThread) {
525 int threads = -1;
526 size_t size = sizeof(threads);
527 sysctlbyname("hw.logicalcpu_max", &threads, &size, NULL, 0);
528 if (threads > 0) {
529 maxThreads = threads;
530 } else {
531 maxThreads = 8;
532 }
533 }
534 SkFILEStream inFile("../../experimental/Intersection/op.htm");
535 if (inFile.isValid()) {
536 SkTDArray<char> inData;
537 inData.setCount(inFile.getLength());
538 size_t inLen = inData.count();
539 inFile.read(inData.begin(), inLen);
540 inFile.setPath(NULL);
541 char* insert = strstr(inData.begin(), marker);
542 if (insert) {
543 insert += sizeof(marker) - 1;
544 const char* numLoc = insert + 4 /* indent spaces */ + testNameSize - 1;
545 testNumber = atoi(numLoc) + 1;
546 }
547 }
548 const char* filename = preferredFilename;
549 SkFILEWStream preferredTest(filename);
550 if (!preferredTest.isValid()) {
551 filename = backupFilename;
552 SkFILEWStream backupTest(filename);
553 SkASSERT(backupTest.isValid());
554 }
555 for (int index = 0; index < maxThreads; ++index) {
556 State4* statePtr = &threadState[index];
557 statePtr->reporter = reporter;
558 strcpy(statePtr->filename, filename);
559 size_t len = strlen(filename);
560 SkASSERT(statePtr->filename[len - 6] == 'X');
561 SkASSERT(statePtr->filename[len - 5] == 'X');
562 statePtr->filename[len - 6] = '0' + index / 10;
563 statePtr->filename[len - 5] = '0' + index % 10;
564 }
565 threadIndex = 0;
566 }
567
568 void outputProgress(const State4& state, const char* pathStr, SkPath::FillType p athFillType) {
569 if (gRunTestsInOneThread && gShowOutputProgress) {
570 if (pathFillType == SkPath::kEvenOdd_FillType) {
571 SkDebugf(" path.setFillType(SkPath::kEvenOdd_FillType);\n", pathS tr);
572 }
573 SkDebugf("%s\n", pathStr);
574 }
575 const char testFunction[] = "testSimplifyx(path);";
576 const char* pathPrefix = NULL;
577 const char* nameSuffix = NULL;
578 if (pathFillType == SkPath::kEvenOdd_FillType) {
579 pathPrefix = " path.setFillType(SkPath::kEvenOdd_FillType);\n";
580 nameSuffix = "x";
581 }
582 if (gUsePhysicalFiles) {
583 SkFILEWStream outFile(state.filename);
584 if (!outFile.isValid()) {
585 SkASSERT(0);
586 return;
587 }
588 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, out File);
589 return;
590 }
591 SkFILEWStream outRam(state.filename);
592 outputToStream(state, pathStr, pathPrefix, nameSuffix, testFunction, outRam) ;
593 }
594
595 void outputProgress(const State4& state, const char* pathStr, SkPathOp op) {
596 SkString testFunc("testPathOp(path, pathB, ");
597 testFunc += opStrs[op];
598 testFunc += ");";
599 const char* testFunction = testFunc.c_str();
600 if (gRunTestsInOneThread && gShowOutputProgress) {
601 SkDebugf("%s\n", pathStr);
602 SkDebugf(" %s\n", testFunction);
603 }
604 const char* nameSuffix = opSuffixes[op];
605 if (gUsePhysicalFiles) {
606 SkFILEWStream outFile(state.filename);
607 if (!outFile.isValid()) {
608 SkASSERT(0);
609 return;
610 }
611 outputToStream(state, pathStr, NULL, nameSuffix, testFunction, outFile);
612 return;
613 }
614 SkFILEWStream outRam(state.filename);
615 outputToStream(state, pathStr, NULL, nameSuffix, testFunction, outRam);
616 }
617
618 static void writeTestName(const char* nameSuffix, SkWStream& outFile) {
619 outFile.writeText(testName);
620 outFile.writeDecAsText(testNumber);
621 if (nameSuffix) {
622 outFile.writeText(nameSuffix);
623 }
624 }
625
626 void outputToStream(const State4& state, const char* pathStr, const char* pathPr efix,
627 const char* nameSuffix,
628 const char* testFunction, SkWStream& outFile) {
629 outFile.writeText("<div id=\"");
630 writeTestName(nameSuffix, outFile);
631 outFile.writeText("\">\n");
632 if (pathPrefix) {
633 outFile.writeText(pathPrefix);
634 }
635 outFile.writeText(pathStr);
636 outFile.writeText("</div>\n\n");
637
638 outFile.writeText(marker);
639 outFile.writeText(" ");
640 writeTestName(nameSuffix, outFile);
641 outFile.writeText(",\n\n\n");
642
643 outFile.writeText("static void ");
644 writeTestName(nameSuffix, outFile);
645 outFile.writeText("() {\n SkPath path");
646 if (!pathPrefix) {
647 outFile.writeText(", pathB");
648 }
649 outFile.writeText(";\n");
650 if (pathPrefix) {
651 outFile.writeText(pathPrefix);
652 }
653 outFile.writeText(pathStr);
654 outFile.writeText(" ");
655 outFile.writeText(testFunction);
656 outFile.writeText("\n}\n\n");
657 outFile.writeText("static void (*firstTest)() = ");
658 writeTestName(nameSuffix, outFile);
659 outFile.writeText(";\n\n");
660
661 outFile.writeText("static struct {\n");
662 outFile.writeText(" void (*fun)();\n");
663 outFile.writeText(" const char* str;\n");
664 outFile.writeText("} tests[] = {\n");
665 outFile.writeText(" TEST(");
666 writeTestName(nameSuffix, outFile);
667 outFile.writeText("),\n");
668 outFile.flush();
669 }
670
671 bool runNextTestSet(State4& state) {
672 if (gRunTestsInOneThread) {
673 return false;
674 }
675 pthread_mutex_lock(&State4::addQueue);
676 state.done = true;
677 State4::queue = &state;
678 if (debugThreads) SkDebugf("%s %d checkQueue done=%d last=%d\n", __FUNCTION_ _, state.index,
679 state.done, state.last);
680 pthread_cond_signal(&State4::checkQueue);
681 while (state.done && !state.last) {
682 if (debugThreads) SkDebugf("%s %d done=%d last=%d\n", __FUNCTION__, stat e.index, state.done, state.last);
683 pthread_cond_wait(&state.initialized, &State4::addQueue);
684 }
685 pthread_mutex_unlock(&State4::addQueue);
686 return !state.last;
687 }
688
689 int waitForCompletion() {
690 int testsRun = 0;
691 if (!gRunTestsInOneThread) {
692 pthread_mutex_lock(&State4::addQueue);
693 int runningThreads = threadIndex;
694 int index;
695 while (runningThreads > 0) {
696 while (!State4::queue) {
697 if (debugThreads) SkDebugf("%s checkQueue\n", __FUNCTION__);
698 pthread_cond_wait(&State4::checkQueue, &State4::addQueue);
699 }
700 while (State4::queue) {
701 --runningThreads;
702 #if DEBUG_SHOW_TEST_PROGRESS
703 SkDebugf("•");
704 #endif
705 State4::queue->last = true;
706 State4* next = NULL;
707 for (index = 0; index < maxThreads; ++index) {
708 State4& test = threadState[index];
709 if (test.done && !test.last) {
710 next = &test;
711 }
712 }
713 if (debugThreads) SkDebugf("%s %d next=%d deQueue\n", __FUNCTION __,
714 State4::queue->index, next ? next->index : -1);
715 pthread_cond_signal(&State4::queue->initialized);
716 State4::queue = next;
717 }
718 }
719 pthread_mutex_unlock(&State4::addQueue);
720 for (index = 0; index < maxThreads; ++index) {
721 pthread_join(threadState[index].threadID, NULL);
722 testsRun += threadState[index].testsRun;
723 }
724 #if DEBUG_SHOW_TEST_PROGRESS
725 SkDebugf("\n");
726 #endif
727 }
728 #ifdef SK_DEBUG
729 gDebugMaxWindSum = SK_MaxS32;
730 gDebugMaxWindValue = SK_MaxS32;
731 #endif
732 return testsRun;
733 }
734
735 void RunTestSet(skiatest::Reporter* reporter, TestDesc tests[], size_t count,
736 void (*firstTest)(skiatest::Reporter* ),
737 void (*stopTest)(skiatest::Reporter* ), bool reverse) {
738 size_t index;
739 if (firstTest) {
740 index = count - 1;
741 while (index > 0 && tests[index].fun != firstTest) {
742 --index;
743 }
744 #if FORCE_RELEASE == 0
745 SkDebugf("<div id=\"%s\">\n", tests[index].str);
746 SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
747 #endif
748 (*tests[index].fun)(reporter);
749 }
750 index = reverse ? count - 1 : 0;
751 size_t last = reverse ? 0 : count - 1;
752 do {
753 if (tests[index].fun != firstTest) {
754 #if FORCE_RELEASE == 0
755 SkDebugf("<div id=\"%s\">\n", tests[index].str);
756 SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str);
757 #endif
758 (*tests[index].fun)(reporter);
759 }
760 if (tests[index].fun == stopTest) {
761 SkDebugf("lastTest\n");
762 }
763 if (index == last) {
764 break;
765 }
766 index += reverse ? -1 : 1;
767 } while (true);
768 }
OLDNEW
« no previous file with comments | « tests/PathOpsExtendedTest.h ('k') | tests/PathOpsOpCubicThreadedTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698