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 SkTracker_DEFINED
9#define SkTracker_DEFINED
10
11#include <stdio.h>
12
13#include "SkBitmap.h"
14#include "SkPoint.h"
15
16// TODO(edisonn): draw plan from point! - list of draw ops of a point, like a tree!
17// TODO(edisonn): Minimal PDF to draw some points - remove everything that it is not needed,
18//                save pdf uncompressed
19
20#define MAX_TRACKING_POINTS 100
21
22/** \class SkTracker
23 *
24 *   A Tracker can be attached to a SkTrackDevice and it will store the track pixels.
25 *   It can be used with SampleApp to investigate bugs (CL not checked in yet).
26 *
27 *   The Tracker tracks 2 sets of points
28 *     A) one which is expected to issue breackpoints if the pixels are changes
29 *     B) one which if changes will disable the breackpoint
30 *   For point in A) there are two modes:
31 *     A.1) a breackpoint require that any of the points is changed
32 *     A.2) a breackpoint require that all of the points is changed
33 *   Points in B are allways in "any mode" - chaning the value of any pixel, will disable
34 *     the breackpoint
35 *
36 *   Point in A) are used to show what are the areas of interest, while poit in B are used to
37 *     disable breackpoints which would be issued in background change.
38 *
39 */
40class SkTracker {
41public:
42    SkTracker() : fEnabled(false)
43                , fBreakOnAny(false)
44                , fCntExpectedTouched(0)
45                , fCntExpectedUntouched(0)
46                , fHits(0) {}
47
48    virtual ~SkTracker() {}
49
50    // Clears all the points, but preserves the break mode.
51    void clearPoints() {
52        fCntExpectedTouched = 0;
53        fCntExpectedUntouched = 0;
54    }
55
56    // Enable the breackpoints.
57    void enableTracking(bool b) {
58        fEnabled = b;
59    }
60
61    // Returns true if breackpoints are enabled.
62    bool trackingEnabled() {
63        return fEnabled;
64    }
65
66    // Puts the tracker in Any mode.
67    void any() {
68        fBreakOnAny = true;
69    }
70
71    // Puts the tracker in Any mode.
72    void all() {
73        fBreakOnAny = false;
74    }
75
76    // returns true in in All mode. False for Any mode.
77    bool requireAllExpectedTouched() {
78        return !fBreakOnAny;
79    }
80
81    // Returns the numbers of points in which if touched, would trigger a breackpoint.
82    int cntExpectedTouched() {
83        return fCntExpectedTouched;
84    }
85
86    // Returns the points which if touched, would trigger a breackpoint.
87    // the Tracker owns the array
88    const SkIPoint* expectedTouched() {
89        return fExpectedTouched;
90    }
91
92    // Returns the numbers of points in which if touched, would disable a breackpoint.
93    int cntExpectedUntouched() {
94        return fCntExpectedUntouched;
95    }
96
97    // Returns the points which if touched, would disable a breackpoint.
98    // the Tracker owns the array
99    const SkIPoint* expectedUntouched() {
100        return fExpectedUntouched;
101    }
102
103    // Adds a point which if changes in a drawFoo operation, would trigger a breakpoint.
104    bool addExpectTouch(int x, int y) {
105        if (fCntExpectedTouched >= MAX_TRACKING_POINTS) {
106            return false;
107        }
108        if (found(x, y)) {
109            return false;
110        }
111        fExpectedTouched[fCntExpectedTouched] = SkIPoint::Make(x, y);
112        fCntExpectedTouched++;
113        return true;
114    }
115
116    // Adds a point which if changes in a drawFoo operation, would disable a breakpoint.
117    bool addExpectUntouch(int x, int y) {
118        if (fCntExpectedUntouched >= MAX_TRACKING_POINTS) {
119            return false;
120        }
121        if (found(x, y)) {
122            return false;
123        }
124        fExpectedUntouched[fCntExpectedUntouched] = SkIPoint::Make(x, y);
125        fCntExpectedUntouched++;
126        return true;
127    }
128
129    // Starts a new rendering session - reset the number of hits.
130    void newFrame() {
131        fHits = 0;
132    }
133
134    // returns the number of breackpoints issues in this rendering session.
135    int hits() {
136        return fHits;
137    }
138
139    // Called before drawFoo to store the state of the pixels
140    void before(const SkBitmap& bitmap) {
141        if (fCntExpectedTouched == 0) {
142            return;
143        }
144
145        for (int i = 0 ; i < fCntExpectedTouched; i++) {
146            fBeforeTouched[i] = pickColor(bitmap, fExpectedTouched[i].x(), fExpectedTouched[i].y());
147        }
148        for (int i = 0 ; i < fCntExpectedUntouched; i++) {
149            fBeforeUntouched[i] = pickColor(bitmap, fExpectedUntouched[i].x(),
150                                            fExpectedUntouched[i].y());
151        }
152    }
153
154    // Called after drawFoo to evaluate what pixels have changed, it could issue a breakpoint.
155    // any/all of the expected touched has to be changed, and all expected untouched must be intact
156    void after(const SkBitmap& bitmap) {
157        if (fCntExpectedTouched == 0) {
158            return;
159        }
160
161        bool doBreak;
162        if (fBreakOnAny) {
163            doBreak = false;
164            for (int i = 0 ; i < fCntExpectedTouched; i++) {
165                doBreak = doBreak || fBeforeTouched[i] != pickColor(bitmap, fExpectedTouched[i].x(),
166                                                                    fExpectedTouched[i].y());
167            }
168        } else {
169            doBreak = true;
170            for (int i = 0 ; i < fCntExpectedTouched; i++) {
171                doBreak = doBreak && fBeforeTouched[i] != pickColor(bitmap, fExpectedTouched[i].x(),
172                                                                    fExpectedTouched[i].y());
173            }
174        }
175
176        for (int i = 0 ; i < fCntExpectedUntouched; i++) {
177            doBreak = doBreak && fBeforeUntouched[i] == pickColor(bitmap, fExpectedUntouched[i].x(),
178                                                                  fExpectedUntouched[i].y());
179        }
180
181        if (doBreak) {
182            fHits++;
183            if (fEnabled) {
184                breakExecution();
185            }
186        }
187    }
188
189private:
190    inline SkColor pickColor(const SkBitmap& bitmap, int x, int y) {
191        return bitmap.getColor(x, y);
192    }
193
194    void breakExecution() {
195        printf("break;\n");
196    }
197
198    inline bool found(int x, int y) {
199        for (int i = 0 ; i < fCntExpectedTouched; i++) {
200            if (x == fExpectedTouched[i].x() && y == fExpectedTouched[i].y()) {
201                return true;
202            }
203        }
204        for (int i = 0 ; i < fCntExpectedUntouched; i++) {
205            if (x == fExpectedUntouched[i].x() && y == fExpectedUntouched[i].y()) {
206                return true;
207            }
208        }
209        return false;
210    }
211
212
213    bool fEnabled;
214    // break on any change on expected touched or all.
215    bool fBreakOnAny;
216    SkIPoint fExpectedTouched[MAX_TRACKING_POINTS];
217    SkColor fBeforeTouched[MAX_TRACKING_POINTS];
218    int fCntExpectedTouched;
219
220    SkIPoint fExpectedUntouched[MAX_TRACKING_POINTS];
221    SkColor fBeforeUntouched[MAX_TRACKING_POINTS];
222    int fCntExpectedUntouched;
223
224    int fHits;
225};
226
227#endif  // SkTracker_DEFINED
228