1/*
2 * Copyright 2013 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#ifndef SkDiffContext_DEFINED
9#define SkDiffContext_DEFINED
10
11#include "SkImageDiffer.h"
12#include "SkString.h"
13#include "SkTArray.h"
14#include "SkTDArray.h"
15#include "SkTLList.h"
16#include "SkThread.h"
17
18class SkWStream;
19
20/**
21 * Collects records of diffs and outputs them as JSON.
22 */
23class SkDiffContext {
24public:
25    SkDiffContext();
26    ~SkDiffContext();
27
28    void setThreadCount(int threadCount) { fThreadCount = threadCount; }
29
30    /**
31     * Creates the directory if it does not exist and uses it to store differences
32     * between images.
33     */
34    void setDifferenceDir(const SkString& directory);
35
36    /**
37     * Sets the differs to be used in each diff. Already started diffs will not retroactively use
38     * these.
39     * @param differs An array of differs to use. The array is copied, but not the differs
40     *                themselves.
41     */
42    void setDiffers(const SkTDArray<SkImageDiffer*>& differs);
43
44    /**
45     * Compares two directories of images with the given differ
46     * @param baselinePath The baseline directory's path
47     * @param testPath     The test directory's path
48     */
49    void diffDirectories(const char baselinePath[], const char testPath[]);
50
51    /**
52     * Compares two sets of images identified by glob style patterns with the given differ
53     * @param baselinePattern A pattern for baseline files
54     * @param testPattern     A pattern for test files that matches each file of the baseline file
55     */
56    void diffPatterns(const char baselinePattern[], const char testPattern[]);
57
58    /**
59     * Compares the images at the given paths
60     * @param baselinePath The baseline file path
61     * @param testPath     The matching test file path
62     */
63    void addDiff(const char* baselinePath, const char* testPath);
64
65    /**
66     * Output the records of each diff in JSON.
67     *
68     * The format of the JSON document is one top level array named "records".
69     * Each record in the array is an object with the following values:
70     *    "commonName"     : string containing the common prefix of the baselinePath
71     *                       and testPath filenames
72     *    "baselinePath"   : string containing the path to the baseline image
73     *    "testPath"       : string containing the path to the test image
74     *    "differencePath" : (optional) string containing the path to an alpha
75     *                       mask of the pixel difference between the baseline
76     *                       and test images
77     *
78     * They also have an array named "diffs" with each element being one diff record for the two
79     * images indicated in the above field.
80     * A diff record includes:
81     *    "differName"       : string name of the diff metric used
82     *    "result"           : numerical result of the diff
83     *
84     * Here is an example:
85     *
86     * {
87     *     "records": [
88     *         {
89     *             "commonName": "queue.png",
90     *             "baselinePath": "/a/queue.png",
91     *             "testPath": "/b/queue.png",
92     *             "diffs": [
93     *                 {
94     *                     "differName": "different_pixels",
95     *                     "result": 1,
96     *                 }
97     *             ]
98     *         }
99     *     ]
100     * }
101     *
102     * @param stream   The stream to output the diff to
103     * @param useJSONP True to adding padding to the JSON output to make it cross-site requestable.
104     */
105    void outputRecords(SkWStream& stream, bool useJSONP);
106
107    /**
108     * Output the records score in csv format.
109     */
110    void outputCsv(SkWStream& stream);
111
112
113private:
114    struct DiffData {
115        const char* fDiffName;
116        SkImageDiffer::Result fResult;
117    };
118
119    struct DiffRecord {
120        SkString           fCommonName;
121        SkString           fDifferencePath;
122        SkString           fBaselinePath;
123        SkString               fTestPath;
124        SkTArray<DiffData>        fDiffs;
125    };
126
127    // Used to protect access to fRecords and ensure only one thread is
128    // adding new entries at a time.
129    SkMutex fRecordMutex;
130
131    // We use linked list for the records so that their pointers remain stable. A resizable array
132    // might change its pointers, which would make it harder for async diffs to record their
133    // results.
134    SkTLList<DiffRecord> fRecords;
135
136    SkImageDiffer** fDiffers;
137    int fDifferCount;
138    int fThreadCount;
139
140    SkString fDifferenceDir;
141};
142
143#endif
144