aboutsummaryrefslogtreecommitdiffhomepage
path: root/libs/graphics/sgl/SkScan_Hairline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/graphics/sgl/SkScan_Hairline.cpp')
-rw-r--r--libs/graphics/sgl/SkScan_Hairline.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/libs/graphics/sgl/SkScan_Hairline.cpp b/libs/graphics/sgl/SkScan_Hairline.cpp
new file mode 100644
index 0000000000..2af9e12163
--- /dev/null
+++ b/libs/graphics/sgl/SkScan_Hairline.cpp
@@ -0,0 +1,254 @@
+#include "SkScan.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+#include "SkFDot6.h"
+
+static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter)
+{
+ SkASSERT(x < stopx);
+
+ do {
+ blitter->blitH(x, fy >> 16, 1);
+ fy += dy;
+ } while (++x < stopx);
+}
+
+static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter)
+{
+ SkASSERT(y < stopy);
+
+ do {
+ blitter->blitH(fx >> 16, y, 1);
+ fx += dx;
+ } while (++y < stopy);
+}
+
+void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* clip, SkBlitter* blitter)
+{
+ SkBlitterClipper clipper;
+
+ SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
+ SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
+ SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
+ SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
+
+ if (clip)
+ {
+ SkRect r;
+ SkRect16 ir;
+ SkPoint pts[2];
+
+ pts[0] = pt0;
+ pts[1] = pt1;
+ r.set(pts, 2);
+ r.roundOut(&ir);
+
+ if (clip->quickReject(ir))
+ return;
+ if (clip->quickContains(ir))
+ clip = nil;
+ 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;
+
+ SkFixed slope = SkFixedDiv(dy, dx);
+ SkFixed startY = SkFDot6ToFixed(y0 + SkFixedMul(slope, (32 - x0) & 63));
+
+ 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;
+
+ SkFixed slope = SkFixedDiv(dx, dy);
+ SkFixed startX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));
+
+ vertline(iy0, iy1, startX, slope, blitter);
+ }
+}
+
+void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
+{
+ SkPoint p0, p1;
+
+ p0.set(rect.fLeft, rect.fTop);
+ p1.set(rect.fRight, rect.fTop);
+ SkScan::HairLine(p0, p1, clip, blitter);
+ p0.set(rect.fRight, rect.fBottom);
+ SkScan::HairLine(p0, p1, clip, blitter);
+ p1.set(rect.fLeft, rect.fBottom);
+ SkScan::HairLine(p0, p1, clip, blitter);
+ p0.set(rect.fLeft, rect.fTop);
+ SkScan::HairLine(p0, p1, clip, blitter);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPath.h"
+#include "SkGeometry.h"
+
+static bool quad_too_curvy(const SkPoint pts[3])
+{
+ return true;
+}
+
+static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level,
+ void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*))
+{
+#if 1
+ if (level > 0 && quad_too_curvy(pts))
+ {
+ SkPoint tmp[5];
+
+ SkChopQuadAtHalf(pts, tmp);
+ hairquad(tmp, clip, blitter, level - 1, lineproc);
+ hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
+ }
+ else
+ lineproc(pts[0], pts[2], clip, blitter);
+#else
+ lineproc(pts[0], pts[1], clip, blitter);
+ lineproc(pts[1], pts[2], clip, blitter);
+#endif
+}
+
+static bool cubic_too_curvy(const SkPoint pts[4])
+{
+ return true;
+}
+
+static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, int level,
+ void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
+{
+ if (level > 0 && cubic_too_curvy(pts))
+ {
+ SkPoint tmp[7];
+
+ SkChopCubicAt(pts, tmp, SK_Scalar1/2);
+ haircubic(tmp, clip, blitter, level - 1, lineproc);
+ haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
+ }
+ else
+ lineproc(pts[0], pts[3], clip, blitter);
+}
+
+#define kMaxCubicSubdivideLevel 6
+#define kMaxQuadSubdivideLevel 5
+
+static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitter,
+ void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
+{
+ if (path.isEmpty())
+ return;
+
+ const SkRect16* clipR = nil;
+
+ if (clip)
+ {
+ SkRect bounds;
+ SkRect16 ibounds;
+
+ path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+ bounds.roundOut(&ibounds);
+ ibounds.inset(-1, -1);
+
+ if (clip->quickReject(ibounds))
+ return;
+
+ if (clip->quickContains(ibounds))
+ clip = nil;
+ else
+ clipR = &clip->getBounds();
+ }
+
+ SkPath::Iter iter(path, false);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb)
+ {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ lineproc(pts[0], pts[1], clip, blitter);
+ break;
+ case SkPath::kQuad_Verb:
+ hairquad(pts, clip, blitter, kMaxQuadSubdivideLevel, lineproc);
+ break;
+ case SkPath::kCubic_Verb:
+ haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void SkScan::HairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+ hair_path(path, clip, blitter, SkScan::HairLine);
+}
+
+void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+ hair_path(path, clip, blitter, SkScan::AntiHairLine);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SkScan::FrameRect(const SkRect& r, SkScalar diameter, const SkRegion* clip, SkBlitter* blitter)
+{
+ SkASSERT(diameter > 0);
+
+ if (r.isEmpty())
+ return;
+
+ SkScalar radius = diameter / 2;
+ SkRect outer, tmp;
+
+ outer.set( r.fLeft - radius, r.fTop - radius,
+ r.fRight + radius, r.fBottom + radius);
+
+ if (r.width() <= diameter || r.height() <= diameter)
+ {
+ SkScan::FillRect(outer, clip, blitter);
+ return;
+ }
+
+ tmp.set(outer.fLeft, outer.fTop, outer.fRight, outer.fTop + diameter);
+ SkScan::FillRect(tmp, clip, blitter);
+ tmp.fTop = outer.fBottom - diameter;
+ tmp.fBottom = outer.fBottom;
+ SkScan::FillRect(tmp, clip, blitter);
+
+ tmp.set(outer.fLeft, outer.fTop + diameter, outer.fLeft + diameter, outer.fBottom - diameter);
+ SkScan::FillRect(tmp, clip, blitter);
+ tmp.fLeft = outer.fRight - diameter;
+ tmp.fRight = outer.fRight;
+ SkScan::FillRect(tmp, clip, blitter);
+}
+