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
This commit is contained in:
parent
b123c9d997
commit
dfe75bcf98
@ -21,13 +21,13 @@
|
||||
#include "GrGpu.h"
|
||||
#include "GrTextureCache.h"
|
||||
#include "GrPaint.h"
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
class GrFontCache;
|
||||
class GrPathIter;
|
||||
class GrVertexBufferAllocPool;
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrInOrderDrawBuffer;
|
||||
class GrPathRenderer;
|
||||
|
||||
class GR_API GrContext : public GrRefCnt {
|
||||
public:
|
||||
@ -479,13 +479,16 @@ private:
|
||||
GrGpu* fGpu;
|
||||
GrTextureCache* fTextureCache;
|
||||
GrFontCache* fFontCache;
|
||||
GrPathRenderer* fPathRenderer;
|
||||
|
||||
GrPathRenderer* fCustomPathRenderer;
|
||||
GrDefaultPathRenderer fDefaultPathRenderer;
|
||||
|
||||
GrVertexBufferAllocPool* fDrawBufferVBAllocPool;
|
||||
GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
|
||||
GrInOrderDrawBuffer* fDrawBuffer;
|
||||
|
||||
GrContext(GrGpu* gpu);
|
||||
|
||||
void flushDrawBuffer();
|
||||
|
||||
static void SetPaint(const GrPaint& paint, GrDrawTarget* target);
|
||||
@ -495,6 +498,11 @@ private:
|
||||
GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
|
||||
|
||||
void drawClipIntoStencil();
|
||||
|
||||
GrPathRenderer* getPathRenderer(const GrDrawTarget* target,
|
||||
GrPathIter* path,
|
||||
GrPathFill fill);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,10 @@
|
||||
#include "GrRefCnt.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
class GrVertexBufferAllocPool;
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrPathRenderer;
|
||||
|
||||
class GrGpu : public GrDrawTarget {
|
||||
|
||||
@ -307,6 +307,14 @@ public:
|
||||
int startVertex,
|
||||
int vertexCount);
|
||||
|
||||
/**
|
||||
* Installs a path renderer that will be used to draw paths that are
|
||||
* part of the clip.
|
||||
*/
|
||||
void setClipPathRenderer(GrPathRenderer* pathRenderer) {
|
||||
GrSafeAssign(fClientPathRenderer, pathRenderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index buffer that can be used to render quads.
|
||||
* Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
|
||||
@ -495,7 +503,9 @@ private:
|
||||
void prepareVertexPool();
|
||||
void prepareIndexPool();
|
||||
|
||||
GrPathRenderer* getPathRenderer();
|
||||
// determines the path renderer used to draw a clip path element.
|
||||
GrPathRenderer* getClipPathRenderer(GrPathIter* path,
|
||||
GrPathFill fill);
|
||||
|
||||
void handleDirtyContext() {
|
||||
if (fContextIsDirty) {
|
||||
@ -514,7 +524,8 @@ private:
|
||||
mutable GrVertexBuffer* fUnitSquareVertexBuffer; // mutable so it can be
|
||||
// created on-demand
|
||||
|
||||
GrPathRenderer* fPathRenderer;
|
||||
GrDefaultPathRenderer* fDefaultPathRenderer;
|
||||
GrPathRenderer* fClientPathRenderer;
|
||||
|
||||
bool fContextIsDirty;
|
||||
|
||||
|
319
gpu/include/GrPathRenderer.h
Normal file
319
gpu/include/GrPathRenderer.h
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
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 GrRefCnt {
|
||||
public:
|
||||
/**
|
||||
* Returns true if this path renderer is able to render the path.
|
||||
* Returning false allows the caller to fallback to another path renderer.
|
||||
*
|
||||
* @param target The target to draw into
|
||||
* @param path The path to draw
|
||||
* @param fill The fill rule to use
|
||||
*
|
||||
* @return true if the path can be drawn by this object, false otherwise.
|
||||
*/
|
||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||
GrPathIter* path,
|
||||
GrPathFill fill) const = 0;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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. Never called with an inverse 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.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called to install a custom path renderer in every GrContext at
|
||||
* create time. The default implementation in GrCreatePathRenderer_none.cpp
|
||||
* returns NULL. Link against another implementation to install your own.
|
||||
*/
|
||||
static GrPathRenderer* CreatePathRenderer();
|
||||
|
||||
private:
|
||||
|
||||
typedef GrRefCnt INHERITED;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 bool canDrawPath(const GrDrawTarget* target,
|
||||
GrPathIter* path,
|
||||
GrPathFill fill) const { return true; }
|
||||
|
||||
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;
|
||||
|
||||
typedef GrPathRenderer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
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 GrRefCnt {
|
||||
public:
|
||||
/**
|
||||
* Returns true if this path renderer is able to render the path.
|
||||
* Returning false allows the caller to fallback to another path renderer.
|
||||
*
|
||||
* @param target The target to draw into
|
||||
* @param path The path to draw
|
||||
* @param fill The fill rule to use
|
||||
*
|
||||
* @return true if the path can be drawn by this object, false otherwise.
|
||||
*/
|
||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||
GrPathIter* path,
|
||||
GrPathFill fill) const = 0;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* 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. Never called with an inverse 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.");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef GrRefCnt INHERITED;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 bool canDrawPath(const GrDrawTarget* target,
|
||||
GrPathIter* path,
|
||||
GrPathFill fill) const { return true; }
|
||||
|
||||
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;
|
||||
|
||||
typedef GrPathRenderer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -93,7 +93,8 @@ static inline void GrSafeUnref(const GrRefCnt* obj) {
|
||||
* Assigns src to dst, checking for NULLs in each, and correctly incrementing
|
||||
* the reference count of src, and decrementing the reference count of dst
|
||||
*/
|
||||
static inline void GrSafeAssign(GrRefCnt*& dst, GrRefCnt* src) {
|
||||
template<typename T>
|
||||
static inline void GrSafeAssign(T*& dst, T* src) {
|
||||
if (src) {
|
||||
src->ref();
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ GrContext::~GrContext() {
|
||||
delete fDrawBuffer;
|
||||
delete fDrawBufferVBAllocPool;
|
||||
delete fDrawBufferIBAllocPool;
|
||||
delete fPathRenderer;
|
||||
GrSafeUnref(fCustomPathRenderer);
|
||||
}
|
||||
|
||||
void GrContext::abandonAllTextures() {
|
||||
@ -546,7 +546,8 @@ void GrContext::drawPath(const GrPaint& paint,
|
||||
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 @@ void GrContext::printStats() const {
|
||||
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 @@ GrContext::GrContext(GrGpu* gpu) {
|
||||
#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 @@ GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
20
gpu/src/GrCreatePathRenderer_none.cpp
Normal file
20
gpu/src/GrCreatePathRenderer_none.cpp
Normal file
@ -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; }
|
@ -78,7 +78,8 @@ GrGpu::GrGpu() : f8bitPaletteSupport(false),
|
||||
fIndexPool(NULL),
|
||||
fQuadIndexBuffer(NULL),
|
||||
fUnitSquareVertexBuffer(NULL),
|
||||
fPathRenderer(NULL),
|
||||
fDefaultPathRenderer(NULL),
|
||||
fClientPathRenderer(NULL),
|
||||
fContextIsDirty(true),
|
||||
fVertexPoolInUse(false),
|
||||
fIndexPoolInUse(false) {
|
||||
@ -93,7 +94,8 @@ GrGpu::~GrGpu() {
|
||||
GrSafeUnref(fUnitSquareVertexBuffer);
|
||||
delete fVertexPool;
|
||||
delete fIndexPool;
|
||||
delete fPathRenderer;
|
||||
GrSafeUnref(fClientPathRenderer);
|
||||
GrSafeUnref(fDefaultPathRenderer);
|
||||
}
|
||||
|
||||
void GrGpu::resetContext() {
|
||||
@ -418,15 +420,20 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
// 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 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
} 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 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
} 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 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
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 @@ void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrPathRenderer* GrGpu::getPathRenderer() {
|
||||
if (NULL == fPathRenderer) {
|
||||
fPathRenderer = new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
|
||||
this->supportsStencilWrapOps());
|
||||
}
|
||||
return fPathRenderer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const GrGpu::Stats& GrGpu::getStats() const {
|
||||
return fStats;
|
||||
}
|
||||
|
@ -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
|
@ -3,6 +3,7 @@ SOURCE := \
|
||||
GrAtlas.cpp \
|
||||
GrClip.cpp \
|
||||
GrContext.cpp \
|
||||
GrCreatePathRenderer_none.cpp \
|
||||
GrDrawTarget.cpp \
|
||||
GrGLIndexBuffer.cpp \
|
||||
GrGLInterface.cpp \
|
||||
|
@ -870,6 +870,7 @@
|
||||
'../gpu/include/GrPaint.h',
|
||||
'../gpu/include/GrPath.h',
|
||||
'../gpu/include/GrPathIter.h',
|
||||
'../gpu/include/GrPathRenderer.h',
|
||||
'../gpu/include/GrPathSink.h',
|
||||
'../gpu/include/GrPlotMgr.h',
|
||||
'../gpu/include/GrPoint.h',
|
||||
@ -902,6 +903,7 @@
|
||||
'../gpu/src/GrBufferAllocPool.h',
|
||||
'../gpu/src/GrClip.cpp',
|
||||
'../gpu/src/GrContext.cpp',
|
||||
'../gpu/src/GrCreatePathRenderer_none.cpp',
|
||||
'../gpu/src/GrDrawTarget.cpp',
|
||||
'../gpu/src/GrGLIndexBuffer.cpp',
|
||||
'../gpu/src/GrGLInterface.cpp',
|
||||
@ -921,7 +923,6 @@
|
||||
'../gpu/src/GrMemory.cpp',
|
||||
'../gpu/src/GrPath.cpp',
|
||||
'../gpu/src/GrPathRenderer.cpp',
|
||||
'../gpu/src/GrPathRenderer.h',
|
||||
'../gpu/src/GrPrintf_printf.cpp',
|
||||
'../gpu/src/GrRectanizer.cpp',
|
||||
'../gpu/src/GrRedBlackTree.h',
|
||||
|
@ -126,6 +126,7 @@
|
||||
<ClInclude Include="..\..\gpu\include\GrPaint.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPath.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPathIter.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPathRenderer.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPathSink.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPlotMgr.h" />
|
||||
<ClInclude Include="..\..\gpu\include\GrPoint.h" />
|
||||
@ -156,7 +157,6 @@
|
||||
<ClInclude Include="..\..\gpu\src\GrGpuGL.h" />
|
||||
<ClInclude Include="..\..\gpu\src\GrGpuGLFixed.h" />
|
||||
<ClInclude Include="..\..\gpu\src\GrGpuGLShaders2.h" />
|
||||
<ClInclude Include="..\..\gpu\src\GrPathRenderer.h" />
|
||||
<ClInclude Include="..\..\gpu\src\GrRedBlackTree.h" />
|
||||
<ClInclude Include="..\..\gpu\src\GrTextStrike_impl.h" />
|
||||
<ClInclude Include="..\..\include\gpu\SkGpuCanvas.h" />
|
||||
@ -220,6 +220,7 @@
|
||||
<ClCompile Include="..\..\gpu\src\GrBufferAllocPool.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrClip.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrContext.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrCreatePathRenderer_none.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrDrawTarget.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrGLIndexBuffer.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrGLInterface.cpp" />
|
||||
|
@ -460,6 +460,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\utils\win\skia_win.cpp" />
|
||||
<ClCompile Include="..\..\src\views\SkTouchGesture.cpp" />
|
||||
<ClCompile Include="..\..\gpu\src\GrCreatePathRenderer_none.cpp">
|
||||
<Filter>Gr\src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\gpu\include\FlingState.h" />
|
||||
@ -692,9 +695,6 @@
|
||||
<ClInclude Include="..\..\gpu\src\GrGpuGLShaders2.h">
|
||||
<Filter>Gr\src_headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\gpu\src\GrPathRenderer.h">
|
||||
<Filter>Gr\src_headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\gpu\src\GrTextStrike_impl.h">
|
||||
<Filter>Gr\src_headers</Filter>
|
||||
</ClInclude>
|
||||
@ -728,6 +728,9 @@
|
||||
<ClInclude Include="..\..\gpu\include\GrGLDefines.h">
|
||||
<Filter>Gr\include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\gpu\include\GrPathRenderer.h">
|
||||
<Filter>Gr\include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ReadMe.txt" />
|
||||
|
@ -96,9 +96,10 @@
|
||||
D542EAAD131C87E90065FC9D /* GrStencil.h in Headers */ = {isa = PBXBuildFile; fileRef = D542EAAC131C87E90065FC9D /* GrStencil.h */; };
|
||||
D5558AE3131EB9BB00C71009 /* GrStencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5558AE2131EB9BB00C71009 /* GrStencil.cpp */; };
|
||||
D58CAF9A12E7212100CB9277 /* GrGLUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D58CAF9812E7212100CB9277 /* GrGLUtil.cpp */; };
|
||||
D59BD3F4133BBB49003B546A /* GrPathRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = D59BD3F3133BBB49003B546A /* GrPathRenderer.h */; };
|
||||
D59BD413133BD384003B546A /* GrCreatePathRenderer_none.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D59BD412133BD384003B546A /* GrCreatePathRenderer_none.cpp */; };
|
||||
D5ED886F1313F92C00B98D64 /* GrRedBlackTree.h in Headers */ = {isa = PBXBuildFile; fileRef = D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */; };
|
||||
D5ED88EB13144FD600B98D64 /* GrPathRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */; };
|
||||
D5ED88EC13144FD600B98D64 /* GrPathRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = D5ED88EA13144FD600B98D64 /* GrPathRenderer.h */; };
|
||||
D5FAF20C130726C6001550A4 /* GrGeometryBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = D5FAF20B130726C6001550A4 /* GrGeometryBuffer.h */; };
|
||||
D5FAF22313072C27001550A4 /* GrBufferAllocPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5FAF22113072C27001550A4 /* GrBufferAllocPool.cpp */; };
|
||||
D5FAF22413072C27001550A4 /* GrBufferAllocPool.h in Headers */ = {isa = PBXBuildFile; fileRef = D5FAF22213072C27001550A4 /* GrBufferAllocPool.h */; };
|
||||
@ -195,9 +196,10 @@
|
||||
D542EAAC131C87E90065FC9D /* GrStencil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrStencil.h; path = ../../gpu/include/GrStencil.h; sourceTree = SOURCE_ROOT; };
|
||||
D5558AE2131EB9BB00C71009 /* GrStencil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrStencil.cpp; path = ../../gpu/src/GrStencil.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D58CAF9812E7212100CB9277 /* GrGLUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrGLUtil.cpp; path = ../../gpu/src/GrGLUtil.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D59BD3F3133BBB49003B546A /* GrPathRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrPathRenderer.h; path = ../../gpu/include/GrPathRenderer.h; sourceTree = SOURCE_ROOT; };
|
||||
D59BD412133BD384003B546A /* GrCreatePathRenderer_none.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrCreatePathRenderer_none.cpp; path = ../../gpu/src/GrCreatePathRenderer_none.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrRedBlackTree.h; path = ../../gpu/src/GrRedBlackTree.h; sourceTree = SOURCE_ROOT; };
|
||||
D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrPathRenderer.cpp; path = ../../gpu/src/GrPathRenderer.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D5ED88EA13144FD600B98D64 /* GrPathRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrPathRenderer.h; path = ../../gpu/src/GrPathRenderer.h; sourceTree = SOURCE_ROOT; };
|
||||
D5FAF20B130726C6001550A4 /* GrGeometryBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrGeometryBuffer.h; path = ../../gpu/include/GrGeometryBuffer.h; sourceTree = SOURCE_ROOT; };
|
||||
D5FAF22113072C27001550A4 /* GrBufferAllocPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GrBufferAllocPool.cpp; path = ../../gpu/src/GrBufferAllocPool.cpp; sourceTree = SOURCE_ROOT; };
|
||||
D5FAF22213072C27001550A4 /* GrBufferAllocPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GrBufferAllocPool.h; path = ../../gpu/src/GrBufferAllocPool.h; sourceTree = SOURCE_ROOT; };
|
||||
@ -217,6 +219,7 @@
|
||||
00115E3712C116B7008296FE /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D59BD3F3133BBB49003B546A /* GrPathRenderer.h */,
|
||||
7D6EBF5913330E8400AEAADD /* GrGLDefines.h */,
|
||||
7D66934D132ABDA7003AC2F5 /* GrGLPlatformIncludes.h */,
|
||||
7D66934B132ABD8F003AC2F5 /* GrGLInterface.h */,
|
||||
@ -294,6 +297,7 @@
|
||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D59BD412133BD384003B546A /* GrCreatePathRenderer_none.cpp */,
|
||||
7D669345132ABD5D003AC2F5 /* GrGLInterface.cpp */,
|
||||
D5ED886E1313F92C00B98D64 /* GrRedBlackTree.h */,
|
||||
D539049A12EA01E30025F3D6 /* GrContext_impl.h */,
|
||||
@ -320,7 +324,6 @@
|
||||
00115DEE12C1167A008296FE /* GrMatrix.cpp */,
|
||||
00115DEF12C1167A008296FE /* GrMemory.cpp */,
|
||||
00115DF012C1167A008296FE /* GrPath.cpp */,
|
||||
D5ED88EA13144FD600B98D64 /* GrPathRenderer.h */,
|
||||
D5ED88E913144FD600B98D64 /* GrPathRenderer.cpp */,
|
||||
00115DF412C1167A008296FE /* GrRectanizer_fifo.cpp */,
|
||||
00115DF512C1167A008296FE /* GrRectanizer.cpp */,
|
||||
@ -418,11 +421,11 @@
|
||||
D5FAF22413072C27001550A4 /* GrBufferAllocPool.h in Headers */,
|
||||
00216E5E130F0B03009A2160 /* GrGLIRect.h in Headers */,
|
||||
D5ED886F1313F92C00B98D64 /* GrRedBlackTree.h in Headers */,
|
||||
D5ED88EC13144FD600B98D64 /* GrPathRenderer.h in Headers */,
|
||||
D542EAAD131C87E90065FC9D /* GrStencil.h in Headers */,
|
||||
7D66934C132ABD8F003AC2F5 /* GrGLInterface.h in Headers */,
|
||||
7D66934E132ABDA7003AC2F5 /* GrGLPlatformIncludes.h in Headers */,
|
||||
7D6EBF5A13330E8400AEAADD /* GrGLDefines.h in Headers */,
|
||||
D59BD3F4133BBB49003B546A /* GrPathRenderer.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -503,6 +506,7 @@
|
||||
D5ED88EB13144FD600B98D64 /* GrPathRenderer.cpp in Sources */,
|
||||
D5558AE3131EB9BB00C71009 /* GrStencil.cpp in Sources */,
|
||||
7D669346132ABD5D003AC2F5 /* GrGLInterface.cpp in Sources */,
|
||||
D59BD413133BD384003B546A /* GrCreatePathRenderer_none.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user