| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkEdgeBuilder.h" | 7 #include "SkEdgeBuilder.h" |
| 8 #include "SkPath.h" | 8 #include "SkPath.h" |
| 9 #include "SkEdge.h" | 9 #include "SkEdge.h" |
| 10 #include "SkEdgeClipper.h" | 10 #include "SkEdgeClipper.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 return kPartial_Combine; | 55 return kPartial_Combine; |
| 56 } | 56 } |
| 57 last->fLastY = last->fFirstY - 1; | 57 last->fLastY = last->fFirstY - 1; |
| 58 last->fFirstY = edge->fFirstY; | 58 last->fFirstY = edge->fFirstY; |
| 59 last->fWinding = edge->fWinding; | 59 last->fWinding = edge->fWinding; |
| 60 return kPartial_Combine; | 60 return kPartial_Combine; |
| 61 } | 61 } |
| 62 return kNo_Combine; | 62 return kNo_Combine; |
| 63 } | 63 } |
| 64 | 64 |
| 65 static bool vertical_line(const SkEdge* edge) { | 65 SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical( |
| 66 const SkAnalyticEdge* edge, SkAnalyticEdge* last) { |
| 67 SkASSERT(fAnalyticAA); |
| 68 if (last->fCurveCount || last->fDX || edge->fX != last->fX) { |
| 69 return kNo_Combine; |
| 70 } |
| 71 if (edge->fWinding == last->fWinding) { |
| 72 if (edge->fLowerY == last->fUpperY) { |
| 73 last->fUpperY = edge->fUpperY; |
| 74 last->fY = last->fUpperY; |
| 75 return kPartial_Combine; |
| 76 } |
| 77 if (edge->fUpperY == last->fLowerY) { |
| 78 last->fLowerY = edge->fLowerY; |
| 79 return kPartial_Combine; |
| 80 } |
| 81 return kNo_Combine; |
| 82 } |
| 83 if (edge->fUpperY == last->fUpperY) { |
| 84 if (edge->fLowerY == last->fLowerY) { |
| 85 return kTotal_Combine; |
| 86 } |
| 87 if (edge->fLowerY < last->fLowerY) { |
| 88 last->fUpperY = edge->fLowerY; |
| 89 last->fY = last->fUpperY; |
| 90 return kPartial_Combine; |
| 91 } |
| 92 last->fUpperY = last->fLowerY; |
| 93 last->fY = last->fUpperY; |
| 94 last->fLowerY = edge->fLowerY; |
| 95 last->fWinding = edge->fWinding; |
| 96 return kPartial_Combine; |
| 97 } |
| 98 if (edge->fLowerY == last->fLowerY) { |
| 99 if (edge->fUpperY > last->fUpperY) { |
| 100 last->fLowerY = edge->fUpperY; |
| 101 return kPartial_Combine; |
| 102 } |
| 103 last->fLowerY = last->fUpperY; |
| 104 last->fUpperY = edge->fUpperY; |
| 105 last->fY = last->fUpperY; |
| 106 last->fWinding = edge->fWinding; |
| 107 return kPartial_Combine; |
| 108 } |
| 109 return kNo_Combine; |
| 110 } |
| 111 |
| 112 bool SkEdgeBuilder::vertical_line(const SkEdge* edge) { |
| 113 return !edge->fDX && !edge->fCurveCount; |
| 114 } |
| 115 |
| 116 bool SkEdgeBuilder::vertical_line(const SkAnalyticEdge* edge) { |
| 117 SkASSERT(fAnalyticAA); |
| 66 return !edge->fDX && !edge->fCurveCount; | 118 return !edge->fDX && !edge->fCurveCount; |
| 67 } | 119 } |
| 68 | 120 |
| 69 void SkEdgeBuilder::addLine(const SkPoint pts[]) { | 121 void SkEdgeBuilder::addLine(const SkPoint pts[]) { |
| 70 SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc); | 122 if (fAnalyticAA) { |
| 71 if (edge->setLine(pts[0], pts[1], fShiftUp)) { | 123 SkAnalyticEdge* edge = typedAllocThrow<SkAnalyticEdge>(fAlloc); |
| 72 if (vertical_line(edge) && fList.count()) { | 124 if (edge->setLine(pts[0], pts[1])) { |
| 73 Combine combine = CombineVertical(edge, *(fList.end() - 1)); | 125 if (vertical_line(edge) && fList.count()) { |
| 74 if (kNo_Combine != combine) { | 126 Combine combine = CombineVertical(edge, (SkAnalyticEdge*)*(fList
.end() - 1)); |
| 75 if (kTotal_Combine == combine) { | 127 if (kNo_Combine != combine) { |
| 76 fList.pop(); | 128 if (kTotal_Combine == combine) { |
| 129 fList.pop(); |
| 130 } |
| 131 goto unallocate_analytic_edge; |
| 77 } | 132 } |
| 78 goto unallocate_edge; | |
| 79 } | 133 } |
| 134 fList.push(edge); |
| 135 } else { |
| 136 unallocate_analytic_edge: |
| 137 ; |
| 138 // TODO: unallocate edge from storage... |
| 80 } | 139 } |
| 81 fList.push(edge); | |
| 82 } else { | 140 } else { |
| 141 SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc); |
| 142 if (edge->setLine(pts[0], pts[1], fShiftUp)) { |
| 143 if (vertical_line(edge) && fList.count()) { |
| 144 Combine combine = CombineVertical(edge, (SkEdge*)*(fList.end() -
1)); |
| 145 if (kNo_Combine != combine) { |
| 146 if (kTotal_Combine == combine) { |
| 147 fList.pop(); |
| 148 } |
| 149 goto unallocate_edge; |
| 150 } |
| 151 } |
| 152 fList.push(edge); |
| 153 } else { |
| 83 unallocate_edge: | 154 unallocate_edge: |
| 84 ; | 155 ; |
| 85 // TODO: unallocate edge from storage... | 156 // TODO: unallocate edge from storage... |
| 157 } |
| 86 } | 158 } |
| 87 } | 159 } |
| 88 | 160 |
| 89 void SkEdgeBuilder::addQuad(const SkPoint pts[]) { | 161 void SkEdgeBuilder::addQuad(const SkPoint pts[]) { |
| 90 SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc); | 162 if (fAnalyticAA) { |
| 91 if (edge->setQuadratic(pts, fShiftUp)) { | 163 SkAnalyticQuadraticEdge* edge = typedAllocThrow<SkAnalyticQuadraticEdge>
(fAlloc); |
| 92 fList.push(edge); | 164 if (edge->setQuadratic(pts)) { |
| 165 fList.push(edge); |
| 166 } else { |
| 167 // TODO: unallocate edge from storage... |
| 168 } |
| 93 } else { | 169 } else { |
| 94 // TODO: unallocate edge from storage... | 170 SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc); |
| 171 if (edge->setQuadratic(pts, fShiftUp)) { |
| 172 fList.push(edge); |
| 173 } else { |
| 174 // TODO: unallocate edge from storage... |
| 175 } |
| 95 } | 176 } |
| 96 } | 177 } |
| 97 | 178 |
| 98 void SkEdgeBuilder::addCubic(const SkPoint pts[]) { | 179 void SkEdgeBuilder::addCubic(const SkPoint pts[]) { |
| 99 SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc); | 180 if (fAnalyticAA) { |
| 100 if (edge->setCubic(pts, fShiftUp)) { | 181 SkAnalyticCubicEdge* edge = typedAllocThrow<SkAnalyticCubicEdge>(fAlloc)
; |
| 101 fList.push(edge); | 182 if (edge->setCubic(pts)) { |
| 183 fList.push(edge); |
| 184 } else { |
| 185 // TODO: unallocate edge from storage... |
| 186 } |
| 102 } else { | 187 } else { |
| 103 // TODO: unallocate edge from storage... | 188 SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc); |
| 189 if (edge->setCubic(pts, fShiftUp)) { |
| 190 fList.push(edge); |
| 191 } else { |
| 192 // TODO: unallocate edge from storage... |
| 193 } |
| 104 } | 194 } |
| 105 } | 195 } |
| 106 | 196 |
| 107 void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) { | 197 void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) { |
| 108 SkPoint pts[4]; | 198 SkPoint pts[4]; |
| 109 SkPath::Verb verb; | 199 SkPath::Verb verb; |
| 110 | 200 |
| 111 while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) { | 201 while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) { |
| 112 switch (verb) { | 202 switch (verb) { |
| 113 case SkPath::kLine_Verb: | 203 case SkPath::kLine_Verb: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 128 /////////////////////////////////////////////////////////////////////////////// | 218 /////////////////////////////////////////////////////////////////////////////// |
| 129 | 219 |
| 130 static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) { | 220 static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) { |
| 131 dst->set(SkIntToScalar(src.fLeft >> shift), | 221 dst->set(SkIntToScalar(src.fLeft >> shift), |
| 132 SkIntToScalar(src.fTop >> shift), | 222 SkIntToScalar(src.fTop >> shift), |
| 133 SkIntToScalar(src.fRight >> shift), | 223 SkIntToScalar(src.fRight >> shift), |
| 134 SkIntToScalar(src.fBottom >> shift)); | 224 SkIntToScalar(src.fBottom >> shift)); |
| 135 } | 225 } |
| 136 | 226 |
| 137 SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge**
edgePtr) { | 227 SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge**
edgePtr) { |
| 138 return !vertical_line(edge) || edgePtr <= fEdgeList ? kNo_Combine : | 228 return !vertical_line(edge) || edgePtr <= (SkEdge**)fEdgeList ? kNo_Combine
: |
| 139 CombineVertical(edge, edgePtr[-1]); | 229 CombineVertical(edge, edgePtr[-1]); |
| 140 } | 230 } |
| 141 | 231 |
| 232 SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkAnalyticEdge* edge, |
| 233 SkAnalyticEdge** edgePtr) { |
| 234 SkASSERT(fAnalyticAA); |
| 235 return !vertical_line(edge) || edgePtr <= (SkAnalyticEdge**)fEdgeList ? kNo_
Combine : |
| 236 CombineVertical(edge, edgePtr[-1]); |
| 237 } |
| 238 |
| 142 int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
Up, | 239 int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
Up, |
| 143 bool canCullToTheRight) { | 240 bool canCullToTheRight) { |
| 144 SkPath::Iter iter(path, true); | 241 SkPath::Iter iter(path, true); |
| 145 SkPoint pts[4]; | 242 SkPoint pts[4]; |
| 146 SkPath::Verb verb; | 243 SkPath::Verb verb; |
| 147 | 244 |
| 148 int maxEdgeCount = path.countPoints(); | 245 int maxEdgeCount = path.countPoints(); |
| 149 if (iclip) { | 246 if (iclip) { |
| 150 // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since | 247 // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since |
| 151 // we turn portions that are clipped out on the left/right into vertical | 248 // we turn portions that are clipped out on the left/right into vertical |
| 152 // segments. | 249 // segments. |
| 153 maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments; | 250 maxEdgeCount *= SkLineClipper::kMaxClippedLineSegments; |
| 154 } | 251 } |
| 155 size_t maxEdgeSize = maxEdgeCount * sizeof(SkEdge); | 252 size_t edgeSize = fAnalyticAA ? sizeof(SkAnalyticEdge) : sizeof(SkEdge); |
| 156 size_t maxEdgePtrSize = maxEdgeCount * sizeof(SkEdge*); | 253 size_t maxEdgeSize = maxEdgeCount * edgeSize; |
| 254 size_t maxEdgePtrSize = maxEdgeCount * sizeof(char*); |
| 157 | 255 |
| 158 // lets store the edges and their pointers in the same block | 256 // lets store the edges and their pointers in the same block |
| 159 char* storage = (char*)fAlloc.allocThrow(maxEdgeSize + maxEdgePtrSize); | 257 char* storage = (char*)fAlloc.allocThrow(maxEdgeSize + maxEdgePtrSize); |
| 160 SkEdge* edge = reinterpret_cast<SkEdge*>(storage); | 258 char* edge = (char*)storage; |
| 161 SkEdge** edgePtr = reinterpret_cast<SkEdge**>(storage + maxEdgeSize); | 259 char** edgePtr = (char**)(storage + maxEdgeSize); |
| 162 // Record the beginning of our pointers, so we can return them to the caller | 260 // Record the beginning of our pointers, so we can return them to the caller |
| 163 fEdgeList = edgePtr; | 261 fEdgeList = (void**)edgePtr; |
| 164 | 262 |
| 165 if (iclip) { | 263 if (iclip) { |
| 166 SkRect clip; | 264 SkRect clip; |
| 167 setShiftedClip(&clip, *iclip, shiftUp); | 265 setShiftedClip(&clip, *iclip, shiftUp); |
| 168 | 266 |
| 169 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { | 267 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { |
| 170 switch (verb) { | 268 switch (verb) { |
| 171 case SkPath::kMove_Verb: | 269 case SkPath::kMove_Verb: |
| 172 case SkPath::kClose_Verb: | 270 case SkPath::kClose_Verb: |
| 173 // we ignore these, and just get the whole segment from | 271 // we ignore these, and just get the whole segment from |
| 174 // the corresponding line/quad/cubic verbs | 272 // the corresponding line/quad/cubic verbs |
| 175 break; | 273 break; |
| 176 case SkPath::kLine_Verb: { | 274 case SkPath::kLine_Verb: { |
| 177 SkPoint lines[SkLineClipper::kMaxPoints]; | 275 SkPoint lines[SkLineClipper::kMaxPoints]; |
| 178 int lineCount = SkLineClipper::ClipLine(pts, clip, lines, ca
nCullToTheRight); | 276 int lineCount = SkLineClipper::ClipLine(pts, clip, lines, ca
nCullToTheRight); |
| 179 SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments
); | 277 SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments
); |
| 180 for (int i = 0; i < lineCount; i++) { | 278 for (int i = 0; i < lineCount; i++) { |
| 181 if (edge->setLine(lines[i], lines[i + 1], shiftUp)) { | 279 bool setLineResult = fAnalyticAA ? |
| 182 Combine combine = checkVertical(edge, edgePtr); | 280 ((SkAnalyticEdge*)edge)->setLine(lines[i], lines
[i + 1]) : |
| 281 ((SkEdge*)edge)->setLine(lines[i], lines[i + 1],
shiftUp); |
| 282 if (setLineResult) { |
| 283 Combine combine = fAnalyticAA ? |
| 284 checkVertical((SkAnalyticEdge*)edge, (SkAnal
yticEdge**)edgePtr) : |
| 285 checkVertical((SkEdge*)edge, (SkEdge**)edgeP
tr); |
| 183 if (kNo_Combine == combine) { | 286 if (kNo_Combine == combine) { |
| 184 *edgePtr++ = edge++; | 287 *edgePtr++ = edge; |
| 288 edge += edgeSize; |
| 185 } else if (kTotal_Combine == combine) { | 289 } else if (kTotal_Combine == combine) { |
| 186 --edgePtr; | 290 --edgePtr; |
| 187 } | 291 } |
| 188 } | 292 } |
| 189 } | 293 } |
| 190 break; | 294 break; |
| 191 } | 295 } |
| 192 default: | 296 default: |
| 193 SkDEBUGFAIL("unexpected verb"); | 297 SkDEBUGFAIL("unexpected verb"); |
| 194 break; | 298 break; |
| 195 } | 299 } |
| 196 } | 300 } |
| 197 } else { | 301 } else { |
| 198 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { | 302 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { |
| 199 switch (verb) { | 303 switch (verb) { |
| 200 case SkPath::kMove_Verb: | 304 case SkPath::kMove_Verb: |
| 201 case SkPath::kClose_Verb: | 305 case SkPath::kClose_Verb: |
| 202 // we ignore these, and just get the whole segment from | 306 // we ignore these, and just get the whole segment from |
| 203 // the corresponding line/quad/cubic verbs | 307 // the corresponding line/quad/cubic verbs |
| 204 break; | 308 break; |
| 205 case SkPath::kLine_Verb: | 309 case SkPath::kLine_Verb: { |
| 206 if (edge->setLine(pts[0], pts[1], shiftUp)) { | 310 bool setLineResult = fAnalyticAA ? |
| 207 Combine combine = checkVertical(edge, edgePtr); | 311 ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) : |
| 312 ((SkEdge*)edge)->setLine(pts[0], pts[1], shiftUp); |
| 313 if (setLineResult) { |
| 314 Combine combine = fAnalyticAA ? |
| 315 checkVertical((SkAnalyticEdge*)edge, (SkAnalytic
Edge**)edgePtr) : |
| 316 checkVertical((SkEdge*)edge, (SkEdge**)edgePtr); |
| 208 if (kNo_Combine == combine) { | 317 if (kNo_Combine == combine) { |
| 209 *edgePtr++ = edge++; | 318 *edgePtr++ = edge; |
| 319 edge += edgeSize; |
| 210 } else if (kTotal_Combine == combine) { | 320 } else if (kTotal_Combine == combine) { |
| 211 --edgePtr; | 321 --edgePtr; |
| 212 } | 322 } |
| 213 } | 323 } |
| 214 break; | 324 break; |
| 325 } |
| 215 default: | 326 default: |
| 216 SkDEBUGFAIL("unexpected verb"); | 327 SkDEBUGFAIL("unexpected verb"); |
| 217 break; | 328 break; |
| 218 } | 329 } |
| 219 } | 330 } |
| 220 } | 331 } |
| 221 SkASSERT((char*)edge <= (char*)fEdgeList); | 332 SkASSERT((char*)edge <= (char*)fEdgeList); |
| 222 SkASSERT(edgePtr - fEdgeList <= maxEdgeCount); | 333 SkASSERT(edgePtr - (char**)fEdgeList <= maxEdgeCount); |
| 223 return SkToInt(edgePtr - fEdgeList); | 334 return SkToInt(edgePtr - (char**)fEdgeList); |
| 224 } | 335 } |
| 225 | 336 |
| 226 static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { | 337 static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { |
| 227 SkPoint monoX[5]; | 338 SkPoint monoX[5]; |
| 228 int n = SkChopQuadAtYExtrema(pts, monoX); | 339 int n = SkChopQuadAtYExtrema(pts, monoX); |
| 229 for (int i = 0; i <= n; i++) { | 340 for (int i = 0; i <= n; i++) { |
| 230 builder->addQuad(&monoX[i * 2]); | 341 builder->addQuad(&monoX[i * 2]); |
| 231 } | 342 } |
| 232 } | 343 } |
| 233 | 344 |
| 234 int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp, | 345 int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp, |
| 235 bool canCullToTheRight) { | 346 bool canCullToTheRight, bool analyticAA) { |
| 236 fAlloc.reset(); | 347 fAlloc.reset(); |
| 237 fList.reset(); | 348 fList.reset(); |
| 238 fShiftUp = shiftUp; | 349 fShiftUp = shiftUp; |
| 350 fAnalyticAA = analyticAA; |
| 239 | 351 |
| 240 if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) { | 352 if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) { |
| 241 return this->buildPoly(path, iclip, shiftUp, canCullToTheRight); | 353 return this->buildPoly(path, iclip, shiftUp, canCullToTheRight); |
| 242 } | 354 } |
| 243 | 355 |
| 244 SkAutoConicToQuads quadder; | 356 SkAutoConicToQuads quadder; |
| 245 const SkScalar conicTol = SK_Scalar1 / 4; | 357 const SkScalar conicTol = SK_Scalar1 / 4; |
| 246 | 358 |
| 247 SkPath::Iter iter(path, true); | 359 SkPath::Iter iter(path, true); |
| 248 SkPoint pts[4]; | 360 SkPoint pts[4]; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 } | 438 } |
| 327 default: | 439 default: |
| 328 SkDEBUGFAIL("unexpected verb"); | 440 SkDEBUGFAIL("unexpected verb"); |
| 329 break; | 441 break; |
| 330 } | 442 } |
| 331 } | 443 } |
| 332 } | 444 } |
| 333 fEdgeList = fList.begin(); | 445 fEdgeList = fList.begin(); |
| 334 return fList.count(); | 446 return fList.count(); |
| 335 } | 447 } |
| OLD | NEW |