1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SkEdgeBuilder.h" 9#include "SkPath.h" 10#include "SkEdge.h" 11#include "SkEdgeClipper.h" 12#include "SkLineClipper.h" 13#include "SkGeometry.h" 14 15SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {} 16 17template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) { 18 return static_cast<T*>(alloc.allocThrow(sizeof(T))); 19} 20 21/////////////////////////////////////////////////////////////////////////////// 22 23void SkEdgeBuilder::addLine(const SkPoint pts[]) { 24 SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc); 25 if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) { 26 fList.push(edge); 27 } else { 28 // TODO: unallocate edge from storage... 29 } 30} 31 32void SkEdgeBuilder::addQuad(const SkPoint pts[]) { 33 SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc); 34 if (edge->setQuadratic(pts, fShiftUp)) { 35 fList.push(edge); 36 } else { 37 // TODO: unallocate edge from storage... 38 } 39} 40 41void SkEdgeBuilder::addCubic(const SkPoint pts[]) { 42 SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc); 43 if (edge->setCubic(pts, NULL, fShiftUp)) { 44 fList.push(edge); 45 } else { 46 // TODO: unallocate edge from storage... 47 } 48} 49 50void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) { 51 SkPoint pts[4]; 52 SkPath::Verb verb; 53 54 while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) { 55 switch (verb) { 56 case SkPath::kLine_Verb: 57 this->addLine(pts); 58 break; 59 case SkPath::kQuad_Verb: 60 this->addQuad(pts); 61 break; 62 case SkPath::kCubic_Verb: 63 this->addCubic(pts); 64 break; 65 default: 66 break; 67 } 68 } 69} 70 71/////////////////////////////////////////////////////////////////////////////// 72 73static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) { 74 dst->set(SkIntToScalar(src.fLeft >> shift), 75 SkIntToScalar(src.fTop >> shift), 76 SkIntToScalar(src.fRight >> shift), 77 SkIntToScalar(src.fBottom >> shift)); 78} 79 80int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, 81 int shiftUp) { 82 fAlloc.reset(); 83 fList.reset(); 84 fShiftUp = shiftUp; 85 86 SkPath::Iter iter(path, true); 87 SkPoint pts[4]; 88 SkPath::Verb verb; 89 90 if (iclip) { 91 SkRect clip; 92 setShiftedClip(&clip, *iclip, shiftUp); 93 SkEdgeClipper clipper; 94 95 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 96 switch (verb) { 97 case SkPath::kMove_Verb: 98 case SkPath::kClose_Verb: 99 // we ignore these, and just get the whole segment from 100 // the corresponding line/quad/cubic verbs 101 break; 102 case SkPath::kLine_Verb: { 103 SkPoint lines[SkLineClipper::kMaxPoints]; 104 int lineCount = SkLineClipper::ClipLine(pts, clip, lines); 105 for (int i = 0; i < lineCount; i++) { 106 this->addLine(&lines[i]); 107 } 108 break; 109 } 110 case SkPath::kQuad_Verb: 111 if (clipper.clipQuad(pts, clip)) { 112 this->addClipper(&clipper); 113 } 114 break; 115 case SkPath::kCubic_Verb: 116 if (clipper.clipCubic(pts, clip)) { 117 this->addClipper(&clipper); 118 } 119 break; 120 default: 121 SkDEBUGFAIL("unexpected verb"); 122 break; 123 } 124 } 125 } else { 126 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 127 switch (verb) { 128 case SkPath::kMove_Verb: 129 case SkPath::kClose_Verb: 130 // we ignore these, and just get the whole segment from 131 // the corresponding line/quad/cubic verbs 132 break; 133 case SkPath::kLine_Verb: 134 this->addLine(pts); 135 break; 136 case SkPath::kQuad_Verb: { 137 SkPoint monoX[5]; 138 int n = SkChopQuadAtYExtrema(pts, monoX); 139 for (int i = 0; i <= n; i++) { 140 this->addQuad(&monoX[i * 2]); 141 } 142 break; 143 } 144 case SkPath::kCubic_Verb: { 145 SkPoint monoY[10]; 146 int n = SkChopCubicAtYExtrema(pts, monoY); 147 for (int i = 0; i <= n; i++) { 148 this->addCubic(&monoY[i * 3]); 149 } 150 break; 151 } 152 default: 153 SkDEBUGFAIL("unexpected verb"); 154 break; 155 } 156 } 157 } 158 return fList.count(); 159} 160 161 162