| Index: src/gpu/GrBitmapTextContext.cpp
|
| diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
|
| index 605703d1c62906ff579c84a4e923d972e92003a3..efce516b79789f245e548822c9440da1413e8894 100755
|
| --- a/src/gpu/GrBitmapTextContext.cpp
|
| +++ b/src/gpu/GrBitmapTextContext.cpp
|
| @@ -48,507 +48,6 @@ static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
|
|
|
| static const int kVerticesPerGlyph = 4;
|
| static const int kIndicesPerGlyph = 6;
|
| -};
|
| -
|
| -// TODO
|
| -// More tests
|
| -// move to SkCache
|
| -// handle textblobs where the whole run is larger than the cache size
|
| -// TODO implement micro speedy hash map for fast refing of glyphs
|
| -
|
| -GrBitmapTextContextB::GrBitmapTextContextB(GrContext* context,
|
| - SkGpuDevice* gpuDevice,
|
| - const SkDeviceProperties& properties)
|
| - : INHERITED(context, gpuDevice, properties) {
|
| - fCurrStrike = NULL;
|
| -}
|
| -
|
| -void GrBitmapTextContextB::ClearCacheEntry(uint32_t key, BitmapTextBlob** blob) {
|
| - (*blob)->unref();
|
| -}
|
| -
|
| -GrBitmapTextContextB::~GrBitmapTextContextB() {
|
| - fCache.foreach(&GrBitmapTextContextB::ClearCacheEntry);
|
| -}
|
| -
|
| -GrBitmapTextContextB* GrBitmapTextContextB::Create(GrContext* context,
|
| - SkGpuDevice* gpuDevice,
|
| - const SkDeviceProperties& props) {
|
| - return SkNEW_ARGS(GrBitmapTextContextB, (context, gpuDevice, props));
|
| -}
|
| -
|
| -bool GrBitmapTextContextB::canDraw(const GrRenderTarget*,
|
| - const GrClip&,
|
| - const GrPaint&,
|
| - const SkPaint& skPaint,
|
| - const SkMatrix& viewMatrix) {
|
| - return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix);
|
| -}
|
| -
|
| -inline void GrBitmapTextContextB::init(GrRenderTarget* rt, const GrClip& clip,
|
| - const GrPaint& paint, const SkPaint& skPaint,
|
| - const SkIRect& regionClipBounds) {
|
| - INHERITED::init(rt, clip, paint, skPaint, regionClipBounds);
|
| -
|
| - fCurrStrike = NULL;
|
| -}
|
| -
|
| -bool GrBitmapTextContextB::MustRegenerateBlob(const BitmapTextBlob& blob, const SkPaint& paint,
|
| - const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
|
| - // We always regenerate blobs with patheffects or mask filters we could cache these
|
| - // TODO find some way to cache the maskfilter / patheffects on the textblob
|
| - return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY != y ||
|
| - paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() != blob.fStyle;
|
| -}
|
| -
|
| -
|
| -inline SkGlyphCache* GrBitmapTextContextB::setupCache(BitmapTextBlob::Run* run,
|
| - const SkPaint& skPaint,
|
| - const SkMatrix& viewMatrix) {
|
| - skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &viewMatrix, false);
|
| - run->fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
|
| - return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc());
|
| -}
|
| -
|
| -inline void GrBitmapTextContextB::BlobGlyphCount(int* glyphCount, int* runCount,
|
| - const SkTextBlob* blob) {
|
| - SkTextBlob::RunIterator itCounter(blob);
|
| - for (; !itCounter.done(); itCounter.next(), (*runCount)++) {
|
| - *glyphCount += itCounter.glyphCount();
|
| - }
|
| -}
|
| -
|
| -GrBitmapTextContextB::BitmapTextBlob* GrBitmapTextContextB::CreateBlob(int glyphCount,
|
| - int runCount) {
|
| - // We allocate size for the BitmapTextBlob itself, plus size for the vertices array,
|
| - // and size for the glyphIds array.
|
| - SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
|
| - vertex_attribute_changed);
|
| - size_t verticesCount = glyphCount * kVerticesPerGlyph * kGrayTextVASize;
|
| - size_t length = sizeof(BitmapTextBlob) +
|
| - verticesCount +
|
| - glyphCount * sizeof(GrGlyph::PackedID) +
|
| - sizeof(BitmapTextBlob::Run) * runCount;
|
| -
|
| - BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(sk_malloc_throw(length), BitmapTextBlob);
|
| -
|
| - // setup offsets for vertices / glyphs
|
| - cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
|
| - cacheBlob->fGlyphIDs =
|
| - reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + verticesCount);
|
| - cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphIDs + glyphCount);
|
| -
|
| - // Initialize runs
|
| - for (int i = 0; i < runCount; i++) {
|
| - SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run);
|
| - }
|
| - cacheBlob->fRunCount = runCount;
|
| - return cacheBlob;
|
| -}
|
| -
|
| -void GrBitmapTextContextB::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
|
| - const SkPaint& skPaint, const SkMatrix& viewMatrix,
|
| - const SkTextBlob* blob, SkScalar x, SkScalar y,
|
| - SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
|
| - BitmapTextBlob* cacheBlob;
|
| - BitmapTextBlob** foundBlob = fCache.find(blob->uniqueID());
|
| - SkIRect clipRect;
|
| - clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
|
| -
|
| - if (foundBlob) {
|
| - cacheBlob = *foundBlob;
|
| - if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) {
|
| - // We have to remake the blob because changes may invalidate our masks.
|
| - // TODO we could probably get away reuse most of the time if the pointer is unique,
|
| - // but we'd have to clear the subrun information
|
| - cacheBlob->unref();
|
| - int glyphCount = 0;
|
| - int runCount = 0;
|
| - BlobGlyphCount(&glyphCount, &runCount, blob);
|
| - cacheBlob = CreateBlob(glyphCount, runCount);
|
| - fCache.set(blob->uniqueID(), cacheBlob);
|
| - this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter,
|
| - clipRect);
|
| - }
|
| - } else {
|
| - int glyphCount = 0;
|
| - int runCount = 0;
|
| - BlobGlyphCount(&glyphCount, &runCount, blob);
|
| - cacheBlob = CreateBlob(glyphCount, runCount);
|
| - fCache.set(blob->uniqueID(), cacheBlob);
|
| - this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect);
|
| - }
|
| -
|
| - // Though for the time being runs in the textblob can override the paint, they only touch font
|
| - // info.
|
| - GrPaint grPaint;
|
| - SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint);
|
| -
|
| - this->flush(fContext->getTextTarget(), cacheBlob, rt, grPaint, clip, viewMatrix,
|
| - fSkPaint.getAlpha());
|
| -}
|
| -
|
| -void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
|
| - const SkPaint& skPaint, const SkMatrix& viewMatrix,
|
| - const SkTextBlob* blob, SkScalar x, SkScalar y,
|
| - SkDrawFilter* drawFilter, const SkIRect& clipRect) {
|
| - cacheBlob->fViewMatrix = viewMatrix;
|
| - cacheBlob->fX = x;
|
| - cacheBlob->fY = y;
|
| - cacheBlob->fStyle = skPaint.getStyle();
|
| -
|
| - // Regenerate textblob
|
| - SkPaint runPaint = skPaint;
|
| - SkTextBlob::RunIterator it(blob);
|
| - for (int run = 0; !it.done(); it.next(), run++) {
|
| - int glyphCount = it.glyphCount();
|
| - size_t textLen = glyphCount * sizeof(uint16_t);
|
| - const SkPoint& offset = it.offset();
|
| - // applyFontToPaint() always overwrites the exact same attributes,
|
| - // so it is safe to not re-seed the paint for this reason.
|
| - it.applyFontToPaint(&runPaint);
|
| -
|
| - if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
|
| - // A false return from filter() means we should abort the current draw.
|
| - runPaint = skPaint;
|
| - continue;
|
| - }
|
| -
|
| - runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
|
| -
|
| - SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix);
|
| -
|
| - // setup vertex / glyphIndex for the new run
|
| - if (run > 0) {
|
| - PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back();
|
| - PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back();
|
| -
|
| - newRun.fVertexStartIndex = lastRun.fVertexEndIndex;
|
| - newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
|
| -
|
| - newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
|
| - newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
|
| - }
|
| -
|
| - switch (it.positioning()) {
|
| - case SkTextBlob::kDefault_Positioning:
|
| - this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatrix,
|
| - (const char *)it.glyphs(), textLen,
|
| - x + offset.x(), y + offset.y(), clipRect);
|
| - break;
|
| - case SkTextBlob::kHorizontal_Positioning:
|
| - this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix,
|
| - (const char*)it.glyphs(), textLen, it.pos(), 1,
|
| - SkPoint::Make(x, y + offset.y()), clipRect);
|
| - break;
|
| - case SkTextBlob::kFull_Positioning:
|
| - this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix,
|
| - (const char*)it.glyphs(), textLen, it.pos(), 2,
|
| - SkPoint::Make(x, y), clipRect);
|
| - break;
|
| - }
|
| -
|
| - if (drawFilter) {
|
| - // A draw filter may change the paint arbitrarily, so we must re-seed in this case.
|
| - runPaint = skPaint;
|
| - }
|
| -
|
| - SkGlyphCache::AttachCache(cache);
|
| - }
|
| -}
|
| -
|
| -void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip,
|
| - const GrPaint& paint, const SkPaint& skPaint,
|
| - const SkMatrix& viewMatrix,
|
| - const char text[], size_t byteLength,
|
| - SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
|
| - int glyphCount = skPaint.countText(text, byteLength);
|
| - SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
|
| - blob->fViewMatrix = viewMatrix;
|
| - blob->fX = x;
|
| - blob->fY = y;
|
| - blob->fStyle = skPaint.getStyle();
|
| -
|
| - SkIRect clipRect;
|
| - clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
|
| -
|
| - // setup cache
|
| - SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix);
|
| - this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, x, y, clipRect);
|
| - SkGlyphCache::AttachCache(cache);
|
| -
|
| - this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, skPaint.getAlpha());
|
| -}
|
| -
|
| -void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex,
|
| - SkGlyphCache* cache, const SkPaint& skPaint,
|
| - const SkMatrix& viewMatrix,
|
| - const char text[], size_t byteLength,
|
| - SkScalar x, SkScalar y, const SkIRect& clipRect) {
|
| - SkASSERT(byteLength == 0 || text != NULL);
|
| -
|
| - // nothing to draw
|
| - if (text == NULL || byteLength == 0) {
|
| - return;
|
| - }
|
| -
|
| - fCurrStrike = NULL;
|
| - SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
|
| -
|
| - // Get GrFontScaler from cache
|
| - GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
| -
|
| - // transform our starting point
|
| - {
|
| - SkPoint loc;
|
| - viewMatrix.mapXY(x, y, &loc);
|
| - x = loc.fX;
|
| - y = loc.fY;
|
| - }
|
| -
|
| - // need to measure first
|
| - if (skPaint.getTextAlign() != SkPaint::kLeft_Align) {
|
| - SkVector stopVector;
|
| - MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
|
| -
|
| - SkScalar stopX = stopVector.fX;
|
| - SkScalar stopY = stopVector.fY;
|
| -
|
| - if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
| - stopX = SkScalarHalf(stopX);
|
| - stopY = SkScalarHalf(stopY);
|
| - }
|
| - x -= stopX;
|
| - y -= stopY;
|
| - }
|
| -
|
| - const char* stop = text + byteLength;
|
| -
|
| - SkAutoKern autokern;
|
| -
|
| - SkFixed fxMask = ~0;
|
| - SkFixed fyMask = ~0;
|
| - SkScalar halfSampleX, halfSampleY;
|
| - if (cache->isSubpixel()) {
|
| - halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
|
| - SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
|
| - if (kX_SkAxisAlignment == baseline) {
|
| - fyMask = 0;
|
| - halfSampleY = SK_ScalarHalf;
|
| - } else if (kY_SkAxisAlignment == baseline) {
|
| - fxMask = 0;
|
| - halfSampleX = SK_ScalarHalf;
|
| - }
|
| - } else {
|
| - halfSampleX = halfSampleY = SK_ScalarHalf;
|
| - }
|
| -
|
| - Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
|
| - Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
|
| -
|
| - while (text < stop) {
|
| - const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
|
| -
|
| - fx += autokern.adjust(glyph);
|
| -
|
| - if (glyph.fWidth) {
|
| - this->appendGlyph(blob,
|
| - runIndex,
|
| - GrGlyph::Pack(glyph.getGlyphID(),
|
| - glyph.getSubXFixed(),
|
| - glyph.getSubYFixed(),
|
| - GrGlyph::kCoverage_MaskStyle),
|
| - Sk48Dot16FloorToInt(fx),
|
| - Sk48Dot16FloorToInt(fy),
|
| - fontScaler,
|
| - clipRect);
|
| - }
|
| -
|
| - fx += glyph.fAdvanceX;
|
| - fy += glyph.fAdvanceY;
|
| - }
|
| -}
|
| -
|
| -void GrBitmapTextContextB::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, const SkIRect& regionClipBounds) {
|
| - int glyphCount = skPaint.countText(text, byteLength);
|
| - SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
|
| - blob->fStyle = skPaint.getStyle();
|
| - blob->fViewMatrix = viewMatrix;
|
| -
|
| - SkIRect clipRect;
|
| - clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
|
| -
|
| - // setup cache
|
| - SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix);
|
| - this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, pos,
|
| - scalarsPerPosition, offset, clipRect);
|
| - SkGlyphCache::AttachCache(cache);
|
| -
|
| - this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, fSkPaint.getAlpha());
|
| -}
|
| -
|
| -void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runIndex,
|
| - SkGlyphCache* cache, const SkPaint& skPaint,
|
| - const SkMatrix& viewMatrix,
|
| - const char text[], size_t byteLength,
|
| - const SkScalar pos[], int scalarsPerPosition,
|
| - const SkPoint& offset, const SkIRect& clipRect) {
|
| - SkASSERT(byteLength == 0 || text != NULL);
|
| - SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
|
| -
|
| - // nothing to draw
|
| - if (text == NULL || byteLength == 0) {
|
| - return;
|
| - }
|
| -
|
| - fCurrStrike = NULL;
|
| - SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
|
| -
|
| - // Get GrFontScaler from cache
|
| - GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
| -
|
| - const char* stop = text + byteLength;
|
| - SkTextAlignProc alignProc(skPaint.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 == skPaint.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(blob,
|
| - runIndex,
|
| - GrGlyph::Pack(glyph.getGlyphID(),
|
| - glyph.getSubXFixed(),
|
| - glyph.getSubYFixed(),
|
| - GrGlyph::kCoverage_MaskStyle),
|
| - Sk48Dot16FloorToInt(fx),
|
| - Sk48Dot16FloorToInt(fy),
|
| - fontScaler,
|
| - clipRect);
|
| - }
|
| - 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(blob,
|
| - runIndex,
|
| - GrGlyph::Pack(glyph.getGlyphID(),
|
| - glyph.getSubXFixed(),
|
| - glyph.getSubYFixed(),
|
| - GrGlyph::kCoverage_MaskStyle),
|
| - Sk48Dot16FloorToInt(fx),
|
| - Sk48Dot16FloorToInt(fy),
|
| - fontScaler,
|
| - clipRect);
|
| - }
|
| - pos += scalarsPerPosition;
|
| - }
|
| - }
|
| - } else { // not subpixel
|
| -
|
| - if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
|
| - while (text < stop) {
|
| - // the last 2 parameters are ignored
|
| - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
| -
|
| - if (glyph.fWidth) {
|
| - SkPoint tmsLoc;
|
| - tmsProc(pos, &tmsLoc);
|
| -
|
| - Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
|
| - Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
|
| - this->appendGlyph(blob,
|
| - runIndex,
|
| - GrGlyph::Pack(glyph.getGlyphID(),
|
| - glyph.getSubXFixed(),
|
| - glyph.getSubYFixed(),
|
| - GrGlyph::kCoverage_MaskStyle),
|
| - Sk48Dot16FloorToInt(fx),
|
| - Sk48Dot16FloorToInt(fy),
|
| - fontScaler,
|
| - clipRect);
|
| - }
|
| - pos += scalarsPerPosition;
|
| - }
|
| - } else {
|
| - while (text < stop) {
|
| - // the last 2 parameters are ignored
|
| - const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
| -
|
| - if (glyph.fWidth) {
|
| - SkPoint tmsLoc;
|
| - tmsProc(pos, &tmsLoc);
|
| -
|
| - SkPoint alignLoc;
|
| - alignProc(tmsLoc, glyph, &alignLoc);
|
| -
|
| - Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf); //halfSampleX;
|
| - Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf); //halfSampleY;
|
| - this->appendGlyph(blob,
|
| - runIndex,
|
| - GrGlyph::Pack(glyph.getGlyphID(),
|
| - glyph.getSubXFixed(),
|
| - glyph.getSubYFixed(),
|
| - GrGlyph::kCoverage_MaskStyle),
|
| - Sk48Dot16FloorToInt(fx),
|
| - Sk48Dot16FloorToInt(fy),
|
| - fontScaler,
|
| - clipRect);
|
| - }
|
| - pos += scalarsPerPosition;
|
| - }
|
| - }
|
| - }
|
| -}
|
|
|
| static size_t get_vertex_stride(GrMaskFormat maskFormat) {
|
| switch (maskFormat) {
|
| @@ -561,501 +60,8 @@ static size_t get_vertex_stride(GrMaskFormat maskFormat) {
|
| }
|
| }
|
|
|
| -void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph::PackedID packed,
|
| - int vx, int vy, GrFontScaler* scaler,
|
| - const SkIRect& clipRect) {
|
| - if (NULL == fCurrStrike) {
|
| - fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
|
| - }
|
| -
|
| - GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
|
| - if (NULL == glyph || glyph->fBounds.isEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - int x = vx + glyph->fBounds.fLeft;
|
| - int y = vy + glyph->fBounds.fTop;
|
| -
|
| - // keep them as ints until we've done the clip-test
|
| - int width = glyph->fBounds.width();
|
| - int height = glyph->fBounds.height();
|
| -
|
| - // check if we clipped out
|
| - if (clipRect.quickReject(x, y, x + width, y + height)) {
|
| - return;
|
| - }
|
| -
|
| - // If the glyph is too large we fall back to paths
|
| - if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
|
| - if (NULL == glyph->fPath) {
|
| - SkPath* path = SkNEW(SkPath);
|
| - if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
|
| - // flag the glyph as being dead?
|
| - SkDELETE(path);
|
| - return;
|
| - }
|
| - glyph->fPath = path;
|
| - }
|
| - SkASSERT(glyph->fPath);
|
| - blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, vy));
|
| - return;
|
| - }
|
| -
|
| - Run& run = blob->fRuns[runIndex];
|
| -
|
| - GrMaskFormat format = glyph->fMaskFormat;
|
| -
|
| - PerSubRunInfo* subRun = &run.fSubRunInfo.back();
|
| - if (run.fInitialized && subRun->fMaskFormat != format) {
|
| - PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back();
|
| - newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex;
|
| - newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex;
|
| -
|
| - newSubRun->fVertexStartIndex = subRun->fVertexEndIndex;
|
| - newSubRun->fVertexEndIndex = subRun->fVertexEndIndex;
|
| -
|
| - subRun = newSubRun;
|
| - }
|
| -
|
| - run.fInitialized = true;
|
| - subRun->fMaskFormat = format;
|
| - blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
|
| -
|
| - size_t vertexStride = get_vertex_stride(format);
|
| -
|
| - SkRect r;
|
| - r.fLeft = SkIntToScalar(x);
|
| - r.fTop = SkIntToScalar(y);
|
| - r.fRight = r.fLeft + SkIntToScalar(width);
|
| - r.fBottom = r.fTop + SkIntToScalar(height);
|
| -
|
| - run.fVertexBounds.joinNonEmptyArg(r);
|
| - GrColor color = fPaint.getColor();
|
| - run.fColor = color;
|
| -
|
| - intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVertexEndIndex);
|
| -
|
| - // V0
|
| - SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
|
| - position->set(r.fLeft, r.fTop);
|
| - if (kA8_GrMaskFormat == format) {
|
| - SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
|
| - *colorPtr = color;
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V1
|
| - position = reinterpret_cast<SkPoint*>(vertex);
|
| - position->set(r.fLeft, r.fBottom);
|
| - if (kA8_GrMaskFormat == format) {
|
| - SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
|
| - *colorPtr = color;
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V2
|
| - position = reinterpret_cast<SkPoint*>(vertex);
|
| - position->set(r.fRight, r.fBottom);
|
| - if (kA8_GrMaskFormat == format) {
|
| - SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
|
| - *colorPtr = color;
|
| - }
|
| - vertex += vertexStride;
|
| -
|
| - // V3
|
| - position = reinterpret_cast<SkPoint*>(vertex);
|
| - position->set(r.fRight, r.fTop);
|
| - if (kA8_GrMaskFormat == format) {
|
| - SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
|
| - *colorPtr = color;
|
| - }
|
| -
|
| - subRun->fGlyphEndIndex++;
|
| - subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
|
| -}
|
| -
|
| -class BitmapTextBatch : public GrBatch {
|
| -public:
|
| - typedef GrBitmapTextContextB::BitmapTextBlob Blob;
|
| - typedef Blob::Run Run;
|
| - typedef Run::SubRunInfo TextInfo;
|
| - struct Geometry {
|
| - Geometry() {}
|
| - Geometry(const Geometry& geometry)
|
| - : fBlob(SkRef(geometry.fBlob.get()))
|
| - , fRun(geometry.fRun)
|
| - , fSubRun(geometry.fSubRun)
|
| - , fColor(geometry.fColor) {}
|
| - SkAutoTUnref<Blob> fBlob;
|
| - int fRun;
|
| - int fSubRun;
|
| - GrColor fColor;
|
| - };
|
| -
|
| - static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
|
| - int glyphCount, GrBatchFontCache* fontCache) {
|
| - return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, glyphCount, fontCache));
|
| - }
|
| -
|
| - const char* name() const override { return "BitmapTextBatch"; }
|
| -
|
| - void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
|
| - if (kARGB_GrMaskFormat == fMaskFormat) {
|
| - out->setUnknownFourComponents();
|
| - } else {
|
| - out->setKnownFourComponents(fBatch.fColor);
|
| - }
|
| - }
|
| -
|
| - void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
|
| - if (kARGB_GrMaskFormat != fMaskFormat) {
|
| - if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
|
| - out->setUnknownSingleComponent();
|
| - } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
|
| - out->setUnknownOpaqueFourComponents();
|
| - out->setUsingLCDCoverage();
|
| - } else {
|
| - out->setUnknownFourComponents();
|
| - out->setUsingLCDCoverage();
|
| - }
|
| - } else {
|
| - out->setKnownSingleComponent(0xff);
|
| - }
|
| - }
|
| -
|
| - void initBatchTracker(const GrPipelineInfo& init) override {
|
| - // Handle any color overrides
|
| - if (init.fColorIgnored) {
|
| - fBatch.fColor = GrColor_ILLEGAL;
|
| - } else if (GrColor_ILLEGAL != init.fOverrideColor) {
|
| - fBatch.fColor = init.fOverrideColor;
|
| - }
|
| -
|
| - // setup batch properties
|
| - fBatch.fColorIgnored = init.fColorIgnored;
|
| - fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
|
| - fBatch.fCoverageIgnored = init.fCoverageIgnored;
|
| - }
|
| -
|
| - void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
|
| - // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
|
| - // TODO actually only invert if we don't have RGBA
|
| - SkMatrix localMatrix;
|
| - if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
|
| - SkDebugf("Cannot invert viewmatrix\n");
|
| - return;
|
| - }
|
| -
|
| - GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
|
| - // This will be ignored in the non A8 case
|
| - bool opaqueVertexColors = GrColorIsOpaque(this->color());
|
| - SkAutoTUnref<const GrGeometryProcessor> gp(
|
| - GrBitmapTextGeoProc::Create(this->color(),
|
| - fFontCache->getTexture(fMaskFormat),
|
| - params,
|
| - fMaskFormat,
|
| - opaqueVertexColors,
|
| - localMatrix));
|
| -
|
| - size_t vertexStride = gp->getVertexStride();
|
| - SkASSERT(vertexStride == get_vertex_stride(fMaskFormat));
|
| -
|
| - this->initDraw(batchTarget, gp, pipeline);
|
| -
|
| - int glyphCount = this->numGlyphs();
|
| - int instanceCount = fGeoData.count();
|
| - const GrVertexBuffer* vertexBuffer;
|
| - int firstVertex;
|
| -
|
| - void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
|
| - glyphCount * kVerticesPerGlyph,
|
| - &vertexBuffer,
|
| - &firstVertex);
|
| - if (!vertices) {
|
| - SkDebugf("Could not allocate vertices\n");
|
| - return;
|
| - }
|
| -
|
| - unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
|
| -
|
| - // setup drawinfo
|
| - const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
|
| - int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
|
| -
|
| - GrDrawTarget::DrawInfo drawInfo;
|
| - drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
|
| - drawInfo.setStartVertex(0);
|
| - drawInfo.setStartIndex(0);
|
| - drawInfo.setVerticesPerInstance(kVerticesPerGlyph);
|
| - drawInfo.setIndicesPerInstance(kIndicesPerGlyph);
|
| - drawInfo.adjustStartVertex(firstVertex);
|
| - drawInfo.setVertexBuffer(vertexBuffer);
|
| - drawInfo.setIndexBuffer(quadIndexBuffer);
|
| -
|
| - int instancesToFlush = 0;
|
| - for (int i = 0; i < instanceCount; i++) {
|
| - Geometry& args = fGeoData[i];
|
| - Blob* blob = args.fBlob;
|
| - Run& run = blob->fRuns[args.fRun];
|
| - TextInfo& info = run.fSubRunInfo[args.fSubRun];
|
| -
|
| - uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
|
| - bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen;
|
| - bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
|
| - int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
|
| -
|
| - // We regenerate both texture coords and colors in the blob itself, and update the
|
| - // atlas generation. If we don't end up purging any unused plots, we can avoid
|
| - // regenerating the coords. We could take a finer grained approach to updating texture
|
| - // coords but its not clear if the extra bookkeeping would offset any gains.
|
| - // To avoid looping over the glyphs twice, we do one loop and conditionally update color
|
| - // or coords as needed. One final note, if we have to break a run for an atlas eviction
|
| - // then we can't really trust the atlas has all of the correct data. Atlas evictions
|
| - // should be pretty rare, so we just always regenerate in those cases
|
| - if (regenerateTextureCoords || regenerateColors) {
|
| - // first regenerate texture coordinates / colors if need be
|
| - const SkDescriptor* desc = NULL;
|
| - SkGlyphCache* cache = NULL;
|
| - GrFontScaler* scaler = NULL;
|
| - GrBatchTextStrike* strike = NULL;
|
| - bool brokenRun = false;
|
| - if (regenerateTextureCoords) {
|
| - desc = run.fDescriptor.getDesc();
|
| - cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
|
| - scaler = GrTextContext::GetGrFontScaler(cache);
|
| - strike = fFontCache->getStrike(scaler);
|
| - }
|
| - for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
|
| - GrGlyph::PackedID glyphID = blob->fGlyphIDs[glyphIdx + info.fGlyphStartIndex];
|
| -
|
| - if (regenerateTextureCoords) {
|
| - // Upload the glyph only if needed
|
| - GrGlyph* glyph = strike->getGlyph(glyphID, scaler);
|
| - SkASSERT(glyph);
|
| -
|
| - if (!fFontCache->hasGlyph(glyph) &&
|
| - !strike->addGlyphToAtlas(batchTarget, glyph, scaler)) {
|
| - this->flush(batchTarget, &drawInfo, instancesToFlush,
|
| - maxInstancesPerDraw);
|
| - this->initDraw(batchTarget, gp, pipeline);
|
| - instancesToFlush = 0;
|
| - brokenRun = glyphIdx > 0;
|
| -
|
| - SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(batchTarget, glyph,
|
| - scaler);
|
| - SkASSERT(success);
|
| - }
|
| -
|
| - fFontCache->setGlyphRefToken(glyph, batchTarget->currentToken());
|
| -
|
| - // Texture coords are the last vertex attribute so we get a pointer to the
|
| - // first one and then map with stride in regenerateTextureCoords
|
| - intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
|
| - vertex += info.fVertexStartIndex;
|
| - vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
|
| - vertex += vertexStride - sizeof(SkIPoint16);
|
| -
|
| - this->regenerateTextureCoords(glyph, vertex, vertexStride);
|
| - }
|
| -
|
| - if (regenerateColors) {
|
| - intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
|
| - vertex += info.fVertexStartIndex;
|
| - vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint);
|
| - this->regenerateColors(vertex, vertexStride, args.fColor);
|
| - }
|
| -
|
| - instancesToFlush++;
|
| - }
|
| -
|
| - if (regenerateTextureCoords) {
|
| - SkGlyphCache::AttachCache(cache);
|
| - info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration :
|
| - fFontCache->atlasGeneration(fMaskFormat);
|
| - }
|
| - } else {
|
| - instancesToFlush += glyphCount;
|
| - }
|
| -
|
| - // now copy all vertices
|
| - size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex;
|
| - memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount);
|
| -
|
| - currVertex += byteCount;
|
| - }
|
| -
|
| - this->flush(batchTarget, &drawInfo, instancesToFlush, maxInstancesPerDraw);
|
| - }
|
| -
|
| - SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
|
| -
|
| -private:
|
| - BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
|
| - int glyphCount, GrBatchFontCache* fontCache)
|
| - : fMaskFormat(maskFormat)
|
| - , fPixelConfig(fontCache->getPixelConfig(maskFormat))
|
| - , fFontCache(fontCache) {
|
| - this->initClassID<BitmapTextBatch>();
|
| - fGeoData.push_back(geometry);
|
| - fBatch.fColor = color;
|
| - fBatch.fViewMatrix = geometry.fBlob->fViewMatrix;
|
| - fBatch.fNumGlyphs = glyphCount;
|
| - }
|
| -
|
| - void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexStride) {
|
| - int width = glyph->fBounds.width();
|
| - int height = glyph->fBounds.height();
|
| - int u0 = glyph->fAtlasLocation.fX;
|
| - int v0 = glyph->fAtlasLocation.fY;
|
| - int u1 = u0 + width;
|
| - int v1 = v0 + height;
|
| -
|
| - // we assume texture coords are the last vertex attribute, this is a bit fragile.
|
| - // TODO pass in this offset or something
|
| - SkIPoint16* textureCoords;
|
| - // V0
|
| - textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
|
| - textureCoords->set(u0, v0);
|
| - vertex += vertexStride;
|
| -
|
| - // V1
|
| - textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
|
| - textureCoords->set(u0, v1);
|
| - vertex += vertexStride;
|
| -
|
| - // V2
|
| - textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
|
| - textureCoords->set(u1, v1);
|
| - vertex += vertexStride;
|
| -
|
| - // V3
|
| - textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
|
| - textureCoords->set(u1, v0);
|
| - }
|
| -
|
| - void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) {
|
| - for (int i = 0; i < kVerticesPerGlyph; i++) {
|
| - SkColor* vcolor = reinterpret_cast<SkColor*>(vertex);
|
| - *vcolor = color;
|
| - vertex += vertexStride;
|
| - }
|
| - }
|
| -
|
| - void initDraw(GrBatchTarget* batchTarget,
|
| - const GrGeometryProcessor* gp,
|
| - const GrPipeline* pipeline) {
|
| - batchTarget->initDraw(gp, pipeline);
|
| -
|
| - // TODO remove this when batch is everywhere
|
| - GrPipelineInfo init;
|
| - init.fColorIgnored = fBatch.fColorIgnored;
|
| - init.fOverrideColor = GrColor_ILLEGAL;
|
| - init.fCoverageIgnored = fBatch.fCoverageIgnored;
|
| - init.fUsesLocalCoords = this->usesLocalCoords();
|
| - gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
|
| - }
|
| -
|
| - void flush(GrBatchTarget* batchTarget,
|
| - GrDrawTarget::DrawInfo* drawInfo,
|
| - int instanceCount,
|
| - int maxInstancesPerDraw) {
|
| - while (instanceCount) {
|
| - drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
|
| - drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verticesPerInstance());
|
| - drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indicesPerInstance());
|
| -
|
| - batchTarget->draw(*drawInfo);
|
| -
|
| - drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexCount());
|
| - instanceCount -= drawInfo->instanceCount();
|
| - }
|
| - }
|
| -
|
| - GrColor color() const { return fBatch.fColor; }
|
| - const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
|
| - bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
|
| - int numGlyphs() const { return fBatch.fNumGlyphs; }
|
| -
|
| - bool onCombineIfPossible(GrBatch* t) override {
|
| - BitmapTextBatch* that = t->cast<BitmapTextBatch>();
|
| -
|
| - if (this->fMaskFormat != that->fMaskFormat) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->color()) {
|
| - return false;
|
| - }
|
| -
|
| - if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
|
| - return false;
|
| - }
|
| -
|
| - fBatch.fNumGlyphs += that->numGlyphs();
|
| - fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
|
| - return true;
|
| - }
|
| -
|
| - struct BatchTracker {
|
| - GrColor fColor;
|
| - SkMatrix fViewMatrix;
|
| - bool fUsesLocalCoords;
|
| - bool fColorIgnored;
|
| - bool fCoverageIgnored;
|
| - int fNumGlyphs;
|
| - };
|
| -
|
| - BatchTracker fBatch;
|
| - SkSTArray<1, Geometry, true> fGeoData;
|
| - GrMaskFormat fMaskFormat;
|
| - GrPixelConfig fPixelConfig;
|
| - GrBatchFontCache* fFontCache;
|
| };
|
|
|
| -void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrRenderTarget* rt,
|
| - const GrPaint& paint, const GrClip& clip,
|
| - const SkMatrix& viewMatrix, int paintAlpha) {
|
| - GrPipelineBuilder pipelineBuilder;
|
| - pipelineBuilder.setFromPaint(paint, rt, clip);
|
| -
|
| - GrColor color = paint.getColor();
|
| - for (uint32_t run = 0; run < blob->fRunCount; run++) {
|
| - for (int subRun = 0; subRun < blob->fRuns[run].fSubRunInfo.count(); subRun++) {
|
| - PerSubRunInfo& info = blob->fRuns[run].fSubRunInfo[subRun];
|
| - int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
|
| - if (0 == glyphCount) {
|
| - continue;
|
| - }
|
| -
|
| - GrMaskFormat format = info.fMaskFormat;
|
| - if (kARGB_GrMaskFormat == format) {
|
| - color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha);
|
| - }
|
| -
|
| - BitmapTextBatch::Geometry geometry;
|
| - geometry.fBlob.reset(SkRef(blob));
|
| - geometry.fRun = run;
|
| - geometry.fSubRun = subRun;
|
| - geometry.fColor = color;
|
| - SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, glyphCount,
|
| - fContext->getBatchFontCache()));
|
| -
|
| - target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertexBounds);
|
| - }
|
| - }
|
| -
|
| - // Now flush big glyphs
|
| - for (int i = 0; i < blob->fBigGlyphs.count(); i++) {
|
| - BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i];
|
| - SkMatrix translate;
|
| - translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGlyph.fVy));
|
| - SkPath tmpPath(bigGlyph.fPath);
|
| - tmpPath.transform(translate);
|
| - GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
|
| - fContext->drawPath(rt, clip, paint, SkMatrix::I(), tmpPath, strokeInfo);
|
| - }
|
| -}
|
| -
|
| GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
|
| SkGpuDevice* gpuDevice,
|
| const SkDeviceProperties& properties)
|
|
|