/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTracker_DEFINED #define SkTracker_DEFINED #include #include "SkBitmap.h" #include "SkPoint.h" // TODO(edisonn): draw plan from point! - list of draw ops of a point, like a tree! // TODO(edisonn): Minimal PDF to draw some points - remove everything that it is not needed, // save pdf uncompressed #define MAX_TRACKING_POINTS 100 /** \class SkTracker * * A Tracker can be attached to a SkTrackDevice and it will store the track pixels. * It can be used with SampleApp to investigate bugs (CL not checked in yet). * * The Tracker tracks 2 sets of points * A) one which is expected to issue breackpoints if the pixels are changes * B) one which if changes will disable the breackpoint * For point in A) there are two modes: * A.1) a breackpoint require that any of the points is changed * A.2) a breackpoint require that all of the points is changed * Points in B are allways in "any mode" - chaning the value of any pixel, will disable * the breackpoint * * Point in A) are used to show what are the areas of interest, while poit in B are used to * disable breackpoints which would be issued in background change. * */ class SkTracker { public: SkTracker() : fEnabled(false) , fBreakOnAny(false) , fCntExpectedTouched(0) , fCntExpectedUntouched(0) , fHits(0) {} virtual ~SkTracker() {} // Clears all the points, but preserves the break mode. void clearPoints() { fCntExpectedTouched = 0; fCntExpectedUntouched = 0; } // Enable the breackpoints. void enableTracking(bool b) { fEnabled = b; } // Returns true if breackpoints are enabled. bool trackingEnabled() { return fEnabled; } // Puts the tracker in Any mode. void any() { fBreakOnAny = true; } // Puts the tracker in Any mode. void all() { fBreakOnAny = false; } // returns true in in All mode. False for Any mode. bool requireAllExpectedTouched() { return !fBreakOnAny; } // Returns the numbers of points in which if touched, would trigger a breackpoint. int cntExpectedTouched() { return fCntExpectedTouched; } // Returns the points which if touched, would trigger a breackpoint. // the Tracker owns the array const SkIPoint* expectedTouched() { return fExpectedTouched; } // Returns the numbers of points in which if touched, would disable a breackpoint. int cntExpectedUntouched() { return fCntExpectedUntouched; } // Returns the points which if touched, would disable a breackpoint. // the Tracker owns the array const SkIPoint* expectedUntouched() { return fExpectedUntouched; } // Adds a point which if changes in a drawFoo operation, would trigger a breakpoint. bool addExpectTouch(int x, int y) { if (fCntExpectedTouched >= MAX_TRACKING_POINTS) { return false; } if (found(x, y)) { return false; } fExpectedTouched[fCntExpectedTouched] = SkIPoint::Make(x, y); fCntExpectedTouched++; return true; } // Adds a point which if changes in a drawFoo operation, would disable a breakpoint. bool addExpectUntouch(int x, int y) { if (fCntExpectedUntouched >= MAX_TRACKING_POINTS) { return false; } if (found(x, y)) { return false; } fExpectedUntouched[fCntExpectedUntouched] = SkIPoint::Make(x, y); fCntExpectedUntouched++; return true; } // Starts a new rendering session - reset the number of hits. void newFrame() { fHits = 0; } // returns the number of breackpoints issues in this rendering session. int hits() { return fHits; } // Called before drawFoo to store the state of the pixels void before(const SkBitmap& bitmap) { if (fCntExpectedTouched == 0) { return; } for (int i = 0 ; i < fCntExpectedTouched; i++) { fBeforeTouched[i] = pickColor(bitmap, fExpectedTouched[i].x(), fExpectedTouched[i].y()); } for (int i = 0 ; i < fCntExpectedUntouched; i++) { fBeforeUntouched[i] = pickColor(bitmap, fExpectedUntouched[i].x(), fExpectedUntouched[i].y()); } } // Called after drawFoo to evaluate what pixels have changed, it could issue a breakpoint. // any/all of the expected touched has to be changed, and all expected untouched must be intact void after(const SkBitmap& bitmap) { if (fCntExpectedTouched == 0) { return; } bool doBreak; if (fBreakOnAny) { doBreak = false; for (int i = 0 ; i < fCntExpectedTouched; i++) { doBreak = doBreak || fBeforeTouched[i] != pickColor(bitmap, fExpectedTouched[i].x(), fExpectedTouched[i].y()); } } else { doBreak = true; for (int i = 0 ; i < fCntExpectedTouched; i++) { doBreak = doBreak && fBeforeTouched[i] != pickColor(bitmap, fExpectedTouched[i].x(), fExpectedTouched[i].y()); } } for (int i = 0 ; i < fCntExpectedUntouched; i++) { doBreak = doBreak && fBeforeUntouched[i] == pickColor(bitmap, fExpectedUntouched[i].x(), fExpectedUntouched[i].y()); } if (doBreak) { fHits++; if (fEnabled) { breakExecution(); } } } private: inline SkColor pickColor(const SkBitmap& bitmap, int x, int y) { return bitmap.getColor(x, y); } void breakExecution() { printf("break;\n"); } inline bool found(int x, int y) { for (int i = 0 ; i < fCntExpectedTouched; i++) { if (x == fExpectedTouched[i].x() && y == fExpectedTouched[i].y()) { return true; } } for (int i = 0 ; i < fCntExpectedUntouched; i++) { if (x == fExpectedUntouched[i].x() && y == fExpectedUntouched[i].y()) { return true; } } return false; } bool fEnabled; // break on any change on expected touched or all. bool fBreakOnAny; SkIPoint fExpectedTouched[MAX_TRACKING_POINTS]; SkColor fBeforeTouched[MAX_TRACKING_POINTS]; int fCntExpectedTouched; SkIPoint fExpectedUntouched[MAX_TRACKING_POINTS]; SkColor fBeforeUntouched[MAX_TRACKING_POINTS]; int fCntExpectedUntouched; int fHits; }; #endif // SkTracker_DEFINED