Sort all user-supplied rects before computeFastBounds
https://codereview.chromium.org/908353002 fixed drawRect 2+ years ago, but drawOval and drawArc were still susceptible. This version ensures that all rects are sorted before we do the bounds check. Added a new makeSorted helper to simplify the code, and an assert to catch any future oversight. All other drawing functions compute their bounds rect in some way that already ensures it is sorted. Bug: skia: Change-Id: I8926b2dbe9d496d0876f1ac5313bd058ae4568b7 Reviewed-on: https://skia-review.googlesource.com/16702 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
ee93e7803a
commit
60751d7a06
@ -986,6 +986,8 @@ public:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const {
|
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const {
|
||||||
|
// Things like stroking, etc... will do math on the bounds rect, assuming that it's sorted.
|
||||||
|
SkASSERT(orig.isSorted());
|
||||||
SkPaint::Style style = this->getStyle();
|
SkPaint::Style style = this->getStyle();
|
||||||
// ultra fast-case: filling with no effects that affect geometry
|
// ultra fast-case: filling with no effects that affect geometry
|
||||||
if (kFill_Style == style) {
|
if (kFill_Style == style) {
|
||||||
|
@ -376,7 +376,22 @@ struct SK_API SkIRect {
|
|||||||
and may have crossed over each other.
|
and may have crossed over each other.
|
||||||
When this returns, left <= right && top <= bottom
|
When this returns, left <= right && top <= bottom
|
||||||
*/
|
*/
|
||||||
void sort();
|
void sort() {
|
||||||
|
if (fLeft > fRight) {
|
||||||
|
SkTSwap<int32_t>(fLeft, fRight);
|
||||||
|
}
|
||||||
|
if (fTop > fBottom) {
|
||||||
|
SkTSwap<int32_t>(fTop, fBottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom).
|
||||||
|
*/
|
||||||
|
SkIRect makeSorted() const {
|
||||||
|
return MakeLTRB(SkMin32(fLeft, fRight), SkMin32(fTop, fBottom),
|
||||||
|
SkMax32(fLeft, fRight), SkMax32(fTop, fBottom));
|
||||||
|
}
|
||||||
|
|
||||||
static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
|
static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
|
||||||
static const SkIRect gEmpty = { 0, 0, 0, 0 };
|
static const SkIRect gEmpty = { 0, 0, 0, 0 };
|
||||||
@ -456,6 +471,11 @@ struct SK_API SkRect {
|
|||||||
*/
|
*/
|
||||||
bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
|
bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the rectangle's width and height are >= 0
|
||||||
|
*/
|
||||||
|
bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; }
|
||||||
|
|
||||||
bool isLargest() const { return SK_ScalarMin == fLeft &&
|
bool isLargest() const { return SK_ScalarMin == fLeft &&
|
||||||
SK_ScalarMin == fTop &&
|
SK_ScalarMin == fTop &&
|
||||||
SK_ScalarMax == fRight &&
|
SK_ScalarMax == fRight &&
|
||||||
@ -887,6 +907,14 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new Rect that is the sorted version of this rect (left <= right, top <= bottom).
|
||||||
|
*/
|
||||||
|
SkRect makeSorted() const {
|
||||||
|
return MakeLTRB(SkMinScalar(fLeft, fRight), SkMinScalar(fTop, fBottom),
|
||||||
|
SkMaxScalar(fLeft, fRight), SkMaxScalar(fTop, fBottom));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cast-safe way to treat the rect as an array of (4) SkScalars.
|
* cast-safe way to treat the rect as an array of (4) SkScalars.
|
||||||
*/
|
*/
|
||||||
|
@ -1981,11 +1981,8 @@ void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
|
|||||||
if (paint.canComputeFastBounds()) {
|
if (paint.canComputeFastBounds()) {
|
||||||
// Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
|
// Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
|
||||||
// To prevent accidental rejecting at this stage, we have to sort it before we check.
|
// To prevent accidental rejecting at this stage, we have to sort it before we check.
|
||||||
SkRect tmp(r);
|
|
||||||
tmp.sort();
|
|
||||||
|
|
||||||
SkRect storage;
|
SkRect storage;
|
||||||
if (this->quickReject(paint.computeFastBounds(tmp, &storage))) {
|
if (this->quickReject(paint.computeFastBounds(r.makeSorted(), &storage))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2028,8 +2025,10 @@ void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
|
|||||||
void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
|
void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
|
||||||
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
|
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawOval()");
|
||||||
if (paint.canComputeFastBounds()) {
|
if (paint.canComputeFastBounds()) {
|
||||||
|
// Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
|
||||||
|
// To prevent accidental rejecting at this stage, we have to sort it before we check.
|
||||||
SkRect storage;
|
SkRect storage;
|
||||||
if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
|
if (this->quickReject(paint.computeFastBounds(oval.makeSorted(), &storage))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2048,9 +2047,11 @@ void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle,
|
|||||||
const SkPaint& paint) {
|
const SkPaint& paint) {
|
||||||
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
|
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
|
||||||
if (paint.canComputeFastBounds()) {
|
if (paint.canComputeFastBounds()) {
|
||||||
|
// Skia will draw an inverted rect, because it explicitly "sorts" it downstream.
|
||||||
|
// To prevent accidental rejecting at this stage, we have to sort it before we check.
|
||||||
SkRect storage;
|
SkRect storage;
|
||||||
// Note we're using the entire oval as the bounds.
|
// Note we're using the entire oval as the bounds.
|
||||||
if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
|
if (this->quickReject(paint.computeFastBounds(oval.makeSorted(), &storage))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,6 @@ void SkIRect::join(int32_t left, int32_t top, int32_t right, int32_t bottom) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkIRect::sort() {
|
|
||||||
if (fLeft > fRight) {
|
|
||||||
SkTSwap<int32_t>(fLeft, fRight);
|
|
||||||
}
|
|
||||||
if (fTop > fBottom) {
|
|
||||||
SkTSwap<int32_t>(fTop, fBottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void SkRect::toQuad(SkPoint quad[4]) const {
|
void SkRect::toQuad(SkPoint quad[4]) const {
|
||||||
|
Loading…
Reference in New Issue
Block a user