зеркало из https://github.com/mozilla/moz-skia.git
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:
Родитель
28bee9591d
Коммит
e28ff55d98
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче