change hairline procs to take array of points
BUG=skia:
Review URL: https://codereview.chromium.org/1085883002
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 636eaa6..878dca5 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -381,15 +381,13 @@
static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count; i += 2) {
- SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
+ SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
}
}
static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
- for (int i = 0; i < count - 1; i++) {
- SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
- }
+ SkScan::HairLine(devPts, count, *rec.fRC, blitter);
}
// aa versions
@@ -397,15 +395,13 @@
static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count; i += 2) {
- SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
+ SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
}
}
static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
- for (int i = 0; i < count - 1; i++) {
- SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
- }
+ SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
}
// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
@@ -1876,9 +1872,7 @@
///////////////////////////////////////////////////////////////////////////////
-typedef void (*HairProc)(SkPoint, SkPoint, const SkRasterClip&, SkBlitter*);
-
-static HairProc ChooseHairProc(bool doAntiAlias) {
+static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) {
return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
}
@@ -2144,12 +2138,13 @@
}
} else {
// no colors[] and no texture, stroke hairlines with paint's color.
- HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
+ SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias());
const SkRasterClip& clip = *fRC;
while (vertProc(&state)) {
- hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get());
- hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get());
- hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get());
+ SkPoint array[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0]
+ };
+ hairProc(array, 4, clip, blitter.get());
}
}
}
diff --git a/src/core/SkScan.h b/src/core/SkScan.h
index 96c58c5..ef44873 100644
--- a/src/core/SkScan.h
+++ b/src/core/SkScan.h
@@ -24,6 +24,15 @@
class SkScan {
public:
+ /*
+ * Draws count-1 line segments, one at a time:
+ * line(pts[0], pts[1])
+ * line(pts[1], pts[2])
+ * line(......, pts[count - 1])
+ */
+ typedef void (*HairRgnProc)(const SkPoint[], int count, const SkRegion*, SkBlitter*);
+ typedef void (*HairRCProc)(const SkPoint[], int count, const SkRasterClip&, SkBlitter*);
+
static void FillPath(const SkPath&, const SkIRect&, SkBlitter*);
///////////////////////////////////////////////////////////////////////////
@@ -41,8 +50,8 @@
static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
const SkRasterClip&, SkBlitter*);
static void FillTriangle(const SkPoint pts[], const SkRasterClip&, SkBlitter*);
- static void HairLine(SkPoint, SkPoint, const SkRasterClip&, SkBlitter*);
- static void AntiHairLine(SkPoint, SkPoint, const SkRasterClip&, SkBlitter*);
+ static void HairLine(const SkPoint[], int count, const SkRasterClip&, SkBlitter*);
+ static void AntiHairLine(const SkPoint[], int count, const SkRasterClip&, SkBlitter*);
static void HairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
static void AntiHairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
static void HairPath(const SkPath&, const SkRasterClip&, SkBlitter*);
@@ -64,8 +73,8 @@
static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
const SkRegion*, SkBlitter*);
- static void HairLineRgn(SkPoint, SkPoint, const SkRegion*, SkBlitter*);
- static void AntiHairLineRgn(SkPoint, SkPoint, const SkRegion*, SkBlitter*);
+ static void HairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*);
+ static void AntiHairLineRgn(const SkPoint[], int count, const SkRegion*, SkBlitter*);
};
/** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index c48ad2c..3073434 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -588,7 +588,8 @@
}
}
-void SkScan::AntiHairLineRgn(SkPoint pt0, SkPoint pt1, const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::AntiHairLineRgn(const SkPoint array[], int arrayCount, const SkRegion* clip,
+ SkBlitter* blitter) {
if (clip && clip->isEmpty()) {
return;
}
@@ -599,86 +600,83 @@
build_gamma_table();
#endif
- SkPoint pts[2] = { pt0, pt1 };
+ const SkScalar max = SkIntToScalar(32767);
+ const SkRect fixedBounds = SkRect::MakeLTRB(-max, -max, max, max);
- // We have to pre-clip the line to fit in a SkFixed, so we just chop
- // the line. TODO find a way to actually draw beyond that range.
- {
- SkRect fixedBounds;
- const SkScalar max = SkIntToScalar(32767);
- fixedBounds.set(-max, -max, max, max);
- if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
- return;
- }
- }
-
+ SkRect clipBounds;
if (clip) {
- SkRect clipBounds;
clipBounds.set(clip->getBounds());
/* We perform integral clipping later on, but we do a scalar clip first
- to ensure that our coordinates are expressible in fixed/integers.
-
- antialiased hairlines can draw up to 1/2 of a pixel outside of
- their bounds, so we need to outset the clip before calling the
- clipper. To make the numerics safer, we outset by a whole pixel,
- since the 1/2 pixel boundary is important to the antihair blitter,
- we don't want to risk numerical fate by chopping on that edge.
+ to ensure that our coordinates are expressible in fixed/integers.
+
+ antialiased hairlines can draw up to 1/2 of a pixel outside of
+ their bounds, so we need to outset the clip before calling the
+ clipper. To make the numerics safer, we outset by a whole pixel,
+ since the 1/2 pixel boundary is important to the antihair blitter,
+ we don't want to risk numerical fate by chopping on that edge.
*/
clipBounds.outset(SK_Scalar1, SK_Scalar1);
-
- 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);
+ for (int i = 0; i < arrayCount - 1; ++i) {
+ SkPoint pts[2];
- 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)) {
- return;
+ // We have to pre-clip the line to fit in a SkFixed, so we just chop
+ // the line. TODO find a way to actually draw beyond that range.
+ if (!SkLineClipper::IntersectLine(&array[i], fixedBounds, pts)) {
+ continue;
}
- if (!clip->quickContains(ir)) {
- SkRegion::Cliperator iter(*clip, ir);
- const SkIRect* r = &iter.rect();
- while (!iter.done()) {
- do_anti_hairline(x0, y0, x1, y1, r, blitter);
- iter.next();
+ if (clip && !SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
+ continue;
+ }
+
+ 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)) {
+ continue;
}
- return;
+ if (!clip->quickContains(ir)) {
+ SkRegion::Cliperator iter(*clip, ir);
+ const SkIRect* r = &iter.rect();
+
+ while (!iter.done()) {
+ do_anti_hairline(x0, y0, x1, y1, r, blitter);
+ iter.next();
+ }
+ continue;
+ }
+ // fall through to no-clip case
}
- // fall through to no-clip case
+ do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
}
- do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
}
void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
SkBlitter* blitter) {
- SkPoint p0, p1;
+ SkPoint pts[5];
- p0.set(rect.fLeft, rect.fTop);
- p1.set(rect.fRight, rect.fTop);
- SkScan::AntiHairLine(p0, p1, clip, blitter);
- p0.set(rect.fRight, rect.fBottom);
- SkScan::AntiHairLine(p0, p1, clip, blitter);
- p1.set(rect.fLeft, rect.fBottom);
- SkScan::AntiHairLine(p0, p1, clip, blitter);
- p0.set(rect.fLeft, rect.fTop);
- SkScan::AntiHairLine(p0, p1, clip, blitter);
+ pts[0].set(rect.fLeft, rect.fTop);
+ pts[1].set(rect.fRight, rect.fTop);
+ pts[2].set(rect.fRight, rect.fBottom);
+ pts[3].set(rect.fLeft, rect.fBottom);
+ pts[4] = pts[0];
+ SkScan::AntiHairLine(pts, 5, clip, blitter);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index 8cce57b..0f2308b 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -40,102 +40,105 @@
}
#endif
-void SkScan::HairLineRgn(SkPoint pt0, SkPoint pt1, const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::HairLineRgn(const SkPoint array[], int arrayCount, const SkRegion* clip,
+ SkBlitter* origBlitter) {
SkBlitterClipper clipper;
- SkRect r;
SkIRect clipR, ptsR;
- SkPoint pts[2] = { pt0, pt1 };
- // We have to pre-clip the line to fit in a SkFixed, so we just chop
- // the line. TODO find a way to actually draw beyond that range.
- {
- SkRect fixedBounds;
- const SkScalar max = SkIntToScalar(32767);
- fixedBounds.set(-max, -max, max, max);
- if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
- return;
- }
+ const SkScalar max = SkIntToScalar(32767);
+ const SkRect fixedBounds = SkRect::MakeLTRB(-max, -max, max, max);
+
+ SkRect clipBounds;
+ if (clip) {
+ clipBounds.set(clip->getBounds());
}
- if (clip) {
+ for (int i = 0; i < arrayCount - 1; ++i) {
+ SkBlitter* blitter = origBlitter;
+
+ SkPoint pts[2];
+
+ // We have to pre-clip the line to fit in a SkFixed, so we just chop
+ // the line. TODO find a way to actually draw beyond that range.
+ if (!SkLineClipper::IntersectLine(&array[i], fixedBounds, pts)) {
+ continue;
+ }
+
// 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;
- }
- }
-
- SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
- SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
- SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
- SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
-
- SkASSERT(canConvertFDot6ToFixed(x0));
- SkASSERT(canConvertFDot6ToFixed(y0));
- SkASSERT(canConvertFDot6ToFixed(x1));
- SkASSERT(canConvertFDot6ToFixed(y1));
-
- 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_FDot6One;
- ptsR.fBottom += SK_FDot6One;
-
- if (!SkIRect::Intersects(ptsR, clipR)) {
- return;
- }
- if (clip->isRect() && clipR.contains(ptsR)) {
- clip = NULL;
- } else {
- blitter = clipper.apply(blitter, clip);
- }
- }
-
- SkFDot6 dx = x1 - x0;
- SkFDot6 dy = y1 - y0;
-
- if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
- if (x0 > x1) { // we want to go left-to-right
- SkTSwap<SkFDot6>(x0, x1);
- SkTSwap<SkFDot6>(y0, y1);
- }
- int ix0 = SkFDot6Round(x0);
- int ix1 = SkFDot6Round(x1);
- if (ix0 == ix1) {// too short to draw
- return;
+ if (clip && !SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
+ continue;
}
- SkFixed slope = SkFixedDiv(dy, dx);
- SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6);
+ SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
+ SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
+ SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
+ SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
- horiline(ix0, ix1, startY, slope, blitter);
- } else { // mostly vertical
- if (y0 > y1) { // we want to go top-to-bottom
- SkTSwap<SkFDot6>(x0, x1);
- SkTSwap<SkFDot6>(y0, y1);
- }
- int iy0 = SkFDot6Round(y0);
- int iy1 = SkFDot6Round(y1);
- if (iy0 == iy1) { // too short to draw
- return;
+ SkASSERT(canConvertFDot6ToFixed(x0));
+ SkASSERT(canConvertFDot6ToFixed(y0));
+ SkASSERT(canConvertFDot6ToFixed(x1));
+ SkASSERT(canConvertFDot6ToFixed(y1));
+
+ 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_FDot6One;
+ ptsR.fBottom += SK_FDot6One;
+
+ if (!SkIRect::Intersects(ptsR, clipR)) {
+ continue;
+ }
+ if (!clip->isRect() || !clipR.contains(ptsR)) {
+ blitter = clipper.apply(origBlitter, clip);
+ }
}
- SkFixed slope = SkFixedDiv(dx, dy);
- SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6);
+ SkFDot6 dx = x1 - x0;
+ SkFDot6 dy = y1 - y0;
- vertline(iy0, iy1, startX, slope, blitter);
+ if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
+ if (x0 > x1) { // we want to go left-to-right
+ SkTSwap<SkFDot6>(x0, x1);
+ SkTSwap<SkFDot6>(y0, y1);
+ }
+ int ix0 = SkFDot6Round(x0);
+ int ix1 = SkFDot6Round(x1);
+ if (ix0 == ix1) {// too short to draw
+ continue;
+ }
+
+ SkFixed slope = SkFixedDiv(dy, dx);
+ SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6);
+
+ horiline(ix0, ix1, startY, slope, blitter);
+ } else { // mostly vertical
+ if (y0 > y1) { // we want to go top-to-bottom
+ SkTSwap<SkFDot6>(x0, x1);
+ SkTSwap<SkFDot6>(y0, y1);
+ }
+ int iy0 = SkFDot6Round(y0);
+ int iy1 = SkFDot6Round(y1);
+ if (iy0 == iy1) { // too short to draw
+ continue;
+ }
+
+ SkFixed slope = SkFixedDiv(dx, dy);
+ SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6);
+
+ vertline(iy0, iy1, startX, slope, blitter);
+ }
}
}
@@ -209,10 +212,8 @@
}
}
-typedef void (*LineProc)(SkPoint, SkPoint, const SkRegion*, SkBlitter*);
-
static void hairquad(const SkPoint pts[3], const SkRegion* clip,
- SkBlitter* blitter, int level, LineProc lineproc) {
+ SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) {
if (level > 0) {
SkPoint tmp[5];
@@ -220,12 +221,13 @@
hairquad(tmp, clip, blitter, level - 1, lineproc);
hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
} else {
- lineproc(pts[0], pts[2], clip, blitter);
+ SkPoint tmp[] = { pts[0], pts[2] };
+ lineproc(tmp, 2, clip, blitter);
}
}
static void haircubic(const SkPoint pts[4], const SkRegion* clip,
- SkBlitter* blitter, int level, LineProc lineproc) {
+ SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) {
if (level > 0) {
SkPoint tmp[7];
@@ -233,7 +235,8 @@
haircubic(tmp, clip, blitter, level - 1, lineproc);
haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
} else {
- lineproc(pts[0], pts[3], clip, blitter);
+ SkPoint tmp[] = { pts[0], pts[3] };
+ lineproc(tmp, 2, clip, blitter);
}
}
@@ -256,7 +259,7 @@
}
static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
- LineProc lineproc) {
+ SkScan::HairRgnProc lineproc) {
if (path.isEmpty()) {
return;
}
@@ -291,7 +294,7 @@
case SkPath::kMove_Verb:
break;
case SkPath::kLine_Verb:
- lineproc(pts[0], pts[1], clip, blitter);
+ lineproc(pts, 2, clip, blitter);
break;
case SkPath::kQuad_Verb:
hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
@@ -364,14 +367,15 @@
SkScan::FillRect(tmp, clip, blitter);
}
-void SkScan::HairLine(SkPoint p0, SkPoint p1, const SkRasterClip& clip, SkBlitter* blitter) {
+void SkScan::HairLine(const SkPoint pts[], int count, const SkRasterClip& clip,
+ SkBlitter* blitter) {
if (clip.isBW()) {
- HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+ HairLineRgn(pts, count, &clip.bwRgn(), blitter);
} else {
const SkRegion* clipRgn = NULL;
+
SkRect r;
- r.set(p0.fX, p0.fY, p1.fX, p1.fY);
- r.sort();
+ r.set(pts, count);
r.outset(SK_ScalarHalf, SK_ScalarHalf);
SkAAClipBlitterWrapper wrap;
@@ -380,18 +384,19 @@
blitter = wrap.getBlitter();
clipRgn = &wrap.getRgn();
}
- HairLineRgn(p0, p1, clipRgn, blitter);
+ HairLineRgn(pts, count, clipRgn, blitter);
}
}
-void SkScan::AntiHairLine(SkPoint p0, SkPoint p1, const SkRasterClip& clip, SkBlitter* blitter) {
+void SkScan::AntiHairLine(const SkPoint pts[], int count, const SkRasterClip& clip,
+ SkBlitter* blitter) {
if (clip.isBW()) {
- AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+ AntiHairLineRgn(pts, count, &clip.bwRgn(), blitter);
} else {
const SkRegion* clipRgn = NULL;
+
SkRect r;
- r.set(p0.fX, p0.fY, p1.fX, p1.fY);
- r.sort();
+ r.set(pts, count);
SkAAClipBlitterWrapper wrap;
if (!clip.quickContains(r.roundOut().makeOutset(1, 1))) {
@@ -399,6 +404,6 @@
blitter = wrap.getBlitter();
clipRgn = &wrap.getRgn();
}
- AntiHairLineRgn(p0, p1, clipRgn, blitter);
+ AntiHairLineRgn(pts, count, clipRgn, blitter);
}
}