From 38a08436886e82de4eb9ebdbcb2bbd5ea7b05c6d Mon Sep 17 00:00:00 2001 From: Khushal Date: Wed, 2 May 2018 10:29:37 -0700 Subject: fonts: Reland push font remoting. This relands the following changes: 1) https://skia-review.googlesource.com/c/skia/+/120283 2) https://skia-review.googlesource.com/c/skia/+/125029 3) https://skia-review.googlesource.com/c/skia/+/125140 The original changes had to be reverted due to a memory leak in SkBaseDevice from SkTextBlobCacheDiffCanvas. This has been addressed by https://skia-review.googlesource.com/c/skia/+/125160 TBR=herb@google.com Bug: skia:7515, 831354 Change-Id: I73f4fcb1c397f31bf01553ff48c71ed2d6dd0770 Reviewed-on: https://skia-review.googlesource.com/125326 Commit-Queue: Khusal Sagar Reviewed-by: Khusal Sagar --- src/core/SkRemoteGlyphCache.cpp | 798 +++++++++++++++++++--------------------- src/core/SkRemoteGlyphCache.h | 288 ++++++++------- src/core/SkScalerContext.h | 4 +- src/core/SkStrikeCache.h | 19 +- src/core/SkTypeface_remote.cpp | 17 +- src/core/SkTypeface_remote.h | 27 +- 6 files changed, 552 insertions(+), 601 deletions(-) (limited to 'src') diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp index 63c3fe9eb9..57c563ad14 100644 --- a/src/core/SkRemoteGlyphCache.cpp +++ b/src/core/SkRemoteGlyphCache.cpp @@ -9,13 +9,51 @@ #include #include +#include #include #include "SkDevice.h" #include "SkFindAndPlaceGlyph.h" #include "SkStrikeCache.h" +#include "SkTextBlobRunIterator.h" +#include "SkTraceEvent.h" #include "SkTypeface_remote.h" +static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc, + SkFontID font_id, + SkAutoDescriptor* ad) { + ad->reset(source_desc->getLength()); + auto* desc = ad->getDesc(); + desc->init(); + + // Rec. + { + uint32_t size; + auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size); + SkScalerContextRec rec; + std::memcpy(&rec, ptr, size); + rec.fFontID = font_id; + desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + } + + // Path effect. + { + uint32_t size; + auto ptr = source_desc->findEntry(kPathEffect_SkDescriptorTag, &size); + if (ptr) desc->addEntry(kPathEffect_SkDescriptorTag, size, ptr); + } + + // Mask filter. + { + uint32_t size; + auto ptr = source_desc->findEntry(kMaskFilter_SkDescriptorTag, &size); + if (ptr) desc->addEntry(kMaskFilter_SkDescriptorTag, size, ptr); + } + + desc->computeChecksum(); + return desc; +} + template class ArraySlice final : public std::tuple { public: @@ -26,7 +64,6 @@ public: const T* begin() { return this->data(); } - const T* end() { return &this->data()[this->size()]; } @@ -46,28 +83,32 @@ private: // -- Serializer ---------------------------------------------------------------------------------- -static size_t pad(size_t size, size_t alignment) { - return (size + (alignment - 1)) & ~(alignment - 1); -} +size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); } -// N.B. pointers are only valid until the next call. class Serializer { public: Serializer(std::vector* buffer) : fBuffer{buffer} { } - template - T* push_back(const T& data) { - auto result = allocate(sizeof(T), alignof(T)); - return new (result) T(data); - } - template - T* emplace_back(Args&& ... args) { + T* emplace(Args&&... args) { auto result = allocate(sizeof(T), alignof(T)); return new (result) T{std::forward(args)...}; } + template + void write(const T& data) { + T* result = (T*)allocate(sizeof(T), alignof(T)); + memcpy(result, &data, sizeof(T)); + } + + template + T* allocate() { + T* result = (T*)allocate(sizeof(T), alignof(T)); + return result; + } + void writeDescriptor(const SkDescriptor& desc) { + write(desc.getLength()); auto result = allocate(desc.getLength(), alignof(SkDescriptor)); memcpy(result, &desc, desc.getLength()); } @@ -89,86 +130,69 @@ private: }; // -- Deserializer ------------------------------------------------------------------------------- - +// Note that the Deserializer is reading untrusted data, we need to guard against invalid data. class Deserializer { public: - Deserializer(const SkData& buffer) : fBuffer{buffer} { } + Deserializer(const volatile char* memory, size_t memorySize) + : fMemory(memory), fMemorySize(memorySize) {} template - T* read() { - size_t padded = pad(fCursor, alignof(T)); - fCursor = padded + sizeof(T); - auto data = (uint8_t*)fBuffer.data(); - return (T*)&data[padded]; - } - - SkDescriptor* readDescriptor() { - size_t padded = pad(fCursor, alignof(SkDescriptor)); - auto data = (uint8_t*)fBuffer.data(); - SkDescriptor* result = (SkDescriptor*)&data[padded]; - fCursor = padded + result->getLength(); - return result; + bool read(T* val) { + auto* result = this->ensureAtLeast(sizeof(T), alignof(T)); + if (!result) return false; + + memcpy(val, const_cast(result), sizeof(T)); + return true; + } + + bool readDescriptor(SkAutoDescriptor* ad) { + uint32_t desc_length = 0u; + if (!read(&desc_length)) return false; + + auto* result = this->ensureAtLeast(desc_length, alignof(SkDescriptor)); + if (!result) return false; + + ad->reset(desc_length); + memcpy(ad->getDesc(), const_cast(result), desc_length); + return true; } template ArraySlice readArray(int count) { - size_t padded = pad(fCursor, alignof(T)); size_t size = count * sizeof(T); - auto data = (uint8_t*)fBuffer.data(); - const T* base = (const T*)&data[padded]; + const T* base = (const T*)this->ensureAtLeast(size, alignof(T)); + if (!base) return ArraySlice(); + ArraySlice result = ArraySlice{base, (uint32_t)count}; - fCursor = padded + size; return result; } - size_t size() {return fCursor;} - private: - const SkData& fBuffer; - size_t fCursor{0}; -}; - - -// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------ + const volatile char* ensureAtLeast(size_t size, size_t alignment) { + size_t padded = pad(fBytesRead, alignment); -SkStrikeDifferences::SkStrikeDifferences( - SkFontID typefaceID, std::unique_ptr desc) - : fTypefaceID{typefaceID} - , fDesc{std::move(desc)} { } + // Not enough data + if (padded + size > fMemorySize) return nullptr; -void SkStrikeDifferences::add(uint16_t glyphID, SkIPoint pos) { - SkPackedGlyphID packedGlyphID{glyphID, pos.x(), pos.y()}; - fGlyphIDs->add(packedGlyphID); -} + auto* result = fMemory + padded; + fBytesRead = padded + size; + return result; + } -SkStrikeDifferences& SkStrikeCacheDifferenceSpec::findStrikeDifferences( - const SkDescriptor& desc, SkFontID typefaceID) -{ - auto mapIter = fDescriptorToDifferencesMap.find(&desc); - if (mapIter == fDescriptorToDifferencesMap.end()) { - auto newDesc = desc.copy(); - auto newDescPtr = newDesc.get(); - SkStrikeDifferences strikeDiffs{typefaceID, std::move(newDesc)}; + // Note that we read each piece of memory only once to guard against TOCTOU violations. + const volatile char* fMemory; + size_t fMemorySize; + size_t fBytesRead = 0u; +}; - mapIter = fDescriptorToDifferencesMap.emplace_hint( - mapIter, newDescPtr, std::move(strikeDiffs)); +size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const { + return key->getChecksum(); } - return mapIter->second; -} - -template -void SkStrikeCacheDifferenceSpec::iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const { - for (auto& i : fDescriptorToDifferencesMap) { - auto strikeDiff = &i.second; - perStrike(strikeDiff->fTypefaceID, - *strikeDiff->fDesc, - strikeDiff->fGlyphIDs->count()); - strikeDiff->fGlyphIDs->foreach([&](SkPackedGlyphID id) { - perGlyph(id); - }); + bool SkDescriptorMapOperators::operator()(const SkDescriptor* lhs, + const SkDescriptor* rhs) const { + return *lhs == *rhs; } -} // -- TrackLayerDevice ----------------------------------------------------------------------------- class TrackLayerDevice : public SkNoPixelsDevice { @@ -182,17 +206,18 @@ public: }; // -- SkTextBlobCacheDiffCanvas ------------------------------------------------------------------- -SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas( - int width, int height, - const SkMatrix& deviceMatrix, - const SkSurfaceProps& props, - SkScalerContextFlags flags, - SkStrikeCacheDifferenceSpec* strikeDiffs) +SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height, + const SkMatrix& deviceMatrix, + const SkSurfaceProps& props, + SkStrikeServer* strikeSever) : SkNoDrawCanvas{sk_make_sp(SkIRect::MakeWH(width, height), props)} , fDeviceMatrix{deviceMatrix} , fSurfaceProps{props} - , fScalerContextFlags{flags} - , fStrikeCacheDiff{strikeDiffs} { } + , fStrikeServer{strikeSever} { + SkASSERT(fStrikeServer); +} + +SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() = default; SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy( const SaveLayerRec&rec) @@ -235,6 +260,10 @@ void SkTextBlobCacheDiffCanvas::processLooper( } } +#define FAIL_AND_RETURN \ + SkDEBUGFAIL("Failed to process glyph run"); \ + return; + void SkTextBlobCacheDiffCanvas::processGlyphRun( const SkPoint& position, const SkTextBlobRunIterator& it, @@ -242,20 +271,24 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( { if (runPaint.getTextEncoding() != SkPaint::TextEncoding::kGlyphID_TextEncoding) { - return; + TRACE_EVENT0("skia", "kGlyphID_TextEncoding"); + FAIL_AND_RETURN } // All other alignment modes need the glyph advances. Use the slow drawing mode. if (runPaint.getTextAlign() != SkPaint::kLeft_Align) { - return; + TRACE_EVENT0("skia", "kLeft_Align"); + FAIL_AND_RETURN } using PosFn = SkPoint(*)(int index, const SkScalar* pos); PosFn posFn; switch (it.positioning()) { - case SkTextBlob::kDefault_Positioning: + case SkTextBlob::kDefault_Positioning: { // Default positioning needs advances. Can't do that. - return; + TRACE_EVENT0("skia", "kDefault_Positioning"); + FAIL_AND_RETURN + } case SkTextBlob::kHorizontal_Positioning: posFn = [](int index, const SkScalar* pos) { @@ -278,7 +311,8 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( SkMatrix blobMatrix{fDeviceMatrix}; blobMatrix.preConcat(this->getTotalMatrix()); if (blobMatrix.hasPerspective()) { - return; + TRACE_EVENT0("skia", "hasPerspective"); + FAIL_AND_RETURN } blobMatrix.preTranslate(position.x(), position.y()); @@ -315,19 +349,22 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( SK_ABORT("Bad matrix."); } - SkAutoDescriptor ad; SkScalerContextRec rec; SkScalerContextEffects effects; + // TODO(crbug.com/831354): The typeface proxy on the client does not replicate the + // filtering done by the typeface on the server. + const bool enableTypefaceFiltering = false; SkScalerContext::MakeRecAndEffects(runPaint, &fSurfaceProps, &runMatrix, - fScalerContextFlags, &rec, &effects); - - auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad); + SkScalerContextFlags::kFakeGammaAndBoostContrast, &rec, + &effects, enableTypefaceFiltering); - auto typefaceID = SkTypefaceProxy::DownCast(runPaint.getTypeface())->remoteTypefaceID(); - auto& diffs = fStrikeCacheDiff->findStrikeDifferences(*desc, typefaceID); + TRACE_EVENT1("skia", "RecForDesc", "rec", TRACE_STR_COPY(rec.dump().c_str())); + auto desc = SkScalerContext::DescriptorGivenRecAndEffects(rec, effects); + auto* glyphCacheState = static_cast(fStrikeServer) + ->getOrCreateCache(runPaint.getTypeface(), std::move(desc)); + SkASSERT(glyphCacheState); - auto cache = SkStrikeCache::FindStrikeExclusive(*desc); bool isSubpixel = SkToBool(rec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); SkAxisAlignment axisAlignment = SkAxisAlignment::kNone_SkAxisAlignment; if (it.positioning() == SkTextBlob::kHorizontal_Positioning) { @@ -342,392 +379,323 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun( subPixelPos = SkFindAndPlaceGlyph::SubpixelAlignment(axisAlignment, glyphPos); } - if (cache && - cache->isGlyphCached(glyphs[index], subPixelPos.x(), subPixelPos.y())) { - continue; - } - - diffs.add(glyphs[index], subPixelPos); + glyphCacheState->addGlyph(runPaint.getTypeface(), + effects, + SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y())); } } -// Op code semantics: -// * FontMetrics - (SkFontID, SkDescriptor) -> SkPaint::FontMetrics -// * GlyphPath - (SkFontID, SkDescriptor, SkPackedGlyphID) -> SkPath -// * GlyphMetricsAndImage - (SkFontID, SkDescriptor, SkPackedGlyphID) -> (SkGlyph, ) -// * PrepopulateCache - StrikeCacheDifferenceSpec -> StrikeCacheDifferenceData - -enum class OpCode : int32_t { - kFontMetrics = 0, - kGlyphPath = 1, - kGlyphMetricsAndImage = 2, - kPrepopulateCache = 3, -}; - -struct StrikeDiffHeader { - StrikeDiffHeader() {} - StrikeDiffHeader(int strikeCount_) : strikeCount{strikeCount_} {} - int strikeCount; -}; - struct StrikeSpec { - StrikeSpec(SkFontID typefaceID_, uint32_t descLength_, int glyphCount_) + StrikeSpec() {} + StrikeSpec(SkFontID typefaceID_, size_t glyphCount_, SkDiscardableHandleId discardableHandleId_) : typefaceID{typefaceID_} - , descLength{descLength_} - , glyphCount{glyphCount_} { } - SkFontID typefaceID; - uint32_t descLength; - int glyphCount; + , glyphCount{glyphCount_} + , discardableHandleId(discardableHandleId_) {} + SkFontID typefaceID = 0u; + size_t glyphCount = 0u; + SkDiscardableHandleId discardableHandleId = 0u; /* desc */ /* n X (glyphs ids) */ }; struct WireTypeface { + WireTypeface() = default; + WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed) + : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {} + + // std::thread::id thread_id; // TODO:need to figure a good solution SkFontID typefaceID; int glyphCount; SkFontStyle style; bool isFixed; }; -class Op { -public: - Op(OpCode opCode, SkFontID typefaceId, const SkScalerContextRec& rec) - : opCode{opCode} - , typefaceId{typefaceId} - , descriptor{rec} { } - const OpCode opCode; - const SkFontID typefaceId; - const SkScalerContextRecDescriptor descriptor; - union { - // kGlyphPath and kGlyphMetricsAndImage - SkPackedGlyphID glyphID; - // kPrepopulateCache - StrikeDiffHeader strikeSpecHeader; - }; -}; +// SkStrikeServer ----------------------------------------- -size_t SkStrikeCacheDifferenceSpec::sizeBytes() const { - size_t sum = sizeof(Op) + sizeof(StrikeDiffHeader); - for (auto& pair : fDescriptorToDifferencesMap) { - const auto& strike = pair.second; - sum += sizeof(StrikeSpec) - + strike.fDesc->getLength() - + strike.fGlyphIDs->count() * sizeof(SkPackedGlyphID); - } - return sum; +SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager) + : fDiscardableHandleManager(discardableHandleManager) { + SkASSERT(fDiscardableHandleManager); } -static void write_strikes_spec(const SkStrikeCacheDifferenceSpec &spec, - Serializer* serializer) { - serializer->emplace_back(OpCode::kPrepopulateCache, SkFontID{0}, SkScalerContextRec{}); +SkStrikeServer::~SkStrikeServer() = default; + +sk_sp SkStrikeServer::serializeTypeface(SkTypeface* tf) { + WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(), + tf->isFixedPitch()); + return SkData::MakeWithCopy(&wire, sizeof(wire)); +} - serializer->emplace_back(spec.strikeCount()); +void SkStrikeServer::writeStrikeData(std::vector* memory) { + if (fLockedDescs.empty() && fTypefacesToSend.empty()) return; - auto perStrike = [serializer](SkFontID typefaceID, const SkDescriptor& desc, int glyphCount) { - serializer->emplace_back(typefaceID, desc.getLength(), glyphCount); - serializer->writeDescriptor(desc); - }; + Serializer serializer(memory); + serializer.emplace(fTypefacesToSend.size()); + for (const auto& tf : fTypefacesToSend) serializer.write(tf); + fTypefacesToSend.clear(); - auto perGlyph = [serializer](SkPackedGlyphID glyphID) { - serializer->push_back(glyphID); - }; + serializer.emplace(fLockedDescs.size()); + for (const auto* desc : fLockedDescs) { + auto it = fRemoteGlyphStateMap.find(desc); + SkASSERT(it != fRemoteGlyphStateMap.end()); - spec.iterateDifferences(perStrike, perGlyph); + // TODO: This is unnecessary, write only the descs which has any glyphs + // to send. It was getting awkward to write the size after writing the + // descs because the vector reallocs. + serializer.emplace(it->second->has_pending_glyphs()); + if (!it->second->has_pending_glyphs()) continue; + + it->second->writePendingGlyphs(&serializer); + } + fLockedDescs.clear(); } -static void read_strikes_spec_write_strikes_data( - Deserializer* deserializer, Serializer* serializer, SkStrikeServer* server) -{ - // Don't start because the op started this deserialization. - auto header = deserializer->read(); - serializer->push_back(*header); - for (int i = 0; i < header->strikeCount; i++) { - auto spec = deserializer->read(); - auto desc = deserializer->readDescriptor(); - serializer->push_back(*spec); - serializer->writeDescriptor(*desc); - SkScalerContextRecDescriptor recDesc{*desc}; - auto scaler = server->generateScalerContext(recDesc, spec->typefaceID); - SkPaint::FontMetrics fontMetrics; - scaler->getFontMetrics(&fontMetrics); - serializer->push_back(fontMetrics); - auto glyphIDs = deserializer->readArray(spec->glyphCount); - for (auto glyphID : glyphIDs) { - auto glyph = serializer->emplace_back(); - glyph->initWithGlyphID(glyphID); - scaler->getMetrics(glyph); - auto imageSize = glyph->computeImageSize(); - glyph->fPathData = nullptr; - glyph->fImage = nullptr; - - if (imageSize > 0) { - // Since the allocateArray can move glyph, make one that stays in one place. - SkGlyph stationaryGlyph = *glyph; - stationaryGlyph.fImage = serializer->allocateArray(imageSize); - scaler->getImage(stationaryGlyph); - } +SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache( + SkTypeface* tf, std::unique_ptr desc) { + SkASSERT(desc); + + // Already locked. + if (fLockedDescs.find(desc.get()) != fLockedDescs.end()) { + auto it = fRemoteGlyphStateMap.find(desc.get()); + SkASSERT(it != fRemoteGlyphStateMap.end()); + return it->second.get(); + } + + // Try to lock. + auto it = fRemoteGlyphStateMap.find(desc.get()); + if (it != fRemoteGlyphStateMap.end()) { + bool locked = fDiscardableHandleManager->lockHandle(it->second->discardable_handle_id()); + if (locked) { + fLockedDescs.insert(it->first); + return it->second.get(); } + + // If the lock failed, the entry was deleted on the client. Remove our + // tracking. + fRemoteGlyphStateMap.erase(it); + } + + const SkFontID typeface_id = tf->uniqueID(); + if (!fCachedTypefaces.contains(typeface_id)) { + fCachedTypefaces.add(typeface_id); + fTypefacesToSend.emplace_back(typeface_id, tf->countGlyphs(), tf->fontStyle(), + tf->isFixedPitch()); } + + auto* desc_ptr = desc.get(); + auto new_handle = fDiscardableHandleManager->createHandle(); + auto cache_state = skstd::make_unique(std::move(desc), new_handle); + auto* cache_state_ptr = cache_state.get(); + + fLockedDescs.insert(desc_ptr); + fRemoteGlyphStateMap[desc_ptr] = std::move(cache_state); + return cache_state_ptr; } -static void update_caches_from_strikes_data(SkStrikeClient *client, - Deserializer *deserializer) { - auto header = deserializer->read(); - for (int i = 0; i < header->strikeCount; i++) { - auto spec = deserializer->read(); - auto desc = deserializer->readDescriptor(); - auto fontMetrics = deserializer->read(); - auto tf = client->lookupTypeface(spec->typefaceID); - - // TODO: implement effects handling. - SkScalerContextEffects effects; - auto strike = SkStrikeCache::FindStrikeExclusive(*desc); - if (strike == nullptr) { - auto scaler = SkStrikeCache::CreateScalerContext(*desc, effects, *tf); - strike = SkStrikeCache::CreateStrikeExclusive(*desc, std::move(scaler), fontMetrics); - } - for (int j = 0; j < spec->glyphCount; j++) { - auto glyph = deserializer->read(); - ArraySlice image; - auto imageSize = glyph->computeImageSize(); - if (imageSize != 0) { - image = deserializer->readArray(imageSize); - } - SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID()); - *allocatedGlyph = *glyph; - allocatedGlyph->allocImage(strike->getAlloc()); - memcpy(allocatedGlyph->fImage, image.data(), image.size()); +SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(std::unique_ptr desc, + uint32_t discardable_handle_id) + : fDesc(std::move(desc)), fDiscardableHandleId(discardable_handle_id) { + SkASSERT(fDesc); +} + +SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default; + +void SkStrikeServer::SkGlyphCacheState::addGlyph(SkTypeface* typeface, + const SkScalerContextEffects& effects, + SkPackedGlyphID glyph) { + // Already cached. + if (fCachedGlyphs.contains(glyph)) return; + + // Serialize and cache. Also create the scalar context to use when serializing + // this glyph. + fCachedGlyphs.add(glyph); + fPendingGlyphs.push_back(glyph); + if (!fContext) fContext = typeface->createScalerContext(effects, fDesc.get(), false); +} + +void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serializer) { + // Write the desc. + serializer->emplace(fContext->getTypeface()->uniqueID(), fPendingGlyphs.size(), + fDiscardableHandleId); + serializer->writeDescriptor(*fDesc.get()); + + // Write FontMetrics. + SkPaint::FontMetrics fontMetrics; + fContext->getFontMetrics(&fontMetrics); + serializer->write(fontMetrics); + + // Write Glyphs. + for (const auto& glyphID : fPendingGlyphs) { + auto glyph = serializer->emplace(); + glyph->initWithGlyphID(glyphID); + fContext->getMetrics(glyph); + auto imageSize = glyph->computeImageSize(); + glyph->fPathData = nullptr; + glyph->fImage = nullptr; + + if (imageSize > 0) { + // Since the allocateArray can move glyph, make one that stays in one place. + SkGlyph stationaryGlyph = *glyph; + stationaryGlyph.fImage = serializer->allocateArray(imageSize); + fContext->getImage(stationaryGlyph); } } + + // Note that we reset the context after serializing pending glyphs since we + // don't want to extend the lifetime of the typeface. + fPendingGlyphs.clear(); + fContext.reset(); } -// -- SkStrikeServer ------------------------------------------------------------------------------- -SkStrikeServer::SkStrikeServer() { } +// SkStrikeClient ----------------------------------------- -SkStrikeServer::~SkStrikeServer() { - printf("Strike server - ops: %d\n", fOpCount); -} +class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner { +public: + DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId, + sk_sp manager) + : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {} -void SkStrikeServer::serve(const SkData& inBuffer, std::vector* outBuffer) { + ~DiscardableStrikePinner() override = default; + bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); } - fOpCount += 1; +private: + const SkDiscardableHandleId fDiscardableHandleId; + sk_sp fManager; +}; - Serializer serializer{outBuffer}; - Deserializer deserializer{inBuffer}; - Op* op = deserializer.read(); +SkStrikeClient::SkStrikeClient(sk_sp discardableManager) + : fDiscardableHandleManager(std::move(discardableManager)) {} - switch (op->opCode) { - case OpCode::kFontMetrics : { - auto scaler = this->generateScalerContext(op->descriptor, op->typefaceId); - SkPaint::FontMetrics metrics; - scaler->getFontMetrics(&metrics); - serializer.push_back(metrics); - break; - } - case OpCode::kGlyphPath : { - auto sc = this->generateScalerContext(op->descriptor, op->typefaceId); - // TODO: check for buffer overflow. - SkPath path; - if (sc->getPath(op->glyphID, &path)) { - size_t pathSize = path.writeToMemory(nullptr); - serializer.push_back(pathSize); - auto pathData = serializer.allocateArray(pathSize); - path.writeToMemory(pathData); - } - break; - } - case OpCode::kGlyphMetricsAndImage : { - auto scaler = this->generateScalerContext(op->descriptor, op->typefaceId); - - auto glyph = serializer.emplace_back(); - // TODO: check for buffer overflow. - glyph->initWithGlyphID(op->glyphID); - scaler->getMetrics(glyph); - auto imageSize = glyph->computeImageSize(); - glyph->fPathData = nullptr; - glyph->fImage = nullptr; - if (imageSize > 0) { - // Since the allocateArray can move glyph, make one that stays in one place. - SkGlyph stationaryGlyph = *glyph; - stationaryGlyph.fImage = serializer.allocateArray(imageSize); - scaler->getImage(stationaryGlyph); - } - break; - } - case OpCode::kPrepopulateCache : { - read_strikes_spec_write_strikes_data( - &deserializer, &serializer, this); - break; - } +SkStrikeClient::~SkStrikeClient() = default; - default: - SK_ABORT("Bad op"); +#define READ_FAILURE \ + { \ + SkDEBUGFAIL("Bad serialization"); \ + return false; \ } -} -void SkStrikeServer::prepareSerializeProcs(SkSerialProcs* procs) { - auto encode = [](SkTypeface* tf, void* ctx) { - return reinterpret_cast(ctx)->encodeTypeface(tf); - }; - procs->fTypefaceProc = encode; - procs->fTypefaceCtx = this; -} +bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) { + SkASSERT(memorySize != 0u); + Deserializer deserializer(static_cast(memory), memorySize); -SkScalerContext* SkStrikeServer::generateScalerContext( - const SkScalerContextRecDescriptor& desc, SkFontID typefaceId) -{ + size_t typefaceSize = 0u; + if (!deserializer.read(&typefaceSize)) READ_FAILURE - auto scaler = fScalerContextMap.find(desc); - if (scaler == nullptr) { - auto typefaceIter = fTypefaceMap.find(typefaceId); - if (typefaceIter == nullptr) { - // TODO: handle this with some future fallback strategy. - SK_ABORT("unknown type face"); - // Should never happen - return nullptr; - } - auto tf = typefaceIter->get(); - // TODO: make effects really work. - SkScalerContextEffects effects; - auto mapSc = tf->createScalerContext(effects, &desc.desc(), false); - scaler = fScalerContextMap.set(desc, std::move(mapSc)); + for (size_t i = 0; i < typefaceSize; ++i) { + WireTypeface wire; + if (!deserializer.read(&wire)) READ_FAILURE + + // TODO(khushalsagar): The typeface no longer needs a reference to the + // SkStrikeClient, since all needed glyphs must have been pushed before + // raster. + addTypeface(wire); } - return scaler->get(); -} -sk_sp SkStrikeServer::encodeTypeface(SkTypeface* tf) { - WireTypeface wire = { - SkTypeface::UniqueID(tf), - tf->countGlyphs(), - tf->fontStyle(), - tf->isFixedPitch() - }; - auto typeFace = fTypefaceMap.find(SkTypeface::UniqueID(tf)); - if (typeFace == nullptr) { - fTypefaceMap.set(SkTypeface::UniqueID(tf), sk_ref_sp(tf)); - } - // Can this be done with no copy? - return SkData::MakeWithCopy(&wire, sizeof(wire)); -} + size_t strikeCount = 0u; + if (!deserializer.read(&strikeCount)) READ_FAILURE -// -- SkStrikeClient ------------------------------------------------------------------------------- -SkStrikeClient::SkStrikeClient(SkStrikeCacheClientRPC clientRPC) - : fClientRPC{clientRPC} { } + for (size_t i = 0; i < strikeCount; ++i) { + bool has_glyphs = false; + if (!deserializer.read(&has_glyphs)) READ_FAILURE -void SkStrikeClient::generateFontMetrics( - const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkPaint::FontMetrics* metrics) -{ - fBuffer.clear(); + if (!has_glyphs) continue; - Serializer serializer{&fBuffer}; - serializer.emplace_back(OpCode::kFontMetrics, typefaceProxy.remoteTypefaceID(), rec); + StrikeSpec spec; + if (!deserializer.read(&spec)) READ_FAILURE - auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); - auto inbuffer = fClientRPC(*outBuffer); - Deserializer deserializer(*inbuffer); - *metrics = *deserializer.read(); -} + SkAutoDescriptor sourceAd; + if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE -void SkStrikeClient::generateMetricsAndImage( - const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkArenaAlloc* alloc, - SkGlyph* glyph) -{ - fBuffer.clear(); - Serializer serializer(&fBuffer); - Op *op = serializer.emplace_back( - OpCode::kGlyphMetricsAndImage, typefaceProxy.remoteTypefaceID(), rec); - op->glyphID = glyph->getPackedID(); - - auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); - auto inbuffer = fClientRPC(*outBuffer); - Deserializer deserializer(*inbuffer); - *glyph = *deserializer.read(); - auto imageSize = glyph->computeImageSize(); - glyph->fPathData = nullptr; - glyph->fImage = nullptr; - if (imageSize > 0) { - auto image = deserializer.readArray(imageSize); - SkASSERT(imageSize == image.size()); - glyph->allocImage(alloc); - memcpy(glyph->fImage, image.data(), imageSize); + SkPaint::FontMetrics fontMetrics; + if (!deserializer.read(&fontMetrics)) READ_FAILURE + + // Get the local typeface from remote fontID. + auto* tf = fRemoteFontIdToTypeface.find(spec.typefaceID)->get(); + // Received strikes for a typeface which doesn't exist. + if (!tf) READ_FAILURE + + // Replace the ContextRec in the desc from the server to create the client + // side descriptor. + // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy. + SkAutoDescriptor ad; + auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad); + + auto strike = SkStrikeCache::FindStrikeExclusive(*client_desc); + if (strike == nullptr) { + // Note that we don't need to deserialize the effects since we won't be generating any + // glyphs here anyway, and the desc is still correct since it includes the serialized + // effects. + SkScalerContextEffects effects; + auto scaler = SkStrikeCache::CreateScalerContext(*client_desc, effects, *tf); + strike = SkStrikeCache::CreateStrikeExclusive( + *client_desc, std::move(scaler), &fontMetrics, + skstd::make_unique(spec.discardableHandleId, + fDiscardableHandleManager)); + } + + for (size_t j = 0; j < spec.glyphCount; j++) { + SkGlyph glyph; + if (!deserializer.read(&glyph)) READ_FAILURE + + SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph.getPackedID()); + *allocatedGlyph = glyph; + + ArraySlice image; + auto imageSize = glyph.computeImageSize(); + if (imageSize != 0) { + image = deserializer.readArray(imageSize); + if (!image.data()) READ_FAILURE + allocatedGlyph->allocImage(strike->getAlloc()); + memcpy(allocatedGlyph->fImage, image.data(), image.size()); + } + } } -} -bool SkStrikeClient::generatePath( - const SkTypefaceProxy& typefaceProxy, - const SkScalerContextRec& rec, - SkGlyphID glyphID, - SkPath* path) -{ - fBuffer.clear(); - - Serializer serializer{&fBuffer}; - Op *op = serializer.emplace_back( - OpCode::kGlyphPath, typefaceProxy.remoteTypefaceID(), rec); - op->glyphID = glyphID; - - auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); - auto inbuffer = fClientRPC(*outBuffer); - Deserializer deserializer(*inbuffer); - size_t pathSize = *deserializer.read(); - if (pathSize == 0) { - return false; - } - auto rawPath = deserializer.readArray(pathSize); - path->readFromMemory(rawPath.data(), rawPath.size()); return true; } -void SkStrikeClient::primeStrikeCache(const SkStrikeCacheDifferenceSpec& strikeDifferences) { - fBuffer.clear(); - fBuffer.reserve(strikeDifferences.sizeBytes()); - - Serializer serializer{&fBuffer}; - write_strikes_spec(strikeDifferences, &serializer); +sk_sp SkStrikeClient::deserializeTypeface(const void* buf, size_t len) { + WireTypeface wire; + if (len != sizeof(wire)) return nullptr; - auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size()); - auto inbuffer = fClientRPC(*outBuffer); - Deserializer deserializer(*inbuffer); - update_caches_from_strikes_data(this, &deserializer); + memcpy(&wire, buf, sizeof(wire)); + return addTypeface(wire); } -void SkStrikeClient::prepareDeserializeProcs(SkDeserialProcs* procs) { - auto decode = [](const void* buf, size_t len, void* ctx) { - return reinterpret_cast(ctx)->decodeTypeface(buf, len); - }; - procs->fTypefaceProc = decode; - procs->fTypefaceCtx = this; +sk_sp SkStrikeClient::addTypeface(const WireTypeface& wire) { + auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID); + if (typeface) return *typeface; + auto newTypeface = sk_make_sp(wire.typefaceID, wire.glyphCount, wire.style, + wire.isFixed, this); + fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface); + return newTypeface; } -SkTypeface* SkStrikeClient::lookupTypeface(SkFontID id) { - auto typeface = fMapIdToTypeface.find(id); - SkASSERT(typeface != nullptr); - return typeface->get(); +void SkStrikeClient::generateFontMetrics(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkPaint::FontMetrics* metrics) { + TRACE_EVENT1("skia", "generateFontMetrics", "rec", TRACE_STR_COPY(rec.dump().c_str())); + SkDebugf("generateFontMetrics: %s\n", rec.dump().c_str()); + SkStrikeCache::Dump(); + SkDEBUGFAIL("GlyphCacheMiss"); } -sk_sp SkStrikeClient::decodeTypeface(const void* buf, size_t len) { - WireTypeface wire; - if (len < sizeof(wire)) { - SK_ABORT("Incomplete transfer"); - return nullptr; - } - memcpy(&wire, buf, sizeof(wire)); - - auto typeFace = fMapIdToTypeface.find(wire.typefaceID); - if (typeFace == nullptr) { - auto newTypeface = sk_make_sp( - wire.typefaceID, - wire.glyphCount, - wire.style, - wire.isFixed, - this); +void SkStrikeClient::generateMetricsAndImage(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkArenaAlloc* alloc, + SkGlyph* glyph) { + TRACE_EVENT1("skia", "generateMetricsAndImage", "rec", TRACE_STR_COPY(rec.dump().c_str())); + SkDebugf("generateMetricsAndImage: %s\n", rec.dump().c_str()); + SkStrikeCache::Dump(); + SkDEBUGFAIL("GlyphCacheMiss"); +} - typeFace = fMapIdToTypeface.set(wire.typefaceID, newTypeface); - } - return *typeFace; +void SkStrikeClient::generatePath(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkGlyphID glyphID, + SkPath* path) { + TRACE_EVENT1("skia", "generateMetricsAndImage", "rec", TRACE_STR_COPY(rec.dump().c_str())); + SkDebugf("generatePath: %s\n", rec.dump().c_str()); + SkStrikeCache::Dump(); + SkDEBUGFAIL("GlyphCacheMiss"); } diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h index ff905862fa..b210f1c6d7 100644 --- a/src/core/SkRemoteGlyphCache.h +++ b/src/core/SkRemoteGlyphCache.h @@ -5,192 +5,196 @@ * found in the LICENSE file. */ -#ifndef SkRemoteGlyphCache_DEFINED -#define SkRemoteGlyphCache_DEFINED +#ifndef SkRemoteGlyphCachePriv_DEFINED +#define SkRemoteGlyphCachePriv_DEFINED #include #include #include +#include #include +#include "../private/SkTHash.h" #include "SkData.h" -#include "SkDescriptor.h" #include "SkDrawLooper.h" -#include "SkGlyphCache.h" #include "SkMakeUnique.h" #include "SkNoDrawCanvas.h" #include "SkRefCnt.h" +#include "SkRemoteGlyphCache.h" #include "SkSerialProcs.h" -#include "SkStrikeCache.h" -#include "SkTextBlobRunIterator.h" -#include "SkTHash.h" #include "SkTypeface.h" -#include "SkTypeface_remote.h" -// The client uses a SkStrikeCacheClientRPC to send and receive data. -using SkStrikeCacheClientRPC = std::function(const SkData&)>; +class Serializer; +class SkDescriptor; +class SkGlyphCache; +struct SkPackedGlyphID; +class SkScalerContextRecDescriptor; +class SkTextBlobRunIterator; +class SkTypefaceProxy; +struct WireTypeface; -class SkScalerContextRecDescriptor { -public: - SkScalerContextRecDescriptor() {} - explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) { - auto desc = reinterpret_cast(&fDescriptor); - desc->init(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - desc->computeChecksum(); - SkASSERT(sizeof(fDescriptor) == desc->getLength()); - } - - explicit SkScalerContextRecDescriptor(const SkDescriptor& desc) - : SkScalerContextRecDescriptor(ExtractRec(desc)) { } - - SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) { - std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength()); - return *this; - } - - const SkDescriptor& desc() const { - return *reinterpret_cast(&fDescriptor); - } - - struct Hash { - uint32_t operator()(SkScalerContextRecDescriptor const& s) const { - return s.desc().getChecksum(); - } - }; - - friend bool operator==(const SkScalerContextRecDescriptor& lhs, - const SkScalerContextRecDescriptor& rhs ) { - return lhs.desc() == rhs.desc(); - } +class SkStrikeServer; -private: - static SkScalerContextRec ExtractRec(const SkDescriptor& desc) { - uint32_t size; - auto recPtr = desc.findEntry(kRec_SkDescriptorTag, &size); - - SkScalerContextRec result; - std::memcpy(&result, recPtr, size); - return result; - } - // The system only passes descriptors without effects. That is why it uses a fixed size - // descriptor. storageFor is needed because some of the constructors below are private. - template - using storageFor = typename std::aligned_storage::type; - struct { - storageFor dummy1; - storageFor dummy2; - storageFor dummy3; - } fDescriptor; +struct SkDescriptorMapOperators { + size_t operator()(const SkDescriptor* key) const; + bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const; }; -class SkStrikeDifferences { -public: - SkStrikeDifferences(SkFontID typefaceID, std::unique_ptr desc); - void add(uint16_t glyphID, SkIPoint pos); - SkFontID fTypefaceID; - std::unique_ptr fDesc; - std::unique_ptr> fGlyphIDs = - skstd::make_unique>(); -}; +template +using SkDescriptorMap = std::unordered_map; -class SkStrikeCacheDifferenceSpec { -public: - SkStrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID); - int strikeCount() const { return fDescriptorToDifferencesMap.size(); } - size_t sizeBytes() const; - template - void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const; +using SkDescriptorSet = + std::unordered_set; -private: - SkDescriptorMap fDescriptorToDifferencesMap{16}; -}; - -class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { +// A SkTextBlobCacheDiffCanvas is used to populate the SkStrikeServer with ops +// which will be serialized and renderered using the SkStrikeClient. +class SK_API SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { public: - SkTextBlobCacheDiffCanvas(int width, int height, - const SkMatrix& deviceMatrix, - const SkSurfaceProps& props, - SkScalerContextFlags flags, - SkStrikeCacheDifferenceSpec* strikeDiffs); + SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix, + const SkSurfaceProps& props, SkStrikeServer* strikeserver); + ~SkTextBlobCacheDiffCanvas() override; protected: - SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; - void onDrawTextBlob( - const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; private: - void processLooper( - const SkPoint& position, - const SkTextBlobRunIterator& it, - const SkPaint& origPaint, - SkDrawLooper* looper); - - void processGlyphRun( - const SkPoint& position, - const SkTextBlobRunIterator& it, - const SkPaint& runPaint); + void processLooper(const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& origPaint, + SkDrawLooper* looper); + void processGlyphRun(const SkPoint& position, + const SkTextBlobRunIterator& it, + const SkPaint& runPaint); const SkMatrix fDeviceMatrix; const SkSurfaceProps fSurfaceProps; - const SkScalerContextFlags fScalerContextFlags; - - SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff; + SkStrikeServer* const fStrikeServer; }; -class SkStrikeServer { -public: - SkStrikeServer(); - ~SkStrikeServer(); +using SkDiscardableHandleId = uint32_t; - // embedding clients call these methods - void serve(const SkData&, std::vector*); +// This class is not thread-safe. +class SK_API SkStrikeServer { +public: + // An interface used by the server to create handles for pinning SkGlyphCache + // entries on the remote client. + class SK_API DiscardableHandleManager { + public: + virtual ~DiscardableHandleManager() {} + + // Creates a new *locked* handle and returns a unique ID that can be used to identify + // it on the remote client. + virtual SkDiscardableHandleId createHandle() = 0; + + // Returns true if the handle could be successfully locked. The server can + // assume it will remain locked until the next set of serialized entries is + // pulled from the SkStrikeServer. + // If returns false, the cache entry mapped to the handle has been deleted + // on the client. Any subsequent attempts to lock the same handle are not + // allowed. + virtual bool lockHandle(SkDiscardableHandleId) = 0; + + // TODO(khushalsagar): Add an API which checks whether a handle is still + // valid without locking, so we can avoid tracking stale handles once they + // have been purged on the remote side. + }; - void prepareSerializeProcs(SkSerialProcs* procs); + SkStrikeServer(DiscardableHandleManager* discardableHandleManager); + ~SkStrikeServer(); - // mostly called internally by Skia - SkScalerContext* generateScalerContext( - const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); + // Serializes the typeface to be remoted using this server. + sk_sp serializeTypeface(SkTypeface*); + + // Serializes the strike data captured using a SkTextBlobCacheDiffCanvas. Any + // handles locked using the DiscardableHandleManager will be assumed to be + // unlocked after this call. + void writeStrikeData(std::vector* memory); + + // Methods used internally in skia ------------------------------------------ + class SkGlyphCacheState { + public: + SkGlyphCacheState(std::unique_ptr desc, + SkDiscardableHandleId discardableHandleId); + ~SkGlyphCacheState(); + + void addGlyph(SkTypeface*, const SkScalerContextEffects&, SkPackedGlyphID); + void writePendingGlyphs(Serializer* serializer); + bool has_pending_glyphs() const { return !fPendingGlyphs.empty(); } + SkDiscardableHandleId discardable_handle_id() const { return fDiscardableHandleId; } + + private: + // The set of glyphs cached on the remote client. + SkTHashSet fCachedGlyphs; + + // The set of glyphs which has not yet been serialized and sent to the + // remote client. + std::vector fPendingGlyphs; + + std::unique_ptr fDesc; + const SkDiscardableHandleId fDiscardableHandleId = -1; + std::unique_ptr fContext; + }; + SkGlyphCacheState* getOrCreateCache(SkTypeface*, std::unique_ptr); private: - using DescriptorToContextMap = SkTHashMap, - SkScalerContextRecDescriptor::Hash>; - - sk_sp encodeTypeface(SkTypeface* tf); + SkDescriptorMap> fRemoteGlyphStateMap; + DiscardableHandleManager* const fDiscardableHandleManager; + SkTHashSet fCachedTypefaces; - int fOpCount = 0; - SkTHashMap> fTypefaceMap; - DescriptorToContextMap fScalerContextMap; + // State cached until the next serialization. + SkDescriptorSet fLockedDescs; + std::vector fTypefacesToSend; }; -class SkStrikeClient { +class SK_API SkStrikeClient { public: - SkStrikeClient(SkStrikeCacheClientRPC); - - // embedding clients call these methods - void primeStrikeCache(const SkStrikeCacheDifferenceSpec&); - void prepareDeserializeProcs(SkDeserialProcs* procs); + // An interface to delete handles that may be pinned by the remote server. + class DiscardableHandleManager : public SkRefCnt { + public: + virtual ~DiscardableHandleManager() {} + + // Returns true if the handle was unlocked and can be safely deleted. Once + // successful, subsequent attempts to delete the same handle are invalid. + virtual bool deleteHandle(SkDiscardableHandleId) = 0; + }; - // mostly called internally by Skia - void generateFontMetrics( - const SkTypefaceProxy&, const SkScalerContextRec&, SkPaint::FontMetrics*); - void generateMetricsAndImage( - const SkTypefaceProxy&, const SkScalerContextRec&, SkArenaAlloc*, SkGlyph*); - bool generatePath( - const SkTypefaceProxy&, const SkScalerContextRec&, SkGlyphID glyph, SkPath* path); - SkTypeface* lookupTypeface(SkFontID id); + SkStrikeClient(sk_sp); + ~SkStrikeClient(); + + // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the + // data is invalid. + sk_sp deserializeTypeface(const void* data, size_t length); + + // Deserializes the strike data from a SkStrikeServer. All messages generated + // from a server when serializing the ops must be deserialized before the op + // is rasterized. + // Returns false if the data is invalid. + bool readStrikeData(const volatile void* memory, size_t memorySize); + + // TODO: Remove these since we don't support pulling this data on-demand. + void generateFontMetrics(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkPaint::FontMetrics* metrics); + void generateMetricsAndImage(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkArenaAlloc* alloc, + SkGlyph* glyph); + void generatePath(const SkTypefaceProxy& typefaceProxy, + const SkScalerContextRec& rec, + SkGlyphID glyphID, + SkPath* path); private: - sk_sp decodeTypeface(const void* buf, size_t len); - - // TODO: Figure out how to manage the entries for the following maps. - SkTHashMap> fMapIdToTypeface; + class DiscardableStrikePinner; - SkStrikeCacheClientRPC fClientRPC; + sk_sp addTypeface(const WireTypeface& wire); - std::vector fBuffer; + SkTHashMap> fRemoteFontIdToTypeface; + sk_sp fDiscardableHandleManager; }; -#endif // SkRemoteGlyphCache_DEFINED +#endif // SkRemoteGlyphCachePriv_DEFINED diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 1c6438bc5f..556ec18c67 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -135,8 +135,8 @@ public: fPost2x2[0][1], fPost2x2[1][0], fPost2x2[1][1]); msg.appendf(" frame %g miter %g format %d join %d cap %d flags %#hx\n", fFrameWidth, fMiterLimit, fMaskFormat, fStrokeJoin, fStrokeCap, fFlags); - msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", - fLumBits, fDeviceGamma, fPaintGamma, fContrast); + msg.appendf(" lum bits %x, device gamma %d, paint gamma %d contrast %d\n", fLumBits, + fDeviceGamma, fPaintGamma, fContrast); return msg; } diff --git a/src/core/SkStrikeCache.h b/src/core/SkStrikeCache.h index 3e199da1e9..df048e33be 100644 --- a/src/core/SkStrikeCache.h +++ b/src/core/SkStrikeCache.h @@ -9,6 +9,7 @@ #define SkStrikeCache_DEFINED #include +#include #include "SkDescriptor.h" #include "SkSpinlock.h" @@ -31,24 +32,6 @@ class SkTraceMemoryDump; /////////////////////////////////////////////////////////////////////////////// -struct SkDescriptorMapOperators { - size_t operator()(const SkDescriptor* key) const { - return key->getChecksum(); - } - - bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const { - return *lhs == *rhs; - } -}; - -template -using SkDescriptorMap = - std::unordered_map< - const SkDescriptor*, - T, - SkDescriptorMapOperators, - SkDescriptorMapOperators>; - class SkStrikePinner { public: virtual ~SkStrikePinner() = default; diff --git a/src/core/SkTypeface_remote.cpp b/src/core/SkTypeface_remote.cpp index bc0d04bc2a..3b58af9366 100644 --- a/src/core/SkTypeface_remote.cpp +++ b/src/core/SkTypeface_remote.cpp @@ -6,17 +6,15 @@ */ #include "SkTypeface_remote.h" +#include "SkRemoteGlyphCache.h" #include "SkPaint.h" -#include "SkRemoteGlyphCache.h" -SkScalerContextProxy::SkScalerContextProxy( - sk_sp tf, - const SkScalerContextEffects& effects, - const SkDescriptor* desc, - SkStrikeClient* rsc) - : SkScalerContext{std::move(tf), effects, desc} - , fClient{rsc} {} +SkScalerContextProxy::SkScalerContextProxy(sk_sp tf, + const SkScalerContextEffects& effects, + const SkDescriptor* desc, + SkStrikeClient* rsc) + : SkScalerContext{std::move(tf), effects, desc}, fClient{rsc} {} unsigned SkScalerContextProxy::generateGlyphCount() { SK_ABORT("Should never be called."); @@ -40,7 +38,8 @@ void SkScalerContextProxy::generateImage(const SkGlyph& glyph) { } bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) { - return fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); + fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path); + return true; } void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) { diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h index 85a8fc5617..691b124049 100644 --- a/src/core/SkTypeface_remote.h +++ b/src/core/SkTypeface_remote.h @@ -21,11 +21,10 @@ class SkTypefaceProxy; class SkScalerContextProxy : public SkScalerContext { public: - SkScalerContextProxy( - sk_sp tf, - const SkScalerContextEffects& effects, - const SkDescriptor* desc, - SkStrikeClient* rsc); + SkScalerContextProxy(sk_sp tf, + const SkScalerContextEffects& effects, + const SkDescriptor* desc, + SkStrikeClient* rsc); protected: unsigned generateGlyphCount() override; @@ -52,16 +51,12 @@ private: class SkTypefaceProxy : public SkTypeface { public: - SkTypefaceProxy( - SkFontID fontId, - int glyphCount, - const SkFontStyle& style, - bool isFixed, - SkStrikeClient* rsc) - : INHERITED{style, false} - , fFontId{fontId} - , fGlyphCount{glyphCount} - , fRsc{rsc} { } + SkTypefaceProxy(SkFontID fontId, + int glyphCount, + const SkFontStyle& style, + bool isFixed, + SkStrikeClient* rsc) + : INHERITED{style, false}, fFontId{fontId}, fGlyphCount{glyphCount}, fRsc{rsc} {} SkFontID remoteTypefaceID() const {return fFontId;} int glyphCount() const {return fGlyphCount;} static SkTypefaceProxy* DownCast(SkTypeface* typeface) { @@ -138,6 +133,8 @@ protected: private: const SkFontID fFontId; const int fGlyphCount; + + // TODO: Does this need a ref to the strike client? If yes, make it a weak ref. SkStrikeClient* const fRsc; typedef SkTypeface INHERITED; -- cgit v1.2.3