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 "include/gpu/GrContextOptions.h"
32#include "src/gpu/GrDrawOpAtlas.h"
33#include "src/gpu/text/GrSDFTOptions.h"
34#endif
35
36static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc,
37 SkFontID font_id,
38 SkAutoDescriptor* ad) {
39 ad->reset(source_desc->getLength());
40 auto* desc = ad->getDesc();
41
42 // Rec.
43 {
44 uint32_t size;
45 auto ptr = source_desc->findEntry(kRec_SkDescriptorTag, &size);
46 SkScalerContextRec rec;
47 std::memcpy((void*)&rec, ptr, size);
48 rec.fFontID = font_id;
49 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
50 }
51
52 // Effects.
53 {
54 uint32_t size;
55 auto ptr = source_desc->findEntry(kEffects_SkDescriptorTag, &size);
56 if (ptr) { desc->addEntry(kEffects_SkDescriptorTag, size, ptr); }
57 }
58
59 desc->computeChecksum();
60 return desc;
61}
62
63static const SkDescriptor* create_descriptor(
64 const SkPaint& paint, const SkFont& font, const SkMatrix& m,
65 const SkSurfaceProps& props, SkScalerContextFlags flags,
66 SkAutoDescriptor* ad, SkScalerContextEffects* effects) {
67 SkScalerContextRec rec;
68 SkScalerContext::MakeRecAndEffects(font, paint, props, flags, m, &rec, effects);
69 return SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, *effects, ad);
70}
71
72// -- Serializer -----------------------------------------------------------------------------------
73size_t pad(size_t size, size_t alignment) { return (size + (alignment - 1)) & ~(alignment - 1); }
74
75// Alignment between x86 and x64 differs for some types, in particular
76// int64_t and doubles have 4 and 8-byte alignment, respectively.
77// Be consistent even when writing and reading across different architectures.
78template<typename T>
79size_t serialization_alignment() {
80 return sizeof(T) == 8 ? 8 : alignof(T);
81}
82
83class Serializer {
84public:
85 explicit Serializer(std::vector<uint8_t>* buffer) : fBuffer{buffer} {}
86
87 template <typename T, typename... Args>
88 T* emplace(Args&&... args) {
89 auto result = allocate(sizeof(T), serialization_alignment<T>());
90 return new (result) T{std::forward<Args>(args)...};
91 }
92
93 template <typename T>
94 void write(const T& data) {
95 T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
96 memcpy(result, &data, sizeof(T));
97 }
98
99 template <typename T>
100 T* allocate() {
101 T* result = (T*)allocate(sizeof(T), serialization_alignment<T>());
102 return result;
103 }
104
105 void writeDescriptor(const SkDescriptor& desc) {
106 write(desc.getLength());
107 auto result = allocate(desc.getLength(), alignof(SkDescriptor));
108 memcpy(result, &desc, desc.getLength());
109 }
110
111 void* allocate(size_t size, size_t alignment) {
112 size_t aligned = pad(fBuffer->size(), alignment);
113 fBuffer->resize(aligned + size);
114 return &(*fBuffer)[aligned];
115 }
116
117private:
118 std::vector<uint8_t>* fBuffer;
119};
120
121// -- Deserializer -------------------------------------------------------------------------------
122// Note that the Deserializer is reading untrusted data, we need to guard against invalid data.
123class Deserializer {
124public:
125 Deserializer(const volatile char* memory, size_t memorySize)
126 : fMemory(memory), fMemorySize(memorySize) {}
127
128 template <typename T>
129 bool read(T* val) {
130 auto* result = this->ensureAtLeast(sizeof(T), serialization_alignment<T>());
131 if (!result) return false;
132
133 memcpy(val, const_cast<const char*>(result), sizeof(T));
134 return true;
135 }
136
137 bool readDescriptor(SkAutoDescriptor* ad) {
138 uint32_t descLength = 0u;
139 if (!read<uint32_t>(&descLength)) return false;
140 if (descLength < sizeof(SkDescriptor)) return false;
141 if (descLength != SkAlign4(descLength)) return false;
142
143 auto* result = this->ensureAtLeast(descLength, alignof(SkDescriptor));
144 if (!result) return false;
145
146 ad->reset(descLength);
147 memcpy(ad->getDesc(), const_cast<const char*>(result), descLength);
148
149 if (ad->getDesc()->getLength() > descLength) return false;
150 return ad->getDesc()->isValid();
151 }
152
153 const volatile void* read(size_t size, size_t alignment) {
154 return this->ensureAtLeast(size, alignment);
155 }
156
157 size_t bytesRead() const { return fBytesRead; }
158
159private:
160 const volatile char* ensureAtLeast(size_t size, size_t alignment) {
161 size_t padded = pad(fBytesRead, alignment);
162
163 // Not enough data.
164 if (padded > fMemorySize) return nullptr;
165 if (size > fMemorySize - padded) return nullptr;
166
167 auto* result = fMemory + padded;
168 fBytesRead = padded + size;
169 return result;
170 }
171
172 // Note that we read each piece of memory only once to guard against TOCTOU violations.
173 const volatile char* fMemory;
174 size_t fMemorySize;
175 size_t fBytesRead = 0u;
176};
177
178bool SkFuzzDeserializeSkDescriptor(sk_sp<SkData> bytes, SkAutoDescriptor* ad) {
179 auto d = Deserializer(reinterpret_cast<const volatile char*>(bytes->data()), bytes->size());
180 return d.readDescriptor(ad);
181}
182
183// Paths use a SkWriter32 which requires 4 byte alignment.
184static const size_t kPathAlignment = 4u;
185
186// -- StrikeSpec -----------------------------------------------------------------------------------
187struct StrikeSpec {
188 StrikeSpec() = default;
189 StrikeSpec(SkFontID typefaceID_, SkDiscardableHandleId discardableHandleId_)
190 : typefaceID{typefaceID_}, discardableHandleId(discardableHandleId_) {}
191 SkFontID typefaceID = 0u;
192 SkDiscardableHandleId discardableHandleId = 0u;
193 /* desc */
194 /* n X (glyphs ids) */
195};
196
197// Represent a set of x sub-pixel-position glyphs with a glyph id < kMaxGlyphID and
198// y sub-pxiel-position must be 0. Most sub-pixel-positioned glyphs have been x-axis aligned
199// forcing the y sub-pixel position to be zero. We can organize the SkPackedGlyphID to check that
200// the glyph id and the y position == 0 with a single compare in the following way:
201// <y-sub-pixel-position>:2 | <glyphid:16> | <x-sub-pixel-position>:2
202// This organization allows a single check of a packed-id to be:
203// packed-id < kMaxGlyphID * possible-x-sub-pixel-positions
204// where possible-x-sub-pixel-positions == 4.
205class LowerRangeBitVector {
206public:
207 bool test(SkPackedGlyphID packedID) const {
208 uint32_t bit = packedID.value();
209 return bit < kMaxIndex && fBits.test(bit);
210 }
211 void setIfLower(SkPackedGlyphID packedID) {
212 uint32_t bit = packedID.value();
213 if (bit < kMaxIndex) {
214 fBits.set(bit);
215 }
216 }
217
218private:
219 using GID = SkPackedGlyphID;
220 static_assert(GID::kSubPixelX < GID::kGlyphID && GID::kGlyphID < GID::kSubPixelY,
221 "SkPackedGlyphID must be organized: sub-y | glyph id | sub-x");
222 static constexpr int kMaxGlyphID = 128;
223 static constexpr int kMaxIndex = kMaxGlyphID * (1u << GID::kSubPixelPosLen);
224 std::bitset<kMaxIndex> fBits;
225};
226
227// -- RemoteStrike ----------------------------------------------------------------------------
228class SkStrikeServer::RemoteStrike final : public SkStrikeForGPU {
229public:
230 // N.B. RemoteStrike is not valid until ensureScalerContext is called.
231 RemoteStrike(const SkDescriptor& descriptor,
232 std::unique_ptr<SkScalerContext> context,
233 SkDiscardableHandleId discardableHandleId);
234 ~RemoteStrike() override;
235
236 void writePendingGlyphs(Serializer* serializer);
237 SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
238
239 const SkDescriptor& getDescriptor() const override {
240 return *fDescriptor.getDesc();
241 }
242
243 void setTypefaceAndEffects(const SkTypeface* typeface, SkScalerContextEffects effects);
244
245 const SkGlyphPositionRoundingSpec& roundingSpec() const override {
246 return fRoundingSpec;
247 }
248
249 void prepareForMaskDrawing(
250 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
251
252 void prepareForSDFTDrawing(
253 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
254
255 void prepareForPathDrawing(
256 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) override;
257
258 void onAboutToExitScope() override {}
259
260 bool hasPendingGlyphs() const {
261 return !fMasksToSend.empty() || !fPathsToSend.empty();
262 }
263
264 void resetScalerContext();
265
266private:
267 template <typename Rejector>
268 void commonMaskLoop(
269 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject);
270
271 // Keep track of if the glyph draw has been totally satisfied. It could be that this
272 // strike can not draw the glyph, and it must be rejected to be handled by fallback.
273 // For example, if a glyph has canDrawAsMask sent, then that data is on the GPU, and this
274 // strike totally satisfies this result. If canDrawAsMask is false, then this glyph must be
275 // rejected, and handled by a later stage using a latter strike.
276 struct MaskSummary {
277 static_assert(SkPackedGlyphID::kMaskAll < (1u << 30), "SkPackedGlyphID is too big.");
278 uint32_t packedID:30;
279 uint32_t canDrawAsMask:1;
280 uint32_t canDrawAsSDFT:1;
281 };
282
283 struct MaskSummaryTraits {
284 static SkPackedGlyphID GetKey(MaskSummary summary) {
285 return SkPackedGlyphID{summary.packedID};
286 }
287
288 static uint32_t Hash(SkPackedGlyphID packedID) {
289 return packedID.hash();
290 }
291 };
292
293 // Same thing as MaskSummary, but for paths.
294 struct PathSummary {
295 constexpr static uint16_t kIsPath = 0;
296 SkGlyphID glyphID;
297 // If drawing glyphID can be done with a path, this is 0, otherwise it is the max
298 // dimension of the glyph.
299 uint16_t maxDimensionOrPath;
300 };
301
302 struct PathSummaryTraits {
303 static SkGlyphID GetKey(PathSummary summary) {
304 return summary.glyphID;
305 }
306
307 static uint32_t Hash(SkGlyphID packedID) {
308 return SkChecksum::CheapMix(packedID);
309 }
310 };
311
312 void writeGlyphPath(const SkGlyph& glyph, Serializer* serializer) const;
313 void ensureScalerContext();
314
315 const int fNumberOfGlyphs;
316 const SkAutoDescriptor fDescriptor;
317 const SkDiscardableHandleId fDiscardableHandleId;
318
319 const SkGlyphPositionRoundingSpec fRoundingSpec;
320
321 // The context built using fDescriptor
322 std::unique_ptr<SkScalerContext> fContext;
323
324 // These fields are set every time getOrCreateCache. This allows the code to maintain the
325 // fContext as lazy as possible.
326 const SkTypeface* fTypeface{nullptr};
327 SkScalerContextEffects fEffects;
328
329 // Have the metrics been sent for this strike. Only send them once.
330 bool fHaveSentFontMetrics{false};
331
332 LowerRangeBitVector fSentLowGlyphIDs;
333
334 // The masks and paths that currently reside in the GPU process.
335 SkTHashTable<MaskSummary, SkPackedGlyphID, MaskSummaryTraits> fSentGlyphs;
336 SkTHashTable<PathSummary, SkGlyphID, PathSummaryTraits> fSentPaths;
337
338 // The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
339 // TextBlobs. Cleared after diffs are serialized.
340 std::vector<SkGlyph> fMasksToSend;
341 std::vector<SkGlyph> fPathsToSend;
342
343 // Alloc for storing bits and pieces of paths, Cleared after diffs are serialized.
344 SkArenaAllocWithReset fPathAlloc{256};
345};
346
347SkStrikeServer::RemoteStrike::RemoteStrike(
348 const SkDescriptor& descriptor,
349 std::unique_ptr<SkScalerContext> context,
350 uint32_t discardableHandleId)
351 : fNumberOfGlyphs(context->getGlyphCount())
352 , fDescriptor{descriptor}
353 , fDiscardableHandleId(discardableHandleId)
354 , fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()}
355 // N.B. context must come last because it is used above.
356 , fContext{std::move(context)}
357 , fSentLowGlyphIDs{} {
358 SkASSERT(fDescriptor.getDesc() != nullptr);
359 SkASSERT(fContext != nullptr);
360}
361
362SkStrikeServer::RemoteStrike::~RemoteStrike() = default;
363
364size_t SkStrikeServer::MapOps::operator()(const SkDescriptor* key) const {
365 return key->getChecksum();
366}
367
368bool SkStrikeServer::MapOps::operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
369 return *lhs == *rhs;
370}
371
372// -- TrackLayerDevice -----------------------------------------------------------------------------
373class SkTextBlobCacheDiffCanvas::TrackLayerDevice final : public SkNoPixelsDevice {
374public:
375 TrackLayerDevice(
376 const SkIRect& bounds, const SkSurfaceProps& props, SkStrikeServer* server,
377 sk_sp<SkColorSpace> colorSpace, bool DFTSupport)
378 : SkNoPixelsDevice(bounds, props, std::move(colorSpace))
379 , fStrikeServer(server)
380 , fDFTSupport(DFTSupport)
381 , fPainter{props, kUnknown_SkColorType, imageInfo().colorSpace(), fStrikeServer} {
382 SkASSERT(fStrikeServer != nullptr);
383 }
384
385 SkBaseDevice* onCreateDevice(const CreateInfo& cinfo, const SkPaint*) override {
386 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
387 return new TrackLayerDevice(this->getGlobalBounds(), surfaceProps, fStrikeServer,
388 cinfo.fInfo.refColorSpace(), fDFTSupport);
389 }
390
391 SkStrikeServer* strikeServer() { return fStrikeServer; }
392
393protected:
394 void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override {
395 #if SK_SUPPORT_GPU
396 GrContextOptions ctxOptions;
397 GrSDFTOptions options =
398 {ctxOptions.fMinDistanceFieldFontSize, ctxOptions.fGlyphsAsPathsFontSize};
399
400 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
401 if (SkTextBlobTrace::Capture* capture = fStrikeServer->fCapture.get()) {
402 capture->capture(glyphRunList);
403 }
404 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
405
406 fPainter.processGlyphRunList(glyphRunList,
407 this->localToDevice(),
408 this->surfaceProps(),
409 fDFTSupport,
410 options,
411 nullptr);
412 #endif // SK_SUPPORT_GPU
413 }
414
415private:
416 SkStrikeServer* const fStrikeServer;
417 const bool fDFTSupport{false};
418 SkGlyphRunListPainter fPainter;
419};
420
421// -- SkTextBlobCacheDiffCanvas -------------------------------------------------------------------
422SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
423 const SkSurfaceProps& props,
424 SkStrikeServer* strikeServer,
425 bool DFTSupport)
426 : SkTextBlobCacheDiffCanvas{width, height, props, strikeServer, nullptr, DFTSupport} { }
427
428SkTextBlobCacheDiffCanvas::SkTextBlobCacheDiffCanvas(int width, int height,
429 const SkSurfaceProps& props,
430 SkStrikeServer* strikeServer,
431 sk_sp<SkColorSpace> colorSpace,
432 bool DFTSupport)
433 : SkNoDrawCanvas{sk_make_sp<TrackLayerDevice>(SkIRect::MakeWH(width, height),
434 props,
435 strikeServer,
436 std::move(colorSpace),
437 DFTSupport)} {
438 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
439 if (!strikeServer->fCapture) {
440 strikeServer->fCapture.reset(new SkTextBlobTrace::Capture);
441 }
442 #endif // SK_CAPTURE_DRAW_TEXT_BLOB
443 }
444
445SkTextBlobCacheDiffCanvas::~SkTextBlobCacheDiffCanvas() {
446#ifdef SK_CAPTURE_DRAW_TEXT_BLOB
447 SkTextBlobTrace::Capture* capture =
448 ((TrackLayerDevice*)this->getTopDevice())->strikeServer()->fCapture.get();
449 if (capture) {
450 capture->dump();
451 }
452#endif // SK_CAPTURE_DRAW_TEXT_BLOB
453}
454
455SkCanvas::SaveLayerStrategy SkTextBlobCacheDiffCanvas::getSaveLayerStrategy(
456 const SaveLayerRec& rec) {
457 return kFullLayer_SaveLayerStrategy;
458}
459
460bool SkTextBlobCacheDiffCanvas::onDoSaveBehind(const SkRect*) {
461 return false;
462}
463
464void SkTextBlobCacheDiffCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
465 const SkPaint& paint) {
466 SkCanvas::onDrawTextBlob(blob, x, y, paint);
467}
468
469// -- WireTypeface ---------------------------------------------------------------------------------
470struct WireTypeface {
471 WireTypeface() = default;
472 WireTypeface(SkFontID typeface_id, int glyph_count, SkFontStyle style, bool is_fixed)
473 : typefaceID(typeface_id), glyphCount(glyph_count), style(style), isFixed(is_fixed) {}
474
475 SkFontID typefaceID{0};
476 int glyphCount{0};
477 SkFontStyle style;
478 bool isFixed{false};
479};
480
481// SkStrikeServer ----------------------------------------------------------------------------------
482SkStrikeServer::SkStrikeServer(DiscardableHandleManager* discardableHandleManager)
483 : fDiscardableHandleManager(discardableHandleManager) {
484 SkASSERT(fDiscardableHandleManager);
485}
486
487SkStrikeServer::~SkStrikeServer() {
488#ifdef SK_CAPTURE_DRAW_TEXT_BLOB
489 if (fCapture) {
490 fCapture->dump();
491 }
492#endif // SK_CAPTURE_DRAW_TEXT_BLOB
493}
494
495sk_sp<SkData> SkStrikeServer::serializeTypeface(SkTypeface* tf) {
496 auto* data = fSerializedTypefaces.find(SkTypeface::UniqueID(tf));
497 if (data) {
498 return *data;
499 }
500
501 WireTypeface wire(SkTypeface::UniqueID(tf), tf->countGlyphs(), tf->fontStyle(),
502 tf->isFixedPitch());
503 data = fSerializedTypefaces.set(SkTypeface::UniqueID(tf),
504 SkData::MakeWithCopy(&wire, sizeof(wire)));
505 return *data;
506}
507
508void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
509 size_t strikesToSend = 0;
510 fRemoteStrikesToSend.foreach ([&](RemoteStrike* strike) {
511 if (strike->hasPendingGlyphs()) {
512 strikesToSend++;
513 } else {
514 strike->resetScalerContext();
515 }
516 });
517
518 if (strikesToSend == 0 && fTypefacesToSend.empty()) {
519 fRemoteStrikesToSend.reset();
520 return;
521 }
522
523 Serializer serializer(memory);
524 serializer.emplace<uint64_t>(fTypefacesToSend.size());
525 for (const auto& tf : fTypefacesToSend) {
526 serializer.write<WireTypeface>(tf);
527 }
528 fTypefacesToSend.clear();
529
530 serializer.emplace<uint64_t>(SkTo<uint64_t>(strikesToSend));
531 fRemoteStrikesToSend.foreach (
532#ifdef SK_DEBUG
533 [&](RemoteStrike* strike) {
534 if (strike->hasPendingGlyphs()) {
535 strike->writePendingGlyphs(&serializer);
536 strike->resetScalerContext();
537 }
538 auto it = fDescToRemoteStrike.find(&strike->getDescriptor());
539 SkASSERT(it != fDescToRemoteStrike.end());
540 SkASSERT(it->second.get() == strike);
541 }
542
543#else
544 [&serializer](RemoteStrike* strike) {
545 if (strike->hasPendingGlyphs()) {
546 strike->writePendingGlyphs(&serializer);
547 strike->resetScalerContext();
548 }
549 }
550#endif
551 );
552 fRemoteStrikesToSend.reset();
553}
554
555SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
556 const SkPaint& paint,
557 const SkFont& font,
558 const SkSurfaceProps& props,
559 const SkMatrix& matrix,
560 SkScalerContextFlags flags,
561 SkScalerContextEffects* effects) {
562 SkAutoDescriptor descStorage;
563 auto desc = create_descriptor(paint, font, matrix, props, flags, &descStorage, effects);
564
565 return this->getOrCreateCache(*desc, *font.getTypefaceOrDefault(), *effects);
566}
567
568SkScopedStrikeForGPU SkStrikeServer::findOrCreateScopedStrike(const SkDescriptor& desc,
569 const SkScalerContextEffects& effects,
570 const SkTypeface& typeface) {
571 return SkScopedStrikeForGPU{this->getOrCreateCache(desc, typeface, effects)};
572}
573
574void SkStrikeServer::AddGlyphForTesting(
575 RemoteStrike* strike, SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
576 strike->prepareForMaskDrawing(drawables, rejects);
577 rejects->flipRejectsToSource();
578 SkASSERT(rejects->source().empty());
579}
580
581void SkStrikeServer::checkForDeletedEntries() {
582 auto it = fDescToRemoteStrike.begin();
583 while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
584 it != fDescToRemoteStrike.end()) {
585 RemoteStrike* strike = it->second.get();
586 if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) {
587 // If we are removing the strike, we better not be trying to send it at the same time.
588 SkASSERT(!fRemoteStrikesToSend.contains(strike));
589 it = fDescToRemoteStrike.erase(it);
590 } else {
591 ++it;
592 }
593 }
594}
595
596SkStrikeServer::RemoteStrike* SkStrikeServer::getOrCreateCache(
597 const SkDescriptor& desc, const SkTypeface& typeface, SkScalerContextEffects effects) {
598
599 // In cases where tracing is turned off, make sure not to get an unused function warning.
600 // Lambdaize the function.
601 TRACE_EVENT1("skia", "RecForDesc", "rec",
602 TRACE_STR_COPY(
603 [&desc](){
604 auto ptr = desc.findEntry(kRec_SkDescriptorTag, nullptr);
605 SkScalerContextRec rec;
606 std::memcpy((void*)&rec, ptr, sizeof(rec));
607 return rec.dump();
608 }().c_str()
609 )
610 );
611
612 auto it = fDescToRemoteStrike.find(&desc);
613 if (it != fDescToRemoteStrike.end()) {
614 // We have processed the RemoteStrike before. Reuse it.
615 RemoteStrike* strike = it->second.get();
616 strike->setTypefaceAndEffects(&typeface, effects);
617 if (fRemoteStrikesToSend.contains(strike)) {
618 // Already tracking
619 return strike;
620 }
621
622 // Strike is in unknown state on GPU. Start tracking strike on GPU by locking it.
623 bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
624 if (locked) {
625 fRemoteStrikesToSend.add(strike);
626 return strike;
627 }
628
629 fDescToRemoteStrike.erase(it);
630 }
631
632 // Create a new RemoteStrike. Start by processing the typeface.
633 const SkFontID typefaceId = typeface.uniqueID();
634 if (!fCachedTypefaces.contains(typefaceId)) {
635 fCachedTypefaces.add(typefaceId);
636 fTypefacesToSend.emplace_back(typefaceId, typeface.countGlyphs(),
637 typeface.fontStyle(),
638 typeface.isFixedPitch());
639 }
640
641 auto context = typeface.createScalerContext(effects, &desc);
642 auto newHandle = fDiscardableHandleManager->createHandle(); // Locked on creation
643 auto remoteStrike = std::make_unique<RemoteStrike>(desc, std::move(context), newHandle);
644 remoteStrike->setTypefaceAndEffects(&typeface, effects);
645 auto remoteStrikePtr = remoteStrike.get();
646 fRemoteStrikesToSend.add(remoteStrikePtr);
647 auto d = &remoteStrike->getDescriptor();
648 fDescToRemoteStrike[d] = std::move(remoteStrike);
649
650 checkForDeletedEntries();
651
652 // Be sure we can build glyphs with this RemoteStrike.
653 remoteStrikePtr->setTypefaceAndEffects(&typeface, effects);
654 return remoteStrikePtr;
655}
656
657// No need to write fForceBW because it is a flag private to SkScalerContext_DW, which will never
658// be called on the GPU side.
659static void writeGlyph(const SkGlyph& glyph, Serializer* serializer) {
660 serializer->write<SkPackedGlyphID>(glyph.getPackedID());
661 serializer->write<float>(glyph.advanceX());
662 serializer->write<float>(glyph.advanceY());
663 serializer->write<uint16_t>(glyph.width());
664 serializer->write<uint16_t>(glyph.height());
665 serializer->write<int16_t>(glyph.top());
666 serializer->write<int16_t>(glyph.left());
667 serializer->write<uint8_t>(glyph.maskFormat());
668}
669
670void SkStrikeServer::RemoteStrike::writePendingGlyphs(Serializer* serializer) {
671 SkASSERT(this->hasPendingGlyphs());
672
673 // Write the desc.
674 serializer->emplace<StrikeSpec>(fContext->getTypeface()->uniqueID(), fDiscardableHandleId);
675 serializer->writeDescriptor(*fDescriptor.getDesc());
676
677 serializer->emplace<bool>(fHaveSentFontMetrics);
678 if (!fHaveSentFontMetrics) {
679 // Write FontMetrics if not sent before.
680 SkFontMetrics fontMetrics;
681 fContext->getFontMetrics(&fontMetrics);
682 serializer->write<SkFontMetrics>(fontMetrics);
683 fHaveSentFontMetrics = true;
684 }
685
686 // Write mask glyphs
687 serializer->emplace<uint64_t>(fMasksToSend.size());
688 for (SkGlyph& glyph : fMasksToSend) {
689 SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
690
691 writeGlyph(glyph, serializer);
692 auto imageSize = glyph.imageSize();
693 if (imageSize > 0 && FitsInAtlas(glyph)) {
694 glyph.fImage = serializer->allocate(imageSize, glyph.formatAlignment());
695 fContext->getImage(glyph);
696 }
697 }
698 fMasksToSend.clear();
699
700 // Write glyphs paths.
701 serializer->emplace<uint64_t>(fPathsToSend.size());
702 for (SkGlyph& glyph : fPathsToSend) {
703 SkASSERT(SkMask::IsValidFormat(glyph.fMaskFormat));
704
705 writeGlyph(glyph, serializer);
706 writeGlyphPath(glyph, serializer);
707 }
708 fPathsToSend.clear();
709 fPathAlloc.reset();
710}
711
712void SkStrikeServer::RemoteStrike::ensureScalerContext() {
713 if (fContext == nullptr) {
714 fContext = fTypeface->createScalerContext(fEffects, fDescriptor.getDesc());
715 }
716}
717
718void SkStrikeServer::RemoteStrike::resetScalerContext() {
719 fContext.reset();
720 fTypeface = nullptr;
721}
722
723void SkStrikeServer::RemoteStrike::setTypefaceAndEffects(
724 const SkTypeface* typeface, SkScalerContextEffects effects) {
725 fTypeface = typeface;
726 fEffects = effects;
727}
728
729void SkStrikeServer::RemoteStrike::writeGlyphPath(
730 const SkGlyph& glyph, Serializer* serializer) const {
731 if (glyph.isColor() || glyph.isEmpty()) {
732 serializer->write<uint64_t>(0u);
733 return;
734 }
735
736 const SkPath* path = glyph.path();
737
738 if (path == nullptr) {
739 serializer->write<uint64_t>(0u);
740 return;
741 }
742
743 size_t pathSize = path->writeToMemory(nullptr);
744 serializer->write<uint64_t>(pathSize);
745 path->writeToMemory(serializer->allocate(pathSize, kPathAlignment));
746}
747
748template <typename Rejector>
749void SkStrikeServer::RemoteStrike::commonMaskLoop(
750 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects, Rejector&& reject) {
751 drawables->forEachGlyphID(
752 [&](size_t i, SkPackedGlyphID packedID, SkPoint position) {
753 MaskSummary* summary = fSentGlyphs.find(packedID);
754 if (summary == nullptr) {
755 // Put the new SkGlyph in the glyphs to send.
756 fMasksToSend.emplace_back(packedID);
757 SkGlyph* glyph = &fMasksToSend.back();
758
759 // Build the glyph
760 this->ensureScalerContext();
761 fContext->getMetrics(glyph);
762 MaskSummary newSummary =
763 {packedID.value(), CanDrawAsMask(*glyph), CanDrawAsSDFT(*glyph)};
764 summary = fSentGlyphs.set(newSummary);
765 }
766
767 // Reject things that are too big.
768 if (reject(*summary)) {
769 rejects->reject(i);
770 }
771 });
772}
773
774void SkStrikeServer::RemoteStrike::prepareForMaskDrawing(
775 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
776 for (auto [i, variant, _] : SkMakeEnumerate(drawables->input())) {
777 SkPackedGlyphID packedID = variant.packedID();
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
814void SkStrikeServer::RemoteStrike::prepareForSDFTDrawing(
815 SkDrawableGlyphBuffer* drawables, SkSourceGlyphBuffer* rejects) {
816 this->commonMaskLoop(drawables, rejects,
817 [](MaskSummary summary){return !summary.canDrawAsSDFT;});
818}
819
820void 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 ----------------------------------------------------------------------------------
855class SkStrikeClient::DiscardableStrikePinner : public SkStrikePinner {
856public:
857 DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
858 sk_sp<DiscardableHandleManager> manager)
859 : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
860
861 ~DiscardableStrikePinner() override = default;
862 bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
863
864private:
865 const SkDiscardableHandleId fDiscardableHandleId;
866 sk_sp<DiscardableHandleManager> fManager;
867};
868
869SkStrikeClient::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
876SkStrikeClient::~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.
890bool 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
906bool 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
1012sk_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
1019sk_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