Force single glyph calls through bulk interface

Enance SkBulkGlyphMetrics, SkBulkGlyphMetricsAndPaths, and SkBulkGlyphMetricsAndImages
with single glyph calls. In addtion, add calls needed to have the rest of the system
work with these interfaces.

As a resulte move the glyph, prepareImage, and preparePath calls to private.

Change-Id: I8d383b649390e45f621dcb9d62fb8367a55cee02
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254056
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
Herb Derby 2019-11-11 18:01:36 -05:00 committed by Skia Commit-Bot
parent a9b348f66c
commit cb443a5928
12 changed files with 131 additions and 82 deletions

View File

@ -218,7 +218,6 @@ void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) {
void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) {
FlushInfo flushInfo;
SkExclusiveStrikePtr autoGlyphCache;
auto& context = target->context()->internal();
auto glyphCache = context.grContext()->priv().getGrStrikeCache();
auto atlasManager = context.grContext()->priv().getAtlasManager();
@ -234,8 +233,7 @@ void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) {
GrTextBlob::VertexRegenerator regenerator(
resourceProvider, fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun,
fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY,
fGeoData[i].fColor.toBytes_RGBA(), &context, glyphCache, atlasManager,
&autoGlyphCache);
fGeoData[i].fColor.toBytes_RGBA(), &context, glyphCache, atlasManager);
bool done = false;
while (!done) {
GrTextBlob::VertexRegenerator::Result result;

View File

@ -39,27 +39,18 @@ public:
std::unique_ptr<SkScalerContext> scaler,
const SkFontMetrics&);
// Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
// advances using a scaler.
SkGlyph* glyph(SkPackedGlyphID packedID);
// Return a glyph. Create it if it doesn't exist, and initialize with the prototype.
SkGlyph* glyphFromPrototype(const SkGlyphPrototype& p, void* image = nullptr);
// Return a glyph or nullptr if it does not exits in the strike.
SkGlyph* glyphOrNull(SkPackedGlyphID id) const;
const void* prepareImage(SkGlyph* glyph);
// Lookup (or create if needed) the toGlyph using toID. If that glyph is not initialized with
// an image, then use the information in from to initialize the width, height top, left,
// format and image of the toGlyph. This is mainly used preserving the glyph if it was
// created by a search of desperation.
SkGlyph* mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from);
// If the path has never been set, then use the scaler context to add the glyph.
const SkPath* preparePath(SkGlyph*);
// If the path has never been set, then add a path to glyph.
const SkPath* preparePath(SkGlyph* glyph, const SkPath* path);
@ -163,11 +154,19 @@ private:
template <typename Fn>
void commonFilterLoop(SkDrawableGlyphBuffer* drawables, Fn&& fn);
// Return a glyph. Create it if it doesn't exist, and initialize the glyph with metrics and
// advances using a scaler.
SkGlyph* glyph(SkPackedGlyphID packedID);
const void* prepareImage(SkGlyph* glyph);
// If the path has never been set, then use the scaler context to add the glyph.
const SkPath* preparePath(SkGlyph*);
enum PathDetail {
kMetricsOnly,
kMetricsAndPath
};
// internalPrepare will only be called with a mutex already held.
SkSpan<const SkGlyph*> internalPrepare(
SkSpan<const SkGlyphID> glyphIDs,

View File

@ -13,6 +13,11 @@
#include "src/core/SkStrikeCache.h"
#include "src/core/SkTLazy.h"
#if SK_SUPPORT_GPU
#include "src/gpu/text/GrStrikeCache.h"
#include "src/gpu/text/GrTextContext.h"
#endif
SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
const SkSurfaceProps& surfaceProps,
SkScalerContextFlags scalerContextFlags,
@ -239,18 +244,48 @@ SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphI
return fStrike->metrics(glyphIDs, fGlyphs.get());
}
const SkGlyph* SkBulkGlyphMetrics::glyph(SkGlyphID glyphID) {
return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
}
SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
: fStrike{spec.findOrCreateExclusiveStrike()} { }
SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(SkExclusiveStrikePtr&& strike)
: fStrike{std::move(strike)} { }
SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
fGlyphs.reset(glyphIDs.size());
return fStrike->preparePaths(glyphIDs, fGlyphs.get());
}
const SkGlyph* SkBulkGlyphMetricsAndPaths::glyph(SkGlyphID glyphID) {
return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
}
void SkBulkGlyphMetricsAndPaths::findIntercepts(
const SkScalar* bounds, SkScalar scale, SkScalar xPos,
const SkGlyph* glyph, SkScalar* array, int* count) {
// TODO(herb): remove this abominable const_cast. Do the intercepts really need to be on the
// glyph?
fStrike->findIntercepts(bounds, scale, xPos, const_cast<SkGlyph*>(glyph), array, count);
}
SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
: fStrike{spec.findOrCreateExclusiveStrike()} { }
SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(SkExclusiveStrikePtr&& strike)
: fStrike{std::move(strike)} { }
SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
fGlyphs.reset(glyphIDs.size());
return fStrike->prepareImages(glyphIDs, fGlyphs.get());
}
const SkGlyph* SkBulkGlyphMetricsAndImages::glyph(SkPackedGlyphID packedID) {
return this->glyphs(SkSpan<const SkPackedGlyphID>{&packedID, 1})[0];
}
const SkDescriptor& SkBulkGlyphMetricsAndImages::descriptor() const {
return fStrike->getDescriptor();
}

View File

@ -13,8 +13,9 @@
#include "src/core/SkStrikeForGPU.h"
#if SK_SUPPORT_GPU
#include "src/gpu/text/GrStrikeCache.h"
#include "src/gpu/text/GrTextContext.h"
class GrStrikeCache;
class GrTextStrike;
#endif
class SkFont;
@ -40,10 +41,10 @@ public:
SkScalerContextFlags scalerContextFlags);
static SkStrikeSpec MakeSourceFallback(const SkFont& font,
const SkPaint& paint,
const SkSurfaceProps& surfaceProps,
SkScalerContextFlags scalerContextFlags,
SkScalar maxSourceGlyphDimension);
const SkPaint& paint,
const SkSurfaceProps& surfaceProps,
SkScalerContextFlags scalerContextFlags,
SkScalar maxSourceGlyphDimension);
// Create a canonical strike spec for device-less measurements.
static SkStrikeSpec MakeCanonicalized(
@ -99,6 +100,7 @@ class SkBulkGlyphMetrics {
public:
explicit SkBulkGlyphMetrics(const SkStrikeSpec& spec);
SkSpan<const SkGlyph*> glyphs(SkSpan<const SkGlyphID> glyphIDs);
const SkGlyph* glyph(SkGlyphID glyphID);
private:
static constexpr int kTypicalGlyphCount = 20;
@ -109,7 +111,11 @@ private:
class SkBulkGlyphMetricsAndPaths {
public:
explicit SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec);
explicit SkBulkGlyphMetricsAndPaths(SkExclusiveStrikePtr&& strike);
SkSpan<const SkGlyph*> glyphs(SkSpan<const SkGlyphID> glyphIDs);
const SkGlyph* glyph(SkGlyphID glyphID);
void findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
const SkGlyph* glyph, SkScalar* array, int* count);
private:
static constexpr int kTypicalGlyphCount = 20;
@ -120,7 +126,11 @@ private:
class SkBulkGlyphMetricsAndImages {
public:
explicit SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec);
SkSpan<const SkGlyph*> glyphs(SkSpan<const SkPackedGlyphID> glyphIDs);
explicit SkBulkGlyphMetricsAndImages(SkExclusiveStrikePtr&& strike);
SkSpan<const SkGlyph*> glyphs(SkSpan<const SkPackedGlyphID> packedIDs);
const SkGlyph* glyph(SkPackedGlyphID packedID);
const SkDescriptor& descriptor() const;
private:
static constexpr int kTypicalGlyphCount = 64;

View File

@ -875,27 +875,27 @@ int get_glyph_run_intercepts(const SkGlyphRun& glyphRun,
interceptPaint.setPathEffect(nullptr);
SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(interceptFont, &interceptPaint);
auto cache = strikeSpec.findOrCreateExclusiveStrike();
SkBulkGlyphMetricsAndPaths metricsAndPaths{strikeSpec};
SkScalar xOffset = 0;
SkScalar xPos = xOffset;
SkScalar prevAdvance = 0;
const SkPoint* posCursor = glyphRun.positions().begin();
for (auto glyphID : glyphRun.glyphsIDs()) {
for (const SkGlyph* glyph : metricsAndPaths.glyphs(glyphRun.glyphsIDs())) {
SkPoint pos = *posCursor++;
SkGlyph* glyph = cache->glyph(SkPackedGlyphID{glyphID});
xPos += prevAdvance * scale;
prevAdvance = glyph->advanceX();
if (cache->preparePath(glyph) != nullptr) {
if (glyph->path() != nullptr) {
// The typeface is scaled, so un-scale the bounds to be in the space of the typeface.
// Also ensure the bounds are properly offset by the vertical positioning of the glyph.
SkScalar scaledBounds[2] = {
(bounds[0] - pos.y()) / scale,
(bounds[1] - pos.y()) / scale
};
cache->findIntercepts(scaledBounds, scale, pos.x(), glyph, intervals, intervalCount);
metricsAndPaths.findIntercepts(
scaledBounds, scale, pos.x(), glyph, intervals, intervalCount);
}
}
return *intervalCount;

View File

@ -340,7 +340,6 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
char* currVertex = reinterpret_cast<char*>(vertices);
SkExclusiveStrikePtr autoGlyphCache;
// each of these is a SubRun
for (int i = 0; i < fGeoCount; i++) {
const Geometry& args = fGeoData[i];
@ -349,7 +348,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
GrTextBlob::VertexRegenerator regenerator(
resourceProvider, blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY,
args.fColor.toBytes_RGBA(), target->deferredUploadTarget(), glyphCache,
atlasManager, &autoGlyphCache);
atlasManager);
bool done = false;
while (!done) {
GrTextBlob::VertexRegenerator::Result result;

View File

@ -11,8 +11,10 @@
#include "src/gpu/text/GrAtlasManager.h"
#include "src/gpu/text/GrStrikeCache.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkAutoMalloc.h"
#include "src/core/SkDistanceFieldGen.h"
#include "src/core/SkStrikeSpec.h"
GrStrikeCache::GrStrikeCache(const GrCaps* caps, size_t maxTextureBytes)
: fPreserveStrike(nullptr)
@ -80,12 +82,12 @@ static void expand_bits(INT_TYPE* dst,
}
}
static bool get_packed_glyph_image(SkStrike* cache, SkGlyph* glyph, int width,
static bool get_packed_glyph_image(const SkGlyph* glyph, int width,
int height, int dstRB, GrMaskFormat expectedMaskFormat,
void* dst, const SkMasks& masks) {
SkASSERT(glyph->width() == width);
SkASSERT(glyph->height() == height);
const void* src = cache->prepareImage(glyph);
const void* src = glyph->image();
if (src == nullptr) {
return false;
}
@ -190,11 +192,11 @@ GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
GrStrikeCache* glyphCache,
GrAtlasManager* fullAtlasManager,
GrGlyph* glyph,
SkStrike* skStrikeCache,
SkBulkGlyphMetricsAndImages* metricsAndImages,
GrMaskFormat expectedMaskFormat,
bool isScaledGlyph) {
SkASSERT(glyph);
SkASSERT(skStrikeCache);
SkASSERT(metricsAndImages);
SkASSERT(fCache.find(glyph->fPackedID));
expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
@ -215,13 +217,13 @@ GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
}
SkAutoSMalloc<1024> storage(size);
SkGlyph* skGlyph = skStrikeCache->glyph(glyph->fPackedID);
const SkGlyph* skGlyph = metricsAndImages->glyph(glyph->fPackedID);
void* dataPtr = storage.get();
if (addPad) {
sk_bzero(dataPtr, size);
dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
}
if (!get_packed_glyph_image(skStrikeCache, skGlyph, glyph->width(), glyph->height(),
if (!get_packed_glyph_image(skGlyph, glyph->width(), glyph->height(),
rowBytes, expectedMaskFormat,
dataPtr, glyphCache->getMasks())) {
return GrDrawOpAtlas::ErrorCode::kError;
@ -242,3 +244,25 @@ GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
}
return result;
}
GrGlyph* GrTextStrike::getGlyph(const SkGlyph& skGlyph) {
GrGlyph* grGlyph = fCache.find(skGlyph.getPackedID());
if (grGlyph == nullptr) {
grGlyph = fAlloc.make<GrGlyph>(skGlyph);
fCache.add(grGlyph);
}
return grGlyph;
}
GrGlyph*
GrTextStrike::getGlyph(SkPackedGlyphID packed, SkBulkGlyphMetricsAndImages* metricsAndImages) {
GrGlyph* grGlyph = fCache.find(packed);
if (grGlyph == nullptr) {
// We could return this to the caller, but in practice it adds code complexity for
// potentially little benefit(ie, if the glyph is not in our font cache, then its not
// in the atlas and we're going to be doing a texture upload anyways).
grGlyph = fAlloc.make<GrGlyph>(*metricsAndImages->glyph(packed));
fCache.add(grGlyph);
}
return grGlyph;
}

View File

@ -9,15 +9,16 @@
#define GrStrikeCache_DEFINED
#include "src/codec/SkMasks.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkStrike.h"
#include "src/core/SkDescriptor.h"
#include "src/core/SkTDynamicHash.h"
#include "src/gpu/GrDrawOpAtlas.h"
#include "src/gpu/GrGlyph.h"
class GrAtlasManager;
class GrGpu;
class GrStrikeCache;
class SkBulkGlyphMetricsAndImages;
/**
* The GrTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory
@ -30,30 +31,13 @@ class GrTextStrike : public SkNVRefCnt<GrTextStrike> {
public:
GrTextStrike(const SkDescriptor& fontScalerKey);
GrGlyph* getGlyph(const SkGlyph& skGlyph) {
GrGlyph* grGlyph = fCache.find(skGlyph.getPackedID());
if (grGlyph == nullptr) {
grGlyph = fAlloc.make<GrGlyph>(skGlyph);
fCache.add(grGlyph);
}
return grGlyph;
}
GrGlyph* getGlyph(const SkGlyph& skGlyph);
// This variant of the above function is called by GrAtlasTextOp. At this point, it is possible
// that the maskformat of the glyph differs from what we expect. In these cases we will just
// draw a clear square.
// skbug:4143 crbug:510931
GrGlyph* getGlyph(SkPackedGlyphID packed, SkStrike* skStrike) {
GrGlyph* grGlyph = fCache.find(packed);
if (grGlyph == nullptr) {
// We could return this to the caller, but in practice it adds code complexity for
// potentially little benefit(ie, if the glyph is not in our font cache, then its not
// in the atlas and we're going to be doing a texture upload anyways).
grGlyph = fAlloc.make<GrGlyph>(*skStrike->glyph(packed));
fCache.add(grGlyph);
}
return grGlyph;
}
GrGlyph* getGlyph(SkPackedGlyphID packed, SkBulkGlyphMetricsAndImages* metricsAndImages);
// returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's
// mask format has changed, then addGlyphToAtlas will draw a clear box. This will almost never
@ -62,7 +46,8 @@ public:
// get the actual glyph image itself when we get the glyph metrics.
GrDrawOpAtlas::ErrorCode addGlyphToAtlas(GrResourceProvider*, GrDeferredUploadTarget*,
GrStrikeCache*, GrAtlasManager*, GrGlyph*,
SkStrike*, GrMaskFormat expectedMaskFormat,
SkBulkGlyphMetricsAndImages*,
GrMaskFormat expectedMaskFormat,
bool isScaledGlyph);
// testing

View File

@ -593,8 +593,7 @@ public:
*/
VertexRegenerator(GrResourceProvider*, GrTextBlob*, int runIdx, int subRunIdx,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y, GrColor color,
GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*,
SkExclusiveStrikePtr*);
GrDeferredUploadTarget*, GrStrikeCache*, GrAtlasManager*);
struct Result {
/**
@ -626,7 +625,7 @@ private:
GrDeferredUploadTarget* fUploadTarget;
GrStrikeCache* fGlyphCache;
GrAtlasManager* fFullAtlasManager;
SkExclusiveStrikePtr* fLazyStrike;
SkTLazy<SkBulkGlyphMetricsAndImages> fMetricsAndImages;
SubRun* fSubRun;
GrColor fColor;
SkScalar fTransX;

View File

@ -122,15 +122,13 @@ GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourcePro
GrColor color,
GrDeferredUploadTarget* uploadTarget,
GrStrikeCache* glyphCache,
GrAtlasManager* fullAtlasManager,
SkExclusiveStrikePtr* lazyStrike)
GrAtlasManager* fullAtlasManager)
: fResourceProvider(resourceProvider)
, fViewMatrix(viewMatrix)
, fBlob(blob)
, fUploadTarget(uploadTarget)
, fGlyphCache(glyphCache)
, fFullAtlasManager(fullAtlasManager)
, fLazyStrike(lazyStrike)
, fSubRun(&blob->fRuns[runIdx].fSubRunInfo[subRunIdx])
, fColor(color) {
// Compute translation if any
@ -166,9 +164,9 @@ bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Resul
const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec();
if (!*fLazyStrike || (*fLazyStrike)->getDescriptor() != strikeSpec.descriptor()) {
*fLazyStrike =
strikeSpec.findOrCreateExclusiveStrike(SkStrikeCache::GlobalStrikeCache());
if (!fMetricsAndImages.isValid()
|| fMetricsAndImages->descriptor() != strikeSpec.descriptor()) {
fMetricsAndImages.init(strikeSpec);
}
if (regenGlyphs) {
@ -193,7 +191,7 @@ bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Resul
// Get the id from the old glyph, and use the new strike to lookup
// the glyph.
SkPackedGlyphID id = fBlob->fGlyphs[glyphOffset]->fPackedID;
fBlob->fGlyphs[glyphOffset] = strike->getGlyph(id, fLazyStrike->get());
fBlob->fGlyphs[glyphOffset] = strike->getGlyph(id, fMetricsAndImages.get());
SkASSERT(id == fBlob->fGlyphs[glyphOffset]->fPackedID);
}
glyph = fBlob->fGlyphs[glyphOffset];
@ -203,7 +201,7 @@ bool GrTextBlob::VertexRegenerator::doRegen(GrTextBlob::VertexRegenerator::Resul
GrDrawOpAtlas::ErrorCode code;
code = strike->addGlyphToAtlas(fResourceProvider, fUploadTarget, fGlyphCache,
fFullAtlasManager, glyph,
fLazyStrike->get(), fSubRun->maskFormat(),
fMetricsAndImages.get(), fSubRun->maskFormat(),
fSubRun->needsTransform());
if (GrDrawOpAtlas::ErrorCode::kError == code) {
// Something horrible has happened - drop the op

View File

@ -442,9 +442,8 @@ struct ImageAndOffset {
sk_sp<SkImage> fImage;
SkIPoint fOffset;
};
static ImageAndOffset to_image(SkGlyphID gid, SkStrike* cache) {
SkGlyph* glyph = cache->glyph(SkPackedGlyphID{gid});
(void)cache->prepareImage(glyph);
static ImageAndOffset to_image(SkGlyphID gid, SkBulkGlyphMetricsAndImages* smallGlyphs) {
const SkGlyph* glyph = smallGlyphs->glyph(SkPackedGlyphID{gid});
SkMask mask = glyph->mask();
if (!mask.fImage) {
return {nullptr, {0, 0}};
@ -485,7 +484,7 @@ static ImageAndOffset to_image(SkGlyphID gid, SkStrike* cache) {
static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
const SkTypeface* typeface,
SkStrike* cache) {
SkScalar xHeight) {
if (SkPDFIndirectReference* ptr = doc->fType3FontDescriptors.find(typeface->uniqueID())) {
return *ptr;
}
@ -501,7 +500,6 @@ static SkPDFIndirectReference type3_descriptor(SkPDFDocument* doc,
// to "greatly help our workflow downstream".
if (metrics->fCapHeight != 0) { descriptor.insertInt("CapHeight", metrics->fCapHeight); }
if (metrics->fStemV != 0) { descriptor.insertInt("StemV", metrics->fStemV); }
SkScalar xHeight = cache->getFontMetrics().fXHeight;
if (xHeight != 0) {
descriptor.insertScalar("XHeight", xHeight);
}
@ -545,11 +543,13 @@ static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
auto cache = strikeSpec.findOrCreateExclusiveStrike();
SkASSERT(cache);
SkScalar emSize = (SkScalar)unitsPerEm;
SkScalar xHeight = cache->getFontMetrics().fXHeight;
SkBulkGlyphMetricsAndPaths metricsAndPaths(std::move(cache));
SkStrikeSpec strikeSpecSmall = kBitmapFontSize > 0 ? make_small_strike(*typeface)
: strikeSpec;
auto smallCache = strikeSpecSmall.findOrCreateExclusiveStrike();
SkASSERT(smallCache);
SkBulkGlyphMetricsAndImages smallGlyphs(strikeSpecSmall);
float bitmapScale = kBitmapFontSize > 0 ? emSize / kBitmapFontSize : 1.0f;
SkPDFDict font("Font");
@ -587,18 +587,18 @@ static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
characterName.set("g0");
} else {
characterName.printf("g%X", gID);
SkGlyph* glyph = cache->glyph(SkPackedGlyphID{gID});
const SkGlyph* glyph = metricsAndPaths.glyph(gID);
advance = glyph->advanceX();
glyphBBox = glyph->iRect();
bbox.join(glyphBBox);
const SkPath* path = cache->preparePath(glyph);
const SkPath* path = glyph->path();
SkDynamicMemoryWStream content;
if (path && !path->isEmpty()) {
setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
SkPDFUtils::EmitPath(*path, SkPaint::kFill_Style, &content);
SkPDFUtils::PaintPath(SkPaint::kFill_Style, path->getFillType(), &content);
} else {
auto pimg = to_image(gID, smallCache.get());
auto pimg = to_image(gID, &smallGlyphs);
if (!pimg.fImage) {
setGlyphWidthAndBoundingBox(glyph->advanceX(), glyphBBox, &content);
} else {
@ -659,7 +659,7 @@ static void emit_subset_type3(const SkPDFFont& pdfFont, SkPDFDocument* doc) {
firstGlyphID,
lastGlyphID);
font.insertRef("ToUnicode", SkPDFStreamOut(nullptr, std::move(toUnicodeCmap), doc));
font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, cache.get()));
font.insertRef("FontDescriptor", type3_descriptor(doc, typeface, xHeight));
font.insertObject("Widths", std::move(widthArray));
font.insertObject("Encoding", std::move(encoding));
font.insertObject("CharProcs", std::move(charProcs));

View File

@ -891,14 +891,17 @@ DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
scalerProxy->initCache(testCache.get(), &strikeCache);
auto rounding = testCache->roundingSpec();
SkBulkGlyphMetricsAndImages metricsAndImages{std::move(testCache)};
// Look for the lost glyph.
{
SkPoint pt{SkFixedToScalar(lostGlyphID.getSubXFixed()),
SkFixedToScalar(lostGlyphID.getSubYFixed())};
SkPackedGlyphID packedID{
lostGlyphID.glyphID(), pt, testCache->roundingSpec().ignorePositionFieldMask};
SkGlyph* lostGlyph = testCache->glyph(packedID);
testCache->prepareImage(lostGlyph);
lostGlyphID.glyphID(), pt, rounding.ignorePositionFieldMask};
const SkGlyph* lostGlyph = metricsAndImages.glyph(packedID);
REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
@ -911,9 +914,8 @@ DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
SkPoint pt{SkFixedToScalar(SK_FixedQuarter),
SkFixedToScalar(SK_FixedQuarter)};
SkPackedGlyphID packedID{
lostGlyphID.glyphID(), pt, testCache->roundingSpec().ignorePositionFieldMask};
SkGlyph* lostGlyph = testCache->glyph(packedID);
testCache->prepareImage(lostGlyph);
lostGlyphID.glyphID(), pt, rounding.ignorePositionFieldMask};
const SkGlyph* lostGlyph = metricsAndImages.glyph(packedID);
REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
REPORTER_ASSERT(reporter, lostGlyph->width() == 2);