15bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com 25bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com/* 35bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Copyright 2011 Google Inc. 45bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * 55bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * Use of this source code is governed by a BSD-style license that can be 65bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com * found in the LICENSE file. 75bb6825f10d64834ad1d1d967f590aebae285360epoger@google.com */ 87ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#ifndef SkClipStack_DEFINED 97ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#define SkClipStack_DEFINED 107ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 117ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#include "SkDeque.h" 1223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com#include "SkPath.h" 1323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com#include "SkRect.h" 147ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#include "SkRegion.h" 15e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com#include "SkTDArray.h" 167ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 177ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 18ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// Because a single save/restore state can have multiple clips, this class 19ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// stores the stack depth (fSaveCount) and clips (fDeque) separately. 20ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// Each clip in fDeque stores the stack state to which it belongs 21ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// (i.e., the fSaveCount in force when it was added). Restores are thus 22ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// implemented by removing clips from fDeque that have an fSaveCount larger 23ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com// then the freshly decremented count. 242083387d719b933797044ad07efd3bb67f99a5c5ctguil@chromium.orgclass SK_API SkClipStack { 257ff121663ecde556b077c703c07b032c0d62dff8reed@google.compublic: 2623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com enum BoundsType { 2723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // The bounding box contains all the pixels that can be written to 2823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kNormal_BoundsType, 2923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // The bounding box contains all the pixels that cannot be written to. 3023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // The real bound extends out to infinity and all the pixels outside 3123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // of the bound can be written to. Note that some of the pixels inside 3223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // the bound may also be writeable but all pixels that cannot be 3323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // written to are guaranteed to be inside. 3423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kInsideOut_BoundsType 3523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com }; 3623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 3723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com class Element { 3823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com public: 3923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com enum Type { 4023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< This element makes the clip empty (regardless of previous elements). 4123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kEmpty_Type, 4223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< This element combines a rect with the current clip using a set operation 4323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kRect_Type, 4423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< This element combines a path with the current clip using a set operation 4523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kPath_Type, 4623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com }; 4723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 4823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element() { 4923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initCommon(0, SkRegion::kReplace_Op, false); 5023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->setEmpty(); 5123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 5223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 5323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element(const SkRect& rect, SkRegion::Op op, bool doAA) { 5423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initRect(0, rect, op, doAA); 5523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 5623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 5723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element(const SkPath& path, SkRegion::Op op, bool doAA) { 5823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initPath(0, path, op, doAA); 5923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 6023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 61e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com bool operator== (const Element& element) const { 62e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com if (this == &element) { 63e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return true; 64e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 65e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com if (fOp != element.fOp || 66e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com fType != element.fType || 67e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com fDoAA != element.fDoAA || 68e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com fSaveCount != element.fSaveCount) { 69e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return false; 70e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 71e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com switch (fType) { 72e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kPath_Type: 73e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fPath == element.fPath; 74e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kRect_Type: 75e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fRect == element.fRect; 76e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kEmpty_Type: 77e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return true; 78e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com default: 79e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com SkDEBUGFAIL("Unexpected type."); 80e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return false; 81e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 82e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 83e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com bool operator!= (const Element& element) const { return !(*this == element); } 84e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com 8523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< Call to get the type of the clip element. 8623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Type getType() const { return fType; } 8723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 8823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< Call if getType() is kPath to get the path. 8923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com const SkPath& getPath() const { return fPath; } 9023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 9123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< Call if getType() is kRect to get the rect. 9223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com const SkRect& getRect() const { return fRect; } 9323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 9423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com //!< Call if getType() is not kEmpty to get the set operation used to combine this element. 9523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkRegion::Op getOp() const { return fOp; } 9623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 9723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased 9823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com when it is rasterized. */ 9923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com bool isAA() const { return fDoAA; } 10023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 101c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty. 102c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com void invertShapeFillType(); 103c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com 104c377c7fd83a90e27e92aca381ce2c2c2aac799e2bsalomon@google.com //!< Sets the set operation represented by the element. 105e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com void setOp(SkRegion::Op op) { fOp = op; } 106e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com 10723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com /** The GenID can be used by clip stack clients to cache representations of the clip. The 10823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com ID corresponds to the set of clip elements up to and including this element within the 10923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com stack not to the element itself. That is the same clip path in different stacks will 11023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com have a different ID since the elements produce different clip result in the context of 11123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com their stacks. */ 112a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; } 11323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 114e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com /** 115e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape 116e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * is inverse filled is not considered.) 117e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com */ 118e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com const SkRect& getBounds() const { 119e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com static const SkRect kEmpty = { 0, 0, 0, 0 }; 120e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com switch (fType) { 121e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kRect_Type: 122e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fRect; 123e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kPath_Type: 124e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fPath.getBounds(); 125e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kEmpty_Type: 126e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return kEmpty; 127e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com default: 128e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com SkDEBUGFAIL("Unexpected type."); 129e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return kEmpty; 130e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 131e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 132e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com 133e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com /** 134e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * Conservatively checks whether the clip shape contains the rect param. (Whether the shape 135e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * is inverse filled is not considered.) 136e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com */ 137e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com bool contains(const SkRect& rect) const { 138e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com switch (fType) { 139e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kRect_Type: 140e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fRect.contains(rect); 141e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kPath_Type: 142e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return fPath.conservativelyContainsRect(rect); 143e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com case kEmpty_Type: 144e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return false; 145e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com default: 146e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com SkDEBUGFAIL("Unexpected type."); 147e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return false; 148e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 149e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 150e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com 151e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com /** 152e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * Is the clip shape inverse filled. 153e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com */ 154e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com bool isInverseFilled() const { 155e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com return kPath_Type == fType && fPath.isInverseFillType(); 156e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com } 157e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com 15823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com private: 15923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com friend class SkClipStack; 16023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 16123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkPath fPath; 16223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkRect fRect; 16323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com int fSaveCount; // save count of stack when this element was added. 16423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkRegion::Op fOp; 16523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Type fType; 16623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com bool fDoAA; 16723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 16823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's 16923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the 17023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be 17123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which 17223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding 17323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside 17423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the 17523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we 17623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com can capture the cancelling out of the extensions to infinity when two inverse filled 17723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com clips are Booleaned together. */ 17823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkClipStack::BoundsType fFiniteBoundType; 17923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com SkRect fFiniteBound; 180f8f29177dd064bcfa4a7458e24434a807bca20b4skia.committer@gmail.com 18123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // When element is applied to the previous elements in the stack is the result known to be 18223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle. 18323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com bool fIsIntersectionOfRects; 18423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 18523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com int fGenID; 18623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 18723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element(int saveCount) { 18823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initCommon(saveCount, SkRegion::kReplace_Op, false); 18923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->setEmpty(); 19023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 19123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 19223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { 19323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initRect(saveCount, rect, op, doAA); 19423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 19523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 19623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { 19723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initPath(saveCount, path, op, doAA); 19823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 19923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 20023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com void initCommon(int saveCount, SkRegion::Op op, bool doAA) { 20123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fSaveCount = saveCount; 20223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fOp = op; 20323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fDoAA = doAA; 20423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // A default of inside-out and empty bounds means the bounds are effectively void as it 20523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // indicates that nothing is known to be outside the clip. 20623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fFiniteBoundType = kInsideOut_BoundsType; 20723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fFiniteBound.setEmpty(); 20823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fIsIntersectionOfRects = false; 20923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fGenID = kInvalidGenID; 21023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 21123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 21223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { 21323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fRect = rect; 21423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fType = kRect_Type; 21523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initCommon(saveCount, op, doAA); 21623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 21723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 21823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { 21923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fPath = path; 22023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fType = kPath_Type; 22123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com this->initCommon(saveCount, op, doAA); 22223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 22323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 22423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com void setEmpty() { 22523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fType = kEmpty_Type; 22623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fFiniteBound.setEmpty(); 22723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fFiniteBoundType = kNormal_BoundsType; 22823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fIsIntersectionOfRects = false; 22923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fRect.setEmpty(); 23023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fPath.reset(); 23123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com fGenID = kEmptyGenID; 23223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com } 23323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 23423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // All Element methods below are only used within SkClipStack.cpp 23523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void checkEmpty() const; 23623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const; 23723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com /* This method checks to see if two rect clips can be safely merged into one. The issue here 238f8f29177dd064bcfa4a7458e24434a807bca20b4skia.committer@gmail.com is that to be strictly correct all the edges of the resulting rect must have the same 23923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com anti-aliasing. */ 24023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const; 24123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com /** Determines possible finite bounds for the Element given the previous element of the 24223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com stack */ 24323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com void updateBoundAndGenID(const Element* prior); 24423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // The different combination of fill & inverse fill when combining bounding boxes 24523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com enum FillCombo { 24623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kPrev_Cur_FillCombo, 24723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kPrev_InvCur_FillCombo, 24823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kInvPrev_Cur_FillCombo, 24923d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com kInvPrev_InvCur_FillCombo 25023d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com }; 25123d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com // per-set operation functions used by updateBoundAndGenID(). 25223d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite); 25323d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void combineBoundsXOR(int combination, const SkRect& prevFinite); 25423d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void combineBoundsUnion(int combination, const SkRect& prevFinite); 25523d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void combineBoundsIntersection(int combination, const SkRect& prevFinite); 25623d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite); 25723d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com }; 25823d318e62f0145501ac0194adaf4e92ae718336cbsalomon@google.com 2597ff121663ecde556b077c703c07b032c0d62dff8reed@google.com SkClipStack(); 2602efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org SkClipStack(const SkClipStack& b); 26187788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com explicit SkClipStack(const SkRect& r); 2627ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com explicit SkClipStack(const SkIRect& r); 263deef1e7433887329d28d96bb184805b9970184e6vandebo@chromium.org ~SkClipStack(); 2647ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 2652efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org SkClipStack& operator=(const SkClipStack& b); 2662efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org bool operator==(const SkClipStack& b) const; 2672efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org bool operator!=(const SkClipStack& b) const { return !(*this == b); } 2682efaa066816c95dbbf50c10a7320c6ba215f3a45vandebo@chromium.org 2697ff121663ecde556b077c703c07b032c0d62dff8reed@google.com void reset(); 2707ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 2717ff121663ecde556b077c703c07b032c0d62dff8reed@google.com int getSaveCount() const { return fSaveCount; } 2727ff121663ecde556b077c703c07b032c0d62dff8reed@google.com void save(); 2737ff121663ecde556b077c703c07b032c0d62dff8reed@google.com void restore(); 2747ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 2756fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com /** 2766fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com * getBounds places the current finite bound in its first parameter. In its 2771fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * second, it indicates which kind of bound is being returned. If 278e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com * 'canvFiniteBound' is a normal bounding box then it encloses all writeable 2791fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * pixels. If 'canvFiniteBound' is an inside out bounding box then it 2806fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com * encloses all the un-writeable pixels and the true/normal bound is the 281ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com * infinite plane. isIntersectionOfRects is an optional parameter 282e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com * that is true if 'canvFiniteBound' resulted from an intersection of rects. 2836fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com */ 2841fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com void getBounds(SkRect* canvFiniteBound, 285ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com BoundsType* boundType, 286ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com bool* isIntersectionOfRects = NULL) const; 2876fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com 288a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com /** 289a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com * Takes an input rect in device space and conservatively clips it to the 290a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com * clip-stack. If false is returned then the rect does not intersect the 291a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com * clip and is unmodified. 292a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com */ 293a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com bool intersectRectWithClip(SkRect* devRect) const; 294a588ffb6f5d538b3f7bb021b391dea78dc1312cfbsalomon@google.com 295c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org /** 296c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org * Returns true if the input rect in device space is entirely contained 297c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org * by the clip. A return value of false does not guarantee that the rect 298c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org * is not contained by the clip. 299c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org */ 300c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org bool quickContains(const SkRect& devRect) const; 301c09cfc3f6d6d9a6ee9386fa5f36d605852693138junov@chromium.org 302ba80e479892aa491c507bd9efb41c43b0e75c559reed@google.com void clipDevRect(const SkIRect& ir, SkRegion::Op op) { 3037ff121663ecde556b077c703c07b032c0d62dff8reed@google.com SkRect r; 3047ff121663ecde556b077c703c07b032c0d62dff8reed@google.com r.set(ir); 305e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com this->clipDevRect(r, op, false); 3067ff121663ecde556b077c703c07b032c0d62dff8reed@google.com } 307e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); 308e9438a94e1dc3a3be96ecc13e799278e90cf8ef5reed@google.com void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); 30905b4f721bd077dd67c6d8a4457323e4efafe2d91reed@google.com // An optimized version of clipDevRect(emptyRect, kIntersect, ...) 31005b4f721bd077dd67c6d8a4457323e4efafe2d91reed@google.com void clipEmpty(); 3117ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 31287788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com /** 3131fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * isWideOpen returns true if the clip state corresponds to the infinite 31487788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com * plane (i.e., draws are not limited at all) 31587788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com */ 31687788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com bool isWideOpen() const; 31787788b18c6d052a419d83851ef6b5347b5b905bdrobertphillips@google.com 318e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com /** 319e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com * The generation ID has three reserved values to indicate special 3206a2ba9e48fd4418c403256dc2e55d6e31d03f7b8bsalomon@google.com * (potentially ignorable) cases 321e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com */ 322a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org static const int32_t kInvalidGenID = 0; //!< Invalid id that is never returned by 323a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org //!< SkClipStack. Useful when caching clips 324a4e9612567d41005e0ade42c615050f2262f6a14commit-bot@chromium.org //!< based on GenID. 325e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com static const int32_t kEmptyGenID = 1; // no pixels writeable 326e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com static const int32_t kWideOpenGenID = 2; // all pixels writeable 327e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com 3287b4e881b6f0c5d4b77363cf4c4dd6dd15ebc1a3arobertphillips@google.com int32_t getTopmostGenID() const; 3297b4e881b6f0c5d4b77363cf4c4dd6dd15ebc1a3arobertphillips@google.com 330de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.compublic: 331de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com class Iter { 3327ff121663ecde556b077c703c07b032c0d62dff8reed@google.com public: 333de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com enum IterStart { 334897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com kBottom_IterStart = SkDeque::Iter::kFront_IterStart, 335897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com kTop_IterStart = SkDeque::Iter::kBack_IterStart 336de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com }; 337de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 338c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com /** 339c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com * Creates an uninitialized iterator. Must be reset() 340c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com */ 341de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com Iter(); 342c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com 343de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com Iter(const SkClipStack& stack, IterStart startLoc); 3447ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 3457ff121663ecde556b077c703c07b032c0d62dff8reed@google.com /** 346e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * Return the clip element for this iterator. If next()/prev() returns NULL, then the 347e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * iterator is done. 3487ff121663ecde556b077c703c07b032c0d62dff8reed@google.com */ 349e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com const Element* next(); 350e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com const Element* prev(); 3517ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 352c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com /** 353e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * Moves the iterator to the topmost element with the specified RegionOp and returns that 354e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com * element. If no clip element with that op is found, the first element is returned. 355c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com */ 356e510935043b8eae6044e9da20fae9800a5785702bsalomon@google.com const Element* skipToTopmost(SkRegion::Op op); 357c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com 358c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com /** 359c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com * Restarts the iterator on a clip stack. 360c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com */ 361de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com void reset(const SkClipStack& stack, IterStart startLoc); 362c93d11c65ab5bd25a956ac1a68407b76610eed27bsalomon@google.com 3637ff121663ecde556b077c703c07b032c0d62dff8reed@google.com private: 364c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com const SkClipStack* fStack; 365c0c941d072fc552f2d98dba299810e4333bd65a8robertphillips@google.com SkDeque::Iter fIter; 366de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com }; 367de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 3681fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com /** 369897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com * The B2TIter iterates from the bottom of the stack to the top. 370897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com * It inherits privately from Iter to prevent access to reverse iteration. 371897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com */ 372897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com class B2TIter : private Iter { 373de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com public: 374897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com B2TIter() {} 375de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 376de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com /** 3771fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * Wrap Iter's 2 parameter ctor to force initialization to the 378897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com * beginning of the deque/bottom of the stack 379de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com */ 3801fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com B2TIter(const SkClipStack& stack) 381897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com : INHERITED(stack, kBottom_IterStart) { 382de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com } 383de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 384de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com using Iter::next; 385de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 386de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com /** 3871fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * Wrap Iter::reset to force initialization to the 388897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com * beginning of the deque/bottom of the stack 389de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com */ 390de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com void reset(const SkClipStack& stack) { 391897a162ac9fa65bcb4063ac76d603f51de8a5b48robertphillips@google.com this->INHERITED::reset(stack, kBottom_IterStart); 392de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com } 393de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 394de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com private: 395de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com 396de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com typedef Iter INHERITED; 3977ff121663ecde556b077c703c07b032c0d62dff8reed@google.com }; 3987ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 3996fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com /** 4001fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * GetConservativeBounds returns a conservative bound of the current clip. 4011fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * Since this could be the infinite plane (if inverse fills were involved) the 4021fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * maxWidth and maxHeight parameters can be used to limit the returned bound 4036fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com * to the expected drawing area. Similarly, the offsetX and offsetY parameters 4041fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * allow the caller to offset the returned bound to account for translated 4056fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com * drawing areas (i.e., those resulting from a saveLayer). For finite bounds, 4061fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * the translation (+offsetX, +offsetY) is applied before the clamp to the 4076fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com * maximum rectangle: [0,maxWidth) x [0,maxHeight). 4081fde19f3b72345b473a1a9bd64729237a388813frmistry@google.com * isIntersectionOfRects is an optional parameter that is true when 4097ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com * 'devBounds' is the result of an intersection of rects. In this case 4107ba33c7ac6383856dfe19f5fcf6968363037d393robertphillips@google.com * 'devBounds' is the exact answer/clip. 4116fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com */ 4126fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com void getConservativeBounds(int offsetX, 4136fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com int offsetY, 4146fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com int maxWidth, 4156fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com int maxHeight, 416e60c6253c3bca3e8800d02290ace13362ff7d724robertphillips@google.com SkRect* devBounds, 417ea85e7af1781c4879d22e5e5ad399be6e9d9eefcrobertphillips@google.com bool* isIntersectionOfRects = NULL) const; 4186fd897d4dcf13d1c0de6a7cbd251487ae1095e42robertphillips@google.com 4197ff121663ecde556b077c703c07b032c0d62dff8reed@google.comprivate: 420de9abcab679c999d879edf19895a06c6acc5cd7erobertphillips@google.com friend class Iter; 4217ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 4227ff121663ecde556b077c703c07b032c0d62dff8reed@google.com SkDeque fDeque; 4237ff121663ecde556b077c703c07b032c0d62dff8reed@google.com int fSaveCount; 424e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com 425e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com // Generation ID for the clip stack. This is incremented for each 426e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com // clipDevRect and clipDevPath call. 0 is reserved to indicate an 427e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com // invalid ID. 428e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com static int32_t gGenID; 429e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com 430e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com /** 431b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org * Restore the stack back to the specified save count. 432b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org */ 433b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org void restoreTo(int saveCount); 434b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org 435b8f710fa222dbb717b8681350f84c6ea916e89a2commit-bot@chromium.org /** 436e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com * Return the next unique generation ID. 437e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com */ 438e05469555381ff89713742474ebd0af0df461dd4robertphillips@google.com static int32_t GetNextGenID(); 4397ff121663ecde556b077c703c07b032c0d62dff8reed@google.com}; 4407ff121663ecde556b077c703c07b032c0d62dff8reed@google.com 4417ff121663ecde556b077c703c07b032c0d62dff8reed@google.com#endif 442