Flutter Engine
The Flutter Engine
SkChromeRemoteGlyphCache.cpp
Go to the documentation of this file.
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
9
12#include "include/core/SkData.h"
18#include "include/core/SkRect.h"
19#include "include/core/SkSize.h"
31#include "src/core/SkDevice.h"
33#include "src/core/SkGlyph.h"
36#include "src/core/SkStrike.h"
39#include "src/core/SkTHash.h"
43#include "src/text/GlyphRun.h"
49
50#include <cstring>
51#include <memory>
52#include <optional>
53#include <unordered_map>
54#include <utility>
55
56class SkPaint;
57
58using namespace skia_private;
59using namespace sktext;
60using namespace sktext::gpu;
61using namespace skglyph;
62
63namespace {
64
65// -- StrikeSpec -----------------------------------------------------------------------------------
66struct StrikeSpec {
67 StrikeSpec() = default;
68 StrikeSpec(SkTypefaceID typefaceID, SkDiscardableHandleId discardableHandleId)
69 : fTypefaceID{typefaceID}, fDiscardableHandleId(discardableHandleId) {}
70 SkTypefaceID fTypefaceID = 0u;
71 SkDiscardableHandleId fDiscardableHandleId = 0u;
72};
73
74// -- RemoteStrike ----------------------------------------------------------------------------
75class RemoteStrike final : public sktext::StrikeForGPU {
76public:
77 // N.B. RemoteStrike is not valid until ensureScalerContext is called.
78 RemoteStrike(const SkStrikeSpec& strikeSpec,
79 std::unique_ptr<SkScalerContext> context,
80 SkDiscardableHandleId discardableHandleId);
81 ~RemoteStrike() override = default;
82
83 void lock() override {}
84 void unlock() override {}
86 bool prepareForImage(SkGlyph* glyph) override {
87 this->ensureScalerContext();
88 glyph->setImage(&fAlloc, fContext.get());
89 return glyph->image() != nullptr;
90 }
91 bool prepareForPath(SkGlyph* glyph) override {
92 this->ensureScalerContext();
93 glyph->setPath(&fAlloc, fContext.get());
94 return glyph->path() != nullptr;
95 }
96 bool prepareForDrawable(SkGlyph* glyph) override {
97 this->ensureScalerContext();
98 glyph->setDrawable(&fAlloc, fContext.get());
99 return glyph->drawable() != nullptr;
100 }
101
102 void writePendingGlyphs(SkWriteBuffer& buffer);
103
104 SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
105
106 const SkDescriptor& getDescriptor() const override {
107 return *fDescriptor.getDesc();
108 }
109
110 void setStrikeSpec(const SkStrikeSpec& strikeSpec);
111
112 const SkGlyphPositionRoundingSpec& roundingSpec() const override {
113 return fRoundingSpec;
114 }
115
116 sktext::SkStrikePromise strikePromise() override;
117
118 bool hasPendingGlyphs() const {
119 return !fMasksToSend.empty() || !fPathsToSend.empty() || !fDrawablesToSend.empty();
120 }
121
122 void resetScalerContext();
123
124private:
125 void ensureScalerContext();
126
127 const SkAutoDescriptor fDescriptor;
128 const SkDiscardableHandleId fDiscardableHandleId;
129
130 const SkGlyphPositionRoundingSpec fRoundingSpec;
131
132 // The context built using fDescriptor
133 std::unique_ptr<SkScalerContext> fContext;
134
135 // fStrikeSpec is set every time getOrCreateCache is called. This allows the code to maintain
136 // the fContext as lazy as possible.
137 const SkStrikeSpec* fStrikeSpec;
138
139 // Have the metrics been sent for this strike. Only send them once.
140 bool fHaveSentFontMetrics{false};
141
142 // The masks and paths that currently reside in the GPU process.
144
145 // The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
146 // TextBlobs. Cleared after diffs are serialized.
147 std::vector<SkGlyph> fMasksToSend;
148 std::vector<SkGlyph> fPathsToSend;
149 std::vector<SkGlyph> fDrawablesToSend;
150
151 // Alloc for storing bits and pieces of paths and drawables, Cleared after diffs are serialized.
152 SkArenaAllocWithReset fAlloc{256};
153};
154
155RemoteStrike::RemoteStrike(
156 const SkStrikeSpec& strikeSpec,
157 std::unique_ptr<SkScalerContext> context,
158 uint32_t discardableHandleId)
159 : fDescriptor{strikeSpec.descriptor()}
160 , fDiscardableHandleId(discardableHandleId)
161 , fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()}
162 // N.B. context must come last because it is used above.
163 , fContext{std::move(context)} {
164 SkASSERT(fDescriptor.getDesc() != nullptr);
165 SkASSERT(fContext != nullptr);
166}
167
168void RemoteStrike::writePendingGlyphs(SkWriteBuffer& buffer) {
169 SkASSERT(this->hasPendingGlyphs());
170
171 buffer.writeUInt(fContext->getTypeface()->uniqueID());
172 buffer.writeUInt(fDiscardableHandleId);
173 fDescriptor.getDesc()->flatten(buffer);
174
175 buffer.writeBool(fHaveSentFontMetrics);
176 if (!fHaveSentFontMetrics) {
177 // Write FontMetrics if not sent before.
178 SkFontMetrics fontMetrics;
179 fContext->getFontMetrics(&fontMetrics);
181 fHaveSentFontMetrics = true;
182 }
183
184 // Make sure to install all the mask data into the glyphs before sending.
185 for (SkGlyph& glyph: fMasksToSend) {
186 this->prepareForImage(&glyph);
187 }
188
189 // Make sure to install all the path data into the glyphs before sending.
190 for (SkGlyph& glyph: fPathsToSend) {
191 this->prepareForPath(&glyph);
192 }
193
194 // Make sure to install all the drawable data into the glyphs before sending.
195 for (SkGlyph& glyph: fDrawablesToSend) {
196 this->prepareForDrawable(&glyph);
197 }
198
199 // Send all the pending glyph information.
200 SkStrike::FlattenGlyphsByType(buffer, fMasksToSend, fPathsToSend, fDrawablesToSend);
201
202 // Reset all the sending data.
203 fMasksToSend.clear();
204 fPathsToSend.clear();
205 fDrawablesToSend.clear();
206 fAlloc.reset();
207}
208
209void RemoteStrike::ensureScalerContext() {
210 if (fContext == nullptr) {
211 fContext = fStrikeSpec->createScalerContext();
212 }
213}
214
215void RemoteStrike::resetScalerContext() {
216 fContext = nullptr;
217 fStrikeSpec = nullptr;
218}
219
220void RemoteStrike::setStrikeSpec(const SkStrikeSpec& strikeSpec) {
221 fStrikeSpec = &strikeSpec;
222}
223
224SkGlyphDigest RemoteStrike::digestFor(ActionType actionType, SkPackedGlyphID packedGlyphID) {
225 SkGlyphDigest* digestPtr = fSentGlyphs.find(packedGlyphID);
226 if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
227 return *digestPtr;
228 }
229
230 SkGlyph* glyph;
231 this->ensureScalerContext();
232 switch (actionType) {
233 case skglyph::kPath: {
234 fPathsToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
235 glyph = &fPathsToSend.back();
236 break;
237 }
238 case skglyph::kDrawable: {
239 fDrawablesToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
240 glyph = &fDrawablesToSend.back();
241 break;
242 }
243 default: {
244 fMasksToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
245 glyph = &fMasksToSend.back();
246 break;
247 }
248 }
249
250 if (digestPtr == nullptr) {
251 digestPtr = fSentGlyphs.set(SkGlyphDigest{0, *glyph});
252 }
253
254 digestPtr->setActionFor(actionType, glyph, this);
255
256 return *digestPtr;
257}
258
259sktext::SkStrikePromise RemoteStrike::strikePromise() {
260 return sktext::SkStrikePromise{*this->fStrikeSpec};
261}
262} // namespace
263
264// -- SkStrikeServerImpl ---------------------------------------------------------------------------
266public:
267 explicit SkStrikeServerImpl(
268 SkStrikeServer::DiscardableHandleManager* discardableHandleManager);
269
270 // SkStrikeServer API methods
271 void writeStrikeData(std::vector<uint8_t>* memory);
272
274
275 // Methods for testing
277 size_t remoteStrikeMapSizeForTesting() const;
278
279private:
280 inline static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
281
282 void checkForDeletedEntries();
283
284 sk_sp<RemoteStrike> getOrCreateCache(const SkStrikeSpec& strikeSpec);
285
286 struct MapOps {
287 size_t operator()(const SkDescriptor* key) const {
288 return key->getChecksum();
289 }
290 bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
291 return *lhs == *rhs;
292 }
293 };
294
295 using DescToRemoteStrike =
296 std::unordered_map<const SkDescriptor*, sk_sp<RemoteStrike>, MapOps, MapOps>;
297 DescToRemoteStrike fDescToRemoteStrike;
298
299 SkStrikeServer::DiscardableHandleManager* const fDiscardableHandleManager;
300 THashSet<SkTypefaceID> fCachedTypefaces;
301 size_t fMaxEntriesInDescriptorMap = kMaxEntriesInDescriptorMap;
302
303 // State cached until the next serialization.
304 THashSet<RemoteStrike*> fRemoteStrikesToSend;
305 std::vector<SkTypefaceProxyPrototype> fTypefacesToSend;
306};
307
309 : fDiscardableHandleManager(dhm) {
310 SkASSERT(fDiscardableHandleManager);
311}
312
314 fMaxEntriesInDescriptorMap = count;
315}
317 return fDescToRemoteStrike.size();
318}
319
320void SkStrikeServerImpl::writeStrikeData(std::vector<uint8_t>* memory) {
321 // We can use the default SkSerialProcs because we do not currently need to encode any SkImages.
322 SkBinaryWriteBuffer buffer{nullptr, 0, {}};
323
324 // Gather statistics about what needs to be sent.
325 size_t strikesToSend = 0;
326 fRemoteStrikesToSend.foreach([&](RemoteStrike* strike) {
327 if (strike->hasPendingGlyphs()) {
328 strikesToSend++;
329 } else {
330 // This strike has nothing to send, so drop its scaler context to reduce memory.
331 strike->resetScalerContext();
332 }
333 });
334
335 // If there are no strikes or typefaces to send, then cleanup and return.
336 if (strikesToSend == 0 && fTypefacesToSend.empty()) {
337 fRemoteStrikesToSend.reset();
338 return;
339 }
340
341 // Send newly seen typefaces.
342 SkASSERT_RELEASE(SkTFitsIn<int>(fTypefacesToSend.size()));
343 buffer.writeInt(fTypefacesToSend.size());
344 for (const auto& typeface: fTypefacesToSend) {
345 SkTypefaceProxyPrototype proto{typeface};
346 proto.flatten(buffer);
347 }
348 fTypefacesToSend.clear();
349
350 buffer.writeInt(strikesToSend);
351 fRemoteStrikesToSend.foreach(
352 [&](RemoteStrike* strike) {
353 if (strike->hasPendingGlyphs()) {
354 strike->writePendingGlyphs(buffer);
355 strike->resetScalerContext();
356 }
357 }
358 );
359 fRemoteStrikesToSend.reset();
360
361 // Copy data into the vector.
362 auto data = buffer.snapshotAsData();
363 memory->assign(data->bytes(), data->bytes() + data->size());
364}
365
367 const SkStrikeSpec& strikeSpec) {
368 return this->getOrCreateCache(strikeSpec);
369}
370
371void SkStrikeServerImpl::checkForDeletedEntries() {
372 auto it = fDescToRemoteStrike.begin();
373 while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
374 it != fDescToRemoteStrike.end()) {
375 RemoteStrike* strike = it->second.get();
376 if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) {
377 // If we are trying to send the strike, then do not erase it.
378 if (!fRemoteStrikesToSend.contains(strike)) {
379 // Erase returns the iterator following the removed element.
380 it = fDescToRemoteStrike.erase(it);
381 continue;
382 }
383 }
384 ++it;
385 }
386}
387
388sk_sp<RemoteStrike> SkStrikeServerImpl::getOrCreateCache(const SkStrikeSpec& strikeSpec) {
389 // In cases where tracing is turned off, make sure not to get an unused function warning.
390 // Lambdaize the function.
391 TRACE_EVENT1("skia", "RecForDesc", "rec",
393 [&strikeSpec](){
394 auto ptr =
395 strikeSpec.descriptor().findEntry(kRec_SkDescriptorTag, nullptr);
397 std::memcpy((void*)&rec, ptr, sizeof(rec));
398 return rec.dump();
399 }().c_str()
400 )
401 );
402
403 if (auto it = fDescToRemoteStrike.find(&strikeSpec.descriptor());
404 it != fDescToRemoteStrike.end())
405 {
406 // We have processed the RemoteStrike before. Reuse it.
407 sk_sp<RemoteStrike> strike = it->second;
408 strike->setStrikeSpec(strikeSpec);
409 if (fRemoteStrikesToSend.contains(strike.get())) {
410 // Already tracking
411 return strike;
412 }
413
414 // Strike is in unknown state on GPU. Start tracking strike on GPU by locking it.
415 bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
416 if (locked) {
417 fRemoteStrikesToSend.add(strike.get());
418 return strike;
419 }
420
421 // If it wasn't locked, then forget this strike, and build it anew below.
422 fDescToRemoteStrike.erase(it);
423 }
424
425 const SkTypeface& typeface = strikeSpec.typeface();
426 // Create a new RemoteStrike. Start by processing the typeface.
427 const SkTypefaceID typefaceId = typeface.uniqueID();
428 if (!fCachedTypefaces.contains(typefaceId)) {
429 fCachedTypefaces.add(typefaceId);
430 fTypefacesToSend.emplace_back(typeface);
431 }
432
433 auto context = strikeSpec.createScalerContext();
434 auto newHandle = fDiscardableHandleManager->createHandle(); // Locked on creation
435 auto remoteStrike = sk_make_sp<RemoteStrike>(strikeSpec, std::move(context), newHandle);
436 remoteStrike->setStrikeSpec(strikeSpec);
437 fRemoteStrikesToSend.add(remoteStrike.get());
438 auto d = &remoteStrike->getDescriptor();
439 fDescToRemoteStrike[d] = remoteStrike;
440
441 checkForDeletedEntries();
442
443 return remoteStrike;
444}
445
446// -- GlyphTrackingDevice --------------------------------------------------------------------------
448public:
450 const SkISize& dimensions, const SkSurfaceProps& props, SkStrikeServerImpl* server,
452 : SkNoPixelsDevice(SkIRect::MakeSize(dimensions), props, std::move(colorSpace))
453 , fStrikeServerImpl(server)
454 , fSDFTControl(SDFTControl) {
455 SkASSERT(fStrikeServerImpl != nullptr);
456 }
457
458 sk_sp<SkDevice> createDevice(const CreateInfo& cinfo, const SkPaint*) override {
461
462 return sk_make_sp<GlyphTrackingDevice>(cinfo.fInfo.dimensions(),
464 fStrikeServerImpl,
465 cinfo.fInfo.refColorSpace(),
466 fSDFTControl);
467 }
468
470 return {this->surfaceProps(), this->scalerContextFlags(), &fSDFTControl};
471 }
472
473protected:
475 const sktext::GlyphRunList& glyphRunList,
476 const SkPaint& paint) override {
477 SkMatrix drawMatrix = this->localToDevice();
478 drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
479
480 // Just ignore the resulting SubRunContainer. Since we're passing in a null SubRunAllocator
481 // no SubRuns will be produced.
482 STSubRunAllocator<sizeof(SubRunContainer), alignof(SubRunContainer)> tempAlloc;
483 auto container = SubRunContainer::MakeInAlloc(glyphRunList,
484 drawMatrix,
485 paint,
486 this->strikeDeviceInfo(),
487 fStrikeServerImpl,
488 &tempAlloc,
489 SubRunContainer::kStrikeCalculationsOnly,
490 "Cache Diff");
491 // Calculations only. No SubRuns.
492 SkASSERT(container->isEmpty());
493 }
494
496 const SkPaint& paint) override {
497 // Full matrix for placing glyphs.
498 SkMatrix positionMatrix = this->localToDevice();
499 positionMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
500
501 // Use the SkStrikeServer's strike cache to generate the Slug.
503 glyphRunList,
504 paint,
505 this->strikeDeviceInfo(),
506 fStrikeServerImpl);
507 }
508
509private:
510 SkStrikeServerImpl* const fStrikeServerImpl;
511 const sktext::gpu::SDFTControl fSDFTControl;
512};
513
514// -- SkStrikeServer -------------------------------------------------------------------------------
516 : fImpl(new SkStrikeServerImpl{dhm}) { }
517
519
520std::unique_ptr<SkCanvas> SkStrikeServer::makeAnalysisCanvas(int width, int height,
521 const SkSurfaceProps& props,
522 sk_sp<SkColorSpace> colorSpace,
523 bool DFTSupport,
524 bool DFTPerspSupport) {
525#if !defined(SK_DISABLE_SDF_TEXT)
526 // These are copied from the defaults in GrContextOptions for historical reasons.
527 // TODO(herb, jvanverth) pipe in parameters that can be used for both Ganesh and Graphite
528 // backends instead of just using the defaults.
529 constexpr float kMinDistanceFieldFontSize = 18.f;
530
531#if defined(SK_BUILD_FOR_ANDROID)
532 constexpr float kGlyphsAsPathsFontSize = 384.f;
533#elif defined(SK_BUILD_FOR_MAC)
534 constexpr float kGlyphsAsPathsFontSize = 256.f;
535#else
536 constexpr float kGlyphsAsPathsFontSize = 324.f;
537#endif
538 auto control = sktext::gpu::SDFTControl{DFTSupport,
540 DFTPerspSupport,
541 kMinDistanceFieldFontSize,
542 kGlyphsAsPathsFontSize};
543#else
544 auto control = sktext::gpu::SDFTControl{};
545#endif
546
547 sk_sp<SkDevice> trackingDevice = sk_make_sp<GlyphTrackingDevice>(
549 props, this->impl(),
550 std::move(colorSpace),
551 control);
552 return std::make_unique<SkCanvas>(std::move(trackingDevice));
553}
554
555void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
556 fImpl->writeStrikeData(memory);
557}
558
559SkStrikeServerImpl* SkStrikeServer::impl() { return fImpl.get(); }
560
562 fImpl->setMaxEntriesInDescriptorMapForTesting(count);
563}
565 return fImpl->remoteStrikeMapSizeForTesting();
566}
567
568// -- DiscardableStrikePinner ----------------------------------------------------------------------
570public:
573 : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
574
575 ~DiscardableStrikePinner() override = default;
576 bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
577 void assertValid() override { fManager->assertHandleValid(fDiscardableHandleId); }
578
579private:
580 const SkDiscardableHandleId fDiscardableHandleId;
582};
583
584// -- SkStrikeClientImpl ---------------------------------------------------------------------------
586public:
588 bool isLogging = true,
589 SkStrikeCache* strikeCache = nullptr);
590
591 bool readStrikeData(const volatile void* memory, size_t memorySize);
592 bool translateTypefaceID(SkAutoDescriptor* descriptor) const;
594
595private:
596 class PictureBackedGlyphDrawable final : public SkDrawable {
597 public:
598 PictureBackedGlyphDrawable(sk_sp<SkPicture> self) : fSelf(std::move(self)) {}
599 private:
600 sk_sp<SkPicture> fSelf;
601 SkRect onGetBounds() override { return fSelf->cullRect(); }
602 size_t onApproximateBytesUsed() override {
603 return sizeof(PictureBackedGlyphDrawable) + fSelf->approximateBytesUsed();
604 }
605 void onDraw(SkCanvas* canvas) override { canvas->drawPicture(fSelf); }
606 };
607
608 sk_sp<SkTypeface> addTypeface(const SkTypefaceProxyPrototype& typefaceProto);
609
610 THashMap<SkTypefaceID, sk_sp<SkTypeface>> fServerTypefaceIdToTypeface;
611 sk_sp<SkStrikeClient::DiscardableHandleManager> fDiscardableHandleManager;
612 SkStrikeCache* const fStrikeCache;
613 const bool fIsLogging;
614};
615
618 discardableManager,
619 bool isLogging,
620 SkStrikeCache* strikeCache)
621 : fDiscardableHandleManager(std::move(discardableManager)),
622 fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()},
623 fIsLogging{isLogging} {}
624
625// Change the path count to track the line number of the failing read.
626// TODO: change __LINE__ back to glyphPathsCount when bug chromium:1287356 is closed.
627#define READ_FAILURE \
628 { \
629 SkDebugf("Bad font data serialization line: %d", __LINE__); \
630 SkStrikeClient::DiscardableHandleManager::ReadFailureData data = { \
631 memorySize, deserializer.bytesRead(), typefaceSize, \
632 strikeCount, glyphImagesCount, __LINE__}; \
633 fDiscardableHandleManager->notifyReadFailure(data); \
634 return false; \
635 }
636
637bool SkStrikeClientImpl::readStrikeData(const volatile void* memory, size_t memorySize) {
638 SkASSERT(memorySize != 0);
639 SkASSERT(memory != nullptr);
640
641 // We do not need to set any SkDeserialProcs here because SkStrikeServerImpl::writeStrikeData
642 // did not encode any SkImages.
643 SkReadBuffer buffer{const_cast<const void*>(memory), memorySize};
644 // Limit the kinds of effects that appear in a glyph's drawable (crbug.com/1442140):
645 buffer.setAllowSkSL(false);
646
647 int curTypeface = 0,
648 curStrike = 0;
649
650 auto postError = [&](int line) {
651 SkDebugf("Read Error Posted %s : %d", __FILE__, line);
653 memorySize,
654 buffer.offset(),
655 SkTo<uint64_t>(curTypeface),
656 SkTo<uint64_t>(curStrike),
657 SkTo<uint64_t>(0),
658 SkTo<uint64_t>(0)};
659 fDiscardableHandleManager->notifyReadFailure(data);
660 };
661
662 // Read the number of typefaces sent.
663 const int typefaceCount = buffer.readInt();
664 for (curTypeface = 0; curTypeface < typefaceCount; ++curTypeface) {
666 if (proto) {
667 this->addTypeface(proto.value());
668 } else {
669 postError(__LINE__);
670 return false;
671 }
672 }
673
674 // Read the number of strikes sent.
675 const int stirkeCount = buffer.readInt();
676 for (curStrike = 0; curStrike < stirkeCount; ++curStrike) {
677
678 const SkTypefaceID serverTypefaceID = buffer.readUInt();
679 if (serverTypefaceID == 0 && !buffer.isValid()) {
680 postError(__LINE__);
681 return false;
682 }
683
684 const SkDiscardableHandleId discardableHandleID = buffer.readUInt();
685 if (discardableHandleID == 0 && !buffer.isValid()) {
686 postError(__LINE__);
687 return false;
688 }
689
690 std::optional<SkAutoDescriptor> serverDescriptor = SkAutoDescriptor::MakeFromBuffer(buffer);
691 if (!buffer.validate(serverDescriptor.has_value())) {
692 postError(__LINE__);
693 return false;
694 }
695
696 const bool fontMetricsInitialized = buffer.readBool();
697 if (!fontMetricsInitialized && !buffer.isValid()) {
698 postError(__LINE__);
699 return false;
700 }
701
702 std::optional<SkFontMetrics> fontMetrics;
703 if (!fontMetricsInitialized) {
705 if (!fontMetrics || !buffer.isValid()) {
706 postError(__LINE__);
707 return false;
708 }
709 }
710
711 auto* clientTypeface = fServerTypefaceIdToTypeface.find(serverTypefaceID);
712 if (clientTypeface == nullptr) {
713 postError(__LINE__);
714 return false;
715 }
716
717 if (!this->translateTypefaceID(&serverDescriptor.value())) {
718 postError(__LINE__);
719 return false;
720 }
721
722 SkDescriptor* clientDescriptor = serverDescriptor->getDesc();
723 auto strike = fStrikeCache->findStrike(*clientDescriptor);
724
725 if (strike == nullptr) {
726 // Metrics are only sent the first time. If creating a new strike, then the metrics
727 // are not initialized.
728 if (fontMetricsInitialized) {
729 postError(__LINE__);
730 return false;
731 }
732 SkStrikeSpec strikeSpec{*clientDescriptor, *clientTypeface};
733 strike = fStrikeCache->createStrike(
734 strikeSpec, &fontMetrics.value(),
735 std::make_unique<DiscardableStrikePinner>(
736 discardableHandleID, fDiscardableHandleManager));
737 }
738
739 // Make sure this strike is pinned on the GPU side.
740 strike->verifyPinnedStrike();
741
742 if (!strike->mergeFromBuffer(buffer)) {
743 postError(__LINE__);
744 return false;
745 }
746 }
747
748 return true;
749}
750
752 SkDescriptor& descriptor = *toChange->getDesc();
753
754 // Rewrite the typefaceID in the rec.
755 {
756 uint32_t size;
757 // findEntry returns a const void*, remove the const in order to update in place.
758 void* ptr = const_cast<void *>(descriptor.findEntry(kRec_SkDescriptorTag, &size));
760 if (!ptr || size != sizeof(rec)) { return false; }
761 std::memcpy((void*)&rec, ptr, size);
762 // Get the local typeface from remote typefaceID.
763 auto* tfPtr = fServerTypefaceIdToTypeface.find(rec.fTypefaceID);
764 // Received a strike for a typeface which doesn't exist.
765 if (!tfPtr) { return false; }
766 // Update the typeface id to work with the client side.
767 rec.fTypefaceID = tfPtr->get()->uniqueID();
768 std::memcpy(ptr, &rec, size);
769 }
770
771 descriptor.computeChecksum();
772
773 return true;
774}
775
777 auto* tfPtr = fServerTypefaceIdToTypeface.find(typefaceID);
778 return tfPtr != nullptr ? *tfPtr : nullptr;
779}
780
781sk_sp<SkTypeface> SkStrikeClientImpl::addTypeface(const SkTypefaceProxyPrototype& typefaceProto) {
782 sk_sp<SkTypeface>* typeface =
783 fServerTypefaceIdToTypeface.find(typefaceProto.serverTypefaceID());
784
785 // We already have the typeface.
786 if (typeface != nullptr) {
787 return *typeface;
788 }
789
790 auto newTypeface = sk_make_sp<SkTypefaceProxy>(
791 typefaceProto, fDiscardableHandleManager, fIsLogging);
792 fServerTypefaceIdToTypeface.set(typefaceProto.serverTypefaceID(), newTypeface);
793 return newTypeface;
794}
795
796// SkStrikeClient ----------------------------------------------------------------------------------
798 bool isLogging,
799 SkStrikeCache* strikeCache)
800 : fImpl{new SkStrikeClientImpl{std::move(discardableManager), isLogging, strikeCache}} {}
801
803
804bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
805 return fImpl->readStrikeData(memory, memorySize);
806}
807
809 SkTypefaceID typefaceID) const {
810 return fImpl->retrieveTypefaceUsingServerID(typefaceID);
811}
812
814 return fImpl->translateTypefaceID(descriptor);
815}
816
818 size_t size) const {
820}
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkDiscardableHandleId
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
const Context & fContext
#define kRec_SkDescriptorTag
#define TRACE_STR_COPY(str)
Definition: SkTraceEvent.h:63
uint32_t SkTypefaceID
Definition: SkTypeface.h:38
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId, sk_sp< SkStrikeClient::DiscardableHandleManager > manager)
~DiscardableStrikePinner() override=default
sk_sp< SkDevice > createDevice(const CreateInfo &cinfo, const SkPaint *) override
sk_sp< sktext::gpu::Slug > convertGlyphRunListToSlug(const sktext::GlyphRunList &glyphRunList, const SkPaint &paint) override
SkStrikeDeviceInfo strikeDeviceInfo() const override
GlyphTrackingDevice(const SkISize &dimensions, const SkSurfaceProps &props, SkStrikeServerImpl *server, sk_sp< SkColorSpace > colorSpace, sktext::gpu::SDFTControl SDFTControl)
void onDrawGlyphRunList(SkCanvas *, const sktext::GlyphRunList &glyphRunList, const SkPaint &paint) override
SkDescriptor * getDesc() const
Definition: SkDescriptor.h:103
static std::optional< SkAutoDescriptor > MakeFromBuffer(SkReadBuffer &buffer)
void drawPicture(const SkPicture *picture)
Definition: SkCanvas.h:1961
void computeChecksum()
const void * findEntry(uint32_t tag, uint32_t *length) const
SkScalerContextFlags scalerContextFlags() const
Definition: SkDevice.cpp:498
const SkMatrix & localToDevice() const
Definition: SkDevice.h:179
const SkSurfaceProps & surfaceProps() const
Definition: SkDevice.h:131
static void Flatten(SkWriteBuffer &buffer, const SkFontMetrics &metrics)
static std::optional< SkFontMetrics > MakeFromBuffer(SkReadBuffer &buffer)
void setActionFor(skglyph::ActionType, SkGlyph *, sktext::StrikeForGPU *)
Definition: SkGlyph.cpp:634
skglyph::GlyphAction actionFor(skglyph::ActionType actionType) const
Definition: SkGlyph.h:343
const SkPath * path() const
Definition: SkGlyph.cpp:284
bool setDrawable(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:310
bool setPath(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:266
bool setImage(SkArenaAlloc *alloc, SkScalerContext *scalerContext)
Definition: SkGlyph.cpp:185
SkDrawable * drawable() const
Definition: SkGlyph.cpp:327
const void * image() const
Definition: SkGlyph.h:465
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:263
virtual SkRect cullRect() const =0
virtual size_t approximateBytesUsed() const =0
sk_sp< SkStrike > createStrike(const SkStrikeSpec &strikeSpec, SkFontMetrics *maybeMetrics=nullptr, std::unique_ptr< SkStrikePinner >=nullptr) SK_EXCLUDES(fLock)
sk_sp< SkStrike > findStrike(const SkDescriptor &desc) SK_EXCLUDES(fLock)
bool translateTypefaceID(SkAutoDescriptor *descriptor) const
bool readStrikeData(const volatile void *memory, size_t memorySize)
SkStrikeClientImpl(sk_sp< SkStrikeClient::DiscardableHandleManager >, bool isLogging=true, SkStrikeCache *strikeCache=nullptr)
sk_sp< SkTypeface > retrieveTypefaceUsingServerID(SkTypefaceID) const
virtual void assertHandleValid(SkDiscardableHandleId)
virtual bool deleteHandle(SkDiscardableHandleId)=0
virtual void notifyReadFailure(const ReadFailureData &data)
SK_SPI bool readStrikeData(const volatile void *memory, size_t memorySize)
sk_sp< SkTypeface > retrieveTypefaceUsingServerIDForTest(SkTypefaceID) const
sk_sp< sktext::gpu::Slug > deserializeSlugForTest(const void *data, size_t size) const
SK_SPI ~SkStrikeClient()
SK_SPI SkStrikeClient(sk_sp< DiscardableHandleManager >, bool isLogging=true, SkStrikeCache *strikeCache=nullptr)
SK_SPI bool translateTypefaceID(SkAutoDescriptor *descriptor) const
SkStrikeServerImpl(SkStrikeServer::DiscardableHandleManager *discardableHandleManager)
sk_sp< sktext::StrikeForGPU > findOrCreateScopedStrike(const SkStrikeSpec &strikeSpec) override
size_t remoteStrikeMapSizeForTesting() const
void setMaxEntriesInDescriptorMapForTesting(size_t count)
void writeStrikeData(std::vector< uint8_t > *memory)
virtual SK_SPI bool lockHandle(SkDiscardableHandleId)=0
virtual SK_SPI SkDiscardableHandleId createHandle()=0
virtual SK_SPI bool isHandleDeleted(SkDiscardableHandleId)=0
SK_SPI ~SkStrikeServer()
void setMaxEntriesInDescriptorMapForTesting(size_t count)
SK_SPI SkStrikeServer(DiscardableHandleManager *discardableHandleManager)
SK_SPI void writeStrikeData(std::vector< uint8_t > *memory)
SK_API std::unique_ptr< SkCanvas > makeAnalysisCanvas(int width, int height, const SkSurfaceProps &props, sk_sp< SkColorSpace > colorSpace, bool DFTSupport, bool DFTPerspSupport=true)
size_t remoteStrikeMapSizeForTesting() const
const SkTypeface & typeface() const
Definition: SkStrikeSpec.h:97
std::unique_ptr< SkScalerContext > createScalerContext() const
Definition: SkStrikeSpec.h:91
const SkDescriptor & descriptor() const
Definition: SkStrikeSpec.h:96
static void FlattenGlyphsByType(SkWriteBuffer &buffer, SkSpan< SkGlyph > images, SkSpan< SkGlyph > paths, SkSpan< SkGlyph > drawables)
Definition: SkStrike.cpp:87
SkSurfaceProps cloneWithPixelGeometry(SkPixelGeometry newPixelGeometry) const
bool isUseDeviceIndependentFonts() const
void flatten(SkWriteBuffer &buffer) const
static std::optional< SkTypefaceProxyPrototype > MakeFromBuffer(SkReadBuffer &buffer)
SkTypefaceID serverTypefaceID() const
SkTypefaceID uniqueID() const
Definition: SkTypeface.h:101
T * get() const
Definition: SkRefCnt.h:303
V * find(const K &key) const
Definition: SkTHash.h:494
V * set(K key, V val)
Definition: SkTHash.h:487
void add(T item)
Definition: SkTHash.h:592
bool contains(const T &item) const
Definition: SkTHash.h:595
void foreach(Fn &&fn) const
Definition: SkTHash.h:609
SkPoint origin() const
Definition: GlyphRun.h:114
static sk_sp< Slug > Deserialize(const void *data, size_t size, const SkStrikeClient *client=nullptr)
Definition: Slug.cpp:42
const Paint & paint
Definition: color_source.cc:38
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition: switches.h:218
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
ActionType
Definition: SkGlyph.h:312
@ kPath
Definition: SkGlyph.h:317
@ kDrawable
Definition: SkGlyph.h:318
sk_sp< Slug > MakeSlug(const SkMatrix &drawMatrix, const sktext::GlyphRunList &glyphRunList, const SkPaint &paint, SkStrikeDeviceInfo strikeDeviceInfo, sktext::StrikeForGPUCacheInterface *strikeCache)
Definition: TextBlob.cpp:255
Definition: ref_ptr.h:256
int32_t height
int32_t width
const SkPixelGeometry fPixelGeometry
Definition: SkDevice.h:307
const SkImageInfo fInfo
Definition: SkDevice.h:306
Definition: SkRect.h:32
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
sk_sp< SkColorSpace > refColorSpace() const
SkISize dimensions() const
Definition: SkImageInfo.h:421
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
SkTypefaceID fTypefaceID
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:141