GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const {
    GrPathRange* glyphs = static_cast<GrPathRange*>(
            ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKey));
    if (nullptr == glyphs) {
        if (fUsingRawGlyphPaths) {
            SkScalerContextEffects noeffects;
            glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), noeffects,
                                                           nullptr, fStyle);
        } else {
            SkGlyphCache* cache = this->getGlyphCache();
            glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(),
                                                           cache->getScalerContext()->getEffects(),
                                                           &cache->getDescriptor(),
                                                           fStyle);
        }
        ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs);
    }
    return glyphs;
}
Пример #2
0
static void dump_visitor(const SkGlyphCache& cache, void* context) {
    int* counter = (int*)context;
    int index = *counter;
    *counter += 1;

    const SkScalerContextRec& rec = cache.getScalerContext()->getRec();

    SkDebugf("[%3d] ID %3d, glyphs %3d, size %g, scale %g, skew %g, [%g %g %g %g]\n",
             index, rec.fFontID, cache.countCachedGlyphs(),
             rec.fTextSize, rec.fPreScaleX, rec.fPreSkewX,
             rec.fPost2x2[0][0], rec.fPost2x2[0][1], rec.fPost2x2[1][0], rec.fPost2x2[1][1]);
}
Пример #3
0
static void sk_trace_dump_visitor(const SkGlyphCache& cache, void* context) {
    SkTraceMemoryDump* dump = static_cast<SkTraceMemoryDump*>(context);

    const SkTypeface* face = cache.getScalerContext()->getTypeface();
    const SkScalerContextRec& rec = cache.getScalerContext()->getRec();

    SkString fontName;
    face->getFamilyName(&fontName);
    // Replace all special characters with '_'.
    for (size_t index = 0; index < fontName.size(); ++index) {
        if (!std::isalnum(fontName[index])) {
            fontName[index] = '_';
        }
    }

    SkString dumpName = SkStringPrintf("%s/%s_%d/%p",
                                       gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache);

    dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", cache.getMemoryUsed());
    dump->dumpNumericValue(dumpName.c_str(), "glyph_count", "objects", cache.countCachedGlyphs());
    dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
}
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());
        }
    }
}
Пример #5
0
GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
    : fStroke(fontAndStroke),
      fFont(fontAndStroke),
      fTotalGlyphCount(0),
      fDetachedGlyphCache(nullptr),
      fLastDrawnGlyphsID(SK_InvalidUniqueID) {
    SkASSERT(!fStroke.isHairlineStyle()); // 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() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
        // 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 = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
        fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
                               true /*strokeAndFill*/);

        fFont.setFakeBoldText(false);
    }

    if (!fFont.getPathEffect() && !fStroke.isDashed()) {
        // 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 (!fStroke.isFillStyle()) {
            fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
                                   SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
        }

        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 && fStroke.isFillStyle()) {
        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 strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
        if (fUsingRawGlyphPaths) {
            const SkTypeface* typeface = fFont.getTypeface();
            GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount);
            reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
            reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount;
            fStroke.asUniqueKeyFragment(&builder[2]);
        } 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 + strokeDataCount + descDataCount);
            reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
            reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDataCount << 16);
            fStroke.asUniqueKeyFragment(&builder[2]);
            memcpy(&builder[2 + strokeDataCount], desc, desc->getLength());
        }
    }

    // When drawing from canonically sized paths, the actual local coords are fTextRatio * coords.
    fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio);
}