Add way to determine at link time what path renderer will be used.
Added mechanism for a custom path renderer to punt and fallback to default path renderer



git-svn-id: http://skia.googlecode.com/svn/trunk@1005 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index a20c6be..f6009f5 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -63,7 +63,7 @@
     delete fDrawBuffer;
     delete fDrawBufferVBAllocPool;
     delete fDrawBufferIBAllocPool;
-    delete fPathRenderer;
+    GrSafeUnref(fCustomPathRenderer);
 }
 
 void GrContext::abandonAllTextures() {
@@ -546,7 +546,8 @@
     if (NULL != paint.getTexture()) {
         enabledStages |= 1;
     }
-    fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
+    GrPathRenderer* pr = getPathRenderer(target, path, fill);
+    pr->drawPath(target, enabledStages, path, fill, translate);
 }
 
 void GrContext::drawPath(const GrPaint& paint,
@@ -738,9 +739,16 @@
     fGpu->printStats();
 }
 
-GrContext::GrContext(GrGpu* gpu) {
+GrContext::GrContext(GrGpu* gpu) :
+    fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
+                         gpu->supportsStencilWrapOps()) {
+
     fGpu = gpu;
     fGpu->ref();
+    
+    fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
+    fGpu->setClipPathRenderer(fCustomPathRenderer);
+
     fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
                                        MAX_TEXTURE_CACHE_BYTES);
     fFontCache = new GrFontCache(fGpu);
@@ -768,8 +776,6 @@
 #if BATCH_RECT_TO_RECT
     fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
 #endif
-    fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsTwoSidedStencil(),
-                                              fGpu->supportsStencilWrapOps());
 }
 
 bool GrContext::finalizeTextureKey(GrTextureKey* key,
@@ -808,3 +814,15 @@
 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
     return fGpu->getQuadIndexBuffer();
 }
+
+GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
+                                           GrPathIter* path,
+                                           GrPathFill fill) {
+    if (NULL != fCustomPathRenderer && 
+        fCustomPathRenderer->canDrawPath(target, path, fill)) {
+        return fCustomPathRenderer;
+    } else {
+        GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
+        return &fDefaultPathRenderer;
+    }
+}
diff --git a/gpu/src/GrCreatePathRenderer_none.cpp b/gpu/src/GrCreatePathRenderer_none.cpp
new file mode 100644
index 0000000..fafecff
--- /dev/null
+++ b/gpu/src/GrCreatePathRenderer_none.cpp
@@ -0,0 +1,20 @@
+/*
+    Copyright 2011 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "GrPathRenderer.h"
+
+
+GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return NULL; }
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index d60287b..4b52fd8 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -78,7 +78,8 @@
                  fIndexPool(NULL),
                  fQuadIndexBuffer(NULL),
                  fUnitSquareVertexBuffer(NULL),
-                 fPathRenderer(NULL),
+                 fDefaultPathRenderer(NULL),
+                 fClientPathRenderer(NULL),
                  fContextIsDirty(true),
                  fVertexPoolInUse(false),
                  fIndexPoolInUse(false) {
@@ -93,7 +94,8 @@
     GrSafeUnref(fUnitSquareVertexBuffer);
     delete fVertexPool;
     delete fIndexPool;
-    delete fPathRenderer;
+    GrSafeUnref(fClientPathRenderer);
+    GrSafeUnref(fDefaultPathRenderer);
 }
 
 void GrGpu::resetContext() {
@@ -418,15 +420,20 @@
                                                // directly to the stencil buffer
                                                // with a non-inverted fill rule
                                                // without extra passes to
-                                               // resolve in/out status. 
+                                               // resolve in/out status.
+
+                GrPathRenderer* pr = NULL;
+                GrPath::Iter pathIter;
                 if (kRect_ClipType == clip.getElementType(c)) {
                     canRenderDirectToStencil = true;
                     fill = kEvenOdd_PathFill;
                 } else {
                     fill = clip.getPathFill(c);
-                    GrPathRenderer* pr = this->getPathRenderer();
+                    const GrPath& path = clip.getPath(c);
+                    pathIter.reset(path);
+                    pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
                     canRenderDirectToStencil = 
-                        !pr->requiresStencilPass(this, clip.getPath(c), 
+                        !pr->requiresStencilPass(this, &pathIter,
                                                  NonInvertedFill(fill));
                 }
 
@@ -462,14 +469,14 @@
                     } else {
                         if (canRenderDirectToStencil) {
                             this->setStencil(gDrawToStencil);
-                            getPathRenderer()->drawPath(this, 0, 
-                                                        clip.getPath(c),
-                                                        NonInvertedFill(fill),
-                                                        NULL);
+                            pr->drawPath(this, 0, 
+                                         &pathIter,
+                                         NonInvertedFill(fill),
+                                         NULL);
                         } else {
-                            getPathRenderer()->drawPathToStencil(this, clip.getPath(c),
-                                                                 NonInvertedFill(fill),
-                                                                 NULL);
+                            pr->drawPathToStencil(this, &pathIter,
+                                                  NonInvertedFill(fill),
+                                                  NULL);
                         }
                     }
                 }
@@ -486,9 +493,7 @@
                         } else {
                             SET_RANDOM_COLOR
                             GrAssert(!IsFillInverted(fill));
-                            getPathRenderer()->drawPath(this, 0,
-                                                        clip.getPath(c),
-                                                        fill, NULL);
+                            pr->drawPath(this, 0, &pathIter, fill, NULL);
                         }
                     } else {
                         SET_RANDOM_COLOR
@@ -512,6 +517,23 @@
     return true;
 }
 
+GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
+                                           GrPathFill fill) {
+    if (NULL != fClientPathRenderer && 
+        fClientPathRenderer->canDrawPath(this, path, fill)) {
+            return fClientPathRenderer;
+    } else {
+        if (NULL == fDefaultPathRenderer) {
+            fDefaultPathRenderer = 
+                new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
+                                          this->supportsStencilWrapOps());
+        }
+        GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
+        return fDefaultPathRenderer;
+    }
+}
+
+
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrGpu::drawIndexed(GrPrimitiveType type,
@@ -665,16 +687,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrPathRenderer* GrGpu::getPathRenderer() {
-    if (NULL == fPathRenderer) {
-        fPathRenderer = new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
-                                                  this->supportsStencilWrapOps());
-    }
-    return fPathRenderer;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 const GrGpu::Stats& GrGpu::getStats() const {
     return fStats;
 }
diff --git a/gpu/src/GrPathRenderer.h b/gpu/src/GrPathRenderer.h
deleted file mode 100644
index 30bdb5a..0000000
--- a/gpu/src/GrPathRenderer.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-    Copyright 2011 Google Inc.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
- */
-
-#ifndef GrPathRenderer_DEFINED
-#define GrPathRenderer_DEFINED
-
-#include "GrDrawTarget.h"
-
-class GrPathIter;
-struct GrPoint;
-
-/**
- *  Base class for drawing paths into a GrDrawTarget.
- */
-class GrPathRenderer {
-public:
-    virtual ~GrPathRenderer() { };
-
-    /**
-     * Draws a path into the draw target. The target will already have its draw
-     * state configured for the draw.
-     * @param target                the target to draw into.
-     * @param stages                indicates which stages the are already
-     *                              in use. All enabled stages expect positions
-     *                              as texture coordinates. The path renderer
-     *                              use the remaining stages for its path
-     *                              filling algorithm.
-     * @param path                  the path to draw.
-     * @param fill                  the fill rule to apply.
-     * @param translate             optional additional translation to apply to
-     *                              the path. NULL means (0,0).
-     */
-    virtual void drawPath(GrDrawTarget* target,
-                          GrDrawTarget::StageBitfield stages,
-                          GrPathIter* path,
-                          GrPathFill fill,
-                          const GrPoint* translate) = 0;
-
-    void drawPath(GrDrawTarget* target,
-                  GrDrawTarget::StageBitfield stages,
-                  const GrPath& path,
-                  GrPathFill fill,
-                  const GrPoint* translate) {
-            GrPath::Iter iter(path);
-            this->drawPath(target, stages, &iter, fill, translate);
-    }
-
-    /**
-     * For complex clips Gr uses the stencil buffer. The path renderer must be
-     * able to render paths into the stencil buffer. However, the path renderer
-     * itself may require the stencil buffer to resolve the path fill rule. This
-     * function queries whether the path render needs its own stencil
-     * pass. If this returns false then drawPath() should not modify the
-     * the target's stencil settings but use those already set on target.
-     *
-     * @param target target that the path will be rendered to
-     * @param path   the path that will be drawn
-     * @param fill   the fill rule that will be used, will never be an inverse
-     *               rule.
-     *
-     * @return false if this path renderer can generate interior-only fragments
-     *         without changing the stencil settings on the target. If it
-     *         returns true the drawPathToStencil will be used when rendering
-     *         clips.
-     */
-    virtual bool requiresStencilPass(const GrDrawTarget* target,
-                                     GrPathIter* path,
-                                     GrPathFill fill) const { return false; }
-
-    bool requiresStencilPass(const GrDrawTarget* target,
-                             const GrPath& path,
-                             GrPathFill fill) const {
-        GrPath::Iter iter(path);
-        return requiresStencilPass(target, &iter, fill);
-    }
-
-    /**
-     * Draws a path to the stencil buffer. Assume the writable stencil bits
-     * are already initialized to zero. Fill will always be either
-     * kWinding_PathFill or kEvenOdd_PathFill.
-     *
-     * Only called if requiresStencilPass returns true for the same combo of
-     * target, path, and fill (or inverse of the fill).
-     *
-     * The default implementation assumes the path filling algorithm doesn't
-     * require a separate stencil pass and so crashes.
-     *
-     *
-     * @param target                the target to draw into.
-     * @param path                  the path to draw.
-     * @param fill                  the fill rule to apply.
-     * @param translate             optional additional translation to apply to
-     *                              the path. NULL means (0,0).
-     */
-    virtual void drawPathToStencil(GrDrawTarget* target,
-                                   GrPathIter* path,
-                                   GrPathFill fill,
-                                   const GrPoint* translate) {
-        GrCrash("Unexpected call to drawPathToStencil.");
-    }
-
-    void drawPathToStencil(GrDrawTarget* target,
-                           const GrPath& path,
-                           GrPathFill fill,
-                           const GrPoint* translate) {
-        GrPath::Iter iter(path);
-        this->drawPathToStencil(target, &iter, fill, translate);
-    }
-};
-
-/**
- *  Subclass that renders the path using the stencil buffer to resolve fill
- *  rules (e.g. winding, even-odd)
- */
-class GrDefaultPathRenderer : public GrPathRenderer {
-public:
-    GrDefaultPathRenderer(bool separateStencilSupport,
-                          bool stencilWrapOpsSupport);
-
-    virtual void drawPath(GrDrawTarget* target,
-                          GrDrawTarget::StageBitfield stages,
-                          GrPathIter* path,
-                          GrPathFill fill,
-                          const GrPoint* translate);
-    virtual bool requiresStencilPass(const GrDrawTarget* target,
-                                     GrPathIter* path,
-                                     GrPathFill fill) const;
-    virtual void drawPathToStencil(GrDrawTarget* target,
-                                   GrPathIter* path,
-                                   GrPathFill fill,
-                                   const GrPoint* translate);
-private:
-
-    void drawPathHelper(GrDrawTarget* target,
-                        GrDrawTarget::StageBitfield stages,
-                        GrPathIter* path,
-                        GrPathFill fill,
-                        const GrPoint* translate,
-                        bool stencilOnly);
-
-    bool    fSeparateStencil;
-    bool    fStencilWrapOps;
-};
-
-#endif
diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk
index 8aeddc9..89ef5f1 100644
--- a/gpu/src/gr_files.mk
+++ b/gpu/src/gr_files.mk
@@ -3,6 +3,7 @@
     GrAtlas.cpp \
     GrClip.cpp \
     GrContext.cpp \
+    GrCreatePathRenderer_none.cpp \
     GrDrawTarget.cpp \
     GrGLIndexBuffer.cpp	\
     GrGLInterface.cpp \