gfx/skia/trunk/src/core/SkClipStack.cpp

changeset 0
6474c204b198
     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 +}

mercurial