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:
parent
0c8ec2f658
commit
4e18c7a9bb
150
gm/rrects.cpp
Normal file
150
gm/rrects.cpp
Normal 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); )
|
||||
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user