diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-11-18 16:09:51 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-11-18 16:09:51 +0000 |
commit | 909994fbae0ffb532f42feac8859f8d86bbf64de (patch) | |
tree | 8fa0989863618109ed9f17c25b949d68f63bf541 /src/core/SkEdgeBuilder.cpp | |
parent | bb13586591bd412a0372aeb85d44159d2fa3f947 (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.cpp | 154 |
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(); +} + + |