// Returns true if this method handled the glyph, false if needs to be passed to fallback // bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, SkScalar sx, SkScalar sy, GrFontScaler* scaler) { if (NULL == fDrawTarget) { return true; } if (NULL == fStrike) { fStrike = fContext->getFontCache()->getStrike(scaler, true); } GrGlyph* glyph = fStrike->getGlyph(packed, scaler); if (NULL == glyph || glyph->fBounds.isEmpty()) { return true; } // fallback to color glyph support if (kA8_GrMaskFormat != glyph->fMaskFormat) { return false; } SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset); SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset); SkScalar scale = fTextRatio; dx *= scale; dy *= scale; sx += dx; sy += dy; width *= scale; height *= scale; SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); // check if we clipped out SkRect dstRect; const SkMatrix& ctm = fViewMatrix; (void) ctm.mapRect(&dstRect, glyphRect); if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()), SkScalarTruncToInt(dstRect.top()), SkScalarTruncToInt(dstRect.right()), SkScalarTruncToInt(dstRect.bottom()))) { return true; } if (NULL == glyph->fPlot) { // needs to be a separate conditional to avoid over-optimization // on Nexus 7 and Nexus 10 // If the glyph is too large we fall back to paths if (!uploadGlyph(glyph, scaler)) { if (NULL == glyph->fPath) { SkPath* path = SkNEW(SkPath); if (!scaler->getGlyphPath(glyph->glyphID(), path)) { // flag the glyph as being dead? delete path; return true; } glyph->fPath = path; } // flush any accumulated draws before drawing this glyph as a path. this->flush(); SkMatrix ctm; ctm.setScale(fTextRatio, fTextRatio); ctm.postTranslate(sx - dx, sy - dy); SkPath tmpPath(*glyph->fPath); tmpPath.transform(ctm); GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); fContext->drawPath(fRenderTarget, fClip, fPaint, fViewMatrix, tmpPath, strokeInfo); // remove this glyph from the vertices we need to allocate fTotalVertexCount -= kVerticesPerGlyph; return true; } } SkASSERT(glyph->fPlot); GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); glyph->fPlot->setDrawToken(drawToken); GrTexture* texture = glyph->fPlot->texture(); SkASSERT(texture); if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) { this->flush(); fCurrTexture = texture; fCurrTexture->ref(); } bool useColorVerts = !fUseLCDText; if (NULL == fVertices) { int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads(); fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices); fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts); } fVertexBounds.joinNonEmptyArg(glyphRect); int u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; int v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; int u1 = u0 + glyph->fBounds.width() - 2*SK_DistanceFieldInset; int v1 = v0 + glyph->fBounds.height() - 2*SK_DistanceFieldInset; size_t vertSize = get_vertex_stride(useColorVerts); intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex; // V0 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); position->set(glyphRect.fLeft, glyphRect.fTop); if (useColorVerts) { SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); *color = fPaint.getColor(); } SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16)); textureCoords->set(u0, v0); vertex += vertSize; // V1 position = reinterpret_cast<SkPoint*>(vertex); position->set(glyphRect.fLeft, glyphRect.fBottom); if (useColorVerts) { SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); *color = fPaint.getColor(); } textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16)); textureCoords->set(u0, v1); vertex += vertSize; // V2 position = reinterpret_cast<SkPoint*>(vertex); position->set(glyphRect.fRight, glyphRect.fBottom); if (useColorVerts) { SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); *color = fPaint.getColor(); } textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16)); textureCoords->set(u1, v1); vertex += vertSize; // V3 position = reinterpret_cast<SkPoint*>(vertex); position->set(glyphRect.fRight, glyphRect.fTop); if (useColorVerts) { SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); *color = fPaint.getColor(); } textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(SkIPoint16)); textureCoords->set(u1, v0); fCurrVertex += 4; return true; }
// Returns true if this method handled the glyph, false if needs to be passed to fallback // bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, SkScalar sx, SkScalar sy, GrFontScaler* scaler) { if (NULL == fDrawTarget) { return true; } if (NULL == fStrike) { fStrike = fContext->getFontCache()->getStrike(scaler, true); } GrGlyph* glyph = fStrike->getGlyph(packed, scaler); if (NULL == glyph || glyph->fBounds.isEmpty()) { return true; } // fallback to color glyph support if (kA8_GrMaskFormat != glyph->fMaskFormat) { return false; } SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset); SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset); SkScalar scale = fTextRatio; dx *= scale; dy *= scale; sx += dx; sy += dy; width *= scale; height *= scale; SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); // check if we clipped out SkRect dstRect; const SkMatrix& ctm = fContext->getMatrix(); (void) ctm.mapRect(&dstRect, glyphRect); if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()), SkScalarTruncToInt(dstRect.top()), SkScalarTruncToInt(dstRect.right()), SkScalarTruncToInt(dstRect.bottom()))) { // SkCLZ(3); // so we can set a break-point in the debugger return true; } if (NULL == glyph->fPlot) { if (!fStrike->glyphTooLargeForAtlas(glyph)) { if (fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } // try to clear out an unused plot before we flush if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } if (c_DumpFontCache) { #ifdef SK_DEVELOPER fContext->getFontCache()->dump(); #endif } // before we purge the cache, we must flush any accumulated draws this->flush(); fContext->flush(); // we should have an unused plot now if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && fStrike->addGlyphToAtlas(glyph, scaler)) { goto HAS_ATLAS; } } if (NULL == glyph->fPath) { SkPath* path = SkNEW(SkPath); if (!scaler->getGlyphPath(glyph->glyphID(), path)) { // flag the glyph as being dead? delete path; return true; } glyph->fPath = path; } // flush any accumulated draws before drawing this glyph as a path. this->flush(); GrContext::AutoMatrix am; SkMatrix ctm; ctm.setScale(fTextRatio, fTextRatio); ctm.postTranslate(sx - dx, sy - dy); GrPaint tmpPaint(fPaint); am.setPreConcat(fContext, ctm, &tmpPaint); GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo); // remove this glyph from the vertices we need to allocate fTotalVertexCount -= kVerticesPerGlyph; return true; } HAS_ATLAS: SkASSERT(glyph->fPlot); GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); glyph->fPlot->setDrawToken(drawToken); GrTexture* texture = glyph->fPlot->texture(); SkASSERT(texture); if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) { this->flush(); fCurrTexture = texture; fCurrTexture->ref(); } bool useColorVerts = !fUseLCDText; if (NULL == fVertices) { int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads(); fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices); fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, useColorVerts); } SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset); SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset); SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset); SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset); fVertexBounds.joinNonEmptyArg(glyphRect); size_t vertSize = get_vertex_stride(useColorVerts); SkPoint* positions = reinterpret_cast<SkPoint*>( reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex); positions->setRectFan(glyphRect.fLeft, glyphRect.fTop, glyphRect.fRight, glyphRect.fBottom, vertSize); // The texture coords are last in both the with and without color vertex layouts. SkPoint* textureCoords = reinterpret_cast<SkPoint*>( reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint)); textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)), SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)), SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)), SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)), vertSize); if (useColorVerts) { // color comes after position. GrColor* colors = reinterpret_cast<GrColor*>(positions + 1); for (int i = 0; i < 4; ++i) { *colors = fPaint.getColor(); colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize); } } fCurrVertex += 4; return true; }