gfx/skia/trunk/include/core/SkClipStack.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     2 /*
     3  * Copyright 2011 Google Inc.
     4  *
     5  * Use of this source code is governed by a BSD-style license that can be
     6  * found in the LICENSE file.
     7  */
     8 #ifndef SkClipStack_DEFINED
     9 #define SkClipStack_DEFINED
    11 #include "SkDeque.h"
    12 #include "SkPath.h"
    13 #include "SkRect.h"
    14 #include "SkRRect.h"
    15 #include "SkRegion.h"
    16 #include "SkTDArray.h"
    17 #include "SkTLazy.h"
    20 // Because a single save/restore state can have multiple clips, this class
    21 // stores the stack depth (fSaveCount) and clips (fDeque) separately.
    22 // Each clip in fDeque stores the stack state to which it belongs
    23 // (i.e., the fSaveCount in force when it was added). Restores are thus
    24 // implemented by removing clips from fDeque that have an fSaveCount larger
    25 // then the freshly decremented count.
    26 class SK_API SkClipStack {
    27 public:
    28     enum BoundsType {
    29         // The bounding box contains all the pixels that can be written to
    30         kNormal_BoundsType,
    31         // The bounding box contains all the pixels that cannot be written to.
    32         // The real bound extends out to infinity and all the pixels outside
    33         // of the bound can be written to. Note that some of the pixels inside
    34         // the bound may also be writeable but all pixels that cannot be
    35         // written to are guaranteed to be inside.
    36         kInsideOut_BoundsType
    37     };
    39     class Element {
    40     public:
    41         enum Type {
    42             //!< This element makes the clip empty (regardless of previous elements).
    43             kEmpty_Type,
    44             //!< This element combines a rect with the current clip using a set operation
    45             kRect_Type,
    46             //!< This element combines a round-rect with the current clip using a set operation
    47             kRRect_Type,
    48             //!< This element combines a path with the current clip using a set operation
    49             kPath_Type,
    50         };
    52         Element() {
    53             this->initCommon(0, SkRegion::kReplace_Op, false);
    54             this->setEmpty();
    55         }
    57         Element(const Element&);
    59         Element(const SkRect& rect, SkRegion::Op op, bool doAA) {
    60             this->initRect(0, rect, op, doAA);
    61         }
    63         Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
    64             this->initRRect(0, rrect, op, doAA);
    65         }
    67         Element(const SkPath& path, SkRegion::Op op, bool doAA) {
    68             this->initPath(0, path, op, doAA);
    69         }
    71         bool operator== (const Element& element) const;
    72         bool operator!= (const Element& element) const { return !(*this == element); }
    74         //!< Call to get the type of the clip element.
    75         Type getType() const { return fType; }
    77         //!< Call if getType() is kPath to get the path.
    78         const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *fPath.get(); }
    80         //!< Call if getType() is kRRect to get the round-rect.
    81         const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return fRRect; }
    83         //!< Call if getType() is kRect to get the rect.
    84         const SkRect& getRect() const {
    85             SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()));
    86             return fRRect.getBounds();
    87         }
    89         //!< Call if getType() is not kEmpty to get the set operation used to combine this element.
    90         SkRegion::Op getOp() const { return fOp; }
    92         //!< Call to get the element as a path, regardless of its type.
    93         void asPath(SkPath* path) const;
    95         /** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
    96             when it is rasterized. */
    97         bool isAA() const { return fDoAA; }
    99         //!< Inverts the fill of the clip shape. Note that a kEmpty element remains kEmpty.
   100         void invertShapeFillType();
   102         //!< Sets the set operation represented by the element.
   103         void setOp(SkRegion::Op op) { fOp = op; }
   105         /** The GenID can be used by clip stack clients to cache representations of the clip. The
   106             ID corresponds to the set of clip elements up to and including this element within the
   107             stack not to the element itself. That is the same clip path in different stacks will
   108             have a different ID since the elements produce different clip result in the context of
   109             their stacks. */
   110         int32_t getGenID() const { SkASSERT(kInvalidGenID != fGenID); return fGenID; }
   112         /**
   113          * Gets the bounds of the clip element, either the rect or path bounds. (Whether the shape
   114          * is inverse filled is not considered.)
   115          */
   116         const SkRect& getBounds() const {
   117             static const SkRect kEmpty = { 0, 0, 0, 0 };
   118             switch (fType) {
   119                 case kRect_Type:  // fallthrough
   120                 case kRRect_Type:
   121                     return fRRect.getBounds();
   122                 case kPath_Type:
   123                     return fPath.get()->getBounds();
   124                 case kEmpty_Type:
   125                     return kEmpty;
   126                 default:
   127                     SkDEBUGFAIL("Unexpected type.");
   128                     return kEmpty;
   129             }
   130         }
   132         /**
   133          * Conservatively checks whether the clip shape contains the rect param. (Whether the shape
   134          * is inverse filled is not considered.)
   135          */
   136         bool contains(const SkRect& rect) const {
   137             switch (fType) {
   138                 case kRect_Type:
   139                     return this->getRect().contains(rect);
   140                 case kRRect_Type:
   141                     return fRRect.contains(rect);
   142                 case kPath_Type:
   143                     return fPath.get()->conservativelyContainsRect(rect);
   144                 case kEmpty_Type:
   145                     return false;
   146                 default:
   147                     SkDEBUGFAIL("Unexpected type.");
   148                     return false;
   149             }
   150         }
   152         /**
   153          * Is the clip shape inverse filled.
   154          */
   155         bool isInverseFilled() const {
   156             return kPath_Type == fType && fPath.get()->isInverseFillType();
   157         }
   159     private:
   160         friend class SkClipStack;
   162         SkTLazy<SkPath> fPath;
   163         SkRRect         fRRect;
   164         int             fSaveCount; // save count of stack when this element was added.
   165         SkRegion::Op    fOp;
   166         Type            fType;
   167         bool            fDoAA;
   169         /* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's
   170            bound. When fFiniteBoundType is kNormal_BoundsType, fFiniteBound represents the
   171            conservative bounding box of the pixels that aren't clipped (i.e., any pixels that can be
   172            drawn to are inside the bound). When fFiniteBoundType is kInsideOut_BoundsType (which
   173            occurs when a clip is inverse filled), fFiniteBound represents the conservative bounding
   174            box of the pixels that _are_ clipped (i.e., any pixels that cannot be drawn to are inside
   175            the bound). When fFiniteBoundType is kInsideOut_BoundsType the actual bound is the
   176            infinite plane. This behavior of fFiniteBoundType and fFiniteBound is required so that we
   177            can capture the cancelling out of the extensions to infinity when two inverse filled
   178            clips are Booleaned together. */
   179         SkClipStack::BoundsType fFiniteBoundType;
   180         SkRect                  fFiniteBound;
   182         // When element is applied to the previous elements in the stack is the result known to be
   183         // equivalent to a single rect intersection? IIOW, is the clip effectively a rectangle.
   184         bool                    fIsIntersectionOfRects;
   186         int                     fGenID;
   188         Element(int saveCount) {
   189             this->initCommon(saveCount, SkRegion::kReplace_Op, false);
   190             this->setEmpty();
   191         }
   193         Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
   194             this->initRRect(saveCount, rrect, op, doAA);
   195         }
   197         Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
   198             this->initRect(saveCount, rect, op, doAA);
   199         }
   201         Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) {
   202             this->initPath(saveCount, path, op, doAA);
   203         }
   205         void initCommon(int saveCount, SkRegion::Op op, bool doAA) {
   206             fSaveCount = saveCount;
   207             fOp = op;
   208             fDoAA = doAA;
   209             // A default of inside-out and empty bounds means the bounds are effectively void as it
   210             // indicates that nothing is known to be outside the clip.
   211             fFiniteBoundType = kInsideOut_BoundsType;
   212             fFiniteBound.setEmpty();
   213             fIsIntersectionOfRects = false;
   214             fGenID = kInvalidGenID;
   215         }
   217         void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) {
   218             fRRect.setRect(rect);
   219             fType = kRect_Type;
   220             this->initCommon(saveCount, op, doAA);
   221         }
   223         void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) {
   224             SkRRect::Type type = rrect.getType();
   225             fRRect = rrect;
   226             if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) {
   227                 fType = kRect_Type;
   228             } else {
   229                 fType = kRRect_Type;
   230             }
   231             this->initCommon(saveCount, op, doAA);
   232         }
   234         void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA);
   236         void setEmpty();
   238         // All Element methods below are only used within SkClipStack.cpp
   239         inline void checkEmpty() const;
   240         inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const;
   241         /* This method checks to see if two rect clips can be safely merged into one. The issue here
   242           is that to be strictly correct all the edges of the resulting rect must have the same
   243           anti-aliasing. */
   244         bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const;
   245         /** Determines possible finite bounds for the Element given the previous element of the
   246             stack */
   247         void updateBoundAndGenID(const Element* prior);
   248         // The different combination of fill & inverse fill when combining bounding boxes
   249         enum FillCombo {
   250             kPrev_Cur_FillCombo,
   251             kPrev_InvCur_FillCombo,
   252             kInvPrev_Cur_FillCombo,
   253             kInvPrev_InvCur_FillCombo
   254         };
   255         // per-set operation functions used by updateBoundAndGenID().
   256         inline void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite);
   257         inline void combineBoundsXOR(int combination, const SkRect& prevFinite);
   258         inline void combineBoundsUnion(int combination, const SkRect& prevFinite);
   259         inline void combineBoundsIntersection(int combination, const SkRect& prevFinite);
   260         inline void combineBoundsRevDiff(int combination, const SkRect& prevFinite);
   261     };
   263     SkClipStack();
   264     SkClipStack(const SkClipStack& b);
   265     explicit SkClipStack(const SkRect& r);
   266     explicit SkClipStack(const SkIRect& r);
   267     ~SkClipStack();
   269     SkClipStack& operator=(const SkClipStack& b);
   270     bool operator==(const SkClipStack& b) const;
   271     bool operator!=(const SkClipStack& b) const { return !(*this == b); }
   273     void reset();
   275     int getSaveCount() const { return fSaveCount; }
   276     void save();
   277     void restore();
   279     /**
   280      * getBounds places the current finite bound in its first parameter. In its
   281      * second, it indicates which kind of bound is being returned. If
   282      * 'canvFiniteBound' is a normal bounding box then it encloses all writeable
   283      * pixels. If 'canvFiniteBound' is an inside out bounding box then it
   284      * encloses all the un-writeable pixels and the true/normal bound is the
   285      * infinite plane. isIntersectionOfRects is an optional parameter
   286      * that is true if 'canvFiniteBound' resulted from an intersection of rects.
   287      */
   288     void getBounds(SkRect* canvFiniteBound,
   289                    BoundsType* boundType,
   290                    bool* isIntersectionOfRects = NULL) const;
   292     /**
   293      * Takes an input rect in device space and conservatively clips it to the
   294      * clip-stack. If false is returned then the rect does not intersect the
   295      * clip and is unmodified.
   296      */
   297     bool intersectRectWithClip(SkRect* devRect) const;
   299     /**
   300      * Returns true if the input rect in device space is entirely contained
   301      * by the clip. A return value of false does not guarantee that the rect
   302      * is not contained by the clip.
   303      */
   304     bool quickContains(const SkRect& devRect) const;
   306     void clipDevRect(const SkIRect& ir, SkRegion::Op op) {
   307         SkRect r;
   308         r.set(ir);
   309         this->clipDevRect(r, op, false);
   310     }
   311     void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
   312     void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA);
   313     void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
   314     // An optimized version of clipDevRect(emptyRect, kIntersect, ...)
   315     void clipEmpty();
   317     /**
   318      * isWideOpen returns true if the clip state corresponds to the infinite
   319      * plane (i.e., draws are not limited at all)
   320      */
   321     bool isWideOpen() const;
   323     /**
   324      * The generation ID has three reserved values to indicate special
   325      * (potentially ignorable) cases
   326      */
   327     static const int32_t kInvalidGenID = 0;     //!< Invalid id that is never returned by
   328                                                 //!< SkClipStack. Useful when caching clips
   329                                                 //!< based on GenID.
   330     static const int32_t kEmptyGenID = 1;       // no pixels writeable
   331     static const int32_t kWideOpenGenID = 2;    // all pixels writeable
   333     int32_t getTopmostGenID() const;
   335 public:
   336     class Iter {
   337     public:
   338         enum IterStart {
   339             kBottom_IterStart = SkDeque::Iter::kFront_IterStart,
   340             kTop_IterStart = SkDeque::Iter::kBack_IterStart
   341         };
   343         /**
   344          * Creates an uninitialized iterator. Must be reset()
   345          */
   346         Iter();
   348         Iter(const SkClipStack& stack, IterStart startLoc);
   350         /**
   351          *  Return the clip element for this iterator. If next()/prev() returns NULL, then the
   352          *  iterator is done.
   353          */
   354         const Element* next();
   355         const Element* prev();
   357         /**
   358          * Moves the iterator to the topmost element with the specified RegionOp and returns that
   359          * element. If no clip element with that op is found, the first element is returned.
   360          */
   361         const Element* skipToTopmost(SkRegion::Op op);
   363         /**
   364          * Restarts the iterator on a clip stack.
   365          */
   366         void reset(const SkClipStack& stack, IterStart startLoc);
   368     private:
   369         const SkClipStack* fStack;
   370         SkDeque::Iter      fIter;
   371     };
   373     /**
   374      * The B2TIter iterates from the bottom of the stack to the top.
   375      * It inherits privately from Iter to prevent access to reverse iteration.
   376      */
   377     class B2TIter : private Iter {
   378     public:
   379         B2TIter() {}
   381         /**
   382          * Wrap Iter's 2 parameter ctor to force initialization to the
   383          * beginning of the deque/bottom of the stack
   384          */
   385         B2TIter(const SkClipStack& stack)
   386         : INHERITED(stack, kBottom_IterStart) {
   387         }
   389         using Iter::next;
   391         /**
   392          * Wrap Iter::reset to force initialization to the
   393          * beginning of the deque/bottom of the stack
   394          */
   395         void reset(const SkClipStack& stack) {
   396             this->INHERITED::reset(stack, kBottom_IterStart);
   397         }
   399     private:
   401         typedef Iter INHERITED;
   402     };
   404     /**
   405      * GetConservativeBounds returns a conservative bound of the current clip.
   406      * Since this could be the infinite plane (if inverse fills were involved) the
   407      * maxWidth and maxHeight parameters can be used to limit the returned bound
   408      * to the expected drawing area. Similarly, the offsetX and offsetY parameters
   409      * allow the caller to offset the returned bound to account for translated
   410      * drawing areas (i.e., those resulting from a saveLayer). For finite bounds,
   411      * the translation (+offsetX, +offsetY) is applied before the clamp to the
   412      * maximum rectangle: [0,maxWidth) x [0,maxHeight).
   413      * isIntersectionOfRects is an optional parameter that is true when
   414      * 'devBounds' is the result of an intersection of rects. In this case
   415      * 'devBounds' is the exact answer/clip.
   416      */
   417     void getConservativeBounds(int offsetX,
   418                                int offsetY,
   419                                int maxWidth,
   420                                int maxHeight,
   421                                SkRect* devBounds,
   422                                bool* isIntersectionOfRects = NULL) const;
   424 private:
   425     friend class Iter;
   427     SkDeque fDeque;
   428     int     fSaveCount;
   430     // Generation ID for the clip stack. This is incremented for each
   431     // clipDevRect and clipDevPath call. 0 is reserved to indicate an
   432     // invalid ID.
   433     static int32_t     gGenID;
   435     /**
   436      * Helper for clipDevPath, etc.
   437      */
   438     void pushElement(const Element& element);
   440     /**
   441      * Restore the stack back to the specified save count.
   442      */
   443     void restoreTo(int saveCount);
   445     /**
   446      * Return the next unique generation ID.
   447      */
   448     static int32_t GetNextGenID();
   449 };
   451 #endif

mercurial