GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const {
    GrPathRange* glyphs = static_cast<GrPathRange*>(
                              ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKey));
    if (nullptr == glyphs) {
        if (fUsingRawGlyphPaths) {
            glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), nullptr, fStroke);
        } else {
            SkGlyphCache* cache = this->getGlyphCache();
            glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerContext()->getTypeface(),
                     &cache->getDescriptor(),
                     fStroke);
        }
        ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyphs);
    }
    return glyphs;
}
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());
        }
    }
}
Пример #3
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);
}