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