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 <bitset>
11 #include <iterator>
12 #include <memory>
13 #include <new>
14 #include <string>
15 #include <tuple>
16 
17 #include "include/private/SkChecksum.h"
18 #include "src/core/SkDevice.h"
19 #include "src/core/SkDraw.h"
20 #include "src/core/SkEnumerate.h"
21 #include "src/core/SkGlyphRun.h"
22 #include "src/core/SkScalerCache.h"
23 #include "src/core/SkSpan.h"
24 #include "src/core/SkStrikeCache.h"
25 #include "src/core/SkTLazy.h"
26 #include "src/core/SkTraceEvent.h"
27 #include "src/core/SkTypeface_remote.h"
28 #include "src/core/SkZip.h"
29 
30 #if SK_SUPPORT_GPU
31 #include "src/gpu/GrDrawOpAtlas.h"
32 #include "src/gpu/text/GrTextContext.h"
33 #endif
34 
auto_descriptor_from_desc(const SkDescriptor * source_desc,SkFontID font_id,SkAutoDescriptor * ad)35 static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc,
36                                                SkFontID font_id,
37                                                SkAutoDescriptor* ad) {
38     ad->reset(source_desc->getLength());
39     auto* desc = ad->getDesc();
40 
41     // Rec.
42     {
43         uint32_t size;
44         auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size);
45         SkScalerContextRec rec;
46         std::memcpy((void*)&rec, ptr, size);
47         rec.fFontID = font_id;
48         desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
49     }
50 
51     // Effects.
52     {
53         uint32_t size;
54         auto ptr = source_desc->findEntry(kEffects_SkDescriptorTag, &size);
55         if (ptr) { desc->addEntry(kEffects_SkDescriptorTag, size, ptr); }
56     }
57 
58     desc->computeChecksum();
59     return desc;
60 }
61 
create_descriptor(const SkPaint & paint,const SkFont & font,const SkMatrix & m,const SkSurfaceProps & props,SkScalerContextFlags flags,SkAutoDescriptor * ad,SkScalerContextEffects * effects)62 static const SkDescriptor* create_descriptor(
63         const SkPaint& paint, const SkFont& font, const SkMatrix& m,
64         const SkSurfaceProps& props, SkScalerContextFlags flags,
65         SkAutoDescriptor* ad, SkScalerContextEffects* effects) {
66     SkScalerContextRec rec;
67     SkScalerContext::MakeRecAndEffects(font, paint, props, flags, m, &rec, effects);
68     return SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
69 }
70 
71 // -- Serializer -----------------------------------------------------------------------------------
pad(size_t size,size_t alignment)72 size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
73 
74 // Alignment between x86 and x64 differs for some types, in particular
75 // int64_t and doubles have 4 and 8-byte alignment, respectively.
76 // Be consistent even when writing and reading across different architectures.
77 template<typename T>
serialization_alignment()78 size_t serialization_alignment() {
79   return sizeof(T) == 8 ? 8 : alignof(T);
80 }
81 
82 class Serializer {
83 public:
Serializer(std::vector<uint8_t> * buffer)84     explicit Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} {}
85 
86     template <typename T, typename... Args>
87     T* emplace(Args&&... args) {
88         auto result = allocate(sizeof(T), serialization_alignment<T>());
89         return new (result) T{std::forward<Args>(args)...};
90     }
91 
92     template <typename T>
write(const T & data)93     void write(const T& data) {
94         T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
95         memcpy(result, &data, sizeof(T));
96     }
97 
98     template <typename T>
allocate()99     T* allocate() {
100         T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
101         return result;
102     }
103 
writeDescriptor(const SkDescriptor & desc)104     void writeDescriptor(const SkDescriptor& desc) {
105         write(desc.getLength());
106         auto result = allocate(desc.getLength(), alignof(SkDescriptor));
107         memcpy(result, &desc, desc.getLength());
108     }
109 
allocate(size_t size,size_t alignment)110     void* allocate(size_t size, size_t alignment) {
111         size_t aligned = pad(fBuffer->size(), alignment);
112         fBuffer->resize(aligned + size);
113         return &(*fBuffer)[aligned];
114     }
115 
116 private:
117     std::vector<uint8_t>* fBuffer;
118 };
119 
120 // -- Deserializer -------------------------------------------------------------------------------
121 // Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
122 class Deserializer {
123 public:
Deserializer(const volatile char * memory,size_t memorySize)124     Deserializer(const volatile char* memory, size_t memorySize)
125             : fMemory(memory), fMemorySize(memorySize) {}
126 
127     template <typename T>
read(T * val)128     bool read(T* val) {
129         auto* result = this->ensureAtLeast(sizeof(T), serialization_alignment<T>());
130         if (!result) return false;
131 
132         memcpy(val, const_cast<const char*>(result), sizeof(T));
133         return true;
134     }
135 
readDescriptor(SkAutoDescriptor * ad)136     bool readDescriptor(SkAutoDescriptor* ad) {
137         uint32_t descLength = 0u;
138         if (!read<uint32_t>(&descLength)) return false;
139         if (descLength < sizeof(SkDescriptor)) return false;
140         if (descLength != SkAlign4(descLength)) return false;
141 
142         auto* result = this->ensureAtLeast(descLength, alignof(SkDescriptor));
143         if (!result) return false;
144 
145         ad->reset(descLength);
146         memcpy(ad->getDesc(), const_cast<const char*>(result), descLength);
147 
148         if (ad->getDesc()->getLength() > descLength) return false;
149         return ad->getDesc()->isValid();
150     }
151 
read(size_t size,size_t alignment)152     const volatile void* read(size_t size, size_t alignment) {
153       return this->ensureAtLeast(size, alignment);
154     }
155 
bytesRead() const156     size_t bytesRead() const { return fBytesRead; }
157 
158 private:
ensureAtLeast(size_t size,size_t alignment)159     const volatile char* ensureAtLeast(size_t size, size_t alignment) {
160         size_t padded = pad(fBytesRead, alignment);
161 
162         // Not enough data.
163         if (padded > fMemorySize) return nullptr;
164         if (size > fMemorySize - padded) return nullptr;
165 
166         auto* result = fMemory + padded;
167         fBytesRead = padded + size;
168         return result;
169     }
170 
171     // Note that we read each piece of memory only once to guard against TOCTOU violations.
172     const volatile char* fMemory;
173     size_t fMemorySize;
174     size_t fBytesRead = 0u;
175 };
176 
SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes,SkAutoDescriptor * ad)177 bool SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes, SkAutoDescriptor* ad) {
178     auto d = Deserializer(reinterpret_cast<const volatile char*>(bytes->data()), bytes->size());
179     return d.readDescriptor(ad);
180 }
181 
182 // Paths use a SkWriter32 which requires 4 byte alignment.
183 static const size_t kPathAlignment  = 4u;
184 
185 // -- StrikeSpec -----------------------------------------------------------------------------------
186 struct StrikeSpec {
187     StrikeSpec() = default;
StrikeSpecStrikeSpec188     StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
189             : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
190     SkFontID typefaceID = 0u;
191     SkDiscardableHandleId discardableHandleId = 0u;
192     /* desc */
193     /* n X (glyphs ids) */
194 };
195 
196 // Represent a set of x sub-pixel-position glyphs with a glyph id < kMaxGlyphID and
197 // y sub-pxiel-position must be 0. Most sub-pixel-positioned glyphs have been x-axis aligned
198 // forcing the y sub-pixel position to be zero. We can organize the SkPackedGlyphID to check that
199 // the glyph id and the y position == 0 with a single compare in the following way:
200 //    <y-sub-pixel-position>:2 | <glyphid:16> | <x-sub-pixel-position>:2
201 // This organization allows a single check of a packed-id to be:
202 //    packed-id < kMaxGlyphID * possible-x-sub-pixel-positions
203 // where possible-x-sub-pixel-positions == 4.
204 class LowerRangeBitVector {
205 public:
test(SkPackedGlyphID packedID) const206     bool test(SkPackedGlyphID packedID) const {
207         uint32_t bit = packedID.value();
208         return bit < kMaxIndex && fBits.test(bit);
209     }
setIfLower(SkPackedGlyphID packedID)210     void setIfLower(SkPackedGlyphID packedID) {
211         uint32_t bit = packedID.value();
212         if (bit < kMaxIndex) {
213             fBits.set(bit);
214         }
215     }
216 
217 private:
218     using GID = SkPackedGlyphID;
219     static_assert(GID::kSubPixelX < GID::kGlyphID && GID::kGlyphID < GID::kSubPixelY,
220             "SkPackedGlyphID must be organized: sub-y | glyph id | sub-x");
221     static constexpr int kMaxGlyphID = 128;
222     static constexpr int kMaxIndex = kMaxGlyphID * (1u << GID::kSubPixelPosLen);
223     std::bitset<kMaxIndex> fBits;
224 };
225 
226 // -- RemoteStrike ----------------------------------------------------------------------------
227 class SkStrikeServer::RemoteStrike final : public SkStrikeForGPU {
228 public:
229     // N.B. RemoteStrike is not valid until ensureScalerContext is called.
230     RemoteStrike(const SkDescriptor& descriptor,
231                  std::unique_ptr<SkScalerContext> context,
232                  SkDiscardableHandleId discardableHandleId);
233     ~RemoteStrike() override;
234 
235     void writePendingGlyphs(Serializer* serializer);
discardableHandleId() const236     SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
237 
getDescriptor() const238     const SkDescriptor& getDescriptor() const override {
239         return *fDescriptor.getDesc();
240     }
241 
242     void setTypefaceAndEffects(const SkTypeface* typeface, SkScalerContextEffects effects);
243 
roundingSpec() const244     const SkGlyphPositionRoundingSpec& roundingSpec() const override {
245         return fRoundingSpec;
246     }
247 
248     void prepareForMaskDrawing(
249             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
250 
251     void prepareForSDFTDrawing(
252             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
253 
254     void prepareForPathDrawing(
255             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
256 
onAboutToExitScope()257     void onAboutToExitScope() override {}
258 
hasPendingGlyphs() const259     bool hasPendingGlyphs() const {
260         return !fMasksToSend.empty() || !fPathsToSend.empty();
261     }
262 
263     void resetScalerContext();
264 
265 private:
266     template <typename Rejector>
267     void commonMaskLoop(
268             SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject);
269 
270     // Keep track of if the glyph draw has been totally satisfied. It could be that this
271     // strike can not draw the glyph, and it must be rejected to be handled by fallback.
272     // For example, if a glyph has canDrawAsMask sent, then that data is on the GPU, and this
273     // strike totally satisfies this result. If canDrawAsMask is false, then this glyph must be
274     // rejected, and handled by a later stage using a latter strike.
275     struct MaskSummary {
276         static_assert(SkPackedGlyphID::kMaskAll < (1u << 30), "SkPackedGlyphID is too big.");
277         uint32_t packedID:30;
278         uint32_t canDrawAsMask:1;
279         uint32_t canDrawAsSDFT:1;
280     };
281 
282     struct MaskSummaryTraits {
GetKeySkStrikeServer::RemoteStrike::MaskSummaryTraits283         static SkPackedGlyphID GetKey(MaskSummary summary) {
284             return SkPackedGlyphID{summary.packedID};
285         }
286 
HashSkStrikeServer::RemoteStrike::MaskSummaryTraits287         static uint32_t Hash(SkPackedGlyphID packedID) {
288             return packedID.hash();
289         }
290     };
291 
292     // Same thing as MaskSummary, but for paths.
293     struct PathSummary {
294         constexpr static uint16_t kIsPath = 0;
295         SkGlyphID glyphID;
296         // If drawing glyphID can be done with a path, this is 0, otherwise it is the max
297         // dimension of the glyph.
298         uint16_t maxDimensionOrPath;
299     };
300 
301     struct PathSummaryTraits {
GetKeySkStrikeServer::RemoteStrike::PathSummaryTraits302         static SkGlyphID GetKey(PathSummary summary) {
303             return summary.glyphID;
304         }
305 
HashSkStrikeServer::RemoteStrike::PathSummaryTraits306         static uint32_t Hash(SkGlyphID packedID) {
307             return SkChecksum::CheapMix(packedID);
308         }
309     };
310 
311     void writeGlyphPath(const SkGlyph& glyph, Serializer* serializer) const;
312     void ensureScalerContext();
313 
314     const int fNumberOfGlyphs;
315     const SkAutoDescriptor fDescriptor;
316     const SkDiscardableHandleId fDiscardableHandleId;
317 
318     const SkGlyphPositionRoundingSpec fRoundingSpec;
319 
320     // The context built using fDescriptor
321     std::unique_ptr<SkScalerContext> fContext;
322 
323     // These fields are set every time getOrCreateCache. This allows the code to maintain the
324     // fContext as lazy as possible.
325     const SkTypeface* fTypeface{nullptr};
326     SkScalerContextEffects fEffects;
327 
328     // Have the metrics been sent for this strike. Only send them once.
329     bool fHaveSentFontMetrics{false};
330 
331     LowerRangeBitVector fSentLowGlyphIDs;
332 
333     // The masks and paths that currently reside in the GPU process.
334     SkTHashTable<MaskSummary, SkPackedGlyphID, MaskSummaryTraits> fSentGlyphs;
335     SkTHashTable<PathSummary, SkGlyphID, PathSummaryTraits> fSentPaths;
336 
337     // The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
338     // TextBlobs. Cleared after diffs are serialized.
339     std::vector<SkGlyph> fMasksToSend;
340     std::vector<SkGlyph> fPathsToSend;
341 
342     // Alloc for storing bits and pieces of paths, Cleared after diffs are serialized.
343     SkArenaAlloc fPathAlloc{256};
344 };
345 
RemoteStrike(const SkDescriptor & descriptor,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)346 SkStrikeServer::RemoteStrike::RemoteStrike(
347         const SkDescriptor& descriptor,
348         std::unique_ptr<SkScalerContext> context,
349         uint32_t discardableHandleId)
350         : fNumberOfGlyphs(context->getGlyphCount())
351         , fDescriptor{descriptor}
352         , fDiscardableHandleId(discardableHandleId)
353         , fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()}
354         // N.B. context must come last because it is used above.
355         , fContext{std::move(context)}
356         , fSentLowGlyphIDs{} {
357     SkASSERT(fDescriptor.getDesc() != nullptr);
358     SkASSERT(fContext != nullptr);
359 }
360 
361 SkStrikeServer::RemoteStrike::~RemoteStrike() = default;
362 
operator ()(const SkDescriptor * key) const363 size_t SkStrikeServer::MapOps::operator()(const SkDescriptor* key) const {
364     return key->getChecksum();
365 }
366 
operator ()(const SkDescriptor * lhs,const SkDescriptor * rhs) const367 bool SkStrikeServer::MapOps::operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
368     return *lhs == *rhs;
369 }
370 
371 // -- TrackLayerDevice -----------------------------------------------------------------------------
372 class SkTextBlobCacheDiffCanvas::TrackLayerDevice final : public SkNoPixelsDevice {
373 public:
TrackLayerDevice(const SkIRect & bounds,const SkSurfaceProps & props,SkStrikeServer * server,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)374     TrackLayerDevice(
375             const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
376             sk_sp<SkColorSpace> colorSpace, bool DFTSupport)
377             : SkNoPixelsDevice(bounds, props, std::move(colorSpace))
378             , fStrikeServer(server)
379             , fDFTSupport(DFTSupport)
380             , fPainter{props, kUnknown_SkColorType, imageInfo().colorSpace(), fStrikeServer} {
381         SkASSERT(fStrikeServer != nullptr);
382     }
383 
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)384     SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override {
385         const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
386         return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps, fStrikeServer,
387                                     cinfo.fInfo.refColorSpace(), fDFTSupport);
388     }
389 
strikeServer()390     SkStrikeServer* strikeServer() { return fStrikeServer; }
391 
392 protected:
drawGlyphRunList(const SkGlyphRunList & glyphRunList)393     void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override {
394         #if SK_SUPPORT_GPU
395         GrTextContext::Options options;
396         GrTextContext::SanitizeOptions(&options);
397 
398     #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
399         if (SkTextBlobTrace::Capture* capture = fStrikeServer->fCapture.get()) {
400             capture->capture(glyphRunList);
401         }
402     #endif  // SK_CAPTURE_DRAW_TEXT_BLOB
403 
404         fPainter.processGlyphRunList(glyphRunList,
405                                      this->localToDevice(),
406                                      this->surfaceProps(),
407                                      fDFTSupport,
408                                      options,
409                                      nullptr);
410         #endif  // SK_SUPPORT_GPU
411     }
412 
413 private:
414     SkStrikeServer* const fStrikeServer;
415     const bool fDFTSupport{false};
416     SkGlyphRunListPainter fPainter;
417 };
418 
419 // -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,bool DFTSupport)420 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
421                                                      const SkSurfaceProps& props,
422                                                      SkStrikeServer* strikeServer,
423                                                      bool DFTSupport)
424     : SkTextBlobCacheDiffCanvas{width, height, props, strikeServer, nullptr, DFTSupport} { }
425 
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,sk_sp<SkColorSpace> colorSpace,bool DFTSupport)426 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
427                                                      const SkSurfaceProps& props,
428                                                      SkStrikeServer* strikeServer,
429                                                      sk_sp<SkColorSpace> colorSpace,
430                                                      bool DFTSupport)
431     : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(SkIRect::MakeWH(width, height),
432                                                   props,
433                                                   strikeServer,
434                                                   std::move(colorSpace),
435                                                   DFTSupport)} {
436     #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
437         if (!strikeServer->fCapture) {
438             strikeServer->fCapture.reset(new SkTextBlobTrace::Capture);
439         }
440     #endif  // SK_CAPTURE_DRAW_TEXT_BLOB
441     }
442 
~SkTextBlobCacheDiffCanvas()443 SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() {
444 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
445     SkTextBlobTrace::Capture* capture =
446         ((TrackLayerDevice*)this->getTopDevice())->strikeServer()->fCapture.get();
447     if (capture) {
448         capture->dump();
449     }
450 #endif  // SK_CAPTURE_DRAW_TEXT_BLOB
451 }
452 
getSaveLayerStrategy(const SaveLayerRec & rec)453 SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
454         const SaveLayerRec& rec) {
455     return kFullLayer_SaveLayerStrategy;
456 }
457 
onDoSaveBehind(const SkRect *)458 bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
459     return false;
460 }
461 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)462 void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
463                                                const SkPaint& paint) {
464     SkCanvas::onDrawTextBlob(blob, x, y, paint);
465 }
466 
467 // -- WireTypeface ---------------------------------------------------------------------------------
468 struct WireTypeface {
469     WireTypeface() = default;
WireTypefaceWireTypeface470     WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
471             : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {}
472 
473     SkFontID        typefaceID{0};
474     int             glyphCount{0};
475     SkFontStyle     style;
476     bool            isFixed{false};
477 };
478 
479 // SkStrikeServer ----------------------------------------------------------------------------------
SkStrikeServer(DiscardableHandleManager * discardableHandleManager)480 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
481         : fDiscardableHandleManager(discardableHandleManager) {
482     SkASSERT(fDiscardableHandleManager);
483 }
484 
~SkStrikeServer()485 SkStrikeServer::~SkStrikeServer() {
486 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
487     if (fCapture) {
488         fCapture->dump();
489     }
490 #endif  // SK_CAPTURE_DRAW_TEXT_BLOB
491 }
492 
serializeTypeface(SkTypeface * tf)493 sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
494     auto* data = fSerializedTypefaces.find(SkTypeface::UniqueID(tf));
495     if (data) {
496         return *data;
497     }
498 
499     WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
500                       tf->isFixedPitch());
501     data = fSerializedTypefaces.set(SkTypeface::UniqueID(tf),
502                                     SkData::MakeWithCopy(&wire, sizeof(wire)));
503     return *data;
504 }
505 
writeStrikeData(std::vector<uint8_t> * memory)506 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
507     size_t strikesToSend = 0;
508     fRemoteStrikesToSend.foreach ([&](RemoteStrike* strike) {
509         if (strike->hasPendingGlyphs()) {
510             strikesToSend++;
511         } else {
512             strike->resetScalerContext();
513         }
514     });
515 
516     if (strikesToSend == 0 && fTypefacesToSend.empty()) {
517         fRemoteStrikesToSend.reset();
518         return;
519     }
520 
521     Serializer serializer(memory);
522     serializer.emplace<uint64_t>(fTypefacesToSend.size());
523     for (const auto& tf : fTypefacesToSend) {
524         serializer.write<WireTypeface>(tf);
525     }
526     fTypefacesToSend.clear();
527 
528     serializer.emplace<uint64_t>(SkTo<uint64_t>(strikesToSend));
529     fRemoteStrikesToSend.foreach (
530 #ifdef SK_DEBUG
531             [&](RemoteStrike* strike) {
532                 if (strike->hasPendingGlyphs()) {
533                     strike->writePendingGlyphs(&serializer);
534                     strike->resetScalerContext();
535                 }
536                 auto it = fDescToRemoteStrike.find(&strike->getDescriptor());
537                 SkASSERT(it != fDescToRemoteStrike.end());
538                 SkASSERT(it->second.get() == strike);
539             }
540 
541 #else
542             [&serializer](RemoteStrike* strike) {
543                 if (strike->hasPendingGlyphs()) {
544                     strike->writePendingGlyphs(&serializer);
545                     strike->resetScalerContext();
546                 }
547             }
548 #endif
549     );
550     fRemoteStrikesToSend.reset();
551 }
552 
getOrCreateCache(const SkPaint & paint,const SkFont & font,const SkSurfaceProps & props,const SkMatrix & matrix,SkScalerContextFlags flags,SkScalerContextEffects * effects)553 SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
554         const SkPaint& paint,
555         const SkFont& font,
556         const SkSurfaceProps& props,
557         const SkMatrix& matrix,
558         SkScalerContextFlags flags,
559         SkScalerContextEffects* effects) {
560     SkAutoDescriptor descStorage;
561     auto desc = create_descriptor(paint, font, matrix, props, flags, &descStorage, effects);
562 
563     return this->getOrCreateCache(*desc, *font.getTypefaceOrDefault(), *effects);
564 }
565 
findOrCreateScopedStrike(const SkDescriptor & desc,const SkScalerContextEffects & effects,const SkTypeface & typeface)566 SkScopedStrikeForGPU SkStrikeServer::findOrCreateScopedStrike(const SkDescriptor& desc,
567                                                               const SkScalerContextEffects& effects,
568                                                               const SkTypeface& typeface) {
569     return SkScopedStrikeForGPU{this->getOrCreateCache(desc, typeface, effects)};
570 }
571 
AddGlyphForTesting(RemoteStrike * strike,SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)572 void SkStrikeServer::AddGlyphForTesting(
573         RemoteStrike* strike, SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
574     strike->prepareForMaskDrawing(drawables, rejects);
575     rejects->flipRejectsToSource();
576     SkASSERT(rejects->source().empty());
577 }
578 
checkForDeletedEntries()579 void SkStrikeServer::checkForDeletedEntries() {
580     auto it = fDescToRemoteStrike.begin();
581     while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
582            it != fDescToRemoteStrike.end()) {
583         RemoteStrike* strike = it->second.get();
584         if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) {
585             // If we are removing the strike, we better not be trying to send it at the same time.
586             SkASSERT(!fRemoteStrikesToSend.contains(strike));
587             it = fDescToRemoteStrike.erase(it);
588         } else {
589             ++it;
590         }
591     }
592 }
593 
getOrCreateCache(const SkDescriptor & desc,const SkTypeface & typeface,SkScalerContextEffects effects)594 SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
595         const SkDescriptor& desc, const SkTypeface& typeface, SkScalerContextEffects effects) {
596 
597     // In cases where tracing is turned off, make sure not to get an unused function warning.
598     // Lambdaize the function.
599     TRACE_EVENT1("skia", "RecForDesc", "rec",
600             TRACE_STR_COPY(
601                     [&desc](){
602                         auto ptr = desc.findEntry(kRec_SkDescriptorTag, nullptr);
603                         SkScalerContextRec rec;
604                         std::memcpy((void*)&rec, ptr, sizeof(rec));
605                         return rec.dump();
606                     }().c_str()
607             )
608     );
609 
610     auto it = fDescToRemoteStrike.find(&desc);
611     if (it != fDescToRemoteStrike.end()) {
612         // We have processed the RemoteStrike before. Reuse it.
613         RemoteStrike* strike = it->second.get();
614         strike->setTypefaceAndEffects(&typeface, effects);
615         if (fRemoteStrikesToSend.contains(strike)) {
616             // Already tracking
617             return strike;
618         }
619 
620         // Strike is in unknown state on GPU. Start tracking strike on GPU by locking it.
621         bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
622         if (locked) {
623             fRemoteStrikesToSend.add(strike);
624             return strike;
625         }
626 
627         fDescToRemoteStrike.erase(it);
628     }
629 
630     // Create a new RemoteStrike. Start by processing the typeface.
631     const SkFontID typefaceId = typeface.uniqueID();
632     if (!fCachedTypefaces.contains(typefaceId)) {
633         fCachedTypefaces.add(typefaceId);
634         fTypefacesToSend.emplace_back(typefaceId, typeface.countGlyphs(),
635                                       typeface.fontStyle(),
636                                       typeface.isFixedPitch());
637     }
638 
639     auto context = typeface.createScalerContext(effects, &desc);
640     auto newHandle = fDiscardableHandleManager->createHandle();  // Locked on creation
641     auto remoteStrike = std::make_unique<RemoteStrike>(desc, std::move(context), newHandle);
642     remoteStrike->setTypefaceAndEffects(&typeface, effects);
643     auto remoteStrikePtr = remoteStrike.get();
644     fRemoteStrikesToSend.add(remoteStrikePtr);
645     auto d = &remoteStrike->getDescriptor();
646     fDescToRemoteStrike[d] = std::move(remoteStrike);
647 
648     checkForDeletedEntries();
649 
650     // Be sure we can build glyphs with this RemoteStrike.
651     remoteStrikePtr->setTypefaceAndEffects(&typeface, effects);
652     return remoteStrikePtr;
653 }
654 
655 // No need to write fForceBW because it is a flag private to SkScalerContext_DW, which will never
656 // be called on the GPU side.
writeGlyph(const SkGlyph & glyph,Serializer * serializer)657 static void writeGlyph(const SkGlyph& glyph, Serializer* serializer) {
658     serializer->write<SkPackedGlyphID>(glyph.getPackedID());
659     serializer->write<float>(glyph.advanceX());
660     serializer->write<float>(glyph.advanceY());
661     serializer->write<uint16_t>(glyph.width());
662     serializer->write<uint16_t>(glyph.height());
663     serializer->write<int16_t>(glyph.top());
664     serializer->write<int16_t>(glyph.left());
665     serializer->write<uint8_t>(glyph.maskFormat());
666 }
667 
writePendingGlyphs(Serializer * serializer)668 void SkStrikeServer::RemoteStrike::writePendingGlyphs(Serializer* serializer) {
669     SkASSERT(this->hasPendingGlyphs());
670 
671     // Write the desc.
672     serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
673     serializer->writeDescriptor(*fDescriptor.getDesc());
674 
675     serializer->emplace<bool>(fHaveSentFontMetrics);
676     if (!fHaveSentFontMetrics) {
677         // Write FontMetrics if not sent before.
678         SkFontMetrics fontMetrics;
679         fContext->getFontMetrics(&fontMetrics);
680         serializer->write<SkFontMetrics>(fontMetrics);
681         fHaveSentFontMetrics = true;
682     }
683 
684     // Write mask glyphs
685     serializer->emplace<uint64_t>(fMasksToSend.size());
686     for (SkGlyph& glyph : fMasksToSend) {
687         SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
688 
689         writeGlyph(glyph, serializer);
690         auto imageSize = glyph.imageSize();
691         if (imageSize > 0 && FitsInAtlas(glyph)) {
692             glyph.fImage = serializer->allocate(imageSize, glyph.formatAlignment());
693             fContext->getImage(glyph);
694         }
695     }
696     fMasksToSend.clear();
697 
698     // Write glyphs paths.
699     serializer->emplace<uint64_t>(fPathsToSend.size());
700     for (SkGlyph& glyph : fPathsToSend) {
701         SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
702 
703         writeGlyph(glyph, serializer);
704         writeGlyphPath(glyph, serializer);
705     }
706     fPathsToSend.clear();
707     fPathAlloc.reset();
708 }
709 
ensureScalerContext()710 void SkStrikeServer::RemoteStrike::ensureScalerContext() {
711     if (fContext == nullptr) {
712         fContext = fTypeface->createScalerContext(fEffects, fDescriptor.getDesc());
713     }
714 }
715 
resetScalerContext()716 void SkStrikeServer::RemoteStrike::resetScalerContext() {
717     fContext.reset();
718     fTypeface = nullptr;
719 }
720 
setTypefaceAndEffects(const SkTypeface * typeface,SkScalerContextEffects effects)721 void SkStrikeServer::RemoteStrike::setTypefaceAndEffects(
722         const SkTypeface* typeface, SkScalerContextEffects effects) {
723     fTypeface = typeface;
724     fEffects = effects;
725 }
726 
writeGlyphPath(const SkGlyph & glyph,Serializer * serializer) const727 void SkStrikeServer::RemoteStrike::writeGlyphPath(
728         const SkGlyph& glyph, Serializer* serializer) const {
729     if (glyph.isColor() || glyph.isEmpty()) {
730         serializer->write<uint64_t>(0u);
731         return;
732     }
733 
734     const SkPath* path = glyph.path();
735 
736     if (path == nullptr) {
737         serializer->write<uint64_t>(0u);
738         return;
739     }
740 
741     size_t pathSize = path->writeToMemory(nullptr);
742     serializer->write<uint64_t>(pathSize);
743     path->writeToMemory(serializer->allocate(pathSize, kPathAlignment));
744 }
745 
746 template <typename Rejector>
commonMaskLoop(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects,Rejector && reject)747 void SkStrikeServer::RemoteStrike::commonMaskLoop(
748         SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject) {
749     drawables->forEachGlyphID(
750             [&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
751                 MaskSummary* summary = fSentGlyphs.find(packedID);
752                 if (summary == nullptr) {
753                     // Put the new SkGlyph in the glyphs to send.
754                     fMasksToSend.emplace_back(packedID);
755                     SkGlyph* glyph = &fMasksToSend.back();
756 
757                     // Build the glyph
758                     this->ensureScalerContext();
759                     fContext->getMetrics(glyph);
760                     MaskSummary newSummary =
761                             {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
762                     summary = fSentGlyphs.set(newSummary);
763                 }
764 
765                 // Reject things that are too big.
766                 if (reject(*summary)) {
767                     rejects->reject(i);
768                 }
769             });
770 }
771 
prepareForMaskDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)772 void SkStrikeServer::RemoteStrike::prepareForMaskDrawing(
773         SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
774     for (auto t : SkMakeEnumerate(drawables->input())) {
775         size_t i; SkPackedGlyphID packedID;
776         std::forward_as_tuple(i, std::tie(packedID, std::ignore)) = t;
777 
778         if (fSentLowGlyphIDs.test(packedID)) {
779             #ifdef SK_DEBUG
780                 MaskSummary* summary = fSentGlyphs.find(packedID);
781                 SkASSERT(summary != nullptr);
782                 SkASSERT(summary->canDrawAsMask && summary->canDrawAsSDFT);
783             #endif
784             continue;
785         }
786 
787         MaskSummary* summary = fSentGlyphs.find(packedID);
788         if (summary == nullptr) {
789             // Put the new SkGlyph in the glyphs to send.
790             fMasksToSend.emplace_back(packedID);
791             SkGlyph* glyph = &fMasksToSend.back();
792 
793             // Build the glyph
794             this->ensureScalerContext();
795             fContext->getMetrics(glyph);
796 
797             MaskSummary newSummary =
798                     {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
799 
800             summary = fSentGlyphs.set(newSummary);
801 
802             if (summary->canDrawAsMask && summary->canDrawAsSDFT) {
803                 fSentLowGlyphIDs.setIfLower(packedID);
804             }
805         }
806 
807         // Reject things that are too big.
808         if (!summary->canDrawAsMask) {
809             rejects->reject(i);
810         }
811     }
812 }
813 
prepareForSDFTDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)814 void SkStrikeServer::RemoteStrike::prepareForSDFTDrawing(
815         SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
816     this->commonMaskLoop(drawables, rejects,
817                          [](MaskSummary summary){return !summary.canDrawAsSDFT;});
818 }
819 
prepareForPathDrawing(SkDrawableGlyphBuffer * drawables,SkSourceGlyphBuffer * rejects)820 void SkStrikeServer::RemoteStrike::prepareForPathDrawing(
821         SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
822     drawables->forEachGlyphID(
823         [&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
824             SkGlyphID glyphID = packedID.glyphID();
825             PathSummary* summary = fSentPaths.find(glyphID);
826             if (summary == nullptr) {
827                 // Put the new SkGlyph in the glyphs to send.
828                 fPathsToSend.emplace_back(SkPackedGlyphID{glyphID});
829                 SkGlyph* glyph = &fPathsToSend.back();
830 
831                 // Build the glyph
832                 this->ensureScalerContext();
833                 fContext->getMetrics(glyph);
834 
835                 uint16_t maxDimensionOrPath = glyph->maxDimension();
836                 // Only try to get the path if the glyphs is not color.
837                 if (!glyph->isColor() && !glyph->isEmpty()) {
838                     glyph->setPath(&fPathAlloc, fContext.get());
839                     if (glyph->path() != nullptr) {
840                         maxDimensionOrPath = PathSummary::kIsPath;
841                     }
842                 }
843 
844                 PathSummary newSummary = {glyph->getGlyphID(), maxDimensionOrPath};
845                 summary = fSentPaths.set(newSummary);
846             }
847 
848             if (summary->maxDimensionOrPath != PathSummary::kIsPath) {
849                 rejects->reject(i, (int)summary->maxDimensionOrPath);
850             }
851         });
852 }
853 
854 // SkStrikeClient ----------------------------------------------------------------------------------
855 class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
856 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<DiscardableHandleManager> manager)857     DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
858                             sk_sp<DiscardableHandleManager> manager)
859             : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
860 
861     ~DiscardableStrikePinner() override = default;
canDelete()862     bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
863 
864 private:
865     const SkDiscardableHandleId fDiscardableHandleId;
866     sk_sp<DiscardableHandleManager> fManager;
867 };
868 
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)869 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
870                                bool isLogging,
871                                SkStrikeCache* strikeCache)
872         : fDiscardableHandleManager(std::move(discardableManager))
873         , fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()}
874         , fIsLogging{isLogging} {}
875 
876 SkStrikeClient::~SkStrikeClient() = default;
877 
878 #define READ_FAILURE                                                     \
879     {                                                                    \
880         SkDebugf("Bad font data serialization line: %d", __LINE__);      \
881         DiscardableHandleManager::ReadFailureData data = {               \
882                 memorySize,  deserializer.bytesRead(), typefaceSize,     \
883                 strikeCount, glyphImagesCount,         glyphPathsCount}; \
884         fDiscardableHandleManager->notifyReadFailure(data);              \
885         return false;                                                    \
886     }
887 
888 // No need to read fForceBW because it is a flag private to SkScalerContext_DW, which will never
889 // be called on the GPU side.
ReadGlyph(SkTLazy<SkGlyph> & glyph,Deserializer * deserializer)890 bool SkStrikeClient::ReadGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) {
891     SkPackedGlyphID glyphID;
892     if (!deserializer->read<SkPackedGlyphID>(&glyphID)) return false;
893     glyph.init(glyphID);
894     if (!deserializer->read<float>(&glyph->fAdvanceX)) return false;
895     if (!deserializer->read<float>(&glyph->fAdvanceY)) return false;
896     if (!deserializer->read<uint16_t>(&glyph->fWidth)) return false;
897     if (!deserializer->read<uint16_t>(&glyph->fHeight)) return false;
898     if (!deserializer->read<int16_t>(&glyph->fTop)) return false;
899     if (!deserializer->read<int16_t>(&glyph->fLeft)) return false;
900     if (!deserializer->read<uint8_t>(&glyph->fMaskFormat)) return false;
901     if (!SkMask::IsValidFormat(glyph->fMaskFormat)) return false;
902 
903     return true;
904 }
905 
readStrikeData(const volatile void * memory,size_t memorySize)906 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
907     SkASSERT(memorySize != 0u);
908     Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize);
909 
910     uint64_t typefaceSize = 0;
911     uint64_t strikeCount = 0;
912     uint64_t glyphImagesCount = 0;
913     uint64_t glyphPathsCount = 0;
914 
915     if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE
916     for (size_t i = 0; i < typefaceSize; ++i) {
917         WireTypeface wire;
918         if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE
919 
920         // TODO(khushalsagar): The typeface no longer needs a reference to the
921         // SkStrikeClient, since all needed glyphs must have been pushed before
922         // raster.
923         addTypeface(wire);
924     }
925 
926     if (!deserializer.read<uint64_t>(&strikeCount)) READ_FAILURE
927 
928     for (size_t i = 0; i < strikeCount; ++i) {
929         StrikeSpec spec;
930         if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
931 
932         SkAutoDescriptor sourceAd;
933         if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE
934 
935         bool fontMetricsInitialized;
936         if (!deserializer.read(&fontMetricsInitialized)) READ_FAILURE
937 
938         SkFontMetrics fontMetrics{};
939         if (!fontMetricsInitialized) {
940             if (!deserializer.read<SkFontMetrics>(&fontMetrics)) READ_FAILURE
941         }
942 
943         // Get the local typeface from remote fontID.
944         auto* tfPtr = fRemoteFontIdToTypeface.find(spec.typefaceID);
945         // Received strikes for a typeface which doesn't exist.
946         if (!tfPtr) READ_FAILURE
947         auto* tf = tfPtr->get();
948 
949         // Replace the ContextRec in the desc from the server to create the client
950         // side descriptor.
951         // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy.
952         SkAutoDescriptor ad;
953         auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad);
954 
955         auto strike = fStrikeCache->findStrike(*client_desc);
956         // Metrics are only sent the first time. If the metrics are not initialized, there must
957         // be an existing strike.
958         if (fontMetricsInitialized && strike == nullptr) READ_FAILURE
959         if (strike == nullptr) {
960             // Note that we don't need to deserialize the effects since we won't be generating any
961             // glyphs here anyway, and the desc is still correct since it includes the serialized
962             // effects.
963             SkScalerContextEffects effects;
964             auto scaler = tf->createScalerContext(effects, client_desc);
965             strike = fStrikeCache->createStrike(
966                     *client_desc, std::move(scaler), &fontMetrics,
967                     std::make_unique<DiscardableStrikePinner>(
968                             spec.discardableHandleId, fDiscardableHandleManager));
969         }
970 
971         if (!deserializer.read<uint64_t>(&glyphImagesCount)) READ_FAILURE
972         for (size_t j = 0; j < glyphImagesCount; j++) {
973             SkTLazy<SkGlyph> glyph;
974             if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
975 
976             if (!glyph->isEmpty() && SkStrikeForGPU::FitsInAtlas(*glyph)) {
977                 const volatile void* image =
978                         deserializer.read(glyph->imageSize(), glyph->formatAlignment());
979                 if (!image) READ_FAILURE
980                 glyph->fImage = (void*)image;
981             }
982 
983             strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
984         }
985 
986         if (!deserializer.read<uint64_t>(&glyphPathsCount)) READ_FAILURE
987         for (size_t j = 0; j < glyphPathsCount; j++) {
988             SkTLazy<SkGlyph> glyph;
989             if (!ReadGlyph(glyph, &deserializer)) READ_FAILURE
990 
991             SkGlyph* allocatedGlyph = strike->mergeGlyphAndImage(glyph->getPackedID(), *glyph);
992 
993             SkPath* pathPtr = nullptr;
994             SkPath path;
995             uint64_t pathSize = 0u;
996             if (!deserializer.read<uint64_t>(&pathSize)) READ_FAILURE
997 
998             if (pathSize > 0) {
999                 auto* pathData = deserializer.read(pathSize, kPathAlignment);
1000                 if (!pathData) READ_FAILURE
1001                 if (!path.readFromMemory(const_cast<const void*>(pathData), pathSize)) READ_FAILURE
1002                 pathPtr = &path;
1003             }
1004 
1005             strike->mergePath(allocatedGlyph, pathPtr);
1006         }
1007     }
1008 
1009     return true;
1010 }
1011 
deserializeTypeface(const void * buf,size_t len)1012 sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) {
1013     WireTypeface wire;
1014     if (len != sizeof(wire)) return nullptr;
1015     memcpy(&wire, buf, sizeof(wire));
1016     return this->addTypeface(wire);
1017 }
1018 
addTypeface(const WireTypeface & wire)1019 sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
1020     auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
1021     if (typeface) return *typeface;
1022 
1023     auto newTypeface = sk_make_sp<SkTypefaceProxy>(
1024             wire.typefaceID, wire.glyphCount, wire.style, wire.isFixed,
1025             fDiscardableHandleManager, fIsLogging);
1026     fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface);
1027     return std::move(newTypeface);
1028 }
1029