Example #1
0
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrDrawContext* dc,
                                                 GrPipelineBuilder* pipelineBuilder,
                                                 GrColor color,
                                                 const SkMatrix& viewMatrix,
                                                 SkScalar x, SkScalar y,
                                                 const SkIRect& clipBounds,
                                                 GrTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fDraw);
    SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() ||
             !fFont.isAntiAlias());

    if (fDraw->count()) {
        pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kKeep_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder->stencil() = kStencilPass;

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count());
            fLastDrawnGlyphsID = glyphs->getUniqueID();
        }

        SkMatrix drawMatrix(viewMatrix);
        drawMatrix.preTranslate(x, y);
        drawMatrix.preScale(fTextRatio, fTextRatio);

        SkMatrix& localMatrix = fLocalMatrixTemplate;
        localMatrix.setTranslateX(x);
        localMatrix.setTranslateY(y);

        dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color, glyphs, fDraw,
                               GrPathRendering::kWinding_FillType);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStroke.applyToPaint(&fallbackSkPaint);
        if (!fStroke.isFillStyle()) {
            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget(),
                                          pipelineBuilder->clip(), fallbackSkPaint, viewMatrix,
                                          fFallbackTextBlob, x, y, nullptr, clipBounds);
    }
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrRenderTargetContext* renderTargetContext,
                                                 const GrClip& clip, const SkMatrix& viewMatrix,
                                                 const SkSurfaceProps& props, SkScalar x,
                                                 SkScalar y, const SkIRect& clipBounds,
                                                 GrAtlasTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);

    if (fInstanceData->count()) {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        sk_sp<GrPathRange> glyphs(this->createGlyphs(ctx->resourceProvider()));
        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->uniqueID();
        }

        GrPaint grPaint;
        if (!SkPaintToGrPaint(ctx, renderTargetContext, originalSkPaint, viewMatrix, &grPaint)) {
            return;
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt GrOp combining.
        const SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(),
                                              renderTargetContext->height());

        // The run's "font" overrides the anti-aliasing of the passed in SkPaint!
        GrAAType aaType;
        if (this->aa() == GrAA::kYes) {
            SkASSERT(renderTargetContext->isStencilBufferMultisampled());
            aaType = renderTargetContext->isUnifiedMultisampled() ? GrAAType::kMSAA
                                                                  : GrAAType::kMixedSamples;
        } else {
            aaType = GrAAType::kNone;
        }

        std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make(
                viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y,
                std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(),
                fInstanceData.get(), bounds);

        renderTargetContext->addDrawOp(clip, std::move(op));
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
        if (!fStyle.isSimpleFill()) {
            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, renderTargetContext, clip, fallbackSkPaint,
                                          viewMatrix, props, fFallbackTextBlob.get(), x, y, nullptr,
                                          clipBounds);
    }
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
        GrDrawContext* dc,
        GrPipelineBuilder* pipelineBuilder,
        GrColor color,
        const SkMatrix& viewMatrix,
        const SkSurfaceProps& props,
        SkScalar x, SkScalar y,
        const SkIRect& clipBounds,
        GrTextContext* fallbackTextContext,
        const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);
    SkASSERT(dc->accessRenderTarget()->isStencilBufferMultisampled() || !fFont.isAntiAlias());

    if (fInstanceData->count()) {
        pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());

        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                     kZero_StencilOp,
                                     kKeep_StencilOp,
                                     kNotEqual_StencilFunc,
                                     0xffff,
                                     0x0000,
                                     0xffff);

        *pipelineBuilder->stencil() = kStencilPass;

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->getUniqueID();
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt batching.
        SkRect bounds = SkRect::MakeIWH(pipelineBuilder->getRenderTarget()->width(),
                                        pipelineBuilder->getRenderTarget()->height());

        SkAutoTUnref<GrDrawPathBatchBase> batch(
            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
                                         fTextInverseRatio * y, color,
                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                         bounds));

        dc->drawPathBatch(*pipelineBuilder, batch);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStroke.applyToPaint(&fallbackSkPaint);
        if (!fStroke.isFillStyle()) {
            fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fallbackSkPaint,
                                          viewMatrix, props, fFallbackTextBlob, x, y, nullptr,
                                          clipBounds);
    }
}
void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
                                                 GrDrawContext* drawContext,
                                                 const GrPaint& grPaint,
                                                 const GrClip& clip,
                                                 const SkMatrix& viewMatrix,
                                                 const SkSurfaceProps& props,
                                                 SkScalar x, SkScalar y,
                                                 const SkIRect& clipBounds,
                                                 GrAtlasTextContext* fallbackTextContext,
                                                 const SkPaint& originalSkPaint) const {
    SkASSERT(fInstanceData);
    SkASSERT(drawContext->isStencilBufferMultisampled() || !grPaint.isAntiAlias());

    if (fInstanceData->count()) {
        static constexpr GrUserStencilSettings kCoverPass(
            GrUserStencilSettings::StaticInit<
                0x0000,
                GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
                0xffff,
                GrUserStencilOp::kZero,
                GrUserStencilOp::kKeep,
                0xffff>()
        );

        SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
            // Either this is the first draw or the glyphs object was purged since last draw.
            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
            fLastDrawnGlyphsID = glyphs->uniqueID();
        }

        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
        // the entire dst. Realistically this is a moot point, because any context that supports
        // NV_path_rendering will also support NV_blend_equation_advanced.
        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
        // hurt batching.
        const SkRect bounds = SkRect::MakeIWH(drawContext->width(), drawContext->height());

        SkAutoTUnref<GrDrawBatch> batch(
            GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRatio * x,
                                         fTextInverseRatio * y, grPaint.getColor(),
                                         GrPathRendering::kWinding_FillType, glyphs, fInstanceData,
                                         bounds));

        GrPipelineBuilder pipelineBuilder(grPaint);
        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, grPaint.isAntiAlias());
        pipelineBuilder.setUserStencil(&kCoverPass);

        drawContext->drawBatch(pipelineBuilder, clip, batch);
    }

    if (fFallbackTextBlob) {
        SkPaint fallbackSkPaint(originalSkPaint);
        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
        if (!fStyle.isSimpleFill()) {
            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
        }

        fallbackTextContext->drawTextBlob(ctx, drawContext, clip, fallbackSkPaint, viewMatrix,
                                          props, fFallbackTextBlob.get(), x, y, nullptr,
                                          clipBounds);
    }
}