aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Khushal <khushalsagar@chromium.org>2018-05-01 10:49:04 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-01 18:15:15 +0000
commit101d56359a5a5dc3b8a2a4149ac171e25eb0bec0 (patch)
tree926066f75a16d8c56da1ab3c3fe4701ce170ebb2 /src
parente618eee83350902a06bba9c5b358b6c4c11e836c (diff)
fonts: Set up remote glyph caching to push fonts.
Currently the SkStrikeClient is designed to pull fonts from the server on demand, and to pre-fetch a batched request by analyzing the ops using a SkTextBlobCacheDiffCanvas. This change modifies the design to support a push based model, where the server pushes fonts required by the client and sets up the requisite SkGlyphCaches on the client prior to rasterizing the ops. This model still relies on the SkTextBlobCacheDiffCanvas for analyzing the glyphs required for rasterizing an op. The glyph caches required for raster are locked and missing glyphs to be sent to the client are tracked by the SkStrikeServer. The embedder can serialize this font data at any point, but must ensure that this data is deserialized by the SkStrikeClient at the remote end, before rasterizing any ops analyzed prior to serialization. Any refs on the caches are released once the font data is serialized by the server. The locking of glyph caches relies on the embedder providing discardable handles. These handles can be created on the server and serialized to be sent to the client, and map to an instance of SkGlyphCache. This allows the server to control the lifetime of the caches on the client. Bug: skia:7515 Change-Id: Id39f346b47b60899778404bbd0429ee811d0e53b Reviewed-on: https://skia-review.googlesource.com/120283 Commit-Queue: Khusal Sagar <khushalsagar@chromium.org> Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkRemoteGlyphCache.cpp797
-rw-r--r--src/core/SkRemoteGlyphCache.h288
-rw-r--r--src/core/SkScalerContext.h4
-rw-r--r--src/core/SkStrikeCache.h19
-rw-r--r--src/core/SkTypeface_remote.cpp17
-rw-r--r--src/core/SkTypeface_remote.h27
6 files changed, 551 insertions, 601 deletions
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index ed484dd6fd..e45421aa05 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -9,13 +9,51 @@
#include <iterator>
#include <memory>
+#include <string>
#include <tuple>
#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 <typename T>
class ArraySlice final : public std::tuple<const T*, size_t> {
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<uint8_t>* buffer) : fBuffer{buffer} { }
- template <typename T>
- T* push_back(const T& data) {
- auto result = allocate(sizeof(T), alignof(T));
- return new (result) T(data);
- }
-
template <typename T, typename... Args>
- T* emplace_back(Args&& ... args) {
+ T* emplace(Args&&... args) {
auto result = allocate(sizeof(T), alignof(T));
return new (result) T{std::forward<Args>(args)...};
}
+ template <typename T>
+ void write(const T& data) {
+ T* result = (T*)allocate(sizeof(T), alignof(T));
+ memcpy(result, &data, sizeof(T));
+ }
+
+ template <typename T>
+ 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 <typename T>
- 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<const char*>(result), sizeof(T));
+ return true;
+ }
+
+ bool readDescriptor(SkAutoDescriptor* ad) {
+ uint32_t desc_length = 0u;
+ if (!read<uint32_t>(&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<const char*>(result), desc_length);
+ return true;
}
template <typename T>
ArraySlice<T> 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<T>();
+
ArraySlice<T> result = ArraySlice<T>{base, (uint32_t)count};
- fCursor = padded + size;
return result;
}
- size_t size() {return fCursor;}
-
private:
- const SkData& fBuffer;
- size_t fCursor{0};
-};
-
+ const volatile char* ensureAtLeast(size_t size, size_t alignment) {
+ size_t padded = pad(fBytesRead, alignment);
-// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------
+ // Not enough data
+ if (padded + size > fMemorySize) return nullptr;
-SkStrikeDifferences::SkStrikeDifferences(
- SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc)
- : fTypefaceID{typefaceID}
- , fDesc{std::move(desc)} { }
-
-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 <typename PerStrike, typename PerGlyph>
-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{new TrackLayerDevice{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,21 @@ 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.
SkScalerContext::MakeRecAndEffects(runPaint, &fSurfaceProps, &runMatrix,
- fScalerContextFlags, &rec, &effects);
-
- auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
+ SkScalerContextFlags::kFakeGammaAndBoostContrast, &rec,
+ &effects);
- 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<SkStrikeServer*>(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 +378,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, <image bits>)
-// * 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<Op>(OpCode::kPrepopulateCache, SkFontID{0}, SkScalerContextRec{});
+SkStrikeServer::~SkStrikeServer() = default;
- serializer->emplace_back<StrikeDiffHeader>(spec.strikeCount());
+sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
+ WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
+ tf->isFixedPitch());
+ return SkData::MakeWithCopy(&wire, sizeof(wire));
+}
+
+void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
+ if (fLockedDescs.empty() && fTypefacesToSend.empty()) return;
- auto perStrike = [serializer](SkFontID typefaceID, const SkDescriptor& desc, int glyphCount) {
- serializer->emplace_back<StrikeSpec>(typefaceID, desc.getLength(), glyphCount);
- serializer->writeDescriptor(desc);
- };
+ Serializer serializer(memory);
+ serializer.emplace<size_t>(fTypefacesToSend.size());
+ for (const auto& tf : fTypefacesToSend) serializer.write<WireTypeface>(tf);
+ fTypefacesToSend.clear();
- auto perGlyph = [serializer](SkPackedGlyphID glyphID) {
- serializer->push_back<SkPackedGlyphID>(glyphID);
- };
+ serializer.emplace<size_t>(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<bool>(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<StrikeDiffHeader>();
- serializer->push_back<StrikeDiffHeader>(*header);
- for (int i = 0; i < header->strikeCount; i++) {
- auto spec = deserializer->read<StrikeSpec>();
- auto desc = deserializer->readDescriptor();
- serializer->push_back<StrikeSpec>(*spec);
- serializer->writeDescriptor(*desc);
- SkScalerContextRecDescriptor recDesc{*desc};
- auto scaler = server->generateScalerContext(recDesc, spec->typefaceID);
- SkPaint::FontMetrics fontMetrics;
- scaler->getFontMetrics(&fontMetrics);
- serializer->push_back<SkPaint::FontMetrics>(fontMetrics);
- auto glyphIDs = deserializer->readArray<SkPackedGlyphID>(spec->glyphCount);
- for (auto glyphID : glyphIDs) {
- auto glyph = serializer->emplace_back<SkGlyph>();
- 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<uint8_t>(imageSize);
- scaler->getImage(stationaryGlyph);
- }
+SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
+ SkTypeface* tf, std::unique_ptr<SkDescriptor> 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<SkGlyphCacheState>(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<StrikeDiffHeader>();
- for (int i = 0; i < header->strikeCount; i++) {
- auto spec = deserializer->read<StrikeSpec>();
- auto desc = deserializer->readDescriptor();
- auto fontMetrics = deserializer->read<SkPaint::FontMetrics>();
- 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<SkGlyph>();
- ArraySlice<uint8_t> image;
- auto imageSize = glyph->computeImageSize();
- if (imageSize != 0) {
- image = deserializer->readArray<uint8_t>(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<SkDescriptor> 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<StrikeSpec>(fContext->getTypeface()->uniqueID(), fPendingGlyphs.size(),
+ fDiscardableHandleId);
+ serializer->writeDescriptor(*fDesc.get());
+
+ // Write FontMetrics.
+ SkPaint::FontMetrics fontMetrics;
+ fContext->getFontMetrics(&fontMetrics);
+ serializer->write<SkPaint::FontMetrics>(fontMetrics);
+
+ // Write Glyphs.
+ for (const auto& glyphID : fPendingGlyphs) {
+ auto glyph = serializer->emplace<SkGlyph>();
+ 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<uint8_t>(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<DiscardableHandleManager> manager)
+ : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
-void SkStrikeServer::serve(const SkData& inBuffer, std::vector<uint8_t>* outBuffer) {
+ ~DiscardableStrikePinner() override = default;
+ bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
- fOpCount += 1;
+private:
+ const SkDiscardableHandleId fDiscardableHandleId;
+ sk_sp<DiscardableHandleManager> fManager;
+};
- Serializer serializer{outBuffer};
- Deserializer deserializer{inBuffer};
- Op* op = deserializer.read<Op>();
+SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> 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<SkPaint::FontMetrics>(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<size_t>(pathSize);
- auto pathData = serializer.allocateArray<uint8_t>(pathSize);
- path.writeToMemory(pathData);
- }
- break;
- }
- case OpCode::kGlyphMetricsAndImage : {
- auto scaler = this->generateScalerContext(op->descriptor, op->typefaceId);
-
- auto glyph = serializer.emplace_back<SkGlyph>();
- // 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<uint8_t>(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<SkStrikeServer*>(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<const volatile char*>(memory), memorySize);
-SkScalerContext* SkStrikeServer::generateScalerContext(
- const SkScalerContextRecDescriptor& desc, SkFontID typefaceId)
-{
+ size_t typefaceSize = 0u;
+ if (!deserializer.read<size_t>(&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<WireTypeface>(&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<SkData> 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<size_t>(&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<bool>(&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<Op>(OpCode::kFontMetrics, typefaceProxy.remoteTypefaceID(), rec);
+ StrikeSpec spec;
+ if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
- auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size());
- auto inbuffer = fClientRPC(*outBuffer);
- Deserializer deserializer(*inbuffer);
- *metrics = *deserializer.read<SkPaint::FontMetrics>();
-}
+ 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<Op>(
- 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<SkGlyph>();
- auto imageSize = glyph->computeImageSize();
- glyph->fPathData = nullptr;
- glyph->fImage = nullptr;
- if (imageSize > 0) {
- auto image = deserializer.readArray<uint8_t>(imageSize);
- SkASSERT(imageSize == image.size());
- glyph->allocImage(alloc);
- memcpy(glyph->fImage, image.data(), imageSize);
+ SkPaint::FontMetrics fontMetrics;
+ if (!deserializer.read<SkPaint::FontMetrics>(&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<DiscardableStrikePinner>(spec.discardableHandleId,
+ fDiscardableHandleManager));
+ }
+
+ for (size_t j = 0; j < spec.glyphCount; j++) {
+ SkGlyph glyph;
+ if (!deserializer.read<SkGlyph>(&glyph)) READ_FAILURE
+
+ ArraySlice<uint8_t> image;
+ auto imageSize = glyph.computeImageSize();
+ if (imageSize != 0) {
+ image = deserializer.readArray<uint8_t>(imageSize);
+ if (!image.data()) READ_FAILURE
+ }
+
+ SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph.getPackedID());
+ *allocatedGlyph = glyph;
+ 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<Op>(
- 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<size_t>();
- if (pathSize == 0) {
- return false;
- }
- auto rawPath = deserializer.readArray<uint8_t>(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<SkTypeface> 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<SkStrikeClient*>(ctx)->decodeTypeface(buf, len);
- };
- procs->fTypefaceProc = decode;
- procs->fTypefaceCtx = this;
+sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
+ auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
+ if (typeface) return *typeface;
+ auto newTypeface = sk_make_sp<SkTypefaceProxy>(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<SkTypeface> 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<SkTypefaceProxy>(
- 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 <memory>
#include <tuple>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
+#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<sk_sp<SkData>(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<SkDescriptor*>(&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<const SkDescriptor*>(&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 <typename T>
- using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
- struct {
- storageFor<SkDescriptor> dummy1;
- storageFor<SkDescriptor::Entry> dummy2;
- storageFor<SkScalerContextRec> 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<SkDescriptor> desc);
- void add(uint16_t glyphID, SkIPoint pos);
- SkFontID fTypefaceID;
- std::unique_ptr<SkDescriptor> fDesc;
- std::unique_ptr<SkTHashSet<SkPackedGlyphID>> fGlyphIDs =
- skstd::make_unique<SkTHashSet<SkPackedGlyphID>>();
-};
+template <typename T>
+using SkDescriptorMap = std::unordered_map<const SkDescriptor*, T, SkDescriptorMapOperators,
+ SkDescriptorMapOperators>;
-class SkStrikeCacheDifferenceSpec {
-public:
- SkStrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID);
- int strikeCount() const { return fDescriptorToDifferencesMap.size(); }
- size_t sizeBytes() const;
- template <typename PerStrike, typename PerGlyph>
- void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const;
+using SkDescriptorSet =
+ std::unordered_set<const SkDescriptor*, SkDescriptorMapOperators, SkDescriptorMapOperators>;
-private:
- SkDescriptorMap<SkStrikeDifferences> 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<uint8_t>*);
+// 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<SkData> 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<uint8_t>* memory);
+
+ // Methods used internally in skia ------------------------------------------
+ class SkGlyphCacheState {
+ public:
+ SkGlyphCacheState(std::unique_ptr<SkDescriptor> 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<SkPackedGlyphID> fCachedGlyphs;
+
+ // The set of glyphs which has not yet been serialized and sent to the
+ // remote client.
+ std::vector<SkPackedGlyphID> fPendingGlyphs;
+
+ std::unique_ptr<SkDescriptor> fDesc;
+ const SkDiscardableHandleId fDiscardableHandleId = -1;
+ std::unique_ptr<SkScalerContext> fContext;
+ };
+ SkGlyphCacheState* getOrCreateCache(SkTypeface*, std::unique_ptr<SkDescriptor>);
private:
- using DescriptorToContextMap = SkTHashMap<SkScalerContextRecDescriptor,
- std::unique_ptr<SkScalerContext>,
- SkScalerContextRecDescriptor::Hash>;
-
- sk_sp<SkData> encodeTypeface(SkTypeface* tf);
+ SkDescriptorMap<std::unique_ptr<SkGlyphCacheState>> fRemoteGlyphStateMap;
+ DiscardableHandleManager* const fDiscardableHandleManager;
+ SkTHashSet<SkFontID> fCachedTypefaces;
- int fOpCount = 0;
- SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap;
- DescriptorToContextMap fScalerContextMap;
+ // State cached until the next serialization.
+ SkDescriptorSet fLockedDescs;
+ std::vector<WireTypeface> 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<DiscardableHandleManager>);
+ ~SkStrikeClient();
+
+ // Deserializes the typeface previously serialized using the SkStrikeServer. Returns null if the
+ // data is invalid.
+ sk_sp<SkTypeface> 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<SkTypeface> decodeTypeface(const void* buf, size_t len);
-
- // TODO: Figure out how to manage the entries for the following maps.
- SkTHashMap<SkFontID, sk_sp<SkTypefaceProxy>> fMapIdToTypeface;
+ class DiscardableStrikePinner;
- SkStrikeCacheClientRPC fClientRPC;
+ sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
- std::vector<uint8_t> fBuffer;
+ SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface;
+ sk_sp<DiscardableHandleManager> fDiscardableHandleManager;
};
-#endif // SkRemoteGlyphCache_DEFINED
+#endif // SkRemoteGlyphCachePriv_DEFINED
diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h
index 84abdcc1a4..675e9a0524 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 <unordered_map>
+#include <unordered_set>
#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 <typename T>
-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<SkTypeface> tf,
- const SkScalerContextEffects& effects,
- const SkDescriptor* desc,
- SkStrikeClient* rsc)
- : SkScalerContext{std::move(tf), effects, desc}
- , fClient{rsc} {}
+SkScalerContextProxy::SkScalerContextProxy(sk_sp<SkTypeface> 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<SkTypeface> tf,
- const SkScalerContextEffects& effects,
- const SkDescriptor* desc,
- SkStrikeClient* rsc);
+ SkScalerContextProxy(sk_sp<SkTypeface> 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;