• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/core/SkRemoteGlyphCache.h"
9 
10 #include <iterator>
11 #include <memory>
12 #include <new>
13 #include <string>
14 #include <tuple>
15 
16 #include "src/core/SkDevice.h"
17 #include "src/core/SkDraw.h"
18 #include "src/core/SkGlyphRun.h"
19 #include "src/core/SkStrike.h"
20 #include "src/core/SkStrikeCache.h"
21 #include "src/core/SkTLazy.h"
22 #include "src/core/SkTraceEvent.h"
23 #include "src/core/SkTypeface_remote.h"
24 
25 #if SK_SUPPORT_GPU
26 #include "src/gpu/GrDrawOpAtlas.h"
27 #include "src/gpu/text/GrTextContext.h"
28 #endif
29 
auto_descriptor_from_desc(const SkDescriptor * source_desc,SkFontID font_id,SkAutoDescriptor * ad)30 static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc,
31                                                SkFontID font_id,
32                                                SkAutoDescriptor* ad) {
33     ad->reset(source_desc->getLength());
34     auto* desc = ad->getDesc();
35     desc->init();
36 
37     // Rec.
38     {
39         uint32_t size;
40         auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size);
41         SkScalerContextRec rec;
42         std::memcpy(&rec, ptr, size);
43         rec.fFontID = font_id;
44         desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
45     }
46 
47     // Effects.
48     {
49         uint32_t size;
50         auto ptr = source_desc->findEntry(kEffects_SkDescriptorTag, &size);
51         if (ptr) { desc->addEntry(kEffects_SkDescriptorTag, size, ptr); }
52     }
53 
54     desc->computeChecksum();
55     return desc;
56 }
57 
create_descriptor(const SkPaint & paint,const SkFont & font,const SkMatrix & m,const SkSurfaceProps & props,SkScalerContextFlags flags,SkAutoDescriptor * ad,SkScalerContextEffects * effects)58 static const SkDescriptor* create_descriptor(
59         const SkPaint& paint, const SkFont& font, const SkMatrix& m,
60         const SkSurfaceProps& props, SkScalerContextFlags flags,
61         SkAutoDescriptor* ad, SkScalerContextEffects* effects) {
62     SkScalerContextRec rec;
63     SkScalerContext::MakeRecAndEffects(font, paint, props, flags, m, &rec, effects);
64     return SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
65 }
66 
67 // -- Serializer -----------------------------------------------------------------------------------
pad(size_t size,size_t alignment)68 size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
69 
70 // Alignment between x86 and x64 differs for some types, in particular
71 // int64_t and doubles have 4 and 8-byte alignment, respectively.
72 // Be consistent even when writing and reading across different architectures.
73 template<typename T>
serialization_alignment()74 size_t serialization_alignment() {
75   return sizeof(T) == 8 ? 8 : alignof(T);
76 }
77 
78 class Serializer {
79 public:
Serializer(std::vector<uint8_t> * buffer)80     Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} { }
81 
82     template <typename T, typename... Args>
emplace(Args &&...args)83     T* emplace(Args&&... args) {
84         auto result = allocate(sizeof(T), serialization_alignment<T>());
85         return new (result) T{std::forward<Args>(args)...};
86     }
87 
88     template <typename T>
write(const T & data)89     void write(const T& data) {
90         T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
91         memcpy(result, &data, sizeof(T));
92     }
93 
94     template <typename T>
allocate()95     T* allocate() {
96         T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
97         return result;
98     }
99 
writeDescriptor(const SkDescriptor & desc)100     void writeDescriptor(const SkDescriptor& desc) {
101         write(desc.getLength());
102         auto result = allocate(desc.getLength(), alignof(SkDescriptor));
103         memcpy(result, &desc, desc.getLength());
104     }
105 
allocate(size_t size,size_t alignment)106     void* allocate(size_t size, size_t alignment) {
107         size_t aligned = pad(fBuffer->size(), alignment);
108         fBuffer->resize(aligned + size);
109         return &(*fBuffer)[aligned];
110     }
111 
112 private:
113     std::vector<uint8_t>* fBuffer;
114 };
115 
116 // -- Deserializer -------------------------------------------------------------------------------
117 // Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
118 class Deserializer {
119 public:
Deserializer(const volatile char * memory,size_t memorySize)120     Deserializer(const volatile char* memory, size_t memorySize)
121             : fMemory(memory), fMemorySize(memorySize) {}
122 
123     template <typename T>
read(T * val)124     bool read(T* val) {
125         auto* result = this->ensureAtLeast(sizeof(T), serialization_alignment<T>());
126         if (!result) return false;
127 
128         memcpy(val, const_cast<const char*>(result), sizeof(T));
129         return true;
130     }
131 
readDescriptor(SkAutoDescriptor * ad)132     bool readDescriptor(SkAutoDescriptor* ad) {
133         uint32_t descLength = 0u;
134         if (!read<uint32_t>(&descLength)) return false;
135         if (descLength < sizeof(SkDescriptor)) return false;
136         if (descLength != SkAlign4(descLength)) return false;
137 
138         auto* result = this->ensureAtLeast(descLength, alignof(SkDescriptor));
139         if (!result) return false;
140 
141         ad->reset(descLength);
142         memcpy(ad->getDesc(), const_cast<const char*>(result), descLength);
143 
144         if (ad->getDesc()->getLength() > descLength) return false;
145         return ad->getDesc()->isValid();
146     }
147 
read(size_t size,size_t alignment)148     const volatile void* read(size_t size, size_t alignment) {
149       return this->ensureAtLeast(size, alignment);
150     }
151 
bytesRead() const152     size_t bytesRead() const { return fBytesRead; }
153 
154 private:
ensureAtLeast(size_t size,size_t alignment)155     const volatile char* ensureAtLeast(size_t size, size_t alignment) {
156         size_t padded = pad(fBytesRead, alignment);
157 
158         // Not enough data.
159         if (padded > fMemorySize) return nullptr;
160         if (size > fMemorySize - padded) return nullptr;
161 
162         auto* result = fMemory + padded;
163         fBytesRead = padded + size;
164         return result;
165     }
166 
167     // Note that we read each piece of memory only once to guard against TOCTOU violations.
168     const volatile char* fMemory;
169     size_t fMemorySize;
170     size_t fBytesRead = 0u;
171 };
172 
173 // Paths use a SkWriter32 which requires 4 byte alignment.
174 static const size_t kPathAlignment  = 4u;
175 
operator ()(const SkDescriptor * key) const176 size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const {
177     return key->getChecksum();
178 }
179 
operator ()(const SkDescriptor * lhs,const SkDescriptor * rhs) const180 bool SkDescriptorMapOperators::operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
181     return *lhs == *rhs;
182 }
183 
184 // -- StrikeSpec -----------------------------------------------------------------------------------
185 struct StrikeSpec {
186     StrikeSpec() = default;
StrikeSpecStrikeSpec187     StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
188             : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
189     SkFontID typefaceID = 0u;
190     SkDiscardableHandleId discardableHandleId = 0u;
191     /* desc */
192     /* n X (glyphs ids) */
193 };
194 
195 // -- SkGlyphCacheState ----------------------------------------------------------------------------
196 class SkStrikeServer::SkGlyphCacheState : public SkStrikeInterface {
197 public:
198     // N.B. SkGlyphCacheState is not valid until ensureScalerContext is called.
199     SkGlyphCacheState(const SkDescriptor& descriptor,
200                       std::unique_ptr<SkScalerContext> context,
201                       SkDiscardableHandleId discardableHandleId);
202     ~SkGlyphCacheState() override;
203 
204     void addGlyph(SkPackedGlyphID, bool asPath);
205     void writePendingGlyphs(Serializer* serializer);
discardableHandleId() const206     SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
207 
isSubpixel() const208     bool isSubpixel() const { return fIsSubpixel; }
209 
getDescriptor() const210     const SkDescriptor& getDescriptor() const override {
211         return *fDescriptor.getDesc();
212     }
213 
214     void setTypefaceAndEffects(const SkTypeface* typeface, SkScalerContextEffects effects);
215 
216     SkVector rounding() const override;
217 
subpixelMask() const218     SkIPoint subpixelMask() const override {
219         return SkIPoint::Make((!fIsSubpixel || fAxisAlignment == kY_SkAxisAlignment) ? 0 : ~0u,
220                               (!fIsSubpixel || fAxisAlignment == kX_SkAxisAlignment) ? 0 : ~0u);
221     }
222 
223     SkSpan<const SkGlyphPos>
224     prepareForDrawingRemoveEmpty(
225             const SkPackedGlyphID packedGlyphIDs[],
226             const SkPoint positions[], size_t n,
227             int maxDimension, PreparationDetail detail,
228             SkGlyphPos results[]) override;
229 
onAboutToExitScope()230     void onAboutToExitScope() override {}
231 
232 private:
hasPendingGlyphs() const233     bool hasPendingGlyphs() const {
234         return !fPendingGlyphImages.empty() || !fPendingGlyphPaths.empty();
235     }
236     void writeGlyphPath(const SkPackedGlyphID& glyphID, Serializer* serializer) const;
237 
238     void ensureScalerContext();
239     void resetScalerContext();
240 
241     // The set of glyphs cached on the remote client.
242     SkTHashSet<SkPackedGlyphID> fCachedGlyphImages;
243     SkTHashSet<SkPackedGlyphID> fCachedGlyphPaths;
244 
245     // The set of glyphs which has not yet been serialized and sent to the
246     // remote client.
247     std::vector<SkPackedGlyphID> fPendingGlyphImages;
248     std::vector<SkPackedGlyphID> fPendingGlyphPaths;
249 
250     const SkAutoDescriptor fDescriptor;
251 
252     const SkDiscardableHandleId fDiscardableHandleId;
253 
254     // Values saved from the initial context.
255     const bool fIsSubpixel;
256     const SkAxisAlignment fAxisAlignment;
257 
258     // The context built using fDescriptor
259     std::unique_ptr<SkScalerContext> fContext;
260 
261     // These fields are set every time getOrCreateCache. This allows the code to maintain the
262     // fContext as lazy as possible.
263     const SkTypeface* fTypeface{nullptr};
264     SkScalerContextEffects fEffects;
265 
266     class GlyphMapHashTraits {
267     public:
GetKey(const SkGlyph * glyph)268         static SkPackedGlyphID GetKey(const SkGlyph* glyph) {
269             return glyph->getPackedID();
270         }
Hash(SkPackedGlyphID glyphId)271         static uint32_t Hash(SkPackedGlyphID glyphId) {
272             return glyphId.hash();
273         }
274     };
275 
276     // FallbackTextHelper cases require glyph metrics when analyzing a glyph run, in which case
277     // we cache them here.
278     SkTHashTable<SkGlyph*, SkPackedGlyphID, GlyphMapHashTraits> fGlyphMap;
279 
280     SkArenaAlloc fAlloc{256};
281 };
282 
SkGlyphCacheState(const SkDescriptor & descriptor,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)283 SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(
284         const SkDescriptor& descriptor,
285         std::unique_ptr<SkScalerContext> context,
286         uint32_t discardableHandleId)
287         : fDescriptor{descriptor}
288         , fDiscardableHandleId(discardableHandleId)
289         , fIsSubpixel{context->isSubpixel()}
290         , fAxisAlignment{context->computeAxisAlignmentForHText()}
291         // N.B. context must come last because it is used above.
292         , fContext{std::move(context)} {
293     SkASSERT(fDescriptor.getDesc() != nullptr);
294     SkASSERT(fContext != nullptr);
295 }
296 
297 SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default;
298 
addGlyph(SkPackedGlyphID glyph,bool asPath)299 void SkStrikeServer::SkGlyphCacheState::addGlyph(SkPackedGlyphID glyph, bool asPath) {
300     auto* cache = asPath ? &fCachedGlyphPaths : &fCachedGlyphImages;
301     auto* pending = asPath ? &fPendingGlyphPaths : &fPendingGlyphImages;
302 
303     // Already cached.
304     if (cache->contains(glyph)) {
305         return;
306     }
307 
308     // A glyph is going to be sent. Make sure we have a scaler context to send it.
309     this->ensureScalerContext();
310 
311     // Serialize and cache. Also create the scalar context to use when serializing
312     // this glyph.
313     cache->add(glyph);
314     pending->push_back(glyph);
315 }
316 
317 
318 // -- TrackLayerDevice -----------------------------------------------------------------------------
319 class SkTextBlobCacheDiffCanvas::TrackLayerDevice final : public SkNoPixelsDevice {
320 public:
TrackLayerDevice(const SkIRect & bounds,const SkSurfaceProps & props,SkStrikeServer * server,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)321     TrackLayerDevice(
322             const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
323             sk_sp<SkColorSpace> colorSpace, bool DFTSupport)
324             : SkNoPixelsDevice(bounds, props, std::move(colorSpace))
325             , fStrikeServer(server)
326             , fDFTSupport(DFTSupport)
327             , fPainter{props, kUnknown_SkColorType, imageInfo().colorSpace(), fStrikeServer} {
328         SkASSERT(fStrikeServer != nullptr);
329     }
330 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)331     SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override {
332         const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
333         return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps, fStrikeServer,
334                                     cinfo.fInfo.refColorSpace(), fDFTSupport);
335     }
336 
337 protected:
drawGlyphRunList(const SkGlyphRunList & glyphRunList)338     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override {
339 #if SK_SUPPORT_GPU
340         GrTextContext::Options options;
341         GrTextContext::SanitizeOptions(&options);
342 
343         fPainter.processGlyphRunList(glyphRunList,
344                                      this->ctm(),
345                                      this->surfaceProps(),
346                                      fDFTSupport,
347                                      options,
348                                      nullptr);
349 #endif  // SK_SUPPORT_GPU
350     }
351 
352 private:
353     SkStrikeServer* const fStrikeServer;
354     const bool fDFTSupport{false};
355     SkGlyphRunListPainter fPainter;
356 };
357 
358 // -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
359 // DEPRECATED
360 // TODO(herb): remove uses in Chrome
361 SkTextBlobCacheDiffCanvas::Settings::Settings() = default;
362 
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,bool DFTSupport)363 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
364                                                      const SkSurfaceProps& props,
365                                                      SkStrikeServer* strikeServer,
366                                                      bool DFTSupport)
367     : SkTextBlobCacheDiffCanvas{width, height, props, strikeServer, nullptr, DFTSupport} { }
368 
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,sk_sp<SkColorSpace> colorSpace,Settings settings)369 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
370                                                      const SkSurfaceProps& props,
371                                                      SkStrikeServer* strikeServer,
372                                                      sk_sp<SkColorSpace> colorSpace,
373                                                      Settings settings)
374     : SkTextBlobCacheDiffCanvas{width, height, props, strikeServer, std::move(colorSpace),
375                                 settings.fContextSupportsDistanceFieldText} { }
376 
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)377 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
378                                                      const SkSurfaceProps& props,
379                                                      SkStrikeServer* strikeServer,
380                                                      sk_sp<SkColorSpace> colorSpace,
381                                                      bool DFTSupport)
382      : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(SkIRect::MakeWH(width, height),
383                                                    props,
384                                                    strikeServer,
385                                                    std::move(colorSpace),
386                                                    DFTSupport)} { }
387 
388 SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() = default;
389 
getSaveLayerStrategy(const SaveLayerRec & rec)390 SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
391         const SaveLayerRec& rec) {
392     return kFullLayer_SaveLayerStrategy;
393 }
394 
onDoSaveBehind(const SkRect *)395 bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
396     return false;
397 }
398 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)399 void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
400                                                const SkPaint& paint) {
401     SkCanvas::onDrawTextBlob(blob, x, y, paint);
402 }
403 
404 // -- WireTypeface ---------------------------------------------------------------------------------
405 struct WireTypeface {
406     WireTypeface() = default;
WireTypefaceWireTypeface407     WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
408             : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {}
409 
410     SkFontID        typefaceID{0};
411     int             glyphCount{0};
412     SkFontStyle     style;
413     bool            isFixed{false};
414 };
415 
416 // SkStrikeServer ----------------------------------------------------------------------------------
SkStrikeServer(DiscardableHandleManager * discardableHandleManager)417 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
418         : fDiscardableHandleManager(discardableHandleManager) {
419     SkASSERT(fDiscardableHandleManager);
420 }
421 
422 SkStrikeServer::~SkStrikeServer() = default;
423 
serializeTypeface(SkTypeface * tf)424 sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
425     auto* data = fSerializedTypefaces.find(SkTypeface::UniqueID(tf));
426     if (data) {
427         return *data;
428     }
429 
430     WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
431                       tf->isFixedPitch());
432     data = fSerializedTypefaces.set(SkTypeface::UniqueID(tf),
433                                     SkData::MakeWithCopy(&wire, sizeof(wire)));
434     return *data;
435 }
436 
writeStrikeData(std::vector<uint8_t> * memory)437 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
438     if (fLockedDescs.empty() && fTypefacesToSend.empty()) {
439         return;
440     }
441 
442     Serializer serializer(memory);
443     serializer.emplace<uint64_t>(fTypefacesToSend.size());
444     for (const auto& tf : fTypefacesToSend) serializer.write<WireTypeface>(tf);
445     fTypefacesToSend.clear();
446 
447     serializer.emplace<uint64_t>(fLockedDescs.size());
448     for (const auto* desc : fLockedDescs) {
449         auto it = fRemoteGlyphStateMap.find(desc);
450         SkASSERT(it != fRemoteGlyphStateMap.end());
451         it->second->writePendingGlyphs(&serializer);
452     }
453     fLockedDescs.clear();
454 }
455 
getOrCreateCache(const SkPaint & paint,const SkFont & font,const SkSurfaceProps & props,const SkMatrix & matrix,SkScalerContextFlags flags,SkScalerContextEffects * effects)456 SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
457         const SkPaint& paint,
458         const SkFont& font,
459         const SkSurfaceProps& props,
460         const SkMatrix& matrix,
461         SkScalerContextFlags flags,
462         SkScalerContextEffects* effects) {
463     SkAutoDescriptor descStorage;
464     auto desc = create_descriptor(paint, font, matrix, props, flags, &descStorage, effects);
465 
466     return this->getOrCreateCache(*desc, *font.getTypefaceOrDefault(), *effects);
467 
468 }
469 
findOrCreateScopedStrike(const SkDescriptor & desc,const SkScalerContextEffects & effects,const SkTypeface & typeface)470 SkScopedStrike SkStrikeServer::findOrCreateScopedStrike(const SkDescriptor& desc,
471                                                         const SkScalerContextEffects& effects,
472                                                         const SkTypeface& typeface) {
473     return SkScopedStrike{this->getOrCreateCache(desc, typeface, effects)};
474 }
475 
AddGlyphForTesting(SkGlyphCacheState * cache,SkPackedGlyphID glyphID,bool asPath)476 void SkStrikeServer::AddGlyphForTesting(
477         SkGlyphCacheState* cache, SkPackedGlyphID glyphID, bool asPath) {
478     cache->addGlyph(glyphID, asPath);
479 }
480 
checkForDeletedEntries()481 void SkStrikeServer::checkForDeletedEntries() {
482     auto it = fRemoteGlyphStateMap.begin();
483     while (fRemoteGlyphStateMap.size() > fMaxEntriesInDescriptorMap &&
484            it != fRemoteGlyphStateMap.end()) {
485         if (fDiscardableHandleManager->isHandleDeleted(it->second->discardableHandleId())) {
486             it = fRemoteGlyphStateMap.erase(it);
487         } else {
488             ++it;
489         }
490     }
491 }
492 
getOrCreateCache(const SkDescriptor & desc,const SkTypeface & typeface,SkScalerContextEffects effects)493 SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
494         const SkDescriptor& desc, const SkTypeface& typeface, SkScalerContextEffects effects) {
495 
496     // In cases where tracing is turned off, make sure not to get an unused function warning.
497     // Lambdaize the function.
498     TRACE_EVENT1("skia", "RecForDesc", "rec",
499             TRACE_STR_COPY(
500                     [&desc](){
501                         auto ptr = desc.findEntry(kRec_SkDescriptorTag, nullptr);
502                         SkScalerContextRec rec;
503                         std::memcpy(&rec, ptr, sizeof(rec));
504                         return rec.dump();
505                     }().c_str()
506             )
507     );
508 
509     // Already locked.
510     if (fLockedDescs.find(&desc) != fLockedDescs.end()) {
511         auto it = fRemoteGlyphStateMap.find(&desc);
512         SkASSERT(it != fRemoteGlyphStateMap.end());
513         SkGlyphCacheState* cache = it->second.get();
514         cache->setTypefaceAndEffects(&typeface, effects);
515         return cache;
516     }
517 
518     // Try to lock.
519     auto it = fRemoteGlyphStateMap.find(&desc);
520     if (it != fRemoteGlyphStateMap.end()) {
521         SkGlyphCacheState* cache = it->second.get();
522         bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
523         if (locked) {
524             fLockedDescs.insert(it->first);
525             cache->setTypefaceAndEffects(&typeface, effects);
526             return cache;
527         }
528 
529         // If the lock failed, the entry was deleted on the client. Remove our
530         // tracking.
531         fRemoteGlyphStateMap.erase(it);
532     }
533 
534     const SkFontID typefaceId = typeface.uniqueID();
535     if (!fCachedTypefaces.contains(typefaceId)) {
536         fCachedTypefaces.add(typefaceId);
537         fTypefacesToSend.emplace_back(typefaceId, typeface.countGlyphs(),
538                                       typeface.fontStyle(),
539                                       typeface.isFixedPitch());
540     }
541 
542     auto context = typeface.createScalerContext(effects, &desc);
543 
544     // Create a new cache state and insert it into the map.
545     auto newHandle = fDiscardableHandleManager->createHandle();
546     auto cacheState = skstd::make_unique<SkGlyphCacheState>(desc, std::move(context), newHandle);
547 
548     auto* cacheStatePtr = cacheState.get();
549 
550     fLockedDescs.insert(&cacheStatePtr->getDescriptor());
551     fRemoteGlyphStateMap[&cacheStatePtr->getDescriptor()] = std::move(cacheState);
552 
553     checkForDeletedEntries();
554 
555     cacheStatePtr->setTypefaceAndEffects(&typeface, effects);
556     return cacheStatePtr;
557 }
558 
559 // No need to write fForceBW because it is a flag private to SkScalerContext_DW, which will never
560 // be called on the GPU side.
writeGlyph(SkGlyph * glyph,Serializer * serializer)561 static void writeGlyph(SkGlyph* glyph, Serializer* serializer) {
562     serializer->write<SkPackedGlyphID>(glyph->getPackedID());
563     serializer->write<float>(glyph->advanceX());
564     serializer->write<float>(glyph->advanceY());
565     serializer->write<uint16_t>(glyph->width());
566     serializer->write<uint16_t>(glyph->height());
567     serializer->write<int16_t>(glyph->top());
568     serializer->write<int16_t>(glyph->left());
569     serializer->write<uint8_t>(glyph->maskFormat());
570 }
571 
writePendingGlyphs(Serializer * serializer)572 void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serializer) {
573     // TODO(khushalsagar): Write a strike only if it has any pending glyphs.
574     serializer->emplace<bool>(this->hasPendingGlyphs());
575     if (!this->hasPendingGlyphs()) {
576         this->resetScalerContext();
577         return;
578     }
579 
580     // Write the desc.
581     serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
582     serializer->writeDescriptor(*fDescriptor.getDesc());
583 
584     // Write FontMetrics.
585     // TODO(khushalsagar): Do we need to re-send each time?
586     SkFontMetrics fontMetrics;
587     fContext->getFontMetrics(&fontMetrics);
588     serializer->write<SkFontMetrics>(fontMetrics);
589 
590     // Write glyphs images.
591     serializer->emplace<uint64_t>(fPendingGlyphImages.size());
592     for (const auto& glyphID : fPendingGlyphImages) {
593         SkGlyph glyph{glyphID};
594         fContext->getMetrics(&glyph);
595         SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
596 
597         writeGlyph(&glyph, serializer);
598         auto imageSize = glyph.imageSize();
599         if (imageSize == 0u) continue;
600 
601         glyph.fImage = serializer->allocate(imageSize, glyph.formatAlignment());
602         fContext->getImage(glyph);
603         // TODO: Generating the image can change the mask format, do we need to update it in the
604         // serialized glyph?
605     }
606     fPendingGlyphImages.clear();
607 
608     // Write glyphs paths.
609     serializer->emplace<uint64_t>(fPendingGlyphPaths.size());
610     for (const auto& glyphID : fPendingGlyphPaths) {
611         SkGlyph glyph{glyphID};
612         fContext->getMetrics(&glyph);
613         SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
614 
615         writeGlyph(&glyph, serializer);
616         writeGlyphPath(glyphID, serializer);
617     }
618     fPendingGlyphPaths.clear();
619     this->resetScalerContext();
620 }
621 
ensureScalerContext()622 void SkStrikeServer::SkGlyphCacheState::ensureScalerContext() {
623     if (fContext == nullptr) {
624         fContext = fTypeface->createScalerContext(fEffects, fDescriptor.getDesc());
625     }
626 }
627 
resetScalerContext()628 void SkStrikeServer::SkGlyphCacheState::resetScalerContext() {
629     fContext.reset();
630     fTypeface = nullptr;
631 }
632 
setTypefaceAndEffects(const SkTypeface * typeface,SkScalerContextEffects effects)633 void SkStrikeServer::SkGlyphCacheState::setTypefaceAndEffects(
634         const SkTypeface* typeface, SkScalerContextEffects effects) {
635     fTypeface = typeface;
636     fEffects = effects;
637 }
638 
rounding() const639 SkVector SkStrikeServer::SkGlyphCacheState::rounding() const {
640     return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignment);
641 }
642 
writeGlyphPath(const SkPackedGlyphID & glyphID,Serializer * serializer) const643 void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& glyphID,
644                                                        Serializer* serializer) const {
645     SkPath path;
646     if (!fContext->getPath(glyphID, &path)) {
647         serializer->write<uint64_t>(0u);
648         return;
649     }
650 
651     size_t pathSize = path.writeToMemory(nullptr);
652     serializer->write<uint64_t>(pathSize);
653     path.writeToMemory(serializer->allocate(pathSize, kPathAlignment));
654 }
655 
656 
657 // Be sure to read and understand the comment for prepareForDrawingRemoveEmpty in
658 // SkStrikeInterface.h before working on this code.
659 SkSpan<const SkGlyphPos>
prepareForDrawingRemoveEmpty(const SkPackedGlyphID packedGlyphIDs[],const SkPoint positions[],size_t n,int maxDimension,PreparationDetail detail,SkGlyphPos results[])660 SkStrikeServer::SkGlyphCacheState::prepareForDrawingRemoveEmpty(
661         const SkPackedGlyphID packedGlyphIDs[],
662         const SkPoint positions[], size_t n,
663         int maxDimension, PreparationDetail detail,
664         SkGlyphPos results[]) {
665     size_t drawableGlyphCount = 0;
666     for (size_t i = 0; i < n; i++) {
667         SkPoint glyphPos = positions[i];
668 
669         // Check the cache for the glyph.
670         SkGlyph* glyphPtr = fGlyphMap.findOrNull(packedGlyphIDs[i]);
671 
672         // Has this glyph ever been seen before?
673         if (glyphPtr == nullptr) {
674 
675             // Never seen before. Make a new glyph.
676             glyphPtr = fAlloc.make<SkGlyph>(packedGlyphIDs[i]);
677             fGlyphMap.set(glyphPtr);
678             this->ensureScalerContext();
679             fContext->getMetrics(glyphPtr);
680 
681             if (glyphPtr->maxDimension() <= maxDimension) {
682                 // do nothing
683             } else if (!glyphPtr->isColor()) {
684                 // The glyph is too big for the atlas, but it is not color, so it is handled
685                 // with a path.
686                 if (glyphPtr->setPath(&fAlloc, fContext.get())) {
687                     // Always send the path data, even if its not available, to make sure empty
688                     // paths are not incorrectly assumed to be cache misses.
689                     fCachedGlyphPaths.add(glyphPtr->getPackedID());
690                     fPendingGlyphPaths.push_back(glyphPtr->getPackedID());
691                 }
692             } else {
693                 // This will be handled by the fallback strike.
694                 SkASSERT(glyphPtr->maxDimension() > maxDimension && glyphPtr->isColor());
695             }
696 
697             // Make sure to send the glyph to the GPU because we always send the image for a glyph.
698             fCachedGlyphImages.add(packedGlyphIDs[i]);
699             fPendingGlyphImages.push_back(packedGlyphIDs[i]);
700         }
701 
702         // Each non-empty glyph needs to be added as per the contract for
703         // prepareForDrawingRemoveEmpty.
704         // TODO(herb): Change the code to only send the glyphs for fallback?
705         if (!glyphPtr->isEmpty()) {
706             results[drawableGlyphCount++] = {i, glyphPtr, glyphPos};
707         }
708     }
709     return SkMakeSpan(results, drawableGlyphCount);
710 }
711 
712 // SkStrikeClient ----------------------------------------------------------------------------------
713 class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
714 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<DiscardableHandleManager> manager)715     DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
716                             sk_sp<DiscardableHandleManager> manager)
717             : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
718 
719     ~DiscardableStrikePinner() override = default;
canDelete()720     bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
721 
722 private:
723     const SkDiscardableHandleId fDiscardableHandleId;
724     sk_sp<DiscardableHandleManager> fManager;
725 };
726 
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)727 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
728                                bool isLogging,
729                                SkStrikeCache* strikeCache)
730         : fDiscardableHandleManager(std::move(discardableManager))
731         , fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()}
732         , fIsLogging{isLogging} {}
733 
734 SkStrikeClient::~SkStrikeClient() = default;
735 
736 #define READ_FAILURE                                                     \
737     {                                                                    \
738         SkDebugf("Bad font data serialization line: %d", __LINE__);      \
739         DiscardableHandleManager::ReadFailureData data = {               \
740                 memorySize,  deserializer.bytesRead(), typefaceSize,     \
741                 strikeCount, glyphImagesCount,         glyphPathsCount}; \
742         fDiscardableHandleManager->notifyReadFailure(data);              \
743         return false;                                                    \
744     }
745 
746 // No need to read fForceBW because it is a flag private to SkScalerContext_DW, which will never
747 // be called on the GPU side.
ReadGlyph(SkTLazy<SkGlyph> & glyph,Deserializer * deserializer)748 bool SkStrikeClient::ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) {
749     SkPackedGlyphID glyphID;
750     if (!deserializer->read<SkPackedGlyphID>(&glyphID)) return false;
751     glyph.init(glyphID);
752     if (!deserializer->read<float>(&glyph->fAdvanceX)) return false;
753     if (!deserializer->read<float>(&glyph->fAdvanceY)) return false;
754     if (!deserializer->read<uint16_t>(&glyph->fWidth)) return false;
755     if (!deserializer->read<uint16_t>(&glyph->fHeight)) return false;
756     if (!deserializer->read<int16_t>(&glyph->fTop)) return false;
757     if (!deserializer->read<int16_t>(&glyph->fLeft)) return false;
758     if (!deserializer->read<uint8_t>(&glyph->fMaskFormat)) return false;
759     if (!SkMask::IsValidFormat(glyph->fMaskFormat)) return false;
760 
761     return true;
762 }
763 
readStrikeData(const volatile void * memory,size_t memorySize)764 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
765     SkASSERT(memorySize != 0u);
766     Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize);
767 
768     uint64_t typefaceSize = 0u;
769     uint64_t strikeCount = 0u;
770     uint64_t glyphImagesCount = 0u;
771     uint64_t glyphPathsCount = 0u;
772 
773     if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE
774 
775     for (size_t i = 0; i < typefaceSize; ++i) {
776         WireTypeface wire;
777         if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE
778 
779         // TODO(khushalsagar): The typeface no longer needs a reference to the
780         // SkStrikeClient, since all needed glyphs must have been pushed before
781         // raster.
782         addTypeface(wire);
783     }
784 
785     if (!deserializer.read<uint64_t>(&strikeCount)) READ_FAILURE
786 
787     for (size_t i = 0; i < strikeCount; ++i) {
788         bool has_glyphs = false;
789         if (!deserializer.read<bool>(&has_glyphs)) READ_FAILURE
790 
791         if (!has_glyphs) continue;
792 
793         StrikeSpec spec;
794         if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
795 
796         SkAutoDescriptor sourceAd;
797         if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE
798 
799         SkFontMetrics fontMetrics;
800         if (!deserializer.read<SkFontMetrics>(&fontMetrics)) READ_FAILURE
801 
802         // Get the local typeface from remote fontID.
803         auto* tfPtr = fRemoteFontIdToTypeface.find(spec.typefaceID);
804         // Received strikes for a typeface which doesn't exist.
805         if (!tfPtr) READ_FAILURE
806         auto* tf = tfPtr->get();
807 
808         // Replace the ContextRec in the desc from the server to create the client
809         // side descriptor.
810         // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy.
811         SkAutoDescriptor ad;
812         auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad);
813 
814         auto strike = fStrikeCache->findStrikeExclusive(*client_desc);
815         if (strike == nullptr) {
816             // Note that we don't need to deserialize the effects since we won't be generating any
817             // glyphs here anyway, and the desc is still correct since it includes the serialized
818             // effects.
819             SkScalerContextEffects effects;
820             auto scaler = SkStrikeCache::CreateScalerContext(*client_desc, effects, *tf);
821             strike = fStrikeCache->createStrikeExclusive(
822                     *client_desc, std::move(scaler), &fontMetrics,
823                     skstd::make_unique<DiscardableStrikePinner>(spec.discardableHandleId,
824                                                                 fDiscardableHandleManager));
825             auto proxyContext = static_cast<SkScalerContextProxy*>(strike->getScalerContext());
826             proxyContext->initCache(strike.get(), fStrikeCache);
827         }
828 
829         if (!deserializer.read<uint64_t>(&glyphImagesCount)) READ_FAILURE
830         for (size_t j = 0; j < glyphImagesCount; j++) {
831             SkTLazy<SkGlyph> glyph;
832             if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
833 
834             if (!glyph->isEmpty()) {
835                 const volatile void* image =
836                         deserializer.read(glyph->imageSize(), glyph->formatAlignment());
837                 if (!image) READ_FAILURE
838                 glyph->fImage = (void*)image;
839             }
840 
841             strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
842         }
843 
844         if (!deserializer.read<uint64_t>(&glyphPathsCount)) READ_FAILURE
845         for (size_t j = 0; j < glyphPathsCount; j++) {
846             SkTLazy<SkGlyph> glyph;
847             if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
848 
849             SkGlyph* allocatedGlyph = strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
850 
851             SkPath* pathPtr = nullptr;
852             SkPath path;
853             uint64_t pathSize = 0u;
854             if (!deserializer.read<uint64_t>(&pathSize)) READ_FAILURE
855 
856             if (pathSize > 0) {
857                 auto* pathData = deserializer.read(pathSize, kPathAlignment);
858                 if (!pathData) READ_FAILURE
859                 if (!path.readFromMemory(const_cast<const void*>(pathData), pathSize)) READ_FAILURE
860                 pathPtr = &path;
861             }
862 
863             strike->preparePath(allocatedGlyph, pathPtr);
864         }
865     }
866 
867     return true;
868 }
869 
deserializeTypeface(const void * buf,size_t len)870 sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) {
871     WireTypeface wire;
872     if (len != sizeof(wire)) return nullptr;
873     memcpy(&wire, buf, sizeof(wire));
874     return this->addTypeface(wire);
875 }
876 
addTypeface(const WireTypeface & wire)877 sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
878     auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
879     if (typeface) return *typeface;
880 
881     auto newTypeface = sk_make_sp<SkTypefaceProxy>(
882             wire.typefaceID, wire.glyphCount, wire.style, wire.isFixed,
883             fDiscardableHandleManager, fIsLogging);
884     fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface);
885     return newTypeface;
886 }
887