void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); SkGlyphCache* glyphCache = this->getGlyphCache(); SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(fFont.getTextEncoding(), fFont.isDevKernText(), true); fTotalGlyphCount = fFont.countText(text, byteLength); fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType, fTotalGlyphCount)); const char* stop = text + byteLength; SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); SkTextAlignProc alignProc(fFont.getTextAlign()); FallbackBlobBuilder fallback; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(glyphCache, &text); if (glyph.fWidth) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); this->appendGlyph(glyph, loc, &fallback); } pos += scalarsPerPosition; } fFallbackTextBlob = fallback.makeIfNeeded(&fFallbackGlyphCount); }
void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != nullptr); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); SkGlyphCache* glyphCache = this->getGlyphCache(); SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransformType, fTotalGlyphCount = fFont.countText(text, byteLength))); const char* stop = text + byteLength; SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); SkTextAlignProc alignProc(fFont.getTextAlign()); FallbackBlobBuilder fallback; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); if (glyph.fWidth) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); this->appendGlyph(glyph, loc, &fallback); } pos += scalarsPerPosition; } fFallbackTextBlob.reset(fallback.buildIfInitialized()); }
void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* drawContext, GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds) { SkASSERT(byteLength == 0 || text != NULL); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); // nothing to draw if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { return; } // This is the fast path. Here we do not bake in the device-transform to // the glyph outline or the advances. This is because we do not need to // position the glyphs at all, since the caller has done the positioning. // The positioning is based on SkPaint::measureText of individual // glyphs. That already uses glyph cache without device transforms. Device // transform is not part of SkPaint::measureText API, and thus we use the // same glyphs as what were measured. this->init(rt, clip, paint, skPaint, byteLength, kMaxPerformance_RenderMode, viewMatrix, regionClipBounds); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); const char* stop = text + byteLength; SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); SkTextAlignProc alignProc(fSkPaint.getTextAlign()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); this->appendGlyph(drawContext, glyph, loc); } pos += scalarsPerPosition; } this->finish(drawContext); }
void GrTextUtils::DrawPosTextAsPath(GrContext* context, GrDrawContext* dc, const SkSurfaceProps& props, const GrClip& clip, const SkPaint& origPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipBounds) { // setup our std paint, in hopes of getting hits in the cache SkPaint paint(origPaint); SkScalar matrixScale = paint.setupForAsPaths(); SkMatrix matrix; matrix.setScale(matrixScale, matrixScale); // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. paint.setStyle(SkPaint::kFill_Style); paint.setPathEffect(nullptr); SkPaint::GlyphCacheProc glyphCacheProc = paint.getGlyphCacheProc(true); SkAutoGlyphCache autoCache(paint, &props, nullptr); SkGlyphCache* cache = autoCache.getCache(); const char* stop = text + byteLength; SkTextAlignProc alignProc(paint.getTextAlign()); SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); // Now restore the original settings, so we "draw" with whatever style/stroking. paint.setStyle(origPaint.getStyle()); paint.setPathEffect(origPaint.getPathEffect()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text); if (glyph.fWidth) { const SkPath* path = cache->findPath(glyph); if (path) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); matrix[SkMatrix::kMTransX] = loc.fX; matrix[SkMatrix::kMTransY] = loc.fY; GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, *path, paint, viewMatrix, &matrix, clipBounds, false); } } pos += scalarsPerPosition; } }
void GrBitmapTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != NULL); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); // nothing to draw if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { return; } this->init(rt, clip, paint, skPaint); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for // performance reasons we just invert here instead if (!viewMatrix.invert(&fLocalMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); fTotalVertexCount = kVerticesPerGlyph*numGlyphs; const char* stop = text + byteLength; SkTextAlignProc alignProc(fSkPaint.getTextAlign()); SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition); SkScalar halfSampleX = 0, halfSampleY = 0; if (cache->isSubpixel()) { // maybe we should skip the rounding if linearText is set SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); SkFixed fxMask = ~0; SkFixed fyMask = ~0; if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_ScalarHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_ScalarHalf; } if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { while (text < stop) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); if (glyph.fWidth) { this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); } pos += scalarsPerPosition; } } else { while (text < stop) { const char* currentText = text; const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); if (metricGlyph.fWidth) { SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint alignLoc; alignProc(tmsLoc, metricGlyph, &alignLoc); Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); // have to call again, now that we've been "aligned" const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, fx & fxMask, fy & fyMask); // the assumption is that the metrics haven't changed SkASSERT(prevAdvX == glyph.fAdvanceX); SkASSERT(prevAdvY == glyph.fAdvanceY); SkASSERT(glyph.fWidth); this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); }
void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint, const char text[], size_t byteLength, const SkScalar pos[], SkScalar constY, int scalarsPerPosition) { SkASSERT(byteLength == 0 || text != NULL); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); // nothing to draw if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { return; } // This is the fast path. Here we do not bake in the device-transform to // the glyph outline or the advances. This is because we do not need to // position the glyphs at all, since the caller has done the positioning. // The positioning is based on SkPaint::measureText of individual // glyphs. That already uses glyph cache without device transforms. Device // transform is not part of SkPaint::measureText API, and thus we use the // same glyphs as what were measured. const float textTranslateY = (1 == scalarsPerPosition ? constY : 0); this->init(paint, skPaint, byteLength, kMaxPerformance_RenderMode, textTranslateY); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); const char* stop = text + byteLength; if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { if (1 == scalarsPerPosition) { fTransformType = GrPathRendering::kTranslateX_PathTransformType; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { this->appendGlyph(glyph.getGlyphID(), *pos); } pos++; } } else { SkASSERT(2 == scalarsPerPosition); fTransformType = GrPathRendering::kTranslate_PathTransformType; while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { this->appendGlyph(glyph.getGlyphID(), pos[0], pos[1]); } pos += 2; } } } else { fTransformType = GrPathRendering::kTranslate_PathTransformType; SkTextMapStateProc tmsProc(SkMatrix::I(), 0, scalarsPerPosition); SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); while (text < stop) { const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); if (glyph.fWidth) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint loc; alignProc(tmsLoc, glyph, &loc); this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); } pos += scalarsPerPosition; } } this->finish(); }