aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gn/tests.gni1
-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
-rw-r--r--tests/SkRemoteGlyphCacheTest.cpp220
-rw-r--r--tools/remote_demo.cpp130
9 files changed, 642 insertions, 861 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index ebf83bbd63..d18758c05e 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -226,7 +226,6 @@ tests_sources = [
"$_tests/SkNxTest.cpp",
"$_tests/SkPEGTest.cpp",
"$_tests/SkRasterPipelineTest.cpp",
- "$_tests/SkRemoteGlyphCacheTest.cpp",
"$_tests/SkResourceCacheTest.cpp",
"$_tests/SkSharedMutexTest.cpp",
"$_tests/SkSLErrorTest.cpp",
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
index e45421aa05..ed484dd6fd 100644
--- a/src/core/SkRemoteGlyphCache.cpp
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -9,51 +9,13 @@
#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:
@@ -64,6 +26,7 @@ public:
const T* begin() {
return this->data();
}
+
const T* end() {
return &this->data()[this->size()];
}
@@ -83,32 +46,28 @@ private:
// -- Serializer ----------------------------------------------------------------------------------
-size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
+static 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, typename... 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));
+ T* push_back(const T& data) {
+ auto result = allocate(sizeof(T), alignof(T));
+ return new (result) T(data);
}
- template <typename T>
- T* allocate() {
- T* result = (T*)allocate(sizeof(T), alignof(T));
- return result;
+ template <typename T, typename... Args>
+ T* emplace_back(Args&& ... args) {
+ auto result = allocate(sizeof(T), alignof(T));
+ return new (result) T{std::forward<Args>(args)...};
}
void writeDescriptor(const SkDescriptor& desc) {
- write(desc.getLength());
auto result = allocate(desc.getLength(), alignof(SkDescriptor));
memcpy(result, &desc, desc.getLength());
}
@@ -130,69 +89,86 @@ private:
};
// -- Deserializer -------------------------------------------------------------------------------
-// Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
+
class Deserializer {
public:
- Deserializer(const volatile char* memory, size_t memorySize)
- : fMemory(memory), fMemorySize(memorySize) {}
+ Deserializer(const SkData& buffer) : fBuffer{buffer} { }
template <typename T>
- 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;
+ 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;
}
template <typename T>
ArraySlice<T> readArray(int count) {
+ size_t padded = pad(fCursor, alignof(T));
size_t size = count * sizeof(T);
- const T* base = (const T*)this->ensureAtLeast(size, alignof(T));
- if (!base) return ArraySlice<T>();
-
+ auto data = (uint8_t*)fBuffer.data();
+ const T* base = (const T*)&data[padded];
ArraySlice<T> result = ArraySlice<T>{base, (uint32_t)count};
+ fCursor = padded + size;
return result;
}
+ size_t size() {return fCursor;}
+
private:
- const volatile char* ensureAtLeast(size_t size, size_t alignment) {
- size_t padded = pad(fBytesRead, alignment);
+ const SkData& fBuffer;
+ size_t fCursor{0};
+};
- // Not enough data
- if (padded + size > fMemorySize) return nullptr;
- auto* result = fMemory + padded;
- fBytesRead = padded + size;
- return result;
- }
+// -- SkStrikeCacheDifferenceSpec ------------------------------------------------------------------
- // 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;
-};
+SkStrikeDifferences::SkStrikeDifferences(
+ SkFontID typefaceID, std::unique_ptr<SkDescriptor> desc)
+ : fTypefaceID{typefaceID}
+ , fDesc{std::move(desc)} { }
-size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const {
- return key->getChecksum();
+void SkStrikeDifferences::add(uint16_t glyphID, SkIPoint pos) {
+ SkPackedGlyphID packedGlyphID{glyphID, pos.x(), pos.y()};
+ fGlyphIDs->add(packedGlyphID);
+}
+
+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)};
+
+ mapIter = fDescriptorToDifferencesMap.emplace_hint(
+ mapIter, newDescPtr, std::move(strikeDiffs));
}
- bool SkDescriptorMapOperators::operator()(const SkDescriptor* lhs,
- const SkDescriptor* rhs) const {
- return *lhs == *rhs;
+ 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);
+ });
}
+}
// -- TrackLayerDevice -----------------------------------------------------------------------------
class TrackLayerDevice : public SkNoPixelsDevice {
@@ -206,18 +182,17 @@ public:
};
// -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
-SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
- const SkMatrix& deviceMatrix,
- const SkSurfaceProps& props,
- SkStrikeServer* strikeSever)
+SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(
+ int width, int height,
+ const SkMatrix& deviceMatrix,
+ const SkSurfaceProps& props,
+ SkScalerContextFlags flags,
+ SkStrikeCacheDifferenceSpec* strikeDiffs)
: SkNoDrawCanvas{new TrackLayerDevice{SkIRect::MakeWH(width, height), props}}
, fDeviceMatrix{deviceMatrix}
, fSurfaceProps{props}
- , fStrikeServer{strikeSever} {
- SkASSERT(fStrikeServer);
-}
-
-SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() = default;
+ , fScalerContextFlags{flags}
+ , fStrikeCacheDiff{strikeDiffs} { }
SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
const SaveLayerRec&rec)
@@ -260,10 +235,6 @@ void SkTextBlobCacheDiffCanvas::processLooper(
}
}
-#define FAIL_AND_RETURN \
- SkDEBUGFAIL("Failed to process glyph run"); \
- return;
-
void SkTextBlobCacheDiffCanvas::processGlyphRun(
const SkPoint& position,
const SkTextBlobRunIterator& it,
@@ -271,24 +242,20 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
{
if (runPaint.getTextEncoding() != SkPaint::TextEncoding::kGlyphID_TextEncoding) {
- TRACE_EVENT0("skia", "kGlyphID_TextEncoding");
- FAIL_AND_RETURN
+ return;
}
// All other alignment modes need the glyph advances. Use the slow drawing mode.
if (runPaint.getTextAlign() != SkPaint::kLeft_Align) {
- TRACE_EVENT0("skia", "kLeft_Align");
- FAIL_AND_RETURN
+ 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.
- TRACE_EVENT0("skia", "kDefault_Positioning");
- FAIL_AND_RETURN
- }
+ return;
case SkTextBlob::kHorizontal_Positioning:
posFn = [](int index, const SkScalar* pos) {
@@ -311,8 +278,7 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
SkMatrix blobMatrix{fDeviceMatrix};
blobMatrix.preConcat(this->getTotalMatrix());
if (blobMatrix.hasPerspective()) {
- TRACE_EVENT0("skia", "hasPerspective");
- FAIL_AND_RETURN
+ return;
}
blobMatrix.preTranslate(position.x(), position.y());
@@ -349,21 +315,19 @@ 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,
- SkScalerContextFlags::kFakeGammaAndBoostContrast, &rec,
- &effects);
+ fScalerContextFlags, &rec, &effects);
+
+ auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
- 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 typefaceID = SkTypefaceProxy::DownCast(runPaint.getTypeface())->remoteTypefaceID();
+ auto& diffs = fStrikeCacheDiff->findStrikeDifferences(*desc, typefaceID);
+ auto cache = SkStrikeCache::FindStrikeExclusive(*desc);
bool isSubpixel = SkToBool(rec.fFlags & SkScalerContext::kSubpixelPositioning_Flag);
SkAxisAlignment axisAlignment = SkAxisAlignment::kNone_SkAxisAlignment;
if (it.positioning() == SkTextBlob::kHorizontal_Positioning) {
@@ -378,323 +342,392 @@ void SkTextBlobCacheDiffCanvas::processGlyphRun(
subPixelPos = SkFindAndPlaceGlyph::SubpixelAlignment(axisAlignment, glyphPos);
}
- glyphCacheState->addGlyph(runPaint.getTypeface(),
- effects,
- SkPackedGlyphID(glyphs[index], subPixelPos.x(), subPixelPos.y()));
+ if (cache &&
+ cache->isGlyphCached(glyphs[index], subPixelPos.x(), subPixelPos.y())) {
+ continue;
+ }
+
+ diffs.add(glyphs[index], subPixelPos);
}
}
+// 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() {}
- StrikeSpec(SkFontID typefaceID_, size_t glyphCount_, SkDiscardableHandleId discardableHandleId_)
+ StrikeSpec(SkFontID typefaceID_, uint32_t descLength_, int glyphCount_)
: typefaceID{typefaceID_}
- , glyphCount{glyphCount_}
- , discardableHandleId(discardableHandleId_) {}
- SkFontID typefaceID = 0u;
- size_t glyphCount = 0u;
- SkDiscardableHandleId discardableHandleId = 0u;
+ , descLength{descLength_}
+ , glyphCount{glyphCount_} { }
+ SkFontID typefaceID;
+ uint32_t descLength;
+ int glyphCount;
/* 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;
};
-// SkStrikeServer -----------------------------------------
-
-SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
- : fDiscardableHandleManager(discardableHandleManager) {
- SkASSERT(fDiscardableHandleManager);
-}
-
-SkStrikeServer::~SkStrikeServer() = default;
+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;
+ };
+};
-sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
- WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
- tf->isFixedPitch());
- return SkData::MakeWithCopy(&wire, sizeof(wire));
+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;
}
-void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
- if (fLockedDescs.empty() && fTypefacesToSend.empty()) return;
+static void write_strikes_spec(const SkStrikeCacheDifferenceSpec &spec,
+ Serializer* serializer) {
+ serializer->emplace_back<Op>(OpCode::kPrepopulateCache, SkFontID{0}, SkScalerContextRec{});
- Serializer serializer(memory);
- serializer.emplace<size_t>(fTypefacesToSend.size());
- for (const auto& tf : fTypefacesToSend) serializer.write<WireTypeface>(tf);
- fTypefacesToSend.clear();
+ serializer->emplace_back<StrikeDiffHeader>(spec.strikeCount());
- serializer.emplace<size_t>(fLockedDescs.size());
- for (const auto* desc : fLockedDescs) {
- auto it = fRemoteGlyphStateMap.find(desc);
- SkASSERT(it != fRemoteGlyphStateMap.end());
+ auto perStrike = [serializer](SkFontID typefaceID, const SkDescriptor& desc, int glyphCount) {
+ serializer->emplace_back<StrikeSpec>(typefaceID, desc.getLength(), glyphCount);
+ serializer->writeDescriptor(desc);
+ };
- // 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;
+ auto perGlyph = [serializer](SkPackedGlyphID glyphID) {
+ serializer->push_back<SkPackedGlyphID>(glyphID);
+ };
- it->second->writePendingGlyphs(&serializer);
- }
- fLockedDescs.clear();
+ spec.iterateDifferences(perStrike, perGlyph);
}
-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();
+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);
+ }
}
-
- // 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;
-}
-
-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);
+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());
}
}
-
- // 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();
}
-// SkStrikeClient -----------------------------------------
+// -- SkStrikeServer -------------------------------------------------------------------------------
+SkStrikeServer::SkStrikeServer() { }
-class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
-public:
- DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
- sk_sp<DiscardableHandleManager> manager)
- : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
+SkStrikeServer::~SkStrikeServer() {
+ printf("Strike server - ops: %d\n", fOpCount);
+}
- ~DiscardableStrikePinner() override = default;
- bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
+void SkStrikeServer::serve(const SkData& inBuffer, std::vector<uint8_t>* outBuffer) {
-private:
- const SkDiscardableHandleId fDiscardableHandleId;
- sk_sp<DiscardableHandleManager> fManager;
-};
+ fOpCount += 1;
-SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager)
- : fDiscardableHandleManager(std::move(discardableManager)) {}
+ Serializer serializer{outBuffer};
+ Deserializer deserializer{inBuffer};
+ Op* op = deserializer.read<Op>();
-SkStrikeClient::~SkStrikeClient() = default;
+ 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;
+ }
-#define READ_FAILURE \
- { \
- SkDEBUGFAIL("Bad serialization"); \
- return false; \
+ default:
+ SK_ABORT("Bad op");
}
+}
-bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
- SkASSERT(memorySize != 0u);
- Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize);
-
- size_t typefaceSize = 0u;
- if (!deserializer.read<size_t>(&typefaceSize)) READ_FAILURE
+void SkStrikeServer::prepareSerializeProcs(SkSerialProcs* procs) {
+ auto encode = [](SkTypeface* tf, void* ctx) {
+ return reinterpret_cast<SkStrikeServer*>(ctx)->encodeTypeface(tf);
+ };
+ procs->fTypefaceProc = encode;
+ procs->fTypefaceCtx = this;
+}
- for (size_t i = 0; i < typefaceSize; ++i) {
- WireTypeface wire;
- if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE
+SkScalerContext* SkStrikeServer::generateScalerContext(
+ const SkScalerContextRecDescriptor& desc, SkFontID typefaceId)
+{
- // TODO(khushalsagar): The typeface no longer needs a reference to the
- // SkStrikeClient, since all needed glyphs must have been pushed before
- // raster.
- addTypeface(wire);
+ 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));
}
+ return scaler->get();
+}
- size_t strikeCount = 0u;
- if (!deserializer.read<size_t>(&strikeCount)) READ_FAILURE
-
- for (size_t i = 0; i < strikeCount; ++i) {
- bool has_glyphs = false;
- if (!deserializer.read<bool>(&has_glyphs)) READ_FAILURE
-
- if (!has_glyphs) continue;
-
- StrikeSpec spec;
- if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
-
- SkAutoDescriptor sourceAd;
- if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE
-
- 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
+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));
+}
- // 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);
+// -- SkStrikeClient -------------------------------------------------------------------------------
+SkStrikeClient::SkStrikeClient(SkStrikeCacheClientRPC clientRPC)
+ : fClientRPC{clientRPC} { }
- 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));
- }
+void SkStrikeClient::generateFontMetrics(
+ const SkTypefaceProxy& typefaceProxy,
+ const SkScalerContextRec& rec,
+ SkPaint::FontMetrics* metrics)
+{
+ fBuffer.clear();
- for (size_t j = 0; j < spec.glyphCount; j++) {
- SkGlyph glyph;
- if (!deserializer.read<SkGlyph>(&glyph)) READ_FAILURE
+ Serializer serializer{&fBuffer};
+ serializer.emplace_back<Op>(OpCode::kFontMetrics, typefaceProxy.remoteTypefaceID(), rec);
- ArraySlice<uint8_t> image;
- auto imageSize = glyph.computeImageSize();
- if (imageSize != 0) {
- image = deserializer.readArray<uint8_t>(imageSize);
- if (!image.data()) READ_FAILURE
- }
+ auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size());
+ auto inbuffer = fClientRPC(*outBuffer);
+ Deserializer deserializer(*inbuffer);
+ *metrics = *deserializer.read<SkPaint::FontMetrics>();
+}
- SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph.getPackedID());
- *allocatedGlyph = glyph;
- allocatedGlyph->allocImage(strike->getAlloc());
- memcpy(allocatedGlyph->fImage, image.data(), image.size());
- }
+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);
}
+}
+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;
}
-sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) {
- WireTypeface wire;
- if (len != sizeof(wire)) return nullptr;
+void SkStrikeClient::primeStrikeCache(const SkStrikeCacheDifferenceSpec& strikeDifferences) {
+ fBuffer.clear();
+ fBuffer.reserve(strikeDifferences.sizeBytes());
- memcpy(&wire, buf, sizeof(wire));
- return addTypeface(wire);
+ Serializer serializer{&fBuffer};
+ write_strikes_spec(strikeDifferences, &serializer);
+
+ auto outBuffer = SkData::MakeWithoutCopy(fBuffer.data(), fBuffer.size());
+ auto inbuffer = fClientRPC(*outBuffer);
+ Deserializer deserializer(*inbuffer);
+ update_caches_from_strikes_data(this, &deserializer);
}
-sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
- auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
- if (typeface) return *typeface;
+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;
- auto newTypeface = sk_make_sp<SkTypefaceProxy>(wire.typefaceID, wire.glyphCount, wire.style,
- wire.isFixed, this);
- fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface);
- return newTypeface;
}
-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");
+SkTypeface* SkStrikeClient::lookupTypeface(SkFontID id) {
+ auto typeface = fMapIdToTypeface.find(id);
+ SkASSERT(typeface != nullptr);
+ return typeface->get();
}
-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");
-}
+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));
-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");
+ auto typeFace = fMapIdToTypeface.find(wire.typefaceID);
+ if (typeFace == nullptr) {
+ auto newTypeface = sk_make_sp<SkTypefaceProxy>(
+ wire.typefaceID,
+ wire.glyphCount,
+ wire.style,
+ wire.isFixed,
+ this);
+
+ typeFace = fMapIdToTypeface.set(wire.typefaceID, newTypeface);
+ }
+ return *typeFace;
}
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
index b210f1c6d7..ff905862fa 100644
--- a/src/core/SkRemoteGlyphCache.h
+++ b/src/core/SkRemoteGlyphCache.h
@@ -5,196 +5,192 @@
* found in the LICENSE file.
*/
-#ifndef SkRemoteGlyphCachePriv_DEFINED
-#define SkRemoteGlyphCachePriv_DEFINED
+#ifndef SkRemoteGlyphCache_DEFINED
+#define SkRemoteGlyphCache_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"
-class Serializer;
-class SkDescriptor;
-class SkGlyphCache;
-struct SkPackedGlyphID;
-class SkScalerContextRecDescriptor;
-class SkTextBlobRunIterator;
-class SkTypefaceProxy;
-struct WireTypeface;
+// The client uses a SkStrikeCacheClientRPC to send and receive data.
+using SkStrikeCacheClientRPC = std::function<sk_sp<SkData>(const SkData&)>;
-class SkStrikeServer;
+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();
+ }
-struct SkDescriptorMapOperators {
- size_t operator()(const SkDescriptor* key) const;
- bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const;
+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;
};
-template <typename T>
-using SkDescriptorMap = std::unordered_map<const SkDescriptor*, T, SkDescriptorMapOperators,
- SkDescriptorMapOperators>;
+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>>();
+};
-using SkDescriptorSet =
- std::unordered_set<const SkDescriptor*, 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;
-// 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 {
+private:
+ SkDescriptorMap<SkStrikeDifferences> fDescriptorToDifferencesMap{16};
+};
+
+class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas {
public:
- SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix,
- const SkSurfaceProps& props, SkStrikeServer* strikeserver);
- ~SkTextBlobCacheDiffCanvas() override;
+ SkTextBlobCacheDiffCanvas(int width, int height,
+ const SkMatrix& deviceMatrix,
+ const SkSurfaceProps& props,
+ SkScalerContextFlags flags,
+ SkStrikeCacheDifferenceSpec* strikeDiffs);
protected:
- SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
+ 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;
- SkStrikeServer* const fStrikeServer;
-};
+ const SkScalerContextFlags fScalerContextFlags;
-using SkDiscardableHandleId = uint32_t;
+ SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff;
+};
-// This class is not thread-safe.
-class SK_API SkStrikeServer {
+class 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.
- };
-
- SkStrikeServer(DiscardableHandleManager* discardableHandleManager);
+ SkStrikeServer();
~SkStrikeServer();
- // 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>);
+ // embedding clients call these methods
+ void serve(const SkData&, std::vector<uint8_t>*);
+
+ void prepareSerializeProcs(SkSerialProcs* procs);
+
+ // mostly called internally by Skia
+ SkScalerContext* generateScalerContext(
+ const SkScalerContextRecDescriptor& desc, SkFontID typefaceId);
private:
- SkDescriptorMap<std::unique_ptr<SkGlyphCacheState>> fRemoteGlyphStateMap;
- DiscardableHandleManager* const fDiscardableHandleManager;
- SkTHashSet<SkFontID> fCachedTypefaces;
+ using DescriptorToContextMap = SkTHashMap<SkScalerContextRecDescriptor,
+ std::unique_ptr<SkScalerContext>,
+ SkScalerContextRecDescriptor::Hash>;
+
+ sk_sp<SkData> encodeTypeface(SkTypeface* tf);
- // State cached until the next serialization.
- SkDescriptorSet fLockedDescs;
- std::vector<WireTypeface> fTypefacesToSend;
+ int fOpCount = 0;
+ SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap;
+ DescriptorToContextMap fScalerContextMap;
};
-class SK_API SkStrikeClient {
+class SkStrikeClient {
public:
- // 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;
- };
+ SkStrikeClient(SkStrikeCacheClientRPC);
- 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);
+ // embedding clients call these methods
+ void primeStrikeCache(const SkStrikeCacheDifferenceSpec&);
+ void prepareDeserializeProcs(SkDeserialProcs* procs);
+
+ // 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);
private:
- class DiscardableStrikePinner;
+ 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;
- sk_sp<SkTypeface> addTypeface(const WireTypeface& wire);
+ SkStrikeCacheClientRPC fClientRPC;
- SkTHashMap<SkFontID, sk_sp<SkTypeface>> fRemoteFontIdToTypeface;
- sk_sp<DiscardableHandleManager> fDiscardableHandleManager;
+ std::vector<uint8_t> fBuffer;
};
-#endif // SkRemoteGlyphCachePriv_DEFINED
+#endif // SkRemoteGlyphCache_DEFINED
diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h
index 675e9a0524..84abdcc1a4 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 df048e33be..3e199da1e9 100644
--- a/src/core/SkStrikeCache.h
+++ b/src/core/SkStrikeCache.h
@@ -9,7 +9,6 @@
#define SkStrikeCache_DEFINED
#include <unordered_map>
-#include <unordered_set>
#include "SkDescriptor.h"
#include "SkSpinlock.h"
@@ -32,6 +31,24 @@ 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 3b58af9366..bc0d04bc2a 100644
--- a/src/core/SkTypeface_remote.cpp
+++ b/src/core/SkTypeface_remote.cpp
@@ -6,15 +6,17 @@
*/
#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.");
@@ -38,8 +40,7 @@ void SkScalerContextProxy::generateImage(const SkGlyph& glyph) {
}
bool SkScalerContextProxy::generatePath(SkGlyphID glyphID, SkPath* path) {
- fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path);
- return true;
+ return fClient->generatePath(*this->typefaceProxy(), this->getRec(), glyphID, path);
}
void SkScalerContextProxy::generateFontMetrics(SkPaint::FontMetrics* metrics) {
diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h
index 691b124049..85a8fc5617 100644
--- a/src/core/SkTypeface_remote.h
+++ b/src/core/SkTypeface_remote.h
@@ -21,10 +21,11 @@ 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;
@@ -51,12 +52,16 @@ 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) {
@@ -133,8 +138,6 @@ 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;
diff --git a/tests/SkRemoteGlyphCacheTest.cpp b/tests/SkRemoteGlyphCacheTest.cpp
deleted file mode 100644
index 7369acec15..0000000000
--- a/tests/SkRemoteGlyphCacheTest.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkGraphics.h"
-#include "SkMutex.h"
-#include "SkRemoteGlyphCache.h"
-#include "SkStrikeCache.h"
-#include "SkSurface.h"
-#include "SkTextBlob.h"
-#include "SkTypeface_remote.h"
-#include "Test.h"
-
-class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
- public SkStrikeClient::DiscardableHandleManager {
-public:
- DiscardableManager() = default;
- ~DiscardableManager() override = default;
-
- // Server implementation.
- SkDiscardableHandleId createHandle() override {
- // Handles starts as locked.
- fLockedHandles.add(++fNextHandleId);
- return fNextHandleId;
- }
- bool lockHandle(SkDiscardableHandleId id) override {
- if (id <= fLastDeletedHandleId) return false;
- fLockedHandles.add(id);
- return true;
- }
-
- // Client implementation.
- bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
-
- void unlockAll() { fLockedHandles.reset(); }
- void unlockAndDeleteAll() {
- unlockAll();
- fLastDeletedHandleId = fNextHandleId;
- }
- const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
- SkDiscardableHandleId handleCount() { return fNextHandleId; }
-
-private:
- SkDiscardableHandleId fNextHandleId = 0u;
- SkDiscardableHandleId fLastDeletedHandleId = 0u;
- SkTHashSet<SkDiscardableHandleId> fLockedHandles;
-};
-
-sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
- SkPaint font;
- font.setTypeface(tf);
- font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- font.setTextAlign(SkPaint::kLeft_Align);
- font.setStyle(SkPaint::kFill_Style);
- font.setHinting(SkPaint::kNormal_Hinting);
- font.setTextSize(1u);
-
- SkTextBlobBuilder builder;
- SkRect bounds = SkRect::MakeWH(10, 10);
- const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
- for (int i = 0; i < glyphCount; i++) runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
- return builder.make();
-}
-
-SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height) {
- auto surface = SkSurface::MakeRasterN32Premul(width, height);
- SkPaint paint;
- surface->getCanvas()->drawTextBlob(blob.get(), 0u, 0u, paint);
- SkBitmap bitmap;
- bitmap.allocN32Pixels(width, height);
- surface->readPixels(bitmap, 0, 0);
- return bitmap;
-}
-
-DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
- sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
- SkStrikeServer server(discardableManager.get());
- SkStrikeClient client(discardableManager);
-
- auto server_tf = SkTypeface::MakeDefault();
- auto tf_data = server.serializeTypeface(server_tf.get());
-
- auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
- REPORTER_ASSERT(reporter, client_tf);
- REPORTER_ASSERT(reporter, SkTypefaceProxy::DownCast(client_tf.get())->remoteTypefaceID() ==
- server_tf->uniqueID());
-}
-
-#if 0
-TODO(khushalsagar): Re-enable once crbug.com/831354 is fixed.
-DEF_TEST(SkRemoteGlyphCache_StrikeSerialization, reporter) {
- sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
- SkStrikeServer server(discardableManager.get());
- SkStrikeClient client(discardableManager);
-
- // Server.
- auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
- auto serverTfData = server.serializeTypeface(serverTf.get());
-
- int glyphCount = 10;
- auto serverBlob = buildTextBlob(serverTf, glyphCount);
- const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
- SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
- SkPaint paint;
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
-
- std::vector<uint8_t> serverStrikeData;
- server.writeStrikeData(&serverStrikeData);
-
- // Client.
- auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
- REPORTER_ASSERT(reporter,
- client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
- auto clientBlob = buildTextBlob(clientTf, glyphCount);
-
- SkBitmap expected = RasterBlob(serverBlob, 10, 10);
- SkBitmap actual = RasterBlob(clientBlob, 10, 10);
- for (int i = 0; i < expected.width(); ++i) {
- for (int j = 0; j < expected.height(); ++j) {
- REPORTER_ASSERT(reporter, expected.getColor(i, j) == actual.getColor(i, j));
- }
- }
-}
-#endif
-
-DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
- sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
- SkStrikeServer server(discardableManager.get());
- SkStrikeClient client(discardableManager);
-
- auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
- server.serializeTypeface(serverTf.get());
- int glyphCount = 10;
- auto serverBlob = buildTextBlob(serverTf, glyphCount);
-
- const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
- SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
- SkPaint paint;
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
-
- // The strike from the blob should be locked after it has been drawn on the canvas.
- REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
- REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
-
- // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
- // again.
- std::vector<uint8_t> fontData;
- server.writeStrikeData(&fontData);
- discardableManager->unlockAll();
- REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
-
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
- REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
- REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
-}
-
-DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
- sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
- SkStrikeServer server(discardableManager.get());
- SkStrikeClient client(discardableManager);
-
- auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
- server.serializeTypeface(serverTf.get());
- int glyphCount = 10;
- auto serverBlob = buildTextBlob(serverTf, glyphCount);
-
- const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
- SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
- SkPaint paint;
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
- REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
-
- // Write the strike data and delete all the handles. Re-analyzing the blob should create new
- // handles.
- std::vector<uint8_t> fontData;
- server.writeStrikeData(&fontData);
- discardableManager->unlockAndDeleteAll();
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
- printf("HandleCount: %d\n ", discardableManager->handleCount());
- REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
-}
-
-DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
- sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
- SkStrikeServer server(discardableManager.get());
- SkStrikeClient client(discardableManager);
-
- // Server.
- auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
- auto serverTfData = server.serializeTypeface(serverTf.get());
-
- int glyphCount = 10;
- auto serverBlob = buildTextBlob(serverTf, glyphCount);
-
- const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
- SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
- SkPaint paint;
- cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
-
- std::vector<uint8_t> serverStrikeData;
- server.writeStrikeData(&serverStrikeData);
-
- // Client.
- REPORTER_ASSERT(reporter,
- client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
- auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
-
- // The cache remains alive until it is pinned in the discardable manager.
- SkGraphics::PurgeFontCache();
- REPORTER_ASSERT(reporter, !clientTf->unique());
-
- // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
- // clientTf.
- discardableManager->unlockAndDeleteAll();
- SkGraphics::PurgeFontCache();
- REPORTER_ASSERT(reporter, clientTf->unique());
-}
diff --git a/tools/remote_demo.cpp b/tools/remote_demo.cpp
index 105a9b3ea7..8fc96cadb8 100644
--- a/tools/remote_demo.cpp
+++ b/tools/remote_demo.cpp
@@ -16,9 +16,8 @@
#include <thread>
#include <unistd.h>
-#include "SkGraphics.h"
#include "SkRemoteGlyphCache.h"
-#include "SkScalerContext.h"
+#include "SkGraphics.h"
#include "SkSurface.h"
static std::string gSkpName;
@@ -26,46 +25,6 @@ static bool gUseGpu = true;
static bool gPurgeFontCaches = true;
static bool gUseProcess = true;
-class ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager {
-public:
- ServerDiscardableManager() = default;
- ~ServerDiscardableManager() override = default;
-
- SkDiscardableHandleId createHandle() override { return ++nextHandleId; }
- bool lockHandle(SkDiscardableHandleId handleId) override {
- return handleId > lastPurgedHandleId;
- }
- void purgeAll() { lastPurgedHandleId = nextHandleId; }
-
-private:
- SkDiscardableHandleId nextHandleId = 0u;
- SkDiscardableHandleId lastPurgedHandleId = 0u;
-};
-
-class ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager {
-public:
- class ScopedPurgeCache {
- public:
- ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) {
- if (fManager) fManager->allowPurging = true;
- }
- ~ScopedPurgeCache() {
- if (fManager) fManager->allowPurging = false;
- }
-
- private:
- ClientDiscardableManager* fManager;
- };
-
- ClientDiscardableManager() = default;
- ~ClientDiscardableManager() override = default;
-
- bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; }
-
-private:
- bool allowPurging = false;
-};
-
static bool write_SkData(int fd, const SkData& data) {
size_t size = data.size();
ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
@@ -84,6 +43,7 @@ static bool write_SkData(int fd, const SkData& data) {
}
static sk_sp<SkData> read_SkData(int fd) {
+
size_t size;
ssize_t readSize = ::read(fd, &size, sizeof(size));
if (readSize <= 0) {
@@ -132,56 +92,44 @@ private:
std::chrono::duration<double> fElapsedSeconds{0.0};
};
-static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer, int writeFd) {
+static void build_prime_cache_spec(const SkIRect &bounds,
+ const SkSurfaceProps &props,
+ const SkPicture &pic,
+ SkStrikeCacheDifferenceSpec *strikeDifference) {
SkMatrix deviceMatrix = SkMatrix::I();
- const SkIRect bounds = pic.cullRect().round();
- const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
- SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), deviceMatrix, props,
- strikeServer);
- pic.playback(&filter);
- std::vector<uint8_t> fontData;
- strikeServer->writeStrikeData(&fontData);
- auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size());
- return write_SkData(writeFd, *data);
+ SkTextBlobCacheDiffCanvas filter(
+ bounds.width(), bounds.height(), deviceMatrix, props,
+ SkScalerContextFlags::kFakeGammaAndBoostContrast,
+ strikeDifference);
+
+ pic.playback(&filter);
}
-static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client,
- ClientDiscardableManager* discardableManager, int readFd, int writeFd) {
- SkDeserialProcs procs;
- auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
- return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length);
- };
- procs.fTypefaceProc = decode;
- procs.fTypefaceCtx = client;
+static void final_draw(std::string outFilename,
+ SkDeserialProcs* procs,
+ SkData* picData,
+ SkStrikeClient* client) {
- auto pic = SkPicture::MakeFromData(picData, &procs);
+ auto pic = SkPicture::MakeFromData(picData, procs);
auto cullRect = pic->cullRect();
auto r = cullRect.round();
auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
auto c = s->getCanvas();
- auto picUnderTest = SkPicture::MakeFromData(picData, &procs);
+ auto picUnderTest = SkPicture::MakeFromData(picData, procs);
Timer drawTime;
- auto randomData = SkData::MakeUninitialized(1u);
for (int i = 0; i < 100; i++) {
if (gPurgeFontCaches) {
- ClientDiscardableManager::ScopedPurgeCache purge(discardableManager);
SkGraphics::PurgeFontCache();
- SkASSERT(SkGraphics::GetFontCacheUsed() == 0u);
}
-
drawTime.start();
if (client != nullptr) {
- // Kick the renderer to send us the fonts.
- write_SkData(writeFd, *randomData);
- auto fontData = read_SkData(readFd);
- if (fontData && !fontData->isEmpty()) {
- if (!client->readStrikeData(fontData->data(), fontData->size()))
- SK_ABORT("Bad serialization");
- }
+ SkStrikeCacheDifferenceSpec strikeDifference;
+ build_prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference);
+ client->primeStrikeCache(strikeDifference);
}
c->drawPicture(picUnderTest);
drawTime.stop();
@@ -202,16 +150,22 @@ static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient*
static void gpu(int readFd, int writeFd) {
if (gUseGpu) {
+ auto clientRPC = [readFd, writeFd](const SkData& inBuffer) {
+ write_SkData(writeFd, inBuffer);
+ return read_SkData(readFd);
+ };
+
auto picData = read_SkData(readFd);
if (picData == nullptr) {
return;
}
- sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
- SkStrikeClient strikeClient(discardableManager);
+ SkStrikeClient client{clientRPC};
- final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
- writeFd);
+ SkDeserialProcs procs;
+ client.prepareDeserializeProcs(&procs);
+
+ final_draw("test.png", &procs, picData.get(), &client);
}
::close(writeFd);
@@ -223,8 +177,7 @@ static void gpu(int readFd, int writeFd) {
static int renderer(
const std::string& skpName, int readFd, int writeFd)
{
- ServerDiscardableManager discardableManager;
- SkStrikeServer server(&discardableManager);
+ SkStrikeServer server{};
auto closeAll = [readFd, writeFd]() {
::close(writeFd);
::close(readFd);
@@ -233,16 +186,11 @@ static int renderer(
auto skpData = SkData::MakeFromFileName(skpName.c_str());
std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
+ SkSerialProcs procs;
sk_sp<SkData> stream;
if (gUseGpu) {
auto pic = SkPicture::MakeFromData(skpData.get());
- SkSerialProcs procs;
- auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
- return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
- };
- procs.fTypefaceProc = encode;
- procs.fTypefaceCtx = &server;
-
+ server.prepareSerializeProcs(&procs);
stream = pic->serialize(&procs);
if (!write_SkData(writeFd, *stream)) {
@@ -250,18 +198,22 @@ static int renderer(
return 1;
}
+ std::vector<uint8_t> tmpBuffer;
while (true) {
auto inBuffer = read_SkData(readFd);
if (inBuffer == nullptr) {
closeAll();
return 0;
}
- if (gPurgeFontCaches) discardableManager.purgeAll();
- push_font_data(*pic.get(), &server, writeFd);
+
+ tmpBuffer.clear();
+ server.serve(*inBuffer, &tmpBuffer);
+ auto outBuffer = SkData::MakeWithoutCopy(tmpBuffer.data(), tmpBuffer.size());
+ write_SkData(writeFd, *outBuffer);
}
} else {
stream = skpData;
- final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
+ final_draw("test-correct.png", nullptr, stream.get(), nullptr);
closeAll();
return 0;
}