bool GrPath::isEqualTo(const SkPath& path, const GrStyle& style) const { // Since this is only called in debug we don't care about performance. int cnt0 = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec); int cnt1 = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec); if (cnt0 < 0 || cnt1 < 0 || cnt0 != cnt1) { return false; } if (cnt0) { SkAutoTArray<uint32_t> key0(cnt0); SkAutoTArray<uint32_t> key1(cnt0); write_style_key(key0.get(), fStyle); write_style_key(key1.get(), style); if (0 != memcmp(key0.get(), key1.get(), cnt0)) { return false; } } return fSkPath == path; }
void GrPath::ComputeKey(const GrShape& shape, GrUniqueKey* key, bool* outIsVolatile) { int geoCnt = shape.unstyledKeySize(); int styleCnt = GrStyle::KeySize(shape.style(), GrStyle::Apply::kPathEffectAndStrokeRec); // This should only fail for an arbitrary path effect, and we should not have gotten // here with anything other than a dash path effect. SkASSERT(styleCnt >= 0); if (geoCnt < 0) { *outIsVolatile = true; return; } static const GrUniqueKey::Domain kGeneralPathDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey::Builder builder(key, kGeneralPathDomain, geoCnt + styleCnt, "Path"); shape.writeUnstyledKey(&builder[0]); if (styleCnt) { write_style_key(&builder[geoCnt], shape.style()); } *outIsVolatile = false; }
const GrStencilAndCoverTextContext::TextBlob& GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, const SkPaint& skPaint) { // The font-related parameters are baked into the text blob and will override this skPaint, so // the only remaining properties that can affect a TextBlob are the ones related to stroke. if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path. if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) { fLRUList.remove(*found); fLRUList.addToTail(*found); return **found; } TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint); this->purgeToFit(*blob); fBlobIdCache.set(skBlob->uniqueID(), blob); fLRUList.addToTail(blob); fCacheSize += blob->cpuMemorySize(); return *blob; } else { GrStyle style(skPaint); SkSTArray<4, uint32_t, true> key; key.reset(1 + style_key_cnt(style)); key[0] = skBlob->uniqueID(); write_style_key(&key[1], style); if (TextBlob** found = fBlobKeyCache.find(key)) { fLRUList.remove(*found); fLRUList.addToTail(*found); return **found; } TextBlob* blob = new TextBlob(key, skBlob, skPaint); this->purgeToFit(*blob); fBlobKeyCache.set(blob); fLRUList.addToTail(blob); fCacheSize += blob->cpuMemorySize(); return *blob; } }
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()); } } }