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 "SkRemoteGlyphCache.h"
9
10 #include <iterator>
11 #include <memory>
12 #include <new>
13 #include <string>
14 #include <tuple>
15
16 #include "SkDevice.h"
17 #include "SkDraw.h"
18 #include "SkGlyphRun.h"
19 #include "SkRemoteGlyphCacheImpl.h"
20 #include "SkStrike.h"
21 #include "SkStrikeCache.h"
22 #include "SkTLazy.h"
23 #include "SkTraceEvent.h"
24 #include "SkTypeface_remote.h"
25
26 #if SK_SUPPORT_GPU
27 #include "GrDrawOpAtlas.h"
28 #include "text/GrTextContext.h"
29 #endif
30
auto_descriptor_from_desc(const SkDescriptor * source_desc,SkFontID font_id,SkAutoDescriptor * ad)31 static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc,
32 SkFontID font_id,
33 SkAutoDescriptor* ad) {
34 ad->reset(source_desc->getLength());
35 auto* desc = ad->getDesc();
36 desc->init();
37
38 // Rec.
39 {
40 uint32_t size;
41 auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size);
42 SkScalerContextRec rec;
43 std::memcpy(&rec, ptr, size);
44 rec.fFontID = font_id;
45 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
46 }
47
48 // Effects.
49 {
50 uint32_t size;
51 auto ptr = source_desc->findEntry(kEffects_SkDescriptorTag, &size);
52 if (ptr) { desc->addEntry(kEffects_SkDescriptorTag, size, ptr); }
53 }
54
55 desc->computeChecksum();
56 return desc;
57 }
58
59 enum DescriptorType : bool { kKey = false, kDevice = true };
create_descriptor(DescriptorType type,const SkPaint & paint,const SkFont & font,const SkMatrix & m,const SkSurfaceProps & props,SkScalerContextFlags flags,SkAutoDescriptor * ad,SkScalerContextEffects * effects)60 static const SkDescriptor* create_descriptor(
61 DescriptorType type, const SkPaint& paint, const SkFont& font, const SkMatrix& m,
62 const SkSurfaceProps& props, SkScalerContextFlags flags,
63 SkAutoDescriptor* ad, SkScalerContextEffects* effects) {
64 SkScalerContextRec deviceRec;
65 bool enableTypefaceFiltering = (type == kDevice);
66 SkScalerContext::MakeRecAndEffects(
67 font, paint, props, flags, m, &deviceRec, effects, enableTypefaceFiltering);
68 return SkScalerContext::AutoDescriptorGivenRecAndEffects(deviceRec, *effects, ad);
69 }
70
71 // -- Serializer ----------------------------------------------------------------------------------
72
pad(size_t size,size_t alignment)73 size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
74
75 class Serializer {
76 public:
Serializer(std::vector<uint8_t> * buffer)77 Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} { }
78
79 template <typename T, typename... Args>
emplace(Args &&...args)80 T* emplace(Args&&... args) {
81 auto result = allocate(sizeof(T), alignof(T));
82 return new (result) T{std::forward<Args>(args)...};
83 }
84
85 template <typename T>
write(const T & data)86 void write(const T& data) {
87 T* result = (T*)allocate(sizeof(T), alignof(T));
88 memcpy(result, &data, sizeof(T));
89 }
90
91 template <typename T>
allocate()92 T* allocate() {
93 T* result = (T*)allocate(sizeof(T), alignof(T));
94 return result;
95 }
96
writeDescriptor(const SkDescriptor & desc)97 void writeDescriptor(const SkDescriptor& desc) {
98 write(desc.getLength());
99 auto result = allocate(desc.getLength(), alignof(SkDescriptor));
100 memcpy(result, &desc, desc.getLength());
101 }
102
allocate(size_t size,size_t alignment)103 void* allocate(size_t size, size_t alignment) {
104 size_t aligned = pad(fBuffer->size(), alignment);
105 fBuffer->resize(aligned + size);
106 return &(*fBuffer)[aligned];
107 }
108
109 private:
110 std::vector<uint8_t>* fBuffer;
111 };
112
113 // -- Deserializer -------------------------------------------------------------------------------
114 // Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
115 class Deserializer {
116 public:
Deserializer(const volatile char * memory,size_t memorySize)117 Deserializer(const volatile char* memory, size_t memorySize)
118 : fMemory(memory), fMemorySize(memorySize) {}
119
120 template <typename T>
read(T * val)121 bool read(T* val) {
122 auto* result = this->ensureAtLeast(sizeof(T), alignof(T));
123 if (!result) return false;
124
125 memcpy(val, const_cast<const char*>(result), sizeof(T));
126 return true;
127 }
128
readDescriptor(SkAutoDescriptor * ad)129 bool readDescriptor(SkAutoDescriptor* ad) {
130 uint32_t desc_length = 0u;
131 if (!read<uint32_t>(&desc_length)) return false;
132
133 auto* result = this->ensureAtLeast(desc_length, alignof(SkDescriptor));
134 if (!result) return false;
135
136 ad->reset(desc_length);
137 memcpy(ad->getDesc(), const_cast<const char*>(result), desc_length);
138 return true;
139 }
140
read(size_t size,size_t alignment)141 const volatile void* read(size_t size, size_t alignment) {
142 return this->ensureAtLeast(size, alignment);
143 }
144
145 private:
ensureAtLeast(size_t size,size_t alignment)146 const volatile char* ensureAtLeast(size_t size, size_t alignment) {
147 size_t padded = pad(fBytesRead, alignment);
148
149 // Not enough data
150 if (padded + size > fMemorySize) return nullptr;
151
152 auto* result = fMemory + padded;
153 fBytesRead = padded + size;
154 return result;
155 }
156
157 // Note that we read each piece of memory only once to guard against TOCTOU violations.
158 const volatile char* fMemory;
159 size_t fMemorySize;
160 size_t fBytesRead = 0u;
161 };
162
163 // Paths use a SkWriter32 which requires 4 byte alignment.
164 static const size_t kPathAlignment = 4u;
165
read_path(Deserializer * deserializer,SkGlyph * glyph,SkStrike * cache)166 bool read_path(Deserializer* deserializer, SkGlyph* glyph, SkStrike* cache) {
167 uint64_t pathSize = 0u;
168 if (!deserializer->read<uint64_t>(&pathSize)) return false;
169
170 if (pathSize == 0u) return true;
171
172 auto* path = deserializer->read(pathSize, kPathAlignment);
173 if (!path) return false;
174
175 return cache->initializePath(glyph, path, pathSize);
176 }
177
operator ()(const SkDescriptor * key) const178 size_t SkDescriptorMapOperators::operator()(const SkDescriptor* key) const {
179 return key->getChecksum();
180 }
181
operator ()(const SkDescriptor * lhs,const SkDescriptor * rhs) const182 bool SkDescriptorMapOperators::operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
183 return *lhs == *rhs;
184 }
185
186 struct StrikeSpec {
StrikeSpecStrikeSpec187 StrikeSpec() {}
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 // -- TrackLayerDevice -----------------------------------------------------------------------------
TrackLayerDevice(const SkIRect & bounds,const SkSurfaceProps & props,SkStrikeServer * server,const SkTextBlobCacheDiffCanvas::Settings & settings)197 SkTextBlobCacheDiffCanvas::TrackLayerDevice::TrackLayerDevice(
198 const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
199 const SkTextBlobCacheDiffCanvas::Settings& settings)
200 : SkNoPixelsDevice(bounds, props)
201 , fStrikeServer(server)
202 , fSettings(settings)
203 , fPainter{props, kUnknown_SkColorType, SkScalerContextFlags::kFakeGammaAndBoostContrast} {
204 SkASSERT(fStrikeServer);
205 }
206
onCreateDevice(const CreateInfo & cinfo,const SkPaint *)207 SkBaseDevice* SkTextBlobCacheDiffCanvas::TrackLayerDevice::onCreateDevice(
208 const CreateInfo& cinfo, const SkPaint*) {
209 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
210 return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps, fStrikeServer, fSettings);
211 }
212
drawGlyphRunList(const SkGlyphRunList & glyphRunList)213 void SkTextBlobCacheDiffCanvas::TrackLayerDevice::drawGlyphRunList(
214 const SkGlyphRunList& glyphRunList) {
215 for (auto& glyphRun : glyphRunList) {
216 this->processGlyphRun(glyphRunList.origin(), glyphRun, glyphRunList.paint());
217 }
218 }
219
220 // -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
221 SkTextBlobCacheDiffCanvas::Settings::Settings() = default;
222
SkTextBlobCacheDiffCanvas(int width,int height,const SkMatrix & deviceMatrix,const SkSurfaceProps & props,SkStrikeServer * strikeServer,Settings settings)223 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
224 const SkMatrix& deviceMatrix,
225 const SkSurfaceProps& props,
226 SkStrikeServer* strikeServer,
227 Settings settings)
228 : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(SkIRect::MakeWH(width, height), props,
229 strikeServer, settings)} {}
230
SkTextBlobCacheDiffCanvas(int width,int height,const SkSurfaceProps & props,SkStrikeServer * strikeServer,Settings settings)231 SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(
232 int width, int height, const SkSurfaceProps& props,
233 SkStrikeServer* strikeServer, Settings settings)
234 : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(
235 SkIRect::MakeWH(width, height), props, strikeServer, settings)} {}
236
237 SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() = default;
238
getSaveLayerStrategy(const SaveLayerRec & rec)239 SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
240 const SaveLayerRec& rec) {
241 return kFullLayer_SaveLayerStrategy;
242 }
243
onDoSaveBehind(const SkRect *)244 bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
245 return false;
246 }
247
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)248 void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
249 const SkPaint& paint) {
250 SkCanvas::onDrawTextBlob(blob, x, y, paint);
251 }
252
253 struct WireTypeface {
254 WireTypeface() = default;
WireTypefaceWireTypeface255 WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
256 : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {}
257
258 SkFontID typefaceID;
259 int glyphCount;
260 SkFontStyle style;
261 bool isFixed;
262 };
263
264 // SkStrikeServer -----------------------------------------
265
SkStrikeServer(DiscardableHandleManager * discardableHandleManager)266 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
267 : fDiscardableHandleManager(discardableHandleManager) {
268 SkASSERT(fDiscardableHandleManager);
269 }
270
271 SkStrikeServer::~SkStrikeServer() = default;
272
serializeTypeface(SkTypeface * tf)273 sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
274 auto* data = fSerializedTypefaces.find(SkTypeface::UniqueID(tf));
275 if (data) {
276 return *data;
277 }
278
279 WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
280 tf->isFixedPitch());
281 data = fSerializedTypefaces.set(SkTypeface::UniqueID(tf),
282 SkData::MakeWithCopy(&wire, sizeof(wire)));
283 return *data;
284 }
285
writeStrikeData(std::vector<uint8_t> * memory)286 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
287 if (fLockedDescs.empty() && fTypefacesToSend.empty()) {
288 return;
289 }
290
291 Serializer serializer(memory);
292 serializer.emplace<uint64_t>(fTypefacesToSend.size());
293 for (const auto& tf : fTypefacesToSend) serializer.write<WireTypeface>(tf);
294 fTypefacesToSend.clear();
295
296 serializer.emplace<uint64_t>(fLockedDescs.size());
297 for (const auto* desc : fLockedDescs) {
298 auto it = fRemoteGlyphStateMap.find(desc);
299 SkASSERT(it != fRemoteGlyphStateMap.end());
300 it->second->writePendingGlyphs(&serializer);
301 }
302 fLockedDescs.clear();
303 }
304
getOrCreateCache(const SkPaint & paint,const SkFont & font,const SkSurfaceProps & props,const SkMatrix & matrix,SkScalerContextFlags flags,SkScalerContextEffects * effects)305 SkStrikeServer::SkGlyphCacheState* SkStrikeServer::getOrCreateCache(
306 const SkPaint& paint,
307 const SkFont& font,
308 const SkSurfaceProps& props,
309 const SkMatrix& matrix,
310 SkScalerContextFlags flags,
311 SkScalerContextEffects* effects) {
312 SkAutoDescriptor keyAutoDesc;
313 auto keyDesc = create_descriptor(
314 kKey, paint, font, matrix, props, flags, &keyAutoDesc, effects);
315
316 // In cases where tracing is turned off, make sure not to get an unused function warning.
317 // Lambdaize the function.
318 TRACE_EVENT1("skia", "RecForDesc", "rec",
319 TRACE_STR_COPY(
320 [keyDesc](){
321 auto ptr = keyDesc->findEntry(kRec_SkDescriptorTag, nullptr);
322 SkScalerContextRec rec;
323 std::memcpy(&rec, ptr, sizeof(rec));
324 return rec.dump();
325 }().c_str()
326 )
327 );
328
329 // Already locked.
330 if (fLockedDescs.find(keyDesc) != fLockedDescs.end()) {
331 auto it = fRemoteGlyphStateMap.find(keyDesc);
332 SkASSERT(it != fRemoteGlyphStateMap.end());
333 SkGlyphCacheState* cache = it->second.get();
334 cache->setFontAndEffects(font, SkScalerContextEffects{paint});
335 return cache;
336 }
337
338 // Try to lock.
339 auto it = fRemoteGlyphStateMap.find(keyDesc);
340 if (it != fRemoteGlyphStateMap.end()) {
341 SkGlyphCacheState* cache = it->second.get();
342 #ifdef SK_DEBUG
343 SkScalerContextEffects deviceEffects;
344 SkAutoDescriptor deviceAutoDesc;
345 auto deviceDesc = create_descriptor(
346 kDevice, paint, font, matrix, props, flags, &deviceAutoDesc, &deviceEffects);
347 SkASSERT(cache->getDeviceDescriptor() == *deviceDesc);
348 #endif
349 bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
350 if (locked) {
351 fLockedDescs.insert(it->first);
352 cache->setFontAndEffects(font, SkScalerContextEffects{paint});
353 return cache;
354 }
355
356 // If the lock failed, the entry was deleted on the client. Remove our
357 // tracking.
358 fRemoteGlyphStateMap.erase(it);
359 }
360
361 auto* tf = font.getTypefaceOrDefault();
362 const SkFontID typefaceId = tf->uniqueID();
363 if (!fCachedTypefaces.contains(typefaceId)) {
364 fCachedTypefaces.add(typefaceId);
365 fTypefacesToSend.emplace_back(typefaceId, tf->countGlyphs(), tf->fontStyle(),
366 tf->isFixedPitch());
367 }
368
369 SkScalerContextEffects deviceEffects;
370 SkAutoDescriptor deviceAutoDesc;
371 auto deviceDesc = create_descriptor(
372 kDevice, paint, font, matrix, props, flags, &deviceAutoDesc, &deviceEffects);
373
374 auto context = tf->createScalerContext(deviceEffects, deviceDesc);
375
376 // Create a new cache state and insert it into the map.
377 auto newHandle = fDiscardableHandleManager->createHandle();
378 auto cacheState = skstd::make_unique<SkGlyphCacheState>(
379 *keyDesc, *deviceDesc, std::move(context), newHandle);
380
381 auto* cacheStatePtr = cacheState.get();
382
383 fLockedDescs.insert(&cacheStatePtr->getKeyDescriptor());
384 fRemoteGlyphStateMap[&cacheStatePtr->getKeyDescriptor()] = std::move(cacheState);
385
386 checkForDeletedEntries();
387
388 cacheStatePtr->setFontAndEffects(font, SkScalerContextEffects{paint});
389 return cacheStatePtr;
390 }
391
checkForDeletedEntries()392 void SkStrikeServer::checkForDeletedEntries() {
393 auto it = fRemoteGlyphStateMap.begin();
394 while (fRemoteGlyphStateMap.size() > fMaxEntriesInDescriptorMap &&
395 it != fRemoteGlyphStateMap.end()) {
396 if (fDiscardableHandleManager->isHandleDeleted(it->second->discardableHandleId())) {
397 it = fRemoteGlyphStateMap.erase(it);
398 } else {
399 ++it;
400 }
401 }
402 }
403
404 // -- SkGlyphCacheState ----------------------------------------------------------------------------
SkGlyphCacheState(const SkDescriptor & keyDescriptor,const SkDescriptor & deviceDescriptor,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)405 SkStrikeServer::SkGlyphCacheState::SkGlyphCacheState(
406 const SkDescriptor& keyDescriptor,
407 const SkDescriptor& deviceDescriptor,
408 std::unique_ptr<SkScalerContext> context,
409 uint32_t discardableHandleId)
410 : fKeyDescriptor{keyDescriptor}
411 , fDeviceDescriptor{deviceDescriptor}
412 , fDiscardableHandleId(discardableHandleId)
413 , fIsSubpixel{context->isSubpixel()}
414 , fAxisAlignmentForHText{context->computeAxisAlignmentForHText()}
415 // N.B. context must come last because it is used above.
416 , fContext{std::move(context)} {
417 SkASSERT(fKeyDescriptor.getDesc() != nullptr);
418 SkASSERT(fDeviceDescriptor.getDesc() != nullptr);
419 SkASSERT(fContext != nullptr);
420 }
421
422 SkStrikeServer::SkGlyphCacheState::~SkGlyphCacheState() = default;
423
addGlyph(SkPackedGlyphID glyph,bool asPath)424 void SkStrikeServer::SkGlyphCacheState::addGlyph(SkPackedGlyphID glyph, bool asPath) {
425 auto* cache = asPath ? &fCachedGlyphPaths : &fCachedGlyphImages;
426 auto* pending = asPath ? &fPendingGlyphPaths : &fPendingGlyphImages;
427
428 // Already cached.
429 if (cache->contains(glyph)) {
430 return;
431 }
432
433 // A glyph is going to be sent. Make sure we have a scaler context to send it.
434 this->ensureScalerContext();
435
436 // Serialize and cache. Also create the scalar context to use when serializing
437 // this glyph.
438 cache->add(glyph);
439 pending->push_back(glyph);
440 }
441
writeGlyph(SkGlyph * glyph,Serializer * serializer)442 static void writeGlyph(SkGlyph* glyph, Serializer* serializer) {
443 serializer->write<SkPackedGlyphID>(glyph->getPackedID());
444 serializer->write<float>(glyph->fAdvanceX);
445 serializer->write<float>(glyph->fAdvanceY);
446 serializer->write<uint16_t>(glyph->fWidth);
447 serializer->write<uint16_t>(glyph->fHeight);
448 serializer->write<int16_t>(glyph->fTop);
449 serializer->write<int16_t>(glyph->fLeft);
450 serializer->write<int8_t>(glyph->fForceBW);
451 serializer->write<uint8_t>(glyph->fMaskFormat);
452 }
453
writePendingGlyphs(Serializer * serializer)454 void SkStrikeServer::SkGlyphCacheState::writePendingGlyphs(Serializer* serializer) {
455 // TODO(khushalsagar): Write a strike only if it has any pending glyphs.
456 serializer->emplace<bool>(this->hasPendingGlyphs());
457 if (!this->hasPendingGlyphs()) {
458 this->resetScalerContext();
459 return;
460 }
461
462 // Write the desc.
463 serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
464 serializer->writeDescriptor(*fKeyDescriptor.getDesc());
465
466 // Write FontMetrics.
467 // TODO(khushalsagar): Do we need to re-send each time?
468 SkFontMetrics fontMetrics;
469 fContext->getFontMetrics(&fontMetrics);
470 serializer->write<SkFontMetrics>(fontMetrics);
471
472 // Write glyphs images.
473 serializer->emplace<uint64_t>(fPendingGlyphImages.size());
474 for (const auto& glyphID : fPendingGlyphImages) {
475 SkGlyph glyph{glyphID};
476 fContext->getMetrics(&glyph);
477 writeGlyph(&glyph, serializer);
478
479 auto imageSize = glyph.computeImageSize();
480 if (imageSize == 0u) continue;
481
482 glyph.fImage = serializer->allocate(imageSize, glyph.formatAlignment());
483 fContext->getImage(glyph);
484 // TODO: Generating the image can change the mask format, do we need to update it in the
485 // serialized glyph?
486 }
487 fPendingGlyphImages.clear();
488
489 // Write glyphs paths.
490 serializer->emplace<uint64_t>(fPendingGlyphPaths.size());
491 for (const auto& glyphID : fPendingGlyphPaths) {
492 SkGlyph glyph{glyphID};
493 fContext->getMetrics(&glyph);
494 writeGlyph(&glyph, serializer);
495 writeGlyphPath(glyphID, serializer);
496 }
497 fPendingGlyphPaths.clear();
498 this->resetScalerContext();
499 }
500
findGlyph(SkPackedGlyphID glyphID)501 const SkGlyph& SkStrikeServer::SkGlyphCacheState::findGlyph(SkPackedGlyphID glyphID) {
502 SkGlyph* glyphPtr = fGlyphMap.findOrNull(glyphID);
503 if (glyphPtr == nullptr) {
504 glyphPtr = fAlloc.make<SkGlyph>(glyphID);
505 fGlyphMap.set(glyphPtr);
506 this->ensureScalerContext();
507 fContext->getMetrics(glyphPtr);
508 }
509
510 return *glyphPtr;
511 }
512
ensureScalerContext()513 void SkStrikeServer::SkGlyphCacheState::ensureScalerContext() {
514 if (fContext == nullptr) {
515 auto tf = fFont->getTypefaceOrDefault();
516 fContext = tf->createScalerContext(fEffects, fDeviceDescriptor.getDesc());
517 }
518 }
519
resetScalerContext()520 void SkStrikeServer::SkGlyphCacheState::resetScalerContext() {
521 fContext.reset();
522 fFont = nullptr;
523 }
524
setFontAndEffects(const SkFont & font,SkScalerContextEffects effects)525 void SkStrikeServer::SkGlyphCacheState::setFontAndEffects(
526 const SkFont& font, SkScalerContextEffects effects) {
527 fFont = &font;
528 fEffects = effects;
529 }
530
rounding() const531 SkVector SkStrikeServer::SkGlyphCacheState::rounding() const {
532 return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignmentForHText);
533 }
534
getGlyphMetrics(SkGlyphID glyphID,SkPoint position)535 const SkGlyph& SkStrikeServer::SkGlyphCacheState::getGlyphMetrics(
536 SkGlyphID glyphID, SkPoint position) {
537 SkIPoint lookupPoint = SkStrikeCommon::SubpixelLookup(fAxisAlignmentForHText, position);
538 SkPackedGlyphID packedGlyphID = fIsSubpixel ? SkPackedGlyphID{glyphID, lookupPoint}
539 : SkPackedGlyphID{glyphID};
540
541 return this->findGlyph(packedGlyphID);
542 }
543
hasImage(const SkGlyph & glyph)544 bool SkStrikeServer::SkGlyphCacheState::hasImage(const SkGlyph& glyph) {
545 // If a glyph has width and height, it must have an image available to it.
546 return !glyph.isEmpty();
547 }
548
hasPath(const SkGlyph & glyph)549 bool SkStrikeServer::SkGlyphCacheState::hasPath(const SkGlyph& glyph) {
550 return const_cast<SkGlyph&>(glyph).addPath(fContext.get(), &fAlloc) != nullptr;
551 }
552
writeGlyphPath(const SkPackedGlyphID & glyphID,Serializer * serializer) const553 void SkStrikeServer::SkGlyphCacheState::writeGlyphPath(const SkPackedGlyphID& glyphID,
554 Serializer* serializer) const {
555 SkPath path;
556 if (!fContext->getPath(glyphID, &path)) {
557 serializer->write<uint64_t>(0u);
558 return;
559 }
560
561 size_t pathSize = path.writeToMemory(nullptr);
562 serializer->write<uint64_t>(pathSize);
563 path.writeToMemory(serializer->allocate(pathSize, kPathAlignment));
564 }
565
566 // SkStrikeClient -----------------------------------------
567 class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
568 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<DiscardableHandleManager> manager)569 DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
570 sk_sp<DiscardableHandleManager> manager)
571 : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
572
573 ~DiscardableStrikePinner() override = default;
canDelete()574 bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
575
576 private:
577 const SkDiscardableHandleId fDiscardableHandleId;
578 sk_sp<DiscardableHandleManager> fManager;
579 };
580
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)581 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
582 bool isLogging,
583 SkStrikeCache* strikeCache)
584 : fDiscardableHandleManager(std::move(discardableManager))
585 , fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()}
586 , fIsLogging{isLogging} {}
587
588 SkStrikeClient::~SkStrikeClient() = default;
589
590 #define READ_FAILURE \
591 { \
592 SkDEBUGFAIL("Bad serialization"); \
593 return false; \
594 }
595
readGlyph(SkTLazy<SkGlyph> & glyph,Deserializer * deserializer)596 static bool readGlyph(SkTLazy<SkGlyph>& glyph, Deserializer* deserializer) {
597 SkPackedGlyphID glyphID;
598 if (!deserializer->read<SkPackedGlyphID>(&glyphID)) return false;
599 glyph.init(glyphID);
600 if (!deserializer->read<float>(&glyph->fAdvanceX)) return false;
601 if (!deserializer->read<float>(&glyph->fAdvanceY)) return false;
602 if (!deserializer->read<uint16_t>(&glyph->fWidth)) return false;
603 if (!deserializer->read<uint16_t>(&glyph->fHeight)) return false;
604 if (!deserializer->read<int16_t>(&glyph->fTop)) return false;
605 if (!deserializer->read<int16_t>(&glyph->fLeft)) return false;
606 if (!deserializer->read<int8_t>(&glyph->fForceBW)) return false;
607 if (!deserializer->read<uint8_t>(&glyph->fMaskFormat)) return false;
608 return true;
609 }
610
readStrikeData(const volatile void * memory,size_t memorySize)611 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
612 SkASSERT(memorySize != 0u);
613 Deserializer deserializer(static_cast<const volatile char*>(memory), memorySize);
614
615 uint64_t typefaceSize = 0u;
616 if (!deserializer.read<uint64_t>(&typefaceSize)) READ_FAILURE
617
618 for (size_t i = 0; i < typefaceSize; ++i) {
619 WireTypeface wire;
620 if (!deserializer.read<WireTypeface>(&wire)) READ_FAILURE
621
622 // TODO(khushalsagar): The typeface no longer needs a reference to the
623 // SkStrikeClient, since all needed glyphs must have been pushed before
624 // raster.
625 addTypeface(wire);
626 }
627
628 uint64_t strikeCount = 0u;
629 if (!deserializer.read<uint64_t>(&strikeCount)) READ_FAILURE
630
631 for (size_t i = 0; i < strikeCount; ++i) {
632 bool has_glyphs = false;
633 if (!deserializer.read<bool>(&has_glyphs)) READ_FAILURE
634
635 if (!has_glyphs) continue;
636
637 StrikeSpec spec;
638 if (!deserializer.read<StrikeSpec>(&spec)) READ_FAILURE
639
640 SkAutoDescriptor sourceAd;
641 if (!deserializer.readDescriptor(&sourceAd)) READ_FAILURE
642
643 SkFontMetrics fontMetrics;
644 if (!deserializer.read<SkFontMetrics>(&fontMetrics)) READ_FAILURE
645
646 // Get the local typeface from remote fontID.
647 auto* tf = fRemoteFontIdToTypeface.find(spec.typefaceID)->get();
648 // Received strikes for a typeface which doesn't exist.
649 if (!tf) READ_FAILURE
650
651 // Replace the ContextRec in the desc from the server to create the client
652 // side descriptor.
653 // TODO: Can we do this in-place and re-compute checksum? Instead of a complete copy.
654 SkAutoDescriptor ad;
655 auto* client_desc = auto_descriptor_from_desc(sourceAd.getDesc(), tf->uniqueID(), &ad);
656
657 auto strike = fStrikeCache->findStrikeExclusive(*client_desc);
658 if (strike == nullptr) {
659 // Note that we don't need to deserialize the effects since we won't be generating any
660 // glyphs here anyway, and the desc is still correct since it includes the serialized
661 // effects.
662 SkScalerContextEffects effects;
663 auto scaler = SkStrikeCache::CreateScalerContext(*client_desc, effects, *tf);
664 strike = fStrikeCache->createStrikeExclusive(
665 *client_desc, std::move(scaler), &fontMetrics,
666 skstd::make_unique<DiscardableStrikePinner>(spec.discardableHandleId,
667 fDiscardableHandleManager));
668 auto proxyContext = static_cast<SkScalerContextProxy*>(strike->getScalerContext());
669 proxyContext->initCache(strike.get(), fStrikeCache);
670 }
671
672 uint64_t glyphImagesCount = 0u;
673 if (!deserializer.read<uint64_t>(&glyphImagesCount)) READ_FAILURE
674 for (size_t j = 0; j < glyphImagesCount; j++) {
675 SkTLazy<SkGlyph> glyph;
676 if (!readGlyph(glyph, &deserializer)) READ_FAILURE
677
678 SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID());
679
680 // Update the glyph unless it's already got an image (from fallback),
681 // preserving any path that might be present.
682 if (allocatedGlyph->fImage == nullptr) {
683 auto* glyphPath = allocatedGlyph->fPathData;
684 *allocatedGlyph = *glyph;
685 allocatedGlyph->fPathData = glyphPath;
686 }
687
688 auto imageSize = glyph->computeImageSize();
689 if (imageSize == 0u) continue;
690
691 auto* image = deserializer.read(imageSize, allocatedGlyph->formatAlignment());
692 if (!image) READ_FAILURE
693 strike->initializeImage(image, imageSize, allocatedGlyph);
694 }
695
696 uint64_t glyphPathsCount = 0u;
697 if (!deserializer.read<uint64_t>(&glyphPathsCount)) READ_FAILURE
698 for (size_t j = 0; j < glyphPathsCount; j++) {
699 SkTLazy<SkGlyph> glyph;
700 if (!readGlyph(glyph, &deserializer)) READ_FAILURE
701
702 SkGlyph* allocatedGlyph = strike->getRawGlyphByID(glyph->getPackedID());
703
704 // Update the glyph unless it's already got a path (from fallback),
705 // preserving any image that might be present.
706 if (allocatedGlyph->fPathData == nullptr) {
707 auto* glyphImage = allocatedGlyph->fImage;
708 *allocatedGlyph = *glyph;
709 allocatedGlyph->fImage = glyphImage;
710 }
711
712 if (!read_path(&deserializer, allocatedGlyph, strike.get())) READ_FAILURE
713 }
714 }
715
716 return true;
717 }
718
deserializeTypeface(const void * buf,size_t len)719 sk_sp<SkTypeface> SkStrikeClient::deserializeTypeface(const void* buf, size_t len) {
720 WireTypeface wire;
721 if (len != sizeof(wire)) return nullptr;
722 memcpy(&wire, buf, sizeof(wire));
723 return this->addTypeface(wire);
724 }
725
addTypeface(const WireTypeface & wire)726 sk_sp<SkTypeface> SkStrikeClient::addTypeface(const WireTypeface& wire) {
727 auto* typeface = fRemoteFontIdToTypeface.find(wire.typefaceID);
728 if (typeface) return *typeface;
729
730 auto newTypeface = sk_make_sp<SkTypefaceProxy>(
731 wire.typefaceID, wire.glyphCount, wire.style, wire.isFixed,
732 fDiscardableHandleManager, fIsLogging);
733 fRemoteFontIdToTypeface.set(wire.typefaceID, newTypeface);
734 return std::move(newTypeface);
735 }
736