SkHitBox added.

SkHitBox is a class that determines which draw command is associated with the pixel located at x,y. By calculating a single point instead of the entire bitmap at once there is no visible performance slowdown.

Review URL: https://codereview.appspot.com/6350098

git-svn-id: http://skia.googlecode.com/svn/trunk@4565 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/debugger/QT/SkCanvasWidget.cpp b/debugger/QT/SkCanvasWidget.cpp
index 39fb1f5..8c660a4 100644
--- a/debugger/QT/SkCanvasWidget.cpp
+++ b/debugger/QT/SkCanvasWidget.cpp
@@ -11,7 +11,6 @@
 #include "SkStream.h"
 #include "SkCanvasWidget.h"
 #include "SkColor.h"
-#include <iostream>
 
 SkCanvasWidget::SkCanvasWidget(QWidget *parent) :
     QWidget(parent) {
@@ -56,7 +55,7 @@
     fDevice = new SkDevice(fBitmap);
     fCanvas = new SkCanvas(fDevice);
     fDebugCanvas->setBounds(event->size().width(), event->size().height());
-    fDebugCanvas->drawTo(fCanvas, fIndex);
+    fDebugCanvas->drawTo(fCanvas, fIndex+1, &fBitmap);
     this->update();
 }
 
@@ -72,7 +71,7 @@
     }
 
     emit commandChanged(fIndex);
-    fDebugCanvas->drawTo(fCanvas, fIndex+1);
+    fDebugCanvas->drawTo(fCanvas, fIndex+1, &fBitmap);
     this->update();
     this->fIndex = fIndex;
 }
@@ -128,6 +127,11 @@
 
 void SkCanvasWidget::mousePressEvent(QMouseEvent* event) {
     fPreviousPoint.set(event->globalX(), event->globalY());
+    fDebugCanvas->getBoxClass()->setHitPoint(event->x(), event->y());
+    fDebugCanvas->isCalculatingHits(true);
+    drawTo(fIndex);
+    emit hitChanged(fDebugCanvas->getHitBoxPoint());
+    fDebugCanvas->isCalculatingHits(false);
 }
 
 void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) {
diff --git a/debugger/QT/SkCanvasWidget.h b/debugger/QT/SkCanvasWidget.h
index 3f18749..65fa2ba 100644
--- a/debugger/QT/SkCanvasWidget.h
+++ b/debugger/QT/SkCanvasWidget.h
@@ -132,6 +132,7 @@
 signals:
     void scaleFactorChanged(float newScaleFactor);
     void commandChanged(int newCommand);
+    void hitChanged(int hit);
 
 protected:
     /**
diff --git a/debugger/QT/SkDebuggerGUI.cpp b/debugger/QT/SkDebuggerGUI.cpp
index 96e1551..12c3bdc 100644
--- a/debugger/QT/SkDebuggerGUI.cpp
+++ b/debugger/QT/SkDebuggerGUI.cpp
@@ -71,10 +71,12 @@
             SLOT(actionCommandFilter()));
     connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this,
             SLOT(actionScale(float)));
-    connect(fSettingsWidget.getCommandCheckBox(), SIGNAL(stateChanged(int)),
+    connect(fSettingsWidget.getCommandCheckBox(), SIGNAL(toggled(bool)),
             this, SLOT(pauseDrawing(bool)));
     connect(&fCanvasWidget, SIGNAL(commandChanged(int)), &fSettingsWidget,
             SLOT(updateCommand(int)));
+    connect(&fCanvasWidget, SIGNAL(hitChanged(int)), &fSettingsWidget,
+            SLOT(updateHit(int)));
 }
 
 SkDebuggerGUI::~SkDebuggerGUI() {
@@ -478,6 +480,7 @@
             fSettingsWidget.getVisibilityButton()->isChecked());
     setupListWidget(cv);
     setupComboBox(cv);
+    fSettingsWidget.setDisabled(false);
 }
 
 void SkDebuggerGUI::setupListWidget(std::vector<std::string>* cv) {
diff --git a/debugger/QT/SkSettingsWidget.cpp b/debugger/QT/SkSettingsWidget.cpp
index 117e7bf..5b5236a 100644
--- a/debugger/QT/SkSettingsWidget.cpp
+++ b/debugger/QT/SkSettingsWidget.cpp
@@ -19,6 +19,7 @@
     , fVisibleOff(&fVisibleFrame)
     , fCommandLayout(&fCommandFrame)
     , fCurrentCommandBox(&fCommandFrame)
+    , fCommandHitBox(&fCommandFrame)
     , fCommandCheckBox(&fCommandFrame)
     , fZoomBox(&fZoomFrame)
     , fZoomLayout(&fZoomFrame)
@@ -65,10 +66,24 @@
     fCurrentCommandLayout.addWidget(&fCurrentCommandLabel);
     fCurrentCommandLayout.addWidget(&fCurrentCommandBox);
 
+    fCommandHitLabel.setText("Command HitBox: ");
+    fCommandHitLabel.setMinimumWidth(178);
+    fCommandHitLabel.setMaximumWidth(178);
+    fCommandHitBox.setText("0");
+    fCommandHitBox.setMinimumSize(QSize(50,25));
+    fCommandHitBox.setMaximumSize(QSize(50,25));
+    fCommandHitBox.setAlignment(Qt::AlignRight);
+    fCommandHitLayout.setSpacing(0);
+    fCommandHitLayout.setContentsMargins(0,0,0,0);
+    fCommandHitLayout.setAlignment(Qt::AlignLeft);
+    fCommandHitLayout.addWidget(&fCommandHitLabel);
+    fCommandHitLayout.addWidget(&fCommandHitBox);
+
     fCommandCheckBox.setText("Pause");
     fCommandLayout.setSpacing(6);
     fCommandLayout.setContentsMargins(11,11,11,11);
     fCommandLayout.addLayout(&fCurrentCommandLayout);
+    fCommandLayout.addLayout(&fCommandHitLayout);
     fCommandLayout.addWidget(&fCommandCheckBox);
 
     // Zoom Info
@@ -93,7 +108,7 @@
     fVerticalLayout.addWidget(&fCommandFrame);
     fVerticalLayout.addWidget(&fZoomFrame);
 
-    //this->setDisabled(true);
+    this->setDisabled(true);
 }
 
 SkSettingsWidget::~SkSettingsWidget() {}
@@ -103,6 +118,10 @@
     fCurrentCommandBox.setText(QString::number(newCommand));
 }
 
+void SkSettingsWidget::updateHit(int newHit) {
+    fCommandHitBox.setText(QString::number(newHit));
+}
+
 QCheckBox* SkSettingsWidget::getCommandCheckBox() {
     return &fCommandCheckBox;
 }
diff --git a/debugger/QT/SkSettingsWidget.h b/debugger/QT/SkSettingsWidget.h
index da7326b..839a331 100644
--- a/debugger/QT/SkSettingsWidget.h
+++ b/debugger/QT/SkSettingsWidget.h
@@ -43,6 +43,7 @@
 
 private slots:
     void updateCommand(int newCommand);
+    void updateHit(int newHit);
 
 signals:
     void scrollingPreferences(bool isStickyActivate);
@@ -64,10 +65,14 @@
     QFrame fCommandFrame;
     QVBoxLayout fCommandLayout;
 
-    QLineEdit fCurrentCommandBox;
     QLabel fCurrentCommandLabel;
+    QLineEdit fCurrentCommandBox;
     QHBoxLayout fCurrentCommandLayout;
 
+    QLabel fCommandHitLabel;
+    QLineEdit fCommandHitBox;
+    QHBoxLayout fCommandHitLayout;
+
     QCheckBox fCommandCheckBox;
 
     QLabel fZoomSetting;
diff --git a/debugger/QT/moc_SkCanvasWidget.cpp b/debugger/QT/moc_SkCanvasWidget.cpp
index 0187620..098b3bb 100644
--- a/debugger/QT/moc_SkCanvasWidget.cpp
+++ b/debugger/QT/moc_SkCanvasWidget.cpp
@@ -1,7 +1,7 @@
 /****************************************************************************
 ** Meta object code from reading C++ file 'SkCanvasWidget.h'
 **
-** Created: Mon Jul 9 13:45:07 2012
+** Created: Wed Jul 11 15:15:07 2012
 **      by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
 **
 ** WARNING! All changes made in this file will be lost!
@@ -23,16 +23,17 @@
        4,       // revision
        0,       // classname
        0,    0, // classinfo
-       2,   14, // methods
+       3,   14, // methods
        0,    0, // properties
        0,    0, // enums/sets
        0,    0, // constructors
        0,       // flags
-       2,       // signalCount
+       3,       // signalCount
 
  // signals: signature, parameters, type, tag, flags
       31,   16,   15,   15, 0x05,
       68,   57,   15,   15, 0x05,
+      92,   88,   15,   15, 0x05,
 
        0        // eod
 };
@@ -40,7 +41,7 @@
 static const char qt_meta_stringdata_SkCanvasWidget[] = {
     "SkCanvasWidget\0\0newScaleFactor\0"
     "scaleFactorChanged(float)\0newCommand\0"
-    "commandChanged(int)\0"
+    "commandChanged(int)\0hit\0hitChanged(int)\0"
 };
 
 const QMetaObject SkCanvasWidget::staticMetaObject = {
@@ -74,9 +75,10 @@
         switch (_id) {
         case 0: scaleFactorChanged((*reinterpret_cast< float(*)>(_a[1]))); break;
         case 1: commandChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
+        case 2: hitChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
         default: ;
         }
-        _id -= 2;
+        _id -= 3;
     }
     return _id;
 }
@@ -94,4 +96,11 @@
     void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
     QMetaObject::activate(this, &staticMetaObject, 1, _a);
 }
+
+// SIGNAL 2
+void SkCanvasWidget::hitChanged(int _t1)
+{
+    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
+    QMetaObject::activate(this, &staticMetaObject, 2, _a);
+}
 QT_END_MOC_NAMESPACE
diff --git a/debugger/QT/moc_SkSettingsWidget.cpp b/debugger/QT/moc_SkSettingsWidget.cpp
index 336b1ef..d2822ce 100644
--- a/debugger/QT/moc_SkSettingsWidget.cpp
+++ b/debugger/QT/moc_SkSettingsWidget.cpp
@@ -1,7 +1,7 @@
 /****************************************************************************
 ** Meta object code from reading C++ file 'SkSettingsWidget.h'
 **
-** Created: Mon Jul 9 13:45:07 2012
+** Created: Wed Jul 11 15:20:23 2012
 **      by: The Qt Meta Object Compiler version 62 (Qt 4.6.2)
 **
 ** WARNING! All changes made in this file will be lost!
@@ -23,7 +23,7 @@
        4,       // revision
        0,       // classname
        0,    0, // classinfo
-       4,   14, // methods
+       5,   14, // methods
        0,    0, // properties
        0,    0, // enums/sets
        0,    0, // constructors
@@ -37,6 +37,7 @@
 
  // slots: signature, parameters, type, tag, flags
      138,  127,   17,   17, 0x08,
+     164,  157,   17,   17, 0x08,
 
        0        // eod
 };
@@ -46,7 +47,7 @@
     "scrollingPreferences(bool)\0isSingleCommand\0"
     "showStyle(bool)\0isEnabled\0"
     "visibilityFilter(bool)\0newCommand\0"
-    "updateCommand(int)\0"
+    "updateCommand(int)\0newHit\0updateHit(int)\0"
 };
 
 const QMetaObject SkSettingsWidget::staticMetaObject = {
@@ -82,9 +83,10 @@
         case 1: showStyle((*reinterpret_cast< bool(*)>(_a[1]))); break;
         case 2: visibilityFilter((*reinterpret_cast< bool(*)>(_a[1]))); break;
         case 3: updateCommand((*reinterpret_cast< int(*)>(_a[1]))); break;
+        case 4: updateHit((*reinterpret_cast< int(*)>(_a[1]))); break;
         default: ;
         }
-        _id -= 4;
+        _id -= 5;
     }
     return _id;
 }
diff --git a/debugger/SkDebugCanvas.cpp b/debugger/SkDebugCanvas.cpp
index c1039f1..8586878 100644
--- a/debugger/SkDebugCanvas.cpp
+++ b/debugger/SkDebugCanvas.cpp
@@ -34,12 +34,11 @@
     }
 }
 
-
-void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
+void SkDebugCanvas::drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap) {
     int counter = 0;
     if(!commandVector.empty()) {
         for(it = commandVector.begin(); it != commandVector.end(); ++it) {
-             if (counter != (index-1)) {
+            if (counter != (index-1)) {
                  if ((*it)->getVisibility()) {
                      (*it)->execute(canvas);
                  }
@@ -56,11 +55,13 @@
                      canvas->drawRectCoords(SkIntToScalar(0),SkIntToScalar(0),SkIntToScalar(fWidth),SkIntToScalar(fHeight), *p);
                      canvas->restore();
                  }
-
                  if ((*it)->getVisibility()) {
                      (*it)->execute(canvas);
                  }
              }
+            if (fCalculateHits == true) {
+                fHitBox.updateHitPoint(bitmap, counter);
+            }
 
             /* TODO(chudy): Implement a bitmap wide function that will take
              *  ~50 out of each R,G,B. This will make everything but the last
diff --git a/debugger/SkDebugCanvas.h b/debugger/SkDebugCanvas.h
index 6375681..e6dd56a 100644
--- a/debugger/SkDebugCanvas.h
+++ b/debugger/SkDebugCanvas.h
@@ -14,6 +14,7 @@
 #include "SkCanvas.h"
 #include "SkDrawCommand.h"
 #include "SkPicture.h"
+#include "SkHitBox.h"
 #include <vector>
 
 class SkDebugCanvas : public SkCanvas {
@@ -45,7 +46,7 @@
         @param canvas  The canvas being drawn to
         @param index  The index of the final command being executed
      */
-    void drawTo(SkCanvas* canvas, int index);
+    void drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap);
 
     /**
         Returns the draw command at the given index.
@@ -70,12 +71,30 @@
     std::vector<std::string>* getDrawCommandsAsStrings();
 
     /**
+        Returns the mapping of all pixels to a layer value.
+     */
+    int* getHitBox() {
+        return fHitBox.getHitBox();
+    }
+
+    SkHitBox* getBoxClass() {
+        return &fHitBox;
+    }
+
+    int getHitBoxPoint() {
+        return fHitBox.getPoint();
+    }
+
+    /**
         Returns length of draw command vector.
      */
     int getSize() {
         return commandVector.size();
     }
 
+    void isCalculatingHits(bool isEnabled) {
+        fCalculateHits = isEnabled;
+    }
     /**
         Toggles the execution of the draw command at index i.
      */
@@ -176,6 +195,8 @@
     int fHeight;
     int fWidth;
     SkBitmap fBm;
+    SkHitBox fHitBox;
+    bool fCalculateHits;
 
     /**
         Adds the command to the classes vector of commands.
diff --git a/debugger/SkHitBox.cpp b/debugger/SkHitBox.cpp
new file mode 100644
index 0000000..a65fcc4
--- /dev/null
+++ b/debugger/SkHitBox.cpp
@@ -0,0 +1,66 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkHitBox.h"
+
+SkHitBox::SkHitBox() {
+    fHitBox = NULL;
+    fX = -1;
+    fY = -1;
+    fLayer = -1;
+}
+
+SkHitBox::~SkHitBox() {}
+
+void SkHitBox::alloc(int width, int height) {
+    free(fHitBox);
+    int length = width * height;
+    fHitBox = (int*) malloc(length * sizeof(int));
+    for (int i = 0; i < length; i++) {
+        fHitBox[i] = 0;
+    }
+}
+
+void SkHitBox::updateHitBox(SkBitmap* newBitmap, int layer) {
+        int length = fPrev.width() * fPrev.height();
+        int* prevBase = (int*)fPrev.getPixels();
+        int* currBase = (int*)newBitmap->getPixels();
+
+        for (int i = 0; i < length; i++) {
+            if (SkUnPreMultiply::PMColorToColor(prevBase[i]) !=
+                    SkUnPreMultiply::PMColorToColor(currBase[i])) {
+                fHitBox[i] = layer;
+            }
+        }
+        if (fPrev.empty()) {
+            alloc(newBitmap->width(), newBitmap->height());
+            fPrev.setConfig(SkBitmap::kARGB_8888_Config, newBitmap->width(), newBitmap->height());
+            fPrev.allocPixels();
+        }
+        newBitmap->deepCopyTo(&fPrev, SkBitmap::kARGB_8888_Config);
+}
+
+void SkHitBox::updateHitPoint(SkBitmap* newBitmap, int layer) {
+    int* prevBase = (int*)fPrev.getPixels();
+    int* currBase = (int*)newBitmap->getPixels();
+    int pixel = fY * fPrev.width() + fX;
+
+    if (pointIsSet() && !fPrev.empty()) {
+        if (SkUnPreMultiply::PMColorToColor(prevBase[pixel]) !=
+                SkUnPreMultiply::PMColorToColor(currBase[pixel])) {
+            fLayer = layer;
+        }
+    }
+    if (fPrev.empty()) {
+        alloc(newBitmap->width(), newBitmap->height());
+        fPrev.setConfig(SkBitmap::kARGB_8888_Config, newBitmap->width(), newBitmap->height());
+        fPrev.allocPixels();
+    }
+    newBitmap->deepCopyTo(&fPrev, SkBitmap::kARGB_8888_Config);
+}
diff --git a/debugger/SkHitBox.h b/debugger/SkHitBox.h
new file mode 100644
index 0000000..19a65fd
--- /dev/null
+++ b/debugger/SkHitBox.h
@@ -0,0 +1,81 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SKHITBOX_H_
+#define SKHITBOX_H_
+
+#include "SkBitmap.h"
+#include "SkUnPreMultiply.h"
+
+/* NOTE(chudy): It's possible that this class can be entirely static similar to
+ * SkObjectParser. We will have to pass in the fHitBox void * every call.
+ */
+class SkHitBox {
+public:
+    SkHitBox();
+    ~SkHitBox();
+
+    /**
+        Allocates enough space in memory for our hitbox pointer to contain
+        a layer value for every pixel. Initializes every value to 0.
+     */
+    void alloc(int width, int height);
+
+    /**
+        Compares the new SkBitmap compared to the SkBitmap from the last
+        call. Updates our hitbox with the draw command number if different.
+     */
+    void updateHitBox(SkBitmap* newBitmap, int layer);
+
+    /**
+        Compares point x,y in the new bitmap compared to the saved previous
+        one. Updates hitpoint with the draw command number if different.
+     */
+    void updateHitPoint(SkBitmap* newBitmap, int layer);
+
+    /**
+        Sets the target hitpoint we are attempting to find the layer of.
+     */
+    void setHitPoint(int x, int y) {
+        fX = x;
+        fY = y;
+        fLayer = 0;
+    }
+
+    /**
+        Returns a pointer to the start of the hitbox.
+     */
+    int* getHitBox() {
+        return fHitBox;
+    }
+
+    /**
+        Returns the layer numbr corresponding to the point (fX, fY) in this class.
+     */
+    int getPoint() {
+        return fLayer;
+    }
+
+    /**
+        Checks to see if a mouse click has been passed in.
+     */
+    bool pointIsSet() {
+        return !(fX == -1 && fY == -1);
+    }
+
+private:
+    SkBitmap fPrev;
+    int* fHitBox;
+    int fX;
+    int fY;
+    int fLayer;
+};
+
+
+#endif /* SKHITBOX_H_ */