xref: /aosp_15_r20/external/skia/src/text/gpu/SkChromeRemoteGlyphCache.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/private/chromium/SkChromeRemoteGlyphCache.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkDrawable.h"
14 #include "include/core/SkFontMetrics.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPicture.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "include/core/SkSurfaceProps.h"
22 #include "include/core/SkTypeface.h"
23 #include "include/private/base/SkAssert.h"
24 #include "include/private/base/SkDebug.h"
25 #include "include/private/base/SkPoint_impl.h"
26 #include "include/private/base/SkTFitsIn.h"
27 #include "include/private/base/SkTo.h"
28 #include "include/private/chromium/Slug.h"
29 #include "src/base/SkArenaAlloc.h"
30 #include "src/core/SkDescriptor.h"
31 #include "src/core/SkDevice.h"
32 #include "src/core/SkFontMetricsPriv.h"
33 #include "src/core/SkGlyph.h"
34 #include "src/core/SkReadBuffer.h"
35 #include "src/core/SkScalerContext.h"
36 #include "src/core/SkStrike.h"
37 #include "src/core/SkStrikeCache.h"
38 #include "src/core/SkStrikeSpec.h"
39 #include "src/core/SkTHash.h"
40 #include "src/core/SkTraceEvent.h"
41 #include "src/core/SkTypeface_remote.h"
42 #include "src/core/SkWriteBuffer.h"
43 #include "src/text/GlyphRun.h"
44 #include "src/text/StrikeForGPU.h"
45 #include "src/text/gpu/SubRunAllocator.h"
46 #include "src/text/gpu/SubRunContainer.h"
47 #include "src/text/gpu/SubRunControl.h"
48 #include "src/text/gpu/TextBlob.h"
49 
50 #include <cstring>
51 #include <memory>
52 #include <optional>
53 #include <unordered_map>
54 #include <utility>
55 
56 class SkPaint;
57 
58 using namespace skia_private;
59 using namespace sktext;
60 using namespace sktext::gpu;
61 using namespace skglyph;
62 
63 namespace {
64 
65 // -- StrikeSpec -----------------------------------------------------------------------------------
66 struct StrikeSpec {
67     StrikeSpec() = default;
StrikeSpec__anond12534150111::StrikeSpec68     StrikeSpec(SkTypefaceID typefaceID, SkDiscardableHandleId discardableHandleId)
69             : fTypefaceID{typefaceID}, fDiscardableHandleId(discardableHandleId) {}
70     SkTypefaceID fTypefaceID = 0u;
71     SkDiscardableHandleId fDiscardableHandleId = 0u;
72 };
73 
74 // -- RemoteStrike ----------------------------------------------------------------------------
75 class RemoteStrike final : public sktext::StrikeForGPU {
76 public:
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 
lock()83     void lock() override {}
unlock()84     void unlock() override {}
85     SkGlyphDigest digestFor(skglyph::ActionType, SkPackedGlyphID) override;
prepareForImage(SkGlyph * glyph)86     bool prepareForImage(SkGlyph* glyph) override {
87         this->ensureScalerContext();
88         glyph->setImage(&fAlloc, fContext.get());
89         return glyph->image() != nullptr;
90     }
prepareForPath(SkGlyph * glyph)91     bool prepareForPath(SkGlyph* glyph) override {
92         this->ensureScalerContext();
93         glyph->setPath(&fAlloc, fContext.get());
94         return glyph->path() != nullptr;
95     }
prepareForDrawable(SkGlyph * glyph)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 
discardableHandleId() const104     SkDiscardableHandleId discardableHandleId() const { return fDiscardableHandleId; }
105 
getDescriptor() const106     const SkDescriptor& getDescriptor() const override {
107         return *fDescriptor.getDesc();
108     }
109 
110     void setStrikeSpec(const SkStrikeSpec& strikeSpec);
111 
roundingSpec() const112     const SkGlyphPositionRoundingSpec& roundingSpec() const override {
113         return fRoundingSpec;
114     }
115 
116     sktext::SkStrikePromise strikePromise() override;
117 
hasPendingGlyphs() const118     bool hasPendingGlyphs() const {
119         return !fMasksToSend.empty() || !fPathsToSend.empty() || !fDrawablesToSend.empty();
120     }
121 
122     void resetScalerContext();
123 
124 private:
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     SkTypefaceID fStrikeSpecTypefaceId;
135 
136     // fStrikeSpec is set every time getOrCreateCache is called. This allows the code to maintain
137     // the fContext as lazy as possible.
138     const SkStrikeSpec* fStrikeSpec;
139 
140     // Have the metrics been sent for this strike. Only send them once.
141     bool fHaveSentFontMetrics{false};
142 
143     // The masks and paths that currently reside in the GPU process.
144     THashTable<SkGlyphDigest, SkPackedGlyphID, SkGlyphDigest> fSentGlyphs;
145 
146     // The Masks, SDFT Mask, and Paths that need to be sent to the GPU task for the processed
147     // TextBlobs. Cleared after diffs are serialized.
148     std::vector<SkGlyph> fMasksToSend;
149     std::vector<SkGlyph> fPathsToSend;
150     std::vector<SkGlyph> fDrawablesToSend;
151 
152     // Alloc for storing bits and pieces of paths and drawables, Cleared after diffs are serialized.
153     SkArenaAllocWithReset fAlloc{256};
154 };
155 
RemoteStrike(const SkStrikeSpec & strikeSpec,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)156 RemoteStrike::RemoteStrike(
157         const SkStrikeSpec& strikeSpec,
158         std::unique_ptr<SkScalerContext> context,
159         uint32_t discardableHandleId)
160         : fDescriptor{strikeSpec.descriptor()}
161         , fDiscardableHandleId(discardableHandleId)
162         , fRoundingSpec{context->isSubpixel(), context->computeAxisAlignmentForHText()}
163         // N.B. context must come last because it is used above.
164         , fContext{std::move(context)}
165         , fStrikeSpecTypefaceId(strikeSpec.typeface().uniqueID()) {
166     SkASSERT(fDescriptor.getDesc() != nullptr);
167     SkASSERT(fContext != nullptr);
168 }
169 
writePendingGlyphs(SkWriteBuffer & buffer)170 void RemoteStrike::writePendingGlyphs(SkWriteBuffer& buffer) {
171     SkASSERT(this->hasPendingGlyphs());
172 
173     // ScalerContext should not hold to the typeface, so we should not use its ID.
174     // We should use StrikeSpec typeface and its ID instead.
175     buffer.writeUInt(fStrikeSpecTypefaceId);
176     buffer.writeUInt(fDiscardableHandleId);
177     fDescriptor.getDesc()->flatten(buffer);
178 
179     buffer.writeBool(fHaveSentFontMetrics);
180     if (!fHaveSentFontMetrics) {
181         // Write FontMetrics if not sent before.
182         SkFontMetrics fontMetrics;
183         fContext->getFontMetrics(&fontMetrics);
184         SkFontMetricsPriv::Flatten(buffer, fontMetrics);
185         fHaveSentFontMetrics = true;
186     }
187 
188     // Make sure to install all the mask data into the glyphs before sending.
189     for (SkGlyph& glyph: fMasksToSend) {
190         this->prepareForImage(&glyph);
191     }
192 
193     // Make sure to install all the path data into the glyphs before sending.
194     for (SkGlyph& glyph: fPathsToSend) {
195         this->prepareForPath(&glyph);
196     }
197 
198     // Make sure to install all the drawable data into the glyphs before sending.
199     for (SkGlyph& glyph: fDrawablesToSend) {
200         this->prepareForDrawable(&glyph);
201     }
202 
203     // Send all the pending glyph information.
204     SkStrike::FlattenGlyphsByType(buffer, fMasksToSend, fPathsToSend, fDrawablesToSend);
205 
206     // Reset all the sending data.
207     fMasksToSend.clear();
208     fPathsToSend.clear();
209     fDrawablesToSend.clear();
210     fAlloc.reset();
211 }
212 
ensureScalerContext()213 void RemoteStrike::ensureScalerContext() {
214     if (fContext == nullptr) {
215         fContext = fStrikeSpec->createScalerContext();
216     }
217 }
218 
resetScalerContext()219 void RemoteStrike::resetScalerContext() {
220     fContext = nullptr;
221     fStrikeSpec = nullptr;
222 }
223 
setStrikeSpec(const SkStrikeSpec & strikeSpec)224 void RemoteStrike::setStrikeSpec(const SkStrikeSpec& strikeSpec) {
225     fStrikeSpec = &strikeSpec;
226 }
227 
digestFor(ActionType actionType,SkPackedGlyphID packedGlyphID)228 SkGlyphDigest RemoteStrike::digestFor(ActionType actionType, SkPackedGlyphID packedGlyphID) {
229     SkGlyphDigest* digestPtr = fSentGlyphs.find(packedGlyphID);
230     if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
231         return *digestPtr;
232     }
233 
234     SkGlyph* glyph;
235     this->ensureScalerContext();
236     switch (actionType) {
237         case skglyph::kPath: {
238             fPathsToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
239             glyph = &fPathsToSend.back();
240             break;
241         }
242         case skglyph::kDrawable: {
243             fDrawablesToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
244             glyph = &fDrawablesToSend.back();
245             break;
246         }
247         default: {
248             fMasksToSend.emplace_back(fContext->makeGlyph(packedGlyphID, &fAlloc));
249             glyph = &fMasksToSend.back();
250             break;
251         }
252     }
253 
254     if (digestPtr == nullptr) {
255         digestPtr = fSentGlyphs.set(SkGlyphDigest{0, *glyph});
256     }
257 
258     digestPtr->setActionFor(actionType, glyph, this);
259 
260     return *digestPtr;
261 }
262 
strikePromise()263 sktext::SkStrikePromise RemoteStrike::strikePromise() {
264     return sktext::SkStrikePromise{*this->fStrikeSpec};
265 }
266 }  // namespace
267 
268 // -- SkStrikeServerImpl ---------------------------------------------------------------------------
269 class SkStrikeServerImpl final : public sktext::StrikeForGPUCacheInterface {
270 public:
271     explicit SkStrikeServerImpl(
272             SkStrikeServer::DiscardableHandleManager* discardableHandleManager);
273 
274     // SkStrikeServer API methods
275     void writeStrikeData(std::vector<uint8_t>* memory);
276 
277     sk_sp<sktext::StrikeForGPU> findOrCreateScopedStrike(const SkStrikeSpec& strikeSpec) override;
278 
279     // Methods for testing
280     void setMaxEntriesInDescriptorMapForTesting(size_t count);
281     size_t remoteStrikeMapSizeForTesting() const;
282 
283 private:
284     inline static constexpr size_t kMaxEntriesInDescriptorMap = 2000u;
285 
286     void checkForDeletedEntries();
287 
288     sk_sp<RemoteStrike> getOrCreateCache(const SkStrikeSpec& strikeSpec);
289 
290     struct MapOps {
operator ()SkStrikeServerImpl::MapOps291         size_t operator()(const SkDescriptor* key) const {
292             return key->getChecksum();
293         }
operator ()SkStrikeServerImpl::MapOps294         bool operator()(const SkDescriptor* lhs, const SkDescriptor* rhs) const {
295             return *lhs == *rhs;
296         }
297     };
298 
299     using DescToRemoteStrike =
300         std::unordered_map<const SkDescriptor*, sk_sp<RemoteStrike>, MapOps, MapOps>;
301     DescToRemoteStrike fDescToRemoteStrike;
302 
303     SkStrikeServer::DiscardableHandleManager* const fDiscardableHandleManager;
304     THashSet<SkTypefaceID> fCachedTypefaces;
305     size_t fMaxEntriesInDescriptorMap = kMaxEntriesInDescriptorMap;
306 
307     // State cached until the next serialization.
308     THashSet<RemoteStrike*> fRemoteStrikesToSend;
309     std::vector<SkTypefaceProxyPrototype> fTypefacesToSend;
310 };
311 
SkStrikeServerImpl(SkStrikeServer::DiscardableHandleManager * dhm)312 SkStrikeServerImpl::SkStrikeServerImpl(SkStrikeServer::DiscardableHandleManager* dhm)
313         : fDiscardableHandleManager(dhm) {
314     SkASSERT(fDiscardableHandleManager);
315 }
316 
setMaxEntriesInDescriptorMapForTesting(size_t count)317 void SkStrikeServerImpl::setMaxEntriesInDescriptorMapForTesting(size_t count) {
318     fMaxEntriesInDescriptorMap = count;
319 }
remoteStrikeMapSizeForTesting() const320 size_t SkStrikeServerImpl::remoteStrikeMapSizeForTesting() const {
321     return fDescToRemoteStrike.size();
322 }
323 
writeStrikeData(std::vector<uint8_t> * memory)324 void SkStrikeServerImpl::writeStrikeData(std::vector<uint8_t>* memory) {
325     // We can use the default SkSerialProcs because we do not currently need to encode any SkImages.
326     SkBinaryWriteBuffer buffer{nullptr, 0, {}};
327 
328     // Gather statistics about what needs to be sent.
329     size_t strikesToSend = 0;
330     fRemoteStrikesToSend.foreach([&](RemoteStrike* strike) {
331         if (strike->hasPendingGlyphs()) {
332             strikesToSend++;
333         } else {
334             // This strike has nothing to send, so drop its scaler context to reduce memory.
335             strike->resetScalerContext();
336         }
337     });
338 
339     // If there are no strikes or typefaces to send, then cleanup and return.
340     if (strikesToSend == 0 && fTypefacesToSend.empty()) {
341         fRemoteStrikesToSend.reset();
342         return;
343     }
344 
345     // Send newly seen typefaces.
346     SkASSERT_RELEASE(SkTFitsIn<int>(fTypefacesToSend.size()));
347     buffer.writeInt(fTypefacesToSend.size());
348     for (const auto& typeface: fTypefacesToSend) {
349         SkTypefaceProxyPrototype proto{typeface};
350         proto.flatten(buffer);
351     }
352     fTypefacesToSend.clear();
353 
354     buffer.writeInt(strikesToSend);
355     fRemoteStrikesToSend.foreach(
356             [&](RemoteStrike* strike) {
357                 if (strike->hasPendingGlyphs()) {
358                     strike->writePendingGlyphs(buffer);
359                     strike->resetScalerContext();
360                 }
361             }
362     );
363     fRemoteStrikesToSend.reset();
364 
365     // Copy data into the vector.
366     auto data = buffer.snapshotAsData();
367     memory->assign(data->bytes(), data->bytes() + data->size());
368 }
369 
findOrCreateScopedStrike(const SkStrikeSpec & strikeSpec)370 sk_sp<StrikeForGPU> SkStrikeServerImpl::findOrCreateScopedStrike(
371         const SkStrikeSpec& strikeSpec) {
372     return this->getOrCreateCache(strikeSpec);
373 }
374 
checkForDeletedEntries()375 void SkStrikeServerImpl::checkForDeletedEntries() {
376     auto it = fDescToRemoteStrike.begin();
377     while (fDescToRemoteStrike.size() > fMaxEntriesInDescriptorMap &&
378            it != fDescToRemoteStrike.end()) {
379         RemoteStrike* strike = it->second.get();
380         if (fDiscardableHandleManager->isHandleDeleted(strike->discardableHandleId())) {
381             // If we are trying to send the strike, then do not erase it.
382             if (!fRemoteStrikesToSend.contains(strike)) {
383                 // Erase returns the iterator following the removed element.
384                 it = fDescToRemoteStrike.erase(it);
385                 continue;
386             }
387         }
388         ++it;
389     }
390 }
391 
getOrCreateCache(const SkStrikeSpec & strikeSpec)392 sk_sp<RemoteStrike> SkStrikeServerImpl::getOrCreateCache(const SkStrikeSpec& strikeSpec) {
393     // In cases where tracing is turned off, make sure not to get an unused function warning.
394     // Lambdaize the function.
395     TRACE_EVENT1("skia", "RecForDesc", "rec",
396                  TRACE_STR_COPY(
397                          [&strikeSpec](){
398                              auto ptr =
399                                  strikeSpec.descriptor().findEntry(kRec_SkDescriptorTag, nullptr);
400                              SkScalerContextRec rec;
401                              std::memcpy((void*)&rec, ptr, sizeof(rec));
402                              return rec.dump();
403                          }().c_str()
404                  )
405     );
406 
407     if (auto it = fDescToRemoteStrike.find(&strikeSpec.descriptor());
408         it != fDescToRemoteStrike.end())
409     {
410         // We have processed the RemoteStrike before. Reuse it.
411         sk_sp<RemoteStrike> strike = it->second;
412         strike->setStrikeSpec(strikeSpec);
413         if (fRemoteStrikesToSend.contains(strike.get())) {
414             // Already tracking
415             return strike;
416         }
417 
418         // Strike is in unknown state on GPU. Start tracking strike on GPU by locking it.
419         bool locked = fDiscardableHandleManager->lockHandle(it->second->discardableHandleId());
420         if (locked) {
421             fRemoteStrikesToSend.add(strike.get());
422             return strike;
423         }
424 
425         // If it wasn't locked, then forget this strike, and build it anew below.
426         fDescToRemoteStrike.erase(it);
427     }
428 
429     const SkTypeface& typeface = strikeSpec.typeface();
430     // Create a new RemoteStrike. Start by processing the typeface.
431     const SkTypefaceID typefaceId = typeface.uniqueID();
432     if (!fCachedTypefaces.contains(typefaceId)) {
433         fCachedTypefaces.add(typefaceId);
434         fTypefacesToSend.emplace_back(typeface);
435     }
436 
437     auto context = strikeSpec.createScalerContext();
438     auto newHandle = fDiscardableHandleManager->createHandle();  // Locked on creation
439     auto remoteStrike = sk_make_sp<RemoteStrike>(strikeSpec, std::move(context), newHandle);
440     remoteStrike->setStrikeSpec(strikeSpec);
441     fRemoteStrikesToSend.add(remoteStrike.get());
442     auto d = &remoteStrike->getDescriptor();
443     fDescToRemoteStrike[d] = remoteStrike;
444 
445     checkForDeletedEntries();
446 
447     return remoteStrike;
448 }
449 
450 // -- GlyphTrackingDevice --------------------------------------------------------------------------
451 class GlyphTrackingDevice final : public SkNoPixelsDevice {
452 public:
GlyphTrackingDevice(const SkISize & dimensions,const SkSurfaceProps & props,SkStrikeServerImpl * server,sk_sp<SkColorSpace> colorSpace,sktext::gpu::SubRunControl SubRunControl)453     GlyphTrackingDevice(
454             const SkISize& dimensions, const SkSurfaceProps& props, SkStrikeServerImpl* server,
455             sk_sp<SkColorSpace> colorSpace, sktext::gpu::SubRunControl SubRunControl)
456             : SkNoPixelsDevice(SkIRect::MakeSize(dimensions), props, std::move(colorSpace))
457             , fStrikeServerImpl(server)
458             , fSubRunControl(SubRunControl) {
459         SkASSERT(fStrikeServerImpl != nullptr);
460     }
461 
createDevice(const CreateInfo & cinfo,const SkPaint *)462     sk_sp<SkDevice> createDevice(const CreateInfo& cinfo, const SkPaint*) override {
463         const SkSurfaceProps surfaceProps =
464             this->surfaceProps().cloneWithPixelGeometry(cinfo.fPixelGeometry);
465 
466         return sk_make_sp<GlyphTrackingDevice>(cinfo.fInfo.dimensions(),
467                                                surfaceProps,
468                                                fStrikeServerImpl,
469                                                cinfo.fInfo.refColorSpace(),
470                                                fSubRunControl);
471     }
472 
strikeDeviceInfo() const473     SkStrikeDeviceInfo strikeDeviceInfo() const override {
474         return {this->surfaceProps(), this->scalerContextFlags(), &fSubRunControl};
475     }
476 
477 protected:
onDrawGlyphRunList(SkCanvas *,const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)478     void onDrawGlyphRunList(SkCanvas*,
479                             const sktext::GlyphRunList& glyphRunList,
480                             const SkPaint& paint) override {
481         SkMatrix drawMatrix = this->localToDevice();
482         drawMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
483 
484         // Just ignore the resulting SubRunContainer. Since we're passing in a null SubRunAllocator
485         // no SubRuns will be produced.
486         STSubRunAllocator<sizeof(SubRunContainer), alignof(SubRunContainer)> tempAlloc;
487         auto container = SubRunContainer::MakeInAlloc(glyphRunList,
488                                                       drawMatrix,
489                                                       paint,
490                                                       this->strikeDeviceInfo(),
491                                                       fStrikeServerImpl,
492                                                       &tempAlloc,
493                                                       SubRunContainer::kStrikeCalculationsOnly,
494                                                       "Cache Diff");
495         // Calculations only. No SubRuns.
496         SkASSERT(container->isEmpty());
497     }
498 
convertGlyphRunListToSlug(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)499     sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug(const sktext::GlyphRunList& glyphRunList,
500                                                        const SkPaint& paint) override {
501         // Full matrix for placing glyphs.
502         SkMatrix positionMatrix = this->localToDevice();
503         positionMatrix.preTranslate(glyphRunList.origin().x(), glyphRunList.origin().y());
504 
505         // Use the SkStrikeServer's strike cache to generate the Slug.
506         return sktext::gpu::MakeSlug(this->localToDevice(),
507                                      glyphRunList,
508                                      paint,
509                                      this->strikeDeviceInfo(),
510                                      fStrikeServerImpl);
511     }
512 
513 private:
514     SkStrikeServerImpl* const fStrikeServerImpl;
515     const sktext::gpu::SubRunControl fSubRunControl;
516 };
517 
518 // -- SkStrikeServer -------------------------------------------------------------------------------
SkStrikeServer(DiscardableHandleManager * dhm)519 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* dhm)
520         : fImpl(new SkStrikeServerImpl{dhm}) { }
521 
522 SkStrikeServer::~SkStrikeServer() = default;
523 
makeAnalysisCanvas(int width,int height,const SkSurfaceProps & props,sk_sp<SkColorSpace> colorSpace,bool DFTSupport,bool DFTPerspSupport)524 std::unique_ptr<SkCanvas> SkStrikeServer::makeAnalysisCanvas(int width, int height,
525                                                              const SkSurfaceProps& props,
526                                                              sk_sp<SkColorSpace> colorSpace,
527                                                              bool DFTSupport,
528                                                              bool DFTPerspSupport) {
529 #if !defined(SK_DISABLE_SDF_TEXT)
530     // These are copied from the defaults in GrContextOptions for historical reasons.
531     // TODO(herb, jvanverth) pipe in parameters that can be used for both Ganesh and Graphite
532     // backends instead of just using the defaults.
533     constexpr float kMinDistanceFieldFontSize = 18.f;
534 
535 #if defined(SK_BUILD_FOR_ANDROID)
536     constexpr float kGlyphsAsPathsFontSize = 384.f;
537 #elif defined(SK_BUILD_FOR_MAC)
538     constexpr float kGlyphsAsPathsFontSize = 256.f;
539 #else
540     constexpr float kGlyphsAsPathsFontSize = 324.f;
541 #endif
542     // There is no need to set forcePathAA for the remote glyph cache as that control impacts
543     // *how* the glyphs are rendered as paths, not *when* they are rendered as paths.
544     auto control = sktext::gpu::SubRunControl{DFTSupport,
545                                             props.isUseDeviceIndependentFonts(),
546                                             DFTPerspSupport,
547                                             kMinDistanceFieldFontSize,
548                                             kGlyphsAsPathsFontSize};
549 #else
550     auto control = sktext::gpu::SubRunControl{};
551 #endif
552 
553     sk_sp<SkDevice> trackingDevice = sk_make_sp<GlyphTrackingDevice>(
554             SkISize::Make(width, height),
555             props, this->impl(),
556             std::move(colorSpace),
557             control);
558     return std::make_unique<SkCanvas>(std::move(trackingDevice));
559 }
560 
writeStrikeData(std::vector<uint8_t> * memory)561 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
562     fImpl->writeStrikeData(memory);
563 }
564 
impl()565 SkStrikeServerImpl* SkStrikeServer::impl() { return fImpl.get(); }
566 
setMaxEntriesInDescriptorMapForTesting(size_t count)567 void SkStrikeServer::setMaxEntriesInDescriptorMapForTesting(size_t count) {
568     fImpl->setMaxEntriesInDescriptorMapForTesting(count);
569 }
remoteStrikeMapSizeForTesting() const570 size_t SkStrikeServer::remoteStrikeMapSizeForTesting() const {
571     return fImpl->remoteStrikeMapSizeForTesting();
572 }
573 
574 // -- DiscardableStrikePinner ----------------------------------------------------------------------
575 class DiscardableStrikePinner : public SkStrikePinner {
576 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<SkStrikeClient::DiscardableHandleManager> manager)577     DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
578                             sk_sp<SkStrikeClient::DiscardableHandleManager> manager)
579             : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
580 
581     ~DiscardableStrikePinner() override = default;
canDelete()582     bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
assertValid()583     void assertValid() override { fManager->assertHandleValid(fDiscardableHandleId); }
584 
585 private:
586     const SkDiscardableHandleId fDiscardableHandleId;
587     sk_sp<SkStrikeClient::DiscardableHandleManager> fManager;
588 };
589 
590 // -- SkStrikeClientImpl ---------------------------------------------------------------------------
591 class SkStrikeClientImpl {
592 public:
593     explicit SkStrikeClientImpl(sk_sp<SkStrikeClient::DiscardableHandleManager>,
594                                 bool isLogging = true,
595                                 SkStrikeCache* strikeCache = nullptr);
596 
597     bool readStrikeData(const volatile void* memory, size_t memorySize);
598     bool translateTypefaceID(SkAutoDescriptor* descriptor) const;
599     sk_sp<SkTypeface> retrieveTypefaceUsingServerID(SkTypefaceID) const;
600 
601 private:
602     class PictureBackedGlyphDrawable final : public SkDrawable {
603     public:
PictureBackedGlyphDrawable(sk_sp<SkPicture> self)604         PictureBackedGlyphDrawable(sk_sp<SkPicture> self) : fSelf(std::move(self)) {}
605     private:
606         sk_sp<SkPicture> fSelf;
onGetBounds()607         SkRect onGetBounds() override { return fSelf->cullRect();  }
onApproximateBytesUsed()608         size_t onApproximateBytesUsed() override {
609             return sizeof(PictureBackedGlyphDrawable) + fSelf->approximateBytesUsed();
610         }
onDraw(SkCanvas * canvas)611         void onDraw(SkCanvas* canvas) override { canvas->drawPicture(fSelf); }
612     };
613 
614     sk_sp<SkTypeface> addTypeface(const SkTypefaceProxyPrototype& typefaceProto);
615 
616     THashMap<SkTypefaceID, sk_sp<SkTypeface>> fServerTypefaceIdToTypeface;
617     sk_sp<SkStrikeClient::DiscardableHandleManager> fDiscardableHandleManager;
618     SkStrikeCache* const fStrikeCache;
619     const bool fIsLogging;
620 };
621 
SkStrikeClientImpl(sk_sp<SkStrikeClient::DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)622 SkStrikeClientImpl::SkStrikeClientImpl(
623         sk_sp<SkStrikeClient::DiscardableHandleManager>
624         discardableManager,
625         bool isLogging,
626         SkStrikeCache* strikeCache)
627     : fDiscardableHandleManager(std::move(discardableManager)),
628       fStrikeCache{strikeCache ? strikeCache : SkStrikeCache::GlobalStrikeCache()},
629       fIsLogging{isLogging} {}
630 
631 // Change the path count to track the line number of the failing read.
632 // TODO: change __LINE__ back to glyphPathsCount when bug chromium:1287356 is closed.
633 #define READ_FAILURE                                                        \
634     {                                                                       \
635         SkDebugf("Bad font data serialization line: %d", __LINE__);         \
636         SkStrikeClient::DiscardableHandleManager::ReadFailureData data = {  \
637                 memorySize,  deserializer.bytesRead(), typefaceSize,        \
638                 strikeCount, glyphImagesCount, __LINE__};                   \
639         fDiscardableHandleManager->notifyReadFailure(data);                 \
640         return false;                                                       \
641     }
642 
readStrikeData(const volatile void * memory,size_t memorySize)643 bool SkStrikeClientImpl::readStrikeData(const volatile void* memory, size_t memorySize) {
644     SkASSERT(memorySize != 0);
645     SkASSERT(memory != nullptr);
646 
647     // We do not need to set any SkDeserialProcs here because SkStrikeServerImpl::writeStrikeData
648     // did not encode any SkImages.
649     SkReadBuffer buffer{const_cast<const void*>(memory), memorySize};
650     // Limit the kinds of effects that appear in a glyph's drawable (crbug.com/1442140):
651     buffer.setAllowSkSL(false);
652 
653     int curTypeface = 0,
654         curStrike = 0;
655 
656     auto postError = [&](int line) {
657         SkDebugf("Read Error Posted %s : %d", __FILE__, line);
658         SkStrikeClient::DiscardableHandleManager::ReadFailureData data{
659                 memorySize,
660                 buffer.offset(),
661                 SkTo<uint64_t>(curTypeface),
662                 SkTo<uint64_t>(curStrike),
663                 SkTo<uint64_t>(0),
664                 SkTo<uint64_t>(0)};
665         fDiscardableHandleManager->notifyReadFailure(data);
666     };
667 
668     // Read the number of typefaces sent.
669     const int typefaceCount = buffer.readInt();
670     for (curTypeface = 0; curTypeface < typefaceCount; ++curTypeface) {
671         auto proto = SkTypefaceProxyPrototype::MakeFromBuffer(buffer);
672         if (proto) {
673             this->addTypeface(proto.value());
674         } else {
675             postError(__LINE__);
676             return false;
677         }
678     }
679 
680     // Read the number of strikes sent.
681     const int stirkeCount = buffer.readInt();
682     for (curStrike = 0; curStrike < stirkeCount; ++curStrike) {
683 
684         const SkTypefaceID serverTypefaceID = buffer.readUInt();
685         if (serverTypefaceID == 0 && !buffer.isValid()) {
686             postError(__LINE__);
687             return false;
688         }
689 
690         const SkDiscardableHandleId discardableHandleID = buffer.readUInt();
691         if (discardableHandleID == 0 && !buffer.isValid()) {
692             postError(__LINE__);
693             return false;
694         }
695 
696         std::optional<SkAutoDescriptor> serverDescriptor = SkAutoDescriptor::MakeFromBuffer(buffer);
697         if (!buffer.validate(serverDescriptor.has_value())) {
698             postError(__LINE__);
699             return false;
700         }
701 
702         const bool fontMetricsInitialized = buffer.readBool();
703         if (!fontMetricsInitialized && !buffer.isValid()) {
704             postError(__LINE__);
705             return false;
706         }
707 
708         std::optional<SkFontMetrics> fontMetrics;
709         if (!fontMetricsInitialized) {
710             fontMetrics = SkFontMetricsPriv::MakeFromBuffer(buffer);
711             if (!fontMetrics || !buffer.isValid()) {
712                 postError(__LINE__);
713                 return false;
714             }
715         }
716 
717         auto* clientTypeface = fServerTypefaceIdToTypeface.find(serverTypefaceID);
718         if (clientTypeface == nullptr) {
719             postError(__LINE__);
720             return false;
721         }
722 
723         if (!this->translateTypefaceID(&serverDescriptor.value())) {
724             postError(__LINE__);
725             return false;
726         }
727 
728         SkDescriptor* clientDescriptor = serverDescriptor->getDesc();
729         auto strike = fStrikeCache->findStrike(*clientDescriptor);
730 
731         if (strike == nullptr) {
732             // Metrics are only sent the first time. If creating a new strike, then the metrics
733             // are not initialized.
734             if (fontMetricsInitialized) {
735                 postError(__LINE__);
736                 return false;
737             }
738             SkStrikeSpec strikeSpec{*clientDescriptor, *clientTypeface};
739             strike = fStrikeCache->createStrike(
740                     strikeSpec, &fontMetrics.value(),
741                     std::make_unique<DiscardableStrikePinner>(
742                             discardableHandleID, fDiscardableHandleManager));
743         }
744 
745         // Make sure this strike is pinned on the GPU side.
746         strike->verifyPinnedStrike();
747 
748         if (!strike->mergeFromBuffer(buffer)) {
749             postError(__LINE__);
750             return false;
751         }
752     }
753 
754     return true;
755 }
756 
translateTypefaceID(SkAutoDescriptor * toChange) const757 bool SkStrikeClientImpl::translateTypefaceID(SkAutoDescriptor* toChange) const {
758     SkDescriptor& descriptor = *toChange->getDesc();
759 
760     // Rewrite the typefaceID in the rec.
761     {
762         uint32_t size;
763         // findEntry returns a const void*, remove the const in order to update in place.
764         void* ptr = const_cast<void *>(descriptor.findEntry(kRec_SkDescriptorTag, &size));
765         SkScalerContextRec rec;
766         if (!ptr || size != sizeof(rec)) { return false; }
767         std::memcpy((void*)&rec, ptr, size);
768         // Get the local typeface from remote typefaceID.
769         auto* tfPtr = fServerTypefaceIdToTypeface.find(rec.fTypefaceID);
770         // Received a strike for a typeface which doesn't exist.
771         if (!tfPtr) { return false; }
772         // Update the typeface id to work with the client side.
773         rec.fTypefaceID = tfPtr->get()->uniqueID();
774         std::memcpy(ptr, &rec, size);
775     }
776 
777     descriptor.computeChecksum();
778 
779     return true;
780 }
781 
retrieveTypefaceUsingServerID(SkTypefaceID typefaceID) const782 sk_sp<SkTypeface> SkStrikeClientImpl::retrieveTypefaceUsingServerID(SkTypefaceID typefaceID) const {
783     auto* tfPtr = fServerTypefaceIdToTypeface.find(typefaceID);
784     return tfPtr != nullptr ? *tfPtr : nullptr;
785 }
786 
addTypeface(const SkTypefaceProxyPrototype & typefaceProto)787 sk_sp<SkTypeface> SkStrikeClientImpl::addTypeface(const SkTypefaceProxyPrototype& typefaceProto) {
788     sk_sp<SkTypeface>* typeface =
789             fServerTypefaceIdToTypeface.find(typefaceProto.serverTypefaceID());
790 
791     // We already have the typeface.
792     if (typeface != nullptr)  {
793         return *typeface;
794     }
795 
796     auto newTypeface = sk_make_sp<SkTypefaceProxy>(
797             typefaceProto, fDiscardableHandleManager, fIsLogging);
798     fServerTypefaceIdToTypeface.set(typefaceProto.serverTypefaceID(), newTypeface);
799     return newTypeface;
800 }
801 
802 // SkStrikeClient ----------------------------------------------------------------------------------
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)803 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
804                                bool isLogging,
805                                SkStrikeCache* strikeCache)
806        : fImpl{new SkStrikeClientImpl{std::move(discardableManager), isLogging, strikeCache}} {}
807 
808 SkStrikeClient::~SkStrikeClient() = default;
809 
readStrikeData(const volatile void * memory,size_t memorySize)810 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
811     return fImpl->readStrikeData(memory, memorySize);
812 }
813 
retrieveTypefaceUsingServerIDForTest(SkTypefaceID typefaceID) const814 sk_sp<SkTypeface> SkStrikeClient::retrieveTypefaceUsingServerIDForTest(
815         SkTypefaceID typefaceID) const {
816     return fImpl->retrieveTypefaceUsingServerID(typefaceID);
817 }
818 
translateTypefaceID(SkAutoDescriptor * descriptor) const819 bool SkStrikeClient::translateTypefaceID(SkAutoDescriptor* descriptor) const {
820     return fImpl->translateTypefaceID(descriptor);
821 }
822 
deserializeSlugForTest(const void * data,size_t size) const823 sk_sp<sktext::gpu::Slug> SkStrikeClient::deserializeSlugForTest(const void* data,
824                                                                 size_t size) const {
825     return sktext::gpu::Slug::Deserialize(data, size, this);
826 }
827