Optimized hit testing feature, refactored into seperate function from canvas draw calls

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

git-svn-id: http://skia.googlecode.com/svn/trunk@4867 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
chudy@google.com 2012-07-31 19:55:32 +00:00
parent 622a17091b
commit 0b5bbb0f82
11 changed files with 74 additions and 231 deletions

View File

@ -33,9 +33,7 @@ SkCanvasWidget::SkCanvasWidget() : QWidget()
}
SkCanvasWidget::~SkCanvasWidget() {
if (fDebugCanvas) {
delete fDebugCanvas;
}
delete fDebugCanvas;
}
void SkCanvasWidget::drawTo(int index) {
@ -78,13 +76,8 @@ void SkCanvasWidget::mouseMoveEvent(QMouseEvent* event) {
void SkCanvasWidget::mousePressEvent(QMouseEvent* event) {
fPreviousPoint.set(event->globalX(), event->globalY());
if (fDebugCanvas) {
fDebugCanvas->getBoxClass()->setHitPoint(event->x(), event->y());
fDebugCanvas->isCalculatingHits(true);
drawTo(fIndex);
emit hitChanged(fDebugCanvas->getHitBoxPoint());
fDebugCanvas->isCalculatingHits(false);
}
emit hitChanged(fDebugCanvas->getLayerAtPoint(event->x(), event->y(),
fIndex, fTransform, fScaleFactor));
}
void SkCanvasWidget::mouseDoubleClickEvent(QMouseEvent* event) {

View File

@ -54,8 +54,7 @@ void SkGLWidget::paintGL() {
} else if (fScaleFactor > 0) {
canvas.scale(fScaleFactor, fScaleFactor);
}
// TODO(chudy): Remove bitmap arguement.
fDebugCanvas->drawTo(&canvas, fIndex+1, NULL);
fDebugCanvas->drawTo(&canvas, fIndex);
canvas.flush();
}

View File

@ -29,7 +29,7 @@ public:
void setDebugCanvas(SkDebugCanvas* debugCanvas) {
fDebugCanvas = debugCanvas;
fIndex = debugCanvas->getSize();
fIndex = debugCanvas->getSize() - 1;
this->updateGL();
}

View File

@ -28,12 +28,8 @@ SkRasterWidget::~SkRasterWidget() {
void SkRasterWidget::resizeEvent(QResizeEvent* event) {
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, event->size().width(), event->size().height());
fBitmap.allocPixels();
if (fDevice) {
delete fDevice;
}
fDevice = new SkDevice(fBitmap);
delete fDevice;
fDevice = new SkDevice(fBitmap);
this->update();
}
@ -50,7 +46,7 @@ void SkRasterWidget::paintEvent(QPaintEvent* event) {
fMatrix = canvas.getTotalMatrix();
fClip = canvas.getTotalClip().getBounds();
fDebugCanvas->drawTo(&canvas, fIndex+1, &fBitmap);
fDebugCanvas->drawTo(&canvas, fIndex);
QPainter painter(this);
QStyleOption opt;

View File

@ -31,7 +31,7 @@ public:
void setDebugCanvas(SkDebugCanvas* debugCanvas) {
fDebugCanvas = debugCanvas;
fIndex = debugCanvas->getSize();
fIndex = debugCanvas->getSize() - 1;
this->update();
}

View File

@ -29,47 +29,62 @@ void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
void SkDebugCanvas::draw(SkCanvas* canvas) {
if(!commandVector.empty()) {
for(it = commandVector.begin(); it != commandVector.end(); ++it) {
if ((*it)->getVisibility()) {
if ((*it)->isVisible()) {
(*it)->execute(canvas);
}
}
}
}
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 ((*it)->getVisibility()) {
(*it)->execute(canvas);
}
} else {
if (fFilter) {
SkPaint* p = new SkPaint();
p->setColor(0xAAFFFFFF);
canvas->save();
canvas->resetMatrix();
SkRect dump;
// TODO(chudy): Replace with a call to QtWidget to get dimensions.
dump.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(fWidth), SkIntToScalar(fHeight));
canvas->clipRect(dump, SkRegion::kReplace_Op, false );
canvas->drawRectCoords(SkIntToScalar(0),SkIntToScalar(0),SkIntToScalar(fWidth),SkIntToScalar(fHeight), *p);
canvas->restore();
}
if ((*it)->getVisibility()) {
(*it)->execute(canvas);
}
}
if (fCalculateHits == true && bitmap != NULL) {
fHitBox.updateHitPoint(bitmap, counter);
}
int SkDebugCanvas::getCommandAtPoint(int x, int y, int index,
SkIPoint transform, float scale) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
bitmap.allocPixels();
/* TODO(chudy): Implement a bitmap wide function that will take
* ~50 out of each R,G,B. This will make everything but the last
* command brighter.
*/
if (++counter == index) return;
SkCanvas canvas(bitmap);
canvas.translate(transform.fX - x, transform.fY - y);
if (scale < 0) {
canvas.scale((1.0 / -scale), (1.0 / -scale));
} else if (scale > 0) {
canvas.scale(scale, scale);
}
int layer = 0;
int prev = bitmap.getColor(0,0);
for (int i = 0; i < index; i++) {
if (commandVector[i]->isVisible()) {
commandVector[i]->execute(&canvas);
}
if (prev != bitmap.getColor(0,0)) {
layer = i;
}
prev = bitmap.getColor(0,0);
}
return layer;
}
void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
int counter = 0;
SkASSERT(!commandVector.empty());
SkASSERT(index < commandVector.size());
for (int i = 0; i <= index; i++) {
if (i == index && fFilter) {
SkPaint p;
p.setColor(0xAAFFFFFF);
canvas->save();
canvas->resetMatrix();
SkRect mask;
mask.set(SkIntToScalar(0), SkIntToScalar(0),
SkIntToScalar(fWidth), SkIntToScalar(fHeight));
canvas->clipRect(mask, SkRegion::kReplace_Op, false);
canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
canvas->restore();
}
if (commandVector[i]->isVisible()) {
commandVector[i]->execute(canvas);
}
}
}
@ -86,7 +101,7 @@ std::vector<std::string>* SkDebugCanvas::getCommandInfoAt(int index) {
bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
SkASSERT(index < commandVector.size());
return commandVector[index]->getVisibility();
return commandVector[index]->isVisible();
}
std::vector<SkDrawCommand*> SkDebugCanvas::getDrawCommands() {
@ -252,5 +267,5 @@ bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
void SkDebugCanvas::toggleCommand(int index, bool toggle) {
SkASSERT(index < commandVector.size());
commandVector[index]->setVisibility(toggle);
commandVector[index]->setVisible(toggle);
}

View File

@ -13,7 +13,6 @@
#include "SkCanvas.h"
#include "SkDrawCommand.h"
#include "SkPicture.h"
#include "SkHitBox.h"
#include <vector>
class SkDebugCanvas : public SkCanvas {
@ -43,7 +42,13 @@ public:
@param canvas The canvas being drawn to
@param index The index of the final command being executed
*/
void drawTo(SkCanvas* canvas, int index, SkBitmap* bitmap);
void drawTo(SkCanvas* canvas, int index);
/**
Returns the index of the last draw command to write to the pixel at (x,y)
*/
int getCommandAtPoint(int x, int y, int index,
SkIPoint transform, float scale);
/**
Returns the draw command at the given index.
@ -73,21 +78,6 @@ public:
*/
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.
*/
@ -95,10 +85,6 @@ public:
return commandVector.size();
}
void isCalculatingHits(bool isEnabled) {
fCalculateHits = isEnabled;
}
/**
Toggles the visibility / execution of the draw command at index i with
the value of toggle.
@ -194,8 +180,6 @@ private:
int fHeight;
int fWidth;
SkBitmap fBm;
SkHitBox fHitBox;
bool fCalculateHits;
bool fFilter;
/**

View File

@ -28,8 +28,13 @@ public:
return GetCommandString(fDrawType);
}
bool getVisibility() const { return fVisible; }
void setVisibility(bool toggle) {fVisible = toggle; }
bool isVisible() const {
return fVisible;
}
void setVisible(bool toggle) {
fVisible = toggle;
}
std::vector<std::string>* Info() {return &fInfo; };
virtual void execute(SkCanvas* canvas)=0;

View File

@ -1,66 +0,0 @@
/*
* 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);
}

View File

@ -1,81 +0,0 @@
/*
* 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_ */

View File

@ -32,8 +32,6 @@
'../debugger/SkObjectParser.cpp',
'../debugger/QT/SkSettingsWidget.h',
'../debugger/QT/SkSettingsWidget.cpp',
'../debugger/SkHitBox.h',
'../debugger/SkHitBox.cpp',
'../debugger/QT/SkGLWidget.h',
'../debugger/QT/SkGLWidget.cpp',
'../debugger/QT/SkRasterWidget.h',