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/poly2poly.cpp',
|
||||||
'../gm/quadpaths.cpp',
|
'../gm/quadpaths.cpp',
|
||||||
'../gm/rrect.cpp',
|
'../gm/rrect.cpp',
|
||||||
|
'../gm/rrects.cpp',
|
||||||
'../gm/samplerstress.cpp',
|
'../gm/samplerstress.cpp',
|
||||||
'../gm/shaderbounds.cpp',
|
'../gm/shaderbounds.cpp',
|
||||||
'../gm/shadertext.cpp',
|
'../gm/shadertext.cpp',
|
||||||
|
@ -662,14 +662,20 @@ public:
|
|||||||
* @param radii Array of 8 scalars, 4 [X,Y] pairs for each corner
|
* @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
|
* @param dir The direction to wind the rectangle's contour. Cannot be
|
||||||
* kUnknown_Direction.
|
* 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[],
|
void addRoundRect(const SkRect& rect, const SkScalar radii[],
|
||||||
Direction dir = kCW_Direction);
|
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
|
* 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,
|
static void add_corner_arc(SkPath* path, const SkRect& rect,
|
||||||
SkScalar rx, SkScalar ry, int startAngle,
|
SkScalar rx, SkScalar ry, int startAngle,
|
||||||
SkPath::Direction dir, bool forceMoveTo) {
|
SkPath::Direction dir, bool forceMoveTo) {
|
||||||
rx = SkMinScalar(SkScalarHalf(rect.width()), rx);
|
// These two asserts are not sufficient, since really we want to know
|
||||||
ry = SkMinScalar(SkScalarHalf(rect.height()), ry);
|
// 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;
|
SkRect r;
|
||||||
r.set(-rx, -ry, rx, ry);
|
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);
|
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) {
|
Direction dir) {
|
||||||
assert_known_direction(dir);
|
SkRRect rrect;
|
||||||
|
rrect.setRectRadii(rect, (const SkVector*) radii);
|
||||||
// abort before we invoke SkAutoPathBoundsUpdate()
|
this->addRRect(rrect, dir);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
|
void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
|
||||||
|
assert_known_direction(dir);
|
||||||
|
|
||||||
|
if (rrect.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const SkRect& bounds = rrect.getBounds();
|
const SkRect& bounds = rrect.getBounds();
|
||||||
|
|
||||||
if (rrect.isRect()) {
|
if (rrect.isRect()) {
|
||||||
@ -1099,7 +1091,20 @@ void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
|
|||||||
const SkVector& rad = rrect.getSimpleRadii();
|
const SkVector& rad = rrect.getSimpleRadii();
|
||||||
this->addRoundRect(bounds, rad.x(), rad.y(), dir);
|
this->addRoundRect(bounds, rad.x(), rad.y(), dir);
|
||||||
} else {
|
} 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