GrClipMaskManager.cpp revision d92cf2ebbfbb9d737ea4a551e64ffccb08376875
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"
10c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAConvexPathRenderer.h"
11c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrAAHairLinePathRenderer.h"
12c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h"
131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrGpu.h"
14c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPaint.h"
15c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPathRenderer.h"
161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrRenderTarget.h"
171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrStencilBuffer.h"
18c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrSWMaskHelper.h"
19c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "effects/GrTextureDomainEffect.h"
206b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com#include "SkRasterClip.h"
215f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
22c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com#include "SkTLazy.h"
23c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com
24ba998f2ddc5a904376bfdb118976868b9ee2b6e8robertphillips@google.com#define GR_AA_CLIP 1
25a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
268182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comtypedef SkClipStack::Element Element;
2751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comusing namespace GrReducedClip;
294c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
3051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
31a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.comnamespace {
32fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the draw state to enable the aa clipping mask. Besides setting up the
3308283afc265f1153834256fc1012519813ba6b73bsalomon@google.com// stage matrix this also alters the vertex layout
34fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comvoid setup_drawstate_aaclip(GrGpu* gpu,
35fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                            GrTexture* result,
36fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                            const SkIRect &devBound) {
37a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrDrawState* drawState = gpu->drawState();
38a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrAssert(drawState);
39a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
40b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix mat;
41c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // We want to use device coords to compute the texture coordinates. We set our matrix to be
42c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // equal to the view matrix followed by an offset to the devBound, and then a scaling matrix to
43c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com    // normalized coords. We apply this matrix to the vertex positions rather than local coords.
44a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.setIDiv(result->width(), result->height());
45fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    mat.preTranslate(SkIntToScalar(-devBound.fLeft),
467b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com                     SkIntToScalar(-devBound.fTop));
47a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    mat.preConcat(drawState->getViewMatrix());
48a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
504c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // This could be a long-lived effect that is cached with the alpha-mask.
51eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    drawState->addCoverageEffect(
52eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com        GrTextureDomainEffect::Create(result,
537b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      mat,
547b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::MakeTexelDomain(result, domainTexels),
55c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                      GrTextureDomainEffect::kDecal_WrapMode,
56c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                      false,
57c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                      GrEffect::kPosition_CoordsType))->unref();
58a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
59a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
608a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.combool path_needs_SW_renderer(GrContext* context,
6113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            GrGpu* gpu,
62c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                            const SkPath& origPath,
635f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                            const SkStrokeRec& stroke,
6413b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com                            bool doAA) {
65c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com    // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
66c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com    SkTCopyOnFirstWrite<SkPath> path(origPath);
67c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com    if (path->isInverseFillType()) {
68c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com        path.writable()->toggleInverseFillType();
69c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com    }
708a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // last (false) parameter disallows use of the SW path renderer
7145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com    GrPathRendererChain::DrawType type = doAA ?
7245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                         GrPathRendererChain::kColorAntiAlias_DrawType :
7345a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                         GrPathRendererChain::kColor_DrawType;
7445a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com
7545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com    return NULL == context->getPathRenderer(*path, stroke, gpu, false, type);
76a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com}
77a6f11c4f717961070cd6fc5e60c361db14c5c4f3robertphillips@google.com
786b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
80fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com/*
81fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer
82fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the
83fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu.
84fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */
854c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.combool GrClipMaskManager::useSWOnlyPath(const ElementList& elements) {
86a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
878a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // TODO: generalize this function so that when
88fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // a clip gets complex enough it can just be done in SW regardless
89fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // of whether it would invoke the GrSoftwarePathRenderer.
905f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
91d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com
924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    for (ElementList::Iter iter(elements.headIter()); iter.get(); iter.next()) {
934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
94f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com        // rects can always be drawn directly w/o using the software path
95f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com        // so only paths need to be checked
968182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        if (Element::kPath_Type == element->getType() &&
97fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            path_needs_SW_renderer(this->getContext(), fGpu,
988182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                                   element->getPath(),
9912b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                                   stroke,
1008182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                                   element->isAA())) {
1014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            return true;
102fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
103fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    }
1044c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return false;
105a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com}
106a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
107f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1086b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// sort out what kind of clip mask needs to be created: alpha, stencil,
1096b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// scissor, or entirely software
110eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.combool GrClipMaskManager::setupClipping(const GrClipData* clipDataIn,
111eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com                                      GrDrawState::AutoRestoreEffects* are) {
112c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kNone_ClipMaskType;
113a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1144c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    ElementList elements(16);
1154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    InitialState initialState;
1164c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect clipSpaceIBounds;
1174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool requiresAA;
1184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool isRect = false;
1194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
12013b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
1211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    const GrRenderTarget* rt = drawState->getRenderTarget();
1231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // GrDrawTarget should have filtered this for us
1241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
1251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
1264c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool ignoreClip = !drawState->isClipState() || clipDataIn->fClipStack->isWideOpen();
1274c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
1284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (!ignoreClip) {
1294c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
1304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        clipSpaceRTIBounds.offset(clipDataIn->fOrigin);
1314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        ReduceClipStack(*clipDataIn->fClipStack,
1324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        clipSpaceRTIBounds,
1334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &elements,
1344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &initialState,
1354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &clipSpaceIBounds,
1364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        &requiresAA);
1374c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (elements.isEmpty()) {
1384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            if (kAllIn_InitialState == initialState) {
1394c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                ignoreClip = clipSpaceIBounds == clipSpaceRTIBounds;
1404c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                isRect = true;
1414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            } else {
1424c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                return false;
1434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
1444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
1454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    }
1463e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com
1474c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (ignoreClip) {
1484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fGpu->disableScissor();
1494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        this->setGpuStencil();
1504c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return true;
151a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
152a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
1534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com#if GR_AA_CLIP
1544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // TODO: catch isRect && requiresAA and use clip planes if available rather than a mask.
155b99225c92bc6d7d0ea7030716ade6a302862e84frobertphillips@google.com
156a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    // If MSAA is enabled we can do everything in the stencil buffer.
1574c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (0 == rt->numSamples() && requiresAA) {
1584c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        int32_t genID = clipDataIn->fClipStack->getTopmostGenID();
1596b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        GrTexture* result = NULL;
160a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
1614c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (this->useSWOnlyPath(elements)) {
1624c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // The clip geometry is complex enough that it will be more efficient to create it
1634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // entirely in software
1644c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            result = this->createSoftwareClipMask(genID,
1654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  initialState,
1664c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  elements,
1674c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  clipSpaceIBounds);
1684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        } else {
1694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            result = this->createAlphaClipMask(genID,
1704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               initialState,
1714c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               elements,
1724c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                               clipSpaceIBounds);
1734c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
1746b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1754c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (NULL != result) {
1764c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // The mask's top left coord should be pinned to the rounded-out top left corner of
1774c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // clipSpace bounds. We determine the mask's position WRT to the render target here.
1784c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
1794c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            rtSpaceMaskBounds.offset(-clipDataIn->fOrigin);
180eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com            are->set(fGpu->drawState());
1814c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            setup_drawstate_aaclip(fGpu, result, rtSpaceMaskBounds);
182a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableScissor();
183a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            this->setGpuStencil();
184f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            return true;
185f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
1864c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // if alpha clip mask creation fails fall through to the non-AA code paths
187f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
188f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com#endif // GR_AA_CLIP
189f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
1904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // Either a hard (stencil buffer) clip was explicitly requested or an anti-aliased clip couldn't
1914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // be created. In either case, free up the texture in the anti-aliased mask cache.
1924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // TODO: this may require more investigation. Ganesh performs a lot of utility draws (e.g.,
1934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // clears, InOrderDrawBuffer playbacks) that hit the stencil buffer path. These may be
1944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // "incorrectly" clearing the AA cache.
1955acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com    fAACache.reset();
1965acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com
197a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // If the clip is a rectangle then just set the scissor. Otherwise, create
198a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // a stencil mask.
1994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (isRect) {
2004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIRect clipRect = clipSpaceIBounds;
2014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        clipRect.offset(-clipDataIn->fOrigin);
2024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fGpu->enableScissor(clipRect);
203a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        this->setGpuStencil();
204a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return true;
2051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
2061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // use the stencil clip if we can't represent the clip as a rectangle.
2084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIPoint clipSpaceToStencilSpaceOffset = -clipDataIn->fOrigin;
2094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    this->createStencilClipMask(initialState,
2104c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                elements,
2114c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                clipSpaceIBounds,
2124c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                clipSpaceToStencilSpaceOffset);
2134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
2144c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // This must occur after createStencilClipMask. That function may change the scissor. Also, it
2154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // only guarantees that the stencil mask is correct within the bounds it was passed, so we must
2164c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // use both stencil and scissor test to the bounds for the final draw.
2174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect scissorSpaceIBounds(clipSpaceIBounds);
2184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
2194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    fGpu->enableScissor(scissorSpaceIBounds);
220a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->setGpuStencil();
2211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
2221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
2231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#define VISUALIZE_COMPLEX_CLIP 0
2251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if VISUALIZE_COMPLEX_CLIP
227223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org    #include "SkRandom.h"
228223137f49d1a4e805f5c1b1c20b7fd68719ac54btfarina@chromium.org    SkRandom gRandom;
2291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
2301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#else
2311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    #define SET_RANDOM_COLOR
2321e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
2331e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
2341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.comnamespace {
235f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
236f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
237fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// set up the OpenGL blend function to perform the specified
238fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// boolean operation for alpha clip mask creation
2396b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.comvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
240f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
241f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    switch (op) {
242f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReplace_Op:
24347059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
244f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
245f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kIntersect_Op:
24647059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
247f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
248f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kUnion_Op:
24947059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
250f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
251f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kXOR_Op:
25247059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kISC_GrBlendCoeff);
253f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
254f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kDifference_Op:
25547059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
256f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
257f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        case SkRegion::kReverseDifference_Op:
25847059542e7aa153926377456a6c611e55c8e428cbsalomon@google.com            drawState->setBlendFunc(kIDC_GrBlendCoeff, kZero_GrBlendCoeff);
259f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
260f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        default:
261f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            GrAssert(false);
262f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            break;
263f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
264f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
265f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
26672176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com}
267f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
268f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
269b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::drawElement(GrTexture* target,
270b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                    const SkClipStack::Element* element,
271b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                    GrPathRenderer* pr) {
27213b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
273f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
274f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
275f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
2768182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    switch (element->getType()) {
2778182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case Element::kRect_Type:
2784c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // TODO: Do rects directly to the accumulator using a aa-rect GrEffect that covers the
2794c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // entire mask bounds and writes 0 outside the rect.
2808182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            if (element->isAA()) {
281cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                getContext()->getAARectRenderer()->fillAARect(fGpu,
282cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                                                              fGpu,
283cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                                                              element->getRect(),
284b19cb7f36785f3ad3b1512c342fc662ab79e3fcarobertphillips@google.com                                                              SkMatrix::I(),
285afd1cba5237eba5394ee011106eede9f6c8074c8robertphillips@google.com                                                              element->getRect(),
286cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com                                                              false);
2878182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            } else {
2888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                fGpu->drawSimpleRect(element->getRect(), NULL);
2898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            }
2908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            return true;
2914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        case Element::kPath_Type: {
292c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            SkTCopyOnFirstWrite<SkPath> path(element->getPath());
293c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            if (path->isInverseFillType()) {
294c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com                path.writable()->toggleInverseFillType();
295c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            }
2965f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
297b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (NULL == pr) {
298b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GrPathRendererChain::DrawType type;
299b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType :
300b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                         GrPathRendererChain::kColor_DrawType;
301b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, false, type);
302b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            }
3034c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            if (NULL == pr) {
3044c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                return false;
3054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
3064c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            pr->drawPath(element->getPath(), stroke, fGpu, element->isAA());
3074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            break;
3084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
3098182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        default:
3108182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            // something is wrong if we're trying to draw an empty element.
3118182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            GrCrash("Unexpected element type");
3128182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            return false;
313f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
314f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return true;
315f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
316f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
317b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.combool GrClipMaskManager::canStencilAndDrawElement(GrTexture* target,
318b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                                 const SkClipStack::Element* element,
319b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                                 GrPathRenderer** pr) {
320b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
321b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    drawState->setRenderTarget(target->asRenderTarget());
322b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
323b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    switch (element->getType()) {
324b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        case Element::kRect_Type:
325b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            return true;
326b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        case Element::kPath_Type: {
327b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            SkTCopyOnFirstWrite<SkPath> path(element->getPath());
328b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (path->isInverseFillType()) {
329b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                path.writable()->toggleInverseFillType();
330b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            }
3315f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
332b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            GrPathRendererChain::DrawType type = element->isAA() ?
333b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GrPathRendererChain::kStencilAndColorAntiAlias_DrawType :
334b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GrPathRendererChain::kStencilAndColor_DrawType;
335b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            *pr = this->getContext()->getPathRenderer(*path, stroke, fGpu, false, type);
336b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            return NULL != *pr;
337b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        }
338b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        default:
339b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            // something is wrong if we're trying to draw an empty element.
340b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            GrCrash("Unexpected element type");
341b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            return false;
342b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    }
343b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com}
344b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
3457b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.comvoid GrClipMaskManager::mergeMask(GrTexture* dstMask,
3467b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  GrTexture* srcMask,
3477b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                  SkRegion::Op op,
348fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                  const SkIRect& dstBound,
349fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                  const SkIRect& srcBound) {
350137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState::AutoViewMatrixRestore avmr;
35113b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
352137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkAssertResult(avmr.setIdentity(drawState));
353eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    GrDrawState::AutoRestoreEffects are(drawState);
354f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
3557b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->setRenderTarget(dstMask->asRenderTarget());
356f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
3577b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    setup_boolean_blendcoeffs(drawState, op);
35872b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com
359b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix sampleM;
3607b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    sampleM.setIDiv(srcMask->width(), srcMask->height());
361eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    drawState->addColorEffect(
3627b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com        GrTextureDomainEffect::Create(srcMask,
3637b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      sampleM,
3647b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                      GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound),
365c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                      GrTextureDomainEffect::kDecal_WrapMode,
366c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com                                      false))->unref();
3677b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL);
368f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
369f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
3706d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations
3716d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com// TODO: given the expense of createTexture we may want to just cache this too
3724c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comvoid GrClipMaskManager::getTemp(int width, int height, GrAutoScratchTexture* temp) {
373f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    if (NULL != temp->texture()) {
3746d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        // we've already allocated the temp texture
3756d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com        return;
3766d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com    }
3776d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
37875b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    GrTextureDesc desc;
37975b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fFlags = kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit;
3804c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    desc.fWidth = width;
3814c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    desc.fHeight = height;
38275b3c9633cb9a594dab0ccf51dab1e694c149a18robertphillips@google.com    desc.fConfig = kAlpha_8_GrPixelConfig;
3836b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
3842c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    temp->set(this->getContext(), desc);
3856d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com}
3866d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com
3876b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
3884c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com// Handles caching & allocation (if needed) of a clip alpha-mask texture for both the sw-upload
3894c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com// or gpu-rendered cases. Returns true if there is no more work to be done (i.e., we got a cache
3904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com// hit)
3914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.combool GrClipMaskManager::getMaskTexture(int32_t clipStackGenID,
3924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                       const SkIRect& clipSpaceIBounds,
3934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                       GrTexture** result) {
3944c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    bool cached = fAACache.canReuse(clipStackGenID, clipSpaceIBounds);
3954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (!cached) {
3964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
3974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // There isn't a suitable entry in the cache so we create a new texture to store the mask.
3984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // Since we are setting up the cache we know the last lookup was a miss. Free up the
3994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // currently cached mask so it can be reused.
4004c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fAACache.reset();
401f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        GrTextureDesc desc;
403b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        desc.fFlags = kRenderTarget_GrTextureFlagBit;
4044c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        desc.fWidth = clipSpaceIBounds.width();
4054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        desc.fHeight = clipSpaceIBounds.height();
40613f181f28f4336adcc93b7297b6d16503f4c323crobertphillips@google.com        desc.fConfig = kRGBA_8888_GrPixelConfig;
40713f181f28f4336adcc93b7297b6d16503f4c323crobertphillips@google.com        if (this->getContext()->isConfigRenderable(kAlpha_8_GrPixelConfig)) {
40813f181f28f4336adcc93b7297b6d16503f4c323crobertphillips@google.com            // We would always like A8 but it isn't supported on all platforms
40913f181f28f4336adcc93b7297b6d16503f4c323crobertphillips@google.com            desc.fConfig = kAlpha_8_GrPixelConfig;
41013f181f28f4336adcc93b7297b6d16503f4c323crobertphillips@google.com        }
411a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
4124c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fAACache.acquireMask(clipStackGenID, desc, clipSpaceIBounds);
4138fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    }
4148fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com
4154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    *result = fAACache.getLastMask();
4164c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return cached;
4176b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
418f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4196b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
4206b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Create a 8-bit clip mask in alpha
4214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comGrTexture* GrClipMaskManager::createAlphaClipMask(int32_t clipStackGenID,
4224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  InitialState initialState,
4234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  const ElementList& elements,
4244c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                  const SkIRect& clipSpaceIBounds) {
425c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
426c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com
4274c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    GrTexture* result;
4284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (this->getMaskTexture(clipStackGenID, clipSpaceIBounds, &result)) {
429c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com        fCurrClipMaskType = kAlpha_ClipMaskType;
4304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return result;
4316b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
432f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (NULL == result) {
434f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
4354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return NULL;
436f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
437f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4384c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The top-left of the mask corresponds to the top-left corner of the bounds.
4397b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    SkVector clipToMaskOffset = {
4404c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIntToScalar(-clipSpaceIBounds.fLeft),
4414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkIntToScalar(-clipSpaceIBounds.fTop)
4427b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    };
4434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The texture may be larger than necessary, this rect represents the part of the texture
4444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // we populate with a rasterization of the clip.
4454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
446f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
447137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    // Set the matrix so that rendered clip elements are transformed to mask space from clip space.
448137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    SkMatrix translate;
449137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    translate.setTranslate(clipToMaskOffset);
450137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &translate);
451137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
452137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
453137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
454cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com    // We're drawing a coverage mask and want coverage to be run through the blend function.
455cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com    drawState->enableState(GrDrawState::kCoverageDrawing_StateBit);
456cf939ae54842fc7408ee68a41427086962b4c3dcbsalomon@google.com
4577b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // The scratch texture that we are drawing into can be substantially larger than the mask. Only
4587b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    // clear the part that we care about.
4594c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    fGpu->clear(&maskSpaceIBounds,
4604c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
4614c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                result->asRenderTarget());
462d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com
463b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // When we use the stencil in the below loop it is important to have this clip installed.
464b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first
465b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // pass must not set values outside of this bounds or stencil values outside the rect won't be
466b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // cleared.
467b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrDrawTarget::AutoClipRestore acr(fGpu, maskSpaceIBounds);
468b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    drawState->enableState(GrDrawState::kClip_StateBit);
469b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
470f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrAutoScratchTexture temp;
471f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    // walk through each clip element and perform its set op
4724c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    for (ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
4734c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
4748182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        SkRegion::Op op = element->getOp();
475b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        bool invert = element->isInverseFilled();
476f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
477b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
478b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            GrPathRenderer* pr = NULL;
479b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            bool useTemp = !this->canStencilAndDrawElement(result, element, &pr);
480b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            GrTexture* dst;
4814c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // This is the bounds of the clip element in the space of the alpha-mask. The temporary
4827b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // mask buffer can be substantially larger than the actually clip stack element. We
4837b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com            // touch the minimum number of pixels necessary and use decal mode to combine it with
484b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            // the accumulator.
485fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org            SkIRect maskSpaceElementIBounds;
486b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
487b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (useTemp) {
488b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                if (invert) {
489b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    maskSpaceElementIBounds = maskSpaceIBounds;
490b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                } else {
491fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                    SkRect elementBounds = element->getBounds();
492b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    elementBounds.offset(clipToMaskOffset);
493b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    elementBounds.roundOut(&maskSpaceElementIBounds);
494b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                }
495b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
496b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                this->getTemp(maskSpaceIBounds.fRight, maskSpaceIBounds.fBottom, &temp);
497b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                if (NULL == temp.texture()) {
498b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    fAACache.reset();
499b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                    return NULL;
500a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com                }
501b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                dst = temp.texture();
502b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // clear the temp target and set blend to replace
503b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fGpu->clear(&maskSpaceElementIBounds,
504b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                            invert ? 0xffffffff : 0x00000000,
505b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                            dst->asRenderTarget());
506b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
507a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com
5084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            } else {
509b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // draw directly into the result with the stencil set to make the pixels affected
510b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // by the clip shape be non-zero.
511b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                dst = result;
512b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
513b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kReplace_StencilOp,
514b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kReplace_StencilOp,
515b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kAlways_StencilFunc,
516b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
517b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
518b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff);
519b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setStencil(kStencilInElement);
520a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com                setup_boolean_blendcoeffs(drawState, op);
5214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
5227b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
523c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            drawState->setAlpha(invert ? 0x00 : 0xff);
524c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com
525b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (!this->drawElement(dst, element, pr)) {
5264c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                fAACache.reset();
5274c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                return NULL;
5284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            }
529f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
530b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (useTemp) {
531b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // Now draw into the accumulator using the real operation and the temp buffer as a
532b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // texture
533b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                this->mergeMask(result,
534b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                temp.texture(),
535b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                op,
536b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                maskSpaceIBounds,
537b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                maskSpaceElementIBounds);
538b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            } else {
539b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                // Draw to the exterior pixels (those with a zero stencil value).
540b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setAlpha(invert ? 0xff : 0x00);
541b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
542b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kZero_StencilOp,
543b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kZero_StencilOp,
544b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             kEqual_StencilFunc,
545b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff,
546b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0x0000,
547b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                             0xffff);
548b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->setStencil(kDrawOutsideElement);
549b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fGpu->drawSimpleRect(clipSpaceIBounds);
550b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                drawState->disableStencil();
551b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            }
552f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        } else {
553c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            // all the remaining ops can just be directly draw into the accumulation buffer
554c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.com            drawState->setAlpha(0xff);
5556b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com            setup_boolean_blendcoeffs(drawState, op);
556b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            this->drawElement(result, element);
557f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        }
558f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
559f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
560c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
5614c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return result;
5621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
5631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
564f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
565fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device
566f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com// (as opposed to canvas) coordinates
5674c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.combool GrClipMaskManager::createStencilClipMask(InitialState initialState,
5684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const ElementList& elements,
5694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const SkIRect& clipSpaceIBounds,
5704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const SkIPoint& clipSpaceToStencilOffset) {
5711e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
572c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
5731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
57413b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com    GrDrawState* drawState = fGpu->drawState();
5751e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(drawState->isClipState());
5761e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
5771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
5781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(NULL != rt);
5791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
5801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // TODO: dynamically attach a SB when needed.
5811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
5821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    if (NULL == stencilBuffer) {
5831e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        return false;
5841e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
5854c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    int32_t genID = elements.tail()->getGenID();
5861e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
5874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (stencilBuffer->mustRenderClip(genID, clipSpaceIBounds, clipSpaceToStencilOffset)) {
5881e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
5894c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        stencilBuffer->setLastClip(genID, clipSpaceIBounds, clipSpaceToStencilOffset);
5901e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
591137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        // Set the matrix so that rendered clip elements are transformed from clip to stencil space.
592137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        SkVector translate = {
593137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            SkIntToScalar(clipSpaceToStencilOffset.fX),
594137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            SkIntToScalar(clipSpaceToStencilOffset.fY)
595137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        };
596137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        SkMatrix matrix;
597137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        matrix.setTranslate(translate);
598137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
59913b85aab6e1ff2ffd5475e329f9d1d21863b8eb6bsalomon@google.com        drawState = fGpu->drawState();
600137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
6011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->setRenderTarget(rt);
6021e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6039f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        // We set the current clip to the bounds so that our recursive draws are scissored to them.
6049f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        SkIRect stencilSpaceIBounds(clipSpaceIBounds);
6059f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
6069f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        GrDrawTarget::AutoClipRestore acr(fGpu, stencilSpaceIBounds);
6079f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com        drawState->enableState(GrDrawState::kClip_StateBit);
6089f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com
6091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#if !VISUALIZE_COMPLEX_CLIP
6101e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
6111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#endif
6121e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        int clipBit = stencilBuffer->bits();
6144c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
6151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        clipBit = (1 << (clipBit-1));
6161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        fGpu->clearStencilClip(stencilSpaceIBounds, kAllIn_InitialState == initialState);
6181e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6191e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // walk through each clip element and perform its set op
6201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // with the existing clip.
6214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        for (ElementList::Iter iter(elements.headIter()); NULL != iter.get(); iter.next()) {
6224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            const Element* element = iter.get();
6238afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            bool fillInverted = false;
6241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // enabled at bottom of loop
6251e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
626ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            // if the target is MSAA then we want MSAA enabled when the clip is soft
627ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            if (rt->isMultisampled()) {
6288182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
629ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com            }
6301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
63145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            // This will be used to determine whether the clip shape can be rendered into the
63245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            // stencil with arbitrary stencil settings.
63345a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            GrPathRenderer::StencilSupport stencilSupport;
6341e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6355f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
63612b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com
6378182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkRegion::Op op = element->getOp();
638f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathRenderer* pr = NULL;
64045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            SkTCopyOnFirstWrite<SkPath> clipPath;
6418182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            if (Element::kRect_Type == element->getType()) {
64245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
6431e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fillInverted = false;
6448afae61a57f87e4a50578effce6c428031499301tomhudson@google.com            } else {
6458182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                GrAssert(Element::kPath_Type == element->getType());
64645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                clipPath.init(element->getPath());
64745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                fillInverted = clipPath->isInverseFillType();
64845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                if (fillInverted) {
64945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                    clipPath.writable()->toggleInverseFillType();
65045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                }
65145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                pr = this->getContext()->getPathRenderer(*clipPath,
65245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         stroke,
65345a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         fGpu,
65445a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         false,
65545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         GrPathRendererChain::kStencilOnly_DrawType,
65645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                         &stencilSupport);
6571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (NULL == pr) {
6581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    return false;
6591e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
6601e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
6611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6621e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            int passes;
6631e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
6641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
66545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            bool canRenderDirectToStencil =
66645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
6671e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool canDrawDirectToClip; // Given the renderer, the element,
6684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // fill rule, and set operation can
6694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // we render the element directly to
6704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      // stencil bit used for clipping.
6714c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            canDrawDirectToClip = GrStencilSettings::GetClipPasses(op,
6724c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   canRenderDirectToStencil,
6734c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   clipBit,
6744c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   fillInverted,
6754c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   &passes,
6764c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                                   stencilSettings);
6771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6781e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // draw the element to the client stencil bits if necessary
6791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (!canDrawDirectToClip) {
6801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
6814c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kIncClamp_StencilOp,
6824c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kIncClamp_StencilOp,
6834c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             kAlways_StencilFunc,
6844c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0xffff,
6854c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0x0000,
6864c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                             0xffff);
6871e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                SET_RANDOM_COLOR
6888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                if (Element::kRect_Type == element->getType()) {
6891e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *drawState->stencil() = gDrawToStencil;
6908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    fGpu->drawSimpleRect(element->getRect(), NULL);
6911e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
6928182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    GrAssert(Element::kPath_Type == element->getType());
6931e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    if (canRenderDirectToStencil) {
6941e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        *drawState->stencil() = gDrawToStencil;
69545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                        pr->drawPath(*clipPath, stroke, fGpu, false);
6961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
69745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                        pr->stencilPath(*clipPath, stroke, fGpu);
6981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
6991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
7001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
7011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7021e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // now we modify the clip bit by rendering either the clip
7031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            // element directly or a bounding rect of the entire clip.
7041e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
7051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            for (int p = 0; p < passes; ++p) {
7061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                *drawState->stencil() = stencilSettings[p];
7071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (canDrawDirectToClip) {
7088182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    if (Element::kRect_Type == element->getType()) {
7091e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
7108182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                        fGpu->drawSimpleRect(element->getRect(), NULL);
7111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
7128182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                        GrAssert(Element::kPath_Type == element->getType());
7131e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        SET_RANDOM_COLOR
71445a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                        pr->drawPath(*clipPath, stroke, fGpu, false);
7151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    }
7161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
7171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    SET_RANDOM_COLOR
7184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    // The view matrix is setup to do clip space -> stencil space translation, so
7194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    // draw rect in clip space.
7204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    fGpu->drawSimpleRect(SkRect::MakeFromIRect(clipSpaceIBounds), NULL);
7211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
7221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
7231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        }
7241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    }
725c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    // set this last because recursive draws may overwrite it back to kNone.
726c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
727c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kStencil_ClipMaskType;
7281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
7291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
7301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
731f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com
732411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping of clip-respecting stencil funcs to normal stencil funcs
733411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com// mapping depends on whether stencil-clipping is in effect.
734fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comstatic const GrStencilFunc
735411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    gSpecialToBasicStencilFunc[2][kClipStencilFuncCount] = {
736411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is DISABLED,  we are effectively always inside the clip
737411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
738411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kAlways_StencilFunc,          // kAlwaysIfInClip_StencilFunc
739411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
740411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
741411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
742411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
743411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kNotEqual_StencilFunc,        // kNonZeroIfInClip_StencilFunc
744411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref 0 and do normal nequal.
745411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    },
746411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    {// Stencil-Clipping is ENABLED
747411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // In the Clip Funcs
748411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kAlwaysIfInClip_StencilFunc
749411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // eq stencil clip bit, mask
750411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // out user bits.
751411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
752411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kEqual_StencilFunc,           // kEqualIfInClip_StencilFunc
753411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // add stencil bit to mask and ref
754411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
755411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kLessIfInClip_StencilFunc
756411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLEqual_StencilFunc,          // kLEqualIfInClip_StencilFunc
757411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // for both of these we can add
758411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // the clip bit to the mask and
759411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // ref and compare as normal
760411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // Special in the clip func that forces user's ref to be 0.
761411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        kLess_StencilFunc,            // kNonZeroIfInClip_StencilFunc
762411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // make ref have only the clip bit set
763411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // and make comparison be less
764411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                      // 10..0 < 1..user_bits..
765411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
766411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com};
767411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
768a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comnamespace {
769a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// Sets the settings to clip against the stencil buffer clip while ignoring the
770a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com// client bits.
771a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comconst GrStencilSettings& basic_apply_stencil_clip_settings() {
772a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // stencil settings to use when clip is in stencil
773a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
774a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
775a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kKeep_StencilOp,
776a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kAlwaysIfInClip_StencilFunc,
777a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
778a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        0x0000,
779fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        0x0000);
780a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
781a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
782a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
783a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
784a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::setGpuStencil() {
785a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // We make two copies of the StencilSettings here (except in the early
786a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // exit scenario. One copy from draw state to the stack var. Then another
787a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // from the stack var to the gpu. We could make this class hold a ptr to
788a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // GrGpu's fStencilSettings and eliminate the stack copy here.
789a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
790a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    const GrDrawState& drawState = fGpu->getDrawState();
791a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
792a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // use stencil for clipping if clipping is enabled and the clip
793a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // has been written into the stencil.
794a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrClipMaskManager::StencilClipMode clipMode;
795a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (this->isClipInStencil() && drawState.isClipState()) {
796a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
797a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We can't be modifying the clip and respecting it at the same time.
798a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrAssert(!drawState.isStateFlagEnabled(
799a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit));
800a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else if (drawState.isStateFlagEnabled(
801a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    GrGpu::kModifyStencilClip_StateBit)) {
802a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
803a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
804a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
805a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
806a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
807a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings settings;
808a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // The GrGpu client may not be using the stencil buffer but we may need to
809a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // enable it in order to respect a stencil clip.
810a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (drawState.getStencil().isDisabled()) {
811a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
812a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            settings = basic_apply_stencil_clip_settings();
813a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
814a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            fGpu->disableStencil();
815a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            return;
816a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
817a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    } else {
818a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings = drawState.getStencil();
819a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
820a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
821a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // TODO: dynamically attach a stencil buffer
822a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    int stencilBits = 0;
823fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    GrStencilBuffer* stencilBuffer =
824a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        drawState.getRenderTarget()->getStencilBuffer();
825a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (NULL != stencilBuffer) {
826a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        stencilBits = stencilBuffer->bits();
827a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
828a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
829bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    GrAssert(fGpu->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp());
830bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    GrAssert(fGpu->caps()->twoSidedStencilSupport() || !settings.isTwoSided());
831a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    this->adjustStencilParams(&settings, clipMode, stencilBits);
832a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    fGpu->setStencilSettings(settings);
833a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
834a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
835a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.comvoid GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
836a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            StencilClipMode mode,
837a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                            int stencilBitCnt) {
838411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    GrAssert(stencilBitCnt > 0);
839411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
840411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    if (kModifyClip_StencilClipMode == mode) {
841a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // We assume that this clip manager itself is drawing to the GrGpu and
842a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // has already setup the correct values.
843a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return;
844411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
845a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
846411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int clipBit = (1 << (stencilBitCnt - 1));
847411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    unsigned int userBits = clipBit - 1;
848411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
849a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
850bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com    bool twoSided = fGpu->caps()->twoSidedStencilSupport();
851a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
852a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    bool finished = false;
853a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    while (!finished) {
854a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrStencilFunc func = settings->func(face);
855a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t writeMask = settings->writeMask(face);
856a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcMask = settings->funcMask(face);
857a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        uint16_t funcRef = settings->funcRef(face);
858a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
859a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        GrAssert((unsigned) func < kStencilFuncCount);
860a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
861a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        writeMask &= userBits;
862a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
863a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (func >= kBasicStencilFuncCount) {
864a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            int respectClip = kRespectClip_StencilClipMode == mode;
865a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            if (respectClip) {
866a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                // The GrGpu class should have checked this
867a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                GrAssert(this->isClipInStencil());
868a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                switch (func) {
869a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kAlwaysIfInClip_StencilFunc:
870a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = clipBit;
871a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
872a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
873a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kEqualIfInClip_StencilFunc:
874a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLessIfInClip_StencilFunc:
875a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kLEqualIfInClip_StencilFunc:
876a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
877a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef  = (funcRef  & userBits) | clipBit;
878a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
879a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    case kNonZeroIfInClip_StencilFunc:
880a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcMask = (funcMask & userBits) | clipBit;
881a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        funcRef = clipBit;
882a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        break;
883a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                    default:
884a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        GrCrash("Unknown stencil func");
885a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                }
886a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            } else {
887a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcMask &= userBits;
888a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                funcRef &= userBits;
889411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            }
890fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            const GrStencilFunc* table =
891a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                gSpecialToBasicStencilFunc[respectClip];
892a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            func = table[func - kBasicStencilFuncCount];
893a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            GrAssert(func >= 0 && func < kBasicStencilFuncCount);
894411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        } else {
895a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcMask &= userBits;
896a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            funcRef &= userBits;
897411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        }
898a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
899a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFunc(face, func);
900a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setWriteMask(face, writeMask);
901a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncMask(face, funcMask);
902a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->setFuncRef(face, funcRef);
903a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
904a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (GrStencilSettings::kFront_Face == face) {
905a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            face = GrStencilSettings::kBack_Face;
906a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = !twoSided;
907a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
908a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            finished = true;
909a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
910a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
911a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (!twoSided) {
912a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        settings->copyFrontSettingsToBack();
913411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
914411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}
915411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
916411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
9174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comGrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t clipStackGenID,
9184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     GrReducedClip::InitialState initialState,
9194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     const GrReducedClip::ElementList& elements,
9204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                                     const SkIRect& clipSpaceIBounds) {
921c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
9226b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    GrTexture* result;
9244c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (this->getMaskTexture(clipStackGenID, clipSpaceIBounds, &result)) {
9254c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return result;
9266b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
9276b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (NULL == result) {
929f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com        fAACache.reset();
9304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        return NULL;
9316b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
9326b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
9334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // The mask texture may be larger than necessary. We round out the clip space bounds and pin
9344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // the top left corner of the resulting rect to the top left of the texture.
9354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
9364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
9372c75681e36b33fcafc5665d7012bbd4fc6647d83robertphillips@google.com    GrSWMaskHelper helper(this->getContext());
9386b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
939b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com    SkMatrix matrix;
9404c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    matrix.setTranslate(SkIntToScalar(-clipSpaceIBounds.fLeft),
9414c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                        SkIntToScalar(-clipSpaceIBounds.fTop));
9424c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    helper.init(maskSpaceIBounds, &matrix);
9434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
9444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    helper.clear(kAllIn_InitialState == initialState ? 0xFF : 0x00);
945fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
9465f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
94712b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com
9484c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    for (ElementList::Iter iter(elements.headIter()) ; NULL != iter.get(); iter.next()) {
949fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
9504c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        const Element* element = iter.get();
9518182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        SkRegion::Op op = element->getOp();
952fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
9534c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
9544c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // Intersect and reverse difference require modifying pixels outside of the geometry
9554c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // that is being "drawn". In both cases we erase all the pixels outside of the geometry
9564c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // but leave the pixels inside the geometry alone. For reverse difference we invert all
9574c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            // the pixels before clearing the ones outside the geometry.
958fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            if (SkRegion::kReverseDifference_Op == op) {
9594c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                SkRect temp = SkRect::MakeFromIRect(clipSpaceIBounds);
960fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // invert the entire scene
961366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                helper.draw(temp, SkRegion::kXOR_Op, false, 0xFF);
962fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
963fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
9648182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            if (Element::kRect_Type == element->getType()) {
965fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // convert the rect to a path so we can invert the fill
966fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                SkPath temp;
9678182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                temp.addRect(element->getRect());
96812b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                temp.setFillType(SkPath::kInverseEvenOdd_FillType);
969fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
97012b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                helper.draw(temp, stroke, SkRegion::kReplace_Op,
97112b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                            element->isAA(),
972366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                            0x00);
9738182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            } else {
9748182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                GrAssert(Element::kPath_Type == element->getType());
97512b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                SkPath clipPath = element->getPath();
97612b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com                clipPath.toggleInverseFillType();
977d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com                helper.draw(clipPath, stroke,
978fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                            SkRegion::kReplace_Op,
9798182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                            element->isAA(),
980366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com                            0x00);
981fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            }
982fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
983fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com            continue;
984fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        }
985fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
986fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // The other ops (union, xor, diff) only affect pixels inside
987fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // the geometry so they can just be drawn normally
9888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        if (Element::kRect_Type == element->getType()) {
9898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            helper.draw(element->getRect(), op, element->isAA(), 0xFF);
9908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        } else {
9918182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            GrAssert(Element::kPath_Type == element->getType());
99212b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com            helper.draw(element->getPath(), stroke, op, element->isAA(), 0xFF);
9936b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com        }
9946b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    }
9956b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
996d92cf2ebbfbb9d737ea4a551e64ffccb08376875robertphillips@google.com    helper.toTexture(result);
9976b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
998c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    fCurrClipMaskType = kAlpha_ClipMaskType;
9994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    return result;
10006b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com}
10016b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com
1002f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
1003f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.comvoid GrClipMaskManager::releaseResources() {
1004f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    fAACache.releaseResources();
10051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com}
10066e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com
10076e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.comvoid GrClipMaskManager::setGpu(GrGpu* gpu) {
10086e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com    fGpu = gpu;
10096e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com    fAACache.setContext(gpu->getContext());
10106e4e65066a7c0dbc9bfbfe4b8f5d49c3d8a79b59bsalomon@google.com}
1011