Home | History | Annotate | Download | only in tests
      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 {
     60     void init(int dirNo) {
     61         fDirNo = dirNo;
     62         sk_bzero(fFilename, sizeof(fFilename));
     63         fTestStep = kCompareBits;
     64         fScaleOversized = true;
     65     }
     66 
     67     SkString status() {
     68         SkString outStr;
     69         outStr.printf("%s %d %d\n", fFilename, fPixelError, fTime);
     70         return outStr;
     71     }
     72 
     73     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 
     81     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 {
     98     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 
    109     static bool bumpSmallCount() {
    110         sk_atomic_inc(&fSmallCount);
    111         return fSmallCount > kSmallLimit;
    112     }
    113 
    114     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 {
    133     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:
    147     TestRunnable(void (*testFun)(TestState*), int dirNo, TestRunner* runner) {
    148         fState.init(dirNo, runner->fReporter);
    149         fTestFun = testFun;
    150     }
    151 
    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 
    161 TestRunner::~TestRunner() {
    162     for (int index = 0; index < fRunnables.count(); index++) {
    163         SkDELETE(fRunnables[index]);
    164     }
    165 }
    166 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    634 static void testSkpClipMain(TestState* data) {
    635         (void) doOneDir(data);
    636 }
    637 
    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 
    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