Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: src/core/SkClipStack.cpp

Issue 163683002: Store SkRRects in SkClipStack (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: fix unhandled enum value warning in unit test Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/core/SkCanvas.cpp ('k') | src/gpu/GrClipMaskManager.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2011 Google Inc. 3 * Copyright 2011 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 #include "SkClipStack.h" 8 #include "SkClipStack.h"
9 #include "SkPath.h" 9 #include "SkPath.h"
10 #include "SkThread.h" 10 #include "SkThread.h"
11 11
12 #include <new> 12 #include <new>
13 13
14 14
15 // 0-2 are reserved for invalid, empty & wide-open 15 // 0-2 are reserved for invalid, empty & wide-open
16 static const int32_t kFirstUnreservedGenID = 3; 16 static const int32_t kFirstUnreservedGenID = 3;
17 int32_t SkClipStack::gGenID = kFirstUnreservedGenID; 17 int32_t SkClipStack::gGenID = kFirstUnreservedGenID;
18 18
19 bool SkClipStack::Element::operator== (const Element& element) const {
20 if (this == &element) {
21 return true;
22 }
23 if (fOp != element.fOp ||
24 fType != element.fType ||
25 fDoAA != element.fDoAA ||
26 fSaveCount != element.fSaveCount) {
27 return false;
28 }
29 switch (fType) {
30 case kPath_Type:
31 return fPath == element.fPath;
32 case kRRect_Type:
33 return fRRect == element.fRRect;
34 case kRect_Type:
35 return fRect == element.fRect;
36 case kEmpty_Type:
37 return true;
38 default:
39 SkDEBUGFAIL("Unexpected type.");
40 return false;
41 }
42 }
43
19 void SkClipStack::Element::invertShapeFillType() { 44 void SkClipStack::Element::invertShapeFillType() {
20 switch (fType) { 45 switch (fType) {
21 case kRect_Type: 46 case kRect_Type:
22 fPath.reset(); 47 fPath.reset();
23 fPath.addRect(fRect); 48 fPath.addRect(fRect);
24 fPath.setFillType(SkPath::kInverseWinding_FillType); 49 fPath.setFillType(SkPath::kInverseEvenOdd_FillType);
50 fType = kPath_Type;
51 break;
52 case kRRect_Type:
53 fPath.reset();
54 fPath.addRRect(fRRect);
55 fPath.setFillType(SkPath::kInverseEvenOdd_FillType);
25 fType = kPath_Type; 56 fType = kPath_Type;
26 break; 57 break;
27 case kPath_Type: 58 case kPath_Type:
28 fPath.toggleInverseFillType(); 59 fPath.toggleInverseFillType();
60 break;
29 case kEmpty_Type: 61 case kEmpty_Type:
62 // Should this set to an empty, inverse filled path?
30 break; 63 break;
31 } 64 }
32 } 65 }
66
67 void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkRegion: :Op op,
68 bool doAA) {
69 if (!path.isInverseFillType()) {
70 if (SkPath::kNone_PathAsRect != path.asRect()) {
71 this->initRect(saveCount, path.getBounds(), op, doAA);
72 return;
73 }
74 SkRect ovalRect;
75 if (path.isOval(&ovalRect)) {
76 SkRRect rrect;
77 rrect.setOval(ovalRect);
78 this->initRRect(saveCount, rrect, op, doAA);
79 return;
80 }
81 }
82 fPath = path;
83 fType = kPath_Type;
84 this->initCommon(saveCount, op, doAA);
85 }
86
87 void SkClipStack::Element::asPath(SkPath* path) const {
88 switch (fType) {
89 case kEmpty_Type:
90 path->reset();
91 break;
92 case kRect_Type:
93 path->reset();
94 path->addRect(fRect);
95 break;
96 case kRRect_Type:
97 path->reset();
98 path->addRRect(fRRect);
99 break;
100 case kPath_Type:
101 *path = fPath;
102 break;
103 }
104 }
33 105
34 void SkClipStack::Element::checkEmpty() const { 106 void SkClipStack::Element::checkEmpty() const {
35 SkASSERT(fFiniteBound.isEmpty()); 107 SkASSERT(fFiniteBound.isEmpty());
36 SkASSERT(kNormal_BoundsType == fFiniteBoundType); 108 SkASSERT(kNormal_BoundsType == fFiniteBoundType);
37 SkASSERT(!fIsIntersectionOfRects); 109 SkASSERT(!fIsIntersectionOfRects);
38 SkASSERT(kEmptyGenID == fGenID); 110 SkASSERT(kEmptyGenID == fGenID);
39 SkASSERT(fPath.isEmpty()); 111 SkASSERT(fPath.isEmpty());
40 } 112 }
41 113
42 bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op o p) const { 114 bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op o p) const {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 // that aren't set are whatever isn't set in the previous 165 // that aren't set are whatever isn't set in the previous
94 // clip and whatever this clip carves out 166 // clip and whatever this clip carves out
95 fFiniteBound.join(prevFinite); 167 fFiniteBound.join(prevFinite);
96 fFiniteBoundType = kInsideOut_BoundsType; 168 fFiniteBoundType = kInsideOut_BoundsType;
97 break; 169 break;
98 case kPrev_InvCur_FillCombo: 170 case kPrev_InvCur_FillCombo:
99 // In this case everything outside of this clip's bound 171 // In this case everything outside of this clip's bound
100 // is erased, so the only pixels that can remain set 172 // is erased, so the only pixels that can remain set
101 // occur w/in the intersection of the two finite bounds 173 // occur w/in the intersection of the two finite bounds
102 if (!fFiniteBound.intersect(prevFinite)) { 174 if (!fFiniteBound.intersect(prevFinite)) {
103 fFiniteBound.setEmpty(); 175 this->setEmpty();
104 fGenID = kEmptyGenID; 176 } else {
177 fFiniteBoundType = kNormal_BoundsType;
105 } 178 }
106 fFiniteBoundType = kNormal_BoundsType;
107 break; 179 break;
108 case kPrev_Cur_FillCombo: 180 case kPrev_Cur_FillCombo:
109 // The most conservative result bound is that of the 181 // The most conservative result bound is that of the
110 // prior clip. This could be wildly incorrect if the 182 // prior clip. This could be wildly incorrect if the
111 // second clip either exactly matches the first clip 183 // second clip either exactly matches the first clip
112 // (which should yield the empty set) or reduces the 184 // (which should yield the empty set) or reduces the
113 // size of the prior bound (e.g., if the second clip 185 // size of the prior bound (e.g., if the second clip
114 // exactly matched the bottom half of the prior clip). 186 // exactly matched the bottom half of the prior clip).
115 // We ignore these two possibilities. 187 // We ignore these two possibilities.
116 fFiniteBound = prevFinite; 188 fFiniteBound = prevFinite;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 // are within the current clip 270 // are within the current clip
199 break; 271 break;
200 case kPrev_InvCur_FillCombo: 272 case kPrev_InvCur_FillCombo:
201 // In this case the only pixels that will remain writeable 273 // In this case the only pixels that will remain writeable
202 // are with the previous clip 274 // are with the previous clip
203 fFiniteBound = prevFinite; 275 fFiniteBound = prevFinite;
204 fFiniteBoundType = kNormal_BoundsType; 276 fFiniteBoundType = kNormal_BoundsType;
205 break; 277 break;
206 case kPrev_Cur_FillCombo: 278 case kPrev_Cur_FillCombo:
207 if (!fFiniteBound.intersect(prevFinite)) { 279 if (!fFiniteBound.intersect(prevFinite)) {
208 fFiniteBound.setEmpty(); 280 this->setEmpty();
209 fGenID = kEmptyGenID;
210 } 281 }
211 break; 282 break;
212 default: 283 default:
213 SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination"); 284 SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination");
214 break; 285 break;
215 } 286 }
216 } 287 }
217 288
218 // a mirror of combineBoundsDiff 289 // a mirror of combineBoundsDiff
219 void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& p revFinite) { 290 void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& p revFinite) {
220 291
221 switch (combination) { 292 switch (combination) {
222 case kInvPrev_InvCur_FillCombo: 293 case kInvPrev_InvCur_FillCombo:
223 // The only pixels that can survive are in the 294 // The only pixels that can survive are in the
224 // previous bound since the extensions to infinity in 295 // previous bound since the extensions to infinity in
225 // both clips cancel out 296 // both clips cancel out
226 fFiniteBound = prevFinite; 297 fFiniteBound = prevFinite;
227 fFiniteBoundType = kNormal_BoundsType; 298 fFiniteBoundType = kNormal_BoundsType;
228 break; 299 break;
229 case kInvPrev_Cur_FillCombo: 300 case kInvPrev_Cur_FillCombo:
230 if (!fFiniteBound.intersect(prevFinite)) { 301 if (!fFiniteBound.intersect(prevFinite)) {
231 fFiniteBound.setEmpty(); 302 this->setEmpty();
232 fGenID = kEmptyGenID; 303 } else {
304 fFiniteBoundType = kNormal_BoundsType;
233 } 305 }
234 fFiniteBoundType = kNormal_BoundsType;
235 break; 306 break;
236 case kPrev_InvCur_FillCombo: 307 case kPrev_InvCur_FillCombo:
237 fFiniteBound.join(prevFinite); 308 fFiniteBound.join(prevFinite);
238 fFiniteBoundType = kInsideOut_BoundsType; 309 fFiniteBoundType = kInsideOut_BoundsType;
239 break; 310 break;
240 case kPrev_Cur_FillCombo: 311 case kPrev_Cur_FillCombo:
241 // Fall through - as with the kDifference_Op case, the 312 // Fall through - as with the kDifference_Op case, the
242 // most conservative result bound is the bound of the 313 // most conservative result bound is the bound of the
243 // current clip. The prior clip could reduce the size of this 314 // current clip. The prior clip could reduce the size of this
244 // bound (as in the kDifference_Op case) but we are ignoring 315 // bound (as in the kDifference_Op case) but we are ignoring
245 // those cases. 316 // those cases.
246 break; 317 break;
247 default: 318 default:
248 SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination"); 319 SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination");
249 break; 320 break;
250 } 321 }
251 } 322 }
252 323
253 void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { 324 void SkClipStack::Element::updateBoundAndGenID(const Element* prior) {
254 // We set this first here but we may overwrite it later if we determine that the clip is 325 // We set this first here but we may overwrite it later if we determine that the clip is
255 // either wide-open or empty. 326 // either wide-open or empty.
256 fGenID = GetNextGenID(); 327 fGenID = GetNextGenID();
257 328
258 // First, optimistically update the current Element's bound information 329 // First, optimistically update the current Element's bound information
259 // with the current clip's bound 330 // with the current clip's bound
260 fIsIntersectionOfRects = false; 331 fIsIntersectionOfRects = false;
261 if (kRect_Type == fType) { 332 switch (fType) {
262 fFiniteBound = fRect; 333 case kRect_Type:
263 fFiniteBoundType = kNormal_BoundsType; 334 fFiniteBound = fRect;
335 fFiniteBoundType = kNormal_BoundsType;
264 336
265 if (SkRegion::kReplace_Op == fOp || 337 if (SkRegion::kReplace_Op == fOp ||
266 (SkRegion::kIntersect_Op == fOp && NULL == prior) || 338 (SkRegion::kIntersect_Op == fOp && NULL == prior) ||
267 (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && 339 (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects &&
268 prior->rectRectIntersectAllowed(fRect, fDoAA))) { 340 prior->rectRectIntersectAllowed(fRect, fDoAA))) {
269 fIsIntersectionOfRects = true; 341 fIsIntersectionOfRects = true;
270 } 342 }
343 break;
344 case kRRect_Type:
345 fFiniteBound = fRRect.getBounds();
346 fFiniteBoundType = kNormal_BoundsType;
347 break;
348 case kPath_Type:
349 fFiniteBound = fPath.getBounds();
271 350
272 } else { 351 if (fPath.isInverseFillType()) {
273 SkASSERT(kPath_Type == fType); 352 fFiniteBoundType = kInsideOut_BoundsType;
274 353 } else {
275 fFiniteBound = fPath.getBounds(); 354 fFiniteBoundType = kNormal_BoundsType;
276 355 }
277 if (fPath.isInverseFillType()) { 356 break;
278 fFiniteBoundType = kInsideOut_BoundsType; 357 case kEmpty_Type:
279 } else { 358 SkDEBUGFAIL("We shouldn't get here with an empty element.");
280 fFiniteBoundType = kNormal_BoundsType; 359 break;
281 }
282 } 360 }
283 361
284 if (!fDoAA) { 362 if (!fDoAA) {
285 // Here we mimic a non-anti-aliased scanline system. If there is 363 // Here we mimic a non-anti-aliased scanline system. If there is
286 // no anti-aliasing we can integerize the bounding box to exclude 364 // no anti-aliasing we can integerize the bounding box to exclude
287 // fractional parts that won't be rendered. 365 // fractional parts that won't be rendered.
288 // Note: the left edge is handled slightly differently below. We 366 // Note: the left edge is handled slightly differently below. We
289 // are a bit more generous in the rounding since we don't want to 367 // are a bit more generous in the rounding since we don't want to
290 // risk missing the left pixels when fLeft is very close to .5 368 // risk missing the left pixels when fLeft is very close to .5
291 fFiniteBound.set(SkScalarFloorToScalar(fFiniteBound.fLeft+0.45f), 369 fFiniteBound.set(SkScalarFloorToScalar(fFiniteBound.fLeft+0.45f),
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 break; 415 break;
338 case SkRegion::kReverseDifference_Op: 416 case SkRegion::kReverseDifference_Op:
339 this->combineBoundsRevDiff(combination, prevFinite); 417 this->combineBoundsRevDiff(combination, prevFinite);
340 break; 418 break;
341 case SkRegion::kReplace_Op: 419 case SkRegion::kReplace_Op:
342 // Replace just ignores everything prior 420 // Replace just ignores everything prior
343 // The current clip's bound information is already filled in 421 // The current clip's bound information is already filled in
344 // so nothing to do 422 // so nothing to do
345 break; 423 break;
346 default: 424 default:
347 SkDebugf("SkRegion::Op error/n"); 425 SkDebugf("SkRegion::Op error\n");
348 SkASSERT(0); 426 SkASSERT(0);
349 break; 427 break;
350 } 428 }
351 } 429 }
352 430
353 // This constant determines how many Element's are allocated together as a block in 431 // This constant determines how many Element's are allocated together as a block in
354 // the deque. As such it needs to balance allocating too much memory vs. 432 // the deque. As such it needs to balance allocating too much memory vs.
355 // incurring allocation/deallocation thrashing. It should roughly correspond to 433 // incurring allocation/deallocation thrashing. It should roughly correspond to
356 // the deepest save/restore stack we expect to see. 434 // the deepest save/restore stack we expect to see.
357 static const int kDefaultElementAllocCnt = 8; 435 static const int kDefaultElementAllocCnt = 8;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 } 599 }
522 } 600 }
523 if (SkRegion::kReplace_Op == element->getOp()) { 601 if (SkRegion::kReplace_Op == element->getOp()) {
524 break; 602 break;
525 } 603 }
526 element = iter.prev(); 604 element = iter.prev();
527 } 605 }
528 return true; 606 return true;
529 } 607 }
530 608
531 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 609 void SkClipStack::pushElement(const Element& element) {
532
533 // Use reverse iterator instead of back because Rect path may need previous 610 // Use reverse iterator instead of back because Rect path may need previous
534 SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); 611 SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart);
535 Element* element = (Element*) iter.prev(); 612 Element* prior = (Element*) iter.prev();
536 613
537 if (NULL != element) { 614 if (NULL != prior) {
538 if (element->canBeIntersectedInPlace(fSaveCount, op)) { 615 if (prior->canBeIntersectedInPlace(fSaveCount, element.getOp())) {
539 switch (element->fType) { 616 switch (prior->fType) {
540 case Element::kEmpty_Type: 617 case Element::kEmpty_Type:
541 element->checkEmpty(); 618 SkDEBUGCODE(prior->checkEmpty();)
542 return; 619 return;
543 case Element::kRect_Type: 620 case Element::kRect_Type:
544 if (element->rectRectIntersectAllowed(rect, doAA)) { 621 if (Element::kRect_Type == element.getType()) {
545 if (!element->fRect.intersect(rect)) { 622 if (prior->rectRectIntersectAllowed(element.getRect(), e lement.isAA())) {
546 element->setEmpty(); 623 if (!prior->fRect.intersect(element.getRect())) {
624 prior->setEmpty();
625 return;
626 }
627
628 prior->fDoAA = element.isAA();
629 Element* priorPrior = (Element*) iter.prev();
630 prior->updateBoundAndGenID(priorPrior);
547 return; 631 return;
548 } 632 }
549 633 break;
550 element->fDoAA = doAA;
551 Element* prev = (Element*) iter.prev();
552 element->updateBoundAndGenID(prev);
553 return;
554 } 634 }
555 break; 635 // fallthrough
556 case Element::kPath_Type: 636 default:
557 if (!SkRect::Intersects(element->fPath.getBounds(), rect)) { 637 if (!SkRect::Intersects(prior->getBounds(), element.getBound s())) {
558 element->setEmpty(); 638 prior->setEmpty();
559 return; 639 return;
560 } 640 }
561 break; 641 break;
562 } 642 }
563 } else if (SkRegion::kReplace_Op == op) { 643 } else if (SkRegion::kReplace_Op == element.getOp()) {
564 this->restoreTo(fSaveCount - 1); 644 this->restoreTo(fSaveCount - 1);
565 element = (Element*) fDeque.back(); 645 prior = (Element*) fDeque.back();
566 } 646 }
567 } 647 }
568 new (fDeque.push_back()) Element(fSaveCount, rect, op, doAA); 648 Element* newElement = SkNEW_PLACEMENT_ARGS(fDeque.push_back(), Element, (ele ment));
569 ((Element*) fDeque.back())->updateBoundAndGenID(element); 649 newElement->updateBoundAndGenID(prior);
650 }
651
652 void SkClipStack::clipDevRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
653 Element element(fSaveCount, rrect, op, doAA);
654 this->pushElement(element);
655 }
656
657 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
658 Element element(fSaveCount, rect, op, doAA);
659 this->pushElement(element);
570 } 660 }
571 661
572 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { 662 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
573 SkRect alt; 663 Element element(fSaveCount, path, op, doAA);
574 if (path.isRect(&alt) && !path.isInverseFillType()) { 664 this->pushElement(element);
575 return this->clipDevRect(alt, op, doAA);
576 }
577
578 Element* element = (Element*)fDeque.back();
579 if (NULL != element) {
580 if (element->canBeIntersectedInPlace(fSaveCount, op)) {
581 const SkRect& pathBounds = path.getBounds();
582 switch (element->fType) {
583 case Element::kEmpty_Type:
584 element->checkEmpty();
585 return;
586 case Element::kRect_Type:
587 if (!SkRect::Intersects(element->fRect, pathBounds)) {
588 element->setEmpty();
589 return;
590 }
591 break;
592 case Element::kPath_Type:
593 if (!SkRect::Intersects(element->fPath.getBounds(), pathBoun ds)) {
594 element->setEmpty();
595 return;
596 }
597 break;
598 }
599 } else if (SkRegion::kReplace_Op == op) {
600 this->restoreTo(fSaveCount - 1);
601 element = (Element*) fDeque.back();
602 }
603 }
604 new (fDeque.push_back()) Element(fSaveCount, path, op, doAA);
605 ((Element*) fDeque.back())->updateBoundAndGenID(element);
606 } 665 }
607 666
608 void SkClipStack::clipEmpty() { 667 void SkClipStack::clipEmpty() {
609
610 Element* element = (Element*) fDeque.back(); 668 Element* element = (Element*) fDeque.back();
611 669
612 if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kInter sect_Op)) { 670 if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kInter sect_Op)) {
613 switch (element->fType) { 671 element->setEmpty();
614 case Element::kEmpty_Type:
615 element->checkEmpty();
616 return;
617 case Element::kRect_Type:
618 case Element::kPath_Type:
619 element->setEmpty();
620 return;
621 }
622 } 672 }
623 new (fDeque.push_back()) Element(fSaveCount); 673 new (fDeque.push_back()) Element(fSaveCount);
624 674
625 ((Element*)fDeque.back())->fGenID = kEmptyGenID; 675 ((Element*)fDeque.back())->fGenID = kEmptyGenID;
626 } 676 }
627 677
628 bool SkClipStack::isWideOpen() const { 678 bool SkClipStack::isWideOpen() const {
629 return this->getTopmostGenID() == kWideOpenGenID; 679 return this->getTopmostGenID() == kWideOpenGenID;
630 } 680 }
631 681
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 return kWideOpenGenID; 780 return kWideOpenGenID;
731 } 781 }
732 782
733 const Element* back = static_cast<const Element*>(fDeque.back()); 783 const Element* back = static_cast<const Element*>(fDeque.back());
734 if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.is Empty()) { 784 if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.is Empty()) {
735 return kWideOpenGenID; 785 return kWideOpenGenID;
736 } 786 }
737 787
738 return back->getGenID(); 788 return back->getGenID();
739 } 789 }
OLDNEW
« no previous file with comments | « src/core/SkCanvas.cpp ('k') | src/gpu/GrClipMaskManager.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698