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