aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Khushal <khushalsagar@chromium.org>2018-05-02 10:29:37 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-02 18:39:31 +0000
commit38a08436886e82de4eb9ebdbcb2bbd5ea7b05c6d (patch)
tree3477528878c8d4b0a053fbc807efd02e60fcde14 /src
parent81afc04b5368fc4a7cb6ae4b4d7069e67a3a51f8 (diff)
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 <khushalsagar@chromium.org> Reviewed-by: Khusal Sagar <khushalsagar@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkRemoteGlyphCache.cpp798
-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, 552 insertions, 601 deletions
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 <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};
-};
-
-
-// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------
+ const volatile char* ensureAtLeast(size_t size, size_t alignment) {
+ size_t padded = pad(fBytesRead, alignment);
-SkStrikeDifferences::SkStrikeDifferences(
- SkFontID typefaceID, std::unique_ptr<SkDescriptor> 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 <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{sk_make_sp<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,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<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 +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, <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;
+
+sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
+ WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
+ tf->isFixedPitch());
+ return SkData::MakeWithCopy(&wire, sizeof(wire));
+}
- serializer->emplace_back<StrikeDiffHeader>(spec.strikeCount());
+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
+
+ SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph.getPackedID());
+ *allocatedGlyph = glyph;
+
+ ArraySlice<uint8_t> image;
+ auto imageSize = glyph.computeImageSize();
+ if (imageSize != 0) {
+ image = deserializer.readArray<uint8_t>(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<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 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 <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;