| Index: include/gpu/GrClip.h
 | 
| diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
 | 
| index fd8b970e39dc8861695181a369429a0a71d60240..68a4eb92241df7286f212c507f72ea38fbe0d2ce 100644
 | 
| --- a/include/gpu/GrClip.h
 | 
| +++ b/include/gpu/GrClip.h
 | 
| @@ -8,185 +8,125 @@
 | 
|  #ifndef GrClip_DEFINED
 | 
|  #define GrClip_DEFINED
 | 
|  
 | 
| +#include "GrFragmentProcessor.h"
 | 
| +#include "GrTypesPriv.h"
 | 
|  #include "SkClipStack.h"
 | 
|  
 | 
| -struct SkIRect;
 | 
| +class GrClipMaskManager;
 | 
| +class GrPipelineBuilder;
 | 
|  
 | 
|  /**
 | 
| - * GrClip encapsulates the information required to construct the clip
 | 
| - * masks. 'A GrClip is either wide open, just an IRect, just a Rect, or a full clipstack.
 | 
| - * If the clip is a clipstack than the origin is used to translate the stack with
 | 
| - * respect to device coordinates. This allows us to use a clip stack that is
 | 
| - * specified for a root device with a layer device that is restricted to a subset
 | 
| - * of the original canvas. For other clip types the origin will always be (0,0).
 | 
| - *
 | 
| - * NOTE: GrClip *must* point to a const clipstack
 | 
| + * Produced by GrClip. It provides a set of modifications to the drawing state that are used to
 | 
| + * create the final GrPipeline for a GrBatch.
 | 
|   */
 | 
| -class GrClip : SkNoncopyable {
 | 
| +class GrAppliedClip {
 | 
|  public:
 | 
| -    GrClip() : fClipType(kWideOpen_ClipType) {
 | 
| -        fOrigin.setZero();
 | 
| -    }
 | 
| +    GrAppliedClip() : fHasStencilClip(false) {}
 | 
| +    const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; }
 | 
| +    const GrScissorState& scissorState() const { return fScissorState; }
 | 
| +    bool hasStencilClip() const { return fHasStencilClip; }
 | 
|  
 | 
| -    GrClip(const SkIRect& rect) : fClipType(kIRect_ClipType) {
 | 
| -        fOrigin.setZero();
 | 
| -        fClip.fIRect = rect;
 | 
| -    }
 | 
| +private:
 | 
| +    SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP;
 | 
| +    GrScissorState                          fScissorState;
 | 
| +    bool                                    fHasStencilClip;
 | 
|  
 | 
| -    GrClip(const SkRect& rect) : fClipType(kIRect_ClipType) {
 | 
| -        fOrigin.setZero();
 | 
| -        fClip.fIRect.fLeft   = SkScalarRoundToInt(rect.fLeft);
 | 
| -        fClip.fIRect.fTop    = SkScalarRoundToInt(rect.fTop);
 | 
| -        fClip.fIRect.fRight  = SkScalarRoundToInt(rect.fRight);
 | 
| -        fClip.fIRect.fBottom = SkScalarRoundToInt(rect.fBottom);
 | 
| -    }
 | 
| +    friend class GrFixedClip;
 | 
| +    friend class GrClipMaskManager;
 | 
|  
 | 
| -    ~GrClip() { this->reset(); }
 | 
| -
 | 
| -    const GrClip& operator=(const GrClip& other) {
 | 
| -        this->reset();
 | 
| -        fClipType = other.fClipType;
 | 
| -        switch (other.fClipType) {
 | 
| -            case kWideOpen_ClipType:
 | 
| -                fOrigin.setZero();
 | 
| -                break;
 | 
| -            case kClipStack_ClipType:
 | 
| -                fClip.fStack = SkRef(other.clipStack());
 | 
| -                fOrigin = other.origin();
 | 
| -                break;
 | 
| -            case kIRect_ClipType:
 | 
| -                fClip.fIRect = other.irect();
 | 
| -                fOrigin.setZero();
 | 
| -                break;
 | 
| -        }
 | 
| -        return *this;
 | 
| -    }
 | 
| +    typedef SkNoncopyable INHERITED;
 | 
| +};
 | 
|  
 | 
| -    bool operator==(const GrClip& other) const {
 | 
| -        if (this->clipType() != other.clipType()) {
 | 
| -            return false;
 | 
| -        }
 | 
| -
 | 
| -        switch (fClipType) {
 | 
| -            case kWideOpen_ClipType:
 | 
| -                return true;
 | 
| -            case kClipStack_ClipType:
 | 
| -                if (this->origin() != other.origin()) {
 | 
| -                    return false;
 | 
| -                }
 | 
| -
 | 
| -                if (this->clipStack() && other.clipStack()) {
 | 
| -                    return *this->clipStack() == *other.clipStack();
 | 
| -                } else {
 | 
| -                    return this->clipStack() == other.clipStack();
 | 
| -                }
 | 
| -                break;
 | 
| -            case kIRect_ClipType:
 | 
| -                return this->irect() == other.irect();
 | 
| -                break;
 | 
| -        }
 | 
| -        SkFAIL("This should not occur\n");
 | 
| -        return false;
 | 
| -    }
 | 
| +/**
 | 
| + * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and
 | 
| + * fills out a GrAppliedClip instructing the caller on how to set up the draw state.
 | 
| + */
 | 
| +class GrClip {
 | 
| +public:
 | 
| +    virtual bool quickContains(const SkRect&) const = 0;
 | 
| +    virtual void getConservativeBounds(int width, int height, SkIRect* devResult,
 | 
| +                                       bool* isIntersectionOfRects = nullptr) const = 0;
 | 
| +    virtual bool apply(GrClipMaskManager*, const GrPipelineBuilder&, const SkRect* devBounds,
 | 
| +                       GrAppliedClip*) const = 0;
 | 
|  
 | 
| -    bool operator!=(const GrClip& other) const {
 | 
| -        return !(*this == other);
 | 
| -    }
 | 
| +    virtual ~GrClip() {}
 | 
| +};
 | 
|  
 | 
| -    const SkClipStack* clipStack() const {
 | 
| -        SkASSERT(kClipStack_ClipType == fClipType);
 | 
| -        return fClip.fStack;
 | 
| -    }
 | 
| +/**
 | 
| + * Specialized implementation for no clip.
 | 
| + */
 | 
| +class GrNoClip final : public GrClip {
 | 
| +private:
 | 
| +    bool quickContains(const SkRect&) const final { return true; }
 | 
| +    void getConservativeBounds(int width, int height, SkIRect* devResult,
 | 
| +                               bool* isIntersectionOfRects) const final;
 | 
| +    bool apply(GrClipMaskManager*, const GrPipelineBuilder&,
 | 
| +               const SkRect*, GrAppliedClip*) const final { return true; }
 | 
| +};
 | 
|  
 | 
| -    void setClipStack(const SkClipStack* clipStack, const SkIPoint* origin = NULL) {
 | 
| -        this->reset();
 | 
| -        if (clipStack->isWideOpen()) {
 | 
| -            fClipType = kWideOpen_ClipType;
 | 
| -            fOrigin.setZero();
 | 
| -        } else {
 | 
| -            fClipType = kClipStack_ClipType;
 | 
| -            fClip.fStack = SkRef(clipStack);
 | 
| -            if (origin) {
 | 
| -                fOrigin = *origin;
 | 
| -            } else {
 | 
| -                fOrigin.setZero();
 | 
| -            }
 | 
| -        }
 | 
| -    }
 | 
| +/**
 | 
| + * GrFixedClip is a clip that can be represented by fixed-function hardware. It never modifies the
 | 
| + * stencil buffer itself, but can be configured to use whatever clip is already there.
 | 
| + */
 | 
| +class GrFixedClip final : public GrClip {
 | 
| +public:
 | 
| +    GrFixedClip() : fHasStencilClip(false) {}
 | 
| +    GrFixedClip(const SkIRect& scissorRect) : fScissorState(scissorRect), fHasStencilClip(false) {}
 | 
|  
 | 
| -    void setIRect(const SkIRect& irect) {
 | 
| -        this->reset();
 | 
| -        fClipType = kIRect_ClipType;
 | 
| -        fOrigin.setZero();
 | 
| -        fClip.fIRect = irect;
 | 
| +    void reset() {
 | 
| +        fScissorState.setDisabled();
 | 
| +        fHasStencilClip = false;
 | 
|      }
 | 
|  
 | 
| -    const SkIRect& irect() const {
 | 
| -        SkASSERT(kIRect_ClipType == fClipType);
 | 
| -        return fClip.fIRect;
 | 
| +    void reset(const SkIRect& scissorRect) {
 | 
| +        fScissorState.set(scissorRect);
 | 
| +        fHasStencilClip = false;
 | 
|      }
 | 
|  
 | 
| -    void reset() {
 | 
| -        if (kClipStack_ClipType == fClipType) {
 | 
| -            fClip.fStack->unref();
 | 
| -            fClip.fStack = NULL;
 | 
| -        }
 | 
| -        fClipType = kWideOpen_ClipType;
 | 
| -        fOrigin.setZero();
 | 
| -    }
 | 
| +    void enableStencilClip(bool enable) { fHasStencilClip = enable; }
 | 
|  
 | 
| -    // We support this for all cliptypes to simplify the logic a bit in clip mask manager.
 | 
| -    // non clipstack clip types MUST have a (0,0) origin
 | 
| -    const SkIPoint& origin() const {
 | 
| -        SkASSERT(fClipType == kClipStack_ClipType || (fOrigin.fX == 0 && fOrigin.fY == 0));
 | 
| -        return fOrigin;
 | 
| -    }
 | 
| +    const GrScissorState& scissorState() const { return fScissorState; }
 | 
| +    bool hasStencilClip() const { return fHasStencilClip; }
 | 
|  
 | 
| -    bool isWideOpen(const SkRect& rect) const {
 | 
| -        return (kWideOpen_ClipType == fClipType) ||
 | 
| -               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
 | 
| -               (kIRect_ClipType == fClipType && this->irect().contains(rect));
 | 
| -    }
 | 
| +    bool quickContains(const SkRect&) const final;
 | 
| +    void getConservativeBounds(int width, int height, SkIRect* devResult,
 | 
| +                               bool* isIntersectionOfRects) const final;
 | 
|  
 | 
| -    bool isWideOpen(const SkIRect& rect) const {
 | 
| -        return (kWideOpen_ClipType == fClipType) ||
 | 
| -               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) ||
 | 
| -               (kIRect_ClipType == fClipType && this->irect().contains(rect));
 | 
| -    }
 | 
| +private:
 | 
| +    bool apply(GrClipMaskManager*, const GrPipelineBuilder&,
 | 
| +               const SkRect* devBounds, GrAppliedClip* out) const final;
 | 
|  
 | 
| -    bool isWideOpen() const {
 | 
| -        return (kWideOpen_ClipType == fClipType) ||
 | 
| -               (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen());
 | 
| -    }
 | 
| +    GrScissorState   fScissorState;
 | 
| +    bool             fHasStencilClip;
 | 
| +};
 | 
|  
 | 
| -    bool quickContains(const SkRect& rect) const {
 | 
| -        return (kWideOpen_ClipType == fClipType) ||
 | 
| -               (kClipStack_ClipType == fClipType && this->clipStack()->quickContains(rect)) ||
 | 
| -               (kIRect_ClipType == fClipType && this->irect().contains(rect));
 | 
| +/**
 | 
| + * GrClipStackClip can apply a generic SkClipStack to the draw state. It may generate clip masks or
 | 
| + * write to the stencil buffer during apply().
 | 
| + */
 | 
| +class GrClipStackClip final : public GrClip {
 | 
| +public:
 | 
| +    GrClipStackClip(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
 | 
| +        this->reset(stack, origin);
 | 
|      }
 | 
|  
 | 
| -    void getConservativeBounds(int width, int height,
 | 
| -                               SkIRect* devResult,
 | 
| -                               bool* isIntersectionOfRects = NULL) const;
 | 
| -
 | 
| -    static const GrClip& WideOpen();
 | 
| +    void reset(const SkClipStack* stack = nullptr, const SkIPoint* origin = nullptr) {
 | 
| +        fOrigin = origin ? *origin : SkIPoint::Make(0, 0);
 | 
| +        fStack.reset(SkSafeRef(stack));
 | 
| +    }
 | 
|  
 | 
| -    enum ClipType {
 | 
| -        kClipStack_ClipType,
 | 
| -        kWideOpen_ClipType,
 | 
| -        kIRect_ClipType,
 | 
| -    };
 | 
| +    const SkIPoint& origin() const { return fOrigin; }
 | 
| +    const SkClipStack* clipStack() const { return fStack; }
 | 
|  
 | 
| -    ClipType clipType() const { return fClipType; }
 | 
| +    bool quickContains(const SkRect&) const final;
 | 
| +    void getConservativeBounds(int width, int height, SkIRect* devResult,
 | 
| +                               bool* isIntersectionOfRects) const final;
 | 
| +    bool apply(GrClipMaskManager*, const GrPipelineBuilder&,
 | 
| +               const SkRect* devBounds, GrAppliedClip*) const final;
 | 
|  
 | 
|  private:
 | 
| -    union Clip {
 | 
| -        const SkClipStack* fStack;
 | 
| -        SkIRect fIRect;
 | 
| -    } fClip;
 | 
| -
 | 
| -    SkIPoint fOrigin;
 | 
| -    ClipType fClipType;
 | 
| +    SkIPoint                          fOrigin;
 | 
| +    SkAutoTUnref<const SkClipStack>   fStack;
 | 
|  };
 | 
|  
 | 
|  #endif
 | 
| 
 |