aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkEdgeBuilder.cpp
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-11-18 16:09:51 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-11-18 16:09:51 +0000
commit909994fbae0ffb532f42feac8859f8d86bbf64de (patch)
tree8fa0989863618109ed9f17c25b949d68f63bf541 /src/core/SkEdgeBuilder.cpp
parentbb13586591bd412a0372aeb85d44159d2fa3f947 (diff)
new scanconversion technique
This technique geometrically clips all segments against the clip bounds, ensuring that we never send a value to the edgelist that might overflow in fixedpoint. Current disabled in SkScan_Path.cpp by a #define. There are a few minor pixel differences between this and the old technique, as found by the gm tool, so at the moment this new code is off by default. git-svn-id: http://skia.googlecode.com/svn/trunk@432 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkEdgeBuilder.cpp')
-rw-r--r--src/core/SkEdgeBuilder.cpp154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
new file mode 100644
index 0000000000..0f8848809c
--- /dev/null
+++ b/src/core/SkEdgeBuilder.cpp
@@ -0,0 +1,154 @@
+#include "SkEdgeBuilder.h"
+#include "SkPath.h"
+#include "SkEdge.h"
+#include "SkEdgeClipper.h"
+#include "SkLineClipper.h"
+#include "SkGeometry.h"
+
+SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
+
+template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
+ return static_cast<T*>(alloc.allocThrow(sizeof(T)));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkEdgeBuilder::addLine(const SkPoint pts[]) {
+ SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
+ if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
+ fList.push(edge);
+ } else {
+ // TODO: unallocate edge from storage...
+ }
+}
+
+void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
+ SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
+ if (edge->setQuadratic(pts, fShiftUp)) {
+ fList.push(edge);
+ } else {
+ // TODO: unallocate edge from storage...
+ }
+}
+
+void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
+ SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
+ if (edge->setCubic(pts, NULL, fShiftUp)) {
+ fList.push(edge);
+ } else {
+ // TODO: unallocate edge from storage...
+ }
+}
+
+void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ this->addLine(pts);
+ break;
+ case SkPath::kQuad_Verb:
+ this->addQuad(pts);
+ break;
+ case SkPath::kCubic_Verb:
+ this->addCubic(pts);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
+ dst->set(SkIntToScalar(src.fLeft >> shift),
+ SkIntToScalar(src.fTop >> shift),
+ SkIntToScalar(src.fRight >> shift),
+ SkIntToScalar(src.fBottom >> shift));
+}
+
+int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
+ int shiftUp) {
+ fAlloc.reset();
+ fList.reset();
+ fShiftUp = shiftUp;
+
+ SkPath::Iter iter(path, true);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ if (iclip) {
+ SkRect clip;
+ setShiftedClip(&clip, *iclip, shiftUp);
+ SkEdgeClipper clipper;
+
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ case SkPath::kClose_Verb:
+ // we ignore these, and just get the whole segment from
+ // the corresponding line/quad/cubic verbs
+ break;
+ case SkPath::kLine_Verb: {
+ SkPoint lines[SkLineClipper::kMaxPoints];
+ int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
+ for (int i = 0; i < lineCount; i++) {
+ this->addLine(&lines[i]);
+ }
+ break;
+ }
+ case SkPath::kQuad_Verb:
+ if (clipper.clipQuad(pts, clip)) {
+ this->addClipper(&clipper);
+ }
+ break;
+ case SkPath::kCubic_Verb:
+ if (clipper.clipCubic(pts, clip)) {
+ this->addClipper(&clipper);
+ }
+ break;
+ default:
+ SkASSERT(!"unexpected verb");
+ break;
+ }
+ }
+ } else {
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ case SkPath::kClose_Verb:
+ // we ignore these, and just get the whole segment from
+ // the corresponding line/quad/cubic verbs
+ break;
+ case SkPath::kLine_Verb:
+ this->addLine(pts);
+ break;
+ case SkPath::kQuad_Verb: {
+ SkPoint monoX[5];
+ int n = SkChopQuadAtYExtrema(pts, monoX);
+ for (int i = 0; i <= n; i++) {
+ this->addQuad(&monoX[i * 2]);
+ }
+ break;
+ }
+ case SkPath::kCubic_Verb: {
+ SkPoint monoY[10];
+ int n = SkChopCubicAtYExtrema(pts, monoY);
+ for (int i = 0; i <= n; i++) {
+ this->addCubic(&monoY[i * 3]);
+ }
+ break;
+ }
+ default:
+ SkASSERT(!"unexpected verb");
+ break;
+ }
+ }
+ }
+ return fList.count();
+}
+
+