GrClipMaskManager.cpp revision d9f7503e0cb0c4db856f53b4bdeec1332db6f296
11e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
21e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com/*
31e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Copyright 2012 Google Inc.
41e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com *
51e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
61e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com * found in the LICENSE file.
71e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com */
81e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
91e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrClipMaskManager.h"
107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com#include "effects/GrTextureDomainEffect.h"
111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h"
121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h"
131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h"
141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrPathRenderer.h"
15a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com#include "GrPaint.h"
166b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h"
17fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAConvexPathRenderer.h"
18fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com#include "GrAAHairLinePathRenderer.h"
1958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrSWMaskHelper.h"
2046a8600405e678718271f62c5994119b8d3241e9robertphillips@google.com#include "GrCacheID.h"
2146a8600405e678718271f62c5994119b8d3241e9robertphillips@google.com
2246a8600405e678718271f62c5994119b8d3241e9robertphillips@google.comGR_DEFINE_RESOURCE_CACHE_DOMAIN(GrClipMaskManager, GetAlphaMaskDomain)
23a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
24ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com#define GR_AA_CLIP 1
25a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
26f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
27a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.comnamespace {
28fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the
2908283afc265f1153834256fc1012519813ba6b73bsalomon@google.com// stage matrix this also alters the vertex layout
30fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comvoid setup_drawstate_aaclip(GrGpu* gpu,
31fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                            GrTexture* result,
327b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                            const GrIRect &devBound) {
33a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrDrawState* drawState = gpu->drawState();
34a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrAssert(drawState);
35a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
36dfdb7e5240276493077b7c6e1f3cc8b8a0e195babsalomon@google.com    static const int kMaskStage = GrPaint::kTotalStages+1;
37a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
38b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix mat;
39a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.setIDiv(result->width(), result->height());
40fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    mat.preTranslate(SkIntToScalar(-devBound.fLeft),
417b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                     SkIntToScalar(-devBound.fTop));
42a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.preConcat(drawState->getViewMatrix());
43a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
4408283afc265f1153834256fc1012519813ba6b73bsalomon@google.com    drawState->stage(kMaskStage)->reset();
457b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
467b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
477b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->stage(kMaskStage)->setEffect(
487b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        GrTextureDomainEffect::Create(result,
497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      mat,
507b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::MakeTexelDomain(result, domainTexels),
517b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::kDecal_WrapMode))->unref();
52a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
53a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
548a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool path_needs_SW_renderer(GrContext* context,
5513b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            GrGpu* gpu,
5613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            const SkPath& path,
5713b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            GrPathFill fill,
5813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            bool doAA) {
598a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // last (false) parameter disallows use of the SW path renderer
608a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    return NULL == context->getPathRenderer(path, fill, gpu, doAA, false);
618a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com}
628a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com
63a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.comGrPathFill get_path_fill(const SkPath& path) {
64a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    switch (path.getFillType()) {
65a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        case SkPath::kWinding_FillType:
66a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            return kWinding_GrPathFill;
67a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        case SkPath::kEvenOdd_FillType:
68a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            return  kEvenOdd_GrPathFill;
69a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        case SkPath::kInverseWinding_FillType:
70a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            return kInverseWinding_GrPathFill;
71a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        case SkPath::kInverseEvenOdd_FillType:
72a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            return kInverseEvenOdd_GrPathFill;
73a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        default:
74a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            GrCrash("Unsupported path fill in clip.");
75a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            return kWinding_GrPathFill; // suppress warning
76a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    }
77a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com}
78a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
79b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com/**
80b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com * Does any individual clip in 'clipIn' use anti-aliasing?
81b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com */
82641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.combool requires_AA(const SkClipStack& clipIn) {
83b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
84641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    SkClipStack::Iter iter;
85641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    iter.reset(clipIn, SkClipStack::Iter::kBottom_IterStart);
86b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
87641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    const SkClipStack::Iter::Clip* clip = NULL;
88b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com    for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
89b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com         NULL != clip;
90e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com         clip = iter.nextCombined()) {
91b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
92b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com        if (clip->fDoAA) {
93b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com            return true;
94b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com        }
95b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com    }
96b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
97b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com    return false;
98b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com}
99b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
1006b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
1016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
102fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/*
103fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer
104fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the
105fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu.
106fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */
107641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.combool GrClipMaskManager::useSWOnlyPath(const SkClipStack& clipIn) {
108a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
1098a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // TODO: generalize this function so that when
110fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // a clip gets complex enough it can just be done in SW regardless
111fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // of whether it would invoke the GrSoftwarePathRenderer.
112fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    bool useSW = false;
113fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
114641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    SkClipStack::Iter iter(clipIn, SkClipStack::Iter::kBottom_IterStart);
115641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    const SkClipStack::Iter::Clip* clip = NULL;
116fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
117a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    for (clip = iter.skipToTopmost(SkRegion::kReplace_Op);
118a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com         NULL != clip;
119e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com         clip = iter.nextCombined()) {
120fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
121f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com        // rects can always be drawn directly w/o using the software path
122f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com        // so only paths need to be checked
123a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (NULL != clip->fPath &&
124fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            path_needs_SW_renderer(this->getContext(), fGpu,
125fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                                   *clip->fPath,
126a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                                   get_path_fill(*clip->fPath),
127a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                                   clip->fDoAA)) {
128f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com            useSW = true;
129fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
130fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    }
131fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
132fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    return useSW;
133a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
134a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
135f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1366b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil,
1376b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software
138beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn) {
139c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kNone_ClipMaskType;
140a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
14113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
142f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com    if (!drawState->isClipState() || clipDataIn->fClipStack->isWideOpen()) {
143a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        fGpu->disableScissor();
144a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        this->setGpuStencil();
1451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return true;
1461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
1471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
1491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // GrDrawTarget should have filtered this for us
1501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
1511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1527b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    GrIRect devClipBounds;
153e4d69c0e46c1a000eb89ef950bdaf0aea680a816robertphillips@google.com    bool isIntersectionOfRects = false;
1543e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com
1557b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    clipDataIn->getConservativeBounds(rt, &devClipBounds, &isIntersectionOfRects);
1567b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    if (devClipBounds.isEmpty()) {
1573e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com        return false;
158a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
159a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1606794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com#if GR_AA_CLIP
161beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com    bool requiresAA = requires_AA(*clipDataIn->fClipStack);
162b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
163a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // If MSAA is enabled we can do everything in the stencil buffer.
164fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // Otherwise check if we should just create the entire clip mask
165a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // in software (this will only happen if the clip mask is anti-aliased
166a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // and too complex for the gpu to handle in its entirety)
167f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com    if (0 == rt->numSamples() &&
168fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        requiresAA &&
169beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        this->useSWOnlyPath(*clipDataIn->fClipStack)) {
1706b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        // The clip geometry is complex enough that it will be more
1716b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        // efficient to create it entirely in software
1726b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        GrTexture* result = NULL;
1737b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        GrIRect devBound;
1747b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        if (this->createSoftwareClipMask(*clipDataIn, &result, &devBound)) {
1757b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            setup_drawstate_aaclip(fGpu, result, devBound);
176a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableScissor();
177a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            this->setGpuStencil();
1786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            return true;
1796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
180a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
181a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        // if SW clip mask creation fails fall through to the other
182a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com        // two possible methods (bottoming out at stencil clipping)
1836b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
1846b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
185f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // If MSAA is enabled use the (faster) stencil path for AA clipping
186f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // otherwise the alpha clip mask is our only option
187b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com    if (0 == rt->numSamples() && requiresAA) {
188f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // Since we are going to create a destination texture of the correct
189f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // size for the mask (rather than being bound by the size of the
190f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // render target) we aren't going to use scissoring like the stencil
191f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // path does (see scissorSettings below)
192a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com        GrTexture* result = NULL;
1937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        GrIRect devBound;
1947b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        if (this->createAlphaClipMask(*clipDataIn, &result, &devBound)) {
1957b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            setup_drawstate_aaclip(fGpu, result, devBound);
196a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableScissor();
197a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            this->setGpuStencil();
198f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            return true;
199f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
200f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
201f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // if alpha clip mask creation fails fall through to the stencil
202f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        // buffer method
203f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
204f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP
205f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
206fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // Either a hard (stencil buffer) clip was explicitly requested or
2075acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // an antialiased clip couldn't be created. In either case, free up
2085acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // the texture in the antialiased mask cache.
2095acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // TODO: this may require more investigation. Ganesh performs a lot of
210a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit
211fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // the stencil buffer path. These may be "incorrectly" clearing the
2125acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    // AA cache.
2135acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    fAACache.reset();
2145acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com
215a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // If the clip is a rectangle then just set the scissor. Otherwise, create
216a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // a stencil mask.
217f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com    if (isIntersectionOfRects) {
2187b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        fGpu->enableScissor(devClipBounds);
219a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        this->setGpuStencil();
220a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return true;
2211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
2221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // use the stencil clip if we can't represent the clip as a rectangle.
224fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    bool useStencil = !clipDataIn->fClipStack->isWideOpen() &&
2257b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                      !devClipBounds.isEmpty();
2261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
227c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    if (useStencil) {
2287b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        this->createStencilClipMask(*clipDataIn, devClipBounds);
2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
230a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // This must occur after createStencilClipMask. That function may change
231a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // the scissor. Also, it only guarantees that the stencil mask is correct
232a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // within the bounds it was passed, so we must use both stencil and scissor
233a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // test to the bounds for the final draw.
2347b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    fGpu->enableScissor(devClipBounds);
235a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->setGpuStencil();
2361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
2371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
2381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0
2401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP
2421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #include "GrRandom.h"
2431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRandom gRandom;
2441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
2451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else
2461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR
2471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
2481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace {
2506623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com/**
2517b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * Does "canvContainer" contain "devContainee"? If either is empty then
2527b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * no containment is possible. "canvContainer" is in canvas coordinates while
2537b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com * "devContainee" is in device coordiates. "origin" provides the mapping between
254f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com * the two.
2556623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com */
256fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.combool contains(const SkRect& canvContainer,
2577b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com              const SkIRect& devContainee,
258f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com              const SkIPoint& origin) {
2597b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    return  !devContainee.isEmpty() && !canvContainer.isEmpty() &&
260fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            canvContainer.fLeft <= SkIntToScalar(devContainee.fLeft+origin.fX) &&
2617b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            canvContainer.fTop <= SkIntToScalar(devContainee.fTop+origin.fY) &&
262fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            canvContainer.fRight >= SkIntToScalar(devContainee.fRight+origin.fX) &&
2637b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            canvContainer.fBottom >= SkIntToScalar(devContainee.fBottom+origin.fY);
2646623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com}
2656623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com
266f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
2671e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// determines how many elements at the head of the clip can be skipped and
2681e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// whether the initial clear should be to the inside- or outside-the-clip value,
2691e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com// and what op should be used to draw the first element that isn't skipped.
270641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.comconst SkClipStack::Iter::Clip* process_initial_clip_elements(
271641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com                                  SkClipStack::Iter* iter,
2727b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                  const GrIRect& devBounds,
2731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                  bool* clearToInside,
274f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                  SkRegion::Op* firstOp,
275f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                  const GrClipData& clipData) {
276a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
277a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    GrAssert(NULL != iter && NULL != clearToInside && NULL != firstOp);
2781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
279fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // logically before the first element of the clip stack is
2801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // processed the clip is entirely open. However, depending on the
2811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // first set op we may prefer to clear to 0 for performance. We may
2821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // also be able to skip the initial clip paths/rects. We loop until
2831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // we cannot skip an element.
2841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    bool done = false;
2851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    *clearToInside = true;
2861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
287641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    const SkClipStack::Iter::Clip* clip = NULL;
288a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
289a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    for (clip = iter->skipToTopmost(SkRegion::kReplace_Op);
290a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com         NULL != clip && !done;
291e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com         clip = iter->nextCombined()) {
292a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        switch (clip->fOp) {
2930f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kReplace_Op:
2941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // replace ignores everything previous
295a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                *firstOp = SkRegion::kReplace_Op;
2961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *clearToInside = false;
2971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                done = true;
2981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
2990f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kIntersect_Op:
3001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if this element contains the entire bounds then we
3011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // can skip it.
302f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                if (NULL != clip->fRect &&
3037b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    contains(*clip->fRect, devBounds, clipData.fOrigin)) {
3041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    break;
3051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if everything is initially clearToInside then intersect is
3071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // same as clear to 0 and treat as a replace. Otherwise,
3081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // set stays empty.
3091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
310a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kReplace_Op;
3111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *clearToInside = false;
3121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // we can skip a leading union.
3160f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kUnion_Op:
3171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if everything is initially outside then union is
318fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                // same as replace. Otherwise, every pixel is still
3191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // clearToInside
3201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (!*clearToInside) {
321a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kReplace_Op;
3221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3250f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kXOR_Op:
3261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // xor is same as difference or replace both of which
3271e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // can be 1-pass instead of 2 for xor.
3281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
329a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kDifference_Op;
3301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
331a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kReplace_Op;
3321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                done = true;
3341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3350f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kDifference_Op:
3361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if all pixels are clearToInside then we have to process the
3371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // difference, otherwise it has no effect and all pixels
3381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // remain outside.
3391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
340a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kDifference_Op;
3411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3440f191f30af7c067883c97b034baf70bfd92f5ea0robertphillips@google.com            case SkRegion::kReverseDifference_Op:
3451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // if all pixels are clearToInside then reverse difference
3466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                // produces empty set. Otherwise it is same as replace
3471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (*clearToInside) {
3481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *clearToInside = false;
3491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
350a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    *firstOp = SkRegion::kReplace_Op;
3511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
3521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                break;
3541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            default:
3551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GrCrash("Unknown set op.");
3561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
357a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
358a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (done) {
359a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            // we need to break out here (rather than letting the test in
360a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            // the loop do it) since backing up the iterator is very expensive
361a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            break;
362a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        }
3631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
364a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    return clip;
3651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
366f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
367f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
369f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.comnamespace {
370f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
371f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
372fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the OpenGL blend function to perform the specified
373fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// boolean operation for alpha clip mask creation
3746b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
375f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
376f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    switch (op) {
377f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReplace_Op:
37847059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
379f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
380f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kIntersect_Op:
38147059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
382f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
383f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kUnion_Op:
38447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
385f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
386f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kXOR_Op:
38747059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
388f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
389f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kDifference_Op:
39047059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
391f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
392f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReverseDifference_Op:
39347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
394f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
395f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        default:
396f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            GrAssert(false);
397f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
398f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
399f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
400f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
401366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com
402366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com////////////////////////////////////////////////////////////////////////////////
40372176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com
4047b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com// 'rect' enters in device coordinates and leaves in canvas coordinates
4057b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.comvoid device_to_canvas(SkRect* rect, const SkIPoint& origin) {
4067b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    GrAssert(NULL != rect);
4077b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com
4087b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    rect->fLeft   += SkIntToScalar(origin.fX);
4097b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    rect->fTop    += SkIntToScalar(origin.fY);
4107b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    rect->fRight  += SkIntToScalar(origin.fX);
4117b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    rect->fBottom += SkIntToScalar(origin.fY);
4127b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com}
4137b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com
41472176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com}
415f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
416f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
41713b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.combool GrClipMaskManager::drawClipShape(GrTexture* target,
418641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com                                      const SkClipStack::Iter::Clip* clip,
4196794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                                      const SkIRect& clipRect) {
42013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
421f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
422f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
423f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
424f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4256794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    GrDrawTarget::AutoClipRestore acr(fGpu);
4266794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkClipStack rectStack(clipRect);
4276794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    GrClipData cd;
4286794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    cd.fClipStack = &rectStack;
4296794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    cd.fOrigin.setZero();
4306794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    fGpu->setClip(&cd);
4316794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
432a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    if (NULL != clip->fRect) {
433a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (clip->fDoAA) {
43413b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com            getContext()->getAARectRenderer()->fillAARect(fGpu, fGpu,
435f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                                          *clip->fRect,
436f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com                                                          true);
437f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
438a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            fGpu->drawSimpleRect(*clip->fRect, NULL);
439f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
440a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    } else if (NULL != clip->fPath) {
4416794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
4426794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        GrPathRenderer* pr = this->getContext()->getPathRenderer(*clip->fPath,
4436794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                                                                 get_path_fill(*clip->fPath),
4446794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                                                                 fGpu,
4456794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                                                                 clip->fDoAA,
4466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                                                                 false);
4476794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        if (NULL == pr) {
4486794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            GrAssert(false); // We should have done the whole clip-stack in SW.
4496794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            return false;
4506794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        }
4516794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
4526794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        pr->drawPath(*clip->fPath, get_path_fill(*clip->fPath), fGpu, clip->fDoAA);
453f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
454f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
455f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
456f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4577b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.comvoid GrClipMaskManager::mergeMask(GrTexture* dstMask,
4587b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  GrTexture* srcMask,
4597b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  SkRegion::Op op,
4607b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  const GrIRect& dstBound,
4617b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  const GrIRect& srcBound) {
46213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
463f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
4647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkMatrix oldMatrix = drawState->getViewMatrix();
4657b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->viewMatrix()->reset();
466f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4677b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->setRenderTarget(dstMask->asRenderTarget());
468f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4697b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    setup_boolean_blendcoeffs(drawState, op);
47072b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com
471b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix sampleM;
4727b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    sampleM.setIDiv(srcMask->width(), srcMask->height());
4737b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->stage(0)->setEffect(
4747b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        GrTextureDomainEffect::Create(srcMask,
4757b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      sampleM,
4767b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound),
4777b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::kDecal_WrapMode))->unref();
4787b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL);
479f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
480676e66096c60615bac52f365111596de5c4ca8a6tomhudson@google.com    drawState->disableStage(0);
4817b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->setViewMatrix(oldMatrix);
482f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
483f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4846d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations
4856d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too
486fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comvoid GrClipMaskManager::getTemp(const GrIRect& bounds,
487f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com                                GrAutoScratchTexture* temp) {
488f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    if (NULL != temp->texture()) {
4896d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        // we've already allocated the temp texture
4906d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        return;
4916d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    }
4926d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
49375b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    GrTextureDesc desc;
49475b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit;
49575b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fWidth = bounds.width();
49675b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fHeight = bounds.height();
49775b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fConfig = kAlpha_8_GrPixelConfig;
4986b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
4992c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    temp->set(this->getContext(), desc);
5006d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com}
5016d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
5026d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
503641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.comvoid GrClipMaskManager::setupCache(const SkClipStack& clipIn,
5046623fcd1ee33b35fa18e304e9c76272faa603cbfrobertphillips@google.com                                   const GrIRect& bounds) {
505f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    // Since we are setting up the cache we know the last lookup was a miss
506f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    // Free up the currently cached mask so it can be reused
507f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.reset();
5086d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
50975b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    GrTextureDesc desc;
51075b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit;
51175b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fWidth = bounds.width();
51275b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fHeight = bounds.height();
51375b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fConfig = kAlpha_8_GrPixelConfig;
514f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
515f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.acquireMask(clipIn, desc, bounds);
516f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com}
517f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5186b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
5196b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Shared preamble between gpu and SW-only AA clip mask creation paths.
5206b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Handles caching, determination of clip mask bound & allocation (if needed)
5216b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// of the result texture
5226b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Returns true if there is no more work to be done (i.e., we got a cache hit)
523beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::clipMaskPreamble(const GrClipData& clipDataIn,
5246b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                         GrTexture** result,
5257b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                         GrIRect* devResultBounds) {
52613b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* origDrawState = fGpu->drawState();
527f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(origDrawState->isClipState());
528f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
529f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrRenderTarget* rt = origDrawState->getRenderTarget();
530f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != rt);
531f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
532f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // unlike the stencil path the alpha path is not bound to the size of the
533f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // render target - determine the minimum size required for the mask
534f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com    // Note: intBounds is in device (as opposed to canvas) coordinates
5359cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com    clipDataIn.getConservativeBounds(rt, devResultBounds);
536f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
537f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // need to outset a pixel since the standard bounding box computation
5386794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // path doesn't leave any room for anti-aliasing (esp. w.r.t. rects)
5399cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com    devResultBounds->outset(1, 1);
540f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
541a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    // TODO: make sure we don't outset if bounds are still 0,0 @ min
542a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
543ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com    if (fAACache.canReuse(*clipDataIn.fClipStack, *devResultBounds)) {
5448fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com        *result = fAACache.getLastMask();
5457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        fAACache.getLastBound(devResultBounds);
5468fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com        return true;
5478fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    }
5488fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com
5499cb5adf50dc3e8f83904380934b08d135229ef6frobertphillips@google.com    this->setupCache(*clipDataIn.fClipStack, *devResultBounds);
5506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    return false;
5516b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
552f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
5536794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.comnamespace {
5546794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com// Does a look-ahead to check whether we can bound earlier mask generation by forthcoming
5556794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com// intersections.
5566794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.comvoid get_current_mask_bounds(const SkIRect& maskResultBounds,
5576794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                             const SkClipStack::Iter& curr,
5586794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                             const SkVector& clipToMaskOffset,
5596794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                             SkRect* currMaskBounds) {
5606794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkClipStack::Iter isectIter(curr);
5616794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    const SkClipStack::Iter::Clip* clip = isectIter.skipToNext(SkRegion::kIntersect_Op);
5626794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    if (NULL != clip) {
5636794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        *currMaskBounds = clip->getBounds();
5646794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        while (NULL != (clip = isectIter.next()) &&
5656794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com               SkRegion::kIntersect_Op == clip->fOp &&
5666794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com               !clip->isInverseFilled()) {
5676794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            currMaskBounds->intersect(clip->getBounds());
5686794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        }
5696794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        currMaskBounds->offset(clipToMaskOffset);
5706794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        currMaskBounds->intersect(SkRect::MakeFromIRect(maskResultBounds));
5716794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    } else {
5726794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        *currMaskBounds = SkRect::MakeFromIRect(maskResultBounds);
5736794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    }
5746794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com}
5756794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com}
5766794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
5776b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
5786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha
579beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createAlphaClipMask(const GrClipData& clipDataIn,
5806b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                            GrTexture** result,
5817b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                            GrIRect *devResultBounds) {
5827b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    GrAssert(NULL != devResultBounds);
583c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
584c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com
5857b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) {
586c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com        fCurrClipMaskType = kAlpha_ClipMaskType;
5876b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return true;
5886b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
589f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
590f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com    // Note: 'resultBounds' is in device (as opposed to canvas) coordinates
591f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com
592f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrTexture* accum = fAACache.getLastMask();
5936d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    if (NULL == accum) {
594f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
595f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        return false;
596f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
597f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
59813b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
59913b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
600f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
60113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawTarget::AutoGeometryPush agp(fGpu);
602f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6037b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // The mask we generate is translated so that its upper-left corner is at devResultBounds
6047b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // upper-left corner in device space.
6057b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    GrIRect maskResultBounds = GrIRect::MakeWH(devResultBounds->width(), devResultBounds->height());
6067b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
6077b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // Set the matrix so that rendered clip elements are transformed from the space of the clip
6087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // stack to the alpha-mask. This accounts for both translation due to the clip-origin and the
6097b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // placement of the mask within the device.
6107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkVector clipToMaskOffset = {
6117b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        SkIntToScalar(-devResultBounds->fLeft - clipDataIn.fOrigin.fX),
6127b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        SkIntToScalar(-devResultBounds->fTop - clipDataIn.fOrigin.fY)
6137b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    };
6147b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->viewMatrix()->setTranslate(clipToMaskOffset);
615f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
616f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    bool clearToInside;
617a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
618a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
6196794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkClipStack::Iter iter(*clipDataIn.fClipStack, SkClipStack::Iter::kBottom_IterStart);
6206794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    iter.skipToTopmost(SkRegion::kReplace_Op);
6216794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
622641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
6237b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                                              *devResultBounds,
624a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                                                              &clearToInside,
625f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                                              &firstOp,
626f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                                              clipDataIn);
6277b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // The scratch texture that we are drawing into can be substantially larger than the mask. Only
6287b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // clear the part that we care about.
6297b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    fGpu->clear(&maskResultBounds,
630fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                clearToInside ? 0xffffffff : 0x00000000,
631c82a8b7aa4ec19fba508c394920a9e88d3e5bd12robertphillips@google.com                accum->asRenderTarget());
6326794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    GR_DEBUGCODE(bool accumClearedToZero = !clearToInside;)
633f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
634d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com
635f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrAutoScratchTexture temp;
636a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    bool first = true;
6376794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
6386794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // We bound mask-generation to both the known bounds of the final result as well as the bounds
6396794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // of the next run of intersections. This limits the amount of clearing and merging we have
6406794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // to do and can also allow us to skip intersect-rects entirely.
6416794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkRect currMaskBounds;
6426794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkIRect currMaskIBounds;
6436794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    get_current_mask_bounds(maskResultBounds, iter, clipToMaskOffset, &currMaskBounds);
6446794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // currMaskBounds is used to reduce the number of pixels touched. It also allows us to skip
6456794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // non-AA intersect rects since we've clipped earlier elements to those rects already.
6466794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // We round out here which is consistent with how non-AA rects are handled.
6476794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    currMaskBounds.roundOut(&currMaskIBounds);
6486794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
6496794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    // used to know when we're through with a run of intersect ops.
6506794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com    SkRegion::Op prevOp = SkRegion::kReplace_Op;
6516794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
652f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // walk through each clip element and perform its set op
653e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com    for ( ; NULL != clip; clip = iter.nextCombined()) {
654f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
655a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        SkRegion::Op op = clip->fOp;
656a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (first) {
657a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            first = false;
658a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            op = firstOp;
659a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        }
660f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6616794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        if (op == SkRegion::kIntersect_Op) {
6626794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // When we encounter an intersect we may have already fully accounted for it by applying
6636794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // currMaskBounds to the accumulated mask.
6646794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            if (NULL != clip->fRect &&
6656794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                (!clip->fDoAA || clip->fRect->contains(currMaskBounds))) {
6666794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                prevOp = SkRegion::kIntersect_Op;
6676794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com                continue;
6687b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            }
6696794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        } else if (prevOp == SkRegion::kIntersect_Op) {
6706794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // We've finished a run of intersects, update currMaskBounds based on the next run.
6716794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            get_current_mask_bounds(maskResultBounds, iter, clipToMaskOffset, &currMaskBounds);
6726794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            currMaskBounds.roundOut(&currMaskIBounds);
6736794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        }
67472b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com
6756794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        prevOp = op;
6766794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com
6776794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        if (SkRegion::kReplace_Op == op) {
6786794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // The accumulator should already be cleared. There can only be one replace since we
6796794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // skip to the last one. Moreover, process_initial_clip_elements will have set
6806794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // clearToInside to false before the initial clear.
6816794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            GrAssert(accumClearedToZero);
6826b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
6836794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            this->drawClipShape(accum, clip, currMaskIBounds);
684f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
685f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else if (SkRegion::kReverseDifference_Op == op ||
686f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                   SkRegion::kIntersect_Op == op) {
6876794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // There is no point in intersecting a screen filling rectangle.
688f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com            if (SkRegion::kIntersect_Op == op && NULL != clip->fRect &&
6897b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                contains(*clip->fRect, *devResultBounds, clipDataIn.fOrigin)) {
690f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                continue;
691f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            }
692f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            getTemp(*devResultBounds, &temp);
694f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com            if (NULL == temp.texture()) {
695f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com                fAACache.reset();
6966d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com                return false;
6976d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com            }
6986d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
6996794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // This is the bounds of the clip element in the space of the alpha-mask. The temporary
7007b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // mask buffer can be substantially larger than the actually clip stack element. We
7017b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // touch the minimum number of pixels necessary and use decal mode to combine it with
7026794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // the accumulator.
7037b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            GrRect elementMaskBounds = clip->getBounds();
7047b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            elementMaskBounds.offset(clipToMaskOffset);
7056794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            elementMaskBounds.intersect(currMaskBounds);
7067b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            GrIRect elementMaskIBounds;
7077b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            elementMaskBounds.roundOut(&elementMaskIBounds);
7087b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
7096794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // Clear the temp target & draw into it
7107b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            fGpu->clear(&elementMaskIBounds, 0x00000000, temp.texture()->asRenderTarget());
711f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
7126b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
7136794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            this->drawClipShape(temp.texture(), clip, currMaskIBounds);
714f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
7156794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // Now draw into the accumulator using the real operation and the temp buffer as a
7166794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            // texture
7177b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            this->mergeMask(accum, temp.texture(), op, maskResultBounds, elementMaskIBounds);
718f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
719fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            // all the remaining ops can just be directly draw into
720f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            // the accumulation buffer
7216b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
7226794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com            this->drawClipShape(accum, clip, currMaskIBounds);
723f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
7246794a258e39358e8003b5106247db1b6812d8c84bsalomon@google.com        GR_DEBUGCODE(accumClearedToZero = false;)
725f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
726f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
727a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    *result = accum;
728c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
729f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
7301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
7311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
732f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
733fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
734f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com// (as opposed to canvas) coordinates
735beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createStencilClipMask(const GrClipData& clipDataIn,
7367b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                              const GrIRect& devClipBounds) {
7371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
738c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
7391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
74013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
7411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(drawState->isClipState());
7421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
7441e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
7451e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // TODO: dynamically attach a SB when needed.
7471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
7481e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (NULL == stencilBuffer) {
7491e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return false;
7501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
7511e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
752beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com    if (stencilBuffer->mustRenderClip(clipDataIn, rt->width(), rt->height())) {
7531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
754beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        stencilBuffer->setLastClip(clipDataIn, rt->width(), rt->height());
7551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we set the current clip to the bounds so that our recursive
7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // draws are scissored to them. We use the copy of the complex clip
7581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we just stashed on the SB to render from. We set it back after
7591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we finish drawing it into the stencil.
760beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        const GrClipData* oldClipData = fGpu->getClip();
761beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com
7627b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        // The origin of 'newClipData' is (0, 0) so it is okay to place
7637b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        // a device-coordinate bound in 'newClipStack'
764641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com        SkClipStack newClipStack(devClipBounds);
765beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        GrClipData newClipData;
766beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        newClipData.fClipStack = &newClipStack;
767beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com
768beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        fGpu->setClip(&newClipData);
7691e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
77013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com        GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
77113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com        drawState = fGpu->drawState();
7721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->setRenderTarget(rt);
77313b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com        GrDrawTarget::AutoGeometryPush agp(fGpu);
7741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
775f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com        if (0 != clipDataIn.fOrigin.fX || 0 != clipDataIn.fOrigin.fY) {
776fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            // Add the saveLayer's offset to the view matrix rather than
777f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com            // offset each individual draw
7787b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            drawState->viewMatrix()->setTranslate(
779fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                           SkIntToScalar(-clipDataIn.fOrigin.fX),
780f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                           SkIntToScalar(-clipDataIn.fOrigin.fY));
781f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com        }
782f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com
7831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP
7841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
7861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int clipBit = stencilBuffer->bits();
7881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        SkASSERT((clipBit <= 16) &&
7891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    "Ganesh only handles 16b or smaller stencil buffers");
7901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        clipBit = (1 << (clipBit-1));
7911e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7927b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        GrIRect devRTRect = GrIRect::MakeWH(rt->width(), rt->height());
7931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        bool clearToInside;
795a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
796a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
797fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        SkClipStack::Iter iter(*oldClipData->fClipStack,
798641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com                               SkClipStack::Iter::kBottom_IterStart);
799641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com        const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
8007b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                                  devRTRect,
801ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com                                                  &clearToInside,
802f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                                  &firstOp,
803f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                                  clipDataIn);
8041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8057b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com        fGpu->clearStencilClip(devClipBounds, clearToInside);
806a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        bool first = true;
8071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // walk through each clip element and perform its set op
8091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // with the existing clip.
810e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com        for ( ; NULL != clip; clip = iter.nextCombined()) {
8111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathFill fill;
8128afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            bool fillInverted = false;
8131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // enabled at bottom of loop
8141e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
815ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            // if the target is MSAA then we want MSAA enabled when the clip is soft
816ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            if (rt->isMultisampled()) {
817d5d69ffaea117428972db48796f7e75f0d1dab34bsalomon@google.com                drawState->setState(GrDrawState::kHWAntialias_StateBit, clip->fDoAA);
818ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            }
8191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8208afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            // Can the clip element be drawn directly to the stencil buffer
8218afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            // with a non-inverted fill rule without extra passes to
8228afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            // resolve in/out status?
8238afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            bool canRenderDirectToStencil = false;
8241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
825a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            SkRegion::Op op = clip->fOp;
826a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            if (first) {
827a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                first = false;
828a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                op = firstOp;
829a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            }
830f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathRenderer* pr = NULL;
8328d033a1b125886c62906d975b5cc28a382064526bsalomon@google.com            const SkPath* clipPath = NULL;
833a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            if (NULL != clip->fRect) {
8341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                canRenderDirectToStencil = true;
83547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com                fill = kEvenOdd_GrPathFill;
8361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = false;
8371e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // there is no point in intersecting a screen filling
8381e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                // rectangle.
839f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                if (SkRegion::kIntersect_Op == op &&
8407b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    contains(*clip->fRect, devRTRect, oldClipData->fOrigin)) {
8411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    continue;
8421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8438afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            } else {
8448afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                GrAssert(NULL != clip->fPath);
845a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                fill = get_path_fill(*clip->fPath);
8461e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = GrIsFillInverted(fill);
8471e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = GrNonInvertedFill(fill);
848a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                clipPath = clip->fPath;
8498afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                pr = this->getContext()->getPathRenderer(*clipPath, fill, fGpu, false, true);
8501e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (NULL == pr) {
8518afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                    fGpu->setClip(oldClipData);
8521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    return false;
8531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                canRenderDirectToStencil =
85513b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                    !pr->requiresStencilPass(*clipPath, fill, fGpu);
8561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            int passes;
8591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
8601e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool canDrawDirectToClip; // Given the renderer, the element,
8621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // fill rule, and set operation can
8631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // we render the element directly to
8641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // stencil bit used for clipping.
8651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            canDrawDirectToClip =
8661e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GrStencilSettings::GetClipPasses(op,
8678afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                                                 canRenderDirectToStencil,
8688afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                                                 clipBit,
8698afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                                                 fillInverted,
8708afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                                                 &passes,
8718afae61a57f87e4a50578effce6c428031499301tomhudson@google.com                                                 stencilSettings);
8721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // draw the element to the client stencil bits if necessary
8741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (!canDrawDirectToClip) {
8751e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
8761e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kIncClamp_StencilOp,
8771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kIncClamp_StencilOp,
8781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kAlways_StencilFunc,
8791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0xffff,
8801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0x0000,
8811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0xffff);
8821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                SET_RANDOM_COLOR
883a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                if (NULL != clip->fRect) {
8841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *drawState->stencil() = gDrawToStencil;
885a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    fGpu->drawSimpleRect(*clip->fRect, NULL);
8861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
8871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    if (canRenderDirectToStencil) {
8881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        *drawState->stencil() = gDrawToStencil;
8890f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com                        pr->drawPath(*clipPath, fill, fGpu, false);
8901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
89113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                        pr->drawPathToStencil(*clipPath, fill, fGpu);
8921e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
8931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
8941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
8951e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // now we modify the clip bit by rendering either the clip
8971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // element directly or a bounding rect of the entire clip.
8981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
8991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            for (int p = 0; p < passes; ++p) {
9001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *drawState->stencil() = stencilSettings[p];
9011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (canDrawDirectToClip) {
902a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                    if (NULL != clip->fRect) {
9031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
904a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                        fGpu->drawSimpleRect(*clip->fRect, NULL);
9051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
9061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
9070f11e1ab5b6e53f6176dde2dbb25a8e3ae34858fbsalomon@google.com                        pr->drawPath(*clipPath, fill, fGpu, false);
9081e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
9091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
9101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    SET_RANDOM_COLOR
911fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                    // 'devClipBounds' is already in device coordinates so the
912fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                    // translation in the view matrix is inappropriate.
9137b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    // Convert it to canvas space so the drawn rect will
914f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                    // be in the correct location
9157b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    GrRect canvClipBounds;
9167b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    canvClipBounds.set(devClipBounds);
9177b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    device_to_canvas(&canvClipBounds, clipDataIn.fOrigin);
9187b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                    fGpu->drawSimpleRect(canvClipBounds, NULL);
9191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
9201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
9211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
9221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // restore clip
923beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com        fGpu->setClip(oldClipData);
9241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
925c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    // set this last because recursive draws may overwrite it back to kNone.
926c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
927c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kStencil_ClipMaskType;
9281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
9291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
9301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
931f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com
932411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping of clip-respecting stencil funcs to normal stencil funcs
933411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping depends on whether stencil-clipping is in effect.
934fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic const GrStencilFunc
935411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = {
936411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is DISABLED,  we are effectively always inside the clip
937411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
938411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
939411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
940411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
941411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
942411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
943411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
944411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref 0 and do normal nequal.
945411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    },
946411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is ENABLED
947411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
948411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
949411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // eq stencil clip bit, mask
950411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // out user bits.
951411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
952411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
953411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // add stencil bit to mask and ref
954411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
955411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
956411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
957411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // for both of these we can add
958411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // the clip bit to the mask and
959411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // ref and compare as normal
960411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
961411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
962411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref have only the clip bit set
963411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // and make comparison be less
964411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // 10..0 < 1..user_bits..
965411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
966411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com};
967411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
968a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace {
969a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// Sets the settings to clip against the stencil buffer clip while ignoring the
970a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// client bits.
971a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comconst GrStencilSettings& basic_apply_stencil_clip_settings() {
972a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // stencil settings to use when clip is in stencil
973a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
974a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
975a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
976a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kAlwaysIfInClip_StencilFunc,
977a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
978a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
979fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        0x0000);
980a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
981a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
982a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
983a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
984a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::setGpuStencil() {
985a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // We make two copies of the StencilSettings here (except in the early
986a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // exit scenario. One copy from draw state to the stack var. Then another
987a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // from the stack var to the gpu. We could make this class hold a ptr to
988a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // GrGpu's fStencilSettings and eliminate the stack copy here.
989a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
990a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    const GrDrawState& drawState = fGpu->getDrawState();
991a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
992a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // use stencil for clipping if clipping is enabled and the clip
993a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // has been written into the stencil.
994a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrClipMaskManager::StencilClipMode clipMode;
995a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (this->isClipInStencil() && drawState.isClipState()) {
996a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
997a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We can't be modifying the clip and respecting it at the same time.
998a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrAssert(!drawState.isStateFlagEnabled(
999a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit));
1000a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else if (drawState.isStateFlagEnabled(
1001a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit)) {
1002a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
1003a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
1004a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
1005a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
1006a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1007a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings settings;
1008a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // The GrGpu client may not be using the stencil buffer but we may need to
1009a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // enable it in order to respect a stencil clip.
1010a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (drawState.getStencil().isDisabled()) {
1011a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
1012a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            settings = basic_apply_stencil_clip_settings();
1013a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
1014a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableStencil();
1015a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            return;
1016a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
1017a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
1018a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings = drawState.getStencil();
1019a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
1020a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1021a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // TODO: dynamically attach a stencil buffer
1022a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    int stencilBits = 0;
1023fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    GrStencilBuffer* stencilBuffer =
1024a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        drawState.getRenderTarget()->getStencilBuffer();
1025a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (NULL != stencilBuffer) {
1026a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        stencilBits = stencilBuffer->bits();
1027a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
1028a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1029f66018798099750e639a8fa131fece492a050997bsalomon@google.com    GrAssert(fGpu->getCaps().stencilWrapOpsSupport() ||
10309e553c6e7cff5fd699ed4dee1d52317362ea30d0bsalomon@google.com             !settings.usesWrapOp());
1031f66018798099750e639a8fa131fece492a050997bsalomon@google.com    GrAssert(fGpu->getCaps().twoSidedStencilSupport() || !settings.isTwoSided());
1032a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->adjustStencilParams(&settings, clipMode, stencilBits);
1033a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    fGpu->setStencilSettings(settings);
1034a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
1035a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1036a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
1037a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            StencilClipMode mode,
1038a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            int stencilBitCnt) {
1039411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    GrAssert(stencilBitCnt > 0);
1040411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1041411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    if (kModifyClip_StencilClipMode == mode) {
1042a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We assume that this clip manager itself is drawing to the GrGpu and
1043a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // has already setup the correct values.
1044a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return;
1045411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
1046a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1047411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int clipBit = (1 << (stencilBitCnt - 1));
1048411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int userBits = clipBit - 1;
1049411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1050a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
1051f66018798099750e639a8fa131fece492a050997bsalomon@google.com    bool twoSided = fGpu->getCaps().twoSidedStencilSupport();
1052a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1053a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    bool finished = false;
1054a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    while (!finished) {
1055a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrStencilFunc func = settings->func(face);
1056a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t writeMask = settings->writeMask(face);
1057a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcMask = settings->funcMask(face);
1058a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcRef = settings->funcRef(face);
1059a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1060a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrAssert((unsigned) func < kStencilFuncCount);
1061a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1062a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        writeMask &= userBits;
1063a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1064a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (func >= kBasicStencilFuncCount) {
1065a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            int respectClip = kRespectClip_StencilClipMode == mode;
1066a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            if (respectClip) {
1067a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                // The GrGpu class should have checked this
1068a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                GrAssert(this->isClipInStencil());
1069a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                switch (func) {
1070a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kAlwaysIfInClip_StencilFunc:
1071a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = clipBit;
1072a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
1073a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
1074a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kEqualIfInClip_StencilFunc:
1075a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLessIfInClip_StencilFunc:
1076a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLEqualIfInClip_StencilFunc:
1077a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
1078a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef  = (funcRef  & userBits) | clipBit;
1079a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
1080a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kNonZeroIfInClip_StencilFunc:
1081a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
1082a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
1083a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
1084a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    default:
1085a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        GrCrash("Unknown stencil func");
1086a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                }
1087a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            } else {
1088a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcMask &= userBits;
1089a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcRef &= userBits;
1090411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            }
1091fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            const GrStencilFunc* table =
1092a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                gSpecialToBasicStencilFunc[respectClip];
1093a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            func = table[func - kBasicStencilFuncCount];
1094a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            GrAssert(func >= 0 && func < kBasicStencilFuncCount);
1095411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        } else {
1096a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcMask &= userBits;
1097a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcRef &= userBits;
1098411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        }
1099a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1100a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFunc(face, func);
1101a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setWriteMask(face, writeMask);
1102a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncMask(face, funcMask);
1103a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncRef(face, funcRef);
1104a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1105a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrStencilSettings::kFront_Face == face) {
1106a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            face = GrStencilSettings::kBack_Face;
1107a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = !twoSided;
1108a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
1109a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = true;
1110a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
1111a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
1112a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (!twoSided) {
1113a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->copyFrontSettingsToBack();
1114411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
1115411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}
1116411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1117411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
1118411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1119fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comnamespace {
1120fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1121fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.comGrPathFill invert_fill(GrPathFill fill) {
1122fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    static const GrPathFill gInvertedFillTable[] = {
112347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        kInverseWinding_GrPathFill, // kWinding_GrPathFill
112447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        kInverseEvenOdd_GrPathFill, // kEvenOdd_GrPathFill
112547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        kWinding_GrPathFill,        // kInverseWinding_GrPathFill
112647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        kEvenOdd_GrPathFill,        // kInverseEvenOdd_GrPathFill
112747059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com        kHairLine_GrPathFill,       // kHairLine_GrPathFill
1128fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    };
112947059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(0 == kWinding_GrPathFill);
113047059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(1 == kEvenOdd_GrPathFill);
113147059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(2 == kInverseWinding_GrPathFill);
113247059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(3 == kInverseEvenOdd_GrPathFill);
113347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(4 == kHairLine_GrPathFill);
113447059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com    GR_STATIC_ASSERT(5 == kGrPathFillCount);
1135fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    return gInvertedFillTable[fill];
1136fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com}
1137fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1138fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com}
1139fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1140beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.combool GrClipMaskManager::createSoftwareClipMask(const GrClipData& clipDataIn,
11416b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                                               GrTexture** result,
11427b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                               GrIRect* devResultBounds) {
1143c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
11446b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
11457b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    if (this->clipMaskPreamble(clipDataIn, result, devResultBounds)) {
11466b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return true;
11476b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
11486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1149f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrTexture* accum = fAACache.getLastMask();
11506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    if (NULL == accum) {
1151f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
11526b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        return false;
11536b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
11546b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
11552c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    GrSWMaskHelper helper(this->getContext());
11566b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1157b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix matrix;
1158fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    matrix.setTranslate(SkIntToScalar(-clipDataIn.fOrigin.fX),
1159f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                        SkIntToScalar(-clipDataIn.fOrigin.fY));
11607b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    helper.init(*devResultBounds, &matrix);
1161fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1162fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    bool clearToInside;
1163a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    SkRegion::Op firstOp = SkRegion::kReplace_Op; // suppress warning
1164a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
1165fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    SkClipStack::Iter iter(*clipDataIn.fClipStack,
1166641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com                           SkClipStack::Iter::kBottom_IterStart);
1167641f8b19a6799b6d73ac17b9c2d2f8a5e6f5ad4drobertphillips@google.com    const SkClipStack::Iter::Clip* clip = process_initial_clip_elements(&iter,
11687b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                                              *devResultBounds,
1169fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                                              &clearToInside,
1170f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                              &firstOp,
1171f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com                                              clipDataIn);
1172fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1173366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    helper.clear(clearToInside ? 0xFF : 0x00);
1174fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1175a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com    bool first = true;
1176e8ca6c6e3a55634ac76efe5aceafaf8d669f43babsalomon@google.com    for ( ; NULL != clip; clip = iter.nextCombined()) {
1177fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1178a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        SkRegion::Op op = clip->fOp;
1179a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (first) {
1180a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            first = false;
1181a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            op = firstOp;
1182a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        }
1183fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1184fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        if (SkRegion::kIntersect_Op == op ||
1185fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            SkRegion::kReverseDifference_Op == op) {
1186fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // Intersect and reverse difference require modifying pixels
1187fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // outside of the geometry that is being "drawn". In both cases
1188fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // we erase all the pixels outside of the geometry but
1189fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // leave the pixels inside the geometry alone. For reverse
1190fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // difference we invert all the pixels before clearing the ones
1191fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            // outside the geometry.
1192fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            if (SkRegion::kReverseDifference_Op == op) {
11937b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                SkRect temp;
11947b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                temp.set(*devResultBounds);
1195ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com                temp.offset(SkIntToScalar(clipDataIn.fOrigin.fX),
1196ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com                            SkIntToScalar(clipDataIn.fOrigin.fX));
1197fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1198fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // invert the entire scene
1199366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF);
1200fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
1201fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1202a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            if (NULL != clip->fRect) {
1203fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1204fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // convert the rect to a path so we can invert the fill
1205fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                SkPath temp;
1206a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                temp.addRect(*clip->fRect);
1207fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1208fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                helper.draw(temp, SkRegion::kReplace_Op,
1209a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                            kInverseEvenOdd_GrPathFill, clip->fDoAA,
1210366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                            0x00);
1211a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            } else if (NULL != clip->fPath) {
1212a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                helper.draw(*clip->fPath,
1213fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            SkRegion::kReplace_Op,
1214a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                            invert_fill(get_path_fill(*clip->fPath)),
1215a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                            clip->fDoAA,
1216366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                            0x00);
1217fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
1218fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1219fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            continue;
1220fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
1221fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1222fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // The other ops (union, xor, diff) only affect pixels inside
1223fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // the geometry so they can just be drawn normally
1224a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        if (NULL != clip->fRect) {
1225fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1226a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com            helper.draw(*clip->fRect,
1227fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        op,
1228a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                        clip->fDoAA, 0xFF);
12296b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1230a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com        } else if (NULL != clip->fPath) {
1231fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            helper.draw(*clip->fPath,
1232fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                        op,
1233a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                        get_path_fill(*clip->fPath),
1234a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com                        clip->fDoAA, 0xFF);
12356b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
12366b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
12376b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1238fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // Because we are using the scratch texture cache, "accum" may be
1239fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // larger than expected and have some cruft in the areas we aren't using.
1240fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // Clear it out.
1241c82a8b7aa4ec19fba508c394920a9e88d3e5bd12robertphillips@google.com    fGpu->clear(NULL, 0x00000000, accum->asRenderTarget());
1242fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
1243366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com    helper.toTexture(accum, clearToInside ? 0xFF : 0x00);
12446b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
12456b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    *result = accum;
12466b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1247c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
12486b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    return true;
12496b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
12506b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1251f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1252f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.comvoid GrClipMaskManager::releaseResources() {
1253f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.releaseResources();
12541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
1255