| Index: tests/PathOpsSkpClipTest.cpp | 
| diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp | 
| index d2fa988c6c32a61b1e00b656e9c012a4bcd3d9b9..7905faa9a574d057a7aa464ee93066dfb3939094 100755 | 
| --- a/tests/PathOpsSkpClipTest.cpp | 
| +++ b/tests/PathOpsSkpClipTest.cpp | 
| @@ -1,207 +1,573 @@ | 
| -#include "PathOpsExtendedTest.h" | 
| -#include "PathOpsThreadedCommon.h" | 
| + | 
| #include "SkBitmap.h" | 
| +#include "SkCanvas.h" | 
| #include "SkColor.h" | 
| +#include "SkColorPriv.h" | 
| #include "SkDevice.h" | 
| -#include "SkCanvas.h" | 
| +#include "SkGraphics.h" | 
| #include "SkImageDecoder.h" | 
| #include "SkImageEncoder.h" | 
| -#include "SkStream.h" | 
| #include "SkOSFile.h" | 
| +#include "SkPathOpsDebug.h" | 
| #include "SkPicture.h" | 
| +#include "SkRTConf.h" | 
| +#include "SkStream.h" | 
| #include "SkString.h" | 
| +#include "SkTArray.h" | 
| +#include "SkTDArray.h" | 
| +#include "SkThreadPool.h" | 
| +#include "SkTime.h" | 
| +#include "Test.h" | 
|  | 
| #ifdef SK_BUILD_FOR_WIN | 
| #define PATH_SLASH "\\" | 
| -    #define IN_DIR "D:" PATH_SLASH "skp" | 
| -    #define OUT_DIR "D:" PATH_SLASH | 
| +    #define IN_DIR "D:\\9-30-13\\" | 
| +    #define OUT_DIR "D:\\opSkpClip\\1\\" | 
| #else | 
| #define PATH_SLASH "/" | 
| -    #if 1 | 
| -        #define IN_DIR "/usr/local/google/home/caryclark/new10k" PATH_SLASH | 
| -        #define OUT_DIR "/usr/local/google/home/caryclark/out10k" PATH_SLASH | 
| +    #ifdef SK_BUILD_FOR_MAC | 
| +        #define IN_DIR "/Volumes/tera/9-30-13/skp" | 
| +        #define OUT_DIR "/Volumes/tera/out/9-30-13/1/" | 
| #else | 
| -        #define IN_DIR "/usr/local/google/home/caryclark/6-18-13" PATH_SLASH | 
| -        #define OUT_DIR "/usr/local/google/home/caryclark" PATH_SLASH | 
| +        #define IN_DIR "/usr/local/google/home/caryclark/skps/9-30-13/skp" | 
| +        #define OUT_DIR "/mnt/skia/opSkpClip/1/" | 
| #endif | 
| #endif | 
|  | 
| -static const char pictDir[] = IN_DIR ; | 
| -static const char outSkpClipDir[] = OUT_DIR "skpClip"; | 
| -static const char outOldClipDir[] = OUT_DIR "oldClip"; | 
| +const struct { | 
| +    int directory; | 
| +    const char* filename; | 
| +} skipOverSept[] = { | 
| +    {9, "http___www_symptome_ch_.skp"}, // triangle clip with corner at x.999 | 
| +    {11, "http___www_menly_fr_.skp"}, | 
| +    {12, "http___www_banrasdr_com_.skp"}, | 
| +}; | 
| + | 
| +size_t skipOverSeptCount = sizeof(skipOverSept) / sizeof(skipOverSept[0]); | 
| + | 
| +enum TestStep { | 
| +    kCompareBits, | 
| +    kEncodeFiles, | 
| +}; | 
| + | 
| +enum { | 
| +    kMaxLength = 128, | 
| +    kMaxFiles = 128, | 
| +    kSmallLimit = 1000, | 
| +}; | 
| + | 
| +struct TestResult { | 
| +    void init(int dirNo) { | 
| +        fDirNo = dirNo; | 
| +        sk_bzero(fFilename, sizeof(fFilename)); | 
| +        fTestStep = kCompareBits; | 
| +        fScaleOversized = true; | 
| +    } | 
| + | 
| +    SkString status() { | 
| +        SkString outStr; | 
| +        outStr.printf("%s %d %d\n", fFilename, fPixelError, fTime); | 
| +        return outStr; | 
| +    } | 
| + | 
| +    static void Test(int dirNo, const char* filename, TestStep testStep) { | 
| +        TestResult test; | 
| +        test.init(dirNo); | 
| +        test.fTestStep = testStep; | 
| +        strcpy(test.fFilename, filename); | 
| +        test.testOne(); | 
| +    } | 
| + | 
| +    void test(int dirNo, const SkString& filename) { | 
| +        init(dirNo); | 
| +        strcpy(fFilename, filename.c_str()); | 
| +        testOne(); | 
| +    } | 
| + | 
| +    void testOne(); | 
| + | 
| +    char fFilename[kMaxLength]; | 
| +    TestStep fTestStep; | 
| +    int fDirNo; | 
| +    int fPixelError; | 
| +    int fTime; | 
| +    bool fScaleOversized; | 
| +}; | 
| + | 
| +struct TestState { | 
| +    void init(int dirNo, skiatest::Reporter* reporter) { | 
| +        fReporter = reporter; | 
| +        fResult.init(dirNo); | 
| +        fFoundCount = 0; | 
| +        TestState::fSmallCount = 0; | 
| +        fSmallestError = 0; | 
| +        sk_bzero(fFilesFound, sizeof(fFilesFound)); | 
| +        sk_bzero(fDirsFound, sizeof(fDirsFound)); | 
| +        sk_bzero(fError, sizeof(fError)); | 
| +    } | 
| + | 
| +    static bool bumpSmallCount() { | 
| +        sk_atomic_inc(&fSmallCount); | 
| +        return fSmallCount > kSmallLimit; | 
| +    } | 
| + | 
| +    static void clearSmallCount() { | 
| +        if (fSmallCount < kSmallLimit) { | 
| +            fSmallCount = 0; | 
| +        } | 
| +    } | 
| + | 
| +    char fFilesFound[kMaxFiles][kMaxLength]; | 
| +    int fDirsFound[kMaxFiles]; | 
| +    int fError[kMaxFiles]; | 
| +    int fFoundCount; | 
| +    static int fSmallCount; | 
| +    int fSmallestError; | 
| +    skiatest::Reporter* fReporter; | 
| +    TestResult fResult; | 
| +}; | 
| + | 
| +int TestState::fSmallCount; | 
| + | 
| +struct TestRunner { | 
| +    TestRunner(skiatest::Reporter* reporter, int threadCount) | 
| +        : fNumThreads(threadCount) | 
| +        , fReporter(reporter) { | 
| +    } | 
| + | 
| +    ~TestRunner(); | 
| +    void render(); | 
| +    int fNumThreads; | 
| +    SkTDArray<class TestRunnable*> fRunnables; | 
| +    skiatest::Reporter* fReporter; | 
| +}; | 
| + | 
| +class TestRunnable : public SkRunnable { | 
| +public: | 
| +    TestRunnable(void (*testFun)(TestState*), int dirNo, TestRunner* runner) { | 
| +        fState.init(dirNo, runner->fReporter); | 
| +        fTestFun = testFun; | 
| +    } | 
| + | 
| +    virtual void run() SK_OVERRIDE { | 
| +        SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024); | 
| +        (*fTestFun)(&fState); | 
| +    } | 
| + | 
| +    TestState fState; | 
| +    void (*fTestFun)(TestState*); | 
| +}; | 
| + | 
| +TestRunner::~TestRunner() { | 
| +    for (int index = 0; index < fRunnables.count(); index++) { | 
| +        SkDELETE(fRunnables[index]); | 
| +    } | 
| +} | 
| + | 
| +void TestRunner::render() { | 
| +    SkThreadPool pool(fNumThreads); | 
| +    for (int index = 0; index < fRunnables.count(); ++ index) { | 
| +        pool.add(fRunnables[index]); | 
| +    } | 
| +} | 
| + | 
| +//////////////////////////////////////////////// | 
| + | 
| +static const char outOpDir[] = OUT_DIR "opClip"; | 
| +static const char outOldDir[] = OUT_DIR "oldClip"; | 
| +static const char outSkpDir[] = OUT_DIR "skpTest"; | 
| +static const char outDiffDir[] = OUT_DIR "outTest"; | 
| +static const char outStatusDir[] = OUT_DIR "statusTest"; | 
|  | 
| -static SkString make_filepath(const char* dir, const SkString& name) { | 
| +static SkString make_filepath(int dirNo, const char* dir, const char* name) { | 
| SkString path(dir); | 
| -    size_t len = strlen(dir); | 
| -    if (len > 0 && dir[len - 1] != PATH_SLASH[0]) { | 
| -        path.append(PATH_SLASH); | 
| +    if (dirNo) { | 
| +        path.appendf("%d", dirNo); | 
| } | 
| +    path.append(PATH_SLASH); | 
| path.append(name); | 
| return path; | 
| } | 
|  | 
| -static SkString make_png_name(const SkString& filename) { | 
| +static SkString make_in_dir_name(int dirNo) { | 
| +    SkString dirName(IN_DIR); | 
| +    dirName.appendf("%d", dirNo); | 
| +    if (!sk_exists(dirName.c_str())) { | 
| +        SkDebugf("could not read dir %s\n", dirName.c_str()); | 
| +        return SkString(); | 
| +    } | 
| +    return dirName; | 
| +} | 
| + | 
| +static bool make_one_out_dir(const char* outDirStr) { | 
| +    SkString outDir = make_filepath(0, outDirStr, ""); | 
| +    if (!sk_exists(outDir.c_str())) { | 
| +        if (!sk_mkdir(outDir.c_str())) { | 
| +            SkDebugf("could not create dir %s\n", outDir.c_str()); | 
| +            return false; | 
| +        } | 
| +    } | 
| +    return true; | 
| +} | 
| + | 
| +static bool make_out_dirs() { | 
| +    SkString outDir = make_filepath(0, OUT_DIR, ""); | 
| +    if (!sk_exists(outDir.c_str())) { | 
| +        if (!sk_mkdir(outDir.c_str())) { | 
| +            SkDebugf("could not create dir %s\n", outDir.c_str()); | 
| +            return false; | 
| +        } | 
| +    } | 
| +    return make_one_out_dir(outOldDir) | 
| +            && make_one_out_dir(outOpDir) | 
| +            && make_one_out_dir(outSkpDir) | 
| +            && make_one_out_dir(outDiffDir) | 
| +            && make_one_out_dir(outStatusDir); | 
| +} | 
| + | 
| +static SkString make_png_name(const char* filename) { | 
| SkString pngName = SkString(filename); | 
| pngName.remove(pngName.size() - 3, 3); | 
| pngName.append("png"); | 
| return pngName; | 
| } | 
|  | 
| -static void testOne(const SkString& filename) { | 
| -    if (filename == SkString("http___migracioncolombia_gov_co.skp") | 
| -            || filename == SkString("http___miuki_info.skp") | 
| -    ) { | 
| -        return; | 
| +static int similarBits(const SkBitmap& gr, const SkBitmap& sk) { | 
| +    const int kRowCount = 3; | 
| +    const int kThreshold = 3; | 
| +    int width = SkTMin(gr.width(), sk.width()); | 
| +    if (width < kRowCount) { | 
| +        return true; | 
| } | 
| -#if DEBUG_SHOW_TEST_NAME | 
| -    SkString testName(filename); | 
| -    const char http[] = "http"; | 
| -    if (testName.startsWith(http)) { | 
| -        testName.remove(0, sizeof(http) - 1); | 
| +    int height = SkTMin(gr.height(), sk.height()); | 
| +    if (height < kRowCount) { | 
| +        return true; | 
| } | 
| -    while (testName.startsWith("_")) { | 
| -        testName.remove(0, 1); | 
| +    int errorTotal = 0; | 
| +    SkTArray<int, true> errorRows; | 
| +    errorRows.push_back_n(width * kRowCount); | 
| +    SkAutoLockPixels autoGr(gr); | 
| +    SkAutoLockPixels autoSk(sk); | 
| +    for (int y = 0; y < height; ++y) { | 
| +        SkPMColor* grRow = gr.getAddr32(0, y); | 
| +        SkPMColor* skRow = sk.getAddr32(0, y); | 
| +        int* base = &errorRows[0]; | 
| +        int* cOut = &errorRows[y % kRowCount]; | 
| +        for (int x = 0; x < width; ++x) { | 
| +            SkPMColor grColor = grRow[x]; | 
| +            SkPMColor skColor = skRow[x]; | 
| +            int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor); | 
| +            int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor); | 
| +            int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor); | 
| +            int error = cOut[x] = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db))); | 
| +            if (error < kThreshold || x < 2) { | 
| +                continue; | 
| +            } | 
| +            if (base[x - 2] < kThreshold | 
| +                    || base[width + x - 2] < kThreshold | 
| +                    || base[width * 2 + x - 2] < kThreshold | 
| +                    || base[x - 1] < kThreshold | 
| +                    || base[width + x - 1] < kThreshold | 
| +                    || base[width * 2 + x - 1] < kThreshold | 
| +                    || base[x] < kThreshold | 
| +                    || base[width + x] < kThreshold | 
| +                    || base[width * 2 + x] < kThreshold) { | 
| +                continue; | 
| +            } | 
| +            errorTotal += error; | 
| +        } | 
| } | 
| -    const char dotSkp[] = ".skp"; | 
| -    if (testName.endsWith(dotSkp)) { | 
| -        size_t len = testName.size(); | 
| -        testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1); | 
| +    return errorTotal; | 
| +} | 
| + | 
| +static bool addError(TestState* data, const TestResult& testResult) { | 
| +    bool foundSmaller = false; | 
| +    int dCount = data->fFoundCount; | 
| +    int pixelError = testResult.fPixelError; | 
| +    if (data->fFoundCount < kMaxFiles) { | 
| +        data->fError[dCount] = pixelError; | 
| +        strcpy(data->fFilesFound[dCount], testResult.fFilename); | 
| +        data->fDirsFound[dCount] = testResult.fDirNo; | 
| +        ++data->fFoundCount; | 
| +    } else if (pixelError > data->fSmallestError) { | 
| +        int smallest = SK_MaxS32; | 
| +        int smallestIndex = 0; | 
| +        for (int index = 0; index < kMaxFiles; ++index) { | 
| +            if (smallest > data->fError[index]) { | 
| +                smallest = data->fError[index]; | 
| +                smallestIndex = index; | 
| +            } | 
| +        } | 
| +        data->fError[smallestIndex] = pixelError; | 
| +        strcpy(data->fFilesFound[smallestIndex], testResult.fFilename); | 
| +        data->fDirsFound[smallestIndex] = testResult.fDirNo; | 
| +        data->fSmallestError = SK_MaxS32; | 
| +        for (int index = 0; index < kMaxFiles; ++index) { | 
| +            if (data->fSmallestError > data->fError[index]) { | 
| +                data->fSmallestError = data->fError[index]; | 
| +            } | 
| +        } | 
| +        SkDebugf("*%d*", data->fSmallestError); | 
| +        foundSmaller = true; | 
| } | 
| -    testName.prepend("skp"); | 
| -    testName.append("1"); | 
| -    strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH); | 
| -#endif | 
| -    SkString path = make_filepath(pictDir, filename); | 
| -    SkFILEStream stream(path.c_str()); | 
| -    if (!stream.isValid()) { | 
| -        return; | 
| +    return foundSmaller; | 
| +} | 
| + | 
| + | 
| + | 
| +static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) { | 
| +    canvas->save(); | 
| +    int pWidth = pic->width(); | 
| +    int pHeight = pic->height(); | 
| +    const int maxDimension = 1000; | 
| +    const int slices = 3; | 
| +    int xInterval = SkTMax(pWidth - maxDimension, 0) / (slices - 1); | 
| +    int yInterval = SkTMax(pHeight - maxDimension, 0) / (slices - 1); | 
| +    SkRect rect = {0, 0, SkIntToScalar(SkTMin(maxDimension, pWidth)), | 
| +            SkIntToScalar(SkTMin(maxDimension, pHeight))}; | 
| +    canvas->clipRect(rect); | 
| +    SkMSec start = SkTime::GetMSecs(); | 
| +    for (int x = 0; x < slices; ++x) { | 
| +        for (int y = 0; y < slices; ++y) { | 
| +            pic->draw(canvas); | 
| +            canvas->translate(0, SkIntToScalar(yInterval)); | 
| +        } | 
| +        canvas->translate(SkIntToScalar(xInterval), SkIntToScalar(-yInterval * slices)); | 
| } | 
| -    SkPicture* pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory); | 
| -    if (!pic) { | 
| -        SkDebugf("unable to decode %s\n", filename.c_str()); | 
| -        return; | 
| +    SkMSec end = SkTime::GetMSecs(); | 
| +    canvas->restore(); | 
| +    return end - start; | 
| +} | 
| + | 
| +static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) { | 
| +    canvas->clear(SK_ColorWHITE); | 
| +    if (scale != 1) { | 
| +        canvas->save(); | 
| +        canvas->scale(1.0f / scale, 1.0f / scale); | 
| } | 
| -    int width = pic->width(); | 
| -    int height = pic->height(); | 
| - | 
| -    SkBitmap bitmap; | 
| -    int scale = 1; | 
| -    do { | 
| -        bitmap.setConfig(SkBitmap::kARGB_8888_Config, (width + scale - 1) / scale, | 
| -            (height + scale - 1) / scale); | 
| -        bool success = bitmap.allocPixels(); | 
| -        bitmap.eraseColor(SK_ColorWHITE); | 
| -        if (success) { | 
| -            break; | 
| -        } | 
| -        SkDebugf("-%d-", scale); | 
| -    } while ((scale *= 2) < 32); | 
| -    if (scale >= 32) { | 
| -        SkDebugf("unable to allocate bitmap for %s (w=%d h=%d)\n", filename.c_str(), | 
| -                width, height); | 
| -        return; | 
| +    pic->draw(canvas); | 
| +    if (scale != 1) { | 
| +        canvas->restore(); | 
| +    } | 
| +} | 
| + | 
| +static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) { | 
| +    SkString outFile = make_filepath(0, outDir, pngName); | 
| +    if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, | 
| +            SkImageEncoder::kPNG_Type, 100)) { | 
| +        SkDebugf("unable to encode gr %s (width=%d height=%d)\n", pngName, | 
| +                    bitmap.width(), bitmap.height()); | 
| } | 
| -    SkCanvas canvas(bitmap); | 
| -    canvas.scale(1.0f / scale, 1.0f / scale); | 
| -    SkString pngName = make_png_name(filename); | 
| -    for (int i = 0; i < 2; ++i) { | 
| -        bool useOp = i ? true : false; | 
| -        canvas.setAllowSimplifyClip(useOp); | 
| -        pic->draw(&canvas); | 
| -        SkString outFile = make_filepath(useOp ? outSkpClipDir : outOldClipDir, pngName); | 
| -        if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap, SkImageEncoder::kPNG_Type, | 
| -                100)) { | 
| -            SkDebugf("unable to encode %s (width=%d height=%d)\n", pngName.c_str(), | 
| -                     bitmap.width(), bitmap.height()); | 
| +} | 
| + | 
| +void TestResult::testOne() { | 
| +    SkPicture* pic = NULL; | 
| +    { | 
| +    #if DEBUG_SHOW_TEST_NAME | 
| +        if (fTestStep == kCompareBits) { | 
| +            SkString testName(fFilename); | 
| +            const char http[] = "http"; | 
| +            if (testName.startsWith(http)) { | 
| +                testName.remove(0, sizeof(http) - 1); | 
| +            } | 
| +            while (testName.startsWith("_")) { | 
| +                testName.remove(0, 1); | 
| +            } | 
| +            const char dotSkp[] = ".skp"; | 
| +            if (testName.endsWith(dotSkp)) { | 
| +                size_t len = testName.size(); | 
| +                testName.remove(len - (sizeof(dotSkp) - 1), sizeof(dotSkp) - 1); | 
| +            } | 
| +            testName.prepend("skp"); | 
| +            testName.append("1"); | 
| +            strncpy(DEBUG_FILENAME_STRING, testName.c_str(), DEBUG_FILENAME_STRING_LENGTH); | 
| +        } else if (fTestStep == kEncodeFiles) { | 
| +            strncpy(DEBUG_FILENAME_STRING, "", DEBUG_FILENAME_STRING_LENGTH); | 
| +        } | 
| +    #endif | 
| +        SkString path = make_filepath(fDirNo, IN_DIR, fFilename); | 
| +        SkFILEStream stream(path.c_str()); | 
| +        if (!stream.isValid()) { | 
| +            SkDebugf("invalid stream %s\n", path.c_str()); | 
| +            goto finish; | 
| +        } | 
| +        SkPicture* pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory); | 
| +        if (!pic) { | 
| +            SkDebugf("unable to decode %s\n", fFilename); | 
| +            goto finish; | 
| +        } | 
| +        int width = pic->width(); | 
| +        int height = pic->height(); | 
| +        SkBitmap oldBitmap, opBitmap; | 
| +        int scale = 1; | 
| +        do { | 
| +            int dimX = (width + scale - 1) / scale; | 
| +            int dimY = (height + scale - 1) / scale; | 
| +            oldBitmap.setConfig(SkBitmap::kARGB_8888_Config, dimX, dimY); | 
| +            opBitmap.setConfig(SkBitmap::kARGB_8888_Config, dimX, dimY); | 
| +            bool success = oldBitmap.allocPixels() && opBitmap.allocPixels(); | 
| +            if (success) { | 
| +                break; | 
| +            } | 
| +            SkDebugf("-%d-", scale); | 
| +        } while ((scale *= 2) < 256); | 
| +        if (scale >= 256) { | 
| +            SkDebugf("unable to allocate bitmap for %s (w=%d h=%d)\n", fFilename, | 
| +                    width, height); | 
| +            return; | 
| +        } | 
| +        oldBitmap.eraseColor(SK_ColorWHITE); | 
| +        SkCanvas oldCanvas(oldBitmap); | 
| +        oldCanvas.setAllowSimplifyClip(false); | 
| +        opBitmap.eraseColor(SK_ColorWHITE); | 
| +        SkCanvas opCanvas(opBitmap); | 
| +        opCanvas.setAllowSimplifyClip(true); | 
| +        drawPict(pic, &oldCanvas, fScaleOversized ? scale : 1); | 
| +        drawPict(pic, &opCanvas, fScaleOversized ? scale : 1); | 
| +        if (fTestStep == kCompareBits) { | 
| +            fPixelError = similarBits(oldBitmap, opBitmap); | 
| +            int oldTime = timePict(pic, &oldCanvas); | 
| +            int opTime = timePict(pic, &opCanvas); | 
| +            fTime = oldTime - opTime; | 
| +        } else if (fTestStep == kEncodeFiles) { | 
| +            SkString pngStr = make_png_name(fFilename); | 
| +            const char* pngName = pngStr.c_str(); | 
| +            writePict(oldBitmap, outOldDir, pngName); | 
| +            writePict(opBitmap, outOpDir, pngName); | 
| } | 
| } | 
| +finish: | 
| SkDELETE(pic); | 
| } | 
|  | 
| -const char* tryFixed[] = { | 
| -    0 | 
| -}; | 
| +static SkString makeStatusString(int dirNo) { | 
| +    SkString statName; | 
| +    statName.printf("stats%d.txt", dirNo); | 
| +    SkString statusFile = make_filepath(0, outStatusDir, statName.c_str()); | 
| +    return statusFile; | 
| +} | 
|  | 
| -size_t tryFixedCount = sizeof(tryFixed) / sizeof(tryFixed[0]); | 
| - | 
| -const char* skipOver[] = { | 
| -    "http___carpetplanet_ru.skp",  // cubic/cubic intersect | 
| -    "http___carrot_is.skp",  // bridgeOp()  SkASSERT(unsortable || !current->done()); | 
| - | 
| -/*!*/"http___dotsrc_org.skp",  // asserts in png decode | 
| -    "http___frauen_magazin_com.skp",  // bridgeOp()  SkASSERT(unsortable || !current->done()); | 
| -    "http___i_gino_com.skp",  // unexpected cubic/quad coincidence | 
| -                            // {61, 857, 61, 789.06897, 116.068977, 734, 184, 734} | 
| -                            // {184, 734, 133.051727, 734, 97.0258636, 770.025879} | 
| -    "http___ilkoora_com.skp",  // assert wind sum != min32 from markDoneBinary / findNextOp #28k | 
| -/*!*/"http___migracioncolombia_gov_co.skp",  // crashes on picture decode | 
| -    "http___mm4everfriends_com.skp",  // bumpSpan/addTCoincident (from calcPartialCoincidentWinding) | 
| -    "http___mtrk_uz.skp",  // checkEnds() assert #36.3k | 
| -    "http___pchappy_com_au.skp",  // bridgeOp() assert unsortable || ! empty #37.2k | 
| -    "http___sciality_com.skp",  // bridgeOp()  SkASSERT(unsortable || !current->done()); #32.4k | 
| -/*!*/"http___sozialticker_com.skp",  // asserts in png decode | 
| -    "http___sudoestenegocios_com.skp",  // assert fT < 1 in addTCoincident | 
| -    "http___thesuburbanite_com.skp",  // bridgeOp()  SkASSERT(unsortable || !current->done()); | 
| - | 
| -    "http___fluentin3months_com.skp", // calcCommonCoincidentWinding from calcPartialCoincidentWinding #38.3k | 
| -    "http___teachersbadi_blogspot_in.skp",  // calcCommonCoincidentWinding from calcPartialCoincidentWinding #53.4k | 
| -    "http___wsms_ru.skp",  // assert wind sum != min32 from markDoneBinary / findNextOp #49.5k | 
| -    "http___voycer_de.skp",  // calcCommonCoincidentWinding from calcPartialCoincidentWinding #47k | 
| -    "http___77hz_jp.skp",  // addTCancel from calcCoincidentWinding #47.1k | 
| - | 
| -    "http___hostloco_com.skp",  // t < 0  AddIntersectsT | 
| -/*!*/"http___oggicronaca_it.skp",  // asserts in png decode | 
| -    "http___sergeychunkevich_com.skp",  // t < 0  AddIntersectsT | 
| -    "http___tracksflow_com.skp",  // assert otherEnd >= 0 from nextChase | 
| -    "http___autobutler_dk.skp",  // t < 0  AddIntersectsT | 
| -    "http___onlinecollege_org.skp",  // bridgeOp() assert unsortable || ! empty #100.1k | 
| -    "http___national_com_au.skp",  // bridgeOp() assert unsortable || ! empty #110.2k | 
| -/*!*/"http___anitadongre_com.skp",  // exceptionally large width and height | 
| -    "http___rentacheat_com.skp",  // bridgeOp() assert unsortable || ! empty #110.8k | 
| -/*!*/"http___gruesse_de.skp",  // asserts in png decode | 
| -/*!*/"http___crn_in.png",  // width=1250047 | 
| -    "http___breakmystyle_com.skp",  // assert qPt == lPt in quad intersection | 
| -    "http___naoxrane_ru.skp",  // assert t4+...t0 == 0 in quartic roots #128.3k | 
| -    "http___tcmevents_org.skp",  // assert in addTCoincident (from calcPartialCoincidentWinding) #143.3k | 
| -/*!*/"http___listbuildingcashsecrets_com.skp",  // asserts in png decode #152.7k | 
| -/*!*/"http___skyscraperpage_com.skp",  // asserts in png decode #155.5k | 
| -    "http___mlk_com.skp",  // bridgeOp() assert unsortable || ! empty #158.7k | 
| -    "http___sd_graphic_net.skp",  // bridgeOp() assert unsortable || ! empty #163.3k | 
| -    "http___kopepasah_com.skp",  // checkEnds() assert #188.2k | 
| -/*!*/"http___darkreloaded_com.skp",  // asserts in png decode #188.4k | 
| -    "http___redbullskatearcade_es.skp",  // bridgeOp() assert unsortable || ! empty #192.5k | 
| -    "http___partainasdemo250_org.skp",  //  bridgeOp() assert unsortable || ! empty #200.2k | 
| - | 
| -// these failures are from the new 10k set | 
| -    "http___www_freerepublic_com_.skp",  // assert in opangle < | 
| -    "http___www_lavoixdunord_fr_.skp",  // bridgeOp() assert unsortable || ! empty | 
| -    "http___www_booking_com_.skp",  // bridgeOp() assert unsortable || ! empty | 
| -    "http___www_fj_p_com_.skp",  // markWinding assert from findChaseOp | 
| -    "http___www_leadpages_net_.skp",  // assert in opangle < | 
| -    "http___www_despegar_com_mx_.skp",  // bridgeOp() assert unsortable || ! empty | 
| -}; | 
| +class PreParser { | 
| +public: | 
| +    PreParser(int dirNo) | 
| +        : fDirNo(dirNo) | 
| +        , fIndex(0) { | 
| +        SkString statusPath = makeStatusString(dirNo); | 
| +        if (!sk_exists(statusPath.c_str())) { | 
| +            return; | 
| +        } | 
| +        SkFILEStream reader; | 
| +        reader.setPath(statusPath.c_str()); | 
| +        while (fetch(reader, &fResults.push_back())) | 
| +            ; | 
| +        fResults.pop_back(); | 
| +    } | 
| + | 
| +    bool fetch(SkFILEStream& reader, TestResult* result) { | 
| +        char c; | 
| +        int i = 0; | 
| +        result->init(fDirNo); | 
| +        result->fPixelError = 0; | 
| +        result->fTime = 0; | 
| +        do { | 
| +            bool readOne = reader.read(&c, 1) != 0; | 
| +            if (!readOne) { | 
| +                SkASSERT(i == 0); | 
| +                return false; | 
| +            } | 
| +            if (c == ' ') { | 
| +                result->fFilename[i++] = '\0'; | 
| +                break; | 
| +            } | 
| +            result->fFilename[i++] = c; | 
| +            SkASSERT(i < kMaxLength); | 
| +        } while (true); | 
| +        do { | 
| +            SkAssertResult(reader.read(&c, 1)); | 
| +            if (c == ' ') { | 
| +                break; | 
| +            } | 
| +            SkASSERT(c >= '0' && c <= '9'); | 
| +            result->fPixelError = result->fPixelError * 10 + (c - '0'); | 
| +        } while (true); | 
| +        bool minus = false; | 
| +        do { | 
| +            SkAssertResult(reader.read(&c, 1)); | 
| +            if (c == '\n') { | 
| +                break; | 
| +            } | 
| +            if (c == '-') { | 
| +                minus = true; | 
| +                continue; | 
| +            } | 
| +            SkASSERT(c >= '0' && c <= '9'); | 
| +            result->fTime = result->fTime * 10 + (c - '0'); | 
| +        } while (true); | 
| +        if (minus) { | 
| +            result->fTime = -result->fTime; | 
| +        } | 
| +        return true; | 
| +    } | 
|  | 
| -size_t skipOverCount = sizeof(skipOver) / sizeof(skipOver[0]); | 
| +    bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) { | 
| +        if (fIndex < fResults.count()) { | 
| +            *result = fResults[fIndex++]; | 
| +            SkASSERT(filename.equals(result->fFilename)); | 
| +            SkString outStr(result->status()); | 
| +            stream->write(outStr.c_str(), outStr.size()); | 
| +            return true; | 
| +        } | 
| +        return false; | 
| +    } | 
|  | 
| -static void PathOpsSkpClipTest(skiatest::Reporter* reporter) { | 
| -    SkOSFile::Iter iter(pictDir, "skp"); | 
| +private: | 
| +    int fDirNo; | 
| +    int fIndex; | 
| +    SkTArray<TestResult, true> fResults; | 
| +}; | 
| + | 
| +static bool doOneDir(TestState* state) { | 
| +    int dirNo = state->fResult.fDirNo; | 
| +    skiatest::Reporter* reporter = state->fReporter; | 
| +    SkString dirName = make_in_dir_name(dirNo); | 
| +    SkASSERT(dirName.size()); | 
| +    SkOSFile::Iter iter(dirName.c_str(), "skp"); | 
| SkString filename; | 
| int testCount = 0; | 
| +    PreParser preParser(dirNo); | 
| +    SkFILEWStream statusStream(makeStatusString(dirNo).c_str()); | 
| while (iter.next(&filename)) { | 
| -        SkString pngName = make_png_name(filename); | 
| -        SkString oldPng = make_filepath(outOldClipDir, pngName); | 
| -        SkString newPng = make_filepath(outSkpClipDir, pngName); | 
| -        if (sk_exists(oldPng.c_str()) && sk_exists(newPng.c_str())) { | 
| -            reporter->bumpTestCount(); | 
| -            continue; | 
| -        } | 
| -        for (size_t index = 0; index < skipOverCount; ++index) { | 
| -            if (skipOver[index] && strcmp(filename.c_str(), skipOver[index]) == 0) { | 
| -                reporter->bumpTestCount(); | 
| +        for (size_t index = 0; index < skipOverSeptCount; ++index) { | 
| +            if (skipOverSept[index].directory == dirNo | 
| +                    && strcmp(filename.c_str(), skipOverSept[index].filename) == 0) { | 
| goto skipOver; | 
| } | 
| } | 
| -        testOne(filename); | 
| +        if (preParser.match(filename, &statusStream, &state->fResult)) { | 
| +            addError(state, state->fResult); | 
| +            ++testCount; | 
| +            goto checkEarlyExit; | 
| +        } | 
| +        if (state->fSmallestError > 5000000) { | 
| +            return false; | 
| +        } | 
| +        { | 
| +            TestResult& result = state->fResult; | 
| +            result.test(dirNo, filename); | 
| +            SkString outStr(result.status()); | 
| +            statusStream.write(outStr.c_str(), outStr.size()); | 
| +            statusStream.flush(); | 
| +            if (1) { | 
| +                SkDebugf("%s", outStr.c_str()); | 
| +            } | 
| +            bool noMatch = addError(state, state->fResult); | 
| +            if (noMatch) { | 
| +                state->clearSmallCount(); | 
| +            } else if (state->bumpSmallCount()) { | 
| +                return false; | 
| +            } | 
| +        } | 
| +        ++testCount; | 
| if (reporter->verbose()) { | 
| SkDebugf("."); | 
| if (++testCount % 100 == 0) { | 
| @@ -209,85 +575,112 @@ static void PathOpsSkpClipTest(skiatest::Reporter* reporter) { | 
| } | 
| } | 
| skipOver: | 
| -        reporter->bumpTestCount(); | 
| +        if (reporter->verbose()) { | 
| +            static int threadTestCount; | 
| +            SkDebugf("."); | 
| +            sk_atomic_inc(&threadTestCount); | 
| +            if (threadTestCount % 100 == 0) { | 
| +                SkDebugf("%d\n", threadTestCount); | 
| +            } | 
| +        } | 
| +checkEarlyExit: | 
| +        if (1 && testCount == 20) { | 
| +            return true; | 
| +        } | 
| } | 
| +    return true; | 
| +} | 
| + | 
| +static bool initTest() { | 
| +#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC | 
| +    SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); | 
| +    SK_CONF_SET("images.png.suppressDecoderWarnings", true); | 
| +#endif | 
| +    return make_out_dirs(); | 
| } | 
|  | 
| -static void bumpCount(skiatest::Reporter* reporter, bool skipping) { | 
| +static void encodeFound(skiatest::Reporter* reporter, TestState& state) { | 
| if (reporter->verbose()) { | 
| -        static int threadTestCount; | 
| -        if (!skipping) { | 
| -            SkDebugf("."); | 
| +        for (int index = 0; index < state.fFoundCount; ++index) { | 
| +            SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index], | 
| +                     state.fError[index]); | 
| } | 
| -        sk_atomic_inc(&threadTestCount); | 
| -        if (!skipping && threadTestCount % 100 == 0) { | 
| -            SkDebugf("%d\n", threadTestCount); | 
| +    } | 
| +    for (int index = 0; index < state.fFoundCount; ++index) { | 
| +        TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles); | 
| +        if (state.fReporter->verbose()) SkDebugf("+"); | 
| +    } | 
| +} | 
| + | 
| +static void PathOpsSkpClipTest(skiatest::Reporter* reporter) { | 
| +    if (!initTest()) { | 
| +        return; | 
| +    } | 
| +    SkTArray<TestResult, true> errors; | 
| +    TestState state; | 
| +    state.init(0, reporter); | 
| +    for (int dirNo = 1; dirNo <= 100; ++dirNo) { | 
| +        if (reporter->verbose()) { | 
| +            SkDebugf("dirNo=%d\n", dirNo); | 
| } | 
| -        if (skipping && threadTestCount % 10000 == 0) { | 
| -            SkDebugf("%d\n", threadTestCount); | 
| +        state.fResult.fDirNo = dirNo; | 
| +        if (!doOneDir(&state)) { | 
| +            break; | 
| } | 
| } | 
| +    encodeFound(reporter, state); | 
| } | 
|  | 
| -static void testSkpClipMain(PathOpsThreadState* data) { | 
| -    SkString str(data->fSerialNo); | 
| -    testOne(str); | 
| -    bumpCount(data->fReporter, false); | 
| -    data->fReporter->bumpTestCount(); | 
| +static void testSkpClipMain(TestState* data) { | 
| +        (void) doOneDir(data); | 
| } | 
|  | 
| static void PathOpsSkpClipThreadedTest(skiatest::Reporter* reporter) { | 
| -    int threadCount = initializeTests(reporter, "skpClipThreadedTest"); | 
| -    PathOpsThreadedTestRunner testRunner(reporter, threadCount); | 
| -    SkOSFile::Iter iter(pictDir, "skp"); | 
| -    SkString filename; | 
| -    while (iter.next(&filename)) { | 
| -        SkString pngName = make_png_name(filename); | 
| -        SkString oldPng = make_filepath(outOldClipDir, pngName); | 
| -        SkString newPng = make_filepath(outSkpClipDir, pngName); | 
| -        if (sk_exists(oldPng.c_str()) && sk_exists(newPng.c_str())) { | 
| -            bumpCount(reporter, true); | 
| -            continue; | 
| -        } | 
| -        for (size_t index = 0; index < skipOverCount; ++index) { | 
| -            if (skipOver[index] && strcmp(filename.c_str(), skipOver[index]) == 0) { | 
| -                bumpCount(reporter, true); | 
| -                goto skipOver; | 
| -            } | 
| -        } | 
| -        *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable, | 
| -                (&testSkpClipMain, filename.c_str(), &testRunner)); | 
| -skipOver: | 
| -        ; | 
| +    if (!initTest()) { | 
| +        return; | 
| +    } | 
| +    int threadCount = reporter->allowThreaded() ? SkThreadPool::kThreadPerCore : 1; | 
| +    TestRunner testRunner(reporter, threadCount); | 
| +    for (int dirNo = 1; dirNo <= 100; ++dirNo) { | 
| +        *testRunner.fRunnables.append() = SkNEW_ARGS(TestRunnable, | 
| +                (&testSkpClipMain, dirNo, &testRunner)); | 
| } | 
| testRunner.render(); | 
| -} | 
| - | 
| -static void PathOpsSkpClipFixedTest(skiatest::Reporter* reporter) { | 
| -    for (size_t index = 0; index < tryFixedCount; ) { | 
| -        SkString filename(tryFixed[index]); | 
| -        testOne(filename); | 
| -        ++index; | 
| -        if (reporter->verbose()) { | 
| -            SkDebugf("."); | 
| -            if (index % 100 == 0) { | 
| -                SkDebugf("\n"); | 
| -            } | 
| +    TestState state; | 
| +    state.init(0, reporter); | 
| +    for (int dirNo = 1; dirNo <= 100; ++dirNo) { | 
| +        TestState& testState = testRunner.fRunnables[dirNo - 1]->fState; | 
| +        for (int inner = 0; inner < testState.fFoundCount; ++inner) { | 
| +            TestResult& testResult = testState.fResult; | 
| +            SkASSERT(testResult.fDirNo == dirNo); | 
| +            testResult.fPixelError = testState.fError[inner]; | 
| +            strcpy(testResult.fFilename, testState.fFilesFound[inner]); | 
| +            addError(&state, testResult); | 
| } | 
| -        reporter->bumpTestCount(); | 
| } | 
| +    encodeFound(reporter, state); | 
| } | 
|  | 
| static void PathOpsSkpClipOneOffTest(skiatest::Reporter* reporter) { | 
| -    SkString filename("http___78_cn_.skp"); | 
| -    testOne(filename); | 
| +    if (!initTest()) { | 
| +        return; | 
| +    } | 
| +    const int testIndex = 43 - 41; | 
| +    int dirNo = skipOverSept[testIndex].directory; | 
| +    SkAssertResult(make_in_dir_name(dirNo).size()); | 
| +    SkString filename(skipOverSept[testIndex].filename); | 
| +    TestResult state; | 
| +    state.test(dirNo, filename); | 
| +    if (reporter->verbose()) { | 
| +        SkDebugf("%s", state.status().c_str()); | 
| +    } | 
| +    state.fTestStep = kEncodeFiles; | 
| +    state.testOne(); | 
| } | 
|  | 
| #include "TestClassDef.h" | 
| DEFINE_TESTCLASS_SHORT(PathOpsSkpClipTest) | 
|  | 
| -DEFINE_TESTCLASS_SHORT(PathOpsSkpClipFixedTest) | 
| - | 
| DEFINE_TESTCLASS_SHORT(PathOpsSkpClipOneOffTest) | 
|  | 
| DEFINE_TESTCLASS_SHORT(PathOpsSkpClipThreadedTest) | 
|  |