• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SDFTControl.h"
46 #include "src/text/gpu/SubRunAllocator.h"
47 #include "src/text/gpu/SubRunContainer.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__anon510e5bb30111::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 
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.
143     THashTable<SkGlyphDigest, SkPackedGlyphID, SkGlyphDigest> fSentGlyphs;
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 
RemoteStrike(const SkStrikeSpec & strikeSpec,std::unique_ptr<SkScalerContext> context,uint32_t discardableHandleId)155 RemoteStrike::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 
writePendingGlyphs(SkWriteBuffer & buffer)168 void 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);
180         SkFontMetricsPriv::Flatten(buffer, 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 
ensureScalerContext()209 void RemoteStrike::ensureScalerContext() {
210     if (fContext == nullptr) {
211         fContext = fStrikeSpec->createScalerContext();
212     }
213 }
214 
resetScalerContext()215 void RemoteStrike::resetScalerContext() {
216     fContext = nullptr;
217     fStrikeSpec = nullptr;
218 }
219 
setStrikeSpec(const SkStrikeSpec & strikeSpec)220 void RemoteStrike::setStrikeSpec(const SkStrikeSpec& strikeSpec) {
221     fStrikeSpec = &strikeSpec;
222 }
223 
digestFor(ActionType actionType,SkPackedGlyphID packedGlyphID)224 SkGlyphDigest 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 
strikePromise()259 sktext::SkStrikePromise RemoteStrike::strikePromise() {
260     return sktext::SkStrikePromise{*this->fStrikeSpec};
261 }
262 }  // namespace
263 
264 // -- SkStrikeServerImpl ---------------------------------------------------------------------------
265 class SkStrikeServerImpl final : public sktext::StrikeForGPUCacheInterface {
266 public:
267     explicit SkStrikeServerImpl(
268             SkStrikeServer::DiscardableHandleManager* discardableHandleManager);
269 
270     // SkStrikeServer API methods
271     void writeStrikeData(std::vector<uint8_t>* memory);
272 
273     sk_sp<sktext::StrikeForGPU> findOrCreateScopedStrike(const SkStrikeSpec& strikeSpec) override;
274 
275     // Methods for testing
276     void setMaxEntriesInDescriptorMapForTesting(size_t count);
277     size_t remoteStrikeMapSizeForTesting() const;
278 
279 private:
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 {
operator ()SkStrikeServerImpl::MapOps287         size_t operator()(const SkDescriptor* key) const {
288             return key->getChecksum();
289         }
operator ()SkStrikeServerImpl::MapOps290         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 
SkStrikeServerImpl(SkStrikeServer::DiscardableHandleManager * dhm)308 SkStrikeServerImpl::SkStrikeServerImpl(SkStrikeServer::DiscardableHandleManager* dhm)
309         : fDiscardableHandleManager(dhm) {
310     SkASSERT(fDiscardableHandleManager);
311 }
312 
setMaxEntriesInDescriptorMapForTesting(size_t count)313 void SkStrikeServerImpl::setMaxEntriesInDescriptorMapForTesting(size_t count) {
314     fMaxEntriesInDescriptorMap = count;
315 }
remoteStrikeMapSizeForTesting() const316 size_t SkStrikeServerImpl::remoteStrikeMapSizeForTesting() const {
317     return fDescToRemoteStrike.size();
318 }
319 
writeStrikeData(std::vector<uint8_t> * memory)320 void 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 
findOrCreateScopedStrike(const SkStrikeSpec & strikeSpec)366 sk_sp<StrikeForGPU> SkStrikeServerImpl::findOrCreateScopedStrike(
367         const SkStrikeSpec& strikeSpec) {
368     return this->getOrCreateCache(strikeSpec);
369 }
370 
checkForDeletedEntries()371 void 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 
getOrCreateCache(const SkStrikeSpec & strikeSpec)388 sk_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",
392                  TRACE_STR_COPY(
393                          [&strikeSpec](){
394                              auto ptr =
395                                  strikeSpec.descriptor().findEntry(kRec_SkDescriptorTag, nullptr);
396                              SkScalerContextRec rec;
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 --------------------------------------------------------------------------
447 class GlyphTrackingDevice final : public SkNoPixelsDevice {
448 public:
GlyphTrackingDevice(const SkISize & dimensions,const SkSurfaceProps & props,SkStrikeServerImpl * server,sk_sp<SkColorSpace> colorSpace,sktext::gpu::SDFTControl SDFTControl)449     GlyphTrackingDevice(
450             const SkISize& dimensions, const SkSurfaceProps& props, SkStrikeServerImpl* server,
451             sk_sp<SkColorSpace> colorSpace, sktext::gpu::SDFTControl SDFTControl)
452             : SkNoPixelsDevice(SkIRect::MakeSize(dimensions), props, std::move(colorSpace))
453             , fStrikeServerImpl(server)
454             , fSDFTControl(SDFTControl) {
455         SkASSERT(fStrikeServerImpl != nullptr);
456     }
457 
createDevice(const CreateInfo & cinfo,const SkPaint *)458     sk_sp<SkDevice> createDevice(const CreateInfo& cinfo, const SkPaint*) override {
459         const SkSurfaceProps surfaceProps =
460             this->surfaceProps().cloneWithPixelGeometry(cinfo.fPixelGeometry);
461 
462         return sk_make_sp<GlyphTrackingDevice>(cinfo.fInfo.dimensions(),
463                                                surfaceProps,
464                                                fStrikeServerImpl,
465                                                cinfo.fInfo.refColorSpace(),
466                                                fSDFTControl);
467     }
468 
strikeDeviceInfo() const469     SkStrikeDeviceInfo strikeDeviceInfo() const override {
470         return {this->surfaceProps(), this->scalerContextFlags(), &fSDFTControl};
471     }
472 
473 protected:
onDrawGlyphRunList(SkCanvas *,const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)474     void onDrawGlyphRunList(SkCanvas*,
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 
convertGlyphRunListToSlug(const sktext::GlyphRunList & glyphRunList,const SkPaint & paint)495     sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug(const sktext::GlyphRunList& glyphRunList,
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.
502         return sktext::gpu::MakeSlug(this->localToDevice(),
503                                      glyphRunList,
504                                      paint,
505                                      this->strikeDeviceInfo(),
506                                      fStrikeServerImpl);
507     }
508 
509 private:
510     SkStrikeServerImpl* const fStrikeServerImpl;
511     const sktext::gpu::SDFTControl fSDFTControl;
512 };
513 
514 // -- SkStrikeServer -------------------------------------------------------------------------------
SkStrikeServer(DiscardableHandleManager * dhm)515 SkStrikeServer::SkStrikeServer(DiscardableHandleManager* dhm)
516         : fImpl(new SkStrikeServerImpl{dhm}) { }
517 
518 SkStrikeServer::~SkStrikeServer() = default;
519 
makeAnalysisCanvas(int width,int height,const SkSurfaceProps & props,sk_sp<SkColorSpace> colorSpace,bool DFTSupport,bool DFTPerspSupport)520 std::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,
539                                             props.isUseDeviceIndependentFonts(),
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>(
548             SkISize::Make(width, height),
549             props, this->impl(),
550             std::move(colorSpace),
551             control);
552     return std::make_unique<SkCanvas>(std::move(trackingDevice));
553 }
554 
writeStrikeData(std::vector<uint8_t> * memory)555 void SkStrikeServer::writeStrikeData(std::vector<uint8_t>* memory) {
556     fImpl->writeStrikeData(memory);
557 }
558 
impl()559 SkStrikeServerImpl* SkStrikeServer::impl() { return fImpl.get(); }
560 
setMaxEntriesInDescriptorMapForTesting(size_t count)561 void SkStrikeServer::setMaxEntriesInDescriptorMapForTesting(size_t count) {
562     fImpl->setMaxEntriesInDescriptorMapForTesting(count);
563 }
remoteStrikeMapSizeForTesting() const564 size_t SkStrikeServer::remoteStrikeMapSizeForTesting() const {
565     return fImpl->remoteStrikeMapSizeForTesting();
566 }
567 
568 // -- DiscardableStrikePinner ----------------------------------------------------------------------
569 class DiscardableStrikePinner : public SkStrikePinner {
570 public:
DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,sk_sp<SkStrikeClient::DiscardableHandleManager> manager)571     DiscardableStrikePinner(SkDiscardableHandleId discardableHandleId,
572                             sk_sp<SkStrikeClient::DiscardableHandleManager> manager)
573             : fDiscardableHandleId(discardableHandleId), fManager(std::move(manager)) {}
574 
575     ~DiscardableStrikePinner() override = default;
canDelete()576     bool canDelete() override { return fManager->deleteHandle(fDiscardableHandleId); }
assertValid()577     void assertValid() override { fManager->assertHandleValid(fDiscardableHandleId); }
578 
579 private:
580     const SkDiscardableHandleId fDiscardableHandleId;
581     sk_sp<SkStrikeClient::DiscardableHandleManager> fManager;
582 };
583 
584 // -- SkStrikeClientImpl ---------------------------------------------------------------------------
585 class SkStrikeClientImpl {
586 public:
587     explicit SkStrikeClientImpl(sk_sp<SkStrikeClient::DiscardableHandleManager>,
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;
593     sk_sp<SkTypeface> retrieveTypefaceUsingServerID(SkTypefaceID) const;
594 
595 private:
596     class PictureBackedGlyphDrawable final : public SkDrawable {
597     public:
PictureBackedGlyphDrawable(sk_sp<SkPicture> self)598         PictureBackedGlyphDrawable(sk_sp<SkPicture> self) : fSelf(std::move(self)) {}
599     private:
600         sk_sp<SkPicture> fSelf;
onGetBounds()601         SkRect onGetBounds() override { return fSelf->cullRect();  }
onApproximateBytesUsed()602         size_t onApproximateBytesUsed() override {
603             return sizeof(PictureBackedGlyphDrawable) + fSelf->approximateBytesUsed();
604         }
onDraw(SkCanvas * canvas)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 
SkStrikeClientImpl(sk_sp<SkStrikeClient::DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)616 SkStrikeClientImpl::SkStrikeClientImpl(
617         sk_sp<SkStrikeClient::DiscardableHandleManager>
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 
readStrikeData(const volatile void * memory,size_t memorySize)637 bool 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);
652         SkStrikeClient::DiscardableHandleManager::ReadFailureData data{
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) {
665         auto proto = SkTypefaceProxyPrototype::MakeFromBuffer(buffer);
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) {
704             fontMetrics = SkFontMetricsPriv::MakeFromBuffer(buffer);
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 
translateTypefaceID(SkAutoDescriptor * toChange) const751 bool SkStrikeClientImpl::translateTypefaceID(SkAutoDescriptor* toChange) const {
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));
759         SkScalerContextRec rec;
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 
retrieveTypefaceUsingServerID(SkTypefaceID typefaceID) const776 sk_sp<SkTypeface> SkStrikeClientImpl::retrieveTypefaceUsingServerID(SkTypefaceID typefaceID) const {
777     auto* tfPtr = fServerTypefaceIdToTypeface.find(typefaceID);
778     return tfPtr != nullptr ? *tfPtr : nullptr;
779 }
780 
addTypeface(const SkTypefaceProxyPrototype & typefaceProto)781 sk_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 ----------------------------------------------------------------------------------
SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,bool isLogging,SkStrikeCache * strikeCache)797 SkStrikeClient::SkStrikeClient(sk_sp<DiscardableHandleManager> discardableManager,
798                                bool isLogging,
799                                SkStrikeCache* strikeCache)
800        : fImpl{new SkStrikeClientImpl{std::move(discardableManager), isLogging, strikeCache}} {}
801 
802 SkStrikeClient::~SkStrikeClient() = default;
803 
readStrikeData(const volatile void * memory,size_t memorySize)804 bool SkStrikeClient::readStrikeData(const volatile void* memory, size_t memorySize) {
805     return fImpl->readStrikeData(memory, memorySize);
806 }
807 
retrieveTypefaceUsingServerIDForTest(SkTypefaceID typefaceID) const808 sk_sp<SkTypeface> SkStrikeClient::retrieveTypefaceUsingServerIDForTest(
809         SkTypefaceID typefaceID) const {
810     return fImpl->retrieveTypefaceUsingServerID(typefaceID);
811 }
812 
translateTypefaceID(SkAutoDescriptor * descriptor) const813 bool SkStrikeClient::translateTypefaceID(SkAutoDescriptor* descriptor) const {
814     return fImpl->translateTypefaceID(descriptor);
815 }
816 
deserializeSlugForTest(const void * data,size_t size) const817 sk_sp<sktext::gpu::Slug> SkStrikeClient::deserializeSlugForTest(const void* data,
818                                                                 size_t size) const {
819     return sktext::gpu::Slug::Deserialize(data, size, this);
820 }
821