LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/ops - GrDefaultPathRenderer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 326 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2011 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "GrDefaultPathRenderer.h"
       9             : 
      10             : #include "GrContext.h"
      11             : #include "GrDefaultGeoProcFactory.h"
      12             : #include "GrDrawOpTest.h"
      13             : #include "GrFixedClip.h"
      14             : #include "GrMesh.h"
      15             : #include "GrOpFlushState.h"
      16             : #include "GrPathUtils.h"
      17             : #include "GrPipelineBuilder.h"
      18             : #include "SkGeometry.h"
      19             : #include "SkString.h"
      20             : #include "SkStrokeRec.h"
      21             : #include "SkTLazy.h"
      22             : #include "SkTraceEvent.h"
      23             : 
      24             : #include "ops/GrMeshDrawOp.h"
      25             : #include "ops/GrRectOpFactory.h"
      26             : 
      27           0 : GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
      28           0 :                                              bool stencilWrapOpsSupport)
      29             :     : fSeparateStencil(separateStencilSupport)
      30           0 :     , fStencilWrapOps(stencilWrapOpsSupport) {
      31           0 : }
      32             : 
      33             : ////////////////////////////////////////////////////////////////////////////////
      34             : // Helpers for drawPath
      35             : 
      36             : #define STENCIL_OFF     0   // Always disable stencil (even when needed)
      37             : 
      38           0 : static inline bool single_pass_shape(const GrShape& shape) {
      39             : #if STENCIL_OFF
      40             :     return true;
      41             : #else
      42             :     // Inverse fill is always two pass.
      43           0 :     if (shape.inverseFilled()) {
      44           0 :         return false;
      45             :     }
      46             :     // This path renderer only accepts simple fill paths or stroke paths that are either hairline
      47             :     // or have a stroke width small enough to treat as hairline. Hairline paths are always single
      48             :     // pass. Filled paths are single pass if they're convex.
      49           0 :     if (shape.style().isSimpleFill()) {
      50           0 :         return shape.knownToBeConvex();
      51             :     }
      52           0 :     return true;
      53             : #endif
      54             : }
      55             : 
      56             : GrPathRenderer::StencilSupport
      57           0 : GrDefaultPathRenderer::onGetStencilSupport(const GrShape& shape) const {
      58           0 :     if (single_pass_shape(shape)) {
      59           0 :         return GrPathRenderer::kNoRestriction_StencilSupport;
      60             :     } else {
      61           0 :         return GrPathRenderer::kStencilOnly_StencilSupport;
      62             :     }
      63             : }
      64             : 
      65           0 : static inline void append_countour_edge_indices(bool hairLine,
      66             :                                                 uint16_t fanCenterIdx,
      67             :                                                 uint16_t edgeV0Idx,
      68             :                                                 uint16_t** indices) {
      69             :     // when drawing lines we're appending line segments along
      70             :     // the contour. When applying the other fill rules we're
      71             :     // drawing triangle fans around fanCenterIdx.
      72           0 :     if (!hairLine) {
      73           0 :         *((*indices)++) = fanCenterIdx;
      74             :     }
      75           0 :     *((*indices)++) = edgeV0Idx;
      76           0 :     *((*indices)++) = edgeV0Idx + 1;
      77           0 : }
      78             : 
      79           0 : static inline void add_quad(SkPoint** vert, const SkPoint* base, const SkPoint pts[],
      80             :                             SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol, bool indexed,
      81             :                             bool isHairline, uint16_t subpathIdxStart, int offset, uint16_t** idx) {
      82             :     // first pt of quad is the pt we ended on in previous step
      83           0 :     uint16_t firstQPtIdx = (uint16_t)(*vert - base) - 1 + offset;
      84             :     uint16_t numPts =  (uint16_t)
      85           0 :         GrPathUtils::generateQuadraticPoints(
      86           0 :             pts[0], pts[1], pts[2],
      87             :             srcSpaceTolSqd, vert,
      88           0 :             GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
      89           0 :     if (indexed) {
      90           0 :         for (uint16_t i = 0; i < numPts; ++i) {
      91           0 :             append_countour_edge_indices(isHairline, subpathIdxStart,
      92           0 :                                          firstQPtIdx + i, idx);
      93             :         }
      94             :     }
      95           0 : }
      96             : 
      97           0 : class DefaultPathOp final : public GrLegacyMeshDrawOp {
      98             : public:
      99           0 :     DEFINE_OP_CLASS_ID
     100             : 
     101           0 :     static std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color, const SkPath& path,
     102             :                                                     SkScalar tolerance, uint8_t coverage,
     103             :                                                     const SkMatrix& viewMatrix, bool isHairline,
     104             :                                                     const SkRect& devBounds) {
     105             :         return std::unique_ptr<GrLegacyMeshDrawOp>(new DefaultPathOp(
     106           0 :                 color, path, tolerance, coverage, viewMatrix, isHairline, devBounds));
     107             :     }
     108             : 
     109           0 :     const char* name() const override { return "DefaultPathOp"; }
     110             : 
     111           0 :     SkString dumpInfo() const override {
     112           0 :         SkString string;
     113           0 :         string.appendf("Color: 0x%08x Count: %d\n", fColor, fPaths.count());
     114           0 :         for (const auto& path : fPaths) {
     115           0 :             string.appendf("Tolerance: %.2f\n", path.fTolerance);
     116             :         }
     117           0 :         string.append(DumpPipelineInfo(*this->pipeline()));
     118           0 :         string.append(INHERITED::dumpInfo());
     119           0 :         return string;
     120             :     }
     121             : 
     122             : private:
     123           0 :     DefaultPathOp(GrColor color, const SkPath& path, SkScalar tolerance, uint8_t coverage,
     124             :                   const SkMatrix& viewMatrix, bool isHairline, const SkRect& devBounds)
     125           0 :             : INHERITED(ClassID())
     126             :             , fColor(color)
     127             :             , fCoverage(coverage)
     128             :             , fViewMatrix(viewMatrix)
     129           0 :             , fIsHairline(isHairline) {
     130           0 :         fPaths.emplace_back(PathData{path, tolerance});
     131             : 
     132           0 :         this->setBounds(devBounds, HasAABloat::kNo,
     133           0 :                         isHairline ? IsZeroArea::kYes : IsZeroArea::kNo);
     134           0 :     }
     135             : 
     136           0 :     void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
     137             :                                     GrProcessorAnalysisCoverage* coverage) const override {
     138           0 :         color->setToConstant(fColor);
     139           0 :         *coverage = this->coverage() == 0xff ? GrProcessorAnalysisCoverage::kNone
     140             :                                              : GrProcessorAnalysisCoverage::kSingleChannel;
     141           0 :     }
     142             : 
     143           0 :     void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
     144           0 :         optimizations.getOverrideColorIfSet(&fColor);
     145           0 :         fUsesLocalCoords = optimizations.readsLocalCoords();
     146           0 :     }
     147             : 
     148           0 :     void onPrepareDraws(Target* target) const override {
     149           0 :         sk_sp<GrGeometryProcessor> gp;
     150             :         {
     151             :             using namespace GrDefaultGeoProcFactory;
     152           0 :             Color color(this->color());
     153           0 :             Coverage coverage(this->coverage());
     154           0 :             LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type :
     155           0 :                                                               LocalCoords::kUnused_Type);
     156           0 :             gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, this->viewMatrix());
     157             :         }
     158             : 
     159           0 :         size_t vertexStride = gp->getVertexStride();
     160           0 :         SkASSERT(vertexStride == sizeof(SkPoint));
     161             : 
     162           0 :         int instanceCount = fPaths.count();
     163             : 
     164             :         // compute number of vertices
     165           0 :         int maxVertices = 0;
     166             : 
     167             :         // We will use index buffers if we have multiple paths or one path with multiple contours
     168           0 :         bool isIndexed = instanceCount > 1;
     169           0 :         for (int i = 0; i < instanceCount; i++) {
     170           0 :             const PathData& args = fPaths[i];
     171             : 
     172             :             int contourCount;
     173           0 :             maxVertices += GrPathUtils::worstCasePointCount(args.fPath, &contourCount,
     174           0 :                                                             args.fTolerance);
     175             : 
     176           0 :             isIndexed = isIndexed || contourCount > 1;
     177             :         }
     178             : 
     179           0 :         if (maxVertices == 0 || maxVertices > ((int)SK_MaxU16 + 1)) {
     180             :             //SkDebugf("Cannot render path (%d)\n", maxVertices);
     181           0 :             return;
     182             :         }
     183             : 
     184             :         // determine primitiveType
     185           0 :         int maxIndices = 0;
     186             :         GrPrimitiveType primitiveType;
     187           0 :         if (this->isHairline()) {
     188           0 :             if (isIndexed) {
     189           0 :                 maxIndices = 2 * maxVertices;
     190           0 :                 primitiveType = kLines_GrPrimitiveType;
     191             :             } else {
     192           0 :                 primitiveType = kLineStrip_GrPrimitiveType;
     193             :             }
     194             :         } else {
     195           0 :             if (isIndexed) {
     196           0 :                 maxIndices = 3 * maxVertices;
     197           0 :                 primitiveType = kTriangles_GrPrimitiveType;
     198             :             } else {
     199           0 :                 primitiveType = kTriangleFan_GrPrimitiveType;
     200             :             }
     201             :         }
     202             : 
     203             :         // allocate vertex / index buffers
     204             :         const GrBuffer* vertexBuffer;
     205             :         int firstVertex;
     206             : 
     207             :         void* verts = target->makeVertexSpace(vertexStride, maxVertices,
     208           0 :                                               &vertexBuffer, &firstVertex);
     209             : 
     210           0 :         if (!verts) {
     211           0 :             SkDebugf("Could not allocate vertices\n");
     212           0 :             return;
     213             :         }
     214             : 
     215           0 :         const GrBuffer* indexBuffer = nullptr;
     216           0 :         int firstIndex = 0;
     217             : 
     218           0 :         void* indices = nullptr;
     219           0 :         if (isIndexed) {
     220           0 :             indices = target->makeIndexSpace(maxIndices, &indexBuffer, &firstIndex);
     221             : 
     222           0 :             if (!indices) {
     223           0 :                 SkDebugf("Could not allocate indices\n");
     224           0 :                 return;
     225             :             }
     226             :         }
     227             : 
     228             :         // fill buffers
     229           0 :         int vertexOffset = 0;
     230           0 :         int indexOffset = 0;
     231           0 :         for (int i = 0; i < instanceCount; i++) {
     232           0 :             const PathData& args = fPaths[i];
     233             : 
     234           0 :             int vertexCnt = 0;
     235           0 :             int indexCnt = 0;
     236           0 :             if (!this->createGeom(verts,
     237             :                                   vertexOffset,
     238             :                                   indices,
     239             :                                   indexOffset,
     240             :                                   &vertexCnt,
     241             :                                   &indexCnt,
     242             :                                   args.fPath,
     243           0 :                                   args.fTolerance,
     244             :                                   isIndexed)) {
     245           0 :                 return;
     246             :             }
     247             : 
     248           0 :             vertexOffset += vertexCnt;
     249           0 :             indexOffset += indexCnt;
     250           0 :             SkASSERT(vertexOffset <= maxVertices && indexOffset <= maxIndices);
     251             :         }
     252             : 
     253           0 :         GrMesh mesh;
     254           0 :         if (isIndexed) {
     255             :             mesh.initIndexed(primitiveType, vertexBuffer, indexBuffer, firstVertex, firstIndex,
     256           0 :                              vertexOffset, indexOffset);
     257             :         } else {
     258           0 :             mesh.init(primitiveType, vertexBuffer, firstVertex, vertexOffset);
     259             :         }
     260           0 :         target->draw(gp.get(), this->pipeline(), mesh);
     261             : 
     262             :         // put back reserves
     263           0 :         target->putBackIndices((size_t)(maxIndices - indexOffset));
     264           0 :         target->putBackVertices((size_t)(maxVertices - vertexOffset), (size_t)vertexStride);
     265             :     }
     266             : 
     267           0 :     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
     268           0 :         DefaultPathOp* that = t->cast<DefaultPathOp>();
     269           0 :         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
     270             :                                     that->bounds(), caps)) {
     271           0 :             return false;
     272             :         }
     273             : 
     274           0 :         if (this->color() != that->color()) {
     275           0 :             return false;
     276             :         }
     277             : 
     278           0 :         if (this->coverage() != that->coverage()) {
     279           0 :             return false;
     280             :         }
     281             : 
     282           0 :         if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
     283           0 :             return false;
     284             :         }
     285             : 
     286           0 :         if (this->isHairline() != that->isHairline()) {
     287           0 :             return false;
     288             :         }
     289             : 
     290           0 :         fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
     291           0 :         this->joinBounds(*that);
     292           0 :         return true;
     293             :     }
     294             : 
     295           0 :     bool createGeom(void* vertices,
     296             :                     size_t vertexOffset,
     297             :                     void* indices,
     298             :                     size_t indexOffset,
     299             :                     int* vertexCnt,
     300             :                     int* indexCnt,
     301             :                     const SkPath& path,
     302             :                     SkScalar srcSpaceTol,
     303             :                     bool isIndexed) const {
     304           0 :             SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
     305             : 
     306           0 :             uint16_t indexOffsetU16 = (uint16_t)indexOffset;
     307           0 :             uint16_t vertexOffsetU16 = (uint16_t)vertexOffset;
     308             : 
     309           0 :             uint16_t* idxBase = reinterpret_cast<uint16_t*>(indices) + indexOffsetU16;
     310           0 :             uint16_t* idx = idxBase;
     311           0 :             uint16_t subpathIdxStart = vertexOffsetU16;
     312             : 
     313           0 :             SkPoint* base = reinterpret_cast<SkPoint*>(vertices) + vertexOffset;
     314           0 :             SkPoint* vert = base;
     315             : 
     316             :             SkPoint pts[4];
     317             : 
     318           0 :             bool first = true;
     319           0 :             int subpath = 0;
     320             : 
     321           0 :             SkPath::Iter iter(path, false);
     322             : 
     323           0 :             bool done = false;
     324           0 :             while (!done) {
     325           0 :                 SkPath::Verb verb = iter.next(pts);
     326           0 :                 switch (verb) {
     327             :                     case SkPath::kMove_Verb:
     328           0 :                         if (!first) {
     329           0 :                             uint16_t currIdx = (uint16_t) (vert - base) + vertexOffsetU16;
     330           0 :                             subpathIdxStart = currIdx;
     331           0 :                             ++subpath;
     332             :                         }
     333           0 :                         *vert = pts[0];
     334           0 :                         vert++;
     335           0 :                         break;
     336             :                     case SkPath::kLine_Verb:
     337           0 :                         if (isIndexed) {
     338           0 :                             uint16_t prevIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
     339           0 :                             append_countour_edge_indices(this->isHairline(), subpathIdxStart,
     340           0 :                                                          prevIdx, &idx);
     341             :                         }
     342           0 :                         *(vert++) = pts[1];
     343           0 :                         break;
     344             :                     case SkPath::kConic_Verb: {
     345           0 :                         SkScalar weight = iter.conicWeight();
     346           0 :                         SkAutoConicToQuads converter;
     347           0 :                         const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
     348           0 :                         for (int i = 0; i < converter.countQuads(); ++i) {
     349           0 :                             add_quad(&vert, base, quadPts + i*2, srcSpaceTolSqd, srcSpaceTol,
     350           0 :                                      isIndexed, this->isHairline(), subpathIdxStart,
     351           0 :                                      (int)vertexOffset, &idx);
     352             :                         }
     353           0 :                         break;
     354             :                     }
     355             :                     case SkPath::kQuad_Verb:
     356           0 :                         add_quad(&vert, base, pts, srcSpaceTolSqd, srcSpaceTol, isIndexed,
     357           0 :                                  this->isHairline(), subpathIdxStart, (int)vertexOffset, &idx);
     358           0 :                         break;
     359             :                     case SkPath::kCubic_Verb: {
     360             :                         // first pt of cubic is the pt we ended on in previous step
     361           0 :                         uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1 + vertexOffsetU16;
     362           0 :                         uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
     363             :                                         pts[0], pts[1], pts[2], pts[3],
     364             :                                         srcSpaceTolSqd, &vert,
     365           0 :                                         GrPathUtils::cubicPointCount(pts, srcSpaceTol));
     366           0 :                         if (isIndexed) {
     367           0 :                             for (uint16_t i = 0; i < numPts; ++i) {
     368           0 :                                 append_countour_edge_indices(this->isHairline(), subpathIdxStart,
     369           0 :                                                              firstCPtIdx + i, &idx);
     370             :                             }
     371             :                         }
     372           0 :                         break;
     373             :                     }
     374             :                     case SkPath::kClose_Verb:
     375           0 :                         break;
     376             :                     case SkPath::kDone_Verb:
     377           0 :                         done = true;
     378             :                 }
     379           0 :                 first = false;
     380             :             }
     381             : 
     382           0 :             *vertexCnt = static_cast<int>(vert - base);
     383           0 :             *indexCnt = static_cast<int>(idx - idxBase);
     384           0 :         return true;
     385             :     }
     386             : 
     387           0 :     GrColor color() const { return fColor; }
     388           0 :     uint8_t coverage() const { return fCoverage; }
     389           0 :     bool usesLocalCoords() const { return fUsesLocalCoords; }
     390           0 :     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     391           0 :     bool isHairline() const { return fIsHairline; }
     392             : 
     393           0 :     struct PathData {
     394             :         SkPath fPath;
     395             :         SkScalar fTolerance;
     396             :     };
     397             : 
     398             :     GrColor fColor;
     399             :     uint8_t fCoverage;
     400             :     SkMatrix fViewMatrix;
     401             :     bool fUsesLocalCoords;
     402             :     bool fIsHairline;
     403             :     SkSTArray<1, PathData, true> fPaths;
     404             : 
     405             :     typedef GrLegacyMeshDrawOp INHERITED;
     406             : };
     407             : 
     408           0 : bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
     409             :                                              GrPaint&& paint,
     410             :                                              GrAAType aaType,
     411             :                                              const GrUserStencilSettings& userStencilSettings,
     412             :                                              const GrClip& clip,
     413             :                                              const SkMatrix& viewMatrix,
     414             :                                              const GrShape& shape,
     415             :                                              bool stencilOnly) {
     416           0 :     SkASSERT(GrAAType::kCoverage != aaType);
     417           0 :     SkPath path;
     418           0 :     shape.asPath(&path);
     419             : 
     420             :     SkScalar hairlineCoverage;
     421           0 :     uint8_t newCoverage = 0xff;
     422           0 :     bool isHairline = false;
     423           0 :     if (IsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
     424           0 :         newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
     425           0 :         isHairline = true;
     426             :     } else {
     427           0 :         SkASSERT(shape.style().isSimpleFill());
     428             :     }
     429             : 
     430           0 :     int                          passCount = 0;
     431             :     const GrUserStencilSettings* passes[3];
     432             :     GrDrawFace                   drawFace[3];
     433           0 :     bool                         reverse = false;
     434             :     bool                         lastPassIsBounds;
     435             : 
     436           0 :     if (isHairline) {
     437           0 :         passCount = 1;
     438           0 :         if (stencilOnly) {
     439           0 :             passes[0] = &gDirectToStencil;
     440             :         } else {
     441           0 :             passes[0] = &userStencilSettings;
     442             :         }
     443           0 :         lastPassIsBounds = false;
     444           0 :         drawFace[0] = GrDrawFace::kBoth;
     445             :     } else {
     446           0 :         if (single_pass_shape(shape)) {
     447           0 :             passCount = 1;
     448           0 :             if (stencilOnly) {
     449           0 :                 passes[0] = &gDirectToStencil;
     450             :             } else {
     451           0 :                 passes[0] = &userStencilSettings;
     452             :             }
     453           0 :             drawFace[0] = GrDrawFace::kBoth;
     454           0 :             lastPassIsBounds = false;
     455             :         } else {
     456           0 :             switch (path.getFillType()) {
     457             :                 case SkPath::kInverseEvenOdd_FillType:
     458           0 :                     reverse = true;
     459             :                     // fallthrough
     460             :                 case SkPath::kEvenOdd_FillType:
     461           0 :                     passes[0] = &gEOStencilPass;
     462           0 :                     if (stencilOnly) {
     463           0 :                         passCount = 1;
     464           0 :                         lastPassIsBounds = false;
     465             :                     } else {
     466           0 :                         passCount = 2;
     467           0 :                         lastPassIsBounds = true;
     468           0 :                         if (reverse) {
     469           0 :                             passes[1] = &gInvEOColorPass;
     470             :                         } else {
     471           0 :                             passes[1] = &gEOColorPass;
     472             :                         }
     473             :                     }
     474           0 :                     drawFace[0] = drawFace[1] = GrDrawFace::kBoth;
     475           0 :                     break;
     476             : 
     477             :                 case SkPath::kInverseWinding_FillType:
     478           0 :                     reverse = true;
     479             :                     // fallthrough
     480             :                 case SkPath::kWinding_FillType:
     481           0 :                     if (fSeparateStencil) {
     482           0 :                         if (fStencilWrapOps) {
     483           0 :                             passes[0] = &gWindStencilSeparateWithWrap;
     484             :                         } else {
     485           0 :                             passes[0] = &gWindStencilSeparateNoWrap;
     486             :                         }
     487           0 :                         passCount = 2;
     488           0 :                         drawFace[0] = GrDrawFace::kBoth;
     489             :                     } else {
     490           0 :                         if (fStencilWrapOps) {
     491           0 :                             passes[0] = &gWindSingleStencilWithWrapInc;
     492           0 :                             passes[1] = &gWindSingleStencilWithWrapDec;
     493             :                         } else {
     494           0 :                             passes[0] = &gWindSingleStencilNoWrapInc;
     495           0 :                             passes[1] = &gWindSingleStencilNoWrapDec;
     496             :                         }
     497             :                         // which is cw and which is ccw is arbitrary.
     498           0 :                         drawFace[0] = GrDrawFace::kCW;
     499           0 :                         drawFace[1] = GrDrawFace::kCCW;
     500           0 :                         passCount = 3;
     501             :                     }
     502           0 :                     if (stencilOnly) {
     503           0 :                         lastPassIsBounds = false;
     504           0 :                         --passCount;
     505             :                     } else {
     506           0 :                         lastPassIsBounds = true;
     507           0 :                         drawFace[passCount-1] = GrDrawFace::kBoth;
     508           0 :                         if (reverse) {
     509           0 :                             passes[passCount-1] = &gInvWindColorPass;
     510             :                         } else {
     511           0 :                             passes[passCount-1] = &gWindColorPass;
     512             :                         }
     513             :                     }
     514           0 :                     break;
     515             :                 default:
     516           0 :                     SkDEBUGFAIL("Unknown path fFill!");
     517           0 :                     return false;
     518             :             }
     519             :         }
     520             :     }
     521             : 
     522           0 :     SkScalar tol = GrPathUtils::kDefaultTolerance;
     523           0 :     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
     524             : 
     525             :     SkRect devBounds;
     526           0 :     GetPathDevBounds(path, renderTargetContext->width(), renderTargetContext->height(), viewMatrix,
     527           0 :                      &devBounds);
     528             : 
     529           0 :     for (int p = 0; p < passCount; ++p) {
     530           0 :         if (lastPassIsBounds && (p == passCount-1)) {
     531             :             SkRect bounds;
     532           0 :             SkMatrix localMatrix = SkMatrix::I();
     533           0 :             if (reverse) {
     534             :                 // draw over the dev bounds (which will be the whole dst surface for inv fill).
     535           0 :                 bounds = devBounds;
     536             :                 SkMatrix vmi;
     537             :                 // mapRect through persp matrix may not be correct
     538           0 :                 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
     539           0 :                     vmi.mapRect(&bounds);
     540             :                 } else {
     541           0 :                     if (!viewMatrix.invert(&localMatrix)) {
     542           0 :                         return false;
     543             :                     }
     544             :                 }
     545             :             } else {
     546           0 :                 bounds = path.getBounds();
     547             :             }
     548           0 :             const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
     549           0 :                                                                                viewMatrix;
     550             :             std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
     551           0 :                     paint.getColor(), viewM, bounds, nullptr, &localMatrix));
     552             : 
     553           0 :             SkASSERT(GrDrawFace::kBoth == drawFace[p]);
     554           0 :             GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
     555           0 :             pipelineBuilder.setDrawFace(drawFace[p]);
     556           0 :             pipelineBuilder.setUserStencil(passes[p]);
     557           0 :             renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip,
     558           0 :                                                      std::move(op));
     559             :         } else {
     560             :             std::unique_ptr<GrLegacyMeshDrawOp> op =
     561             :                     DefaultPathOp::Make(paint.getColor(), path, srcSpaceTol, newCoverage,
     562           0 :                                         viewMatrix, isHairline, devBounds);
     563           0 :             bool stencilPass = stencilOnly || passCount > 1;
     564           0 :             GrPaint::MoveOrNew passPaint(paint, stencilPass);
     565           0 :             if (stencilPass) {
     566           0 :                 passPaint.paint().setXPFactory(GrDisableColorXPFactory::Get());
     567             :             }
     568           0 :             GrPipelineBuilder pipelineBuilder(std::move(passPaint), aaType);
     569           0 :             pipelineBuilder.setDrawFace(drawFace[p]);
     570           0 :             pipelineBuilder.setUserStencil(passes[p]);
     571           0 :             renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip,
     572           0 :                                                      std::move(op));
     573             :         }
     574             :     }
     575           0 :     return true;
     576             : }
     577             : 
     578           0 : bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     579             :     // This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
     580           0 :     return GrAAType::kCoverage != args.fAAType &&
     581           0 :            (args.fShape->style().isSimpleFill() ||
     582           0 :             IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr));
     583             : }
     584             : 
     585           0 : bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
     586           0 :     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     587             :                               "GrDefaultPathRenderer::onDrawPath");
     588           0 :     return this->internalDrawPath(args.fRenderTargetContext,
     589           0 :                                   std::move(args.fPaint),
     590           0 :                                   args.fAAType,
     591           0 :                                   *args.fUserStencilSettings,
     592           0 :                                   *args.fClip,
     593           0 :                                   *args.fViewMatrix,
     594           0 :                                   *args.fShape,
     595           0 :                                   false);
     596             : }
     597             : 
     598           0 : void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
     599           0 :     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
     600             :                               "GrDefaultPathRenderer::onStencilPath");
     601           0 :     SkASSERT(!args.fShape->inverseFilled());
     602             : 
     603           0 :     GrPaint paint;
     604           0 :     paint.setXPFactory(GrDisableColorXPFactory::Get());
     605             : 
     606           0 :     this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
     607           0 :                            GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
     608           0 :                            *args.fShape, true);
     609           0 : }
     610             : 
     611             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     612             : 
     613             : #if GR_TEST_UTILS
     614             : 
     615           0 : DRAW_OP_TEST_DEFINE(DefaultPathOp) {
     616           0 :     GrColor color = GrRandomColor(random);
     617           0 :     SkMatrix viewMatrix = GrTest::TestMatrix(random);
     618             : 
     619             :     // For now just hairlines because the other types of draws require two ops.
     620             :     // TODO we should figure out a way to combine the stencil and cover steps into one op.
     621           0 :     GrStyle style(SkStrokeRec::kHairline_InitStyle);
     622           0 :     SkPath path = GrTest::TestPath(random);
     623             : 
     624             :     // Compute srcSpaceTol
     625           0 :     SkRect bounds = path.getBounds();
     626           0 :     SkScalar tol = GrPathUtils::kDefaultTolerance;
     627           0 :     SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
     628             : 
     629           0 :     viewMatrix.mapRect(&bounds);
     630           0 :     uint8_t coverage = GrRandomCoverage(random);
     631           0 :     return DefaultPathOp::Make(color, path, srcSpaceTol, coverage, viewMatrix, true, bounds);
     632             : }
     633             : 
     634             : #endif

Generated by: LCOV version 1.13