1/*
2 * Copyright 2011 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/*
9 * Code for the "gm" (Golden Master) rendering comparison tool.
10 *
11 * If you make changes to this, re-run the self-tests at gm/tests/run.sh
12 * to make sure they still pass... you may need to change the expected
13 * results of the self-test.
14 */
15
16#include "gm.h"
17#include "gm_error.h"
18#include "gm_expectations.h"
19#include "system_preferences.h"
20#include "CrashHandler.h"
21#include "Resources.h"
22#include "SamplePipeControllers.h"
23#include "SkBitmap.h"
24#include "SkColorPriv.h"
25#include "SkCommandLineFlags.h"
26#include "SkData.h"
27#include "SkDeferredCanvas.h"
28#include "SkDevice.h"
29#include "SkDocument.h"
30#include "SkDrawFilter.h"
31#include "SkForceLinking.h"
32#include "SkGPipe.h"
33#include "SkGraphics.h"
34#include "SkImageDecoder.h"
35#include "SkImageEncoder.h"
36#include "SkJSONCPP.h"
37#include "SkOSFile.h"
38#include "SkPDFRasterizer.h"
39#include "SkPicture.h"
40#include "SkPictureRecorder.h"
41#include "SkRefCnt.h"
42#include "SkScalar.h"
43#include "SkStream.h"
44#include "SkString.h"
45#include "SkSurface.h"
46#include "SkTArray.h"
47#include "SkTDict.h"
48
49#ifdef SK_DEBUG
50static const bool kDebugOnly = true;
51#define GR_DUMP_FONT_CACHE 0
52#else
53static const bool kDebugOnly = false;
54#endif
55
56__SK_FORCE_IMAGE_DECODER_LINKING;
57
58#if SK_SUPPORT_GPU
59#include "GrContextFactory.h"
60#include "SkGpuDevice.h"
61typedef GrContextFactory::GLContextType GLContextType;
62#define DEFAULT_CACHE_VALUE -1
63static int gGpuCacheSizeBytes;
64static int gGpuCacheSizeCount;
65#else
66class GrContextFactory;
67class GrContext;
68class GrSurface;
69typedef int GLContextType;
70#endif
71
72#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
73
74DECLARE_bool(useDocumentInsteadOfDevice);
75
76#ifdef SK_SUPPORT_PDF
77    #include "SkPDFDevice.h"
78    #include "SkPDFDocument.h"
79#endif
80
81// Until we resolve http://code.google.com/p/skia/issues/detail?id=455 ,
82// stop writing out XPS-format image baselines in gm.
83#undef SK_SUPPORT_XPS
84#ifdef SK_SUPPORT_XPS
85    #include "SkXPSDevice.h"
86#endif
87
88#ifdef SK_BUILD_FOR_MAC
89    #include "SkCGUtils.h"
90#endif
91
92using namespace skiagm;
93
94class Iter {
95public:
96    Iter() {
97        this->reset();
98    }
99
100    void reset() {
101        fReg = GMRegistry::Head();
102    }
103
104    GM* next() {
105        if (fReg) {
106            GMRegistry::Factory fact = fReg->factory();
107            fReg = fReg->next();
108            return fact(0);
109        }
110        return NULL;
111    }
112
113    static int Count() {
114        const GMRegistry* reg = GMRegistry::Head();
115        int count = 0;
116        while (reg) {
117            count += 1;
118            reg = reg->next();
119        }
120        return count;
121    }
122
123private:
124    const GMRegistry* fReg;
125};
126
127// TODO(epoger): Right now, various places in this code assume that all the
128// image files read/written by GM use this file extension.
129// Search for references to this constant to find these assumptions.
130const static char kPNG_FileExtension[] = "png";
131
132enum Backend {
133    kRaster_Backend,
134    kGPU_Backend,
135    kPDF_Backend,
136    kXPS_Backend,
137};
138
139enum BbhType {
140    kNone_BbhType,
141    kRTree_BbhType,
142    kTileGrid_BbhType,
143    kQuadTree_BbhType
144};
145
146enum ConfigFlags {
147    kNone_ConfigFlag  = 0x0,
148    /* Write GM images if a write path is provided. */
149    kWrite_ConfigFlag = 0x1,
150    /* Read reference GM images if a read path is provided. */
151    kRead_ConfigFlag  = 0x2,
152    kRW_ConfigFlag    = (kWrite_ConfigFlag | kRead_ConfigFlag),
153};
154
155struct ConfigData {
156    SkColorType                     fColorType;
157    Backend                         fBackend;
158    GLContextType                   fGLContextType; // GPU backend only
159    int                             fSampleCnt;     // GPU backend only
160    ConfigFlags                     fFlags;
161    const char*                     fName;
162    bool                            fRunByDefault;
163};
164
165struct PDFRasterizerData {
166    bool        (*fRasterizerFunction)(SkStream*, SkBitmap*);
167    const char* fName;
168    bool        fRunByDefault;
169};
170
171class BWTextDrawFilter : public SkDrawFilter {
172public:
173    virtual bool filter(SkPaint*, Type) SK_OVERRIDE;
174};
175bool BWTextDrawFilter::filter(SkPaint* p, Type t) {
176    if (kText_Type == t) {
177        p->setAntiAlias(false);
178    }
179    return true;
180}
181
182struct PipeFlagComboData {
183    const char* name;
184    uint32_t flags;
185};
186
187static PipeFlagComboData gPipeWritingFlagCombos[] = {
188    { "", 0 },
189    { " cross-process", SkGPipeWriter::kCrossProcess_Flag },
190    { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag
191        | SkGPipeWriter::kSharedAddressSpace_Flag }
192};
193
194static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap);
195DECLARE_int32(pdfRasterDpi);
196
197const static ErrorCombination kDefaultIgnorableErrorTypes = ErrorCombination()
198    .plus(kMissingExpectations_ErrorType)
199    .plus(kIntentionallySkipped_ErrorType);
200
201class GMMain {
202public:
203    GMMain() : fUseFileHierarchy(false), fWriteChecksumBasedFilenames(false),
204               fIgnorableErrorTypes(kDefaultIgnorableErrorTypes),
205               fMismatchPath(NULL), fMissingExpectationsPath(NULL), fTestsRun(0),
206               fRenderModesEncountered(1) {}
207
208    /**
209     * Assemble shortNamePlusConfig from (surprise!) shortName and configName.
210     *
211     * The method for doing so depends on whether we are using hierarchical naming.
212     * For example, shortName "selftest1" and configName "8888" could be assembled into
213     * either "selftest1_8888" or "8888/selftest1".
214     */
215    SkString make_shortname_plus_config(const char *shortName, const char *configName) {
216        SkString name;
217        if (0 == strlen(configName)) {
218            name.append(shortName);
219        } else if (fUseFileHierarchy) {
220            name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName);
221        } else {
222            name.appendf("%s_%s", shortName, configName);
223        }
224        return name;
225    }
226
227    /**
228     * Assemble filename, suitable for writing out the results of a particular test.
229     */
230    SkString make_filename(const char *path,
231                           const char *shortName,
232                           const char *configName,
233                           const char *renderModeDescriptor,
234                           const char *suffix) {
235        SkString filename = make_shortname_plus_config(shortName, configName);
236        filename.append(renderModeDescriptor);
237        filename.appendUnichar('.');
238        filename.append(suffix);
239        return SkOSPath::SkPathJoin(path, filename.c_str());
240    }
241
242    /**
243     * Assemble filename suitable for writing out an SkBitmap.
244     */
245    SkString make_bitmap_filename(const char *path,
246                                  const char *shortName,
247                                  const char *configName,
248                                  const char *renderModeDescriptor,
249                                  const GmResultDigest &bitmapDigest) {
250        if (fWriteChecksumBasedFilenames) {
251            SkString filename;
252            filename.append(bitmapDigest.getHashType());
253            filename.appendUnichar('_');
254            filename.append(shortName);
255            filename.appendUnichar('_');
256            filename.append(bitmapDigest.getDigestValue());
257            filename.appendUnichar('.');
258            filename.append(kPNG_FileExtension);
259            return SkOSPath::SkPathJoin(path, filename.c_str());
260        } else {
261            return make_filename(path, shortName, configName, renderModeDescriptor,
262                                 kPNG_FileExtension);
263        }
264    }
265
266    /* since PNG insists on unpremultiplying our alpha, we take no
267       precision chances and force all pixels to be 100% opaque,
268       otherwise on compare we may not get a perfect match.
269    */
270    static void force_all_opaque(const SkBitmap& bitmap) {
271        SkColorType colorType = bitmap.colorType();
272        switch (colorType) {
273        case kN32_SkColorType:
274            force_all_opaque_8888(bitmap);
275            break;
276        case kRGB_565_SkColorType:
277            // nothing to do here; 565 bitmaps are inherently opaque
278            break;
279        default:
280            SkDebugf("unsupported bitmap colorType %d\n", colorType);
281            DEBUGFAIL_SEE_STDERR;
282        }
283    }
284
285    static void force_all_opaque_8888(const SkBitmap& bitmap) {
286        SkAutoLockPixels lock(bitmap);
287        for (int y = 0; y < bitmap.height(); y++) {
288            for (int x = 0; x < bitmap.width(); x++) {
289                *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
290            }
291        }
292    }
293
294    static ErrorCombination write_bitmap(const SkString& path, const SkBitmap& bitmap) {
295        // TODO(epoger): Now that we have removed force_all_opaque()
296        // from this method, we should be able to get rid of the
297        // transformation to 8888 format also.
298        SkBitmap copy;
299        bitmap.copyTo(&copy, kN32_SkColorType);
300        if (!SkImageEncoder::EncodeFile(path.c_str(), copy,
301                                        SkImageEncoder::kPNG_Type,
302                                        100)) {
303            SkDebugf("FAILED to write bitmap: %s\n", path.c_str());
304            return ErrorCombination(kWritingReferenceImage_ErrorType);
305        }
306        return kEmpty_ErrorCombination;
307    }
308
309    /**
310     * Add all render modes encountered thus far to the "modes" array.
311     */
312    void GetRenderModesEncountered(SkTArray<SkString> &modes) {
313        SkTDict<int>::Iter iter(this->fRenderModesEncountered);
314        const char* mode;
315        while ((mode = iter.next(NULL)) != NULL) {
316            SkString modeAsString = SkString(mode);
317            // TODO(epoger): It seems a bit silly that all of these modes were
318            // recorded with a leading "-" which we have to remove here
319            // (except for mode "", which means plain old original mode).
320            // But that's how renderModeDescriptor has been passed into
321            // compare_test_results_to_reference_bitmap() historically,
322            // and changing that now may affect other parts of our code.
323            if (modeAsString.startsWith("-")) {
324                modeAsString.remove(0, 1);
325            }
326            modes.push_back(modeAsString);
327        }
328    }
329
330    /**
331     * Returns true if failures on this test should be ignored.
332     */
333    bool ShouldIgnoreTest(const char *name) const {
334        for (int i = 0; i < fIgnorableTestNames.count(); i++) {
335            if (fIgnorableTestNames[i].equals(name)) {
336                return true;
337            }
338        }
339        return false;
340    }
341
342    /**
343     * Calls RecordTestResults to record that we skipped a test.
344     *
345     * Depending on the backend, this may mean that we skipped a single rendermode, or all
346     * rendermodes; see http://skbug.com/1994 and https://codereview.chromium.org/129203002/
347     */
348    void RecordSkippedTest(const SkString& shortNamePlusConfig,
349                           const char renderModeDescriptor [], Backend backend) {
350        if (kRaster_Backend == backend) {
351            // Skipping a test on kRaster_Backend means that we will skip ALL renderModes
352            // (as opposed to other backends, on which we only run the default renderMode).
353            //
354            // We cannot call RecordTestResults yet, because we won't know the full set of
355            // renderModes until we have run all tests.
356            fTestsSkippedOnAllRenderModes.push_back(shortNamePlusConfig);
357        } else {
358            this->RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
359                                    renderModeDescriptor);
360        }
361    }
362
363    /**
364     * Records the results of this test in fTestsRun and fFailedTests.
365     *
366     * We even record successes, and errors that we regard as
367     * "ignorable"; we can filter them out later.
368     */
369    void RecordTestResults(const ErrorCombination& errorCombination,
370                           const SkString& shortNamePlusConfig,
371                           const char renderModeDescriptor []) {
372        // Things to do regardless of errorCombination.
373        fTestsRun++;
374        int renderModeCount = 0;
375        this->fRenderModesEncountered.find(renderModeDescriptor, &renderModeCount);
376        renderModeCount++;
377        this->fRenderModesEncountered.set(renderModeDescriptor, renderModeCount);
378
379        if (errorCombination.isEmpty()) {
380            return;
381        }
382
383        // Things to do only if there is some error condition.
384        SkString fullName = shortNamePlusConfig;
385        fullName.append(renderModeDescriptor);
386        for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
387            ErrorType type = static_cast<ErrorType>(typeInt);
388            if (errorCombination.includes(type)) {
389                fFailedTests[type].push_back(fullName);
390            }
391        }
392    }
393
394    /**
395     * Return the number of significant (non-ignorable) errors we have
396     * encountered so far.
397     */
398    int NumSignificantErrors() {
399        int significantErrors = 0;
400        for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
401            ErrorType type = static_cast<ErrorType>(typeInt);
402            if (!fIgnorableErrorTypes.includes(type)) {
403                significantErrors += fFailedTests[type].count();
404            }
405        }
406        return significantErrors;
407    }
408
409    /**
410     * Display the summary of results with this ErrorType.
411     *
412     * @param type which ErrorType
413     * @param verbose whether to be all verbose about it
414     */
415    void DisplayResultTypeSummary(ErrorType type, bool verbose) {
416        bool isIgnorableType = fIgnorableErrorTypes.includes(type);
417
418        SkString line;
419        if (isIgnorableType) {
420            line.append("[ ] ");
421        } else {
422            line.append("[*] ");
423        }
424
425        SkTArray<SkString> *failedTestsOfThisType = &fFailedTests[type];
426        int count = failedTestsOfThisType->count();
427        line.appendf("%d %s", count, getErrorTypeName(type));
428        if (!isIgnorableType || verbose) {
429            line.append(":");
430            for (int i = 0; i < count; ++i) {
431                line.append(" ");
432                line.append((*failedTestsOfThisType)[i]);
433            }
434        }
435        SkDebugf("%s\n", line.c_str());
436    }
437
438    /**
439     * List contents of fFailedTests to stdout.
440     *
441     * @param verbose whether to be all verbose about it
442     */
443    void ListErrors(bool verbose) {
444        // First, print a single summary line.
445        SkString summary;
446        summary.appendf("Ran %d tests:", fTestsRun);
447        for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
448            ErrorType type = static_cast<ErrorType>(typeInt);
449            summary.appendf(" %s=%d", getErrorTypeName(type), fFailedTests[type].count());
450        }
451        SkDebugf("%s\n", summary.c_str());
452
453        // Now, for each failure type, list the tests that failed that way.
454        for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
455            this->DisplayResultTypeSummary(static_cast<ErrorType>(typeInt), verbose);
456        }
457        SkDebugf("(results marked with [*] will cause nonzero return value)\n");
458    }
459
460    static ErrorCombination write_document(const SkString& path, SkStreamAsset* asset) {
461        SkFILEWStream stream(path.c_str());
462        if (!stream.writeStream(asset, asset->getLength())) {
463            SkDebugf("FAILED to write document: %s\n", path.c_str());
464            return ErrorCombination(kWritingReferenceImage_ErrorType);
465        }
466        return kEmpty_ErrorCombination;
467    }
468
469    /**
470     * Prepare an SkBitmap to render a GM into.
471     *
472     * After you've rendered the GM into the SkBitmap, you must call
473     * complete_bitmap()!
474     *
475     * @todo thudson 22 April 2011 - could refactor this to take in
476     * a factory to generate the context, always call readPixels()
477     * (logically a noop for rasters, if wasted time), and thus collapse the
478     * GPU special case and also let this be used for SkPicture testing.
479     */
480    static void setup_bitmap(const ConfigData& gRec, SkISize& size,
481                             SkBitmap* bitmap) {
482        bitmap->allocPixels(SkImageInfo::Make(size.width(), size.height(),
483                                              gRec.fColorType, kPremul_SkAlphaType));
484        bitmap->eraseColor(SK_ColorTRANSPARENT);
485    }
486
487    /**
488     * Any finalization steps we need to perform on the SkBitmap after
489     * we have rendered the GM into it.
490     *
491     * It's too bad that we are throwing away alpha channel data
492     * we could otherwise be examining, but this had always been happening
493     * before... it was buried within the compare() method at
494     * https://code.google.com/p/skia/source/browse/trunk/gm/gmmain.cpp?r=7289#305 .
495     *
496     * Apparently we need this, at least for bitmaps that are either:
497     * (a) destined to be written out as PNG files, or
498     * (b) compared against bitmaps read in from PNG files
499     * for the reasons described just above the force_all_opaque() method.
500     *
501     * Neglecting to do this led to the difficult-to-diagnose
502     * http://code.google.com/p/skia/issues/detail?id=1079 ('gm generating
503     * spurious pixel_error messages as of r7258')
504     *
505     * TODO(epoger): Come up with a better solution that allows us to
506     * compare full pixel data, including alpha channel, while still being
507     * robust in the face of transformations to/from PNG files.
508     * Options include:
509     *
510     * 1. Continue to call force_all_opaque(), but ONLY for bitmaps that
511     *    will be written to, or compared against, PNG files.
512     *    PRO: Preserve/compare alpha channel info for the non-PNG cases
513     *         (comparing different renderModes in-memory)
514     *    CON: The bitmaps (and hash digests) for these non-PNG cases would be
515     *         different than those for the PNG-compared cases, and in the
516     *         case of a failed renderMode comparison, how would we write the
517     *         image to disk for examination?
518     *
519     * 2. Always compute image hash digests from PNG format (either
520     *    directly from the the bytes of a PNG file, or capturing the
521     *    bytes we would have written to disk if we were writing the
522     *    bitmap out as a PNG).
523     *    PRO: I think this would allow us to never force opaque, and to
524     *         the extent that alpha channel data can be preserved in a PNG
525     *         file, we could observe it.
526     *    CON: If we read a bitmap from disk, we need to take its hash digest
527     *         from the source PNG (we can't compute it from the bitmap we
528     *         read out of the PNG, because we will have already premultiplied
529     *         the alpha).
530     *    CON: Seems wasteful to convert a bitmap to PNG format just to take
531     *         its hash digest. (Although we're wasting lots of effort already
532     *         calling force_all_opaque().)
533     *
534     * 3. Make the alpha premultiply/unpremultiply routines 100% consistent,
535     *    so we can transform images back and forth without fear of off-by-one
536     *    errors.
537     *    CON: Math is hard.
538     *
539     * 4. Perform a "close enough" comparison of bitmaps (+/- 1 bit in each
540     *    channel), rather than demanding absolute equality.
541     *    CON: Can't do this with hash digests.
542     */
543    static void complete_bitmap(SkBitmap* bitmap) {
544        force_all_opaque(*bitmap);
545    }
546
547    static void installFilter(SkCanvas* canvas);
548
549    static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF, bool isDeferred) {
550        SkAutoCanvasRestore acr(canvas, true);
551
552        if (!isPDF) {
553            canvas->concat(gm->getInitialTransform());
554        }
555        installFilter(canvas);
556        gm->setCanvasIsDeferred(isDeferred);
557        gm->draw(canvas);
558        canvas->setDrawFilter(NULL);
559    }
560
561    static ErrorCombination generate_image(GM* gm, const ConfigData& gRec,
562                                           GrSurface* gpuTarget,
563                                           SkBitmap* bitmap,
564                                           bool deferred) {
565        SkISize size (gm->getISize());
566        setup_bitmap(gRec, size, bitmap);
567        const SkImageInfo info = bitmap->info();
568
569        SkAutoTUnref<SkSurface> surface;
570        SkAutoTUnref<SkCanvas> canvas;
571
572        if (gRec.fBackend == kRaster_Backend) {
573            surface.reset(SkSurface::NewRasterDirect(info,
574                                                     bitmap->getPixels(),
575                                                     bitmap->rowBytes()));
576            if (deferred) {
577                canvas.reset(SkDeferredCanvas::Create(surface));
578            } else {
579                canvas.reset(SkRef(surface->getCanvas()));
580            }
581            invokeGM(gm, canvas, false, deferred);
582            canvas->flush();
583        }
584#if SK_SUPPORT_GPU
585        else {  // GPU
586            surface.reset(SkSurface::NewRenderTargetDirect(gpuTarget->asRenderTarget()));
587            if (deferred) {
588                canvas.reset(SkDeferredCanvas::Create(surface));
589            } else {
590                canvas.reset(SkRef(surface->getCanvas()));
591            }
592            invokeGM(gm, canvas, false, deferred);
593            // the device is as large as the current rendertarget, so
594            // we explicitly only readback the amount we expect (in
595            // size) overwrite our previous allocation
596            bitmap->setInfo(SkImageInfo::MakeN32Premul(size.fWidth, size.fHeight));
597            canvas->readPixels(bitmap, 0, 0);
598        }
599#endif
600        complete_bitmap(bitmap);
601        return kEmpty_ErrorCombination;
602    }
603
604    static void generate_image_from_picture(GM* gm, const ConfigData& gRec,
605                                            SkPicture* pict, SkBitmap* bitmap,
606                                            SkScalar scale = SK_Scalar1,
607                                            bool tile = false) {
608        SkISize size = gm->getISize();
609        setup_bitmap(gRec, size, bitmap);
610
611        if (tile) {
612            // Generate the result image by rendering to tiles and accumulating
613            // the results in 'bitmap'
614
615            // This 16x16 tiling matches the settings applied to 'pict' in
616            // 'generate_new_picture'
617            SkISize tileSize = SkISize::Make(16, 16);
618
619            SkBitmap tileBM;
620            setup_bitmap(gRec, tileSize, &tileBM);
621            SkCanvas tileCanvas(tileBM);
622            installFilter(&tileCanvas);
623
624            SkCanvas bmpCanvas(*bitmap);
625            SkPaint bmpPaint;
626            bmpPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
627
628            for (int yTile = 0; yTile < (size.height()+15)/16; ++yTile) {
629                for (int xTile = 0; xTile < (size.width()+15)/16; ++xTile) {
630                    int saveCount = tileCanvas.save();
631                    SkMatrix mat(tileCanvas.getTotalMatrix());
632                    mat.postTranslate(SkIntToScalar(-xTile*tileSize.width()),
633                                      SkIntToScalar(-yTile*tileSize.height()));
634                    tileCanvas.setMatrix(mat);
635                    pict->draw(&tileCanvas);
636                    tileCanvas.flush();
637                    tileCanvas.restoreToCount(saveCount);
638                    bmpCanvas.drawBitmap(tileBM,
639                                         SkIntToScalar(xTile * tileSize.width()),
640                                         SkIntToScalar(yTile * tileSize.height()),
641                                         &bmpPaint);
642                }
643            }
644        } else {
645            SkCanvas canvas(*bitmap);
646            installFilter(&canvas);
647            canvas.scale(scale, scale);
648            canvas.drawPicture(pict);
649            complete_bitmap(bitmap);
650        }
651    }
652
653    static bool generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
654#ifdef SK_SUPPORT_PDF
655        SkMatrix initialTransform = gm->getInitialTransform();
656        if (FLAGS_useDocumentInsteadOfDevice) {
657            SkISize pageISize = gm->getISize();
658            SkAutoTUnref<SkDocument> pdfDoc(
659                    SkDocument::CreatePDF(&pdf, NULL,
660                                          encode_to_dct_data,
661                                          SkIntToScalar(FLAGS_pdfRasterDpi)));
662
663            if (!pdfDoc.get()) {
664                return false;
665            }
666
667            SkCanvas* canvas = NULL;
668            canvas = pdfDoc->beginPage(SkIntToScalar(pageISize.width()),
669                                       SkIntToScalar(pageISize.height()));
670            canvas->concat(initialTransform);
671
672            invokeGM(gm, canvas, true, false);
673
674            return pdfDoc->close();
675        } else {
676            SkISize pageSize = gm->getISize();
677            SkPDFDevice* dev = NULL;
678            if (initialTransform.isIdentity()) {
679                dev = new SkPDFDevice(pageSize, pageSize, initialTransform);
680            } else {
681                SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()),
682                                                SkIntToScalar(pageSize.height()));
683                initialTransform.mapRect(&content);
684                content.intersect(0, 0, SkIntToScalar(pageSize.width()),
685                                  SkIntToScalar(pageSize.height()));
686                SkISize contentSize =
687                    SkISize::Make(SkScalarRoundToInt(content.width()),
688                                  SkScalarRoundToInt(content.height()));
689                dev = new SkPDFDevice(pageSize, contentSize, initialTransform);
690            }
691            dev->setDCTEncoder(encode_to_dct_data);
692            dev->setRasterDpi(SkIntToScalar(FLAGS_pdfRasterDpi));
693            SkAutoUnref aur(dev);
694            SkCanvas c(dev);
695            invokeGM(gm, &c, true, false);
696            SkPDFDocument doc;
697            doc.appendPage(dev);
698            doc.emitPDF(&pdf);
699        }
700#endif  // SK_SUPPORT_PDF
701        return true; // Do not report failure if pdf is not supported.
702    }
703
704    static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) {
705#ifdef SK_SUPPORT_XPS
706        SkISize size = gm->getISize();
707
708        SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()),
709                                       SkIntToScalar(size.height()));
710        static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254);
711        static const SkScalar upm = 72 * inchesPerMeter;
712        SkVector unitsPerMeter = SkPoint::Make(upm, upm);
713        static const SkScalar ppm = 200 * inchesPerMeter;
714        SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm);
715
716        SkXPSDevice* dev = new SkXPSDevice();
717        SkAutoUnref aur(dev);
718
719        SkCanvas c(dev);
720        dev->beginPortfolio(&xps);
721        dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize);
722        invokeGM(gm, &c, false, false);
723        dev->endSheet();
724        dev->endPortfolio();
725
726#endif
727    }
728
729    /**
730     * Log more detail about the mistmatch between expectedBitmap and
731     * actualBitmap.
732     */
733    void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& actualBitmap,
734                             const char *testName) {
735        const int expectedWidth = expectedBitmap.width();
736        const int expectedHeight = expectedBitmap.height();
737        const int width = actualBitmap.width();
738        const int height = actualBitmap.height();
739        if ((expectedWidth != width) || (expectedHeight != height)) {
740            SkDebugf("---- %s: dimension mismatch -- expected [%d %d], actual [%d %d]\n",
741                     testName, expectedWidth, expectedHeight, width, height);
742            return;
743        }
744
745        if ((kN32_SkColorType != expectedBitmap.colorType()) ||
746            (kN32_SkColorType != actualBitmap.colorType())) {
747            SkDebugf("---- %s: not computing max per-channel pixel mismatch because non-8888\n",
748                     testName);
749            return;
750        }
751
752        SkAutoLockPixels alp0(expectedBitmap);
753        SkAutoLockPixels alp1(actualBitmap);
754        int errR = 0;
755        int errG = 0;
756        int errB = 0;
757        int errA = 0;
758        int differingPixels = 0;
759
760        for (int y = 0; y < height; ++y) {
761            const SkPMColor* expectedPixelPtr = expectedBitmap.getAddr32(0, y);
762            const SkPMColor* actualPixelPtr = actualBitmap.getAddr32(0, y);
763            for (int x = 0; x < width; ++x) {
764                SkPMColor expectedPixel = *expectedPixelPtr++;
765                SkPMColor actualPixel = *actualPixelPtr++;
766                if (expectedPixel != actualPixel) {
767                    differingPixels++;
768                    errR = SkMax32(errR, SkAbs32((int)SkGetPackedR32(expectedPixel) -
769                                                 (int)SkGetPackedR32(actualPixel)));
770                    errG = SkMax32(errG, SkAbs32((int)SkGetPackedG32(expectedPixel) -
771                                                 (int)SkGetPackedG32(actualPixel)));
772                    errB = SkMax32(errB, SkAbs32((int)SkGetPackedB32(expectedPixel) -
773                                                 (int)SkGetPackedB32(actualPixel)));
774                    errA = SkMax32(errA, SkAbs32((int)SkGetPackedA32(expectedPixel) -
775                                                 (int)SkGetPackedA32(actualPixel)));
776                }
777            }
778        }
779        SkDebugf("---- %s: %d (of %d) differing pixels, "
780                 "max per-channel mismatch R=%d G=%d B=%d A=%d\n",
781                 testName, differingPixels, width*height, errR, errG, errB, errA);
782    }
783
784    /**
785     * Compares actual hash digest to expectations, returning the set of errors
786     * (if any) that we saw along the way.
787     *
788     * If fMismatchPath has been set, and there are pixel diffs, then the
789     * actual bitmap will be written out to a file within fMismatchPath.
790     * And similarly for fMissingExpectationsPath...
791     *
792     * @param expectations what expectations to compare actualBitmap against
793     * @param actualBitmapAndDigest the SkBitmap we actually generated, and its GmResultDigest
794     * @param shortName name of test, e.g. "selftest1"
795     * @param configName name of config, e.g. "8888"
796     * @param renderModeDescriptor e.g., "-rtree", "-deferred"
797     * @param addToJsonSummary whether to add these results (both actual and
798     *        expected) to the JSON summary. Regardless of this setting, if
799     *        we find an image mismatch in this test, we will write these
800     *        results to the JSON summary.  (This is so that we will always
801     *        report errors across rendering modes, such as pipe vs tiled.
802     *        See https://codereview.chromium.org/13650002/ )
803     */
804    ErrorCombination compare_to_expectations(Expectations expectations,
805                                             const BitmapAndDigest& actualBitmapAndDigest,
806                                             const char *shortName, const char *configName,
807                                             const char *renderModeDescriptor,
808                                             bool addToJsonSummary) {
809        ErrorCombination errors;
810        SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
811        SkString completeNameString(shortNamePlusConfig);
812        completeNameString.append(renderModeDescriptor);
813        completeNameString.append(".");
814        completeNameString.append(kPNG_FileExtension);
815        const char* completeName = completeNameString.c_str();
816
817        if (expectations.empty()) {
818            errors.add(kMissingExpectations_ErrorType);
819
820            // Write out the "actuals" for any tests without expectations, if we have
821            // been directed to do so.
822            if (fMissingExpectationsPath) {
823                SkString path = make_bitmap_filename(fMissingExpectationsPath, shortName,
824                                                     configName, renderModeDescriptor,
825                                                     actualBitmapAndDigest.fDigest);
826                write_bitmap(path, actualBitmapAndDigest.fBitmap);
827            }
828
829        } else if (!expectations.match(actualBitmapAndDigest.fDigest)) {
830            addToJsonSummary = true;
831            // The error mode we record depends on whether this was running
832            // in a non-standard renderMode.
833            if ('\0' == *renderModeDescriptor) {
834                errors.add(kExpectationsMismatch_ErrorType);
835            } else {
836                errors.add(kRenderModeMismatch_ErrorType);
837            }
838
839            // Write out the "actuals" for any mismatches, if we have
840            // been directed to do so.
841            if (fMismatchPath) {
842                SkString path = make_bitmap_filename(fMismatchPath, shortName, configName,
843                                                     renderModeDescriptor,
844                                                     actualBitmapAndDigest.fDigest);
845                write_bitmap(path, actualBitmapAndDigest.fBitmap);
846            }
847
848            // If we have access to a single expected bitmap, log more
849            // detail about the mismatch.
850            const SkBitmap *expectedBitmapPtr = expectations.asBitmap();
851            if (NULL != expectedBitmapPtr) {
852                report_bitmap_diffs(*expectedBitmapPtr, actualBitmapAndDigest.fBitmap,
853                                    completeName);
854            }
855        }
856
857        if (addToJsonSummary) {
858            add_actual_results_to_json_summary(completeName, actualBitmapAndDigest.fDigest, errors,
859                                               expectations.ignoreFailure());
860            add_expected_results_to_json_summary(completeName, expectations);
861        }
862
863        return errors;
864    }
865
866    /**
867     * Add this result to the appropriate JSON collection of actual results (but just ONE),
868     * depending on errors encountered.
869     */
870    void add_actual_results_to_json_summary(const char testName[],
871                                            const GmResultDigest &actualResultDigest,
872                                            ErrorCombination errors,
873                                            bool ignoreFailure) {
874        Json::Value jsonActualResults = actualResultDigest.asJsonTypeValuePair();
875        Json::Value *resultCollection = NULL;
876
877        if (errors.isEmpty()) {
878            resultCollection = &this->fJsonActualResults_Succeeded;
879        } else if (errors.includes(kRenderModeMismatch_ErrorType)) {
880            resultCollection = &this->fJsonActualResults_Failed;
881        } else if (errors.includes(kExpectationsMismatch_ErrorType)) {
882            if (ignoreFailure) {
883                resultCollection = &this->fJsonActualResults_FailureIgnored;
884            } else {
885                resultCollection = &this->fJsonActualResults_Failed;
886            }
887        } else if (errors.includes(kMissingExpectations_ErrorType)) {
888            // TODO: What about the case where there IS an expected
889            // image hash digest, but that gm test doesn't actually
890            // run?  For now, those cases will always be ignored,
891            // because gm only looks at expectations that correspond
892            // to gm tests that were actually run.
893            //
894            // Once we have the ability to express expectations as a
895            // JSON file, we should fix this (and add a test case for
896            // which an expectation is given but the test is never
897            // run).
898            resultCollection = &this->fJsonActualResults_NoComparison;
899        }
900
901        // If none of the above cases match, we don't add it to ANY tally of actual results.
902        if (resultCollection) {
903            (*resultCollection)[testName] = jsonActualResults;
904        }
905    }
906
907    /**
908     * Add this test to the JSON collection of expected results.
909     */
910    void add_expected_results_to_json_summary(const char testName[],
911                                              Expectations expectations) {
912        this->fJsonExpectedResults[testName] = expectations.asJsonValue();
913    }
914
915    /**
916     * Compare actualBitmap to expectations stored in this->fExpectationsSource.
917     *
918     * @param gm which test generated the actualBitmap
919     * @param gRec
920     * @param configName The config name to look for in the expectation file.
921     * @param actualBitmapAndDigest ptr to bitmap generated by this run, or NULL
922     *        if we don't have a usable bitmap representation
923     */
924    ErrorCombination compare_test_results_to_stored_expectations(
925        GM* gm, const ConfigData& gRec, const char* configName,
926        const BitmapAndDigest* actualBitmapAndDigest) {
927        ErrorCombination errors;
928
929        if (NULL == actualBitmapAndDigest) {
930            // Note that we intentionally skipped validating the results for
931            // this test, because we don't know how to generate an SkBitmap
932            // version of the output.
933            errors.add(ErrorCombination(kIntentionallySkipped_ErrorType));
934        } else if (!(gRec.fFlags & kWrite_ConfigFlag)) {
935            // We don't record the results for this test or compare them
936            // against any expectations, because the output image isn't
937            // meaningful.
938            // See https://code.google.com/p/skia/issues/detail?id=1410 ('some
939            // GM result images not available for download from Google Storage')
940            errors.add(ErrorCombination(kIntentionallySkipped_ErrorType));
941        } else {
942            ExpectationsSource *expectationsSource = this->fExpectationsSource.get();
943            SkString nameWithExtension = make_shortname_plus_config(gm->getName(), configName);
944            nameWithExtension.append(".");
945            nameWithExtension.append(kPNG_FileExtension);
946
947            if (expectationsSource && (gRec.fFlags & kRead_ConfigFlag)) {
948                /*
949                 * Get the expected results for this test, as one or more allowed
950                 * hash digests. The current implementation of expectationsSource
951                 * get this by computing the hash digest of a single PNG file on disk.
952                 *
953                 * TODO(epoger): This relies on the fact that
954                 * force_all_opaque() was called on the bitmap before it
955                 * was written to disk as a PNG in the first place. If
956                 * not, the hash digest returned here may not match the
957                 * hash digest of actualBitmap, which *has* been run through
958                 * force_all_opaque().
959                 * See comments above complete_bitmap() for more detail.
960                 */
961                Expectations expectations = expectationsSource->get(nameWithExtension.c_str());
962                if (this->ShouldIgnoreTest(gm->getName())) {
963                    expectations.setIgnoreFailure(true);
964                }
965                errors.add(compare_to_expectations(expectations, *actualBitmapAndDigest,
966                                                   gm->getName(), configName, "", true));
967            } else {
968                // If we are running without expectations, we still want to
969                // record the actual results.
970                add_actual_results_to_json_summary(nameWithExtension.c_str(),
971                                                   actualBitmapAndDigest->fDigest,
972                                                   ErrorCombination(kMissingExpectations_ErrorType),
973                                                   false);
974                errors.add(ErrorCombination(kMissingExpectations_ErrorType));
975            }
976        }
977        return errors;
978    }
979
980    /**
981     * Compare actualBitmap to referenceBitmap.
982     *
983     * @param shortName test name, e.g. "selftest1"
984     * @param configName configuration name, e.g. "8888"
985     * @param renderModeDescriptor
986     * @param actualBitmap actual bitmap generated by this run
987     * @param referenceBitmap bitmap we expected to be generated
988     */
989    ErrorCombination compare_test_results_to_reference_bitmap(
990        const char *shortName, const char *configName, const char *renderModeDescriptor,
991        SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) {
992
993        SkASSERT(referenceBitmap);
994        Expectations expectations(*referenceBitmap);
995        BitmapAndDigest actualBitmapAndDigest(actualBitmap);
996
997        // TODO: Eliminate RecordTestResults from here.
998        // Results recording code for the test_drawing path has been refactored so that
999        // RecordTestResults is only called once, at the topmost level. However, the
1000        // other paths have not yet been refactored, and RecordTestResults has been added
1001        // here to maintain proper behavior for calls not coming from the test_drawing path.
1002        ErrorCombination errors;
1003        errors.add(compare_to_expectations(expectations, actualBitmapAndDigest, shortName,
1004                                           configName, renderModeDescriptor, false));
1005        SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName);
1006        RecordTestResults(errors, shortNamePlusConfig, renderModeDescriptor);
1007
1008        return errors;
1009    }
1010
1011    static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t recordFlags,
1012                                           SkScalar scale = SK_Scalar1) {
1013        int width = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().width()), scale));
1014        int height = SkScalarCeilToInt(SkScalarMul(SkIntToScalar(gm->getISize().height()), scale));
1015
1016        SkAutoTDelete<SkBBHFactory> factory;
1017        if (kTileGrid_BbhType == bbhType) {
1018            SkTileGridFactory::TileGridInfo info;
1019            info.fMargin.setEmpty();
1020            info.fOffset.setZero();
1021            info.fTileInterval.set(16, 16);
1022            factory.reset(SkNEW_ARGS(SkTileGridFactory, (info)));
1023        } else if (kQuadTree_BbhType == bbhType) {
1024            factory.reset(SkNEW(SkQuadTreeFactory));
1025        } else if (kRTree_BbhType == bbhType) {
1026            factory.reset(SkNEW(SkRTreeFactory));
1027        }
1028        SkPictureRecorder recorder;
1029        SkCanvas* cv = recorder.beginRecording(width, height, factory.get(), recordFlags);
1030        cv->scale(scale, scale);
1031        invokeGM(gm, cv, false, false);
1032        return recorder.endRecording();
1033    }
1034
1035    static SkPicture* stream_to_new_picture(const SkPicture& src) {
1036        SkDynamicMemoryWStream storage;
1037        src.serialize(&storage, NULL);
1038        SkAutoTUnref<SkStreamAsset> pictReadback(storage.detachAsStream());
1039        SkPicture* retval = SkPicture::CreateFromStream(pictReadback,
1040                                                        &SkImageDecoder::DecodeMemory);
1041        return retval;
1042    }
1043
1044    // Test: draw into a bitmap or pdf.
1045    // Depending on flags, possibly compare to an expected image.
1046    // If writePath is not NULL, also write images (or documents) to the specified path.
1047    ErrorCombination test_drawing(GM* gm, const ConfigData& gRec,
1048                                  const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
1049                                  const char writePath [],
1050                                  GrSurface* gpuTarget,
1051                                  SkBitmap* bitmap) {
1052        ErrorCombination errors;
1053        SkDynamicMemoryWStream document;
1054        SkString path;
1055
1056        if (gRec.fBackend == kRaster_Backend ||
1057            gRec.fBackend == kGPU_Backend) {
1058            // Early exit if we can't generate the image.
1059            errors.add(generate_image(gm, gRec, gpuTarget, bitmap, false));
1060            if (!errors.isEmpty()) {
1061                // TODO: Add a test to exercise what the stdout and
1062                // JSON look like if we get an "early error" while
1063                // trying to generate the image.
1064                return errors;
1065            }
1066            BitmapAndDigest bitmapAndDigest(*bitmap);
1067            errors.add(compare_test_results_to_stored_expectations(
1068                           gm, gRec, gRec.fName, &bitmapAndDigest));
1069
1070            if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
1071                path = make_bitmap_filename(writePath, gm->getName(), gRec.fName,
1072                                            "", bitmapAndDigest.fDigest);
1073                errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
1074            }
1075        } else if (gRec.fBackend == kPDF_Backend) {
1076            if (!generate_pdf(gm, document)) {
1077                errors.add(kGeneratePdfFailed_ErrorType);
1078            } else {
1079                SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
1080                if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
1081                    path = make_filename(writePath, gm->getName(), gRec.fName, "", "pdf");
1082                    errors.add(write_document(path, documentStream));
1083                }
1084
1085                if (!(gm->getFlags() & GM::kSkipPDFRasterization_Flag)) {
1086                    for (int i = 0; i < pdfRasterizers.count(); i++) {
1087                        SkBitmap pdfBitmap;
1088                        documentStream->rewind();
1089                        bool success = (*pdfRasterizers[i]->fRasterizerFunction)(
1090                                documentStream.get(), &pdfBitmap);
1091                        if (!success) {
1092                            SkDebugf("FAILED to render PDF for %s using renderer %s\n",
1093                                     gm->getName(),
1094                                     pdfRasterizers[i]->fName);
1095                            continue;
1096                        }
1097
1098                        SkString configName(gRec.fName);
1099                        configName.append("-");
1100                        configName.append(pdfRasterizers[i]->fName);
1101
1102                        BitmapAndDigest bitmapAndDigest(pdfBitmap);
1103                        errors.add(compare_test_results_to_stored_expectations(
1104                                   gm, gRec, configName.c_str(), &bitmapAndDigest));
1105
1106                        if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
1107                            path = make_bitmap_filename(writePath, gm->getName(),
1108                                                        configName.c_str(),
1109                                                        "", bitmapAndDigest.fDigest);
1110                            errors.add(write_bitmap(path, bitmapAndDigest.fBitmap));
1111                        }
1112                    }
1113                } else {
1114                    errors.add(kIntentionallySkipped_ErrorType);
1115                }
1116            }
1117        } else if (gRec.fBackend == kXPS_Backend) {
1118            generate_xps(gm, document);
1119            SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream());
1120
1121            errors.add(compare_test_results_to_stored_expectations(
1122                           gm, gRec, gRec.fName, NULL));
1123
1124            if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
1125                path = make_filename(writePath, gm->getName(), gRec.fName, "", "xps");
1126                errors.add(write_document(path, documentStream));
1127            }
1128        } else {
1129            SkASSERT(false);
1130        }
1131        return errors;
1132    }
1133
1134    ErrorCombination test_deferred_drawing(GM* gm,
1135                                           const ConfigData& gRec,
1136                                           const SkBitmap& referenceBitmap,
1137                                           GrSurface* gpuTarget) {
1138        if (gRec.fBackend == kRaster_Backend ||
1139            gRec.fBackend == kGPU_Backend) {
1140            const char renderModeDescriptor[] = "-deferred";
1141            SkBitmap bitmap;
1142            // Early exit if we can't generate the image, but this is
1143            // expected in some cases, so don't report a test failure.
1144            ErrorCombination errors = generate_image(gm, gRec, gpuTarget, &bitmap, true);
1145            // TODO(epoger): This logic is the opposite of what is
1146            // described above... if we succeeded in generating the
1147            // -deferred image, we exit early!  We should fix this
1148            // ASAP, because it is hiding -deferred errors... but for
1149            // now, I'm leaving the logic as it is so that the
1150            // refactoring change
1151            // https://codereview.chromium.org/12992003/ is unblocked.
1152            //
1153            // Filed as https://code.google.com/p/skia/issues/detail?id=1180
1154            // ('image-surface gm test is failing in "deferred" mode,
1155            // and gm is not reporting the failure')
1156            if (errors.isEmpty()) {
1157                // TODO(epoger): Report this as a new ErrorType,
1158                // something like kImageGeneration_ErrorType?
1159                return kEmpty_ErrorCombination;
1160            }
1161            return compare_test_results_to_reference_bitmap(
1162                gm->getName(), gRec.fName, renderModeDescriptor, bitmap, &referenceBitmap);
1163        }
1164        return kEmpty_ErrorCombination;
1165    }
1166
1167    ErrorCombination test_pipe_playback(GM* gm, const ConfigData& gRec,
1168                                        const SkBitmap& referenceBitmap, bool simulateFailure) {
1169        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
1170                                                                        gRec.fName);
1171        ErrorCombination errors;
1172        for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
1173            SkString renderModeDescriptor("-pipe");
1174            renderModeDescriptor.append(gPipeWritingFlagCombos[i].name);
1175
1176            if (gm->getFlags() & GM::kSkipPipe_Flag
1177                || (gPipeWritingFlagCombos[i].flags == SkGPipeWriter::kCrossProcess_Flag
1178                    && gm->getFlags() & GM::kSkipPipeCrossProcess_Flag)) {
1179                RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1180                                  renderModeDescriptor.c_str());
1181                errors.add(kIntentionallySkipped_ErrorType);
1182            } else {
1183                SkBitmap bitmap;
1184                SkISize size = gm->getISize();
1185                setup_bitmap(gRec, size, &bitmap);
1186                SkCanvas canvas(bitmap);
1187                installFilter(&canvas);
1188                // Pass a decoding function so the factory GM (which has an SkBitmap
1189                // with encoded data) will not fail playback.
1190                PipeController pipeController(&canvas, &SkImageDecoder::DecodeMemory);
1191                SkGPipeWriter writer;
1192                SkCanvas* pipeCanvas = writer.startRecording(&pipeController,
1193                                                             gPipeWritingFlagCombos[i].flags,
1194                                                             size.width(), size.height());
1195                if (!simulateFailure) {
1196                    invokeGM(gm, pipeCanvas, false, false);
1197                }
1198                complete_bitmap(&bitmap);
1199                writer.endRecording();
1200                errors.add(compare_test_results_to_reference_bitmap(
1201                    gm->getName(), gRec.fName, renderModeDescriptor.c_str(), bitmap,
1202                    &referenceBitmap));
1203                if (!errors.isEmpty()) {
1204                    break;
1205                }
1206            }
1207        }
1208        return errors;
1209    }
1210
1211    ErrorCombination test_tiled_pipe_playback(GM* gm, const ConfigData& gRec,
1212                                              const SkBitmap& referenceBitmap) {
1213        const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(),
1214                                                                        gRec.fName);
1215        ErrorCombination errors;
1216        for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) {
1217            SkString renderModeDescriptor("-tiled pipe");
1218            renderModeDescriptor.append(gPipeWritingFlagCombos[i].name);
1219
1220            if ((gm->getFlags() & GM::kSkipPipe_Flag) ||
1221                (gm->getFlags() & GM::kSkipTiled_Flag)) {
1222                RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1223                                  renderModeDescriptor.c_str());
1224                errors.add(kIntentionallySkipped_ErrorType);
1225            } else {
1226                SkBitmap bitmap;
1227                SkISize size = gm->getISize();
1228                setup_bitmap(gRec, size, &bitmap);
1229                SkCanvas canvas(bitmap);
1230                installFilter(&canvas);
1231                TiledPipeController pipeController(bitmap, &SkImageDecoder::DecodeMemory);
1232                SkGPipeWriter writer;
1233                SkCanvas* pipeCanvas = writer.startRecording(&pipeController,
1234                                                             gPipeWritingFlagCombos[i].flags,
1235                                                             size.width(), size.height());
1236                invokeGM(gm, pipeCanvas, false, false);
1237                complete_bitmap(&bitmap);
1238                writer.endRecording();
1239                errors.add(compare_test_results_to_reference_bitmap(gm->getName(), gRec.fName,
1240                                                                    renderModeDescriptor.c_str(),
1241                                                                    bitmap, &referenceBitmap));
1242                if (!errors.isEmpty()) {
1243                    break;
1244                }
1245            }
1246        }
1247        return errors;
1248    }
1249
1250    //
1251    // member variables.
1252    // They are public for now, to allow easier setting by tool_main().
1253    //
1254
1255    bool fUseFileHierarchy, fWriteChecksumBasedFilenames;
1256    ErrorCombination fIgnorableErrorTypes;
1257    SkTArray<SkString> fIgnorableTestNames;
1258
1259    const char* fMismatchPath;
1260    const char* fMissingExpectationsPath;
1261
1262    // collection of tests that have failed with each ErrorType
1263    SkTArray<SkString> fFailedTests[kLast_ErrorType+1];
1264    SkTArray<SkString> fTestsSkippedOnAllRenderModes;
1265    int fTestsRun;
1266    SkTDict<int> fRenderModesEncountered;
1267
1268    // Where to read expectations (expected image hash digests, etc.) from.
1269    // If unset, we don't do comparisons.
1270    SkAutoTUnref<ExpectationsSource> fExpectationsSource;
1271
1272    // JSON summaries that we generate as we go (just for output).
1273    Json::Value fJsonExpectedResults;
1274    Json::Value fJsonActualResults_Failed;
1275    Json::Value fJsonActualResults_FailureIgnored;
1276    Json::Value fJsonActualResults_NoComparison;
1277    Json::Value fJsonActualResults_Succeeded;
1278}; // end of GMMain class definition
1279
1280#if SK_SUPPORT_GPU
1281static const GLContextType kDontCare_GLContextType = GrContextFactory::kNative_GLContextType;
1282#else
1283static const GLContextType kDontCare_GLContextType = 0;
1284#endif
1285
1286static const ConfigData gRec[] = {
1287    { kN32_SkColorType,     kRaster_Backend, kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "8888",         true },
1288    { kRGB_565_SkColorType, kRaster_Backend, kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "565",          true },
1289#if SK_SUPPORT_GPU
1290    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNative_GLContextType,  0, kRW_ConfigFlag,    "gpu",          true },
1291    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNative_GLContextType, 16, kRW_ConfigFlag,    "msaa16",       false},
1292    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNative_GLContextType,  4, kRW_ConfigFlag,    "msaa4",        false},
1293    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNVPR_GLContextType,    4, kRW_ConfigFlag,    "nvprmsaa4",   true },
1294    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNVPR_GLContextType,   16, kRW_ConfigFlag,    "nvprmsaa16",  false},
1295    /* The gpudebug context does not generate meaningful images, so don't record
1296     * the images it generates!  We only run it to look for asserts. */
1297    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kDebug_GLContextType,   0, kNone_ConfigFlag,  "gpudebug",     kDebugOnly},
1298    /* The gpunull context does the least amount of work possible and doesn't
1299       generate meaninful images, so don't record them!. It can be run to
1300       isolate the CPU-side processing expense from the GPU-side.
1301      */
1302    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kNull_GLContextType,    0, kNone_ConfigFlag,  "gpunull",      kDebugOnly},
1303#if SK_ANGLE
1304    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kANGLE_GLContextType,   0, kRW_ConfigFlag,    "angle",        true },
1305    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kANGLE_GLContextType,  16, kRW_ConfigFlag,    "anglemsaa16",  true },
1306#endif // SK_ANGLE
1307#ifdef SK_MESA
1308    { kN32_SkColorType, kGPU_Backend,    GrContextFactory::kMESA_GLContextType,    0, kRW_ConfigFlag,    "mesa",         true },
1309#endif // SK_MESA
1310#endif // SK_SUPPORT_GPU
1311#ifdef SK_SUPPORT_XPS
1312    /* At present we have no way of comparing XPS files (either natively or by converting to PNG). */
1313    { kN32_SkColorType, kXPS_Backend,    kDontCare_GLContextType,                  0, kWrite_ConfigFlag, "xps",          true },
1314#endif // SK_SUPPORT_XPS
1315#ifdef SK_SUPPORT_PDF
1316    { kN32_SkColorType, kPDF_Backend,    kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "pdf",          true },
1317#endif // SK_SUPPORT_PDF
1318};
1319
1320static bool SkNoRasterizePDF(SkStream*, SkBitmap*) { return false; }
1321
1322static const PDFRasterizerData kPDFRasterizers[] = {
1323#ifdef SK_BUILD_FOR_MAC
1324    { &SkPDFDocumentToBitmap, "mac",     true },
1325#endif
1326#ifdef SK_BUILD_POPPLER
1327    { &SkPopplerRasterizePDF, "poppler", true },
1328#endif
1329#ifdef SK_BUILD_NATIVE_PDF_RENDERER
1330    { &SkNativeRasterizePDF,  "native",  true },
1331#endif  // SK_BUILD_NATIVE_PDF_RENDERER
1332    // The following exists so that this array is never zero length.
1333    { &SkNoRasterizePDF,      "none",    false},
1334};
1335
1336static const char kDefaultsConfigStr[] = "defaults";
1337static const char kExcludeConfigChar = '~';
1338
1339static SkString configUsage() {
1340    SkString result;
1341    result.appendf("Space delimited list of which configs to run. Possible options: [");
1342    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
1343        SkASSERT(gRec[i].fName != kDefaultsConfigStr);
1344        if (i > 0) {
1345            result.append("|");
1346        }
1347        result.appendf("%s", gRec[i].fName);
1348    }
1349    result.append("]\n");
1350    result.appendf("The default value is: \"");
1351    SkString firstDefault;
1352    SkString allButFirstDefaults;
1353    SkString nonDefault;
1354    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
1355        if (gRec[i].fRunByDefault) {
1356            if (i > 0) {
1357                result.append(" ");
1358            }
1359            result.append(gRec[i].fName);
1360            if (firstDefault.isEmpty()) {
1361                firstDefault = gRec[i].fName;
1362            } else {
1363                if (!allButFirstDefaults.isEmpty()) {
1364                    allButFirstDefaults.append(" ");
1365                }
1366                allButFirstDefaults.append(gRec[i].fName);
1367            }
1368        } else {
1369            nonDefault = gRec[i].fName;
1370        }
1371    }
1372    result.append("\"\n");
1373    result.appendf("\"%s\" evaluates to the default set of configs.\n", kDefaultsConfigStr);
1374    result.appendf("Prepending \"%c\" on a config name excludes it from the set of configs to run.\n"
1375                   "Exclusions always override inclusions regardless of order.\n",
1376                   kExcludeConfigChar);
1377    result.appendf("E.g. \"--config %s %c%s %s\" will run these configs:\n\t%s %s",
1378                   kDefaultsConfigStr,
1379                   kExcludeConfigChar,
1380                   firstDefault.c_str(),
1381                   nonDefault.c_str(),
1382                   allButFirstDefaults.c_str(),
1383                   nonDefault.c_str());
1384    return result;
1385}
1386
1387static SkString pdfRasterizerUsage() {
1388    SkString result;
1389    result.appendf("Space delimited list of which PDF rasterizers to run. Possible options: [");
1390    // For this (and further) loops through kPDFRasterizers, there is a typecast to int to avoid
1391    // the compiler giving an "comparison of unsigned expression < 0 is always false" warning
1392    // and turning it into a build-breaking error.
1393    for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
1394        if (i > 0) {
1395            result.append(" ");
1396        }
1397        result.append(kPDFRasterizers[i].fName);
1398    }
1399    result.append("]\n");
1400    result.append("The default value is: \"");
1401    for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
1402        if (kPDFRasterizers[i].fRunByDefault) {
1403            if (i > 0) {
1404                result.append(" ");
1405            }
1406            result.append(kPDFRasterizers[i].fName);
1407        }
1408    }
1409    result.append("\"");
1410    return result;
1411}
1412
1413// Macro magic to convert a numeric preprocessor token into a string.
1414// Adapted from http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string
1415// This should probably be moved into one of our common headers...
1416#define TOSTRING_INTERNAL(x) #x
1417#define TOSTRING(x) TOSTRING_INTERNAL(x)
1418
1419// Alphabetized ignoring "no" prefix ("readPath", "noreplay", "resourcePath").
1420DEFINE_string(config, "", configUsage().c_str());
1421DEFINE_string(pdfRasterizers, "default", pdfRasterizerUsage().c_str());
1422DEFINE_bool(deferred, false, "Exercise the deferred rendering test pass.");
1423DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done.");
1424DEFINE_string(excludeConfig, "", "Space delimited list of configs to skip.");
1425DEFINE_bool(forceBWtext, false, "Disable text anti-aliasing.");
1426#if SK_SUPPORT_GPU
1427DEFINE_string(gpuCacheSize, "", "<bytes> <count>: Limit the gpu cache to byte size or "
1428              "object count. " TOSTRING(DEFAULT_CACHE_VALUE) " for either value means "
1429              "use the default. 0 for either disables the cache.");
1430#endif
1431DEFINE_bool(hierarchy, false, "Whether to use multilevel directory structure "
1432            "when reading/writing files.");
1433DEFINE_string(ignoreErrorTypes, kDefaultIgnorableErrorTypes.asString(" ").c_str(),
1434              "Space-separated list of ErrorTypes that should be ignored. If any *other* error "
1435              "types are encountered, the tool will exit with a nonzero return value.");
1436DEFINE_string(ignoreFailuresFile, "", "Path to file containing a list of tests for which we "
1437              "should ignore failures.\n"
1438              "The file should list one test per line, except for comment lines starting with #");
1439DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects.");
1440DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n"
1441              "Multiple matches may be separated by spaces.\n"
1442              "~ causes a matching test to always be skipped\n"
1443              "^ requires the start of the test to match\n"
1444              "$ requires the end of the test to match\n"
1445              "^ and $ requires an exact match\n"
1446              "If a test does not match any list entry,\n"
1447              "it is skipped unless some list entry starts with ~");
1448DEFINE_string(missingExpectationsPath, "", "Write images for tests without expectations "
1449              "into this directory.");
1450DEFINE_string(mismatchPath, "", "Write images for tests that failed due to "
1451              "pixel mismatches into this directory.");
1452DEFINE_string(modulo, "", "[--modulo <remainder> <divisor>]: only run tests for which "
1453              "testIndex %% divisor == remainder.");
1454DEFINE_bool(pipe, false, "Exercise the SkGPipe replay test pass.");
1455DEFINE_bool(quadtree, false, "Exercise the QuadTree variant of SkPicture test pass.");
1456DEFINE_string2(readPath, r, "", "Read reference images from this dir, and report "
1457               "any differences between those and the newly generated ones.");
1458DEFINE_bool(replay, false, "Exercise the SkPicture replay test pass.");
1459#if SK_SUPPORT_GPU
1460DEFINE_bool(resetGpuContext, false, "Reset the GrContext prior to running each GM.");
1461#endif
1462DEFINE_bool(rtree, false, "Exercise the R-Tree variant of SkPicture test pass.");
1463DEFINE_bool(serialize, false, "Exercise the SkPicture serialization & deserialization test pass.");
1464DEFINE_bool(simulatePipePlaybackFailure, false, "Simulate a rendering failure in pipe mode only.");
1465DEFINE_bool(tiledPipe, false, "Exercise tiled SkGPipe replay.");
1466DEFINE_bool(tileGrid, false, "Exercise the tile grid variant of SkPicture.");
1467DEFINE_string(tileGridReplayScales, "", "Space separated list of floating-point scale "
1468              "factors to be used for tileGrid playback testing. Default value: 1.0");
1469DEFINE_bool2(verbose, v, false, "Give more detail (e.g. list all GMs run, more info about "
1470             "each test).");
1471DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-"
1472            "based filenames, as rebaseline.py will use when downloading them from Google Storage");
1473DEFINE_string(writeJsonSummaryPath, "", "Write a JSON-formatted result summary to this file.");
1474DEFINE_string2(writePath, w, "",  "Write rendered images into this directory.");
1475DEFINE_string2(writePicturePath, p, "", "Write .skp files into this directory.");
1476DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, "
1477             "which can be in range 0-100). N = -1 will disable JPEG compression. "
1478             "Default is N = 100, maximum quality.");
1479// TODO(edisonn): pass a matrix instead of forcePerspectiveMatrix
1480// Either the 9 numbers defining the matrix
1481// or probably more readable would be to replace it with a set of a few predicates
1482// Like --prerotate 100 200 10 --posttranslate 10, 10
1483// Probably define spacial names like centerx, centery, top, bottom, left, right
1484// then we can write something reabable like --rotate centerx centery 90
1485DEFINE_bool(forcePerspectiveMatrix, false, "Force a perspective matrix.");
1486DEFINE_bool(useDocumentInsteadOfDevice, false, "Use SkDocument::CreateFoo instead of SkFooDevice.");
1487DEFINE_int32(pdfRasterDpi, 72, "Scale at which at which the non suported "
1488             "features in PDF are rasterized. Must be be in range 0-10000. "
1489             "Default is 72. N = 0 will disable rasterizing features like "
1490             "text shadows or perspective bitmaps.");
1491static SkData* encode_to_dct_data(size_t*, const SkBitmap& bitmap) {
1492    // Filter output of warnings that JPEG is not available for the image.
1493    if (bitmap.width() >= 65500 || bitmap.height() >= 65500) return NULL;
1494    if (FLAGS_pdfJpegQuality == -1) return NULL;
1495
1496    SkBitmap bm = bitmap;
1497#if defined(SK_BUILD_FOR_MAC)
1498    // Workaround bug #1043 where bitmaps with referenced pixels cause
1499    // CGImageDestinationFinalize to crash
1500    SkBitmap copy;
1501    bitmap.deepCopyTo(&copy);
1502    bm = copy;
1503#endif
1504
1505    SkPixelRef* pr = bm.pixelRef();
1506    if (pr != NULL) {
1507        SkData* data = pr->refEncodedData();
1508        if (data != NULL) {
1509            return data;
1510        }
1511    }
1512
1513    return SkImageEncoder::EncodeData(bm,
1514                                      SkImageEncoder::kJPEG_Type,
1515                                      FLAGS_pdfJpegQuality);
1516}
1517
1518static int findConfig(const char config[]) {
1519    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
1520        if (!strcmp(config, gRec[i].fName)) {
1521            return (int) i;
1522        }
1523    }
1524    return -1;
1525}
1526
1527static const PDFRasterizerData* findPDFRasterizer(const char rasterizer[]) {
1528    for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); i++) {
1529        if (!strcmp(rasterizer, kPDFRasterizers[i].fName)) {
1530            return &kPDFRasterizers[i];
1531        }
1532    }
1533    return NULL;
1534}
1535
1536template <typename T> void appendUnique(SkTDArray<T>* array, const T& value) {
1537    int index = array->find(value);
1538    if (index < 0) {
1539        *array->append() = value;
1540    }
1541}
1542
1543/**
1544 * Run this test in a number of different drawing modes (pipe,
1545 * deferred, tiled, etc.), confirming that the resulting bitmaps all
1546 * *exactly* match comparisonBitmap.
1547 *
1548 * Returns all errors encountered while doing so.
1549 */
1550ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig,
1551                                    const SkBitmap &comparisonBitmap,
1552                                    const SkTDArray<SkScalar> &tileGridReplayScales);
1553ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig,
1554                                    const SkBitmap &comparisonBitmap,
1555                                    const SkTDArray<SkScalar> &tileGridReplayScales) {
1556    ErrorCombination errorsForAllModes;
1557    uint32_t gmFlags = gm->getFlags();
1558    const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
1559                                                                           compareConfig.fName);
1560
1561    SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0);
1562    SkAutoUnref aur(pict);
1563    if (FLAGS_replay) {
1564        const char renderModeDescriptor[] = "-replay";
1565        if (gmFlags & GM::kSkipPicture_Flag) {
1566            gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1567                                     renderModeDescriptor);
1568            errorsForAllModes.add(kIntentionallySkipped_ErrorType);
1569        } else {
1570            SkBitmap bitmap;
1571            gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
1572            errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
1573                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
1574                &comparisonBitmap));
1575        }
1576    }
1577
1578    if (FLAGS_serialize) {
1579        const char renderModeDescriptor[] = "-serialize";
1580        if (gmFlags & GM::kSkipPicture_Flag) {
1581            gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1582                                     renderModeDescriptor);
1583            errorsForAllModes.add(kIntentionallySkipped_ErrorType);
1584        } else {
1585            SkPicture* repict = gmmain.stream_to_new_picture(*pict);
1586            SkAutoUnref aurr(repict);
1587            SkBitmap bitmap;
1588            gmmain.generate_image_from_picture(gm, compareConfig, repict, &bitmap);
1589            errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
1590                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
1591                &comparisonBitmap));
1592        }
1593    }
1594
1595    if ((1 == FLAGS_writePicturePath.count()) &&
1596        !(gmFlags & GM::kSkipPicture_Flag)) {
1597        const char* pictureSuffix = "skp";
1598        // TODO(epoger): Make sure this still works even though the
1599        // filename now contains the config name (it used to contain
1600        // just the shortName).  I think this is actually an
1601        // *improvement*, because now runs with different configs will
1602        // write out their SkPictures to separate files rather than
1603        // overwriting each other.  But we should make sure it doesn't
1604        // break anybody.
1605        SkString path = gmmain.make_filename(FLAGS_writePicturePath[0], gm->getName(),
1606                                             compareConfig.fName, "", pictureSuffix);
1607        SkFILEWStream stream(path.c_str());
1608        pict->serialize(&stream);
1609    }
1610
1611    if (FLAGS_rtree) {
1612        const char renderModeDescriptor[] = "-rtree";
1613        if ((gmFlags & GM::kSkipPicture_Flag) || (gmFlags & GM::kSkipTiled_Flag)) {
1614            gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1615                                     renderModeDescriptor);
1616            errorsForAllModes.add(kIntentionallySkipped_ErrorType);
1617        } else {
1618            SkPicture* pict = gmmain.generate_new_picture(gm, kRTree_BbhType, 0);
1619            SkAutoUnref aur(pict);
1620            SkBitmap bitmap;
1621            gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
1622            errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
1623                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
1624                &comparisonBitmap));
1625        }
1626    }
1627
1628    if (FLAGS_quadtree) {
1629        const char renderModeDescriptor[] = "-quadtree";
1630        if ((gmFlags & GM::kSkipPicture_Flag) || (gmFlags & GM::kSkipTiled_Flag)) {
1631            gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1632                                     renderModeDescriptor);
1633            errorsForAllModes.add(kIntentionallySkipped_ErrorType);
1634        } else {
1635            SkPicture* pict = gmmain.generate_new_picture(gm, kQuadTree_BbhType, 0);
1636            SkAutoUnref aur(pict);
1637            SkBitmap bitmap;
1638            gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
1639            errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
1640                gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
1641                &comparisonBitmap));
1642        }
1643    }
1644
1645    if (FLAGS_tileGrid) {
1646        for(int scaleIndex = 0; scaleIndex < tileGridReplayScales.count(); ++scaleIndex) {
1647            SkScalar replayScale = tileGridReplayScales[scaleIndex];
1648            SkString renderModeDescriptor("-tilegrid");
1649            if (SK_Scalar1 != replayScale) {
1650                renderModeDescriptor += "-scale-";
1651                renderModeDescriptor.appendScalar(replayScale);
1652            }
1653
1654            if ((gmFlags & GM::kSkipPicture_Flag) ||
1655                (gmFlags & GM::kSkipTiled_Flag) ||
1656                ((gmFlags & GM::kSkipScaledReplay_Flag) && replayScale != 1)) {
1657                gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
1658                                         renderModeDescriptor.c_str());
1659                errorsForAllModes.add(kIntentionallySkipped_ErrorType);
1660            } else {
1661                // We record with the reciprocal scale to obtain a replay
1662                // result that can be validated against comparisonBitmap.
1663                SkScalar recordScale = SkScalarInvert(replayScale);
1664                SkPicture* pict = gmmain.generate_new_picture(
1665                    gm, kTileGrid_BbhType, 0, recordScale);
1666                SkAutoUnref aur(pict);
1667                SkBitmap bitmap;
1668                // We cannot yet pass 'true' to generate_image_from_picture to
1669                // perform actual tiled rendering (see Issue 1198 -
1670                // https://code.google.com/p/skia/issues/detail?id=1198)
1671                gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap,
1672                                                   replayScale /*, true */);
1673                errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
1674                    gm->getName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap,
1675                    &comparisonBitmap));
1676            }
1677        }
1678    }
1679
1680    // run the pipe centric GM steps
1681    if (FLAGS_pipe) {
1682        errorsForAllModes.add(gmmain.test_pipe_playback(gm, compareConfig, comparisonBitmap,
1683                                                        FLAGS_simulatePipePlaybackFailure));
1684        if (FLAGS_tiledPipe) {
1685            errorsForAllModes.add(gmmain.test_tiled_pipe_playback(gm, compareConfig,
1686                                                                  comparisonBitmap));
1687        }
1688    }
1689    return errorsForAllModes;
1690}
1691
1692
1693/**
1694 * Run this test in a number of different configs (8888, 565, PDF,
1695 * etc.), confirming that the resulting bitmaps match expectations
1696 * (which may be different for each config).
1697 *
1698 * Returns all errors encountered while doing so.
1699 */
1700ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
1701                                      const SkTDArray<size_t> &configs,
1702                                      const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
1703                                      const SkTDArray<SkScalar> &tileGridReplayScales,
1704                                      GrContextFactory *grFactory);
1705ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
1706                                      const SkTDArray<size_t> &configs,
1707                                      const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
1708                                      const SkTDArray<SkScalar> &tileGridReplayScales,
1709                                      GrContextFactory *grFactory) {
1710    const char renderModeDescriptor[] = "";
1711    ErrorCombination errorsForAllConfigs;
1712    uint32_t gmFlags = gm->getFlags();
1713
1714    for (int i = 0; i < configs.count(); i++) {
1715        ConfigData config = gRec[configs[i]];
1716        const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(),
1717                                                                               config.fName);
1718
1719        // Skip any tests that we don't even need to try.
1720        // If any of these were skipped on a per-GM basis, record them as
1721        // kIntentionallySkipped.
1722        if (kPDF_Backend == config.fBackend) {
1723            if (gmFlags & GM::kSkipPDF_Flag) {
1724                gmmain.RecordSkippedTest(shortNamePlusConfig,
1725                                         renderModeDescriptor,
1726                                         config.fBackend);
1727                errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
1728                continue;
1729            }
1730        }
1731        if ((gmFlags & GM::kSkip565_Flag) &&
1732            (kRaster_Backend == config.fBackend) &&
1733            (kRGB_565_SkColorType == config.fColorType)) {
1734            gmmain.RecordSkippedTest(shortNamePlusConfig,
1735                                     renderModeDescriptor,
1736                                     config.fBackend);
1737            errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
1738            continue;
1739        }
1740        if (((gmFlags & GM::kSkipGPU_Flag) && kGPU_Backend == config.fBackend) ||
1741            ((gmFlags & GM::kGPUOnly_Flag) && kGPU_Backend != config.fBackend)) {
1742            gmmain.RecordSkippedTest(shortNamePlusConfig,
1743                                     renderModeDescriptor,
1744                                     config.fBackend);
1745            errorsForAllConfigs.add(kIntentionallySkipped_ErrorType);
1746            continue;
1747        }
1748
1749        // Now we know that we want to run this test and record its
1750        // success or failure.
1751        ErrorCombination errorsForThisConfig;
1752        GrSurface* gpuTarget = NULL;
1753#if SK_SUPPORT_GPU
1754        SkAutoTUnref<GrSurface> auGpuTarget;
1755        if ((errorsForThisConfig.isEmpty()) && (kGPU_Backend == config.fBackend)) {
1756            if (FLAGS_resetGpuContext) {
1757                grFactory->destroyContexts();
1758            }
1759            GrContext* gr = grFactory->get(config.fGLContextType);
1760            bool grSuccess = false;
1761            if (gr) {
1762                // create a render target to back the device
1763                GrTextureDesc desc;
1764                desc.fConfig = kSkia8888_GrPixelConfig;
1765                desc.fFlags = kRenderTarget_GrTextureFlagBit;
1766                desc.fWidth = gm->getISize().width();
1767                desc.fHeight = gm->getISize().height();
1768                desc.fSampleCnt = config.fSampleCnt;
1769                auGpuTarget.reset(gr->createUncachedTexture(desc, NULL, 0));
1770                if (NULL != auGpuTarget) {
1771                    gpuTarget = auGpuTarget;
1772                    grSuccess = true;
1773                    // Set the user specified cache limits if non-default.
1774                    size_t bytes;
1775                    int count;
1776                    gr->getResourceCacheLimits(&count, &bytes);
1777                    if (DEFAULT_CACHE_VALUE != gGpuCacheSizeBytes) {
1778                        bytes = static_cast<size_t>(gGpuCacheSizeBytes);
1779                    }
1780                    if (DEFAULT_CACHE_VALUE != gGpuCacheSizeCount) {
1781                        count = gGpuCacheSizeCount;
1782                    }
1783                    gr->setResourceCacheLimits(count, bytes);
1784                }
1785            }
1786            if (!grSuccess) {
1787                errorsForThisConfig.add(kNoGpuContext_ErrorType);
1788            }
1789        }
1790#endif
1791
1792        SkBitmap comparisonBitmap;
1793
1794        const char* writePath;
1795        if (FLAGS_writePath.count() == 1) {
1796            writePath = FLAGS_writePath[0];
1797        } else {
1798            writePath = NULL;
1799        }
1800
1801        if (errorsForThisConfig.isEmpty()) {
1802            errorsForThisConfig.add(gmmain.test_drawing(gm, config, pdfRasterizers,
1803                                                        writePath, gpuTarget,
1804                                                        &comparisonBitmap));
1805            gmmain.RecordTestResults(errorsForThisConfig, shortNamePlusConfig, "");
1806        }
1807
1808        // TODO: run only if gmmain.test_drawing succeeded.
1809        if (kRaster_Backend == config.fBackend) {
1810            run_multiple_modes(gmmain, gm, config, comparisonBitmap, tileGridReplayScales);
1811        }
1812
1813        if (FLAGS_deferred && errorsForThisConfig.isEmpty() &&
1814            (kGPU_Backend == config.fBackend || kRaster_Backend == config.fBackend)) {
1815            errorsForThisConfig.add(gmmain.test_deferred_drawing(gm, config, comparisonBitmap,
1816                                                                 gpuTarget));
1817        }
1818
1819        errorsForAllConfigs.add(errorsForThisConfig);
1820    }
1821    return errorsForAllConfigs;
1822}
1823
1824
1825/**
1826 * Read individual lines from a file, pushing them into the given array.
1827 *
1828 * @param filename path to the file to read
1829 * @param lines array of strings to add the lines to
1830 * @returns true if able to read lines from the file
1831 */
1832static bool read_lines_from_file(const char* filename, SkTArray<SkString> &lines) {
1833    SkAutoTUnref<SkStream> streamWrapper(SkStream::NewFromFile(filename));
1834    SkStream *stream = streamWrapper.get();
1835    if (!stream) {
1836        SkDebugf("unable to read file '%s'\n", filename);
1837        return false;
1838    }
1839
1840    char c;
1841    SkString line;
1842    while (1 == stream->read(&c, 1)) {
1843        // If we hit either CR or LF, we've completed a line.
1844        //
1845        // TODO: If the file uses both CR and LF, this will return an extra blank
1846        // line for each line of the file.  Which is OK for current purposes...
1847        //
1848        // TODO: Does this properly handle unicode?  It doesn't matter for
1849        // current purposes...
1850        if ((c == 0x0d) || (c == 0x0a)) {
1851            lines.push_back(line);
1852            line.reset();
1853        } else {
1854            line.append(&c, 1);
1855        }
1856    }
1857    lines.push_back(line);
1858    return true;
1859}
1860
1861/**
1862 * Return a list of all entries in an array of strings as a single string
1863 * of this form:
1864 * "item1", "item2", "item3"
1865 */
1866SkString list_all(const SkTArray<SkString> &stringArray);
1867SkString list_all(const SkTArray<SkString> &stringArray) {
1868    SkString total;
1869    for (int i = 0; i < stringArray.count(); i++) {
1870        if (i > 0) {
1871            total.append(", ");
1872        }
1873        total.append("\"");
1874        total.append(stringArray[i]);
1875        total.append("\"");
1876    }
1877    return total;
1878}
1879
1880/**
1881 * Return a list of configuration names, as a single string of this form:
1882 * "item1", "item2", "item3"
1883 *
1884 * @param configs configurations, as a list of indices into gRec
1885 */
1886SkString list_all_config_names(const SkTDArray<size_t> &configs);
1887SkString list_all_config_names(const SkTDArray<size_t> &configs) {
1888    SkString total;
1889    for (int i = 0; i < configs.count(); i++) {
1890        if (i > 0) {
1891            total.append(", ");
1892        }
1893        total.append("\"");
1894        total.append(gRec[configs[i]].fName);
1895        total.append("\"");
1896    }
1897    return total;
1898}
1899
1900static bool prepare_subdirectories(const char *root, bool useFileHierarchy,
1901                                   const SkTDArray<size_t> &configs,
1902                                   const SkTDArray<const PDFRasterizerData*>& pdfRasterizers) {
1903    if (!sk_mkdir(root)) {
1904        return false;
1905    }
1906    if (useFileHierarchy) {
1907        for (int i = 0; i < configs.count(); i++) {
1908            ConfigData config = gRec[configs[i]];
1909            SkString subdir;
1910            subdir.appendf("%s%c%s", root, SkPATH_SEPARATOR, config.fName);
1911            if (!sk_mkdir(subdir.c_str())) {
1912                return false;
1913            }
1914
1915            if (config.fBackend == kPDF_Backend) {
1916                for (int j = 0; j < pdfRasterizers.count(); j++) {
1917                    SkString pdfSubdir = subdir;
1918                    pdfSubdir.appendf("-%s", pdfRasterizers[j]->fName);
1919                    if (!sk_mkdir(pdfSubdir.c_str())) {
1920                        return false;
1921                    }
1922                }
1923            }
1924        }
1925    }
1926    return true;
1927}
1928
1929static bool parse_flags_configs(SkTDArray<size_t>* outConfigs,
1930                         GrContextFactory* grFactory) {
1931    SkTDArray<size_t> excludeConfigs;
1932
1933    for (int i = 0; i < FLAGS_config.count(); i++) {
1934        const char* config = FLAGS_config[i];
1935        bool exclude = false;
1936        if (*config == kExcludeConfigChar) {
1937            exclude = true;
1938            config += 1;
1939        }
1940        int index = findConfig(config);
1941        if (index >= 0) {
1942            if (exclude) {
1943                *excludeConfigs.append() = index;
1944            } else {
1945                appendUnique<size_t>(outConfigs, index);
1946            }
1947        } else if (0 == strcmp(kDefaultsConfigStr, config)) {
1948            if (exclude) {
1949                SkDebugf("%c%s is not allowed.\n",
1950                         kExcludeConfigChar, kDefaultsConfigStr);
1951                return false;
1952            }
1953            for (size_t c = 0; c < SK_ARRAY_COUNT(gRec); ++c) {
1954                if (gRec[c].fRunByDefault) {
1955                    appendUnique<size_t>(outConfigs, c);
1956                }
1957            }
1958        } else {
1959            SkDebugf("unrecognized config %s\n", config);
1960            return false;
1961        }
1962    }
1963
1964    for (int i = 0; i < FLAGS_excludeConfig.count(); i++) {
1965        int index = findConfig(FLAGS_excludeConfig[i]);
1966        if (index >= 0) {
1967            *excludeConfigs.append() = index;
1968        } else {
1969            SkDebugf("unrecognized excludeConfig %s\n", FLAGS_excludeConfig[i]);
1970            return false;
1971        }
1972    }
1973
1974    if (outConfigs->count() == 0) {
1975        // if no config is specified by user, add the defaults
1976        for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
1977            if (gRec[i].fRunByDefault) {
1978                *outConfigs->append() = i;
1979            }
1980        }
1981    }
1982    // now remove any explicitly excluded configs
1983    for (int i = 0; i < excludeConfigs.count(); ++i) {
1984        int index = outConfigs->find(excludeConfigs[i]);
1985        if (index >= 0) {
1986            outConfigs->remove(index);
1987            // now assert that there was only one copy in configs[]
1988            SkASSERT(outConfigs->find(excludeConfigs[i]) < 0);
1989        }
1990    }
1991
1992#if SK_SUPPORT_GPU
1993    SkASSERT(grFactory != NULL);
1994    for (int i = 0; i < outConfigs->count(); ++i) {
1995        size_t index = (*outConfigs)[i];
1996        if (kGPU_Backend == gRec[index].fBackend) {
1997            GrContext* ctx = grFactory->get(gRec[index].fGLContextType);
1998            if (NULL == ctx) {
1999                SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n",
2000                         gRec[index].fName);
2001                outConfigs->remove(i);
2002                --i;
2003                continue;
2004            }
2005            if (gRec[index].fSampleCnt > ctx->getMaxSampleCount()) {
2006                SkDebugf("Sample count (%d) of config %s is not supported."
2007                         " Config will be skipped.\n",
2008                         gRec[index].fSampleCnt, gRec[index].fName);
2009                outConfigs->remove(i);
2010                --i;
2011            }
2012        }
2013    }
2014#endif
2015
2016    if (outConfigs->isEmpty()) {
2017        SkDebugf("No configs to run.");
2018        return false;
2019    }
2020
2021    // now show the user the set of configs that will be run.
2022    SkString configStr("These configs will be run:");
2023    // show the user the config that will run.
2024    for (int i = 0; i < outConfigs->count(); ++i) {
2025        configStr.appendf(" %s", gRec[(*outConfigs)[i]].fName);
2026    }
2027    SkDebugf("%s\n", configStr.c_str());
2028
2029    return true;
2030}
2031
2032static bool parse_flags_pdf_rasterizers(const SkTDArray<size_t>& configs,
2033                                        SkTDArray<const PDFRasterizerData*>* outRasterizers) {
2034    // No need to run this check (and display the PDF rasterizers message)
2035    // if no PDF backends are in the configs.
2036    bool configHasPDF = false;
2037    for (int i = 0; i < configs.count(); i++) {
2038        if (gRec[configs[i]].fBackend == kPDF_Backend) {
2039            configHasPDF = true;
2040            break;
2041        }
2042    }
2043    if (!configHasPDF) {
2044        return true;
2045    }
2046
2047    if (FLAGS_pdfRasterizers.count() == 1 &&
2048            !strcmp(FLAGS_pdfRasterizers[0], "default")) {
2049        for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) {
2050            if (kPDFRasterizers[i].fRunByDefault) {
2051                *outRasterizers->append() = &kPDFRasterizers[i];
2052            }
2053        }
2054    } else {
2055        for (int i = 0; i < FLAGS_pdfRasterizers.count(); i++) {
2056            const char* rasterizer = FLAGS_pdfRasterizers[i];
2057            const PDFRasterizerData* rasterizerPtr =
2058                    findPDFRasterizer(rasterizer);
2059            if (rasterizerPtr == NULL) {
2060                SkDebugf("unrecognized rasterizer %s\n", rasterizer);
2061                return false;
2062            }
2063            appendUnique<const PDFRasterizerData*>(outRasterizers,
2064                                                   rasterizerPtr);
2065        }
2066    }
2067
2068    // now show the user the set of configs that will be run.
2069    SkString configStr("These PDF rasterizers will be run:");
2070    // show the user the config that will run.
2071    for (int i = 0; i < outRasterizers->count(); ++i) {
2072        configStr.appendf(" %s", (*outRasterizers)[i]->fName);
2073    }
2074    SkDebugf("%s\n", configStr.c_str());
2075
2076    return true;
2077}
2078
2079static bool parse_flags_ignore_error_types(ErrorCombination* outErrorTypes) {
2080    if (FLAGS_ignoreErrorTypes.count() > 0) {
2081        *outErrorTypes = ErrorCombination();
2082        for (int i = 0; i < FLAGS_ignoreErrorTypes.count(); i++) {
2083            ErrorType type;
2084            const char *name = FLAGS_ignoreErrorTypes[i];
2085            if (!getErrorTypeByName(name, &type)) {
2086                SkDebugf("cannot find ErrorType with name '%s'\n", name);
2087                return false;
2088            } else {
2089                outErrorTypes->add(type);
2090            }
2091        }
2092    }
2093    return true;
2094}
2095
2096/**
2097 * Replace contents of ignoreTestNames with a list of test names, indicating
2098 * which tests' failures should be ignored.
2099 */
2100static bool parse_flags_ignore_tests(SkTArray<SkString> &ignoreTestNames) {
2101    ignoreTestNames.reset();
2102
2103    // Parse --ignoreFailuresFile
2104    for (int i = 0; i < FLAGS_ignoreFailuresFile.count(); i++) {
2105        SkTArray<SkString> linesFromFile;
2106        if (!read_lines_from_file(FLAGS_ignoreFailuresFile[i], linesFromFile)) {
2107            return false;
2108        } else {
2109            for (int j = 0; j < linesFromFile.count(); j++) {
2110                SkString thisLine = linesFromFile[j];
2111                if (thisLine.isEmpty() || thisLine.startsWith('#')) {
2112                    // skip this line
2113                } else {
2114                    ignoreTestNames.push_back(thisLine);
2115                }
2116            }
2117        }
2118    }
2119
2120    return true;
2121}
2122
2123static bool parse_flags_modulo(int* moduloRemainder, int* moduloDivisor) {
2124    if (FLAGS_modulo.count() == 2) {
2125        *moduloRemainder = atoi(FLAGS_modulo[0]);
2126        *moduloDivisor = atoi(FLAGS_modulo[1]);
2127        if (*moduloRemainder < 0 || *moduloDivisor <= 0 ||
2128                *moduloRemainder >= *moduloDivisor) {
2129            SkDebugf("invalid modulo values.");
2130            return false;
2131        }
2132    }
2133    return true;
2134}
2135
2136#if SK_SUPPORT_GPU
2137static bool parse_flags_gpu_cache(int* sizeBytes, int* sizeCount) {
2138    if (FLAGS_gpuCacheSize.count() > 0) {
2139        if (FLAGS_gpuCacheSize.count() != 2) {
2140            SkDebugf("--gpuCacheSize requires two arguments\n");
2141            return false;
2142        }
2143        *sizeBytes = atoi(FLAGS_gpuCacheSize[0]);
2144        *sizeCount = atoi(FLAGS_gpuCacheSize[1]);
2145    } else {
2146        *sizeBytes = DEFAULT_CACHE_VALUE;
2147        *sizeCount = DEFAULT_CACHE_VALUE;
2148    }
2149    return true;
2150}
2151#endif
2152
2153static bool parse_flags_tile_grid_replay_scales(SkTDArray<SkScalar>* outScales) {
2154    *outScales->append() = SK_Scalar1; // By default only test at scale 1.0
2155    if (FLAGS_tileGridReplayScales.count() > 0) {
2156        outScales->reset();
2157        for (int i = 0; i < FLAGS_tileGridReplayScales.count(); i++) {
2158            double val = atof(FLAGS_tileGridReplayScales[i]);
2159            if (0 < val) {
2160                *outScales->append() = SkDoubleToScalar(val);
2161            }
2162        }
2163        if (0 == outScales->count()) {
2164            // Should have at least one scale
2165            SkDebugf("--tileGridReplayScales requires at least one scale.\n");
2166            return false;
2167        }
2168    }
2169    return true;
2170}
2171
2172static bool parse_flags_gmmain_paths(GMMain* gmmain) {
2173    gmmain->fUseFileHierarchy = FLAGS_hierarchy;
2174    gmmain->fWriteChecksumBasedFilenames = FLAGS_writeChecksumBasedFilenames;
2175
2176    if (FLAGS_mismatchPath.count() == 1) {
2177        gmmain->fMismatchPath = FLAGS_mismatchPath[0];
2178    }
2179
2180    if (FLAGS_missingExpectationsPath.count() == 1) {
2181        gmmain->fMissingExpectationsPath = FLAGS_missingExpectationsPath[0];
2182    }
2183
2184    if (FLAGS_readPath.count() == 1) {
2185        const char* readPath = FLAGS_readPath[0];
2186        if (!sk_exists(readPath)) {
2187            SkDebugf("readPath %s does not exist!\n", readPath);
2188            return false;
2189        }
2190        if (sk_isdir(readPath)) {
2191            if (FLAGS_verbose) {
2192                SkDebugf("reading from %s\n", readPath);
2193            }
2194            gmmain->fExpectationsSource.reset(SkNEW_ARGS(
2195                IndividualImageExpectationsSource, (readPath)));
2196        } else {
2197            if (FLAGS_verbose) {
2198                SkDebugf("reading expectations from JSON summary file %s\n", readPath);
2199            }
2200            gmmain->fExpectationsSource.reset(SkNEW_ARGS(JsonExpectationsSource, (readPath)));
2201        }
2202    }
2203    return true;
2204}
2205
2206static bool parse_flags_jpeg_quality() {
2207    if (FLAGS_pdfJpegQuality < -1 || FLAGS_pdfJpegQuality > 100) {
2208        SkDebugf("%s\n", "pdfJpegQuality must be in [-1 .. 100] range.");
2209        return false;
2210    }
2211    return true;
2212}
2213
2214int tool_main(int argc, char** argv);
2215int tool_main(int argc, char** argv) {
2216    SetupCrashHandler();
2217
2218    SkString usage;
2219    usage.printf("Run the golden master tests.\n");
2220    SkCommandLineFlags::SetUsage(usage.c_str());
2221    SkCommandLineFlags::Parse(argc, argv);
2222
2223#if SK_ENABLE_INST_COUNT
2224    if (FLAGS_leaks) {
2225        gPrintInstCount = true;
2226    }
2227#endif
2228
2229    SkGraphics::Init();
2230
2231    setSystemPreferences();
2232    GMMain gmmain;
2233
2234    SkTDArray<size_t> configs;
2235
2236    int moduloRemainder = -1;
2237    int moduloDivisor = -1;
2238    SkTDArray<const PDFRasterizerData*> pdfRasterizers;
2239    SkTDArray<SkScalar> tileGridReplayScales;
2240#if SK_SUPPORT_GPU
2241    GrContextFactory* grFactory = new GrContextFactory;
2242#else
2243    GrContextFactory* grFactory = NULL;
2244#endif
2245
2246    if (FLAGS_dryRun) {
2247        SkDebugf( "Doing a dry run; no tests will actually be executed.\n");
2248    }
2249
2250    if (!parse_flags_modulo(&moduloRemainder, &moduloDivisor) ||
2251        !parse_flags_ignore_error_types(&gmmain.fIgnorableErrorTypes) ||
2252        !parse_flags_ignore_tests(gmmain.fIgnorableTestNames) ||
2253#if SK_SUPPORT_GPU
2254        !parse_flags_gpu_cache(&gGpuCacheSizeBytes, &gGpuCacheSizeCount) ||
2255#endif
2256        !parse_flags_tile_grid_replay_scales(&tileGridReplayScales) ||
2257        !parse_flags_jpeg_quality() ||
2258        !parse_flags_configs(&configs, grFactory) ||
2259        !parse_flags_pdf_rasterizers(configs, &pdfRasterizers) ||
2260        !parse_flags_gmmain_paths(&gmmain)) {
2261        return -1;
2262    }
2263
2264    if (FLAGS_verbose) {
2265        if (FLAGS_writePath.count() == 1) {
2266            SkDebugf("writing to %s\n", FLAGS_writePath[0]);
2267        }
2268        if (NULL != gmmain.fMismatchPath) {
2269            SkDebugf("writing mismatches to %s\n", gmmain.fMismatchPath);
2270        }
2271        if (NULL != gmmain.fMissingExpectationsPath) {
2272            SkDebugf("writing images without expectations to %s\n",
2273                     gmmain.fMissingExpectationsPath);
2274        }
2275        if (FLAGS_writePicturePath.count() == 1) {
2276            SkDebugf("writing pictures to %s\n", FLAGS_writePicturePath[0]);
2277        }
2278        if (!GetResourcePath().isEmpty()) {
2279            SkDebugf("reading resources from %s\n", GetResourcePath().c_str());
2280        }
2281    }
2282
2283    int gmsRun = 0;
2284    int gmIndex = -1;
2285    SkString moduloStr;
2286
2287    if (!FLAGS_dryRun) {
2288        // If we will be writing out files, prepare subdirectories.
2289        if (FLAGS_writePath.count() == 1) {
2290            if (!prepare_subdirectories(FLAGS_writePath[0], gmmain.fUseFileHierarchy,
2291                                        configs, pdfRasterizers)) {
2292                return -1;
2293            }
2294        }
2295        if (NULL != gmmain.fMismatchPath) {
2296            if (!prepare_subdirectories(gmmain.fMismatchPath, gmmain.fUseFileHierarchy,
2297                                        configs, pdfRasterizers)) {
2298                return -1;
2299            }
2300        }
2301        if (NULL != gmmain.fMissingExpectationsPath) {
2302            if (!prepare_subdirectories(gmmain.fMissingExpectationsPath, gmmain.fUseFileHierarchy,
2303                                        configs, pdfRasterizers)) {
2304                return -1;
2305            }
2306        }
2307    }
2308    Iter iter;
2309    GM* gm;
2310    while ((gm = iter.next()) != NULL) {
2311        if (FLAGS_forcePerspectiveMatrix) {
2312            SkMatrix perspective;
2313            perspective.setIdentity();
2314            perspective.setPerspY(SkScalarDiv(SK_Scalar1, SkIntToScalar(1000)));
2315            perspective.setSkewX(SkScalarDiv(SkIntToScalar(8),
2316                                 SkIntToScalar(25)));
2317
2318            gm->setStarterMatrix(perspective);
2319        }
2320        SkAutoTDelete<GM> adgm(gm);
2321        ++gmIndex;
2322        if (moduloRemainder >= 0) {
2323            if ((gmIndex % moduloDivisor) != moduloRemainder) {
2324                continue;
2325            }
2326            moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor);
2327        }
2328
2329        const char* shortName = gm->getName();
2330
2331        if (SkCommandLineFlags::ShouldSkip(FLAGS_match, shortName)) {
2332            continue;
2333        }
2334
2335        gmsRun++;
2336        SkISize size = gm->getISize();
2337        SkDebugf("%sdrawing... %s [%d %d]\n", moduloStr.c_str(), shortName,
2338                 size.width(), size.height());
2339        if (!FLAGS_dryRun)
2340            run_multiple_configs(gmmain, gm, configs, pdfRasterizers, tileGridReplayScales, grFactory);
2341    }
2342
2343    if (FLAGS_dryRun)
2344        return 0;
2345
2346    SkTArray<SkString> modes;
2347    gmmain.GetRenderModesEncountered(modes);
2348    int modeCount = modes.count();
2349
2350    // Now that we have run all the tests and thus know the full set of renderModes that we
2351    // tried to run, we can call RecordTestResults() to record the cases in which we skipped
2352    // ALL renderModes.
2353    // See http://skbug.com/1994 and https://codereview.chromium.org/129203002/
2354    int testCount = gmmain.fTestsSkippedOnAllRenderModes.count();
2355    for (int testNum = 0; testNum < testCount; ++testNum) {
2356        const SkString &shortNamePlusConfig = gmmain.fTestsSkippedOnAllRenderModes[testNum];
2357        for (int modeNum = 0; modeNum < modeCount; ++modeNum) {
2358            gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig,
2359                                     modes[modeNum].c_str());
2360        }
2361    }
2362
2363    bool reportError = false;
2364    if (gmmain.NumSignificantErrors() > 0) {
2365        reportError = true;
2366    }
2367
2368    // We test every GM against every config, and for every raster config also test every mode.
2369    int rasterConfigs = 0;
2370    for (int i = 0; i < configs.count(); i++) {
2371        if (gRec[configs[i]].fBackend == kRaster_Backend) {
2372            rasterConfigs++;
2373        }
2374    }
2375    // For raster configs, we run all renderModes; for non-raster configs, just default renderMode
2376    const int expectedNumberOfTests = rasterConfigs * gmsRun * modeCount
2377                                    + (configs.count() - rasterConfigs) * gmsRun;
2378
2379    // Output summary to stdout.
2380    if (FLAGS_verbose) {
2381        SkDebugf("Ran %d GMs\n", gmsRun);
2382        SkDebugf("... over %2d configs [%s]\n", configs.count(),
2383                 list_all_config_names(configs).c_str());
2384        SkDebugf("...  and %2d modes   [%s]\n", modeCount, list_all(modes).c_str());
2385        SkDebugf("... so there should be a total of %d tests.\n", expectedNumberOfTests);
2386    }
2387    gmmain.ListErrors(FLAGS_verbose);
2388
2389    // TODO(epoger): Enable this check for Android, too, once we resolve
2390    // https://code.google.com/p/skia/issues/detail?id=1222
2391    // ('GM is unexpectedly skipping tests on Android')
2392#ifndef SK_BUILD_FOR_ANDROID
2393    if (expectedNumberOfTests != gmmain.fTestsRun) {
2394        SkDebugf("expected %d tests, but ran or skipped %d tests\n",
2395                 expectedNumberOfTests, gmmain.fTestsRun);
2396        reportError = true;
2397    }
2398#endif
2399
2400    if (FLAGS_writeJsonSummaryPath.count() == 1) {
2401        Json::Value root = CreateJsonTree(
2402            gmmain.fJsonExpectedResults,
2403            gmmain.fJsonActualResults_Failed, gmmain.fJsonActualResults_FailureIgnored,
2404            gmmain.fJsonActualResults_NoComparison, gmmain.fJsonActualResults_Succeeded);
2405        std::string jsonStdString = root.toStyledString();
2406        SkFILEWStream stream(FLAGS_writeJsonSummaryPath[0]);
2407        stream.write(jsonStdString.c_str(), jsonStdString.length());
2408    }
2409
2410#if SK_SUPPORT_GPU
2411
2412#if GR_CACHE_STATS
2413    for (int i = 0; i < configs.count(); i++) {
2414        ConfigData config = gRec[configs[i]];
2415
2416        if (FLAGS_verbose && (kGPU_Backend == config.fBackend)) {
2417            GrContext* gr = grFactory->get(config.fGLContextType);
2418
2419            SkDebugf("config: %s %x\n", config.fName, gr);
2420            gr->printCacheStats();
2421        }
2422    }
2423#endif
2424
2425#if GR_DUMP_FONT_CACHE
2426    for (int i = 0; i < configs.count(); i++) {
2427        ConfigData config = gRec[configs[i]];
2428
2429        if (kGPU_Backend == config.fBackend) {
2430            GrContext* gr = grFactory->get(config.fGLContextType);
2431
2432           gr->dumpFontCache();
2433        }
2434    }
2435#endif
2436
2437    delete grFactory;
2438#endif
2439    SkGraphics::Term();
2440
2441    return (reportError) ? -1 : 0;
2442}
2443
2444void GMMain::installFilter(SkCanvas* canvas) {
2445    if (FLAGS_forceBWtext) {
2446        canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref();
2447    }
2448}
2449
2450#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
2451int main(int argc, char * const argv[]) {
2452    return tool_main(argc, (char**) argv);
2453}
2454#endif
2455