Use device-space stroke width for SkDraw::drawRect() quick-reject

The stroke width needs to be CTM-adjusted when applied to device space
rects.

BUG=skia:3313
R=reed@google.com

Review URL: https://codereview.chromium.org/801353008
This commit is contained in:
fmalita 2015-01-15 06:01:23 -08:00 committed by Commit bot
parent 6e87913ab9
commit 1a178ca6dd
3 changed files with 75 additions and 16 deletions

View File

@ -177,6 +177,7 @@
'../tests/RecordTest.cpp',
'../tests/RecorderTest.cpp',
'../tests/RecordingXfermodeTest.cpp',
'../tests/RectTest.cpp',
'../tests/RefCntTest.cpp',
'../tests/RefDictTest.cpp',
'../tests/RegionTest.cpp',

View File

@ -735,6 +735,16 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
}
}
static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
SkASSERT(matrix.rectStaysRect());
SkASSERT(SkPaint::kFill_Style != paint.getStyle());
SkVector size;
SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
matrix.mapVectors(&size, &pt, 1);
return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
}
static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
SkPoint* strokeSize) {
if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
@ -742,11 +752,7 @@ static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
return false;
}
SkASSERT(matrix.rectStaysRect());
SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
matrix.mapVectors(strokeSize, &pt, 1);
strokeSize->fX = SkScalarAbs(strokeSize->fX);
strokeSize->fY = SkScalarAbs(strokeSize->fY);
*strokeSize = compute_stroke_size(paint, matrix);
return true;
}
@ -822,26 +828,27 @@ void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
}
SkRect devRect;
if (paintMatrix) {
// skip the paintMatrix when transforming the rect by the CTM
fMatrix->mapPoints(rect_points(devRect), rect_points(*postPaintRect), 2);
} else {
fMatrix->mapPoints(rect_points(devRect), rect_points(prePaintRect), 2);
}
// transform rect into devRect
const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
// skip the paintMatrix when transforming the rect by the CTM
fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
devRect.sort();
// look for the quick exit, before we build a blitter
SkIRect ir = devRect.roundOut();
SkRect bbox = devRect;
if (paint.getStyle() != SkPaint::kFill_Style) {
// extra space for hairlines
if (paint.getStrokeWidth() == 0) {
ir.outset(1, 1);
bbox.outset(1, 1);
} else {
SkScalar radius = SkScalarHalf(paint.getStrokeWidth());
ir.outset(radius, radius);
// For kStroke_RectType, strokeSize is already computed.
const SkPoint& ssize = (kStroke_RectType == rtype)
? strokeSize
: compute_stroke_size(paint, *fMatrix);
bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
}
}
SkIRect ir = bbox.roundOut();
if (fRC->quickReject(ir)) {
return;
}

51
tests/RectTest.cpp Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkRect.h"
#include "Test.h"
static bool has_green_pixels(const SkBitmap& bm) {
for (int j = 0; j < bm.height(); ++j) {
for (int i = 0; i < bm.width(); ++i) {
if (SkColorGetG(bm.getColor(i, j))) {
return true;
}
}
}
return false;
}
static void test_stroke_width_clipping(skiatest::Reporter* reporter) {
SkBitmap bm;
bm.allocN32Pixels(100, 10);
bm.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(bm);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(10);
paint.setColor(0xff00ff00);
// clip out the left half of our canvas
canvas.clipRect(SkRect::MakeXYWH(51, 0, 49, 100));
// no stroke bleed should be visible
canvas.drawRect(SkRect::MakeWH(44, 100), paint);
REPORTER_ASSERT(reporter, !has_green_pixels(bm));
// right stroke edge should bleed into the visible area
canvas.scale(2, 2);
canvas.drawRect(SkRect::MakeWH(22, 50), paint);
REPORTER_ASSERT(reporter, has_green_pixels(bm));
}
DEF_TEST(Rect, reporter) {
test_stroke_width_clipping(reporter);
}