blob: ef0124e481973c841587e658280dd5bfcf686a36 [file] [log] [blame]
Khushal38a08432018-05-02 10:29:37 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkGraphics.h"
9#include "include/core/SkSurface.h"
10#include "include/core/SkTextBlob.h"
11#include "include/private/SkMutex.h"
12#include "src/core/SkDraw.h"
13#include "src/core/SkRemoteGlyphCache.h"
Herb Derby81e84a62020-02-14 11:47:35 -050014#include "src/core/SkScalerCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkStrikeCache.h"
Herb Derbyd249e8c2019-06-03 11:36:01 -040016#include "src/core/SkStrikeSpec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkSurfacePriv.h"
18#include "src/core/SkTypeface_remote.h"
19#include "tests/Test.h"
20#include "tools/Resources.h"
21#include "tools/ToolUtils.h"
22#include "tools/fonts/TestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070023
Herb Derby082232b2020-06-10 15:08:18 -040024#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070026
Khushal38a08432018-05-02 10:29:37 -070027class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
28 public SkStrikeClient::DiscardableHandleManager {
29public:
Khushald4160832018-05-23 18:16:00 -070030 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070031 ~DiscardableManager() override = default;
32
33 // Server implementation.
34 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040035 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070036
Khushal38a08432018-05-02 10:29:37 -070037 // Handles starts as locked.
38 fLockedHandles.add(++fNextHandleId);
39 return fNextHandleId;
40 }
41 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040042 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070043
Khushal38a08432018-05-02 10:29:37 -070044 if (id <= fLastDeletedHandleId) return false;
45 fLockedHandles.add(id);
46 return true;
47 }
48
49 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070050 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040051 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070052
Khushal3de67bd2019-03-15 14:43:15 -070053 return id <= fLastDeletedHandleId;
54 }
55
56 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040057 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070058
59 fCacheMissCount[type]++;
60 }
61 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040062 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070063
64 return id <= fLastDeletedHandleId;
65 }
66
67 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040068 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070069
70 fLockedHandles.reset();
71 }
Khushal38a08432018-05-02 10:29:37 -070072 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040073 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070074
75 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070076 fLastDeletedHandleId = fNextHandleId;
77 }
Khushal3de67bd2019-03-15 14:43:15 -070078 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040079 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070080
81 return fLockedHandles;
82 }
83 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040084 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070085
86 return fNextHandleId;
87 }
88 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040089 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070090
91 return fCacheMissCount[type];
92 }
Khushalfa8ff092018-06-06 17:46:38 -070093 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040094 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070095
Khushalfa8ff092018-06-06 17:46:38 -070096 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040097 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -070098 }
99 return false;
100 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400101 void resetCacheMissCounts() {
102 SkAutoMutexExclusive l(fMutex);
103 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
104 }
Khushal38a08432018-05-02 10:29:37 -0700105
106private:
Khushal3de67bd2019-03-15 14:43:15 -0700107 // The tests below run in parallel on multiple threads and use the same
108 // process global SkStrikeCache. So the implementation needs to be
109 // thread-safe.
110 mutable SkMutex fMutex;
111
Khushal38a08432018-05-02 10:29:37 -0700112 SkDiscardableHandleId fNextHandleId = 0u;
113 SkDiscardableHandleId fLastDeletedHandleId = 0u;
114 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700115 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700116};
117
118sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500119 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700120 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400121 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500122 font.setSize(1u);
123 font.setEdging(SkFont::Edging::kAntiAlias);
124 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700125
126 SkTextBlobBuilder builder;
127 SkRect bounds = SkRect::MakeWH(10, 10);
128 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
129 SkASSERT(runBuffer.utf8text == nullptr);
130 SkASSERT(runBuffer.clusters == nullptr);
131
132 for (int i = 0; i < glyphCount; i++) {
133 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
134 runBuffer.pos[i] = SkIntToScalar(i);
135 }
136 return builder.make();
137}
138
Chris Daltonf9a90a22018-08-28 14:17:55 -0600139static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
140 skiatest::Reporter* reporter, int tolerance = 0) {
141 SkASSERT(expected.width() == actual.width());
142 SkASSERT(expected.height() == actual.height());
143 for (int i = 0; i < expected.width(); ++i) {
144 for (int j = 0; j < expected.height(); ++j) {
145 SkColor expectedColor = expected.getColor(i, j);
146 SkColor actualColor = actual.getColor(i, j);
147 if (0 == tolerance) {
148 REPORTER_ASSERT(reporter, expectedColor == actualColor);
149 } else {
150 for (int k = 0; k < 4; ++k) {
151 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
152 int actualChannel = (actualColor >> (k*8)) & 0xff;
153 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
154 }
155 }
156 }
Khushal51371a42018-05-17 10:41:40 -0700157 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600158}
Khushal51371a42018-05-17 10:41:40 -0700159
Herb Derbyc3415002018-11-08 16:40:26 -0500160sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
161 const SkImageInfo info =
162 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
163 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
164}
165
166const SkSurfaceProps FindSurfaceProps(GrContext* context) {
167 auto surface = MakeSurface(1, 1, context);
168 return surface->props();
169}
170
Ravi Mistrycd21d672018-05-29 21:45:46 +0000171SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400172 GrContext* context, const SkMatrix* matrix = nullptr,
173 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500174 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000175 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400176 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700177 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000178 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700179 surface->readPixels(bitmap, 0, 0);
180 return bitmap;
181}
182
183DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
184 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
185 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400186 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700187
188 auto server_tf = SkTypeface::MakeDefault();
189 auto tf_data = server.serializeTypeface(server_tf.get());
190
191 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
192 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700193 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700194 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700195
196 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
197 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700198}
199
Khushal3e7548c2018-05-23 15:45:01 -0700200DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700201 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
202 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400203 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700204 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700205
206 // Server.
207 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
208 auto serverTfData = server.serializeTypeface(serverTf.get());
209
210 int glyphCount = 10;
211 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500212 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500213 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
herb7022b772019-08-15 22:45:43 -0400214 ctxInfo.grContext()->supportsDistanceFieldText());
Hal Canarye107faa2019-10-23 12:52:33 -0400215 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
216 {
217 SkDynamicMemoryWStream wStream;
218 server.fCapture.reset(new SkTextBlobTrace::Capture);
219 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
220 server.fCapture->dump(&wStream);
221 std::unique_ptr<SkStreamAsset> stream = wStream.detachAsStream();
222 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(stream.get());
223 REPORTER_ASSERT(reporter, trace.size() == 1);
224 }
225 #else
Khushal38a08432018-05-02 10:29:37 -0700226 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Hal Canarye107faa2019-10-23 12:52:33 -0400227 #endif
Khushal38a08432018-05-02 10:29:37 -0700228
229 std::vector<uint8_t> serverStrikeData;
230 server.writeStrikeData(&serverStrikeData);
231
232 // Client.
233 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
234 REPORTER_ASSERT(reporter,
235 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
236 auto clientBlob = buildTextBlob(clientTf, glyphCount);
237
Ravi Mistrycd21d672018-05-29 21:45:46 +0000238 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
239 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600240 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700241 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700242
243 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
244 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700245}
246
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400247DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
248 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
249 SkStrikeServer server(discardableManager.get());
250 SkStrikeClient client(discardableManager, false);
251
252 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500253 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400254 auto serverTfData = server.serializeTypeface(serverTf.get());
255 REPORTER_ASSERT(reporter, serverTf->unique());
256
257 {
258 const SkPaint paint;
259 int glyphCount = 10;
260 auto serverBlob = buildTextBlob(serverTf, glyphCount);
261 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400262 SkTextBlobCacheDiffCanvas cache_diff_canvas(
263 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400264 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
265 REPORTER_ASSERT(reporter, !serverTf->unique());
266
267 std::vector<uint8_t> serverStrikeData;
268 server.writeStrikeData(&serverStrikeData);
269 }
270 REPORTER_ASSERT(reporter, serverTf->unique());
271
272 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
273 discardableManager->unlockAndDeleteAll();
274}
275
Khushal38a08432018-05-02 10:29:37 -0700276DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
277 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
278 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400279 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700280
281 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
282 server.serializeTypeface(serverTf.get());
283 int glyphCount = 10;
284 auto serverBlob = buildTextBlob(serverTf, glyphCount);
285
286 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500287 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700288 SkPaint paint;
289 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
290
291 // The strike from the blob should be locked after it has been drawn on the canvas.
292 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
293 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
294
295 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
296 // again.
297 std::vector<uint8_t> fontData;
298 server.writeStrikeData(&fontData);
299 discardableManager->unlockAll();
300 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
301
302 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
303 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
304 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700305
306 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
307 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700308}
309
310DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
311 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
312 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400313 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700314
315 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
316 server.serializeTypeface(serverTf.get());
317 int glyphCount = 10;
318 auto serverBlob = buildTextBlob(serverTf, glyphCount);
319
320 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500321 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700322 SkPaint paint;
323 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
324 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
325
326 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
327 // handles.
328 std::vector<uint8_t> fontData;
329 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700330
331 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
332 // works. This is a regression test for crbug.com/999682.
333 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
334 server.writeStrikeData(&fontData);
335 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
336
Khushal38a08432018-05-02 10:29:37 -0700337 discardableManager->unlockAndDeleteAll();
338 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700339 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700340
341 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
342 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700343}
344
345DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
346 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
347 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400348 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700349
350 // Server.
351 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
352 auto serverTfData = server.serializeTypeface(serverTf.get());
353
354 int glyphCount = 10;
355 auto serverBlob = buildTextBlob(serverTf, glyphCount);
356
357 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500358 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700359 SkPaint paint;
360 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
361
362 std::vector<uint8_t> serverStrikeData;
363 server.writeStrikeData(&serverStrikeData);
364
365 // Client.
366 REPORTER_ASSERT(reporter,
367 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
368 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
369
370 // The cache remains alive until it is pinned in the discardable manager.
371 SkGraphics::PurgeFontCache();
372 REPORTER_ASSERT(reporter, !clientTf->unique());
373
374 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
375 // clientTf.
376 discardableManager->unlockAndDeleteAll();
377 SkGraphics::PurgeFontCache();
378 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700379
380 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
381 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700382}
Khushalb2e71272018-05-15 12:59:48 -0700383
384DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
385 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
386 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400387 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700388
389 // Server.
390 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
391 auto serverTfData = server.serializeTypeface(serverTf.get());
392
393 int glyphCount = 10;
394 auto serverBlob = buildTextBlob(serverTf, glyphCount);
395
396 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500397 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700398 SkPaint paint;
399 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
400
401 std::vector<uint8_t> serverStrikeData;
402 server.writeStrikeData(&serverStrikeData);
403
404 // Client.
405 REPORTER_ASSERT(reporter,
406 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700407
408 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
409 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700410}
Khushal51371a42018-05-17 10:41:40 -0700411
Khushalcf33b1b2018-08-29 16:16:25 -0700412DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
413 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
414 SkStrikeServer server(discardableManager.get());
415 server.setMaxEntriesInDescriptorMapForTesting(1u);
416 SkStrikeClient client(discardableManager, false);
417
418 {
419 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
420 int glyphCount = 10;
421 auto serverBlob = buildTextBlob(serverTf, glyphCount);
422
423 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500424 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700425 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400426 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700427 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400428 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700429 }
430
431 // Serialize to release the lock from the strike server and delete all current
432 // handles.
433 std::vector<uint8_t> fontData;
434 server.writeStrikeData(&fontData);
435 discardableManager->unlockAndDeleteAll();
436
437 // Use a different typeface. Creating a new strike should evict the previous
438 // one.
439 {
440 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
441 int glyphCount = 10;
442 auto serverBlob = buildTextBlob(serverTf, glyphCount);
443
444 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500445 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700446 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400447 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700448 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400449 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700450 }
451
452 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
453 discardableManager->unlockAndDeleteAll();
454}
455
Khushal3e7548c2018-05-23 15:45:01 -0700456DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700457 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
458 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400459 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700460 SkPaint paint;
461 paint.setStyle(SkPaint::kStroke_Style);
462 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400463 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400464 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700465
466 // Server.
467 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
468 auto serverTfData = server.serializeTypeface(serverTf.get());
469
470 int glyphCount = 10;
471 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500472 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400473 SkTextBlobCacheDiffCanvas cache_diff_canvas(
474 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700475 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
476
477 std::vector<uint8_t> serverStrikeData;
478 server.writeStrikeData(&serverStrikeData);
479
480 // Client.
481 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
482 REPORTER_ASSERT(reporter,
483 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
484 auto clientBlob = buildTextBlob(clientTf, glyphCount);
485
Ravi Mistrycd21d672018-05-29 21:45:46 +0000486 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
487 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600488 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700489 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700490
491 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
492 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700493}
Khushal3e7548c2018-05-23 15:45:01 -0700494
Herb Derby8e318fd2018-08-29 11:04:18 -0400495sk_sp<SkTextBlob> make_blob_causing_fallback(
496 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500497 SkFont font;
498 font.setSubpixel(true);
499 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400500 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500501 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400502
Herb Derbyd249e8c2019-06-03 11:36:01 -0400503 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400504 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400505
506 char s[] = "Skia";
507 int runSize = strlen(s);
508
509 SkTextBlobBuilder builder;
510 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500511 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400512 SkASSERT(runBuffer.utf8text == nullptr);
513 SkASSERT(runBuffer.clusters == nullptr);
514
Mike Reed64670cb2019-04-16 11:37:38 -0700515 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
516 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400517
518 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500519 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400520
Herb Derby5fd955e2019-01-16 11:23:29 -0500521 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400522
523 for (int i = 0; i < runSize; i++) {
524 runBuffer.pos[i] = i * 10;
525 }
526
527 return builder.make();
528}
529
530DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
531 reporter, ctxInfo) {
532 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
533 SkStrikeServer server(discardableManager.get());
534 SkStrikeClient client(discardableManager, false);
535
536 SkPaint paint;
537
538 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
539 // TODO: when the cq bots can handle this font remove the check.
540 if (serverTf == nullptr) {
541 return;
542 }
543 auto serverTfData = server.serializeTypeface(serverTf.get());
544
545 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
546
Herb Derbyc3415002018-11-08 16:40:26 -0500547 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400548 SkTextBlobCacheDiffCanvas cache_diff_canvas(
549 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400550 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
551
552 std::vector<uint8_t> serverStrikeData;
553 server.writeStrikeData(&serverStrikeData);
554
555 // Client.
556 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
557 REPORTER_ASSERT(reporter,
558 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
559
560 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
561
562 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
563 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
564 compare_blobs(expected, actual, reporter);
565 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400566
567 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
568 discardableManager->unlockAndDeleteAll();
569}
570
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400571#if 0
572// TODO: turn this one when I figure out how to deal with the pixel variance from linear
573// interpolation from GPU to GPU.
574DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
575 reporter, ctxInfo) {
576 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
577 SkStrikeServer server(discardableManager.get());
578 SkStrikeClient client(discardableManager, false);
579
580 SkPaint paint;
581
582 auto serverTf = ToolUtils::planet_typeface();
583 // TODO: when the cq bots can handle this font remove the check.
584 if (serverTf == nullptr) {
585 return;
586 }
587 auto serverTfData = server.serializeTypeface(serverTf.get());
588
589 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
590 SkFont font;
591 font.setSubpixel(true);
592 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400593 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400594 font.setTypeface(typeface);
595
596 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
597
598 // Mercury to Uranus.
599 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
600
601 SkTextBlobBuilder builder;
602 SkRect bounds = SkRect::MakeIWH(100, 100);
603 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
604 SkASSERT(runBuffer.utf8text == nullptr);
605 SkASSERT(runBuffer.clusters == nullptr);
606
607 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
608
609 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
610 runBuffer.pos[i] = i * 100;
611 }
612
613 return builder.make();
614 };
615
616 auto serverBlob = makeBlob(serverTf);
617
618 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400619 SkTextBlobCacheDiffCanvas cache_diff_canvas(
620 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400621 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
622
623 std::vector<uint8_t> serverStrikeData;
624 server.writeStrikeData(&serverStrikeData);
625
626 // Client.
627 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
628 REPORTER_ASSERT(reporter,
629 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
630
631 auto clientBlob = makeBlob(clientTf);
632
633 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
634 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
635
636 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
637 // interpolation.
638 compare_blobs(expected, actual, reporter, 36);
639 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400640
641 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
642 discardableManager->unlockAndDeleteAll();
643}
644#endif
645
Herb Derby1a9971e2018-07-19 13:41:15 -0400646DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
647 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
648 SkStrikeServer server(discardableManager.get());
649 SkStrikeClient client(discardableManager, false);
650 SkPaint paint;
651 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400652
653 // Server.
654 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
655 auto serverTfData = server.serializeTypeface(serverTf.get());
656
657 int glyphCount = 10;
658 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500659 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400660 SkTextBlobCacheDiffCanvas cache_diff_canvas(
661 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400662 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
663
664 std::vector<uint8_t> serverStrikeData;
665 server.writeStrikeData(&serverStrikeData);
666
667 // Client.
668 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
669 REPORTER_ASSERT(reporter,
670 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
671 auto clientBlob = buildTextBlob(clientTf, glyphCount);
672
673 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
674 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600675 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400676 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400677
678 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
679 discardableManager->unlockAndDeleteAll();
680}
681
Khushal3e7548c2018-05-23 15:45:01 -0700682DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
683 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
684 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400685 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700686 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500687 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700688
Jim Van Verthce3cf802019-10-10 11:06:20 -0400689 // A scale transform forces fallback to dft.
Mike Reed1f607332020-05-21 12:11:27 -0400690 SkMatrix matrix = SkMatrix::Scale(16, 16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000691 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400692 GrTextContext::Options options;
693 GrTextContext::SanitizeOptions(&options);
694 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500695 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700696
697 // Server.
698 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
699 auto serverTfData = server.serializeTypeface(serverTf.get());
700
701 int glyphCount = 10;
702 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000703 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400704 SkTextBlobCacheDiffCanvas cache_diff_canvas(
705 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700706 cache_diff_canvas.concat(matrix);
707 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
708
709 std::vector<uint8_t> serverStrikeData;
710 server.writeStrikeData(&serverStrikeData);
711
712 // Client.
713 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
714 REPORTER_ASSERT(reporter,
715 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
716 auto clientBlob = buildTextBlob(clientTf, glyphCount);
717
Ravi Mistrycd21d672018-05-29 21:45:46 +0000718 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
719 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600720 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700721 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700722
723 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
724 discardableManager->unlockAndDeleteAll();
725}
Khushald4160832018-05-23 18:16:00 -0700726
727DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
728 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
729 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400730 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700731
732 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
733 auto tfData = server.serializeTypeface(serverTf.get());
734 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
735 REPORTER_ASSERT(reporter, clientTf);
736 int glyphCount = 10;
737 auto clientBlob = buildTextBlob(clientTf, glyphCount);
738
739 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000740 SkPaint paint;
741 SkMatrix matrix = SkMatrix::I();
742 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700743 REPORTER_ASSERT(reporter,
744 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
745 REPORTER_ASSERT(reporter,
746 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
747
748 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
749 // miss.
750 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
751 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
752
753 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
754 discardableManager->unlockAndDeleteAll();
755}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400756
Herb Derbye384a1e2019-05-21 11:27:40 -0400757sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
758 sk_sp<SkTypeface> clientTf = nullptr) {
759 SkFont font;
760 font.setTypeface(serverTf);
761 font.setSize(textSize);
762
763 const char* text = ToolUtils::emoji_sample_text();
764 SkFont serverFont = font;
765 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
766 if (clientTf == nullptr) return blob;
767
768 SkSerialProcs s_procs;
769 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
770 return SkData::MakeUninitialized(1u);
771 };
772 auto serialized = blob->serialize(s_procs);
773
774 SkDeserialProcs d_procs;
775 d_procs.fTypefaceCtx = &clientTf;
776 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
777 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
778 };
779 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
780}
781
782DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
783 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
784 SkStrikeServer server(discardableManager.get());
785 SkStrikeClient client(discardableManager, false);
786
787 auto serverTf = ToolUtils::emoji_typeface();
788 auto serverTfData = server.serializeTypeface(serverTf.get());
789 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
790
Mike Reed69aaee02019-05-30 11:40:51 +0000791 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400792 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
793 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400794 SkTextBlobCacheDiffCanvas cache_diff_canvas(
795 500, 500, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400796 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000797 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400798
799 std::vector<uint8_t> serverStrikeData;
800 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400801 if (!serverStrikeData.empty()) {
802 REPORTER_ASSERT(reporter,
803 client.readStrikeData(serverStrikeData.data(),
804 serverStrikeData.size()));
805 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400806 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
807 REPORTER_ASSERT(reporter, clientBlob);
808
Mike Reed69aaee02019-05-30 11:40:51 +0000809 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400810 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400811 discardableManager->resetCacheMissCounts();
812 }
813
814 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
815 discardableManager->unlockAndDeleteAll();
816}
817