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