/* * Copyright 2018 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkRemoteGlyphCache_DEFINED #define SkRemoteGlyphCache_DEFINED #include #include #include #include #include "SkData.h" #include "SkDescriptor.h" #include "SkDrawLooper.h" #include "SkGlyphCache.h" #include "SkMakeUnique.h" #include "SkNoDrawCanvas.h" #include "SkRefCnt.h" #include "SkSerialProcs.h" #include "SkTextBlobRunIterator.h" #include "SkTHash.h" #include "SkTypeface.h" #include "SkTypeface_remote.h" // The client uses a SkStrikeCacheClientRPC to send and receive data. using SkStrikeCacheClientRPC = std::function(const SkData&)>; class SkScalerContextRecDescriptor { public: SkScalerContextRecDescriptor() {} explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) { auto desc = reinterpret_cast(&fDescriptor); desc->init(); desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); desc->computeChecksum(); SkASSERT(sizeof(fDescriptor) == desc->getLength()); } explicit SkScalerContextRecDescriptor(const SkDescriptor& desc) : SkScalerContextRecDescriptor(ExtractRec(desc)) { } SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) { std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength()); return *this; } const SkDescriptor& desc() const { return *reinterpret_cast(&fDescriptor); } struct Hash { uint32_t operator()(SkScalerContextRecDescriptor const& s) const { return s.desc().getChecksum(); } }; friend bool operator==(const SkScalerContextRecDescriptor& lhs, const SkScalerContextRecDescriptor& rhs ) { return lhs.desc() == rhs.desc(); } private: static SkScalerContextRec ExtractRec(const SkDescriptor& desc) { uint32_t size; auto recPtr = desc.findEntry(kRec_SkDescriptorTag, &size); SkScalerContextRec result; std::memcpy(&result, recPtr, size); return result; } // The system only passes descriptors without effects. That is why it uses a fixed size // descriptor. storageFor is needed because some of the constructors below are private. template using storageFor = typename std::aligned_storage::type; struct { storageFor dummy1; storageFor dummy2; storageFor dummy3; } fDescriptor; }; class SkStrikeDifferences { public: SkStrikeDifferences(SkFontID typefaceID, std::unique_ptr desc); void add(uint16_t glyphID, SkIPoint pos); SkFontID fTypefaceID; std::unique_ptr fDesc; std::unique_ptr> fGlyphIDs = skstd::make_unique>(); }; class SkStrikeCacheDifferenceSpec { public: SkStrikeDifferences& findStrikeDifferences(const SkDescriptor& desc, SkFontID typefaceID); int strikeCount() const { return fDescriptorToDifferencesMap.size(); } size_t sizeBytes() const; template void iterateDifferences(PerStrike perStrike, PerGlyph perGlyph) const; private: struct DescHash { size_t operator()(const SkDescriptor* key) const { return key->getChecksum(); } }; struct DescEq { bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const { return lhs->getChecksum() == rhs->getChecksum(); } }; using DescMap = std::unordered_map; DescMap fDescriptorToDifferencesMap{16, DescHash(), DescEq()}; }; class SkTextBlobCacheDiffCanvas : public SkNoDrawCanvas { public: SkTextBlobCacheDiffCanvas(int width, int height, const SkMatrix& deviceMatrix, const SkSurfaceProps& props, SkScalerContextFlags flags, SkStrikeCacheDifferenceSpec* strikeDiffs); protected: SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) 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); const SkMatrix fDeviceMatrix; const SkSurfaceProps fSurfaceProps; const SkScalerContextFlags fScalerContextFlags; SkStrikeCacheDifferenceSpec* const fStrikeCacheDiff; }; class SkStrikeServer { public: SkStrikeServer(); ~SkStrikeServer(); // embedding clients call these methods void serve(const SkData&, std::vector*); void prepareSerializeProcs(SkSerialProcs* procs); // mostly called internally by Skia SkScalerContext* generateScalerContext( const SkScalerContextRecDescriptor& desc, SkFontID typefaceId); private: using DescriptorToContextMap = SkTHashMap, SkScalerContextRecDescriptor::Hash>; sk_sp encodeTypeface(SkTypeface* tf); int fOpCount = 0; SkTHashMap> fTypefaceMap; DescriptorToContextMap fScalerContextMap; }; class SkStrikeClient { public: SkStrikeClient(SkStrikeCacheClientRPC); // 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: sk_sp decodeTypeface(const void* buf, size_t len); // TODO: Figure out how to manage the entries for the following maps. SkTHashMap> fMapIdToTypeface; SkStrikeCacheClientRPC fClientRPC; std::vector fBuffer; }; #endif // SkRemoteGlyphCache_DEFINED