• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #include "SkBitmap.h"
3 #include "SkCanvas.h"
4 #include "SkColor.h"
5 #include "SkColorPriv.h"
6 #include "SkDevice.h"
7 #include "SkGraphics.h"
8 #include "SkImageDecoder.h"
9 #include "SkImageEncoder.h"
10 #include "SkOSFile.h"
11 #include "SkPathOpsDebug.h"
12 #include "SkPicture.h"
13 #include "SkRTConf.h"
14 #include "SkStream.h"
15 #include "SkString.h"
16 #include "SkTArray.h"
17 #include "SkTDArray.h"
18 #include "SkThreadPool.h"
19 #include "SkTime.h"
20 #include "Test.h"
21 
22 #ifdef SK_BUILD_FOR_WIN
23     #define PATH_SLASH "\\"
24     #define IN_DIR "D:\\9-30-13\\"
25     #define OUT_DIR "D:\\opSkpClip\\1\\"
26 #else
27     #define PATH_SLASH "/"
28     #ifdef SK_BUILD_FOR_MAC
29         #define IN_DIR "/Volumes/tera/9-30-13/skp"
30         #define OUT_DIR "/Volumes/tera/out/9-30-13/1/"
31     #else
32         #define IN_DIR "/usr/local/google/home/caryclark/skps/9-30-13/skp"
33         #define OUT_DIR "/mnt/skia/opSkpClip/1/"
34     #endif
35 #endif
36 
37 const struct {
38     int directory;
39     const char* filename;
40 } skipOverSept[] = {
41     {9, "http___www_symptome_ch_.skp"}, // triangle clip with corner at x.999
42     {11, "http___www_menly_fr_.skp"},
43     {12, "http___www_banrasdr_com_.skp"},
44 };
45 
46 size_t skipOverSeptCount = sizeof(skipOverSept) / sizeof(skipOverSept[0]);
47 
48 enum TestStep {
49     kCompareBits,
50     kEncodeFiles,
51 };
52 
53 enum {
54     kMaxLength = 128,
55     kMaxFiles = 128,
56     kSmallLimit = 1000,
57 };
58 
59 struct TestResult {
initTestResult60     void init(int dirNo) {
61         fDirNo = dirNo;
62         sk_bzero(fFilename, sizeof(fFilename));
63         fTestStep = kCompareBits;
64         fScaleOversized = true;
65     }
66 
statusTestResult67     SkString status() {
68         SkString outStr;
69         outStr.printf("%s %d %d\n", fFilename, fPixelError, fTime);
70         return outStr;
71     }
72 
TestTestResult73     static void Test(int dirNo, const char* filename, TestStep testStep) {
74         TestResult test;
75         test.init(dirNo);
76         test.fTestStep = testStep;
77         strcpy(test.fFilename, filename);
78         test.testOne();
79     }
80 
testTestResult81     void test(int dirNo, const SkString& filename) {
82         init(dirNo);
83         strcpy(fFilename, filename.c_str());
84         testOne();
85     }
86 
87     void testOne();
88 
89     char fFilename[kMaxLength];
90     TestStep fTestStep;
91     int fDirNo;
92     int fPixelError;
93     int fTime;
94     bool fScaleOversized;
95 };
96 
97 struct TestState {
initTestState98     void init(int dirNo, skiatest::Reporter* reporter) {
99         fReporter = reporter;
100         fResult.init(dirNo);
101         fFoundCount = 0;
102         TestState::fSmallCount = 0;
103         fSmallestError = 0;
104         sk_bzero(fFilesFound, sizeof(fFilesFound));
105         sk_bzero(fDirsFound, sizeof(fDirsFound));
106         sk_bzero(fError, sizeof(fError));
107     }
108 
bumpSmallCountTestState109     static bool bumpSmallCount() {
110         sk_atomic_inc(&fSmallCount);
111         return fSmallCount > kSmallLimit;
112     }
113 
clearSmallCountTestState114     static void clearSmallCount() {
115         if (fSmallCount < kSmallLimit) {
116             fSmallCount = 0;
117         }
118     }
119 
120     char fFilesFound[kMaxFiles][kMaxLength];
121     int fDirsFound[kMaxFiles];
122     int fError[kMaxFiles];
123     int fFoundCount;
124     static int fSmallCount;
125     int fSmallestError;
126     skiatest::Reporter* fReporter;
127     TestResult fResult;
128 };
129 
130 int TestState::fSmallCount;
131 
132 struct TestRunner {
TestRunnerTestRunner133     TestRunner(skiatest::Reporter* reporter, int threadCount)
134         : fNumThreads(threadCount)
135         , fReporter(reporter) {
136     }
137 
138     ~TestRunner();
139     void render();
140     int fNumThreads;
141     SkTDArray<class TestRunnable*> fRunnables;
142     skiatest::Reporter* fReporter;
143 };
144 
145 class TestRunnable : public SkRunnable {
146 public:
TestRunnable(void (* testFun)(TestState *),int dirNo,TestRunner * runner)147     TestRunnable(void (*testFun)(TestState*), int dirNo, TestRunner* runner) {
148         fState.init(dirNo, runner->fReporter);
149         fTestFun = testFun;
150     }
151 
run()152     virtual void run() SK_OVERRIDE {
153         SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
154         (*fTestFun)(&fState);
155     }
156 
157     TestState fState;
158     void (*fTestFun)(TestState*);
159 };
160 
~TestRunner()161 TestRunner::~TestRunner() {
162     for (int index = 0; index < fRunnables.count(); index++) {
163         SkDELETE(fRunnables[index]);
164     }
165 }
166 
render()167 void TestRunner::render() {
168     SkThreadPool pool(fNumThreads);
169     for (int index = 0; index < fRunnables.count(); ++ index) {
170         pool.add(fRunnables[index]);
171     }
172 }
173 
174 ////////////////////////////////////////////////
175 
176 static const char outOpDir[] = OUT_DIR "opClip";
177 static const char outOldDir[] = OUT_DIR "oldClip";
178 static const char outSkpDir[] = OUT_DIR "skpTest";
179 static const char outDiffDir[] = OUT_DIR "outTest";
180 static const char outStatusDir[] = OUT_DIR "statusTest";
181 
make_filepath(int dirNo,const char * dir,const char * name)182 static SkString make_filepath(int dirNo, const char* dir, const char* name) {
183     SkString path(dir);
184     if (dirNo) {
185         path.appendf("%d", dirNo);
186     }
187     path.append(PATH_SLASH);
188     path.append(name);
189     return path;
190 }
191 
make_in_dir_name(int dirNo)192 static SkString make_in_dir_name(int dirNo) {
193     SkString dirName(IN_DIR);
194     dirName.appendf("%d", dirNo);
195     if (!sk_exists(dirName.c_str())) {
196         SkDebugf("could not read dir %s\n", dirName.c_str());
197         return SkString();
198     }
199     return dirName;
200 }
201 
make_one_out_dir(const char * outDirStr)202 static bool make_one_out_dir(const char* outDirStr) {
203     SkString outDir = make_filepath(0, outDirStr, "");
204     if (!sk_exists(outDir.c_str())) {
205         if (!sk_mkdir(outDir.c_str())) {
206             SkDebugf("could not create dir %s\n", outDir.c_str());
207             return false;
208         }
209     }
210     return true;
211 }
212 
make_out_dirs()213 static bool make_out_dirs() {
214     SkString outDir = make_filepath(0, OUT_DIR, "");
215     if (!sk_exists(outDir.c_str())) {
216         if (!sk_mkdir(outDir.c_str())) {
217             SkDebugf("could not create dir %s\n", outDir.c_str());
218             return false;
219         }
220     }
221     return make_one_out_dir(outOldDir)
222             && make_one_out_dir(outOpDir)
223             && make_one_out_dir(outSkpDir)
224             && make_one_out_dir(outDiffDir)
225             && make_one_out_dir(outStatusDir);
226 }
227 
make_png_name(const char * filename)228 static SkString make_png_name(const char* filename) {
229     SkString pngName = SkString(filename);
230     pngName.remove(pngName.size() - 3, 3);
231     pngName.append("png");
232     return pngName;
233 }
234 
similarBits(const SkBitmap & gr,const SkBitmap & sk)235 static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
236     const int kRowCount = 3;
237     const int kThreshold = 3;
238     int width = SkTMin(gr.width(), sk.width());
239     if (width < kRowCount) {
240         return true;
241     }
242     int height = SkTMin(gr.height(), sk.height());
243     if (height < kRowCount) {
244         return true;
245     }
246     int errorTotal = 0;
247     SkTArray<int, true> errorRows;
248     errorRows.push_back_n(width * kRowCount);
249     SkAutoLockPixels autoGr(gr);
250     SkAutoLockPixels autoSk(sk);
251     for (int y = 0; y < height; ++y) {
252         SkPMColor* grRow = gr.getAddr32(0, y);
253         SkPMColor* skRow = sk.getAddr32(0, y);
254         int* base = &errorRows[0];
255         int* cOut = &errorRows[y % kRowCount];
256         for (int x = 0; x < width; ++x) {
257             SkPMColor grColor = grRow[x];
258             SkPMColor skColor = skRow[x];
259             int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor);
260             int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor);
261             int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor);
262             int error = cOut[x] = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db)));
263             if (error < kThreshold || x < 2) {
264                 continue;
265             }
266             if (base[x - 2] < kThreshold
267                     || base[width + x - 2] < kThreshold
268                     || base[width * 2 + x - 2] < kThreshold
269                     || base[x - 1] < kThreshold
270                     || base[width + x - 1] < kThreshold
271                     || base[width * 2 + x - 1] < kThreshold
272                     || base[x] < kThreshold
273                     || base[width + x] < kThreshold
274                     || base[width * 2 + x] < kThreshold) {
275                 continue;
276             }
277             errorTotal += error;
278         }
279     }
280     return errorTotal;
281 }
282 
addError(TestState * data,const TestResult & testResult)283 static bool addError(TestState* data, const TestResult& testResult) {
284     bool foundSmaller = false;
285     int dCount = data->fFoundCount;
286     int pixelError = testResult.fPixelError;
287     if (data->fFoundCount < kMaxFiles) {
288         data->fError[dCount] = pixelError;
289         strcpy(data->fFilesFound[dCount], testResult.fFilename);
290         data->fDirsFound[dCount] = testResult.fDirNo;
291         ++data->fFoundCount;
292     } else if (pixelError > data->fSmallestError) {
293         int smallest = SK_MaxS32;
294         int smallestIndex = 0;
295         for (int index = 0; index < kMaxFiles; ++index) {
296             if (smallest > data->fError[index]) {
297                 smallest = data->fError[index];
298                 smallestIndex = index;
299             }
300         }
301         data->fError[smallestIndex] = pixelError;
302         strcpy(data->fFilesFound[smallestIndex], testResult.fFilename);
303         data->fDirsFound[smallestIndex] = testResult.fDirNo;
304         data->fSmallestError = SK_MaxS32;
305         for (int index = 0; index < kMaxFiles; ++index) {
306             if (data->fSmallestError > data->fError[index]) {
307                 data->fSmallestError = data->fError[index];
308             }
309         }
310         SkDebugf("*%d*", data->fSmallestError);
311         foundSmaller = true;
312     }
313     return foundSmaller;
314 }
315 
316 
317 
timePict(SkPicture * pic,SkCanvas * canvas)318 static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) {
319     canvas->save();
320     int pWidth = pic->width();
321     int pHeight = pic->height();
322     const int maxDimension = 1000;
323     const int slices = 3;
324     int xInterval = SkTMax(pWidth - maxDimension, 0) / (slices - 1);
325     int yInterval = SkTMax(pHeight - maxDimension, 0) / (slices - 1);
326     SkRect rect = {0, 0, SkIntToScalar(SkTMin(maxDimension, pWidth)),
327             SkIntToScalar(SkTMin(maxDimension, pHeight))};
328     canvas->clipRect(rect);
329     SkMSec start = SkTime::GetMSecs();
330     for (int x = 0; x < slices; ++x) {
331         for (int y = 0; y < slices; ++y) {
332             pic->draw(canvas);
333             canvas->translate(0, SkIntToScalar(yInterval));
334         }
335         canvas->translate(SkIntToScalar(xInterval), SkIntToScalar(-yInterval * slices));
336     }
337     SkMSec end = SkTime::GetMSecs();
338     canvas->restore();
339     return end - start;
340 }
341 
drawPict(SkPicture * pic,SkCanvas * canvas,int scale)342 static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
343     canvas->clear(SK_ColorWHITE);
344     if (scale != 1) {
345         canvas->save();
346         canvas->scale(1.0f / scale, 1.0f / scale);
347     }
348     pic->draw(canvas);
349     if (scale != 1) {
350         canvas->restore();
351     }
352 }
353 
writePict(const SkBitmap & bitmap,const char * outDir,const char * pngName)354 static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
355     SkString outFile = make_filepath(0, outDir, pngName);
356     if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap,
357             SkImageEncoder::kPNG_Type, 100)) {
358         SkDebugf("unable to encode gr %s (width=%d height=%d)\n", pngName,
359                     bitmap.width(), bitmap.height());
360     }
361 }
362 
testOne()363 void TestResult::testOne() {
364     SkPicture* pic = NULL;
365     {
366     #if DEBUG_SHOW_TEST_NAME
367         if (fTestStep == kCompareBits) {
368             SkString testName(fFilename);
369             const char http[] = "http";
370             if (testName.startsWith(http)) {
371                 testName.remove(0, sizeof(http) - 1);
372             }
373             while (testName.startsWith("_")) {
374                 testName.remove(0, 1);
375             }
376             const char dotSkp[] = ".skp";
377             if (testName.endsWith(dotSkp)) {
378                 size_t len = testName.size();
379                 testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1);
380             }
381             testName.prepend("skp");
382             testName.append("1");
383             strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH);
384         } else if (fTestStep == kEncodeFiles) {
385             strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH);
386         }
387     #endif
388         SkString path = make_filepath(fDirNo, IN_DIR, fFilename);
389         SkFILEStream stream(path.c_str());
390         if (!stream.isValid()) {
391             SkDebugf("invalid stream %s\n", path.c_str());
392             goto finish;
393         }
394         SkPicture* pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
395         if (!pic) {
396             SkDebugf("unable to decode %s\n", fFilename);
397             goto finish;
398         }
399         int width = pic->width();
400         int height = pic->height();
401         SkBitmap oldBitmap, opBitmap;
402         int scale = 1;
403         do {
404             int dimX = (width + scale - 1) / scale;
405             int dimY = (height + scale - 1) / scale;
406             oldBitmap.setConfig(SkBitmap::kARGB_8888_Config, dimX, dimY);
407             opBitmap.setConfig(SkBitmap::kARGB_8888_Config, dimX, dimY);
408             bool success = oldBitmap.allocPixels() && opBitmap.allocPixels();
409             if (success) {
410                 break;
411             }
412             SkDebugf("-%d-", scale);
413         } while ((scale *= 2) < 256);
414         if (scale >= 256) {
415             SkDebugf("unable to allocate bitmap for %s (w=%d h=%d)\n", fFilename,
416                     width, height);
417             return;
418         }
419         oldBitmap.eraseColor(SK_ColorWHITE);
420         SkCanvas oldCanvas(oldBitmap);
421         oldCanvas.setAllowSimplifyClip(false);
422         opBitmap.eraseColor(SK_ColorWHITE);
423         SkCanvas opCanvas(opBitmap);
424         opCanvas.setAllowSimplifyClip(true);
425         drawPict(pic, &oldCanvas, fScaleOversized ? scale : 1);
426         drawPict(pic, &opCanvas, fScaleOversized ? scale : 1);
427         if (fTestStep == kCompareBits) {
428             fPixelError = similarBits(oldBitmap, opBitmap);
429             int oldTime = timePict(pic, &oldCanvas);
430             int opTime = timePict(pic, &opCanvas);
431             fTime = oldTime - opTime;
432         } else if (fTestStep == kEncodeFiles) {
433             SkString pngStr = make_png_name(fFilename);
434             const char* pngName = pngStr.c_str();
435             writePict(oldBitmap, outOldDir, pngName);
436             writePict(opBitmap, outOpDir, pngName);
437         }
438     }
439 finish:
440     SkDELETE(pic);
441 }
442 
makeStatusString(int dirNo)443 static SkString makeStatusString(int dirNo) {
444     SkString statName;
445     statName.printf("stats%d.txt", dirNo);
446     SkString statusFile = make_filepath(0, outStatusDir, statName.c_str());
447     return statusFile;
448 }
449 
450 class PreParser {
451 public:
PreParser(int dirNo)452     PreParser(int dirNo)
453         : fDirNo(dirNo)
454         , fIndex(0) {
455         SkString statusPath = makeStatusString(dirNo);
456         if (!sk_exists(statusPath.c_str())) {
457             return;
458         }
459         SkFILEStream reader;
460         reader.setPath(statusPath.c_str());
461         while (fetch(reader, &fResults.push_back()))
462             ;
463         fResults.pop_back();
464     }
465 
fetch(SkFILEStream & reader,TestResult * result)466     bool fetch(SkFILEStream& reader, TestResult* result) {
467         char c;
468         int i = 0;
469         result->init(fDirNo);
470         result->fPixelError = 0;
471         result->fTime = 0;
472         do {
473             bool readOne = reader.read(&c, 1) != 0;
474             if (!readOne) {
475                 SkASSERT(i == 0);
476                 return false;
477             }
478             if (c == ' ') {
479                 result->fFilename[i++] = '\0';
480                 break;
481             }
482             result->fFilename[i++] = c;
483             SkASSERT(i < kMaxLength);
484         } while (true);
485         do {
486             SkAssertResult(reader.read(&c, 1));
487             if (c == ' ') {
488                 break;
489             }
490             SkASSERT(c >= '0' && c <= '9');
491             result->fPixelError = result->fPixelError * 10 + (c - '0');
492         } while (true);
493         bool minus = false;
494         do {
495             SkAssertResult(reader.read(&c, 1));
496             if (c == '\n') {
497                 break;
498             }
499             if (c == '-') {
500                 minus = true;
501                 continue;
502             }
503             SkASSERT(c >= '0' && c <= '9');
504             result->fTime = result->fTime * 10 + (c - '0');
505         } while (true);
506         if (minus) {
507             result->fTime = -result->fTime;
508         }
509         return true;
510     }
511 
match(const SkString & filename,SkFILEWStream * stream,TestResult * result)512     bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) {
513         if (fIndex < fResults.count()) {
514             *result = fResults[fIndex++];
515             SkASSERT(filename.equals(result->fFilename));
516             SkString outStr(result->status());
517             stream->write(outStr.c_str(), outStr.size());
518             return true;
519         }
520         return false;
521     }
522 
523 private:
524     int fDirNo;
525     int fIndex;
526     SkTArray<TestResult, true> fResults;
527 };
528 
doOneDir(TestState * state)529 static bool doOneDir(TestState* state) {
530     int dirNo = state->fResult.fDirNo;
531     skiatest::Reporter* reporter = state->fReporter;
532     SkString dirName = make_in_dir_name(dirNo);
533     SkASSERT(dirName.size());
534     SkOSFile::Iter iter(dirName.c_str(), "skp");
535     SkString filename;
536     int testCount = 0;
537     PreParser preParser(dirNo);
538     SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
539     while (iter.next(&filename)) {
540         for (size_t index = 0; index < skipOverSeptCount; ++index) {
541             if (skipOverSept[index].directory == dirNo
542                     && strcmp(filename.c_str(), skipOverSept[index].filename) == 0) {
543                 goto skipOver;
544             }
545         }
546         if (preParser.match(filename, &statusStream, &state->fResult)) {
547             addError(state, state->fResult);
548             ++testCount;
549             goto checkEarlyExit;
550         }
551         if (state->fSmallestError > 5000000) {
552             return false;
553         }
554         {
555             TestResult& result = state->fResult;
556             result.test(dirNo, filename);
557             SkString outStr(result.status());
558             statusStream.write(outStr.c_str(), outStr.size());
559             statusStream.flush();
560             if (1) {
561                 SkDebugf("%s", outStr.c_str());
562             }
563             bool noMatch = addError(state, state->fResult);
564             if (noMatch) {
565                 state->clearSmallCount();
566             } else if (state->bumpSmallCount()) {
567                 return false;
568             }
569         }
570         ++testCount;
571         if (reporter->verbose()) {
572             SkDebugf(".");
573             if (++testCount % 100 == 0) {
574                 SkDebugf("%d\n", testCount);
575             }
576         }
577 skipOver:
578         if (reporter->verbose()) {
579             static int threadTestCount;
580             SkDebugf(".");
581             sk_atomic_inc(&threadTestCount);
582             if (threadTestCount % 100 == 0) {
583                 SkDebugf("%d\n", threadTestCount);
584             }
585         }
586 checkEarlyExit:
587         if (1 && testCount == 20) {
588             return true;
589         }
590     }
591     return true;
592 }
593 
initTest()594 static bool initTest() {
595 #if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
596     SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
597     SK_CONF_SET("images.png.suppressDecoderWarnings", true);
598 #endif
599     return make_out_dirs();
600 }
601 
encodeFound(skiatest::Reporter * reporter,TestState & state)602 static void encodeFound(skiatest::Reporter* reporter, TestState& state) {
603     if (reporter->verbose()) {
604         for (int index = 0; index < state.fFoundCount; ++index) {
605             SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index],
606                      state.fError[index]);
607         }
608     }
609     for (int index = 0; index < state.fFoundCount; ++index) {
610         TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles);
611         if (state.fReporter->verbose()) SkDebugf("+");
612     }
613 }
614 
PathOpsSkpClipTest(skiatest::Reporter * reporter)615 static void PathOpsSkpClipTest(skiatest::Reporter* reporter) {
616     if (!initTest()) {
617         return;
618     }
619     SkTArray<TestResult, true> errors;
620     TestState state;
621     state.init(0, reporter);
622     for (int dirNo = 1; dirNo <= 100; ++dirNo) {
623         if (reporter->verbose()) {
624             SkDebugf("dirNo=%d\n", dirNo);
625         }
626         state.fResult.fDirNo = dirNo;
627         if (!doOneDir(&state)) {
628             break;
629         }
630     }
631     encodeFound(reporter, state);
632 }
633 
testSkpClipMain(TestState * data)634 static void testSkpClipMain(TestState* data) {
635         (void) doOneDir(data);
636 }
637 
PathOpsSkpClipThreadedTest(skiatest::Reporter * reporter)638 static void PathOpsSkpClipThreadedTest(skiatest::Reporter* reporter) {
639     if (!initTest()) {
640         return;
641     }
642     int threadCount = reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1;
643     TestRunner testRunner(reporter, threadCount);
644     for (int dirNo = 1; dirNo <= 100; ++dirNo) {
645         *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnable,
646                 (&testSkpClipMain, dirNo, &testRunner));
647     }
648     testRunner.render();
649     TestState state;
650     state.init(0, reporter);
651     for (int dirNo = 1; dirNo <= 100; ++dirNo) {
652         TestState& testState = testRunner.fRunnables[dirNo - 1]->fState;
653         for (int inner = 0; inner < testState.fFoundCount; ++inner) {
654             TestResult& testResult = testState.fResult;
655             SkASSERT(testResult.fDirNo == dirNo);
656             testResult.fPixelError = testState.fError[inner];
657             strcpy(testResult.fFilename, testState.fFilesFound[inner]);
658             addError(&state, testResult);
659         }
660     }
661     encodeFound(reporter, state);
662 }
663 
PathOpsSkpClipOneOffTest(skiatest::Reporter * reporter)664 static void PathOpsSkpClipOneOffTest(skiatest::Reporter* reporter) {
665     if (!initTest()) {
666         return;
667     }
668     const int testIndex = 43 - 41;
669     int dirNo = skipOverSept[testIndex].directory;
670     SkAssertResult(make_in_dir_name(dirNo).size());
671     SkString filename(skipOverSept[testIndex].filename);
672     TestResult state;
673     state.test(dirNo, filename);
674     if (reporter->verbose()) {
675         SkDebugf("%s", state.status().c_str());
676     }
677     state.fTestStep = kEncodeFiles;
678     state.testOne();
679 }
680 
681 #include "TestClassDef.h"
682 DEFINE_TESTCLASS_SHORT(PathOpsSkpClipTest)
683 
684 DEFINE_TESTCLASS_SHORT(PathOpsSkpClipOneOffTest)
685 
686 DEFINE_TESTCLASS_SHORT(PathOpsSkpClipThreadedTest)
687