void GrStencilAndCoverTextContext::drawText(GrContext* context, GrDrawContext* dc, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) { if (context->abandoned()) { return; } else if (this->canDraw(skPaint, viewMatrix)) { TextRun run(skPaint); GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); run.setText(text, byteLength, x, y); run.draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, props, 0, 0, clipBounds, fFallbackTextContext, skPaint); return; } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) { fFallbackTextContext->drawText(context, dc, clip, paint, skPaint, viewMatrix, props, text, byteLength, x, y, clipBounds); return; } // fall back to drawing as a path GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, byteLength, x, y, clipBounds); }
void GrAtlasTextBlob::flushCached(GrContext* context, GrDrawContext* dc, const SkTextBlob* blob, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const SkPaint& skPaint, const GrPaint& grPaint, SkDrawFilter* drawFilter, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y) { // We loop through the runs of the blob, flushing each. If any run is too large, then we flush // it as paths GrPipelineBuilder pipelineBuilder(grPaint, dc->isUnifiedMultisampled()); pipelineBuilder.setRenderTarget(dc->accessRenderTarget()); GrColor color = grPaint.getColor(); SkTextBlobRunIterator it(blob); for (int run = 0; !it.done(); it.next(), run++) { if (fRuns[run].fDrawAsPaths) { this->flushRunAsPaths(context, dc, props, it, clip, skPaint, drawFilter, viewMatrix, clipBounds, x, y); continue; } this->flushRun(dc, &pipelineBuilder, clip, run, viewMatrix, x, y, color, skPaint, props, distanceAdjustTable, context->getBatchFontCache()); } // Now flush big glyphs this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds); }
void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds) { TextRun run(skPaint); GrPipelineBuilder pipelineBuilder(paint, rt, clip); run.setText(text, byteLength, x, y); run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, fFallbackTextContext, skPaint); }
void GrSoftwarePathRenderer::DrawNonAARect(GrDrawContext* drawContext, const GrPaint& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix& localMatrix) { SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect, nullptr, &localMatrix)); GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); pipelineBuilder.setUserStencil(&userStencilSettings); drawContext->drawBatch(pipelineBuilder, clip, batch); }
void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { TextRun run(skPaint); GrPipelineBuilder pipelineBuilder(paint, rt, clip); run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds, fFallbackTextContext, skPaint); }
void GrAtlasTextBlob::flushThrowaway(GrContext* context, GrDrawContext* dc, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const SkPaint& skPaint, const GrPaint& grPaint, const GrClip& clip, const SkIRect& clipBounds) { GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip); GrColor color = grPaint.getColor(); for (int run = 0; run < fRunCount; run++) { this->flushRun(dc, &pipelineBuilder, run, color, 0, 0, skPaint, props, distanceAdjustTable, context->getBatchFontCache()); } // Now flush big glyphs this->flushBigGlyphs(context, dc, clip, skPaint, 0, 0, clipBounds); }
void GrAtlasTextBlob::flushThrowaway(GrContext* context, GrDrawContext* dc, const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable, const SkPaint& skPaint, const GrPaint& grPaint, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y) { GrPipelineBuilder pipelineBuilder(grPaint, dc->isUnifiedMultisampled()); pipelineBuilder.setRenderTarget(dc->accessRenderTarget()); GrColor color = grPaint.getColor(); for (int run = 0; run < fRunCount; run++) { this->flushRun(dc, &pipelineBuilder, clip, run, viewMatrix, x, y, color, skPaint, props, distanceAdjustTable, context->getBatchFontCache()); } // Now flush big glyphs this->flushBigGlyphs(context, dc, clip, skPaint, viewMatrix, x, y, clipBounds); }
void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* skBlob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { if (context->abandoned()) { return; } if (!this->internalCanDraw(skPaint)) { fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } if (drawFilter || skPaint.getPathEffect()) { // This draw can't be cached. this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props, skBlob, x, y, drawFilter, clipBounds); return; } GrPaint paint; if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { run->draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
void GrSWMaskHelper::DrawToTargetWithShapeMask(GrTexture* texture, GrDrawContext* drawContext, const GrPaint& paint, const GrUserStencilSettings* userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& rect) { SkMatrix invert; if (!viewMatrix.invert(&invert)) { return; } SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft, SK_Scalar1 * rect.fTop, SK_Scalar1 * rect.fRight, SK_Scalar1 * rect.fBottom); // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. SkMatrix maskMatrix; maskMatrix.setIDiv(texture->width(), texture->height()); maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop)); GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); pipelineBuilder.setUserStencil(userStencilSettings); pipelineBuilder.addCoverageFragmentProcessor( GrSimpleTextureEffect::Make(texture, maskMatrix, GrTextureParams::kNone_FilterMode, kDevice_GrCoordSet)); SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), SkMatrix::I(), dstRect, nullptr, &invert)); drawContext->drawBatch(pipelineBuilder, clip, batch); }
bool GrDefaultPathRenderer::internalDrawPath(GrDrawContext* drawContext, const GrPaint& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const GrShape& shape, bool stencilOnly) { SkPath path; shape.asPath(&path); SkScalar hairlineCoverage; uint8_t newCoverage = 0xff; bool isHairline = false; if (IsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) { newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); isHairline = true; } else { SkASSERT(shape.style().isSimpleFill()); } int passCount = 0; const GrUserStencilSettings* passes[3]; GrDrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (isHairline) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = &userStencilSettings; } lastPassIsBounds = false; drawFace[0] = GrDrawFace::kBoth; } else { if (single_pass_shape(shape)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = &userStencilSettings; } drawFace[0] = GrDrawFace::kBoth; lastPassIsBounds = false; } else { switch (path.getFillType()) { case SkPath::kInverseEvenOdd_FillType: reverse = true; // fallthrough case SkPath::kEvenOdd_FillType: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawFace::kBoth; break; case SkPath::kInverseWinding_FillType: reverse = true; // fallthrough case SkPath::kWinding_FillType: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawFace::kBoth; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawFace::kCW; drawFace[1] = GrDrawFace::kCCW; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawFace::kBoth; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: SkDEBUGFAIL("Unknown path fFill!"); return false; } } } SkScalar tol = GrPathUtils::kDefaultTolerance; SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); SkRect devBounds; GetPathDevBounds(path, drawContext->width(), drawContext->height(), viewMatrix, &devBounds); for (int p = 0; p < passCount; ++p) { if (lastPassIsBounds && (p == passCount-1)) { SkRect bounds; SkMatrix localMatrix = SkMatrix::I(); if (reverse) { // draw over the dev bounds (which will be the whole dst surface for inv fill). bounds = devBounds; SkMatrix vmi; // mapRect through persp matrix may not be correct if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { vmi.mapRect(&bounds); } else { if (!viewMatrix.invert(&localMatrix)) { return false; } } } else { bounds = path.getBounds(); } const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix; SkAutoTUnref<GrDrawBatch> batch( GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewM, bounds, nullptr, &localMatrix)); SkASSERT(GrDrawFace::kBoth == drawFace[p]); GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); pipelineBuilder.setDrawFace(drawFace[p]); pipelineBuilder.setUserStencil(passes[p]); drawContext->drawBatch(pipelineBuilder, clip, batch); } else { SkAutoTUnref<GrDrawBatch> batch(new DefaultPathBatch(paint.getColor(), path, srcSpaceTol, newCoverage, viewMatrix, isHairline, devBounds)); GrPipelineBuilder pipelineBuilder(paint, drawContext->mustUseHWAA(paint)); pipelineBuilder.setDrawFace(drawFace[p]); pipelineBuilder.setUserStencil(passes[p]); if (passCount > 1) { pipelineBuilder.setDisableColorXPFactory(); } drawContext->drawBatch(pipelineBuilder, clip, batch); } } return true; }
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); } }