Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 {}
85 SkGlyphDigest digestFor(skglyph::ActionType, SkPackedGlyphID) 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,
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 -------------------------------------------------------------------------------
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
int count
#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)
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
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:503
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
void setAllowSkSL(bool allow)
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
std::unique_ptr< SkScalerContext > createScalerContext() const
const SkDescriptor & descriptor() const
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:479
V * set(K key, V val)
Definition SkTHash.h:472
void add(T item)
Definition SkTHash.h:573
bool contains(const T &item) const
Definition SkTHash.h:576
void foreach(Fn &&fn) const
Definition SkTHash.h:590
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
static SubRunContainerOwner MakeInAlloc(const GlyphRunList &glyphRunList, const SkMatrix &positionMatrix, const SkPaint &runPaint, SkStrikeDeviceInfo strikeDeviceInfo, StrikeForGPUCacheInterface *strikeCache, sktext::gpu::SubRunAllocator *alloc, SubRunCreationBehavior creationBehavior, const char *tag)
const Paint & paint
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
static const uint8_t buffer[]
AutoTArray< uint8_t > data((int) size)
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
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
sk_sp< SkColorSpace > refColorSpace() const
SkISize dimensions() const
constexpr float y() const
constexpr float x() const
SkTypefaceID fTypefaceID
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)