void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { SkASSERT(!args.fPath->isInverseFillType()); SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, *args.fViewMatrix)); SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke)); args.fTarget->stencilPath(*args.fPipelineBuilder, pp, p, convert_skpath_filltype(args.fPath->getFillType())); }
void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target) { SkASSERT(!path.isInverseFillType()); SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke)); target->stencilPath(p, convert_skpath_filltype(path.getFillType())); }
void GrStencilAndCoverPathRenderer::onStencilPath(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& stroke) { SkASSERT(!path.isInverseFillType()); SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix)); SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke.getStrokeRec())); target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); }
bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder, GrColor color, const SkMatrix& viewMatrix, const SkPath& path, const GrStrokeInfo& stroke, bool antiAlias) { SkASSERT(!antiAlias); SkASSERT(!stroke.getStrokeRec().isHairlineStyle()); SkASSERT(!stroke.isDashed()); SkASSERT(pipelineBuilder->getStencil().isDisabled()); SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke.getStrokeRec())); if (path.isInverseFillType()) { GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, kZero_StencilOp, kZero_StencilOp, // We know our rect will hit pixels outside the clip and the user bits will be 0 // outside the clip. So we can't just fill where the user bits are 0. We also need to // check that the clip bit is set. kEqualIfInClip_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix)); target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); SkMatrix invert = SkMatrix::I(); SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()), SkIntToScalar(pipelineBuilder->getRenderTarget()->height())); SkMatrix vmi; // mapRect through persp matrix may not be correct if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { vmi.mapRect(&bounds); // theoretically could set bloat = 0, instead leave it because of matrix inversion // precision. SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { if (!viewMatrix.invert(&invert)) { return false; } } const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, kZero_StencilOp, kNotEqual_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kStencilPass); SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color, viewMatrix)); target->drawPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); } pipelineBuilder->stencil()->setDisabled(); return true; }
bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target, bool antiAlias) { SkASSERT(!antiAlias); SkASSERT(!stroke.isHairlineStyle()); GrDrawState* drawState = target->drawState(); SkASSERT(drawState->getStencil().isDisabled()); SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke)); if (path.isInverseFillType()) { GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, kZero_StencilOp, kZero_StencilOp, // We know our rect will hit pixels outside the clip and the user bits will be 0 // outside the clip. So we can't just fill where the user bits are 0. We also need to // check that the clip bit is set. kEqualIfInClip_StencilFunc, 0xffff, 0x0000, 0xffff); drawState->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover target->stencilPath(p, convert_skpath_filltype(path.getFillType())); GrDrawState::AutoViewMatrixRestore avmr; SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(drawState->getRenderTarget()->width()), SkIntToScalar(drawState->getRenderTarget()->height())); SkMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); // theoretically could set bloat = 0, instead leave it because of matrix inversion // precision. SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { avmr.setIdentity(drawState); } target->drawSimpleRect(bounds); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, kZero_StencilOp, kNotEqual_StencilFunc, 0xffff, 0x0000, 0xffff); drawState->setStencil(kStencilPass); target->drawPath(p, convert_skpath_filltype(path.getFillType())); } target->drawState()->stencil()->setDisabled(); return true; }
bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { SkASSERT(!args.fStroke->isHairlineStyle()); const SkPath& path = *args.fPath; GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder; const SkMatrix& viewMatrix = *args.fViewMatrix; SkASSERT(pipelineBuilder->getStencil().isDisabled()); if (args.fAntiAlias) { SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled()); pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag); } SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke)); if (path.isInverseFillType()) { GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, kKeep_StencilOp, kZero_StencilOp, // We know our rect will hit pixels outside the clip and the user bits will be 0 // outside the clip. So we can't just fill where the user bits are 0. We also need to // check that the clip bit is set. kEqualIfInClip_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, convert_skpath_filltype(path.getFillType())); SkMatrix invert = SkMatrix::I(); SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()), SkIntToScalar(pipelineBuilder->getRenderTarget()->height())); SkMatrix vmi; // mapRect through persp matrix may not be correct if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { vmi.mapRect(&bounds); // theoretically could set bloat = 0, instead leave it because of matrix inversion // precision. SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { if (!viewMatrix.invert(&invert)) { return false; } } const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; args.fTarget->drawNonAARect(*pipelineBuilder, args.fColor, viewM, bounds, invert); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, kKeep_StencilOp, kNotEqual_StencilFunc, 0xffff, 0x0000, 0xffff); pipelineBuilder->setStencil(kStencilPass); args.fTarget->drawPath(*pipelineBuilder, viewMatrix, args.fColor, p, convert_skpath_filltype(path.getFillType())); } pipelineBuilder->stencil()->setDisabled(); return true; }
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke) : INHERITED(gpu, origSkPath, origStroke), fPathID(gpu->glPathRendering()->genPaths(1)) { if (origSkPath.isEmpty()) { InitPathObjectEmptyPath(gpu, fPathID); fShouldStroke = false; fShouldFill = false; } else { const SkPath* skPath = &origSkPath; SkTLazy<SkPath> tmpPath; const GrStrokeInfo* stroke = &origStroke; GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle); if (stroke->isDashed()) { // Skia stroking and NVPR stroking differ with respect to dashing // pattern. // Convert a dashing to either a stroke or a fill. if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) { skPath = tmpPath.get(); stroke = &tmpStroke; } } bool didInit = false; if (stroke->needToApply() && stroke->getCap() != SkPaint::kButt_Cap) { // Skia stroking and NVPR stroking differ with respect to stroking // end caps of empty subpaths. // Convert stroke to fill if path contains empty subpaths. didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *skPath); if (!didInit) { if (!tmpPath.isValid()) { tmpPath.init(); } SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath)); skPath = tmpPath.get(); tmpStroke.setFillStyle(); stroke = &tmpStroke; } } if (!didInit) { InitPathObjectPathData(gpu, fPathID, *skPath); } fShouldStroke = stroke->needToApply(); fShouldFill = stroke->isFillStyle() || stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style; fFillType = convert_skpath_filltype(skPath->getFillType()); fBounds = skPath->getBounds(); if (fShouldStroke) { InitPathObjectStroke(gpu, fPathID, *stroke); // FIXME: try to account for stroking, without rasterizing the stroke. fBounds.outset(stroke->getWidth(), stroke->getWidth()); } } this->registerWithCache(); }