// Adjust rect for all paints that may affect its geometry, then map it to identity space. Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const { // Inverted rectangles really confuse our BBHs. rect.sort(); // Adjust the rect for its own paint. if (!AdjustForPaint(paint, &rect)) { // The paint could do anything to our bounds. The only safe answer is the current clip. return fCurrentClipBounds; } // Adjust rect for all the paints from the SaveLayers we're inside. if (!this->adjustForSaveLayerPaints(&rect)) { // Same deal as above. return fCurrentClipBounds; } // Map the rect back to identity space. fCTM.mapRect(&rect); // Nothing can draw outside the current clip. if (!rect.intersect(fCurrentClipBounds)) { return Bounds::MakeEmpty(); } return rect; }
bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) { SkRect outBounds = bounds; outBounds.sort(); if (paint) { // account for stroking, path effects, shadows, etc if (paint->canComputeFastBounds()) { SkRect temp; outBounds = paint->computeFastBounds(outBounds, &temp); } else { // set bounds to current clip if (!this->getClipBounds(&outBounds)) { // current clip is empty return false; } } } if (!outBounds.isEmpty() && !this->quickReject(outBounds)) { this->getTotalMatrix().mapRect(&outBounds); this->handleBBox(outBounds); return true; } return false; }
// returns true if we should proceed void init(SkPath* path) { fPath = path; fDirty = SkToBool(path->fBoundsIsDirty); fEmpty = path->isEmpty(); // Cannot use fRect for our bounds unless we know it is sorted fRect.sort(); }
void draw(SkCanvas* canvas) { SkRect rect = SkRect::MakeLTRB(5, 35, 15, 25); SkDebugf("rect: %g, %g, %g, %g isEmpty: %s\n", rect.left(), rect.top(), rect.right(), rect.bottom(), rect.isEmpty() ? "true" : "false"); rect.sort(); SkDebugf("rect: %g, %g, %g, %g isEmpty: %s\n", rect.left(), rect.top(), rect.right(), rect.bottom(), rect.isEmpty() ? "true" : "false"); }
virtual Draw* create(const SkPoint& p0, const SkPoint& p1) { SkRect r; r.set(p0.x(), p0.y(), p1.x(), p1.y()); r.sort(); RDraw* d = new RDraw(r, RDraw::kRRect_Style); d->setPaint(this->getPaint()); return d; }
static SkRect random_texRect(SkRandom* random) { static const SkScalar kMinCoord = 0.0f; static const SkScalar kMaxCoord = 1024.f; SkRect texRect = SkRect::MakeLTRB(random->nextRangeScalar(kMinCoord, kMaxCoord), random->nextRangeScalar(kMinCoord, kMaxCoord), random->nextRangeScalar(kMinCoord, kMaxCoord), random->nextRangeScalar(kMinCoord, kMaxCoord)); texRect.sort(); return texRect; }
static SkRect random_rect(SkRandom& rand) { SkRect rect = {0,0,0,0}; while (rect.isEmpty()) { rect.fLeft = rand.nextRangeF(0, MAX_SIZE); rect.fRight = rand.nextRangeF(0, MAX_SIZE); rect.fTop = rand.nextRangeF(0, MAX_SIZE); rect.fBottom = rand.nextRangeF(0, MAX_SIZE); rect.sort(); } return rect; }
// Move a small box from the start position by (stepX, stepY) 'numSteps' times // testing for containment in 'rr' at each step. static void test_direction(skiatest::Reporter* reporter, const SkRRect &rr, SkScalar initX, int stepX, SkScalar initY, int stepY, int numSteps, const bool* contains) { SkScalar x = initX, y = initY; for (int i = 0; i < numSteps; ++i) { SkRect test = SkRect::MakeXYWH(x, y, stepX ? SkIntToScalar(stepX) : SK_Scalar1, stepY ? SkIntToScalar(stepY) : SK_Scalar1); test.sort(); REPORTER_ASSERT(reporter, contains[i] == rr.contains(test)); x += stepX; y += stepY; } }
// Adjust rect for all paints that may affect its geometry, then map it to identity space. Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const { // Inverted rectangles really confuse our BBHs. rect.sort(); // Adjust the rect for its own paint. if (!AdjustForPaint(paint, &rect)) { // The paint could do anything to our bounds. The only safe answer is the current clip. return fCurrentClipBounds; } // Adjust rect for all the paints from the SaveLayers we're inside. if (!this->adjustForSaveLayerPaints(&rect)) { // Same deal as above. return fCurrentClipBounds; } // Map the rect back to identity space. fCTM->mapRect(&rect); // Nothing can draw outside the current clip. // (Only bounded ops call into this method, so oddballs like Clear don't matter here.) rect.intersect(fCurrentClipBounds); return rect; }
/** sorts a rect */ static SkRect sorted_rect(const SkRect& unsorted) { SkRect r = unsorted; r.sort(); return r; }
void SkTileGrid::search(const SkRect& originalQuery, SkTDArray<unsigned>* results) const { // The inset counteracts the outset that applied in 'insert', which optimizes // for lookups of size 'tileInterval + 2 * margin' (aligned with the tile grid). SkRect query = originalQuery; query.inset(fMarginWidth, fMarginHeight); this->commonAdjust(&query); // The inset may have inverted the rectangle, so sort(). // TODO(mtklein): It looks like we only end up with inverted bounds in unit tests // that make explicitly inverted queries, not from insetting. If we can drop support for // unsorted bounds (i.e. we don't see them outside unit tests), I think we can drop this. query.sort(); // No intersection check. We optimize for queries that are in bounds. // We're safe anyway: userToGrid() will clamp out-of-bounds queries to nearest tile. SkIRect grid; this->userToGrid(query, &grid); const int tilesHit = (grid.fRight - grid.fLeft + 1) * (grid.fBottom - grid.fTop + 1); SkASSERT(tilesHit > 0); if (tilesHit == 1) { // A performance shortcut. The merging code below would work fine here too. *results = fTiles[grid.fTop * fXTiles + grid.fLeft]; return; } // We've got to merge the data in many tiles into a single sorted and deduplicated stream. // We do a simple k-way merge based on the value of opIndex. // Gather pointers to the starts and ends of the tiles to merge. SkAutoSTArray<kStackAllocationTileCount, const unsigned*> starts(tilesHit), ends(tilesHit); int i = 0; for (int y = grid.fTop; y <= grid.fBottom; y++) { for (int x = grid.fLeft; x <= grid.fRight; x++) { starts[i] = fTiles[y * fXTiles + x].begin(); ends[i] = fTiles[y * fXTiles + x].end(); i++; } } // Merge tiles into results until they're fully consumed. results->reset(); while (true) { // The tiles themselves are already ordered, so the earliest op is at the front of some // tile. It may be at the front of several, even all, tiles. unsigned earliest = SK_MaxU32; for (int i = 0; i < starts.count(); i++) { if (starts[i] < ends[i]) { earliest = SkTMin(earliest, *starts[i]); } } // If we didn't find an earliest op, there isn't anything left to merge. if (SK_MaxU32 == earliest) { return; } // We did find an earliest op. Output it, and step forward every tile that contains it. results->push(earliest); for (int i = 0; i < starts.count(); i++) { if (starts[i] < ends[i] && *starts[i] == earliest) { starts[i]++; } } } }