blob: 593c5e760366b8ad1d09a1e969489d29e838fe61 [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 Derby3d6bf042020-06-12 11:09:48 -040024#include "src/gpu/GrContextPriv.h"
Herb Derby082232b2020-06-10 15:08:18 -040025#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "src/gpu/text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070027
Khushal38a08432018-05-02 10:29:37 -070028class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
29 public SkStrikeClient::DiscardableHandleManager {
30public:
Khushald4160832018-05-23 18:16:00 -070031 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070032 ~DiscardableManager() override = default;
33
34 // Server implementation.
35 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040036 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070037
Khushal38a08432018-05-02 10:29:37 -070038 // Handles starts as locked.
39 fLockedHandles.add(++fNextHandleId);
40 return fNextHandleId;
41 }
42 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040043 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070044
Khushal38a08432018-05-02 10:29:37 -070045 if (id <= fLastDeletedHandleId) return false;
46 fLockedHandles.add(id);
47 return true;
48 }
49
50 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070051 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040052 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070053
Khushal3de67bd2019-03-15 14:43:15 -070054 return id <= fLastDeletedHandleId;
55 }
56
57 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040058 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070059
60 fCacheMissCount[type]++;
61 }
62 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040063 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070064
65 return id <= fLastDeletedHandleId;
66 }
67
68 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040069 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070070
71 fLockedHandles.reset();
72 }
Khushal38a08432018-05-02 10:29:37 -070073 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040074 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070075
76 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070077 fLastDeletedHandleId = fNextHandleId;
78 }
Khushal3de67bd2019-03-15 14:43:15 -070079 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040080 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070081
82 return fLockedHandles;
83 }
84 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040085 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070086
87 return fNextHandleId;
88 }
89 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040090 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070091
92 return fCacheMissCount[type];
93 }
Khushalfa8ff092018-06-06 17:46:38 -070094 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040095 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070096
Khushalfa8ff092018-06-06 17:46:38 -070097 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040098 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -070099 }
100 return false;
101 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400102 void resetCacheMissCounts() {
103 SkAutoMutexExclusive l(fMutex);
104 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
105 }
Khushal38a08432018-05-02 10:29:37 -0700106
107private:
Khushal3de67bd2019-03-15 14:43:15 -0700108 // The tests below run in parallel on multiple threads and use the same
109 // process global SkStrikeCache. So the implementation needs to be
110 // thread-safe.
111 mutable SkMutex fMutex;
112
Khushal38a08432018-05-02 10:29:37 -0700113 SkDiscardableHandleId fNextHandleId = 0u;
114 SkDiscardableHandleId fLastDeletedHandleId = 0u;
115 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700116 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700117};
118
119sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500120 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700121 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400122 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500123 font.setSize(1u);
124 font.setEdging(SkFont::Edging::kAntiAlias);
125 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700126
127 SkTextBlobBuilder builder;
128 SkRect bounds = SkRect::MakeWH(10, 10);
129 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
130 SkASSERT(runBuffer.utf8text == nullptr);
131 SkASSERT(runBuffer.clusters == nullptr);
132
133 for (int i = 0; i < glyphCount; i++) {
134 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
135 runBuffer.pos[i] = SkIntToScalar(i);
136 }
137 return builder.make();
138}
139
Chris Daltonf9a90a22018-08-28 14:17:55 -0600140static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
141 skiatest::Reporter* reporter, int tolerance = 0) {
142 SkASSERT(expected.width() == actual.width());
143 SkASSERT(expected.height() == actual.height());
144 for (int i = 0; i < expected.width(); ++i) {
145 for (int j = 0; j < expected.height(); ++j) {
146 SkColor expectedColor = expected.getColor(i, j);
147 SkColor actualColor = actual.getColor(i, j);
148 if (0 == tolerance) {
149 REPORTER_ASSERT(reporter, expectedColor == actualColor);
150 } else {
151 for (int k = 0; k < 4; ++k) {
152 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
153 int actualChannel = (actualColor >> (k*8)) & 0xff;
154 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
155 }
156 }
157 }
Khushal51371a42018-05-17 10:41:40 -0700158 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600159}
Khushal51371a42018-05-17 10:41:40 -0700160
Herb Derbyc3415002018-11-08 16:40:26 -0500161sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
162 const SkImageInfo info =
163 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
164 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
165}
166
167const SkSurfaceProps FindSurfaceProps(GrContext* context) {
168 auto surface = MakeSurface(1, 1, context);
169 return surface->props();
170}
171
Ravi Mistrycd21d672018-05-29 21:45:46 +0000172SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400173 GrContext* context, const SkMatrix* matrix = nullptr,
174 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500175 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000176 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400177 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700178 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000179 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700180 surface->readPixels(bitmap, 0, 0);
181 return bitmap;
182}
183
184DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
185 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
186 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400187 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700188
189 auto server_tf = SkTypeface::MakeDefault();
190 auto tf_data = server.serializeTypeface(server_tf.get());
191
192 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
193 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700194 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700195 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700196
197 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
198 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700199}
200
Khushal3e7548c2018-05-23 15:45:01 -0700201DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700202 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
203 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400204 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700205 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700206
207 // Server.
208 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
209 auto serverTfData = server.serializeTypeface(serverTf.get());
210
211 int glyphCount = 10;
212 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500213 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500214 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
herb7022b772019-08-15 22:45:43 -0400215 ctxInfo.grContext()->supportsDistanceFieldText());
Hal Canarye107faa2019-10-23 12:52:33 -0400216 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
217 {
218 SkDynamicMemoryWStream wStream;
219 server.fCapture.reset(new SkTextBlobTrace::Capture);
220 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
221 server.fCapture->dump(&wStream);
222 std::unique_ptr<SkStreamAsset> stream = wStream.detachAsStream();
223 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(stream.get());
224 REPORTER_ASSERT(reporter, trace.size() == 1);
225 }
226 #else
Khushal38a08432018-05-02 10:29:37 -0700227 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Hal Canarye107faa2019-10-23 12:52:33 -0400228 #endif
Khushal38a08432018-05-02 10:29:37 -0700229
230 std::vector<uint8_t> serverStrikeData;
231 server.writeStrikeData(&serverStrikeData);
232
233 // Client.
234 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
235 REPORTER_ASSERT(reporter,
236 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
237 auto clientBlob = buildTextBlob(clientTf, glyphCount);
238
Ravi Mistrycd21d672018-05-29 21:45:46 +0000239 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
240 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600241 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700242 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700243
244 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
245 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700246}
247
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400248DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
249 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
250 SkStrikeServer server(discardableManager.get());
251 SkStrikeClient client(discardableManager, false);
252
253 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500254 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400255 auto serverTfData = server.serializeTypeface(serverTf.get());
256 REPORTER_ASSERT(reporter, serverTf->unique());
257
258 {
259 const SkPaint paint;
260 int glyphCount = 10;
261 auto serverBlob = buildTextBlob(serverTf, glyphCount);
262 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400263 SkTextBlobCacheDiffCanvas cache_diff_canvas(
264 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400265 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
266 REPORTER_ASSERT(reporter, !serverTf->unique());
267
268 std::vector<uint8_t> serverStrikeData;
269 server.writeStrikeData(&serverStrikeData);
270 }
271 REPORTER_ASSERT(reporter, serverTf->unique());
272
273 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
274 discardableManager->unlockAndDeleteAll();
275}
276
Khushal38a08432018-05-02 10:29:37 -0700277DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
278 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
279 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400280 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700281
282 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
283 server.serializeTypeface(serverTf.get());
284 int glyphCount = 10;
285 auto serverBlob = buildTextBlob(serverTf, glyphCount);
286
287 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500288 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700289 SkPaint paint;
290 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
291
292 // The strike from the blob should be locked after it has been drawn on the canvas.
293 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
294 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
295
296 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
297 // again.
298 std::vector<uint8_t> fontData;
299 server.writeStrikeData(&fontData);
300 discardableManager->unlockAll();
301 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
302
303 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
304 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
305 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700306
307 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
308 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700309}
310
311DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
312 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
313 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400314 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700315
316 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
317 server.serializeTypeface(serverTf.get());
318 int glyphCount = 10;
319 auto serverBlob = buildTextBlob(serverTf, glyphCount);
320
321 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500322 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700323 SkPaint paint;
324 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
325 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
326
327 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
328 // handles.
329 std::vector<uint8_t> fontData;
330 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700331
332 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
333 // works. This is a regression test for crbug.com/999682.
334 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
335 server.writeStrikeData(&fontData);
336 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
337
Khushal38a08432018-05-02 10:29:37 -0700338 discardableManager->unlockAndDeleteAll();
339 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700340 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700341
342 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
343 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700344}
345
346DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
347 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
348 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400349 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700350
351 // Server.
352 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
353 auto serverTfData = server.serializeTypeface(serverTf.get());
354
355 int glyphCount = 10;
356 auto serverBlob = buildTextBlob(serverTf, glyphCount);
357
358 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500359 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700360 SkPaint paint;
361 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
362
363 std::vector<uint8_t> serverStrikeData;
364 server.writeStrikeData(&serverStrikeData);
365
366 // Client.
367 REPORTER_ASSERT(reporter,
368 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
369 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
370
371 // The cache remains alive until it is pinned in the discardable manager.
372 SkGraphics::PurgeFontCache();
373 REPORTER_ASSERT(reporter, !clientTf->unique());
374
375 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
376 // clientTf.
377 discardableManager->unlockAndDeleteAll();
378 SkGraphics::PurgeFontCache();
379 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700380
381 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
382 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700383}
Khushalb2e71272018-05-15 12:59:48 -0700384
385DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
386 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
387 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400388 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700389
390 // Server.
391 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
392 auto serverTfData = server.serializeTypeface(serverTf.get());
393
394 int glyphCount = 10;
395 auto serverBlob = buildTextBlob(serverTf, glyphCount);
396
397 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500398 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700399 SkPaint paint;
400 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
401
402 std::vector<uint8_t> serverStrikeData;
403 server.writeStrikeData(&serverStrikeData);
404
405 // Client.
406 REPORTER_ASSERT(reporter,
407 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700408
409 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
410 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700411}
Khushal51371a42018-05-17 10:41:40 -0700412
Khushalcf33b1b2018-08-29 16:16:25 -0700413DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
414 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
415 SkStrikeServer server(discardableManager.get());
416 server.setMaxEntriesInDescriptorMapForTesting(1u);
417 SkStrikeClient client(discardableManager, false);
418
419 {
420 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
421 int glyphCount = 10;
422 auto serverBlob = buildTextBlob(serverTf, glyphCount);
423
424 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500425 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700426 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400427 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700428 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400429 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700430 }
431
432 // Serialize to release the lock from the strike server and delete all current
433 // handles.
434 std::vector<uint8_t> fontData;
435 server.writeStrikeData(&fontData);
436 discardableManager->unlockAndDeleteAll();
437
438 // Use a different typeface. Creating a new strike should evict the previous
439 // one.
440 {
441 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
442 int glyphCount = 10;
443 auto serverBlob = buildTextBlob(serverTf, glyphCount);
444
445 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500446 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700447 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400448 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700449 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400450 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700451 }
452
453 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
454 discardableManager->unlockAndDeleteAll();
455}
456
Khushal3e7548c2018-05-23 15:45:01 -0700457DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700458 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
459 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400460 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700461 SkPaint paint;
462 paint.setStyle(SkPaint::kStroke_Style);
463 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400464 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400465 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700466
467 // Server.
468 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
469 auto serverTfData = server.serializeTypeface(serverTf.get());
470
471 int glyphCount = 10;
472 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500473 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400474 SkTextBlobCacheDiffCanvas cache_diff_canvas(
475 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700476 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
477
478 std::vector<uint8_t> serverStrikeData;
479 server.writeStrikeData(&serverStrikeData);
480
481 // Client.
482 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
483 REPORTER_ASSERT(reporter,
484 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
485 auto clientBlob = buildTextBlob(clientTf, glyphCount);
486
Ravi Mistrycd21d672018-05-29 21:45:46 +0000487 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
488 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600489 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700490 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700491
492 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
493 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700494}
Khushal3e7548c2018-05-23 15:45:01 -0700495
Herb Derby8e318fd2018-08-29 11:04:18 -0400496sk_sp<SkTextBlob> make_blob_causing_fallback(
497 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500498 SkFont font;
499 font.setSubpixel(true);
500 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400501 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500502 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400503
Herb Derbyd249e8c2019-06-03 11:36:01 -0400504 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400505 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400506
507 char s[] = "Skia";
508 int runSize = strlen(s);
509
510 SkTextBlobBuilder builder;
511 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500512 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400513 SkASSERT(runBuffer.utf8text == nullptr);
514 SkASSERT(runBuffer.clusters == nullptr);
515
Mike Reed64670cb2019-04-16 11:37:38 -0700516 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
517 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400518
519 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500520 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400521
Herb Derby5fd955e2019-01-16 11:23:29 -0500522 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400523
524 for (int i = 0; i < runSize; i++) {
525 runBuffer.pos[i] = i * 10;
526 }
527
528 return builder.make();
529}
530
531DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
532 reporter, ctxInfo) {
533 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
534 SkStrikeServer server(discardableManager.get());
535 SkStrikeClient client(discardableManager, false);
536
537 SkPaint paint;
538
539 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
540 // TODO: when the cq bots can handle this font remove the check.
541 if (serverTf == nullptr) {
542 return;
543 }
544 auto serverTfData = server.serializeTypeface(serverTf.get());
545
546 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
547
Herb Derbyc3415002018-11-08 16:40:26 -0500548 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400549 SkTextBlobCacheDiffCanvas cache_diff_canvas(
550 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400551 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
552
553 std::vector<uint8_t> serverStrikeData;
554 server.writeStrikeData(&serverStrikeData);
555
556 // Client.
557 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
558 REPORTER_ASSERT(reporter,
559 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
560
561 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
562
563 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
564 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
565 compare_blobs(expected, actual, reporter);
566 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400567
568 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
569 discardableManager->unlockAndDeleteAll();
570}
571
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400572#if 0
573// TODO: turn this one when I figure out how to deal with the pixel variance from linear
574// interpolation from GPU to GPU.
575DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
576 reporter, ctxInfo) {
577 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
578 SkStrikeServer server(discardableManager.get());
579 SkStrikeClient client(discardableManager, false);
580
581 SkPaint paint;
582
583 auto serverTf = ToolUtils::planet_typeface();
584 // TODO: when the cq bots can handle this font remove the check.
585 if (serverTf == nullptr) {
586 return;
587 }
588 auto serverTfData = server.serializeTypeface(serverTf.get());
589
590 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
591 SkFont font;
592 font.setSubpixel(true);
593 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400594 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400595 font.setTypeface(typeface);
596
597 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
598
599 // Mercury to Uranus.
600 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
601
602 SkTextBlobBuilder builder;
603 SkRect bounds = SkRect::MakeIWH(100, 100);
604 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
605 SkASSERT(runBuffer.utf8text == nullptr);
606 SkASSERT(runBuffer.clusters == nullptr);
607
608 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
609
610 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
611 runBuffer.pos[i] = i * 100;
612 }
613
614 return builder.make();
615 };
616
617 auto serverBlob = makeBlob(serverTf);
618
619 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400620 SkTextBlobCacheDiffCanvas cache_diff_canvas(
621 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400622 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
623
624 std::vector<uint8_t> serverStrikeData;
625 server.writeStrikeData(&serverStrikeData);
626
627 // Client.
628 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
629 REPORTER_ASSERT(reporter,
630 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
631
632 auto clientBlob = makeBlob(clientTf);
633
634 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
635 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
636
637 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
638 // interpolation.
639 compare_blobs(expected, actual, reporter, 36);
640 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400641
642 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
643 discardableManager->unlockAndDeleteAll();
644}
645#endif
646
Herb Derby1a9971e2018-07-19 13:41:15 -0400647DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
648 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
649 SkStrikeServer server(discardableManager.get());
650 SkStrikeClient client(discardableManager, false);
651 SkPaint paint;
652 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400653
654 // Server.
655 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
656 auto serverTfData = server.serializeTypeface(serverTf.get());
657
658 int glyphCount = 10;
659 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500660 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400661 SkTextBlobCacheDiffCanvas cache_diff_canvas(
662 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400663 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
664
665 std::vector<uint8_t> serverStrikeData;
666 server.writeStrikeData(&serverStrikeData);
667
668 // Client.
669 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
670 REPORTER_ASSERT(reporter,
671 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
672 auto clientBlob = buildTextBlob(clientTf, glyphCount);
673
674 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
675 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600676 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400677 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400678
679 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
680 discardableManager->unlockAndDeleteAll();
681}
682
Khushal3e7548c2018-05-23 15:45:01 -0700683DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
684 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
685 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400686 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700687 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500688 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700689
Jim Van Verthce3cf802019-10-10 11:06:20 -0400690 // A scale transform forces fallback to dft.
Mike Reed1f607332020-05-21 12:11:27 -0400691 SkMatrix matrix = SkMatrix::Scale(16, 16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000692 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby3d6bf042020-06-12 11:09:48 -0400693 GrTextContext::Options options =
694 ctxInfo.grContext()->priv().asRecordingContext()->priv().SDFTOptions();
Herb Derby26cbe512018-05-24 14:39:01 -0400695 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500696 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700697
698 // Server.
699 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
700 auto serverTfData = server.serializeTypeface(serverTf.get());
701
702 int glyphCount = 10;
703 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000704 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400705 SkTextBlobCacheDiffCanvas cache_diff_canvas(
706 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700707 cache_diff_canvas.concat(matrix);
708 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
709
710 std::vector<uint8_t> serverStrikeData;
711 server.writeStrikeData(&serverStrikeData);
712
713 // Client.
714 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
715 REPORTER_ASSERT(reporter,
716 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
717 auto clientBlob = buildTextBlob(clientTf, glyphCount);
718
Ravi Mistrycd21d672018-05-29 21:45:46 +0000719 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
720 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600721 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700722 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700723
724 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
725 discardableManager->unlockAndDeleteAll();
726}
Khushald4160832018-05-23 18:16:00 -0700727
728DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
729 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
730 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400731 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700732
733 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
734 auto tfData = server.serializeTypeface(serverTf.get());
735 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
736 REPORTER_ASSERT(reporter, clientTf);
737 int glyphCount = 10;
738 auto clientBlob = buildTextBlob(clientTf, glyphCount);
739
740 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000741 SkPaint paint;
742 SkMatrix matrix = SkMatrix::I();
743 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700744 REPORTER_ASSERT(reporter,
745 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
746 REPORTER_ASSERT(reporter,
747 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
748
749 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
750 // miss.
751 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
752 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
753
754 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
755 discardableManager->unlockAndDeleteAll();
756}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400757
Herb Derbye384a1e2019-05-21 11:27:40 -0400758sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
759 sk_sp<SkTypeface> clientTf = nullptr) {
760 SkFont font;
761 font.setTypeface(serverTf);
762 font.setSize(textSize);
763
764 const char* text = ToolUtils::emoji_sample_text();
765 SkFont serverFont = font;
766 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
767 if (clientTf == nullptr) return blob;
768
769 SkSerialProcs s_procs;
770 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
771 return SkData::MakeUninitialized(1u);
772 };
773 auto serialized = blob->serialize(s_procs);
774
775 SkDeserialProcs d_procs;
776 d_procs.fTypefaceCtx = &clientTf;
777 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
778 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
779 };
780 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
781}
782
783DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
784 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
785 SkStrikeServer server(discardableManager.get());
786 SkStrikeClient client(discardableManager, false);
787
788 auto serverTf = ToolUtils::emoji_typeface();
789 auto serverTfData = server.serializeTypeface(serverTf.get());
790 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
791
Mike Reed69aaee02019-05-30 11:40:51 +0000792 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400793 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
794 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400795 SkTextBlobCacheDiffCanvas cache_diff_canvas(
796 500, 500, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400797 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000798 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400799
800 std::vector<uint8_t> serverStrikeData;
801 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400802 if (!serverStrikeData.empty()) {
803 REPORTER_ASSERT(reporter,
804 client.readStrikeData(serverStrikeData.data(),
805 serverStrikeData.size()));
806 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400807 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
808 REPORTER_ASSERT(reporter, clientBlob);
809
Mike Reed69aaee02019-05-30 11:40:51 +0000810 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400811 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400812 discardableManager->resetCacheMissCounts();
813 }
814
815 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
816 discardableManager->unlockAndDeleteAll();
817}
818