Add RRect GM

https://codereview.appspot.com/6945063/



git-svn-id: http://skia.googlecode.com/svn/trunk@6866 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2012-12-17 21:48:19 +00:00
parent 0c8ec2f658
commit 4e18c7a9bb
4 changed files with 189 additions and 27 deletions

150
gm/rrects.cpp Normal file
View File

@ -0,0 +1,150 @@
/*
* 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 "gm.h"
#include "SkRRect.h"
namespace skiagm {
///////////////////////////////////////////////////////////////////////////////
class RRectGM : public GM {
public:
RRectGM(bool doAA, bool doClip) : fDoAA(doAA), fDoClip(doClip) {
this->setBGColor(0xFFDDDDDD);
this->setUpRRects();
}
protected:
SkString onShortName() {
SkString name("rrect");
if (fDoClip) {
name.append("_clip");
}
if (fDoAA) {
name.append("_aa");
} else {
name.append("_bw");
}
return name;
}
virtual SkISize onISize() { return make_isize(kImageWidth, kImageHeight); }
virtual void onDraw(SkCanvas* canvas) {
SkPaint paint;
// when clipping the AA is pushed into the clip operation
paint.setAntiAlias(fDoClip ? false : fDoAA);
static const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX), SkIntToScalar(kTileY));
int curRRect = 0;
for (int y = 1; y < kImageHeight; y += kTileY) {
for (int x = 1; x < kImageWidth; x += kTileX) {
if (curRRect >= kNumRRects) {
break;
}
SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));
canvas->save();
canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
if (fDoClip) {
canvas->clipRRect(fRRects[curRRect], SkRegion::kReplace_Op, fDoAA);
canvas->drawRect(kMaxTileBound, paint);
} else {
canvas->drawRRect(fRRects[curRRect], paint);
}
++curRRect;
canvas->restore();
}
}
}
void setUpRRects() {
// each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
// the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.
// simple cases
fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);
// The first complex case needs special handling since it is a square
fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
for (int i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
}
}
private:
bool fDoAA;
bool fDoClip; // use clipRRect & drawRect instead of drawRRect
static const int kImageWidth = 640;
static const int kImageHeight = 480;
static const int kTileX = 80;
static const int kTileY = 40;
static const int kNumSimpleCases = 3;
static const int kNumComplexCases = 19;
static const SkVector RRectGM::gRadii[kNumComplexCases][4];
static const int kNumRRects = kNumSimpleCases + kNumComplexCases;
SkRRect fRRects[kNumRRects];
typedef GM INHERITED;
};
// Radii for the various test cases. Order is UL, UR, LR, LL
const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
// a circle
{ { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },
// odd ball cases
{ { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
{ { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
{ { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },
// UL
{ { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
{ { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
{ { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
// UR
{ { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
{ { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
{ { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },
// LR
{ { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
{ { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
{ { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },
// LL
{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
{ { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },
// over-sized radii
{ { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
{ { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
{ { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
};
///////////////////////////////////////////////////////////////////////////////
DEF_GM( return new RRectGM(false, false); )
DEF_GM( return new RRectGM(true, false); )
DEF_GM( return new RRectGM(false, true); )
DEF_GM( return new RRectGM(true, true); )
}

View File

@ -63,6 +63,7 @@
'../gm/poly2poly.cpp',
'../gm/quadpaths.cpp',
'../gm/rrect.cpp',
'../gm/rrects.cpp',
'../gm/samplerstress.cpp',
'../gm/shaderbounds.cpp',
'../gm/shadertext.cpp',

View File

@ -662,14 +662,20 @@ public:
* @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
* @param dir The direction to wind the rectangle's contour. Cannot be
* kUnknown_Direction.
* Note: The radii here now go through the same constraint handling as the
* SkRRect radii (i.e., either radii at a corner being 0 implies a
* sqaure corner and oversized radii are proportionally scaled down).
*/
void addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir = kCW_Direction);
/**
* Add a SkRRect contour to the path
* Add an SkRRect contour to the path
* @param rrect The rounded rect to add as a closed contour
* @param dir The winding direction for the new contour. Cannot be
* kUnknown_Direction.
*/
void addRRect(const SkRRect&, Direction dir = kCW_Direction);
void addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
/**
* Add a new contour made of just lines. This is just a fast version of

View File

@ -1035,8 +1035,12 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
static void add_corner_arc(SkPath* path, const SkRect& rect,
SkScalar rx, SkScalar ry, int startAngle,
SkPath::Direction dir, bool forceMoveTo) {
rx = SkMinScalar(SkScalarHalf(rect.width()), rx);
ry = SkMinScalar(SkScalarHalf(rect.height()), ry);
// These two asserts are not sufficient, since really we want to know
// that the pair of radii (e.g. left and right, or top and bottom) sum
// to <= dimension, but we don't have that data here, so we just have
// these conservative asserts.
SkASSERT(0 <= rx && rx <= rect.width());
SkASSERT(0 <= ry && ry <= rect.height());
SkRect r;
r.set(-rx, -ry, rx, ry);
@ -1063,32 +1067,20 @@ static void add_corner_arc(SkPath* path, const SkRect& rect,
path->arcTo(r, start, sweep, forceMoveTo);
}
void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[],
void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir) {
assert_known_direction(dir);
// abort before we invoke SkAutoPathBoundsUpdate()
if (rect.isEmpty()) {
return;
}
SkAutoPathBoundsUpdate apbu(this, rect);
if (kCW_Direction == dir) {
add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false);
add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false);
} else {
add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
add_corner_arc(this, rect, rad[6], rad[7], 90, dir, false);
add_corner_arc(this, rect, rad[4], rad[5], 0, dir, false);
add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
}
this->close();
SkRRect rrect;
rrect.setRectRadii(rect, (const SkVector*) radii);
this->addRRect(rrect, dir);
}
void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
assert_known_direction(dir);
if (rrect.isEmpty()) {
return;
}
const SkRect& bounds = rrect.getBounds();
if (rrect.isRect()) {
@ -1099,7 +1091,20 @@ void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
const SkVector& rad = rrect.getSimpleRadii();
this->addRoundRect(bounds, rad.x(), rad.y(), dir);
} else {
this->addRoundRect(bounds, (const SkScalar*)&rrect.fRadii[0], dir);
SkAutoPathBoundsUpdate apbu(this, bounds);
if (kCW_Direction == dir) {
add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false);
add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false);
} else {
add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false);
add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false);
add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
}
this->close();
}
}