// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } // We actually only need A8, but it often isn't supported as a // render target so default to RGBA_8888 GrPixelConfig config = kRGBA_8888_GrPixelConfig; if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, sampleCnt > 0)) { config = kAlpha_8_GrPixelConfig; } sk_sp<GrDrawContext> drawContext(context->newDrawContext(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), config, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
void TestStyle(SkRandom* random, GrStyle* style) { SkStrokeRec::InitStyle initStyle = SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1)); SkStrokeRec stroke(initStyle); randomize_stroke_rec(&stroke, random); sk_sp<SkPathEffect> pe; if (random->nextBool()) { int cnt = random->nextRangeU(1, 50) * 2; std::unique_ptr<SkScalar[]> intervals(new SkScalar[cnt]); SkScalar sum = 0; for (int i = 0; i < cnt; i++) { intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01), SkDoubleToScalar(10.0)); sum += intervals[i]; } SkScalar phase = random->nextRangeScalar(0, sum); pe = TestDashPathEffect::Make(intervals.get(), cnt, phase); } *style = GrStyle(stroke, std::move(pe)); }
// Create a mask of 'devPath' and place the result in 'mask'. static sk_sp<GrTexture> create_mask_GPU(GrContext* context, const SkIRect& maskRect, const SkPath& devPath, SkStrokeRec::InitStyle fillOrHairline, bool doAA, int sampleCnt) { if (!doAA) { // Don't need MSAA if mask isn't AA sampleCnt = 0; } sk_sp<GrDrawContext> drawContext(context->makeDrawContextWithFallback(SkBackingFit::kApprox, maskRect.width(), maskRect.height(), kAlpha_8_GrPixelConfig, nullptr, sampleCnt)); if (!drawContext) { return nullptr; } drawContext->clear(nullptr, 0x0, true); GrPaint tempPaint; tempPaint.setAntiAlias(doAA); tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); GrFixedClip clip(clipRect); // Draw the mask into maskTexture with the path's integerized top-left at // the origin using tempPaint. SkMatrix translate; translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); drawContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline)); return drawContext->asTexture();; }
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) : fStyle(fontAndStroke) , fFont(fontAndStroke) , fTotalGlyphCount(0) , fFallbackGlyphCount(0) , fDetachedGlyphCache(nullptr) , fLastDrawnGlyphsID(SK_InvalidUniqueID) { SkASSERT(fFont.getTextSize() > 0); SkASSERT(!fStyle.hasNonDashPathEffect()); // Arbitrary path effects not supported. SkASSERT(!fStyle.isSimpleHairline()); // Hairlines are not supported. // Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path // rendering API for stroking). fFont.setStyle(SkPaint::kFill_Style); if (fFont.isFakeBoldText() && fStyle.isSimpleFill()) { const SkStrokeRec& stroke = fStyle.strokeRec(); // Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke. SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), kStdFakeBoldInterpKeys, kStdFakeBoldInterpValues, kStdFakeBoldInterpLength); SkScalar extra = fFont.getTextSize() * fakeBoldScale; SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle); strokeRec.setStrokeStyle(stroke.needToApply() ? stroke.getWidth() + extra : extra, true /*strokeAndFill*/); fStyle = GrStyle(strokeRec, fStyle.refPathEffect()); fFont.setFakeBoldText(false); } if (!fFont.getPathEffect() && !fStyle.isDashed()) { const SkStrokeRec& stroke = fStyle.strokeRec(); // We can draw the glyphs from canonically sized paths. fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize(); // Compensate for the glyphs being scaled by fTextRatio. if (!fStyle.isSimpleFill()) { SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle); strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio, SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()); fStyle = GrStyle(strokeRec, fStyle.refPathEffect()); } fFont.setLinearText(true); fFont.setLCDRenderText(false); fFont.setAutohinted(false); fFont.setHinting(SkPaint::kNo_Hinting); fFont.setSubpixelText(true); fFont.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)); fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && 0 == fFont.getTextSkewX() && !fFont.isFakeBoldText() && !fFont.isVerticalText(); } else { fTextRatio = fTextInverseRatio = 1.0f; fUsingRawGlyphPaths = false; } // Generate the key that will be used to cache the GPU glyph path objects. if (fUsingRawGlyphPaths && fStyle.isSimpleFill()) { static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain(); const SkTypeface* typeface = fFont.getTypeface(); GrUniqueKey::Builder builder(&fGlyphPathsKey, kRawFillPathGlyphDomain, 1); reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; } else { static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain(); int styleDataCount = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec); // Key should be valid since we opted out of drawing arbitrary path effects. SkASSERT(styleDataCount >= 0); if (fUsingRawGlyphPaths) { const SkTypeface* typeface = fFont.getTypeface(); GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount); reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount; if (styleDataCount) { write_style_key(&builder[2], fStyle); } } else { SkGlyphCache* glyphCache = this->getGlyphCache(); const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface(); const SkDescriptor* desc = &glyphCache->getDescriptor(); int descDataCount = (desc->getLength() + 3) / 4; GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount + descDataCount); reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0; reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount | (descDataCount << 16); if (styleDataCount) { write_style_key(&builder[2], fStyle); } memcpy(&builder[2 + styleDataCount], desc, desc->getLength()); } } }