diff options
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(); +} + + |