michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrPathRenderer_DEFINED michael@0: #define GrPathRenderer_DEFINED michael@0: michael@0: #include "GrDrawTarget.h" michael@0: #include "GrPathRendererChain.h" michael@0: #include "GrStencil.h" michael@0: michael@0: #include "SkDrawProcs.h" michael@0: #include "SkStrokeRec.h" michael@0: #include "SkTArray.h" michael@0: michael@0: class SkPath; michael@0: michael@0: struct GrPoint; michael@0: michael@0: /** michael@0: * Base class for drawing paths into a GrDrawTarget. michael@0: * michael@0: * Derived classes can use stages GrPaint::kTotalStages through GrDrawState::kNumStages-1. The michael@0: * stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and michael@0: * filter masks). michael@0: */ michael@0: class SK_API GrPathRenderer : public SkRefCnt { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(GrPathRenderer) michael@0: michael@0: /** michael@0: * This is called to install custom path renderers in every GrContext at create time. The michael@0: * default implementation in GrCreatePathRenderer_none.cpp does not add any additional michael@0: * renderers. Link against another implementation to install your own. The first added is the michael@0: * most preferred path renderer, second is second most preferred, etc. michael@0: * michael@0: * @param context the context that will use the path renderer michael@0: * @param prChain the chain to add path renderers to. michael@0: */ michael@0: static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain); michael@0: michael@0: michael@0: GrPathRenderer(); michael@0: michael@0: /** michael@0: * A caller may wish to use a path renderer to draw a path into the stencil buffer. However, michael@0: * the path renderer itself may require use of the stencil buffer. Also a path renderer may michael@0: * use a GrEffect coverage stage that sets coverage to zero to eliminate pixels that are covered michael@0: * by bounding geometry but outside the path. These exterior pixels would still be rendered into michael@0: * the stencil. michael@0: * michael@0: * A GrPathRenderer can provide three levels of support for stenciling paths: michael@0: * 1) kNoRestriction: This is the most general. The caller sets up the GrDrawState on the target michael@0: * and calls drawPath(). The path is rendered exactly as the draw state michael@0: * indicates including support for simultaneous color and stenciling with michael@0: * arbitrary stenciling rules. Pixels partially covered by AA paths are michael@0: * affected by the stencil settings. michael@0: * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil michael@0: * simultaneously. The path renderer does support the stencilPath() function michael@0: * which performs no color writes and writes a non-zero stencil value to pixels michael@0: * covered by the path. michael@0: * 3) kNoSupport: This path renderer cannot be used to stencil the path. michael@0: */ michael@0: typedef GrPathRendererChain::StencilSupport StencilSupport; michael@0: static const StencilSupport kNoSupport_StencilSupport = michael@0: GrPathRendererChain::kNoSupport_StencilSupport; michael@0: static const StencilSupport kStencilOnly_StencilSupport = michael@0: GrPathRendererChain::kStencilOnly_StencilSupport; michael@0: static const StencilSupport kNoRestriction_StencilSupport = michael@0: GrPathRendererChain::kNoRestriction_StencilSupport; michael@0: michael@0: /** michael@0: * This function is to get the stencil support for a particular path. The path's fill must michael@0: * not be an inverse type. michael@0: * michael@0: * @param target target that the path will be rendered to michael@0: * @param path the path that will be drawn michael@0: * @param stroke the stroke information (width, join, cap). michael@0: */ michael@0: StencilSupport getStencilSupport(const SkPath& path, michael@0: const SkStrokeRec& stroke, michael@0: const GrDrawTarget* target) const { michael@0: SkASSERT(!path.isInverseFillType()); michael@0: return this->onGetStencilSupport(path, stroke, target); michael@0: } michael@0: michael@0: /** michael@0: * Returns true if this path renderer is able to render the path. Returning false allows the michael@0: * caller to fallback to another path renderer This function is called when searching for a path michael@0: * renderer capable of rendering a path. michael@0: * michael@0: * @param path The path to draw michael@0: * @param stroke The stroke information (width, join, cap) michael@0: * @param target The target that the path will be rendered to michael@0: * @param antiAlias True if anti-aliasing is required. michael@0: * michael@0: * @return true if the path can be drawn by this object, false otherwise. michael@0: */ michael@0: virtual bool canDrawPath(const SkPath& path, michael@0: const SkStrokeRec& rec, michael@0: const GrDrawTarget* target, michael@0: bool antiAlias) const = 0; michael@0: /** michael@0: * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then michael@0: * the subclass must respect the stencil settings of the target's draw state. michael@0: * michael@0: * @param path the path to draw. michael@0: * @param stroke the stroke information (width, join, cap) michael@0: * @param target target that the path will be rendered to michael@0: * @param antiAlias true if anti-aliasing is required. michael@0: */ michael@0: bool drawPath(const SkPath& path, michael@0: const SkStrokeRec& stroke, michael@0: GrDrawTarget* target, michael@0: bool antiAlias) { michael@0: SkASSERT(!path.isEmpty()); michael@0: SkASSERT(this->canDrawPath(path, stroke, target, antiAlias)); michael@0: SkASSERT(target->drawState()->getStencil().isDisabled() || michael@0: kNoRestriction_StencilSupport == this->getStencilSupport(path, stroke, target)); michael@0: return this->onDrawPath(path, stroke, target, antiAlias); michael@0: } michael@0: michael@0: /** michael@0: * Draws the path to the stencil buffer. Assume the writable stencil bits are already michael@0: * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards. michael@0: * michael@0: * @param path the path to draw. michael@0: * @param stroke the stroke information (width, join, cap) michael@0: * @param target target that the path will be rendered to michael@0: */ michael@0: void stencilPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target) { michael@0: SkASSERT(!path.isEmpty()); michael@0: SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(path, stroke, target)); michael@0: this->onStencilPath(path, stroke, target); michael@0: } michael@0: michael@0: // Helper for determining if we can treat a thin stroke as a hairline w/ coverage. michael@0: // If we can, we draw lots faster (raster device does this same test). michael@0: static bool IsStrokeHairlineOrEquivalent(const SkStrokeRec& stroke, const SkMatrix& matrix, michael@0: SkScalar* outCoverage) { michael@0: if (stroke.isHairlineStyle()) { michael@0: if (NULL != outCoverage) { michael@0: *outCoverage = SK_Scalar1; michael@0: } michael@0: return true; michael@0: } michael@0: return stroke.getStyle() == SkStrokeRec::kStroke_Style && michael@0: SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage); michael@0: } michael@0: michael@0: protected: michael@0: /** michael@0: * Subclass overrides if it has any limitations of stenciling support. michael@0: */ michael@0: virtual StencilSupport onGetStencilSupport(const SkPath&, michael@0: const SkStrokeRec&, michael@0: const GrDrawTarget*) const { michael@0: return kNoRestriction_StencilSupport; michael@0: } michael@0: michael@0: /** michael@0: * Subclass implementation of drawPath() michael@0: */ michael@0: virtual bool onDrawPath(const SkPath& path, michael@0: const SkStrokeRec& stroke, michael@0: GrDrawTarget* target, michael@0: bool antiAlias) = 0; michael@0: michael@0: /** michael@0: * Subclass implementation of stencilPath(). Subclass must override iff it ever returns michael@0: * kStencilOnly in onGetStencilSupport(). michael@0: */ michael@0: virtual void onStencilPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target) { michael@0: GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); michael@0: GrDrawState* drawState = target->drawState(); michael@0: GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil, michael@0: kReplace_StencilOp, michael@0: kReplace_StencilOp, michael@0: kAlways_StencilFunc, michael@0: 0xffff, michael@0: 0xffff, michael@0: 0xffff); michael@0: drawState->setStencil(kIncrementStencil); michael@0: drawState->enableState(GrDrawState::kNoColorWrites_StateBit); michael@0: this->drawPath(path, stroke, target, false); michael@0: } michael@0: michael@0: // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set michael@0: // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize. michael@0: static void GetPathDevBounds(const SkPath& path, michael@0: int devW, michael@0: int devH, michael@0: const SkMatrix& matrix, michael@0: SkRect* bounds); michael@0: michael@0: // Helper version that gets the dev width and height from a GrSurface. michael@0: static void GetPathDevBounds(const SkPath& path, michael@0: const GrSurface* device, michael@0: const SkMatrix& matrix, michael@0: SkRect* bounds) { michael@0: GetPathDevBounds(path, device->width(), device->height(), matrix, bounds); michael@0: } michael@0: michael@0: private: michael@0: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: #endif