1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkClipStack.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,827 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkClipStack.h" 1.12 +#include "SkPath.h" 1.13 +#include "SkThread.h" 1.14 + 1.15 +#include <new> 1.16 + 1.17 + 1.18 +// 0-2 are reserved for invalid, empty & wide-open 1.19 +static const int32_t kFirstUnreservedGenID = 3; 1.20 +int32_t SkClipStack::gGenID = kFirstUnreservedGenID; 1.21 + 1.22 +SkClipStack::Element::Element(const Element& that) { 1.23 + switch (that.getType()) { 1.24 + case kEmpty_Type: 1.25 + fPath.reset(); 1.26 + break; 1.27 + case kRect_Type: // Rect uses rrect 1.28 + case kRRect_Type: 1.29 + fPath.reset(); 1.30 + fRRect = that.fRRect; 1.31 + break; 1.32 + case kPath_Type: 1.33 + fPath.set(that.getPath()); 1.34 + break; 1.35 + } 1.36 + 1.37 + fSaveCount = that.fSaveCount; 1.38 + fOp = that.fOp; 1.39 + fType = that.fType; 1.40 + fDoAA = that.fDoAA; 1.41 + fFiniteBoundType = that.fFiniteBoundType; 1.42 + fFiniteBound = that.fFiniteBound; 1.43 + fIsIntersectionOfRects = that.fIsIntersectionOfRects; 1.44 + fGenID = that.fGenID; 1.45 +} 1.46 + 1.47 +bool SkClipStack::Element::operator== (const Element& element) const { 1.48 + if (this == &element) { 1.49 + return true; 1.50 + } 1.51 + if (fOp != element.fOp || 1.52 + fType != element.fType || 1.53 + fDoAA != element.fDoAA || 1.54 + fSaveCount != element.fSaveCount) { 1.55 + return false; 1.56 + } 1.57 + switch (fType) { 1.58 + case kPath_Type: 1.59 + return this->getPath() == element.getPath(); 1.60 + case kRRect_Type: 1.61 + return fRRect == element.fRRect; 1.62 + case kRect_Type: 1.63 + return this->getRect() == element.getRect(); 1.64 + case kEmpty_Type: 1.65 + return true; 1.66 + default: 1.67 + SkDEBUGFAIL("Unexpected type."); 1.68 + return false; 1.69 + } 1.70 +} 1.71 + 1.72 +void SkClipStack::Element::invertShapeFillType() { 1.73 + switch (fType) { 1.74 + case kRect_Type: 1.75 + fPath.init(); 1.76 + fPath.get()->addRect(this->getRect()); 1.77 + fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType); 1.78 + fType = kPath_Type; 1.79 + break; 1.80 + case kRRect_Type: 1.81 + fPath.init(); 1.82 + fPath.get()->addRRect(fRRect); 1.83 + fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType); 1.84 + fType = kPath_Type; 1.85 + break; 1.86 + case kPath_Type: 1.87 + fPath.get()->toggleInverseFillType(); 1.88 + break; 1.89 + case kEmpty_Type: 1.90 + // Should this set to an empty, inverse filled path? 1.91 + break; 1.92 + } 1.93 +} 1.94 + 1.95 +void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkRegion::Op op, 1.96 + bool doAA) { 1.97 + if (!path.isInverseFillType()) { 1.98 + if (SkPath::kNone_PathAsRect != path.asRect()) { 1.99 + this->initRect(saveCount, path.getBounds(), op, doAA); 1.100 + return; 1.101 + } 1.102 + SkRect ovalRect; 1.103 + if (path.isOval(&ovalRect)) { 1.104 + SkRRect rrect; 1.105 + rrect.setOval(ovalRect); 1.106 + this->initRRect(saveCount, rrect, op, doAA); 1.107 + return; 1.108 + } 1.109 + } 1.110 + fPath.set(path); 1.111 + fType = kPath_Type; 1.112 + this->initCommon(saveCount, op, doAA); 1.113 +} 1.114 + 1.115 +void SkClipStack::Element::asPath(SkPath* path) const { 1.116 + switch (fType) { 1.117 + case kEmpty_Type: 1.118 + path->reset(); 1.119 + break; 1.120 + case kRect_Type: 1.121 + path->reset(); 1.122 + path->addRect(this->getRect()); 1.123 + break; 1.124 + case kRRect_Type: 1.125 + path->reset(); 1.126 + path->addRRect(fRRect); 1.127 + break; 1.128 + case kPath_Type: 1.129 + *path = *fPath.get(); 1.130 + break; 1.131 + } 1.132 +} 1.133 + 1.134 +void SkClipStack::Element::setEmpty() { 1.135 + fType = kEmpty_Type; 1.136 + fFiniteBound.setEmpty(); 1.137 + fFiniteBoundType = kNormal_BoundsType; 1.138 + fIsIntersectionOfRects = false; 1.139 + fRRect.setEmpty(); 1.140 + fPath.reset(); 1.141 + fGenID = kEmptyGenID; 1.142 + SkDEBUGCODE(this->checkEmpty();) 1.143 +} 1.144 + 1.145 +void SkClipStack::Element::checkEmpty() const { 1.146 + SkASSERT(fFiniteBound.isEmpty()); 1.147 + SkASSERT(kNormal_BoundsType == fFiniteBoundType); 1.148 + SkASSERT(!fIsIntersectionOfRects); 1.149 + SkASSERT(kEmptyGenID == fGenID); 1.150 + SkASSERT(!fPath.isValid()); 1.151 +} 1.152 + 1.153 +bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const { 1.154 + if (kEmpty_Type == fType && 1.155 + (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) { 1.156 + return true; 1.157 + } 1.158 + // Only clips within the same save/restore frame (as captured by 1.159 + // the save count) can be merged 1.160 + return fSaveCount == saveCount && 1.161 + SkRegion::kIntersect_Op == op && 1.162 + (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp); 1.163 +} 1.164 + 1.165 +bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const { 1.166 + SkASSERT(kRect_Type == fType); 1.167 + 1.168 + if (fDoAA == newAA) { 1.169 + // if the AA setting is the same there is no issue 1.170 + return true; 1.171 + } 1.172 + 1.173 + if (!SkRect::Intersects(this->getRect(), newR)) { 1.174 + // The calling code will correctly set the result to the empty clip 1.175 + return true; 1.176 + } 1.177 + 1.178 + if (this->getRect().contains(newR)) { 1.179 + // if the new rect carves out a portion of the old one there is no 1.180 + // issue 1.181 + return true; 1.182 + } 1.183 + 1.184 + // So either the two overlap in some complex manner or newR contains oldR. 1.185 + // In the first, case the edges will require different AA. In the second, 1.186 + // the AA setting that would be carried forward is incorrect (e.g., oldR 1.187 + // is AA while newR is BW but since newR contains oldR, oldR will be 1.188 + // drawn BW) since the new AA setting will predominate. 1.189 + return false; 1.190 +} 1.191 + 1.192 +// a mirror of combineBoundsRevDiff 1.193 +void SkClipStack::Element::combineBoundsDiff(FillCombo combination, const SkRect& prevFinite) { 1.194 + switch (combination) { 1.195 + case kInvPrev_InvCur_FillCombo: 1.196 + // In this case the only pixels that can remain set 1.197 + // are inside the current clip rect since the extensions 1.198 + // to infinity of both clips cancel out and whatever 1.199 + // is outside of the current clip is removed 1.200 + fFiniteBoundType = kNormal_BoundsType; 1.201 + break; 1.202 + case kInvPrev_Cur_FillCombo: 1.203 + // In this case the current op is finite so the only pixels 1.204 + // that aren't set are whatever isn't set in the previous 1.205 + // clip and whatever this clip carves out 1.206 + fFiniteBound.join(prevFinite); 1.207 + fFiniteBoundType = kInsideOut_BoundsType; 1.208 + break; 1.209 + case kPrev_InvCur_FillCombo: 1.210 + // In this case everything outside of this clip's bound 1.211 + // is erased, so the only pixels that can remain set 1.212 + // occur w/in the intersection of the two finite bounds 1.213 + if (!fFiniteBound.intersect(prevFinite)) { 1.214 + this->setEmpty(); 1.215 + } else { 1.216 + fFiniteBoundType = kNormal_BoundsType; 1.217 + } 1.218 + break; 1.219 + case kPrev_Cur_FillCombo: 1.220 + // The most conservative result bound is that of the 1.221 + // prior clip. This could be wildly incorrect if the 1.222 + // second clip either exactly matches the first clip 1.223 + // (which should yield the empty set) or reduces the 1.224 + // size of the prior bound (e.g., if the second clip 1.225 + // exactly matched the bottom half of the prior clip). 1.226 + // We ignore these two possibilities. 1.227 + fFiniteBound = prevFinite; 1.228 + break; 1.229 + default: 1.230 + SkDEBUGFAIL("SkClipStack::Element::combineBoundsDiff Invalid fill combination"); 1.231 + break; 1.232 + } 1.233 +} 1.234 + 1.235 +void SkClipStack::Element::combineBoundsXOR(int combination, const SkRect& prevFinite) { 1.236 + 1.237 + switch (combination) { 1.238 + case kInvPrev_Cur_FillCombo: // fall through 1.239 + case kPrev_InvCur_FillCombo: 1.240 + // With only one of the clips inverted the result will always 1.241 + // extend to infinity. The only pixels that may be un-writeable 1.242 + // lie within the union of the two finite bounds 1.243 + fFiniteBound.join(prevFinite); 1.244 + fFiniteBoundType = kInsideOut_BoundsType; 1.245 + break; 1.246 + case kInvPrev_InvCur_FillCombo: 1.247 + // The only pixels that can survive are within the 1.248 + // union of the two bounding boxes since the extensions 1.249 + // to infinity of both clips cancel out 1.250 + // fall through! 1.251 + case kPrev_Cur_FillCombo: 1.252 + // The most conservative bound for xor is the 1.253 + // union of the two bounds. If the two clips exactly overlapped 1.254 + // the xor could yield the empty set. Similarly the xor 1.255 + // could reduce the size of the original clip's bound (e.g., 1.256 + // if the second clip exactly matched the bottom half of the 1.257 + // first clip). We ignore these two cases. 1.258 + fFiniteBound.join(prevFinite); 1.259 + fFiniteBoundType = kNormal_BoundsType; 1.260 + break; 1.261 + default: 1.262 + SkDEBUGFAIL("SkClipStack::Element::combineBoundsXOR Invalid fill combination"); 1.263 + break; 1.264 + } 1.265 +} 1.266 + 1.267 +// a mirror of combineBoundsIntersection 1.268 +void SkClipStack::Element::combineBoundsUnion(int combination, const SkRect& prevFinite) { 1.269 + 1.270 + switch (combination) { 1.271 + case kInvPrev_InvCur_FillCombo: 1.272 + if (!fFiniteBound.intersect(prevFinite)) { 1.273 + fFiniteBound.setEmpty(); 1.274 + fGenID = kWideOpenGenID; 1.275 + } 1.276 + fFiniteBoundType = kInsideOut_BoundsType; 1.277 + break; 1.278 + case kInvPrev_Cur_FillCombo: 1.279 + // The only pixels that won't be drawable are inside 1.280 + // the prior clip's finite bound 1.281 + fFiniteBound = prevFinite; 1.282 + fFiniteBoundType = kInsideOut_BoundsType; 1.283 + break; 1.284 + case kPrev_InvCur_FillCombo: 1.285 + // The only pixels that won't be drawable are inside 1.286 + // this clip's finite bound 1.287 + break; 1.288 + case kPrev_Cur_FillCombo: 1.289 + fFiniteBound.join(prevFinite); 1.290 + break; 1.291 + default: 1.292 + SkDEBUGFAIL("SkClipStack::Element::combineBoundsUnion Invalid fill combination"); 1.293 + break; 1.294 + } 1.295 +} 1.296 + 1.297 +// a mirror of combineBoundsUnion 1.298 +void SkClipStack::Element::combineBoundsIntersection(int combination, const SkRect& prevFinite) { 1.299 + 1.300 + switch (combination) { 1.301 + case kInvPrev_InvCur_FillCombo: 1.302 + // The only pixels that aren't writable in this case 1.303 + // occur in the union of the two finite bounds 1.304 + fFiniteBound.join(prevFinite); 1.305 + fFiniteBoundType = kInsideOut_BoundsType; 1.306 + break; 1.307 + case kInvPrev_Cur_FillCombo: 1.308 + // In this case the only pixels that will remain writeable 1.309 + // are within the current clip 1.310 + break; 1.311 + case kPrev_InvCur_FillCombo: 1.312 + // In this case the only pixels that will remain writeable 1.313 + // are with the previous clip 1.314 + fFiniteBound = prevFinite; 1.315 + fFiniteBoundType = kNormal_BoundsType; 1.316 + break; 1.317 + case kPrev_Cur_FillCombo: 1.318 + if (!fFiniteBound.intersect(prevFinite)) { 1.319 + this->setEmpty(); 1.320 + } 1.321 + break; 1.322 + default: 1.323 + SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination"); 1.324 + break; 1.325 + } 1.326 +} 1.327 + 1.328 +// a mirror of combineBoundsDiff 1.329 +void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& prevFinite) { 1.330 + 1.331 + switch (combination) { 1.332 + case kInvPrev_InvCur_FillCombo: 1.333 + // The only pixels that can survive are in the 1.334 + // previous bound since the extensions to infinity in 1.335 + // both clips cancel out 1.336 + fFiniteBound = prevFinite; 1.337 + fFiniteBoundType = kNormal_BoundsType; 1.338 + break; 1.339 + case kInvPrev_Cur_FillCombo: 1.340 + if (!fFiniteBound.intersect(prevFinite)) { 1.341 + this->setEmpty(); 1.342 + } else { 1.343 + fFiniteBoundType = kNormal_BoundsType; 1.344 + } 1.345 + break; 1.346 + case kPrev_InvCur_FillCombo: 1.347 + fFiniteBound.join(prevFinite); 1.348 + fFiniteBoundType = kInsideOut_BoundsType; 1.349 + break; 1.350 + case kPrev_Cur_FillCombo: 1.351 + // Fall through - as with the kDifference_Op case, the 1.352 + // most conservative result bound is the bound of the 1.353 + // current clip. The prior clip could reduce the size of this 1.354 + // bound (as in the kDifference_Op case) but we are ignoring 1.355 + // those cases. 1.356 + break; 1.357 + default: 1.358 + SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination"); 1.359 + break; 1.360 + } 1.361 +} 1.362 + 1.363 +void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { 1.364 + // We set this first here but we may overwrite it later if we determine that the clip is 1.365 + // either wide-open or empty. 1.366 + fGenID = GetNextGenID(); 1.367 + 1.368 + // First, optimistically update the current Element's bound information 1.369 + // with the current clip's bound 1.370 + fIsIntersectionOfRects = false; 1.371 + switch (fType) { 1.372 + case kRect_Type: 1.373 + fFiniteBound = this->getRect(); 1.374 + fFiniteBoundType = kNormal_BoundsType; 1.375 + 1.376 + if (SkRegion::kReplace_Op == fOp || 1.377 + (SkRegion::kIntersect_Op == fOp && NULL == prior) || 1.378 + (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && 1.379 + prior->rectRectIntersectAllowed(this->getRect(), fDoAA))) { 1.380 + fIsIntersectionOfRects = true; 1.381 + } 1.382 + break; 1.383 + case kRRect_Type: 1.384 + fFiniteBound = fRRect.getBounds(); 1.385 + fFiniteBoundType = kNormal_BoundsType; 1.386 + break; 1.387 + case kPath_Type: 1.388 + fFiniteBound = fPath.get()->getBounds(); 1.389 + 1.390 + if (fPath.get()->isInverseFillType()) { 1.391 + fFiniteBoundType = kInsideOut_BoundsType; 1.392 + } else { 1.393 + fFiniteBoundType = kNormal_BoundsType; 1.394 + } 1.395 + break; 1.396 + case kEmpty_Type: 1.397 + SkDEBUGFAIL("We shouldn't get here with an empty element."); 1.398 + break; 1.399 + } 1.400 + 1.401 + if (!fDoAA) { 1.402 + // Here we mimic a non-anti-aliased scanline system. If there is 1.403 + // no anti-aliasing we can integerize the bounding box to exclude 1.404 + // fractional parts that won't be rendered. 1.405 + // Note: the left edge is handled slightly differently below. We 1.406 + // are a bit more generous in the rounding since we don't want to 1.407 + // risk missing the left pixels when fLeft is very close to .5 1.408 + fFiniteBound.set(SkScalarFloorToScalar(fFiniteBound.fLeft+0.45f), 1.409 + SkScalarRoundToScalar(fFiniteBound.fTop), 1.410 + SkScalarRoundToScalar(fFiniteBound.fRight), 1.411 + SkScalarRoundToScalar(fFiniteBound.fBottom)); 1.412 + } 1.413 + 1.414 + // Now determine the previous Element's bound information taking into 1.415 + // account that there may be no previous clip 1.416 + SkRect prevFinite; 1.417 + SkClipStack::BoundsType prevType; 1.418 + 1.419 + if (NULL == prior) { 1.420 + // no prior clip means the entire plane is writable 1.421 + prevFinite.setEmpty(); // there are no pixels that cannot be drawn to 1.422 + prevType = kInsideOut_BoundsType; 1.423 + } else { 1.424 + prevFinite = prior->fFiniteBound; 1.425 + prevType = prior->fFiniteBoundType; 1.426 + } 1.427 + 1.428 + FillCombo combination = kPrev_Cur_FillCombo; 1.429 + if (kInsideOut_BoundsType == fFiniteBoundType) { 1.430 + combination = (FillCombo) (combination | 0x01); 1.431 + } 1.432 + if (kInsideOut_BoundsType == prevType) { 1.433 + combination = (FillCombo) (combination | 0x02); 1.434 + } 1.435 + 1.436 + SkASSERT(kInvPrev_InvCur_FillCombo == combination || 1.437 + kInvPrev_Cur_FillCombo == combination || 1.438 + kPrev_InvCur_FillCombo == combination || 1.439 + kPrev_Cur_FillCombo == combination); 1.440 + 1.441 + // Now integrate with clip with the prior clips 1.442 + switch (fOp) { 1.443 + case SkRegion::kDifference_Op: 1.444 + this->combineBoundsDiff(combination, prevFinite); 1.445 + break; 1.446 + case SkRegion::kXOR_Op: 1.447 + this->combineBoundsXOR(combination, prevFinite); 1.448 + break; 1.449 + case SkRegion::kUnion_Op: 1.450 + this->combineBoundsUnion(combination, prevFinite); 1.451 + break; 1.452 + case SkRegion::kIntersect_Op: 1.453 + this->combineBoundsIntersection(combination, prevFinite); 1.454 + break; 1.455 + case SkRegion::kReverseDifference_Op: 1.456 + this->combineBoundsRevDiff(combination, prevFinite); 1.457 + break; 1.458 + case SkRegion::kReplace_Op: 1.459 + // Replace just ignores everything prior 1.460 + // The current clip's bound information is already filled in 1.461 + // so nothing to do 1.462 + break; 1.463 + default: 1.464 + SkDebugf("SkRegion::Op error\n"); 1.465 + SkASSERT(0); 1.466 + break; 1.467 + } 1.468 +} 1.469 + 1.470 +// This constant determines how many Element's are allocated together as a block in 1.471 +// the deque. As such it needs to balance allocating too much memory vs. 1.472 +// incurring allocation/deallocation thrashing. It should roughly correspond to 1.473 +// the deepest save/restore stack we expect to see. 1.474 +static const int kDefaultElementAllocCnt = 8; 1.475 + 1.476 +SkClipStack::SkClipStack() 1.477 + : fDeque(sizeof(Element), kDefaultElementAllocCnt) 1.478 + , fSaveCount(0) { 1.479 +} 1.480 + 1.481 +SkClipStack::SkClipStack(const SkClipStack& b) 1.482 + : fDeque(sizeof(Element), kDefaultElementAllocCnt) { 1.483 + *this = b; 1.484 +} 1.485 + 1.486 +SkClipStack::SkClipStack(const SkRect& r) 1.487 + : fDeque(sizeof(Element), kDefaultElementAllocCnt) 1.488 + , fSaveCount(0) { 1.489 + if (!r.isEmpty()) { 1.490 + this->clipDevRect(r, SkRegion::kReplace_Op, false); 1.491 + } 1.492 +} 1.493 + 1.494 +SkClipStack::SkClipStack(const SkIRect& r) 1.495 + : fDeque(sizeof(Element), kDefaultElementAllocCnt) 1.496 + , fSaveCount(0) { 1.497 + if (!r.isEmpty()) { 1.498 + SkRect temp; 1.499 + temp.set(r); 1.500 + this->clipDevRect(temp, SkRegion::kReplace_Op, false); 1.501 + } 1.502 +} 1.503 + 1.504 +SkClipStack::~SkClipStack() { 1.505 + reset(); 1.506 +} 1.507 + 1.508 +SkClipStack& SkClipStack::operator=(const SkClipStack& b) { 1.509 + if (this == &b) { 1.510 + return *this; 1.511 + } 1.512 + reset(); 1.513 + 1.514 + fSaveCount = b.fSaveCount; 1.515 + SkDeque::F2BIter recIter(b.fDeque); 1.516 + for (const Element* element = (const Element*)recIter.next(); 1.517 + element != NULL; 1.518 + element = (const Element*)recIter.next()) { 1.519 + new (fDeque.push_back()) Element(*element); 1.520 + } 1.521 + 1.522 + return *this; 1.523 +} 1.524 + 1.525 +bool SkClipStack::operator==(const SkClipStack& b) const { 1.526 + if (this->getTopmostGenID() == b.getTopmostGenID()) { 1.527 + return true; 1.528 + } 1.529 + if (fSaveCount != b.fSaveCount || 1.530 + fDeque.count() != b.fDeque.count()) { 1.531 + return false; 1.532 + } 1.533 + SkDeque::F2BIter myIter(fDeque); 1.534 + SkDeque::F2BIter bIter(b.fDeque); 1.535 + const Element* myElement = (const Element*)myIter.next(); 1.536 + const Element* bElement = (const Element*)bIter.next(); 1.537 + 1.538 + while (myElement != NULL && bElement != NULL) { 1.539 + if (*myElement != *bElement) { 1.540 + return false; 1.541 + } 1.542 + myElement = (const Element*)myIter.next(); 1.543 + bElement = (const Element*)bIter.next(); 1.544 + } 1.545 + return myElement == NULL && bElement == NULL; 1.546 +} 1.547 + 1.548 +void SkClipStack::reset() { 1.549 + // We used a placement new for each object in fDeque, so we're responsible 1.550 + // for calling the destructor on each of them as well. 1.551 + while (!fDeque.empty()) { 1.552 + Element* element = (Element*)fDeque.back(); 1.553 + element->~Element(); 1.554 + fDeque.pop_back(); 1.555 + } 1.556 + 1.557 + fSaveCount = 0; 1.558 +} 1.559 + 1.560 +void SkClipStack::save() { 1.561 + fSaveCount += 1; 1.562 +} 1.563 + 1.564 +void SkClipStack::restore() { 1.565 + fSaveCount -= 1; 1.566 + restoreTo(fSaveCount); 1.567 +} 1.568 + 1.569 +void SkClipStack::restoreTo(int saveCount) { 1.570 + while (!fDeque.empty()) { 1.571 + Element* element = (Element*)fDeque.back(); 1.572 + if (element->fSaveCount <= saveCount) { 1.573 + break; 1.574 + } 1.575 + element->~Element(); 1.576 + fDeque.pop_back(); 1.577 + } 1.578 +} 1.579 + 1.580 +void SkClipStack::getBounds(SkRect* canvFiniteBound, 1.581 + BoundsType* boundType, 1.582 + bool* isIntersectionOfRects) const { 1.583 + SkASSERT(NULL != canvFiniteBound && NULL != boundType); 1.584 + 1.585 + Element* element = (Element*)fDeque.back(); 1.586 + 1.587 + if (NULL == element) { 1.588 + // the clip is wide open - the infinite plane w/ no pixels un-writeable 1.589 + canvFiniteBound->setEmpty(); 1.590 + *boundType = kInsideOut_BoundsType; 1.591 + if (NULL != isIntersectionOfRects) { 1.592 + *isIntersectionOfRects = false; 1.593 + } 1.594 + return; 1.595 + } 1.596 + 1.597 + *canvFiniteBound = element->fFiniteBound; 1.598 + *boundType = element->fFiniteBoundType; 1.599 + if (NULL != isIntersectionOfRects) { 1.600 + *isIntersectionOfRects = element->fIsIntersectionOfRects; 1.601 + } 1.602 +} 1.603 + 1.604 +bool SkClipStack::intersectRectWithClip(SkRect* rect) const { 1.605 + SkASSERT(NULL != rect); 1.606 + 1.607 + SkRect bounds; 1.608 + SkClipStack::BoundsType bt; 1.609 + this->getBounds(&bounds, &bt); 1.610 + if (bt == SkClipStack::kInsideOut_BoundsType) { 1.611 + if (bounds.contains(*rect)) { 1.612 + return false; 1.613 + } else { 1.614 + // If rect's x values are both within bound's x range we 1.615 + // could clip here. Same for y. But we don't bother to check. 1.616 + return true; 1.617 + } 1.618 + } else { 1.619 + return rect->intersect(bounds); 1.620 + } 1.621 +} 1.622 + 1.623 +bool SkClipStack::quickContains(const SkRect& rect) const { 1.624 + 1.625 + Iter iter(*this, Iter::kTop_IterStart); 1.626 + const Element* element = iter.prev(); 1.627 + while (element != NULL) { 1.628 + if (SkRegion::kIntersect_Op != element->getOp() && SkRegion::kReplace_Op != element->getOp()) 1.629 + return false; 1.630 + if (element->isInverseFilled()) { 1.631 + // Part of 'rect' could be trimmed off by the inverse-filled clip element 1.632 + if (SkRect::Intersects(element->getBounds(), rect)) { 1.633 + return false; 1.634 + } 1.635 + } else { 1.636 + if (!element->contains(rect)) { 1.637 + return false; 1.638 + } 1.639 + } 1.640 + if (SkRegion::kReplace_Op == element->getOp()) { 1.641 + break; 1.642 + } 1.643 + element = iter.prev(); 1.644 + } 1.645 + return true; 1.646 +} 1.647 + 1.648 +void SkClipStack::pushElement(const Element& element) { 1.649 + // Use reverse iterator instead of back because Rect path may need previous 1.650 + SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); 1.651 + Element* prior = (Element*) iter.prev(); 1.652 + 1.653 + if (NULL != prior) { 1.654 + if (prior->canBeIntersectedInPlace(fSaveCount, element.getOp())) { 1.655 + switch (prior->fType) { 1.656 + case Element::kEmpty_Type: 1.657 + SkDEBUGCODE(prior->checkEmpty();) 1.658 + return; 1.659 + case Element::kRect_Type: 1.660 + if (Element::kRect_Type == element.getType()) { 1.661 + if (prior->rectRectIntersectAllowed(element.getRect(), element.isAA())) { 1.662 + SkRect isectRect; 1.663 + if (!isectRect.intersect(prior->getRect(), element.getRect())) { 1.664 + prior->setEmpty(); 1.665 + return; 1.666 + } 1.667 + 1.668 + prior->fRRect.setRect(isectRect); 1.669 + prior->fDoAA = element.isAA(); 1.670 + Element* priorPrior = (Element*) iter.prev(); 1.671 + prior->updateBoundAndGenID(priorPrior); 1.672 + return; 1.673 + } 1.674 + break; 1.675 + } 1.676 + // fallthrough 1.677 + default: 1.678 + if (!SkRect::Intersects(prior->getBounds(), element.getBounds())) { 1.679 + prior->setEmpty(); 1.680 + return; 1.681 + } 1.682 + break; 1.683 + } 1.684 + } else if (SkRegion::kReplace_Op == element.getOp()) { 1.685 + this->restoreTo(fSaveCount - 1); 1.686 + prior = (Element*) fDeque.back(); 1.687 + } 1.688 + } 1.689 + Element* newElement = SkNEW_PLACEMENT_ARGS(fDeque.push_back(), Element, (element)); 1.690 + newElement->updateBoundAndGenID(prior); 1.691 +} 1.692 + 1.693 +void SkClipStack::clipDevRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1.694 + Element element(fSaveCount, rrect, op, doAA); 1.695 + this->pushElement(element); 1.696 +} 1.697 + 1.698 +void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1.699 + Element element(fSaveCount, rect, op, doAA); 1.700 + this->pushElement(element); 1.701 +} 1.702 + 1.703 +void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1.704 + Element element(fSaveCount, path, op, doAA); 1.705 + this->pushElement(element); 1.706 +} 1.707 + 1.708 +void SkClipStack::clipEmpty() { 1.709 + Element* element = (Element*) fDeque.back(); 1.710 + 1.711 + if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) { 1.712 + element->setEmpty(); 1.713 + } 1.714 + new (fDeque.push_back()) Element(fSaveCount); 1.715 + 1.716 + ((Element*)fDeque.back())->fGenID = kEmptyGenID; 1.717 +} 1.718 + 1.719 +bool SkClipStack::isWideOpen() const { 1.720 + return this->getTopmostGenID() == kWideOpenGenID; 1.721 +} 1.722 + 1.723 +/////////////////////////////////////////////////////////////////////////////// 1.724 + 1.725 +SkClipStack::Iter::Iter() : fStack(NULL) { 1.726 +} 1.727 + 1.728 +SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) 1.729 + : fStack(&stack) { 1.730 + this->reset(stack, startLoc); 1.731 +} 1.732 + 1.733 +const SkClipStack::Element* SkClipStack::Iter::next() { 1.734 + return (const SkClipStack::Element*)fIter.next(); 1.735 +} 1.736 + 1.737 +const SkClipStack::Element* SkClipStack::Iter::prev() { 1.738 + return (const SkClipStack::Element*)fIter.prev(); 1.739 +} 1.740 + 1.741 +const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) { 1.742 + 1.743 + if (NULL == fStack) { 1.744 + return NULL; 1.745 + } 1.746 + 1.747 + fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart); 1.748 + 1.749 + const SkClipStack::Element* element = NULL; 1.750 + 1.751 + for (element = (const SkClipStack::Element*) fIter.prev(); 1.752 + NULL != element; 1.753 + element = (const SkClipStack::Element*) fIter.prev()) { 1.754 + 1.755 + if (op == element->fOp) { 1.756 + // The Deque's iterator is actually one pace ahead of the 1.757 + // returned value. So while "element" is the element we want to 1.758 + // return, the iterator is actually pointing at (and will 1.759 + // return on the next "next" or "prev" call) the element 1.760 + // in front of it in the deque. Bump the iterator forward a 1.761 + // step so we get the expected result. 1.762 + if (NULL == fIter.next()) { 1.763 + // The reverse iterator has run off the front of the deque 1.764 + // (i.e., the "op" clip is the first clip) and can't 1.765 + // recover. Reset the iterator to start at the front. 1.766 + fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 1.767 + } 1.768 + break; 1.769 + } 1.770 + } 1.771 + 1.772 + if (NULL == element) { 1.773 + // There were no "op" clips 1.774 + fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 1.775 + } 1.776 + 1.777 + return this->next(); 1.778 +} 1.779 + 1.780 +void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) { 1.781 + fStack = &stack; 1.782 + fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc)); 1.783 +} 1.784 + 1.785 +// helper method 1.786 +void SkClipStack::getConservativeBounds(int offsetX, 1.787 + int offsetY, 1.788 + int maxWidth, 1.789 + int maxHeight, 1.790 + SkRect* devBounds, 1.791 + bool* isIntersectionOfRects) const { 1.792 + SkASSERT(NULL != devBounds); 1.793 + 1.794 + devBounds->setLTRB(0, 0, 1.795 + SkIntToScalar(maxWidth), SkIntToScalar(maxHeight)); 1.796 + 1.797 + SkRect temp; 1.798 + SkClipStack::BoundsType boundType; 1.799 + 1.800 + // temp starts off in canvas space here 1.801 + this->getBounds(&temp, &boundType, isIntersectionOfRects); 1.802 + if (SkClipStack::kInsideOut_BoundsType == boundType) { 1.803 + return; 1.804 + } 1.805 + 1.806 + // but is converted to device space here 1.807 + temp.offset(SkIntToScalar(offsetX), SkIntToScalar(offsetY)); 1.808 + 1.809 + if (!devBounds->intersect(temp)) { 1.810 + devBounds->setEmpty(); 1.811 + } 1.812 +} 1.813 + 1.814 +int32_t SkClipStack::GetNextGenID() { 1.815 + // TODO: handle overflow. 1.816 + return sk_atomic_inc(&gGenID); 1.817 +} 1.818 + 1.819 +int32_t SkClipStack::getTopmostGenID() const { 1.820 + if (fDeque.empty()) { 1.821 + return kWideOpenGenID; 1.822 + } 1.823 + 1.824 + const Element* back = static_cast<const Element*>(fDeque.back()); 1.825 + if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty()) { 1.826 + return kWideOpenGenID; 1.827 + } 1.828 + 1.829 + return back->getGenID(); 1.830 +}