GrClipMaskManager.cpp revision 8a4fc40b02fa0a8300ade26863f4ddae69197d62
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
9c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrClipMaskManager.h"
10c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrGpu.h"
11bfe2b9d3a290d0153b82617cd6b65a4814fe89e3jvanverth@google.com#include "GrRenderTarget.h"
12c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrStencilBuffer.h"
13c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPathRenderer.h"
14c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrPaint.h"
151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "SkRasterClip.h"
166bc1b5fab8554a9cb643277b4867965dd4535cd6bsalomon#include "GrAAConvexPathRenderer.h"
171e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com#include "GrAAHairLinePathRenderer.h"
18c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com
193a0cfeb96185934c0a36f1313f21b96c57ca6341joshualitt// TODO: move GrSWMaskHelper out of GrSoftwarePathRender.h & remove this include
203a0cfeb96185934c0a36f1313f21b96c57ca6341joshualitt#include "GrSoftwarePathRenderer.h"
213a0cfeb96185934c0a36f1313f21b96c57ca6341joshualitt
22a58fe35fdae3481cf43062f7032820c320c3d163joshualitt//#define GR_AA_CLIP 1
239513143efa734bef0c1a0c7f945022572dbc8518egdaniel//#define GR_SW_CLIP 1
24a58fe35fdae3481cf43062f7032820c320c3d163joshualitt
259513143efa734bef0c1a0c7f945022572dbc8518egdaniel////////////////////////////////////////////////////////////////////////////////
26c6b3e48cb3a22d83ba3f4b9a614a5a35b05958a0bsalomon@google.comvoid ScissoringSettings::setupScissoring(GrGpu* gpu) {
278182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    if (!fEnableScissoring) {
2851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        gpu->disableScissor();
2951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        return;
30e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    }
31fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3208283afc265f1153834256fc1012519813ba6b73bsalomon@google.com    gpu->enableScissoring(fScissorRect);
339853ccef19c200be93a6211f32589fa82a53067cjoshualitt}
348dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
359853ccef19c200be93a6211f32589fa82a53067cjoshualittnamespace {
368dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel// set up the draw state to enable the aa clipping mask. Besides setting up the
37a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com// sampler matrix this also alters the vertex layout
38b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.comvoid setup_drawstate_aaclip(GrGpu* gpu,
39309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon                            GrTexture* result,
40309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon                            const GrIRect &bound) {
41a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    GrDrawState* drawState = gpu->drawState();
42fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    GrAssert(drawState);
437b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com
44a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    static const int maskStage = GrPaint::kTotalStages+1;
457b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    GrMatrix mat;
478dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    mat.setIDiv(result->width(), result->height());
48eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com    mat.preTranslate(SkIntToScalar(-bound.fLeft), SkIntToScalar(-bound.fTop));
497b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    mat.preConcat(drawState->getViewMatrix());
50907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org
51907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org    drawState->sampler(maskStage)->reset(GrSamplerState::kClamp_WrapMode,
52b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com                                         GrSamplerState::kNearest_Filter,
53309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon                                         mat);
54a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
55a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    drawState->setTexture(maskStage, result);
56e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
579853ccef19c200be93a6211f32589fa82a53067cjoshualitt    // The AA clipping determination happens long after the geometry has
588dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    // been set up to draw. Here we directly enable the AA clip mask stage
598059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    gpu->addToVertexLayout(
60e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(maskStage));
61e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com}
62e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
63e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool path_needs_SW_renderer(GrContext* context,
64e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                           GrGpu* gpu,
65e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                           const SkPath& path,
66e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                           GrPathFill fill,
67e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                           bool doAA) {
68e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    // last (false) parameter disallows use of the SW path renderer
6945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com    return NULL == context->getPathRenderer(path, fill, gpu, doAA, false);
7045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com}
7145a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com
7245a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com}
738dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
748dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel/*
75e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com * This method traverses the clip stack to see if the GrSoftwarePathRenderer
766b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com * will be used on any element. If so, it returns true to indicate that the
776b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com * entire clip should be rendered in SW and then uploaded en masse to the gpu.
78fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com */
79fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.combool GrClipMaskManager::useSWOnlyPath(GrGpu* gpu, const GrClip& clipIn) {
80fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com
81fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    if (!clipIn.requiresAA()) {
82fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com        // The stencil buffer can handle this case
838dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        return false;
848059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    }
859853ccef19c200be93a6211f32589fa82a53067cjoshualitt
868a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com    // TODO: generalize this function so that when
87fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // a clip gets complex enough it can just be done in SW regardless
88fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com    // of whether it would invoke the GrSoftwarePathRenderer.
895f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    bool useSW = false;
90d21444aab7128c97f4e0eb5e9bf05111d5037292skia.committer@gmail.com
918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    for (int i = 0; i < clipIn.getElementCount(); ++i) {
928059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt
938059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        if (SkRegion::kReplace_Op == clipIn.getOp(i)) {
948059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            // Everything before a replace op can be ignored so start
958059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            // afresh w.r.t. determining if any element uses the SW path
96bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina            useSW = false;
974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        }
98f69a11b5c5dc5ae02489dfe7ca6432d641b9f121robertphillips@google.com
99e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        if (kRect_ClipType == clipIn.getElementType(i)) {
100e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // Non-anti-aliased rects can always be drawn directly (w/o
101e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // using the software path) so the anti-aliased rects are all
102e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            // that need to be checked here
1038dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            if (clipIn.getDoAA(i)) {
1048059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                // Antialiased rects are converted to paths and then drawn with
105e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                // kEvenOdd_PathFill.
106e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
107fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // TODO: wrap GrContext::fillAARect in a helper class and
108fa66294c7705831808ce7772d4328fc626d45034robertphillips@google.com                // draw AA rects directly rather than converting to paths
1094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                SkPath temp;
110a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com                temp.addRect(clipIn.getRect(i));
111a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com
1128dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                if (path_needs_SW_renderer(this->getContext(), gpu, temp,
1138dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                           kEvenOdd_PathFill, true)) {
1149853ccef19c200be93a6211f32589fa82a53067cjoshualitt                    useSW = true;
115e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                }
116217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein            }
117e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        } else {
11849f085dddff10473b6ebf832a974288300224e60bsalomon            if (path_needs_SW_renderer(this->getContext(), gpu,
119e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                       clipIn.getPath(i),
120e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                       clipIn.getPathFill(i),
121e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                       clipIn.getDoAA(i))) {
122e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                useSW = true;
1238dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            }
1248dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        }
125bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina    }
126e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
12749f085dddff10473b6ebf832a974288300224e60bsalomon    return useSW;
128e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org}
129e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
130e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
131e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org// sort out what kind of clip mask needs to be created: alpha, stencil,
132e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org// scissor, or entirely software
133e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.orgbool GrClipMaskManager::createClipMask(GrGpu* gpu,
134e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                       const GrClip& clipIn,
135e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org                                       ScissoringSettings* scissorSettings) {
136e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
13749f085dddff10473b6ebf832a974288300224e60bsalomon    GrAssert(scissorSettings);
138e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
139e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    scissorSettings->fEnableScissoring = false;
140e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    fClipMaskInStencil = false;
141e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    fClipMaskInAlpha = false;
142e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
143e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    GrDrawState* drawState = gpu->drawState();
144e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    if (!drawState->isClipState()) {
145e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        return true;
146e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
147e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
148e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    GrRenderTarget* rt = drawState->getRenderTarget();
149e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
150e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // GrDrawTarget should have filtered this for us
151e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    GrAssert(NULL != rt);
152e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
153e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org#if GR_SW_CLIP
154e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // If MSAA is enabled we can do everything in the stencil buffer.
155b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    // Otherwise check if we should just create the entire clip mask
156e85a32d4f8ce7fb9b6aaae89137dbf3766d833f2robertphillips    // in software (this will only happen if the clip mask is anti-aliased
157e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // and too complex for the gpu to handle in its entirety)
158217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein    if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
159e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // The clip geometry is complex enough that it will be more
160e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // efficient to create it entirely in software
161e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        GrTexture* result = NULL;
162b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        GrIRect bound;
163b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
164e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            fClipMaskInAlpha = true;
165b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt
166b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            setup_drawstate_aaclip(gpu, result, bound);
167e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            return true;
168b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        }
169e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
170e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // if SW clip mask creation fails fall through to the other
171b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        // two possible methods (bottoming out at stencil clipping)
172e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
173e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org#endif // GR_SW_CLIP
174e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
175e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org#if GR_AA_CLIP
176e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // If MSAA is enabled use the (faster) stencil path for AA clipping
177b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    // otherwise the alpha clip mask is our only option
178e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    if (0 == rt->numSamples() && clipIn.requiresAA()) {
179e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // Since we are going to create a destination texture of the correct
180e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // size for the mask (rather than being bound by the size of the
181e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // render target) we aren't going to use scissoring like the stencil
182e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // path does (see scissorSettings below)
183b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        GrTexture* result = NULL;
184e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        GrIRect bound;
185e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
186e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            fClipMaskInAlpha = true;
187e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
188e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            setup_drawstate_aaclip(gpu, result, bound);
189b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            return true;
1908dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        }
191217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein
192e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // if alpha clip mask creation fails fall through to the stencil
193e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org        // buffer method
194e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    }
195e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org#endif // GR_AA_CLIP
196217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein
197e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // Either a hard (stencil buffer) clip was explicitly requested or
198e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // an antialiased clip couldn't be created. In either case, free up
199e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // the texture in the antialiased mask cache.
200e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // TODO: this may require more investigation. Ganesh performs a lot of
201e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit
202e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // the stencil buffer path. These may be "incorrectly" clearing the
203e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // AA cache.
204e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    fAACache.reset();
205f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
2066b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    GrRect bounds;
2076b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    GrRect rtRect;
2088dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    rtRect.setLTRB(0, 0,
2098dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                   GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
2108dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    if (clipIn.hasConservativeBounds()) {
2113e79124a69d4806f0a1a776090bff718e1b90970bsalomon        bounds = clipIn.getConservativeBounds();
2129853ccef19c200be93a6211f32589fa82a53067cjoshualitt        if (!bounds.intersect(rtRect)) {
2139853ccef19c200be93a6211f32589fa82a53067cjoshualitt            bounds.setEmpty();
214c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com        }
2157a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt    } else {
2167a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt        bounds = rtRect;
2177a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt    }
218a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
219bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina    bounds.roundOut(&scissorSettings->fScissorRect);
220d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    if  (scissorSettings->fScissorRect.isEmpty()) {
221bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
2224c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // TODO: I think we can do an early exit here - after refactoring try:
2234c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        //  set fEnableScissoring to true but leave fClipMaskInStencil false
2248dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        //  and return - everything is going to be scissored away anyway!
2254c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    }
2261e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    scissorSettings->fEnableScissoring = true;
22749f085dddff10473b6ebf832a974288300224e60bsalomon
2281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    // use the stencil clip if we can't represent the clip as a rectangle.
2298dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
2304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                         !bounds.isEmpty();
2314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
2324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    if (fClipMaskInStencil) {
233bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
234bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina    }
235bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina
236bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina    return true;
237bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina}
238bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina
239bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina#define VISUALIZE_COMPLEX_CLIP 0
2404c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
241bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina#if VISUALIZE_COMPLEX_CLIP
2424c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    #include "GrRandom.h"
2434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    GrRandom gRandom;
2444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    #define SET_RANDOM_COLOR drawState->setColor(0xff000000 | gRandom.nextU());
2454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com#else
2464c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    #define SET_RANDOM_COLOR
2474c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com#endif
2483e11c0bd92fbd12f59080c3f9450201d6105db83robertphillips@google.com
2494c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.comnamespace {
2508dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel/**
2514c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com * Does "container" contain "containee"? If either is empty then
252a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com * no containment is possible.
253a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com */
254e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.orgbool contains(const SkRect& container, const SkIRect& containee) {
255e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    return  !containee.isEmpty() && !container.isEmpty() &&
256e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            container.fLeft <= SkIntToScalar(containee.fLeft) &&
257e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            container.fTop <= SkIntToScalar(containee.fTop) &&
258e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            container.fRight >= SkIntToScalar(containee.fRight) &&
259e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org            container.fBottom >= SkIntToScalar(containee.fBottom);
260e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org}
261e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
262e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org
263e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
264b21fac156d9287d6c0cfd446d707c4c7be6fae6ecommit-bot@chromium.org// determines how many elements at the head of the clip can be skipped and
265e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org// whether the initial clear should be to the inside- or outside-the-clip value,
266259656779334689ab1624ec4e2e234b35fe4024bbsalomon// and what op should be used to draw the first element that isn't skipped.
267217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtkleinint process_initial_clip_elements(const GrClip& clip,
268217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                                  const GrIRect& bounds,
269217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                                  bool* clearToInside,
270217daa7ec592fc306edffb9fb2a3d8c7ebff8c2dmtklein                                  SkRegion::Op* startOp) {
27177b1307c1f5dac019575a6d431d5ce657370c4fbjoshualitt
272e5a041c0688ccb861cc85f8917338602864d8e5acommit-bot@chromium.org    // logically before the first element of the clip stack is
2738dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    // processed the clip is entirely open. However, depending on the
27465ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org    // first set op we may prefer to clear to 0 for performance. We may
27565ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org    // also be able to skip the initial clip paths/rects. We loop until
27665ee5f424cb4dabd453268902c00086605d77c1dcommit-bot@chromium.org    // we cannot skip an element.
277d3066bd9b4a37cf4a39e7df7e1432f3df10dbc67bsalomon@google.com    int curr;
278a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com    bool done = false;
2794c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    *clearToInside = true;
2806b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    int count = clip.getElementCount();
281a3e5c63ab0264332169df4583a8a7da186fb4e66robertphillips@google.com
2828059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    for (curr = 0; curr < count && !done; ++curr) {
2838059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        switch (clip.getOp(curr)) {
2848059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            case SkRegion::kReplace_Op:
2858059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                // replace ignores everything previous
2868059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                *startOp = SkRegion::kReplace_Op;
2878059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                *clearToInside = false;
2888dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                done = true;
2894c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                break;
2904c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            case SkRegion::kIntersect_Op:
2914c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // if this element contains the entire bounds then we
2924c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // can skip it.
2934c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                if (kRect_ClipType == clip.getElementType(curr)
2948059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                    && contains(clip.getRect(curr), bounds)) {
2954c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    break;
2964c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                }
2974c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // if everything is initially clearToInside then intersect is
2984c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // same as clear to 0 and treat as a replace. Otherwise,
2994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // set stays empty.
3008059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                if (*clearToInside) {
3014c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    *startOp = SkRegion::kReplace_Op;
3024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    *clearToInside = false;
3036b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com                    done = true;
30449f085dddff10473b6ebf832a974288300224e60bsalomon                }
3054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                break;
3064c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // we can skip a leading union.
3074c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            case SkRegion::kUnion_Op:
3084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // if everything is initially outside then union is
3098dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                // same as replace. Otherwise, every pixel is still
3108dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                // clearToInside
311f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                if (!*clearToInside) {
312f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3134c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    done = true;
314f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                }
315f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                break;
3164c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            case SkRegion::kXOR_Op:
3174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // xor is same as difference or replace both of which
3184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // can be 1-pass instead of 2 for xor.
3194c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                if (*clearToInside) {
3204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    *startOp = SkRegion::kDifference_Op;
3215acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com                } else {
3225acc0e36d987dff3172fd45a14b66c52a51d49e4robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                }
3244c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                done = true;
3259853ccef19c200be93a6211f32589fa82a53067cjoshualitt                break;
3269853ccef19c200be93a6211f32589fa82a53067cjoshualitt            case SkRegion::kDifference_Op:
327d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org                // if all pixels are clearToInside then we have to process the
3284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // difference, otherwise it has no effect and all pixels
3294c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // remain outside.
3304c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                if (*clearToInside) {
3314c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    *startOp = SkRegion::kDifference_Op;
3324c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    done = true;
3334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                }
3344c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                break;
3354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            case SkRegion::kReverseDifference_Op:
3364c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // if all pixels are clearToInside then reverse difference
33777b1307c1f5dac019575a6d431d5ce657370c4fbjoshualitt                // produces empty set. Otherise it is same as replace
3388dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                if (*clearToInside) {
3391e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *clearToInside = false;
3401e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                } else {
3411e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *startOp = SkRegion::kReplace_Op;
3421e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    done = true;
343f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                }
3448dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                break;
3458dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            default:
3468dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                GrCrash("Unknown set op.");
3478750924a1470e8215b2a344155259b93062d3fa2egdaniel        }
3488dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    }
349f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    return done ? curr-1 : count;
35072176b2d38db005863a54e3dd6657bbabd068bb6robertphillips@google.com}
351f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
352f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com}
3538dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
3548059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt
3559853ccef19c200be93a6211f32589fa82a53067cjoshualittnamespace {
356e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
357e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
3589853ccef19c200be93a6211f32589fa82a53067cjoshualitt// set up the OpenGL blend function to perform the specified
359f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com// boolean operation for alpha clip mask creation
3608dd688b7569df569a672a8a67b2db86a9d376cfcegdanielvoid setup_boolean_blendcoeffs(GrDrawState* drawState, SkRegion::Op op) {
361f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
3628750924a1470e8215b2a344155259b93062d3fa2egdaniel    switch (op) {
3638750924a1470e8215b2a344155259b93062d3fa2egdaniel        case SkRegion::kReplace_Op:
3648750924a1470e8215b2a344155259b93062d3fa2egdaniel            drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
3658750924a1470e8215b2a344155259b93062d3fa2egdaniel            break;
366e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        case SkRegion::kIntersect_Op:
3678182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            drawState->setBlendFunc(kDC_BlendCoeff, kZero_BlendCoeff);
368e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            break;
369e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        case SkRegion::kUnion_Op:
370e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            drawState->setBlendFunc(kOne_BlendCoeff, kISC_BlendCoeff);
3718182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
372b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt        case SkRegion::kXOR_Op:
373b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt            drawState->setBlendFunc(kIDC_BlendCoeff, kISC_BlendCoeff);
3748182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
3758059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        case SkRegion::kDifference_Op:
3768059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            drawState->setBlendFunc(kZero_BlendCoeff, kISC_BlendCoeff);
377329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt            break;
3788dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        case SkRegion::kReverseDifference_Op:
3792e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt            drawState->setBlendFunc(kIDC_BlendCoeff, kZero_BlendCoeff);
3808059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            break;
381a58fe35fdae3481cf43062f7032820c320c3d163joshualitt        default:
3828059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            GrAssert(false);
3838182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
3848dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    }
3858182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com}
3868182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
387e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org////////////////////////////////////////////////////////////////////////////////
388e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgbool draw_path(GrContext* context,
389e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org               GrGpu* gpu,
390b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth               const SkPath& path,
391e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org               GrPathFill fill,
392e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org               bool doAA) {
393e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
3945f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    GrPathRenderer* pr = context->getPathRenderer(path, fill, gpu, doAA, true);
395e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    if (NULL == pr) {
396e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com        return false;
397e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    }
398e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
3998dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    pr->drawPath(path, fill, NULL, gpu, 0, doAA);
4008dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    return true;
401e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com}
402e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
4034c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com}
4044c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
4059853ccef19c200be93a6211f32589fa82a53067cjoshualitt////////////////////////////////////////////////////////////////////////////////
4068dd688b7569df569a672a8a67b2db86a9d376cfcegdanielbool GrClipMaskManager::drawClipShape(GrGpu* gpu,
4078dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                      GrTexture* target,
4084c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      const GrClip& clipIn,
4094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                      int index) {
410f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrDrawState* drawState = gpu->drawState();
411f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    GrAssert(NULL != drawState);
412f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
413f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    drawState->setRenderTarget(target->asRenderTarget());
4148dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
4159853ccef19c200be93a6211f32589fa82a53067cjoshualitt    if (kRect_ClipType == clipIn.getElementType(index)) {
4169853ccef19c200be93a6211f32589fa82a53067cjoshualitt        if (clipIn.getDoAA(index)) {
4179853ccef19c200be93a6211f32589fa82a53067cjoshualitt            // convert the rect to a path for AA
4188dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            SkPath temp;
419b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            temp.addRect(clipIn.getRect(index));
420e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org
421e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            return draw_path(this->getContext(), gpu, temp,
422e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                             kEvenOdd_PathFill, clipIn.getDoAA(index));
423e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        } else {
424e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            gpu->drawSimpleRect(clipIn.getRect(index), NULL, 0);
425e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        }
426e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    } else {
427e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        return draw_path(this->getContext(), gpu,
428e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                         clipIn.getPath(index),
429b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                         clipIn.getPathFill(index),
430e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                         clipIn.getDoAA(index));
431e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    }
432e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org    return true;
433e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org}
4348dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
4358059eb9f6e24ed609393fbda4ad71edea03ac258joshualittvoid GrClipMaskManager::drawTexture(GrGpu* gpu,
43649f085dddff10473b6ebf832a974288300224e60bsalomon                                    GrTexture* target,
437b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                    GrTexture* texture) {
438b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrDrawState* drawState = gpu->drawState();
439b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    GrAssert(NULL != drawState);
4408dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
4419853ccef19c200be93a6211f32589fa82a53067cjoshualitt    // no AA here since it is encoded in the texture
4427b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    drawState->setRenderTarget(target->asRenderTarget());
4437b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
444fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    GrMatrix sampleM;
445fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    sampleM.setIDiv(texture->width(), texture->height());
4468dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    drawState->setTexture(0, texture);
447f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
4488750924a1470e8215b2a344155259b93062d3fa2egdaniel    drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
4498dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                 GrSamplerState::kNearest_Filter,
45072b2e6fff3f54c6aa80a98eab4c73f02a8cd450dskia.committer@gmail.com                                 sampleM);
451b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com
4527b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()),
453956b310f13c7412c035406c658ff16ca85eac656skia.committer@gmail.com                                 SkIntToScalar(target->height()));
4548dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
4557b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    gpu->drawSimpleRect(rect, NULL, 1 << 0);
4567b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
457907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org    drawState->setTexture(0, NULL);
458907fbd53c5e5dd4cbde7b72f9242b51febd7ef95commit-bot@chromium.org}
459b86add1ad37776818e1f730359ec587c9fdbff5fhumper@google.com
4608750924a1470e8215b2a344155259b93062d3fa2egdanielnamespace {
4618dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
4628dd688b7569df569a672a8a67b2db86a9d376cfcegdanielvoid clear(GrGpu* gpu,
463f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com           GrTexture* target,
464f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com           GrColor color) {
465427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon    GrDrawState* drawState = gpu->drawState();
466f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon    GrAssert(NULL != drawState);
4673f490a0c0170feb8b53c220d6c5331c23aeb3f23bsalomon
4684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // zap entire target to specified color
4694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    drawState->setRenderTarget(target->asRenderTarget());
47051d1f7e3a4305e517586dc158a0329bbaa8896aabsalomon    gpu->clear(NULL, color);
47151d1f7e3a4305e517586dc158a0329bbaa8896aabsalomon}
47251d1f7e3a4305e517586dc158a0329bbaa8896aabsalomon
47351d1f7e3a4305e517586dc158a0329bbaa8896aabsalomon}
47451d1f7e3a4305e517586dc158a0329bbaa8896aabsalomon
4756b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// get a texture to act as a temporary buffer for AA clip boolean operations
476329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt// TODO: given the expense of createTexture we may want to just cache this too
4776d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.comvoid GrClipMaskManager::getTemp(const GrIRect& bounds,
4786d62df404bf420bedff4d7b5edd061740a673d44robertphillips@google.com                                GrAutoScratchTexture* temp) {
4796b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    if (NULL != temp->texture()) {
480ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        // we've already allocated the temp texture
481ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        return;
482ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    }
483d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org
4844c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    const GrTextureDesc desc = {
485ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
486ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        bounds.width(),
4874c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        bounds.height(),
488ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        kAlpha_8_GrPixelConfig,
489ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        0           // samples
490f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    };
491ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
492ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    temp->set(this->getContext(), desc);
493ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski}
494ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
495ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
496ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevskivoid GrClipMaskManager::setupCache(const GrClip& clipIn,
497ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski                                   const GrIRect& bounds) {
498ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // Since we are setting up the cache we know the last lookup was a miss
499ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // Free up the currently cached mask so it can be reused
500a72eef322c686954cdffa849dc26d8133b802f1drobertphillips@google.com    fAACache.reset();
501f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon
502f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon    const GrTextureDesc desc = {
503ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        kRenderTarget_GrTextureFlagBit|kNoStencil_GrTextureFlagBit,
504ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        bounds.width(),
505ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        bounds.height(),
506ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        kAlpha_8_GrPixelConfig,
507ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski        0           // samples
508ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    };
5098fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com
5108fff356c8505f2ac78e1fc9dc17c1192e3a608e4robertphillips@google.com    fAACache.acquireMask(clipIn, desc, bounds);
511ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski}
512ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
5136b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com////////////////////////////////////////////////////////////////////////////////
514f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com// Shared preamble between gpu and SW-only AA clip mask creation paths.
5156b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// Handles caching, determination of clip mask bound & allocation (if needed)
5166b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com// of the result texture
517d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org// Returns true if there is no more work to be done (i.e., we got a cache hit)
518bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarinabool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu,
519bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina                                         const GrClip& clipIn,
5208059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                         GrTexture** result,
5214c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                         GrIRect *resultBounds) {
522f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    GrDrawState* origDrawState = gpu->drawState();
523c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com    GrAssert(origDrawState->isClipState());
524ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
525ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    GrRenderTarget* rt = origDrawState->getRenderTarget();
52649f085dddff10473b6ebf832a974288300224e60bsalomon    GrAssert(NULL != rt);
527c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com
5284c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    GrRect rtRect;
5296b70a7bd3328ea0a12be47b1a7f835c905f16147robertphillips@google.com    rtRect.setLTRB(0, 0,
530f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
531ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski
532ad1dc589cef8aebf7e14672ffdaa31c6d399675dkrajcevski    // unlike the stencil path the alpha path is not bound to the size of the
5334c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    // render target - determine the minimum size required for the mask
534f105b109264f71dfb0bfd9977e6a5dd0a5a12f57robertphillips@google.com    GrRect bounds;
5354c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
536f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    if (clipIn.hasConservativeBounds()) {
537f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        bounds = clipIn.getConservativeBounds();
5388059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        if (!bounds.intersect(rtRect)) {
5398059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            // the mask will be empty in this case
5408059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            GrAssert(false);
5418059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            bounds.setEmpty();
5428059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        }
5434c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    } else {
5444c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        // still locked to the size of the render target
5454c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com        bounds = rtRect;
546f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com    }
5477b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com
5487b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    GrIRect intBounds;
549329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt    bounds.roundOut(&intBounds);
550329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt
551329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt    // need to outset a pixel since the standard bounding box computation
552329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt    // path doesn't leave any room for antialiasing (esp. w.r.t. rects)
553d9f7503e0cb0c4db856f53b4bdeec1332db6f296skia.committer@gmail.com    intBounds.outset(1, 1);
554b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
555b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    // TODO: make sure we don't outset if bounds are still 0,0 @ min
556b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
557b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    if (fAACache.canReuse(clipIn,
558329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt                          intBounds.width(),
559427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon                          intBounds.height())) {
5609853ccef19c200be93a6211f32589fa82a53067cjoshualitt        *result = fAACache.getLastMask();
561f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        fAACache.getLastBound(resultBounds);
562bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina        return true;
5634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com    }
5648182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com
565b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    this->setupCache(clipIn, intBounds);
566b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
5678dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    *resultBounds = intBounds;
5689853ccef19c200be93a6211f32589fa82a53067cjoshualitt    return false;
569e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com}
5708dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
571b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
5724c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com// Create a 8-bit clip mask in alpha
5737b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.combool GrClipMaskManager::createAlphaClipMask(GrGpu* gpu,
5747b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com                                            const GrClip& clipIn,
575b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                            GrTexture** result,
576fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org                                            GrIRect *resultBounds) {
577b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
578b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
579b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        return true;
580b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    }
581b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
582fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org    GrTexture* accum = fAACache.getLastMask();
583b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    if (NULL == accum) {
584b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        fClipMaskInAlpha = false;
585b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        fAACache.reset();
586b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        return false;
587427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon    }
588427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon
589427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon    GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
590427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon    GrDrawState* drawState = gpu->drawState();
591427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon
592427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon    GrDrawTarget::AutoGeometryPush agp(gpu);
593427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon
594a7aedfec9e28db36c97e49f11f2bc2e0eb624c30skia.committer@gmail.com    int count = clipIn.getElementCount();
595427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon
596b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
597329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt        // if we were able to trim down the size of the mask we need to
5989853ccef19c200be93a6211f32589fa82a53067cjoshualitt        // offset the paths & rects that will be used to compute it
5999853ccef19c200be93a6211f32589fa82a53067cjoshualitt        GrMatrix m;
6009853ccef19c200be93a6211f32589fa82a53067cjoshualitt
6018dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
6024c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                       SkIntToScalar(-resultBounds->fTop));
603b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
604b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        drawState->setViewMatrix(m);
605b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    }
606b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
607b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    bool clearToInside;
608b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
609b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com    int start = process_initial_clip_elements(clipIn,
610b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                              *resultBounds,
611b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                              &clearToInside,
612b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                                              &startOp);
6138dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
6148dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    clear(gpu, accum, clearToInside ? 0xffffffff : 0x00000000);
6154c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
6167b7cdd147f5528865238e5ed98c79e6d319fde9bbsalomon@google.com    GrAutoScratchTexture temp;
6178dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
618e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    // walk through each clip element and perform its set op
619e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com    for (int c = start; c < count; ++c) {
6204c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
621f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com        SkRegion::Op op = (c == start) ? startOp : clipIn.getOp(c);
622b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
6238dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        if (SkRegion::kReplace_Op == op) {
6248dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // TODO: replace is actually a lot faster then intersection
6258fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            // for this path - refactor the stencil path so it can handle
626b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            // replace ops and alter GrClip to allow them through
627b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
6288dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // clear the accumulator and draw the new object directly into it
6299853ccef19c200be93a6211f32589fa82a53067cjoshualitt            clear(gpu, accum, 0x00000000);
630427cf28861867c0ea9aafca3a23878ec4068ad99bsalomon
631b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            setup_boolean_blendcoeffs(drawState, op);
632b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            this->drawClipShape(gpu, accum, clipIn, c);
633b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
634b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com        } else if (SkRegion::kReverseDifference_Op == op ||
6358dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                   SkRegion::kIntersect_Op == op) {
6368dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // there is no point in intersecting a screen filling rectangle.
6378fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt            if (SkRegion::kIntersect_Op == op &&
6388dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                kRect_ClipType == clipIn.getElementType(c) &&
639b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                contains(clipIn.getRect(c), *resultBounds)) {
640b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                continue;
641b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            }
642b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com
643b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            getTemp(*resultBounds, &temp);
644b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            if (NULL == temp.texture()) {
645b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fClipMaskInAlpha = false;
646b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com                fAACache.reset();
6478dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                return false;
6488750924a1470e8215b2a344155259b93062d3fa2egdaniel            }
6498dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
6508059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            // clear the temp target & draw into it
651b68addd39f3e7183facc70374a133e7a6fb603c5bsalomon@google.com            clear(gpu, temp.texture(), 0x00000000);
652f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
6538dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            setup_boolean_blendcoeffs(drawState, SkRegion::kReplace_Op);
6549853ccef19c200be93a6211f32589fa82a53067cjoshualitt            this->drawClipShape(gpu, temp.texture(), clipIn, c);
655e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
6568dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // TODO: rather than adding these two translations here
6578750924a1470e8215b2a344155259b93062d3fa2egdaniel            // compute the bounding box needed to render the texture
6588dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // into temp
659f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
660f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com                GrMatrix m;
661f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
662c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com                m.setTranslate(SkIntToScalar(resultBounds->fLeft),
6634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                               SkIntToScalar(resultBounds->fTop));
6641e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6651e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                drawState->preConcatViewMatrix(m);
666f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com            }
667fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
668f8d904a7eed435b9de68fd2eef6d7f3c59fcc9ccrobertphillips@google.com            // Now draw into the accumulator using the real operation
6699853ccef19c200be93a6211f32589fa82a53067cjoshualitt            // and the temp buffer as a texture
6709853ccef19c200be93a6211f32589fa82a53067cjoshualitt            setup_boolean_blendcoeffs(drawState, op);
671bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina            this->drawTexture(gpu, accum, temp.texture());
672bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina
6734c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            if (0 != resultBounds->fTop || 0 != resultBounds->fLeft) {
6744c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                GrMatrix m;
675f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org
67649f085dddff10473b6ebf832a974288300224e60bsalomon                m.setTranslate(SkIntToScalar(-resultBounds->fLeft),
6771e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                               SkIntToScalar(-resultBounds->fTop));
6786bc1b5fab8554a9cb643277b4867965dd4535cd6bsalomon
6791e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                drawState->preConcatViewMatrix(m);
6801e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
6811e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
6821e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        } else {
683d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            // all the remaining ops can just be directly draw into
684d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org            // the accumulation buffer
685137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            setup_boolean_blendcoeffs(drawState, op);
686137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com            this->drawClipShape(gpu, accum, clipIn, c);
687137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com        }
688137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com    }
689137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com
6908059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt    *result = accum;
6918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt
6921e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    return true;
6939f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com}
6949f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com
6959f13174da5295e88d447f29740318003b9cec9c3bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
696329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt// Create a 1-bit clip mask in the stencil buffer
6971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.combool GrClipMaskManager::createStencilClipMask(GrGpu* gpu,
6981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                              const GrClip& clipIn,
6994c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                              const GrRect& bounds,
7001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                              ScissoringSettings* scissorSettings) {
7011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
702329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt    GrAssert(fClipMaskInStencil);
703329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt
704329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt    GrDrawState* drawState = gpu->drawState();
7051e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrAssert(drawState->isClipState());
7061e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com    GrRenderTarget* rt = drawState->getRenderTarget();
708bf54e49e30cdc92f9ce3f336cc48cf6b236ddeabtfarina    GrAssert(NULL != rt);
7094c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
7109853ccef19c200be93a6211f32589fa82a53067cjoshualitt    // TODO: dynamically attach a SB when needed.
7118dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
7128dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    if (NULL == stencilBuffer) {
713080e673b10ac607305f140ddb245e140ccde40c6egdaniel        return false;
7148dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    }
7159853ccef19c200be93a6211f32589fa82a53067cjoshualitt
716ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com    if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
717ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com
7188dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel        stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
719ded4f4b163f5aa19c22c871178c55ecb34623846bsalomon@google.com
7201e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // we set the current clip to the bounds so that our recursive
7219853ccef19c200be93a6211f32589fa82a53067cjoshualitt        // draws are scissored to them. We use the copy of the complex clip
7229853ccef19c200be93a6211f32589fa82a53067cjoshualitt        // we just stashed on the SB to render from. We set it back after
7239853ccef19c200be93a6211f32589fa82a53067cjoshualitt        // we finish drawing it into the stencil.
7249853ccef19c200be93a6211f32589fa82a53067cjoshualitt        const GrClip& clipCopy = stencilBuffer->getLastClip();
72545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com        gpu->setClip(GrClip(bounds));
72645a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com
72745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com        GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
7281e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        drawState = gpu->drawState();
7295f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        drawState->setRenderTarget(rt);
7308182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        GrDrawTarget::AutoGeometryPush agp(gpu);
731f294b773f0b2b9f05eb45b52dd3cb4d97b96af06robertphillips@google.com
732e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com        gpu->disableScissor();
733e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org#if !VISUALIZE_COMPLEX_CLIP
7348182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
73545a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com#endif
7361e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7378afae61a57f87e4a50578effce6c428031499301tomhudson@google.com        int count = clipCopy.getElementCount();
738e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        int clipBit = stencilBuffer->bits();
739e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        SkASSERT((clipBit <= 16) &&
740e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                    "Ganesh only handles 16b or smaller stencil buffers");
741e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        clipBit = (1 << (clipBit-1));
742e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
7439853ccef19c200be93a6211f32589fa82a53067cjoshualitt        GrIRect rtRect = GrIRect::MakeWH(rt->width(), rt->height());
7448dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
7458059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        bool clearToInside;
7469853ccef19c200be93a6211f32589fa82a53067cjoshualitt        SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
74745a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com        int start = process_initial_clip_elements(clipCopy,
74845a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                    rtRect,
74945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com                                                    &clearToInside,
750e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com                                                    &startOp);
751e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com
7521e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
7531e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7541e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // walk through each clip element and perform its set op
7551e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        // with the existing clip.
7561e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com        for (int c = start; c < count; ++c) {
7571e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrPathFill fill;
7581e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            bool fillInverted;
75945a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            // enabled at bottom of loop
76045a15f551b5b3c6c747d8eaf6466b7d3b76a8faebsalomon@google.com            drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
7611e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7624c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            bool canRenderDirectToStencil; // can the clip element be drawn
7634c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                           // directly to the stencil buffer
7644c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                           // with a non-inverted fill rule
7654c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                           // without extra passes to
7664c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                                           // resolve in/out status.
7674c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
7684c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            SkRegion::Op op = (c == start) ? startOp : clipCopy.getOp(c);
7694c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com
7704c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com            GrPathRenderer* pr = NULL;
7711e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            const SkPath* clipPath = NULL;
7721e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            if (kRect_ClipType == clipCopy.getElementType(c)) {
7731e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                canRenderDirectToStencil = true;
7741e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = kEvenOdd_PathFill;
7754c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                fillInverted = false;
7764c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // there is no point in intersecting a screen filling
7774c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                // rectangle.
7784c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                if (SkRegion::kIntersect_Op == op &&
7794c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    contains(clipCopy.getRect(c), rtRect)) {
7804c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    continue;
7818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                }
7828dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            } else {
7838dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                fill = clipCopy.getPathFill(c);
7848059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                fillInverted = GrIsFillInverted(fill);
7851e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                fill = GrNonInvertedFill(fill);
786e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org                clipPath = &clipCopy.getPath(c);
7879853ccef19c200be93a6211f32589fa82a53067cjoshualitt                pr = this->getContext()->getPathRenderer(*clipPath,
78819dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                                                         fill, gpu, false,
7898dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                                         true);
7908dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                if (NULL == pr) {
7918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                    fClipMaskInStencil = false;
79219dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                    gpu->setClip(clipCopy);     // restore to the original
7938dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                    return false;
7948dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                }
79519dd017a6256be636ccb550752bb563c4e7caeb5commit-bot@chromium.org                canRenderDirectToStencil =
7961e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    !pr->requiresStencilPass(*clipPath, fill, gpu);
7971e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            }
7981e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
7991e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            int passes;
8001e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com            GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
8011e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com
8027a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt            bool canDrawDirectToClip; // Given the renderer, the element,
8031e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                        // fill rule, and set operation can
8048dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                        // we render the element directly to
8058dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                        // stencil bit used for clipping.
8069853ccef19c200be93a6211f32589fa82a53067cjoshualitt            canDrawDirectToClip =
8071e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GrStencilSettings::GetClipPasses(op,
8088182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                                                    canRenderDirectToStencil,
8098dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                                                    clipBit,
8102e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                                                    fillInverted,
8111e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                                                    &passes, stencilSettings);
8129853ccef19c200be93a6211f32589fa82a53067cjoshualitt
8138dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel            // draw the element to the client stencil bits if necessary
8148059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt            if (!canDrawDirectToClip) {
8151e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
8161e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    kIncClamp_StencilOp,
8174c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    kIncClamp_StencilOp,
8184c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com                    kAlways_StencilFunc,
8198dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel                    0xffff,
8202e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                    0x0000,
8211e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    0xffff);
8221e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                SET_RANDOM_COLOR
8231e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                if (kRect_ClipType == clipCopy.getElementType(c)) {
8241e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    *drawState->stencil() = gDrawToStencil;
825c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com                    gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
826f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                } else {
827c8f7f47afaf8f9471e6d111655c5610a8bd210a2bsalomon@google.com                    if (canRenderDirectToStencil) {
8287a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt                        *drawState->stencil() = gDrawToStencil;
8291e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
8301e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                    } else {
8311e945b7e708c633d4aed937ebfce57d52ba21d83robertphillips@google.com                        pr->drawPathToStencil(*clipPath, fill, gpu);
832411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    }
833411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                }
834fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            }
835411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
836411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            // now we modify the clip bit by rendering either the clip
837411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            // element directly or a bounding rect of the entire clip.
838411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
839411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            for (int p = 0; p < passes; ++p) {
840411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                *drawState->stencil() = stencilSettings[p];
841411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                if (canDrawDirectToClip) {
842411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    if (kRect_ClipType == clipCopy.getElementType(c)) {
843411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                        SET_RANDOM_COLOR
844411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                        gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
845411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    } else {
846411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                        SET_RANDOM_COLOR
847411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                        pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
848411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    }
849411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                } else {
850411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    SET_RANDOM_COLOR
851411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                    gpu->drawSimpleRect(bounds, NULL, 0);
852411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                }
853411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            }
854411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        }
855411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // restore clip
856411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        gpu->setClip(clipCopy);
857411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // recusive draws would have disabled this since they drew with
858411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        // the clip bounds as clip.
859411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com        fClipMaskInStencil = true;
860411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    }
861411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
862411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    return true;
863411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}
864411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
865411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.comnamespace {
866411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
867411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.comGrPathFill invert_fill(GrPathFill fill) {
868a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    static const GrPathFill gInvertedFillTable[] = {
869a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kInverseWinding_PathFill, // kWinding_PathFill
870a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kInverseEvenOdd_PathFill, // kEvenOdd_PathFill
871a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kWinding_PathFill,        // kInverseWinding_PathFill
872a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kEvenOdd_PathFill,        // kInverseEvenOdd_PathFill
873a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        kHairLine_PathFill,       // kHairLine_PathFill
874a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    };
875a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_ASSERT(0 == kWinding_PathFill);
876a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_ASSERT(1 == kEvenOdd_PathFill);
877a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_ASSERT(2 == kInverseWinding_PathFill);
878a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_ASSERT(3 == kInverseEvenOdd_PathFill);
879fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    GR_STATIC_ASSERT(4 == kHairLine_PathFill);
880a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GR_STATIC_ASSERT(5 == kPathFillCount);
881a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    return gInvertedFillTable[fill];
882a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com}
883a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
8848dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel}
8858dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
886a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com////////////////////////////////////////////////////////////////////////////////
887a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.combool GrClipMaskManager::createSoftwareClipMask(GrGpu* gpu,
888a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                               const GrClip& clipIn,
889a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                               GrTexture** result,
890a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                               GrIRect *resultBounds) {
891a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
892a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    if (this->clipMaskPreamble(gpu, clipIn, result, resultBounds)) {
893a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return true;
8949853ccef19c200be93a6211f32589fa82a53067cjoshualitt    }
895a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
896a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrTexture* accum = fAACache.getLastMask();
8978dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    if (NULL == accum) {
8987a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt        fClipMaskInAlpha = false;
899a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        fAACache.reset();
900a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        return false;
901a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    }
902a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
903a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrSWMaskHelper helper(this->getContext());
9048dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
905a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    helper.init(*resultBounds, NULL, false);
906a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
907a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    int count = clipIn.getElementCount();
9086bc1b5fab8554a9cb643277b4867965dd4535cd6bsalomon
9096bc1b5fab8554a9cb643277b4867965dd4535cd6bsalomon    bool clearToInside;
91049f085dddff10473b6ebf832a974288300224e60bsalomon    SkRegion::Op startOp = SkRegion::kReplace_Op; // suppress warning
911a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    int start = process_initial_clip_elements(clipIn,
912a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                              *resultBounds,
913a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                              &clearToInside,
914329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt                                              &startOp);
915329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt
9167a6184fdf717a1da0c6e1e37b942b17fdaa236d3joshualitt    helper.clear(clearToInside ? SK_ColorWHITE : 0x00000000);
9178dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel
9188dd688b7569df569a672a8a67b2db86a9d376cfcegdaniel    for (int i = start; i < count; ++i) {
919a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
920a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        SkRegion::Op op = (i == start) ? startOp : clipIn.getOp(i);
921a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
922a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (SkRegion::kIntersect_Op == op ||
923a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            SkRegion::kReverseDifference_Op == op) {
924f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org            // Intersect and reverse difference require modifying pixels
925411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            // outside of the geometry that is being "drawn". In both cases
926411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            // we erase all the pixels outside of the geometry but
927a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            // leave the pixels inside the geometry alone. For reverse
928a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            // difference we invert all the pixels before clearing the ones
929a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            // outside the geometry.
930411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com            if (SkRegion::kReverseDifference_Op == op) {
931a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                SkRect temp = SkRect::MakeLTRB(
932411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                       SkIntToScalar(resultBounds->left()),
933411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                       SkIntToScalar(resultBounds->top()),
934411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                                       SkIntToScalar(resultBounds->right()),
935a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                                       SkIntToScalar(resultBounds->bottom()));
936329bf4862e9d5e05363c2b071d8ca475a0ef1952joshualitt
937a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                // invert the entire scene
938a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                helper.draw(temp, SkRegion::kXOR_Op, false, SK_ColorWHITE);
939a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            }
940a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
941a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            if (kRect_ClipType == clipIn.getElementType(i)) {
942a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
943a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                // convert the rect to a path so we can invert the fill
944a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                SkPath temp;
945f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                temp.addRect(clipIn.getRect(i));
946a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
947a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                helper.draw(temp, SkRegion::kReplace_Op,
948a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            kInverseEvenOdd_PathFill, clipIn.getDoAA(i),
949a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            0x00000000);
950a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            } else {
951a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                GrAssert(kPath_ClipType == clipIn.getElementType(i));
952a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
953f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org                helper.draw(clipIn.getPath(i),
954a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            SkRegion::kReplace_Op,
955a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            invert_fill(clipIn.getPathFill(i)),
956a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            clipIn.getDoAA(i),
957a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                            0x00000000);
958a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            }
959a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
960a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            continue;
961a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
962a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
963a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // The other ops (union, xor, diff) only affect pixels inside
964a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        // the geometry so they can just be drawn normally
965a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        if (kRect_ClipType == clipIn.getElementType(i)) {
966a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
967a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            helper.draw(clipIn.getRect(i),
968a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        op,
969a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        clipIn.getDoAA(i), SK_ColorWHITE);
97088cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org
971a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        } else {
972a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            GrAssert(kPath_ClipType == clipIn.getElementType(i));
973a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
974a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com            helper.draw(clipIn.getPath(i),
975411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com                        op,
976fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                        clipIn.getPathFill(i),
977a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com                        clipIn.getDoAA(i), SK_ColorWHITE);
978a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com        }
979f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    }
980411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
981a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // Because we are using the scratch texture cache, "accum" may be
982a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // larger than expected and have some cruft in the areas we aren't using.
983411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com    // Clear it out.
984a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
985a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // TODO: need a simpler way to clear the texture - can we combine
986a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // the clear and the writePixels (inside toTexture)
987a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrDrawState* drawState = gpu->drawState();
988a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrAssert(NULL != drawState);
989a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    GrRenderTarget* temp = drawState->getRenderTarget();
990a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    clear(gpu, accum, 0x00000000);
991a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    // can't leave the accum bound as a rendertarget
992a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    drawState->setRenderTarget(temp);
993a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
994a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    helper.toTexture(accum);
995a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
996a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    *result = accum;
997a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com
998a320194e4242ef0e5e758aea896bfd52bcb3dac7bsalomon@google.com    return true;
999411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com}
1000411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com
1001411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.com////////////////////////////////////////////////////////////////////////////////
1002411dad0630913fc07f2412b4be17acfbfd914fbcbsalomon@google.comvoid GrClipMaskManager::releaseResources() {
1003d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org    fAACache.releaseResources();
10044c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com}
10054c2443e36fdc6c095b17e90baa4a2f26a6f00b08bsalomon@google.com