diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index 8212f71e1f..9e144ed278 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -258,8 +258,10 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { flushInfo.fGeometryProcessor = this->setupDfProcessor(fullAtlasManager); SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective()); } else { + GrSamplerState samplerState = fHasScaledGlyphs ? GrSamplerState::ClampBilerp() + : GrSamplerState::ClampNearest(); flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( - this->color(), proxies, atlasPageCount, GrSamplerState::ClampNearest(), maskFormat, + this->color(), proxies, atlasPageCount, samplerState, maskFormat, localMatrix, this->usesLocalCoords()); } @@ -349,8 +351,10 @@ void GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) co proxies, numProxies, GrSamplerState::ClampBilerp()); } } else { - reinterpret_cast(gp)->addNewProxies( - proxies, numProxies, GrSamplerState::ClampNearest()); + GrSamplerState samplerState = fHasScaledGlyphs ? GrSamplerState::ClampBilerp() + : GrSamplerState::ClampNearest(); + reinterpret_cast(gp)->addNewProxies(proxies, numProxies, + samplerState); } } @@ -398,6 +402,10 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) { return false; } + + if (fHasScaledGlyphs != that->fHasScaledGlyphs) { + return false; + } } // Keep the batch vertex buffer size below 32K so we don't have to create a special one diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index ae1c95b56e..9ba6c87b9c 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -41,8 +41,9 @@ public: }; static std::unique_ptr MakeBitmap( - GrPaint&& paint, GrMaskFormat maskFormat, - int glyphCount, GrRestrictedAtlasManager* restrictedAtlasManager) { + GrPaint&& paint, GrMaskFormat maskFormat, int glyphCount, + bool hasScaledGlyphs, + GrRestrictedAtlasManager* restrictedAtlasManager) { std::unique_ptr op(new GrAtlasTextOp(restrictedAtlasManager, std::move(paint))); @@ -60,6 +61,7 @@ public: op->fNumGlyphs = glyphCount; op->fGeoCount = 1; op->fLuminanceColor = 0; + op->fHasScaledGlyphs = hasScaledGlyphs; return op; } @@ -183,15 +185,18 @@ private: int fGeoDataAllocSize; uint32_t fSRGBFlags; GrProcessorSet fProcessors; - bool fUsesLocalCoords; - bool fCanCombineOnTouchOrOverlap; + struct { + uint32_t fUsesLocalCoords : 1; + uint32_t fCanCombineOnTouchOrOverlap : 1; + uint32_t fUseGammaCorrectDistanceTable : 1; + uint32_t fHasScaledGlyphs : 1; + }; int fGeoCount; int fNumGlyphs; MaskType fMaskType; // Distance field properties sk_sp fDistanceAdjustTable; SkColor fLuminanceColor; - bool fUseGammaCorrectDistanceTable; uint32_t fDFGPFlags = 0; typedef GrMeshDrawOp INHERITED; diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp index 8470370e1d..bd3d76814f 100644 --- a/src/gpu/text/GrAtlasTextBlob.cpp +++ b/src/gpu/text/GrAtlasTextBlob.cpp @@ -152,6 +152,7 @@ void GrAtlasTextBlob::appendGlyph(int runIndex, subRun->appendVertices(vertexStride); fGlyphs[subRun->glyphEndIndex()] = glyph; subRun->glyphAppended(); + subRun->setHasScaledGlyphs(SK_Scalar1 != scale); } void GrAtlasTextBlob::appendPathGlyph(int runIndex, const SkPath& path, SkScalar x, SkScalar y, @@ -264,8 +265,8 @@ inline std::unique_ptr GrAtlasTextBlob::makeOp( target->colorSpaceInfo().isGammaCorrect(), paint.luminanceColor(), info.hasUseLCDText(), useBGR, info.isAntiAliased()); } else { - op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, - glyphCount, restrictedAtlasManager); + op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, glyphCount, + info.hasScaledGlyphs(), restrictedAtlasManager); } GrAtlasTextOp::Geometry& geometry = op->geometry(); geometry.fViewMatrix = viewMatrix; @@ -355,9 +356,10 @@ void GrAtlasTextBlob::flush(GrRestrictedAtlasManager* restrictedAtlasManager, SkRect rtBounds = SkRect::MakeWH(target->width(), target->height()); SkRRect clipRRect; GrAA aa; - // We can clip geometrically if we're not using SDFs, + // We can clip geometrically if we're not using SDFs or scaled glyphs, // and we have an axis-aligned rectangular non-AA clip - if (!info.drawAsDistanceFields() && clip.isRRect(rtBounds, &clipRRect, &aa) && + if (!info.drawAsDistanceFields() && !info.hasScaledGlyphs() && + clip.isRRect(rtBounds, &clipRRect, &aa) && clipRRect.isRect() && GrAA::kNo == aa) { skipClip = true; // We only need to do clipping work if the subrun isn't contained by the clip diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h index 52771c7de1..b4a11a496d 100644 --- a/src/gpu/text/GrAtlasTextBlob.h +++ b/src/gpu/text/GrAtlasTextBlob.h @@ -435,13 +435,19 @@ private: fFlags = hasW ? (fFlags | kHasWCoord_Flag) : fFlags & ~kHasWCoord_Flag; } bool hasWCoord() const { return SkToBool(fFlags & kHasWCoord_Flag); } + void setHasScaledGlyphs(bool hasScaledGlyphs) { + fFlags = hasScaledGlyphs ? (fFlags | kHasScaledGlyphs_Flag) + : fFlags & ~kHasScaledGlyphs_Flag; + } + bool hasScaledGlyphs() const { return SkToBool(fFlags & kHasScaledGlyphs_Flag); } private: enum Flag { - kDrawAsSDF_Flag = 0x1, - kUseLCDText_Flag = 0x2, - kAntiAliased_Flag = 0x4, - kHasWCoord_Flag = 0x8 + kDrawAsSDF_Flag = 0x01, + kUseLCDText_Flag = 0x02, + kAntiAliased_Flag = 0x04, + kHasWCoord_Flag = 0x08, + kHasScaledGlyphs_Flag = 0x10 }; GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp index f574d6f046..296df22f51 100644 --- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp +++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp @@ -280,7 +280,8 @@ Regenerator::Result Regenerator::doRegen() { if (!fFullAtlasManager->hasGlyph(glyph) && !strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache, fFullAtlasManager, glyph, - fLazyCache->get(), fSubRun->maskFormat())) { + fLazyCache->get(), fSubRun->maskFormat(), + fSubRun->hasScaledGlyphs())) { fBrokenRun = glyphIdx > 0; result.fFinished = false; return result; diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp index 5ac683e6f3..4a10e101e2 100644 --- a/src/gpu/text/GrAtlasTextContext.cpp +++ b/src/gpu/text/GrAtlasTextContext.cpp @@ -856,6 +856,7 @@ void GrAtlasTextContext::FallbackTextHelper::appendText(const SkGlyph& glyph, in SkScalar scaledGlyphSize = maxDim * fMaxScale; if (!fViewMatrix.hasPerspective() && scaledGlyphSize > fMaxTextSize) { fUseScaledFallback = true; + fMaxTextSize -= 2; // Subtract 2 to account for the bilerp pad around the glyph } } diff --git a/src/gpu/text/GrGlyphCache.cpp b/src/gpu/text/GrGlyphCache.cpp index 7d899076b2..2372af815c 100644 --- a/src/gpu/text/GrGlyphCache.cpp +++ b/src/gpu/text/GrGlyphCache.cpp @@ -298,35 +298,57 @@ bool GrTextStrike::addGlyphToAtlas(GrResourceProvider* resourceProvider, GrAtlasManager* fullAtlasManager, GrGlyph* glyph, SkGlyphCache* cache, - GrMaskFormat expectedMaskFormat) { + GrMaskFormat expectedMaskFormat, + bool isScaledGlyph) { SkASSERT(glyph); SkASSERT(cache); SkASSERT(fCache.find(glyph->fPackedID)); int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); + int width = glyph->width(); + int height = glyph->height(); + int rowBytes = width * bytesPerPixel; size_t size = glyph->fBounds.area() * bytesPerPixel; + bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID); + bool addPad = isScaledGlyph && !isSDFGlyph; + if (addPad) { + width += 2; + rowBytes += 2*bytesPerPixel; + size += 2 * rowBytes; + height += 2; + size += 2 * (height + 2) * bytesPerPixel; + } SkAutoSMalloc<1024> storage(size); const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID); - if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) { - if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(), + if (isSDFGlyph) { + if (!get_packed_glyph_df_image(cache, skGlyph, width, height, storage.get())) { return false; } } else { + void* dataPtr = storage.get(); + if (addPad) { + sk_bzero(dataPtr, size); + dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel; + } if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(), - glyph->width() * bytesPerPixel, expectedMaskFormat, - storage.get())) { + rowBytes, expectedMaskFormat, + dataPtr)) { return false; } } bool success = fullAtlasManager->addToAtlas(resourceProvider, glyphCache, this, &glyph->fID, target, expectedMaskFormat, - glyph->width(), glyph->height(), + width, height, storage.get(), &glyph->fAtlasLocation); if (success) { + if (addPad) { + glyph->fAtlasLocation.fX += 1; + glyph->fAtlasLocation.fY += 1; + } SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID); fAtlasedGlyphs++; } diff --git a/src/gpu/text/GrGlyphCache.h b/src/gpu/text/GrGlyphCache.h index 8279814241..7e6056e6f5 100644 --- a/src/gpu/text/GrGlyphCache.h +++ b/src/gpu/text/GrGlyphCache.h @@ -65,7 +65,7 @@ public: // get the actual glyph image itself when we get the glyph metrics. bool addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, GrGlyphCache*, GrAtlasManager*, GrGlyph*, - SkGlyphCache*, GrMaskFormat expectedMaskFormat); + SkGlyphCache*, GrMaskFormat expectedMaskFormat, bool isScaledGlyph); // testing int countGlyphs() const { return fCache.count(); }