void GrContext::drawFontCache(const SkRect& rect, GrMaskFormat format, const SkPaint& paint, GrRenderTarget* target) { GrBatchFontCache* cache = this->getBatchFontCache(); GrTexture* atlas = cache->getTexture(format); SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(target)); // TODO: add drawContext method to encapsulate this. GrPaint grPaint; SkMatrix mat; mat.reset(); if (!SkPaintToGrPaint(this, paint, mat, &grPaint)) { return; } SkMatrix textureMat; textureMat.reset(); // TODO: use setScaleTranslate() textureMat[SkMatrix::kMScaleX] = 1.0f/rect.width(); textureMat[SkMatrix::kMScaleY] = 1.0f/rect.height(); textureMat[SkMatrix::kMTransX] = -rect.fLeft/rect.width(); textureMat[SkMatrix::kMTransY] = -rect.fTop/rect.height(); grPaint.addColorTextureProcessor(atlas, textureMat); GrClip clip; drawContext->drawRect(clip, grPaint, mat, rect); }
void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context, GrDrawContext* dc, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkSurfaceProps& props, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { SkPaint runPaint = skPaint; SkTextBlobRunIterator it(blob); for (;!it.done(); it.next()) { size_t textLen = it.glyphCount() * sizeof(uint16_t); const SkPoint& offset = it.offset(); // applyFontToPaint() always overwrites the exact same attributes, // so it is safe to not re-seed the paint for this reason. it.applyFontToPaint(&runPaint); if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) { // A false return from filter() means we should abort the current draw. runPaint = skPaint; continue; } runPaint.setFlags(GrTextUtils::FilterTextFlags(props, runPaint)); GrPaint grPaint; if (!SkPaintToGrPaint(context, dc, runPaint, viewMatrix, &grPaint)) { return; } switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: this->drawText(context, dc, clip, grPaint, runPaint, viewMatrix, props, (const char *)it.glyphs(), textLen, x + offset.x(), y + offset.y(), clipBounds); break; case SkTextBlob::kHorizontal_Positioning: this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatrix, props, (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), clipBounds); break; case SkTextBlob::kFull_Positioning: this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatrix, props, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds); break; } if (drawFilter) { // A draw filter may change the paint arbitrarily, so we must re-seed in this case. runPaint = skPaint; } } }
void SkGpuDevice::drawTexture(GrTexture* tex, const SkRect& dst, const SkPaint& paint) { GrPaint grPaint; SkMatrix mat; mat.reset(); if (!SkPaintToGrPaint(this->context(), paint, mat, this->surfaceProps().isGammaCorrect(), &grPaint)) { return; } SkMatrix textureMat; textureMat.reset(); textureMat[SkMatrix::kMScaleX] = 1.0f/dst.width(); textureMat[SkMatrix::kMScaleY] = 1.0f/dst.height(); textureMat[SkMatrix::kMTransX] = -dst.fLeft/dst.width(); textureMat[SkMatrix::kMTransY] = -dst.fTop/dst.height(); grPaint.addColorTextureProcessor(tex, textureMat); fDrawContext->drawRect(GrNoClip(), grPaint, mat, dst); }
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, dc, skPaint, viewMatrix, &paint)) { return; } const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); TextBlob::Iter iter(blob); for (TextRun* run = iter.get(); run; run = iter.next()) { // The run's "font" overrides the anti-aliasing of the passed in paint! paint.setAntiAlias(run->isAntiAlias()); run->draw(context, dc, paint, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext, skPaint); run->releaseGlyphCache(); } }
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 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); } }