Convert BBH APIs to use SkRect.

Still TODO: convert internals of SkTileGrid.cpp and SkRTree.cpp to work in floats too.

NOTREECHECKS=true

BUG=skia:1021
R=robertphillips@google.com, reed@google.com, mtklein@google.com

Author: mtklein@chromium.org

Review URL: https://codereview.chromium.org/511613002
This commit is contained in:
mtklein 2014-08-27 10:39:42 -07:00 committed by Commit bot
parent 3031350e05
commit 533eb782ed
20 changed files with 207 additions and 196 deletions

View File

@ -13,12 +13,12 @@
#include "SkString.h" #include "SkString.h"
// confine rectangles to a smallish area, so queries generally hit something, and overlap occurs: // confine rectangles to a smallish area, so queries generally hit something, and overlap occurs:
static const int GENERATE_EXTENTS = 1000; static const SkScalar GENERATE_EXTENTS = 1000.0f;
static const int NUM_BUILD_RECTS = 500; static const int NUM_BUILD_RECTS = 500;
static const int NUM_QUERY_RECTS = 5000; static const int NUM_QUERY_RECTS = 5000;
static const int GRID_WIDTH = 100; static const int GRID_WIDTH = 100;
typedef SkIRect (*MakeRectProc)(SkRandom&, int, int); typedef SkRect (*MakeRectProc)(SkRandom&, int, int);
// Time how long it takes to build an R-Tree either bulk-loaded or not // Time how long it takes to build an R-Tree either bulk-loaded or not
class RTreeBuildBench : public Benchmark { class RTreeBuildBench : public Benchmark {
@ -115,32 +115,32 @@ protected:
SkRandom rand; SkRandom rand;
for (int i = 0; i < loops; ++i) { for (int i = 0; i < loops; ++i) {
SkTDArray<void*> hits; SkTDArray<void*> hits;
SkIRect query; SkRect query;
switch(fQuery) { switch(fQuery) {
case kSmall_QueryType: case kSmall_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS; query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextU() % GENERATE_EXTENTS; query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + (GENERATE_EXTENTS / 20); query.fRight = query.fLeft + (GENERATE_EXTENTS / 20);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 20); query.fBottom = query.fTop + (GENERATE_EXTENTS / 20);
break; break;
case kLarge_QueryType: case kLarge_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS; query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextU() % GENERATE_EXTENTS; query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + (GENERATE_EXTENTS / 2); query.fRight = query.fLeft + (GENERATE_EXTENTS / 2);
query.fBottom = query.fTop + (GENERATE_EXTENTS / 2); query.fBottom = query.fTop + (GENERATE_EXTENTS / 2);
break; break;
case kFull_QueryType: case kFull_QueryType:
query.fLeft = -GENERATE_EXTENTS; query.fLeft = -GENERATE_EXTENTS;
query.fTop = -GENERATE_EXTENTS; query.fTop = -GENERATE_EXTENTS;
query.fRight = 2 * GENERATE_EXTENTS; query.fRight = 2 * GENERATE_EXTENTS;
query.fBottom = 2 * GENERATE_EXTENTS; query.fBottom = 2 * GENERATE_EXTENTS;
break; break;
default: // fallthrough default: // fallthrough
case kRandom_QueryType: case kRandom_QueryType:
query.fLeft = rand.nextU() % GENERATE_EXTENTS; query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fTop = rand.nextU() % GENERATE_EXTENTS; query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
query.fRight = query.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); query.fRight = query.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
query.fBottom = query.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 2); query.fBottom = query.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
break; break;
}; };
fTree->search(query, &hits); fTree->search(query, &hits);
@ -155,34 +155,34 @@ private:
typedef Benchmark INHERITED; typedef Benchmark INHERITED;
}; };
static inline SkIRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) { static inline SkRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) {
SkIRect out = {0, 0, index + 1, index + 1}; SkRect out = SkRect::MakeWH(SkIntToScalar(index+1), SkIntToScalar(index+1));
return out; return out;
} }
static inline SkIRect make_XYordered_rects(SkRandom& rand, int index, int numRects) { static inline SkRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
SkIRect out; SkRect out;
out.fLeft = index % GRID_WIDTH; out.fLeft = SkIntToScalar(index % GRID_WIDTH);
out.fTop = index / GRID_WIDTH; out.fTop = SkIntToScalar(index / GRID_WIDTH);
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
return out; return out;
} }
static inline SkIRect make_YXordered_rects(SkRandom& rand, int index, int numRects) { static inline SkRect make_YXordered_rects(SkRandom& rand, int index, int numRects) {
SkIRect out; SkRect out;
out.fLeft = index / GRID_WIDTH; out.fLeft = SkIntToScalar(index / GRID_WIDTH);
out.fTop = index % GRID_WIDTH; out.fTop = SkIntToScalar(index % GRID_WIDTH);
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
return out; return out;
} }
static inline SkIRect make_random_rects(SkRandom& rand, int index, int numRects) { static inline SkRect make_random_rects(SkRandom& rand, int index, int numRects) {
SkIRect out; SkRect out;
out.fLeft = rand.nextS() % GENERATE_EXTENTS; out.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS);
out.fTop = rand.nextS() % GENERATE_EXTENTS; out.fTop = rand.nextRangeF(0, GENERATE_EXTENTS);
out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 5); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
return out; return out;
} }

View File

@ -288,7 +288,7 @@ private:
/** PRIVATE / EXPERIMENTAL -- do not call /** PRIVATE / EXPERIMENTAL -- do not call
Return the operations required to render the content inside 'queryRect'. Return the operations required to render the content inside 'queryRect'.
*/ */
const OperationList* EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const; const OperationList* EXPERIMENTAL_getActiveOps(const SkRect& queryRect) const;
void createHeader(SkPictInfo* info) const; void createHeader(SkPictInfo* info) const;
static bool IsValidPictInfo(const SkPictInfo& info); static bool IsValidPictInfo(const SkPictInfo& info);

View File

@ -144,7 +144,7 @@ protected:
static bool FindLayersToHoist(const GrAccelData *gpuData, static bool FindLayersToHoist(const GrAccelData *gpuData,
const SkPicture::OperationList* ops, const SkPicture::OperationList* ops,
const SkIRect& query, const SkRect& query,
bool* pullForward); bool* pullForward);
void drawLayers(const SkPicture* picture, void drawLayers(const SkPicture* picture,
const SkTDArray<GrCachedLayer*>& atlased, const SkTDArray<GrCachedLayer*>& atlased,

View File

@ -49,7 +49,7 @@ public:
* structures than repeated inserts) until flushDeferredInserts is called or the first * structures than repeated inserts) until flushDeferredInserts is called or the first
* search. * search.
*/ */
virtual void insert(void* data, const SkIRect& bounds, bool defer = false) = 0; virtual void insert(void* data, const SkRect& bounds, bool defer = false) = 0;
/** /**
* If any insertions have been deferred, this forces them to be inserted * If any insertions have been deferred, this forces them to be inserted
@ -59,7 +59,7 @@ public:
/** /**
* Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query' * Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query'
*/ */
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const = 0; virtual void search(const SkRect& query, SkTDArray<void*>* results) const = 0;
virtual void clear() = 0; virtual void clear() = 0;

View File

@ -20,10 +20,8 @@ SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size,
} }
void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) { void SkBBoxHierarchyRecord::handleBBox(const SkRect& bounds) {
SkIRect r;
bounds.roundOut(&r);
SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten()); SkPictureStateTree::Draw* draw = fStateTree->appendDraw(this->writeStream().bytesWritten());
fBoundingHierarchy->insert(draw, r, true); fBoundingHierarchy->insert(draw, bounds, true);
} }
void SkBBoxHierarchyRecord::willSave() { void SkBBoxHierarchyRecord::willSave() {

View File

@ -335,7 +335,7 @@ const SkMatrix& SkPicture::OperationList::matrix(int index) const {
} }
// fRecord TODO(robert) / kind of OK in a non-optimal sense // fRecord TODO(robert) / kind of OK in a non-optimal sense
const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) const { const SkPicture::OperationList* SkPicture::EXPERIMENTAL_getActiveOps(const SkRect& queryRect) const {
SkASSERT(NULL != fData.get()); SkASSERT(NULL != fData.get());
if (NULL != fData.get()) { if (NULL != fData.get()) {
return fData->getActiveOps(queryRect); return fData->getActiveOps(queryRect);

View File

@ -635,7 +635,7 @@ bool SkPictureData::parseBuffer(SkReadBuffer& buffer) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
const SkPicture::OperationList* SkPictureData::getActiveOps(const SkIRect& query) const { const SkPicture::OperationList* SkPictureData::getActiveOps(const SkRect& query) const {
if (NULL == fStateTree || NULL == fBoundingHierarchy) { if (NULL == fStateTree || NULL == fBoundingHierarchy) {
return NULL; return NULL;
} }

View File

@ -84,7 +84,7 @@ public:
virtual ~SkPictureData(); virtual ~SkPictureData();
const SkPicture::OperationList* getActiveOps(const SkIRect& queryRect) const; const SkPicture::OperationList* getActiveOps(const SkRect& queryRect) const;
void serialize(SkWStream*, SkPicture::EncodeBitmap) const; void serialize(SkWStream*, SkPicture::EncodeBitmap) const;
void flatten(SkWriteBuffer&) const; void flatten(SkWriteBuffer&) const;

View File

@ -71,18 +71,15 @@ const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas*
if (fUseBBH) { if (fUseBBH) {
SkRect clipBounds; SkRect clipBounds;
if (canvas->getClipBounds(&clipBounds)) { if (canvas->getClipBounds(&clipBounds)) {
SkIRect query; return fPictureData->getActiveOps(clipBounds);
clipBounds.roundOut(&query);
return fPictureData->getActiveOps(query);
} }
} }
return NULL; return NULL;
} }
// Initialize the state tree iterator. Return false if there is nothing left to draw. // Initialize the state tree iterator. Return false if there is nothing left to draw.
bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter, bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter,
SkCanvas* canvas, SkCanvas* canvas,
const SkPicture::OperationList *activeOpsList) { const SkPicture::OperationList *activeOpsList) {
@ -172,9 +169,9 @@ void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback)
} }
} }
void SkPicturePlayback::handleOp(SkReader32* reader, void SkPicturePlayback::handleOp(SkReader32* reader,
DrawType op, DrawType op,
uint32_t size, uint32_t size,
SkCanvas* canvas, SkCanvas* canvas,
const SkMatrix& initialMatrix) { const SkMatrix& initialMatrix) {
switch (op) { switch (op) {
@ -310,7 +307,7 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
break; break;
case DRAW_PATCH: { case DRAW_PATCH: {
const SkPaint& paint = *fPictureData->getPaint(reader); const SkPaint& paint = *fPictureData->getPaint(reader);
const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts * const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts *
sizeof(SkPoint)); sizeof(SkPoint));
uint32_t flag = reader->readInt(); uint32_t flag = reader->readInt();

View File

@ -44,7 +44,14 @@ SkRTree::~SkRTree() {
this->clear(); this->clear();
} }
void SkRTree::insert(void* data, const SkIRect& bounds, bool defer) { void SkRTree::insert(void* data, const SkRect& fbounds, bool defer) {
SkIRect bounds;
if (fbounds.isLargest()) {
bounds.setLargest();
} else {
fbounds.roundOut(&bounds);
}
this->validate(); this->validate();
if (bounds.isEmpty()) { if (bounds.isEmpty()) {
SkASSERT(false); SkASSERT(false);
@ -102,7 +109,9 @@ void SkRTree::flushDeferredInserts() {
this->validate(); this->validate();
} }
void SkRTree::search(const SkIRect& query, SkTDArray<void*>* results) const { void SkRTree::search(const SkRect& fquery, SkTDArray<void*>* results) const {
SkIRect query;
fquery.roundOut(&query);
this->validate(); this->validate();
SkASSERT(0 == fDeferredInserts.count()); // If this fails, you should have flushed. SkASSERT(0 == fDeferredInserts.count()); // If this fails, you should have flushed.
if (!this->isEmpty() && SkIRect::IntersectsNoEmptyCheck(fRoot.fBounds, query)) { if (!this->isEmpty() && SkIRect::IntersectsNoEmptyCheck(fRoot.fBounds, query)) {

View File

@ -67,7 +67,7 @@ public:
* @param bounds The corresponding bounding box * @param bounds The corresponding bounding box
* @param defer Can this insert be deferred? (this may be ignored) * @param defer Can this insert be deferred? (this may be ignored)
*/ */
virtual void insert(void* data, const SkIRect& bounds, bool defer = false) SK_OVERRIDE; virtual void insert(void* data, const SkRect& bounds, bool defer = false) SK_OVERRIDE;
/** /**
* If any inserts have been deferred, this will add them into the tree * If any inserts have been deferred, this will add them into the tree
@ -77,7 +77,7 @@ public:
/** /**
* Given a query rectangle, populates the passed-in array with the elements it intersects * Given a query rectangle, populates the passed-in array with the elements it intersects
*/ */
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE; virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void clear() SK_OVERRIDE; virtual void clear() SK_OVERRIDE;
bool isEmpty() const { return 0 == fCount; } bool isEmpty() const { return 0 == fCount; }

View File

@ -16,15 +16,12 @@ void SkRecordDraw(const SkRecord& record,
if (NULL != bbh) { if (NULL != bbh) {
// Draw only ops that affect pixels in the canvas's current clip. // Draw only ops that affect pixels in the canvas's current clip.
SkIRect query;
// The SkRecord and BBH were recorded in identity space. This canvas // The SkRecord and BBH were recorded in identity space. This canvas
// is not necessarily in that same space. getClipBounds() returns us // is not necessarily in that same space. getClipBounds() returns us
// this canvas' clip bounds transformed back into identity space, which // this canvas' clip bounds transformed back into identity space, which
// lets us query the BBH. // lets us query the BBH.
SkRect clipBounds = { 0, 0, 0, 0 }; SkRect query = { 0, 0, 0, 0 };
(void)canvas->getClipBounds(&clipBounds); (void)canvas->getClipBounds(&query);
clipBounds.roundOut(&query);
SkTDArray<void*> ops; SkTDArray<void*> ops;
bbh->search(query, &ops); bbh->search(query, &ops);
@ -123,7 +120,7 @@ public:
FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) { FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) {
// Calculate bounds for all ops. This won't go quite in order, so we'll need // Calculate bounds for all ops. This won't go quite in order, so we'll need
// to store the bounds separately then feed them in to the BBH later in order. // to store the bounds separately then feed them in to the BBH later in order.
const SkIRect largest = SkIRect::MakeLargest(); const Bounds largest = Bounds::MakeLargest();
fCTM = &SkMatrix::I(); fCTM = &SkMatrix::I();
fCurrentClipBounds = largest; fCurrentClipBounds = largest;
for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) {
@ -158,9 +155,12 @@ public:
} }
private: private:
// In this file, SkRect are in local coordinates, Bounds are translated back to identity space.
typedef SkRect Bounds;
struct SaveBounds { struct SaveBounds {
int controlOps; // Number of control ops in this Save block, including the Save. int controlOps; // Number of control ops in this Save block, including the Save.
SkIRect bounds; // Bounds of everything in the block. Bounds bounds; // Bounds of everything in the block.
const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block. const SkPaint* paint; // Unowned. If set, adjusts the bounds of all ops in this block.
}; };
@ -171,11 +171,11 @@ private:
template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ } template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
// Each of these devBounds fields is the state of the device bounds after the op. // Each of these devBounds fields is the state of the device bounds after the op.
// So Restore's devBounds are those bounds saved by its paired Save or SaveLayer. // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
void updateClipBounds(const Restore& op) { fCurrentClipBounds = op.devBounds; } void updateClipBounds(const Restore& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = op.devBounds; } void updateClipBounds(const ClipPath& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = op.devBounds; } void updateClipBounds(const ClipRRect& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = op.devBounds; } void updateClipBounds(const ClipRect& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBounds; } void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = Bounds::Make(op.devBounds); }
void updateClipBounds(const SaveLayer& op) { void updateClipBounds(const SaveLayer& op) {
if (op.bounds) { if (op.bounds) {
fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint)); fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
@ -207,7 +207,7 @@ private:
void pushSaveBlock(const SkPaint* paint) { void pushSaveBlock(const SkPaint* paint) {
// Starting a new Save block. Push a new entry to represent that. // Starting a new Save block. Push a new entry to represent that.
SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint }; SaveBounds sb = { 0, Bounds::MakeEmpty(), paint };
fSaveStack.push(sb); fSaveStack.push(sb);
this->pushControl(); this->pushControl();
} }
@ -217,13 +217,13 @@ private:
return paint && (paint->getImageFilter() || paint->getColorFilter()); return paint && (paint->getImageFilter() || paint->getColorFilter());
} }
SkIRect popSaveBlock() { Bounds popSaveBlock() {
// We're done the Save block. Apply the block's bounds to all control ops inside it. // We're done the Save block. Apply the block's bounds to all control ops inside it.
SaveBounds sb; SaveBounds sb;
fSaveStack.pop(&sb); fSaveStack.pop(&sb);
// If the paint affects transparent black, we can't trust any of our calculated bounds. // If the paint affects transparent black, we can't trust any of our calculated bounds.
const SkIRect& bounds = const Bounds& bounds =
PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.bounds; PaintMayAffectTransparentBlack(sb.paint) ? fCurrentClipBounds : sb.bounds;
while (sb.controlOps --> 0) { while (sb.controlOps --> 0) {
@ -244,12 +244,12 @@ private:
} }
} }
void popControl(const SkIRect& bounds) { void popControl(const Bounds& bounds) {
fBounds[fControlIndices.top()] = bounds; fBounds[fControlIndices.top()] = bounds;
fControlIndices.pop(); fControlIndices.pop();
} }
void updateSaveBounds(const SkIRect& bounds) { void updateSaveBounds(const Bounds& bounds) {
// If we're in a Save block, expand its bounds to cover these bounds too. // If we're in a Save block, expand its bounds to cover these bounds too.
if (!fSaveStack.isEmpty()) { if (!fSaveStack.isEmpty()) {
fSaveStack.top().bounds.join(bounds); fSaveStack.top().bounds.join(bounds);
@ -257,49 +257,49 @@ private:
} }
// FIXME: this method could use better bounds // FIXME: this method could use better bounds
SkIRect bounds(const DrawText&) const { return fCurrentClipBounds; } Bounds bounds(const DrawText&) const { return fCurrentClipBounds; }
SkIRect bounds(const Clear&) const { return SkIRect::MakeLargest(); } // Ignores the clip. Bounds bounds(const Clear&) const { return Bounds::MakeLargest(); } // Ignores the clip.
SkIRect bounds(const DrawPaint&) const { return fCurrentClipBounds; } Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; }
SkIRect bounds(const NoOp&) const { return SkIRect::MakeEmpty(); } // NoOps don't draw. Bounds bounds(const NoOp&) const { return Bounds::MakeEmpty(); } // NoOps don't draw.
SkIRect bounds(const DrawSprite& op) const { Bounds bounds(const DrawSprite& op) const {
const SkBitmap& bm = op.bitmap; const SkBitmap& bm = op.bitmap;
return SkIRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // Ignores the matrix. return Bounds::MakeXYWH(op.left, op.top, bm.width(), bm.height()); // Ignores the matrix.
} }
SkIRect bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); } Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
SkIRect bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); } Bounds bounds(const DrawOval& op) const { return this->adjustAndMap(op.oval, &op.paint); }
SkIRect bounds(const DrawRRect& op) const { Bounds bounds(const DrawRRect& op) const {
return this->adjustAndMap(op.rrect.rect(), &op.paint); return this->adjustAndMap(op.rrect.rect(), &op.paint);
} }
SkIRect bounds(const DrawDRRect& op) const { Bounds bounds(const DrawDRRect& op) const {
return this->adjustAndMap(op.outer.rect(), &op.paint); return this->adjustAndMap(op.outer.rect(), &op.paint);
} }
SkIRect bounds(const DrawBitmapRectToRect& op) const { Bounds bounds(const DrawBitmapRectToRect& op) const {
return this->adjustAndMap(op.dst, op.paint); return this->adjustAndMap(op.dst, op.paint);
} }
SkIRect bounds(const DrawBitmapNine& op) const { Bounds bounds(const DrawBitmapNine& op) const {
return this->adjustAndMap(op.dst, op.paint); return this->adjustAndMap(op.dst, op.paint);
} }
SkIRect bounds(const DrawBitmap& op) const { Bounds bounds(const DrawBitmap& op) const {
const SkBitmap& bm = op.bitmap; const SkBitmap& bm = op.bitmap;
return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()), return this->adjustAndMap(SkRect::MakeXYWH(op.left, op.top, bm.width(), bm.height()),
op.paint); op.paint);
} }
SkIRect bounds(const DrawBitmapMatrix& op) const { Bounds bounds(const DrawBitmapMatrix& op) const {
const SkBitmap& bm = op.bitmap; const SkBitmap& bm = op.bitmap;
SkRect dst = SkRect::MakeWH(bm.width(), bm.height()); SkRect dst = SkRect::MakeWH(bm.width(), bm.height());
op.matrix.mapRect(&dst); op.matrix.mapRect(&dst);
return this->adjustAndMap(dst, op.paint); return this->adjustAndMap(dst, op.paint);
} }
SkIRect bounds(const DrawPath& op) const { Bounds bounds(const DrawPath& op) const {
return op.path.isInverseFillType() ? fCurrentClipBounds return op.path.isInverseFillType() ? fCurrentClipBounds
: this->adjustAndMap(op.path.getBounds(), &op.paint); : this->adjustAndMap(op.path.getBounds(), &op.paint);
} }
SkIRect bounds(const DrawPoints& op) const { Bounds bounds(const DrawPoints& op) const {
SkRect dst; SkRect dst;
dst.set(op.pts, op.count); dst.set(op.pts, op.count);
@ -309,18 +309,18 @@ private:
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawPatch& op) const { Bounds bounds(const DrawPatch& op) const {
SkRect dst; SkRect dst;
dst.set(op.cubics, SkPatchUtils::kNumCtrlPts); dst.set(op.cubics, SkPatchUtils::kNumCtrlPts);
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawVertices& op) const { Bounds bounds(const DrawVertices& op) const {
SkRect dst; SkRect dst;
dst.set(op.vertices, op.vertexCount); dst.set(op.vertices, op.vertexCount);
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawPicture& op) const { Bounds bounds(const DrawPicture& op) const {
SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height()); SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height());
if (op.matrix) { if (op.matrix) {
op.matrix->mapRect(&dst); op.matrix->mapRect(&dst);
@ -328,10 +328,10 @@ private:
return this->adjustAndMap(dst, op.paint); return this->adjustAndMap(dst, op.paint);
} }
SkIRect bounds(const DrawPosText& op) const { Bounds bounds(const DrawPosText& op) const {
const int N = op.paint.countText(op.text, op.byteLength); const int N = op.paint.countText(op.text, op.byteLength);
if (N == 0) { if (N == 0) {
return SkIRect::MakeEmpty(); return Bounds::MakeEmpty();
} }
SkRect dst; SkRect dst;
@ -339,10 +339,10 @@ private:
AdjustTextForFontMetrics(&dst, op.paint); AdjustTextForFontMetrics(&dst, op.paint);
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawPosTextH& op) const { Bounds bounds(const DrawPosTextH& op) const {
const int N = op.paint.countText(op.text, op.byteLength); const int N = op.paint.countText(op.text, op.byteLength);
if (N == 0) { if (N == 0) {
return SkIRect::MakeEmpty(); return Bounds::MakeEmpty();
} }
SkScalar left = op.xpos[0], right = op.xpos[0]; SkScalar left = op.xpos[0], right = op.xpos[0];
@ -354,7 +354,7 @@ private:
AdjustTextForFontMetrics(&dst, op.paint); AdjustTextForFontMetrics(&dst, op.paint);
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawTextOnPath& op) const { Bounds bounds(const DrawTextOnPath& op) const {
SkRect dst = op.path.getBounds(); SkRect dst = op.path.getBounds();
// Pad all sides by the maximum padding in any direction we'd normally apply. // Pad all sides by the maximum padding in any direction we'd normally apply.
@ -370,7 +370,7 @@ private:
return this->adjustAndMap(dst, &op.paint); return this->adjustAndMap(dst, &op.paint);
} }
SkIRect bounds(const DrawTextBlob& op) const { Bounds bounds(const DrawTextBlob& op) const {
SkRect dst = op.blob->bounds(); SkRect dst = op.blob->bounds();
dst.offset(op.x, op.y); dst.offset(op.x, op.y);
// TODO: remove when implicit bounds are plumbed through // TODO: remove when implicit bounds are plumbed through
@ -415,8 +415,8 @@ private:
return true; return true;
} }
// Adjust rect for all paints that may affect its geometry, then map it to device space. // Adjust rect for all paints that may affect its geometry, then map it to identity space.
SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const { Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
// Inverted rectangles really confuse our BBHs. // Inverted rectangles really confuse our BBHs.
rect.sort(); rect.sort();
@ -434,26 +434,24 @@ private:
} }
} }
// Map the rect back to device space. // Map the rect back to identity space.
fCTM->mapRect(&rect); fCTM->mapRect(&rect);
SkIRect devRect;
rect.roundOut(&devRect);
// Nothing can draw outside the current clip. // Nothing can draw outside the current clip.
// (Only bounded ops call into this method, so oddballs like Clear don't matter here.) // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
devRect.intersect(fCurrentClipBounds); rect.intersect(fCurrentClipBounds);
return devRect; return rect;
} }
// Conservative device bounds for each op in the SkRecord. // Conservative identity-space bounds for each op in the SkRecord.
SkAutoTMalloc<SkIRect> fBounds; SkAutoTMalloc<Bounds> fBounds;
// We walk fCurrentOp through the SkRecord, as we go using updateCTM() // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
// and updateClipBounds() to maintain the exact CTM (fCTM) and conservative // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
// device bounds of the current clip (fCurrentClipBounds). // identity-space bounds of the current clip (fCurrentClipBounds).
unsigned fCurrentOp; unsigned fCurrentOp;
const SkMatrix* fCTM; const SkMatrix* fCTM;
SkIRect fCurrentClipBounds; Bounds fCurrentClipBounds;
// Used to track the bounds of Save/Restore blocks and the control ops inside them. // Used to track the bounds of Save/Restore blocks and the control ops inside them.
SkTDArray<SaveBounds> fSaveStack; SkTDArray<SaveBounds> fSaveStack;

View File

@ -23,13 +23,15 @@ SkTileGrid::~SkTileGrid() {
SkDELETE_ARRAY(fTiles); SkDELETE_ARRAY(fTiles);
} }
void SkTileGrid::insert(void* data, const SkIRect& bounds, bool) { void SkTileGrid::insert(void* data, const SkRect& fbounds, bool) {
SkASSERT(!bounds.isEmpty()); SkASSERT(!fbounds.isEmpty());
SkIRect dilatedBounds = bounds; SkIRect dilatedBounds;
if (fbounds.isLargest()) {
// Dilating the largest SkIRect will overflow. Other nearly-largest rects may overflow too, // Dilating the largest SkIRect will overflow. Other nearly-largest rects may overflow too,
// but we don't make active use of them like we do the largest. // but we don't make active use of them like we do the largest.
if (!bounds.isLargest()) { dilatedBounds.setLargest();
} else {
fbounds.roundOut(&dilatedBounds);
dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height()); dilatedBounds.outset(fInfo.fMargin.width(), fInfo.fMargin.height());
dilatedBounds.offset(fInfo.fOffset); dilatedBounds.offset(fInfo.fOffset);
} }
@ -67,8 +69,9 @@ static int divide_ceil(int x, int y) {
// require 512 tiles of size 256 x 256 pixels. // require 512 tiles of size 256 x 256 pixels.
static const int kStackAllocationTileCount = 1024; static const int kStackAllocationTileCount = 1024;
void SkTileGrid::search(const SkIRect& query, SkTDArray<void*>* results) const { void SkTileGrid::search(const SkRect& query, SkTDArray<void*>* results) const {
SkIRect adjusted = query; SkIRect adjusted;
query.roundOut(&adjusted);
// The inset is to counteract the outset that was applied in 'insert' // The inset is to counteract the outset that was applied in 'insert'
// The outset/inset is to optimize for lookups of size // The outset/inset is to optimize for lookups of size

View File

@ -28,7 +28,7 @@ public:
* @param bounds The bounding box, should not be empty. * @param bounds The bounding box, should not be empty.
* @param defer Ignored; SkTileGrid does not defer insertions. * @param defer Ignored; SkTileGrid does not defer insertions.
*/ */
virtual void insert(void* data, const SkIRect& bounds, bool) SK_OVERRIDE; virtual void insert(void* data, const SkRect& bounds, bool) SK_OVERRIDE;
virtual void flushDeferredInserts() SK_OVERRIDE {}; virtual void flushDeferredInserts() SK_OVERRIDE {};
@ -36,7 +36,7 @@ public:
* Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query'. * Populate 'results' with data pointers corresponding to bounding boxes that intersect 'query'.
* This will be fastest if the query is an exact match to a single grid tile. * This will be fastest if the query is an exact match to a single grid tile.
*/ */
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE; virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE;
virtual void clear() SK_OVERRIDE; virtual void clear() SK_OVERRIDE;

View File

@ -1617,7 +1617,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
CHECK_SHOULD_DRAW(draw, false); CHECK_SHOULD_DRAW(draw, false);
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext); GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext);
const uint16_t* outIndices; const uint16_t* outIndices;
SkAutoTDeleteArray<uint16_t> outAlloc(NULL); SkAutoTDeleteArray<uint16_t> outAlloc(NULL);
GrPrimitiveType primType; GrPrimitiveType primType;
@ -1625,13 +1625,13 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
// If both textures and vertex-colors are NULL, strokes hairlines with the paint's color. // If both textures and vertex-colors are NULL, strokes hairlines with the paint's color.
if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) { if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) {
texs = NULL; texs = NULL;
SkPaint copy(paint); SkPaint copy(paint);
copy.setStyle(SkPaint::kStroke_Style); copy.setStyle(SkPaint::kStroke_Style);
copy.setStrokeWidth(0); copy.setStrokeWidth(0);
// we ignore the shader if texs is null. // we ignore the shader if texs is null.
SkPaint2GrPaintNoShader(this->context(), copy, SkColor2GrColor(copy.getColor()), SkPaint2GrPaintNoShader(this->context(), copy, SkColor2GrColor(copy.getColor()),
NULL == colors, &grPaint); NULL == colors, &grPaint);
@ -1648,13 +1648,13 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
triangleCount = n - 2; triangleCount = n - 2;
break; break;
} }
VertState state(vertexCount, indices, indexCount); VertState state(vertexCount, indices, indexCount);
VertState::Proc vertProc = state.chooseProc(vmode); VertState::Proc vertProc = state.chooseProc(vmode);
//number of indices for lines per triangle with kLines //number of indices for lines per triangle with kLines
indexCount = triangleCount * 6; indexCount = triangleCount * 6;
outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount)); outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount));
outIndices = outAlloc.get(); outIndices = outAlloc.get();
uint16_t* auxIndices = outAlloc.get(); uint16_t* auxIndices = outAlloc.get();
@ -1671,7 +1671,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
} else { } else {
outIndices = indices; outIndices = indices;
primType = gVertexMode2PrimitiveType[vmode]; primType = gVertexMode2PrimitiveType[vmode];
if (NULL == texs || NULL == paint.getShader()) { if (NULL == texs || NULL == paint.getShader()) {
SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColor(paint.getColor()), SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColor(paint.getColor()),
NULL == colors, &grPaint); NULL == colors, &grPaint);
@ -1879,7 +1879,7 @@ static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re
// Return true if any layers are suitable for hoisting // Return true if any layers are suitable for hoisting
bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData, bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData,
const SkPicture::OperationList* ops, const SkPicture::OperationList* ops,
const SkIRect& query, const SkRect& query,
bool* pullForward) { bool* pullForward) {
bool anyHoisted = false; bool anyHoisted = false;
@ -1929,12 +1929,12 @@ bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData,
for (int j = 0; j < gpuData->numSaveLayers(); ++j) { for (int j = 0; j < gpuData->numSaveLayers(); ++j) {
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j); const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j);
SkIRect layerRect = SkIRect::MakeXYWH(info.fOffset.fX, SkRect layerRect = SkRect::MakeXYWH(SkIntToScalar(info.fOffset.fX),
info.fOffset.fY, SkIntToScalar(info.fOffset.fY),
info.fSize.fWidth, SkIntToScalar(info.fSize.fWidth),
info.fSize.fHeight); SkIntToScalar(info.fSize.fHeight));
if (!SkIRect::Intersects(query, layerRect)) { if (!SkRect::Intersects(query, layerRect)) {
continue; continue;
} }
@ -1986,12 +1986,11 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
if (!mainCanvas->getClipBounds(&clipBounds)) { if (!mainCanvas->getClipBounds(&clipBounds)) {
return true; return true;
} }
SkIRect query;
clipBounds.roundOut(&query);
SkAutoTDelete<const SkPicture::OperationList> ops(picture->EXPERIMENTAL_getActiveOps(query)); SkAutoTDelete<const SkPicture::OperationList> ops(
picture->EXPERIMENTAL_getActiveOps(clipBounds));
if (!FindLayersToHoist(gpuData, ops.get(), query, pullForward.get())) { if (!FindLayersToHoist(gpuData, ops.get(), clipBounds, pullForward.get())) {
return false; return false;
} }
@ -2005,9 +2004,9 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
if (pullForward[i]) { if (pullForward[i]) {
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(), GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
info.fSaveLayerOpID, info.fSaveLayerOpID,
info.fRestoreOpID, info.fRestoreOpID,
info.fCTM); info.fCTM);
SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo = SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
@ -2030,7 +2029,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
} }
layerInfo->fBM = SkNEW(SkBitmap); // fBM is allocated so ReplacementInfo can be POD layerInfo->fBM = SkNEW(SkBitmap); // fBM is allocated so ReplacementInfo can be POD
wrap_texture(layer->texture(), wrap_texture(layer->texture(),
!layer->isAtlased() ? desc.fWidth : layer->texture()->width(), !layer->isAtlased() ? desc.fWidth : layer->texture()->width(),
!layer->isAtlased() ? desc.fHeight : layer->texture()->height(), !layer->isAtlased() ? desc.fHeight : layer->texture()->height(),
layerInfo->fBM); layerInfo->fBM);
@ -2066,7 +2065,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
} }
void SkGpuDevice::drawLayers(const SkPicture* picture, void SkGpuDevice::drawLayers(const SkPicture* picture,
const SkTDArray<GrCachedLayer*>& atlased, const SkTDArray<GrCachedLayer*>& atlased,
const SkTDArray<GrCachedLayer*>& nonAtlased) { const SkTDArray<GrCachedLayer*>& nonAtlased) {
// Render the atlased layers that require it // Render the atlased layers that require it
if (atlased.count() > 0) { if (atlased.count() > 0) {
@ -2171,7 +2170,7 @@ void SkGpuDevice::unlockLayers(const SkPicture* picture) {
} }
#if DISABLE_CACHING #if DISABLE_CACHING
// This code completely clears out the atlas. It is required when // This code completely clears out the atlas. It is required when
// caching is disabled so the atlas doesn't fill up and force more // caching is disabled so the atlas doesn't fill up and force more
// free floating layers // free floating layers
fContext->getLayerCache()->purge(picture->uniqueID()); fContext->getLayerCache()->purge(picture->uniqueID());

View File

@ -17,20 +17,20 @@ static const int NUM_RECTS = 200;
static const size_t NUM_ITERATIONS = 100; static const size_t NUM_ITERATIONS = 100;
static const size_t NUM_QUERIES = 50; static const size_t NUM_QUERIES = 50;
static const int MAX_SIZE = 1000; static const SkScalar MAX_SIZE = 1000.0f;
struct DataRect { struct DataRect {
SkIRect rect; SkRect rect;
void* data; void* data;
}; };
static SkIRect random_rect(SkRandom& rand) { static SkRect random_rect(SkRandom& rand) {
SkIRect rect = {0,0,0,0}; SkRect rect = {0,0,0,0};
while (rect.isEmpty()) { while (rect.isEmpty()) {
rect.fLeft = rand.nextS() % MAX_SIZE; rect.fLeft = rand.nextRangeF(0, MAX_SIZE);
rect.fRight = rand.nextS() % MAX_SIZE; rect.fRight = rand.nextRangeF(0, MAX_SIZE);
rect.fTop = rand.nextS() % MAX_SIZE; rect.fTop = rand.nextRangeF(0, MAX_SIZE);
rect.fBottom = rand.nextS() % MAX_SIZE; rect.fBottom = rand.nextRangeF(0, MAX_SIZE);
rect.sort(); rect.sort();
} }
return rect; return rect;
@ -43,12 +43,15 @@ static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
} }
} }
static bool verify_query(SkIRect query, DataRect rects[], static bool verify_query(SkRect query, DataRect rects[],
SkTDArray<void*>& found) { SkTDArray<void*>& found) {
// TODO(mtklein): no need to do this after everything's SkRects
query.roundOut();
SkTDArray<void*> expected; SkTDArray<void*> expected;
// manually intersect with every rectangle // manually intersect with every rectangle
for (int i = 0; i < NUM_RECTS; ++i) { for (int i = 0; i < NUM_RECTS; ++i) {
if (SkIRect::IntersectsNoEmptyCheck(query, rects[i].rect)) { if (SkRect::Intersects(query, rects[i].rect)) {
expected.push(rects[i].data); expected.push(rects[i].data);
} }
} }
@ -73,7 +76,7 @@ static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect r
SkBBoxHierarchy& tree) { SkBBoxHierarchy& tree) {
for (size_t i = 0; i < NUM_QUERIES; ++i) { for (size_t i = 0; i < NUM_QUERIES; ++i) {
SkTDArray<void*> hits; SkTDArray<void*> hits;
SkIRect query = random_rect(rand); SkRect query = random_rect(rand);
tree.search(query, &hits); tree.search(query, &hits);
REPORTER_ASSERT(reporter, verify_query(query, rects, hits)); REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
} }

View File

@ -1808,12 +1808,12 @@ struct CountingBBH : public SkBBoxHierarchy {
CountingBBH() : searchCalls(0) {} CountingBBH() : searchCalls(0) {}
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const { virtual void search(const SkRect& query, SkTDArray<void*>* results) const {
this->searchCalls++; this->searchCalls++;
} }
// All other methods unimplemented. // All other methods unimplemented.
virtual void insert(void* data, const SkIRect& bounds, bool defer) {} virtual void insert(void* data, const SkRect& bounds, bool defer) {}
virtual void flushDeferredInserts() {} virtual void flushDeferredInserts() {}
virtual void clear() {} virtual void clear() {}
virtual int getCount() const { return 0; } virtual int getCount() const { return 0; }

View File

@ -18,17 +18,17 @@ static const size_t NUM_ITERATIONS = 100;
static const size_t NUM_QUERIES = 50; static const size_t NUM_QUERIES = 50;
struct DataRect { struct DataRect {
SkIRect rect; SkRect rect;
void* data; void* data;
}; };
static SkIRect random_rect(SkRandom& rand) { static SkRect random_rect(SkRandom& rand) {
SkIRect rect = {0,0,0,0}; SkRect rect = {0,0,0,0};
while (rect.isEmpty()) { while (rect.isEmpty()) {
rect.fLeft = rand.nextS() % 1000; rect.fLeft = rand.nextRangeF(0, 1000);
rect.fRight = rand.nextS() % 1000; rect.fRight = rand.nextRangeF(0, 1000);
rect.fTop = rand.nextS() % 1000; rect.fTop = rand.nextRangeF(0, 1000);
rect.fBottom = rand.nextS() % 1000; rect.fBottom = rand.nextRangeF(0, 1000);
rect.sort(); rect.sort();
} }
return rect; return rect;
@ -41,12 +41,16 @@ static void random_data_rects(SkRandom& rand, DataRect out[], int n) {
} }
} }
static bool verify_query(SkIRect query, DataRect rects[], static bool verify_query(SkRect query, DataRect rects[],
SkTDArray<void*>& found) { SkTDArray<void*>& found) {
// TODO(mtklein): no need to do this after everything's SkRects
query.roundOut();
SkTDArray<void*> expected; SkTDArray<void*> expected;
// manually intersect with every rectangle // manually intersect with every rectangle
for (int i = 0; i < NUM_RECTS; ++i) { for (int i = 0; i < NUM_RECTS; ++i) {
if (SkIRect::IntersectsNoEmptyCheck(query, rects[i].rect)) { if (SkRect::Intersects(query, rects[i].rect)) {
expected.push(rects[i].data); expected.push(rects[i].data);
} }
} }
@ -71,7 +75,7 @@ static void run_queries(skiatest::Reporter* reporter, SkRandom& rand, DataRect r
SkRTree& tree) { SkRTree& tree) {
for (size_t i = 0; i < NUM_QUERIES; ++i) { for (size_t i = 0; i < NUM_QUERIES; ++i) {
SkTDArray<void*> hits; SkTDArray<void*> hits;
SkIRect query = random_rect(rand); SkRect query = random_rect(rand);
tree.search(query, &hits); tree.search(query, &hits);
REPORTER_ASSERT(reporter, verify_query(query, rects, hits)); REPORTER_ASSERT(reporter, verify_query(query, rects, hits));
} }

View File

@ -97,7 +97,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
} }
struct TestBBH : public SkBBoxHierarchy { struct TestBBH : public SkBBoxHierarchy {
virtual void insert(void* data, const SkIRect& bounds, bool defer) SK_OVERRIDE { virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE {
Entry e = { (uintptr_t)data, bounds }; Entry e = { (uintptr_t)data, bounds };
entries.push(e); entries.push(e);
} }
@ -105,14 +105,14 @@ struct TestBBH : public SkBBoxHierarchy {
virtual void flushDeferredInserts() SK_OVERRIDE {} virtual void flushDeferredInserts() SK_OVERRIDE {}
virtual void search(const SkIRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {} virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
virtual void clear() SK_OVERRIDE {} virtual void clear() SK_OVERRIDE {}
virtual void rewindInserts() SK_OVERRIDE {} virtual void rewindInserts() SK_OVERRIDE {}
virtual int getDepth() const SK_OVERRIDE { return -1; } virtual int getDepth() const SK_OVERRIDE { return -1; }
struct Entry { struct Entry {
uintptr_t data; uintptr_t data;
SkIRect bounds; SkRect bounds;
}; };
SkTDArray<Entry> entries; SkTDArray<Entry> entries;
}; };
@ -137,6 +137,6 @@ DEF_TEST(RecordDraw_BBH, r) {
for (int i = 0; i < bbh.entries.count(); i++) { for (int i = 0; i < bbh.entries.count(); i++) {
REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i); REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i);
REPORTER_ASSERT(r, bbh.entries[i].bounds == SkIRect::MakeWH(400, 480)); REPORTER_ASSERT(r, bbh.entries[i].bounds == SkRect::MakeWH(400, 480));
} }
} }

View File

@ -31,7 +31,7 @@ public:
SkTDArray<SkRect> fRects; SkTDArray<SkRect> fRects;
}; };
static void verifyTileHits(skiatest::Reporter* reporter, SkIRect rect, static void verifyTileHits(skiatest::Reporter* reporter, SkRect rect,
uint32_t tileMask, int borderPixels = 0) { uint32_t tileMask, int borderPixels = 0) {
SkTileGridFactory::TileGridInfo info; SkTileGridFactory::TileGridInfo info;
info.fMargin.set(borderPixels, borderPixels); info.fMargin.set(borderPixels, borderPixels);
@ -223,29 +223,29 @@ DEF_TEST(TileGrid_OverlapOffsetQueryAlignment, reporter) {
DEF_TEST(TileGrid, reporter) { DEF_TEST(TileGrid, reporter) {
// Out of bounds // Out of bounds
verifyTileHits(reporter, SkIRect::MakeXYWH(30, 0, 1, 1), 0); verifyTileHits(reporter, SkRect::MakeXYWH(30, 0, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 30, 1, 1), 0); verifyTileHits(reporter, SkRect::MakeXYWH(0, 30, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(-10, 0, 1, 1), 0); verifyTileHits(reporter, SkRect::MakeXYWH(-10, 0, 1, 1), 0);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, -10, 1, 1), 0); verifyTileHits(reporter, SkRect::MakeXYWH(0, -10, 1, 1), 0);
// Dilation for AA consideration // Dilation for AA consideration
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 9, 9), kTopLeft_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 10, 10), kAll_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1), kAll_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1), kAll_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(11, 11, 1, 1), kBottomRight_Tile);
// BorderPixels // BorderPixels
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1); verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 6, 6), kTopLeft_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1); verifyTileHits(reporter, SkRect::MakeXYWH(0, 0, 7, 7), kAll_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1); verifyTileHits(reporter, SkRect::MakeXYWH(9, 9, 1, 1), kAll_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1); verifyTileHits(reporter, SkRect::MakeXYWH(10, 10, 1, 1), kBottomRight_Tile, 1);
verifyTileHits(reporter, SkIRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1); verifyTileHits(reporter, SkRect::MakeXYWH(17, 17, 1, 1), kBottomRight_Tile, 1);
// BBoxes that overlap tiles // BBoxes that overlap tiles
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 1), kTopLeft_Tile | kTopRight_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile | verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 1, 10), kTopLeft_Tile |
kBottomLeft_Tile); kBottomLeft_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(5, 5, 10, 10), kAll_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(5, 5, 10, 10), kAll_Tile);
verifyTileHits(reporter, SkIRect::MakeXYWH(-10, -10, 40, 40), kAll_Tile); verifyTileHits(reporter, SkRect::MakeXYWH(-10, -10, 40, 40), kAll_Tile);
} }