retool clipping in hairlines to catch huge coordinates

git-svn-id: http://skia.googlecode.com/svn/trunk@436 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-11-19 20:46:39 +00:00
Родитель 28bee9591d
Коммит e28ff55d98
5 изменённых файлов: 181 добавлений и 84 удалений

Просмотреть файл

@ -23,6 +23,17 @@ public:
*/
static int ClipLine(const SkPoint pts[2], const SkRect& clip,
SkPoint lines[kMaxPoints]);
/* Intersect the line segment against the rect. If there is a non-empty
resulting segment, return true and set dst[] to that segment. If not,
return false and ignore dst[].
ClipLine is specialized for scan-conversion, as it adds vertical
segments on the sides to show where the line extended beyond the
left or right sides. IntersectLine does not.
*/
static bool IntersectLine(const SkPoint src[2], const SkRect& clip,
SkPoint dst[2]);
};
#endif

Просмотреть файл

@ -17,6 +17,18 @@
#include "SkLineClipper.h"
#include "SkEdgeClipper.h"
#define AUTO_ANIMATE true
static int test0(SkPoint pts[], SkRect* clip) {
pts[0].set(200000, 140);
pts[1].set(-740000, 483);
pts[2].set(1.00000102e-06f, 9.10000017e-05f);
clip->set(0, 0, 640, 480);
return 2;
}
///////////////////////////////////////////////////////////////////////////////
static void drawQuad(SkCanvas* canvas, const SkPoint pts[3], const SkPaint& p) {
SkPath path;
path.moveTo(pts[0]);
@ -47,10 +59,21 @@ static void check_clipper(int count, const SkPoint pts[], const SkRect& clip) {
}
}
static void line_clipper(const SkPoint src[], const SkRect& clip,
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
static void line_intersector(const SkPoint src[], const SkRect& clip,
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, src, p1);
SkPoint dst[2];
if (SkLineClipper::IntersectLine(src, clip, dst)) {
check_clipper(2, dst, clip);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, dst, p0);
}
}
static void line_clipper(const SkPoint src[], const SkRect& clip,
SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, src, p1);
SkPoint dst[SkLineClipper::kMaxPoints];
int count = SkLineClipper::ClipLine(src, clip, dst);
for (int i = 0; i < count; i++) {
@ -110,6 +133,7 @@ static void cubic_clipper(const SkPoint src[], const SkRect& clip,
}
static const clipper_proc gProcs[] = {
line_intersector,
line_clipper,
quad_clipper,
cubic_clipper
@ -139,7 +163,7 @@ class LineClipperView : public SkView {
public:
LineClipperView() {
fProcIndex = 2;
fProcIndex = 0;
fCounter = 0;
int x = (640 - W)/2;
@ -172,6 +196,8 @@ protected:
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
// fProcIndex = test0(fPts, &fClip);
SkPaint paint, paint1;
@ -194,7 +220,7 @@ protected:
paint1.setStyle(SkPaint::kStroke_Style);
gProcs[fProcIndex](fPts, fClip, canvas, paint, paint1);
if (true) {
if (AUTO_ANIMATE) {
this->randPts();
this->inval(NULL);
}

Просмотреть файл

@ -22,6 +22,68 @@ static SkScalar sect_with_vertical(const SkPoint src[2], SkScalar X) {
}
}
///////////////////////////////////////////////////////////////////////////////
bool SkLineClipper::IntersectLine(const SkPoint src[2], const SkRect& clip,
SkPoint dst[2]) {
SkRect bounds;
bounds.set(src, 2);
if (bounds.fLeft >= clip.fRight || clip.fLeft >= bounds.fRight ||
bounds.fTop >= clip.fBottom || clip.fTop >= bounds.fBottom) {
return false;
}
if (clip.contains(bounds)) {
if (src != dst) {
memcpy(dst, src, 2 * sizeof(SkPoint));
}
return true;
}
int index0, index1;
if (src[0].fY < src[1].fY) {
index0 = 0;
index1 = 1;
} else {
index0 = 1;
index1 = 0;
}
SkPoint tmp[2];
memcpy(tmp, src, sizeof(tmp));
// now compute Y intersections
if (tmp[index0].fY < clip.fTop) {
tmp[index0].set(sect_with_horizontal(src, clip.fTop), clip.fTop);
}
if (tmp[index1].fY > clip.fBottom) {
tmp[index1].set(sect_with_horizontal(src, clip.fBottom), clip.fBottom);
}
if (tmp[0].fX < tmp[1].fX) {
index0 = 0;
index1 = 1;
} else {
index0 = 1;
index1 = 0;
}
// check for quick-reject in X again, now that we may have been chopped
if (tmp[index1].fX <= clip.fLeft || tmp[index0].fX >= clip.fRight) {
return false;
}
if (tmp[index0].fX < clip.fLeft) {
tmp[index0].set(clip.fLeft, sect_with_vertical(src, clip.fLeft));
}
if (tmp[index1].fX > clip.fRight) {
tmp[index1].set(clip.fRight, sect_with_vertical(src, clip.fRight));
}
memcpy(dst, tmp, sizeof(tmp));
return true;
}
int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
SkPoint lines[]) {
int index0, index1;

Просмотреть файл

@ -18,6 +18,7 @@
#include "SkScan.h"
#include "SkBlitter.h"
#include "SkColorPriv.h"
#include "SkLineClipper.h"
#include "SkRegion.h"
#include "SkFDot6.h"
@ -423,33 +424,41 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
build_gamma_table();
#endif
SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
SkPoint pts[2] = { pt0, pt1 };
if (clip)
{
SkFDot6 left = SkMin32(x0, x1);
SkFDot6 top = SkMin32(y0, y1);
SkFDot6 right = SkMax32(x0, x1);
SkFDot6 bottom = SkMax32(y0, y1);
SkIRect ir;
if (clip) {
SkRect clipBounds;
clipBounds.set(clip->getBounds());
if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
return;
}
}
SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
if (clip) {
SkFDot6 left = SkMin32(x0, x1);
SkFDot6 top = SkMin32(y0, y1);
SkFDot6 right = SkMax32(x0, x1);
SkFDot6 bottom = SkMax32(y0, y1);
SkIRect ir;
ir.set( SkFDot6Floor(left) - 1,
SkFDot6Floor(top) - 1,
SkFDot6Ceil(right) + 1,
SkFDot6Ceil(bottom) + 1);
if (clip->quickReject(ir))
if (clip->quickReject(ir)) {
return;
if (!clip->quickContains(ir))
{
}
if (!clip->quickContains(ir)) {
SkRegion::Cliperator iter(*clip, ir);
const SkIRect* r = &iter.rect();
while (!iter.done())
{
while (!iter.done()) {
do_anti_hairline(x0, y0, x1, y1, r, blitter);
iter.next();
}
@ -462,19 +471,6 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
void SkScan::AntiHairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
{
if (clip)
{
SkIRect ir;
SkRect r = rect;
r.inset(-SK_Scalar1/2, -SK_Scalar1/2);
r.roundOut(&ir);
if (clip->quickReject(ir))
return;
if (clip->quickContains(ir))
clip = NULL;
}
SkPoint p0, p1;
p0.set(rect.fLeft, rect.fTop);
@ -631,41 +627,32 @@ static void antifillrect(const SkRect& r, SkBlitter* blitter) {
those to our version of antifillrect, which converts it into an XRect and
then calls the blit.
*/
void SkScan::AntiFillRect(const SkRect& r, const SkRegion* clip,
void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
SkBlitter* blitter) {
if (clip) {
SkRect newR;
newR.set(clip->getBounds());
if (!newR.intersect(origR)) {
return;
}
SkIRect outerBounds;
r.roundOut(&outerBounds);
newR.roundOut(&outerBounds);
if (clip->isRect()) {
const SkIRect& clipBounds = clip->getBounds();
if (clipBounds.contains(outerBounds)) {
antifillrect(r, blitter);
} else {
SkRect tmpR;
// this keeps our original edges fractional
tmpR.set(clipBounds);
if (tmpR.intersect(r)) {
antifillrect(tmpR, blitter);
}
}
antifillrect(newR, blitter);
} else {
SkRegion::Cliperator clipper(*clip, outerBounds);
const SkIRect& rr = clipper.rect();
while (!clipper.done()) {
SkRect tmpR;
// this keeps our original edges fractional
tmpR.set(rr);
if (tmpR.intersect(r)) {
antifillrect(tmpR, blitter);
newR.set(clipper.rect());
if (newR.intersect(origR)) {
antifillrect(newR, blitter);
}
clipper.next();
}
}
} else {
antifillrect(r, blitter);
antifillrect(origR, blitter);
}
}

Просмотреть файл

@ -19,6 +19,7 @@
#include "SkBlitter.h"
#include "SkRegion.h"
#include "SkFDot6.h"
#include "SkLineClipper.h"
static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter)
{
@ -43,38 +44,47 @@ static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitte
void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* clip, SkBlitter* blitter)
{
SkBlitterClipper clipper;
SkRect r;
SkIRect clipR, ptsR;
SkPoint pts[2] = { pt0, pt1 };
SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
if (clip)
{
SkRect r;
SkIRect ir;
SkPoint pts[2];
pts[0] = pt0;
pts[1] = pt1;
r.set(pts, 2);
r.roundOut(&ir);
// if we're given a horizontal or vertical line
// this rect could be empty (in area), in which case
// clip->quickReject() will always return true.
// hence we bloat the rect to avoid that case
if (ir.width() == 0)
ir.fRight += 1;
if (ir.height() == 0)
ir.fBottom += 1;
if (clip->quickReject(ir))
if (clip) {
// Perform a clip in scalar space, so we catch huge values which might
// be missed after we convert to SkFDot6 (overflow)
r.set(clip->getBounds());
if (!SkLineClipper::IntersectLine(pts, r, pts)) {
return;
if (clip->quickContains(ir))
}
}
SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
if (clip) {
// now perform clipping again, as the rounding to dot6 can wiggle us
// our rects are really dot6 rects, but since we've already used
// lineclipper, we know they will fit in 32bits (26.6)
const SkIRect& bounds = clip->getBounds();
clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom));
ptsR.set(x0, y0, x1, y1);
ptsR.sort();
// outset the right and bottom, to account for how hairlines are
// actually drawn, which may hit the pixel to the right or below of
// the coordinate
ptsR.fRight += SK_FDot61;
ptsR.fBottom += SK_FDot61;
if (!SkIRect::Intersects(ptsR, clipR)) {
return;
}
if (clip->isRect() && clipR.contains(ptsR)) {
clip = NULL;
else
{
} else {
blitter = clipper.apply(blitter, clip);
}
}
@ -120,6 +130,7 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* cl
// we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
// and double-hit the top-left.
// TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
{
SkBlitterClipper clipper;