blob: 1b870aafb808b59efb4a1a69349a595c30c909e5 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070025
Khushal38a08432018-05-02 10:29:37 -070026class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
27 public SkStrikeClient::DiscardableHandleManager {
28public:
Khushald4160832018-05-23 18:16:00 -070029 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070030 ~DiscardableManager() override = default;
31
32 // Server implementation.
33 SkDiscardableHandleId createHandle() override {
Herb Derby9b869552019-05-10 12:16:17 -040034 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070035
Khushal38a08432018-05-02 10:29:37 -070036 // Handles starts as locked.
37 fLockedHandles.add(++fNextHandleId);
38 return fNextHandleId;
39 }
40 bool lockHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040041 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070042
Khushal38a08432018-05-02 10:29:37 -070043 if (id <= fLastDeletedHandleId) return false;
44 fLockedHandles.add(id);
45 return true;
46 }
47
48 // Client implementation.
Khushal3de67bd2019-03-15 14:43:15 -070049 bool deleteHandle(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040050 SkAutoMutexExclusive l(fMutex);
Khushal38a08432018-05-02 10:29:37 -070051
Khushal3de67bd2019-03-15 14:43:15 -070052 return id <= fLastDeletedHandleId;
53 }
54
55 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
Herb Derby9b869552019-05-10 12:16:17 -040056 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070057
58 fCacheMissCount[type]++;
59 }
60 bool isHandleDeleted(SkDiscardableHandleId id) override {
Herb Derby9b869552019-05-10 12:16:17 -040061 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070062
63 return id <= fLastDeletedHandleId;
64 }
65
66 void unlockAll() {
Herb Derby9b869552019-05-10 12:16:17 -040067 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070068
69 fLockedHandles.reset();
70 }
Khushal38a08432018-05-02 10:29:37 -070071 void unlockAndDeleteAll() {
Herb Derby9b869552019-05-10 12:16:17 -040072 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070073
74 fLockedHandles.reset();
Khushal38a08432018-05-02 10:29:37 -070075 fLastDeletedHandleId = fNextHandleId;
76 }
Khushal3de67bd2019-03-15 14:43:15 -070077 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
Herb Derby9b869552019-05-10 12:16:17 -040078 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070079
80 return fLockedHandles;
81 }
82 SkDiscardableHandleId handleCount() {
Herb Derby9b869552019-05-10 12:16:17 -040083 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070084
85 return fNextHandleId;
86 }
87 int cacheMissCount(uint32_t type) {
Herb Derby9b869552019-05-10 12:16:17 -040088 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070089
90 return fCacheMissCount[type];
91 }
Khushalfa8ff092018-06-06 17:46:38 -070092 bool hasCacheMiss() const {
Herb Derby9b869552019-05-10 12:16:17 -040093 SkAutoMutexExclusive l(fMutex);
Khushal3de67bd2019-03-15 14:43:15 -070094
Khushalfa8ff092018-06-06 17:46:38 -070095 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
Hal Canarye107faa2019-10-23 12:52:33 -040096 if (fCacheMissCount[i] > 0) { return true; }
Khushalfa8ff092018-06-06 17:46:38 -070097 }
98 return false;
99 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400100 void resetCacheMissCounts() {
101 SkAutoMutexExclusive l(fMutex);
102 sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
103 }
Khushal38a08432018-05-02 10:29:37 -0700104
105private:
Khushal3de67bd2019-03-15 14:43:15 -0700106 // The tests below run in parallel on multiple threads and use the same
107 // process global SkStrikeCache. So the implementation needs to be
108 // thread-safe.
109 mutable SkMutex fMutex;
110
Khushal38a08432018-05-02 10:29:37 -0700111 SkDiscardableHandleId fNextHandleId = 0u;
112 SkDiscardableHandleId fLastDeletedHandleId = 0u;
113 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -0700114 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -0700115};
116
117sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -0500118 SkFont font;
Khushal38a08432018-05-02 10:29:37 -0700119 font.setTypeface(tf);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400120 font.setHinting(SkFontHinting::kNormal);
Mike Reed2ed78202018-11-21 15:10:08 -0500121 font.setSize(1u);
122 font.setEdging(SkFont::Edging::kAntiAlias);
123 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -0700124
125 SkTextBlobBuilder builder;
126 SkRect bounds = SkRect::MakeWH(10, 10);
127 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
128 SkASSERT(runBuffer.utf8text == nullptr);
129 SkASSERT(runBuffer.clusters == nullptr);
130
131 for (int i = 0; i < glyphCount; i++) {
132 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
133 runBuffer.pos[i] = SkIntToScalar(i);
134 }
135 return builder.make();
136}
137
Chris Daltonf9a90a22018-08-28 14:17:55 -0600138static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
139 skiatest::Reporter* reporter, int tolerance = 0) {
140 SkASSERT(expected.width() == actual.width());
141 SkASSERT(expected.height() == actual.height());
142 for (int i = 0; i < expected.width(); ++i) {
143 for (int j = 0; j < expected.height(); ++j) {
144 SkColor expectedColor = expected.getColor(i, j);
145 SkColor actualColor = actual.getColor(i, j);
146 if (0 == tolerance) {
147 REPORTER_ASSERT(reporter, expectedColor == actualColor);
148 } else {
149 for (int k = 0; k < 4; ++k) {
150 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
151 int actualChannel = (actualColor >> (k*8)) & 0xff;
152 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
153 }
154 }
155 }
Khushal51371a42018-05-17 10:41:40 -0700156 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600157}
Khushal51371a42018-05-17 10:41:40 -0700158
Herb Derbyc3415002018-11-08 16:40:26 -0500159sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
160 const SkImageInfo info =
161 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
162 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
163}
164
165const SkSurfaceProps FindSurfaceProps(GrContext* context) {
166 auto surface = MakeSurface(1, 1, context);
167 return surface->props();
168}
169
Ravi Mistrycd21d672018-05-29 21:45:46 +0000170SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400171 GrContext* context, const SkMatrix* matrix = nullptr,
172 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500173 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000174 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400175 surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
Khushal38a08432018-05-02 10:29:37 -0700176 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000177 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700178 surface->readPixels(bitmap, 0, 0);
179 return bitmap;
180}
181
182DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
183 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
184 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400185 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700186
187 auto server_tf = SkTypeface::MakeDefault();
188 auto tf_data = server.serializeTypeface(server_tf.get());
189
190 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
191 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700192 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700193 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700194
195 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
196 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700197}
198
Khushal3e7548c2018-05-23 15:45:01 -0700199DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700200 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
201 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400202 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700203 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700204
205 // Server.
206 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
207 auto serverTfData = server.serializeTypeface(serverTf.get());
208
209 int glyphCount = 10;
210 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500211 auto props = FindSurfaceProps(ctxInfo.grContext());
Mike Reedf922c782019-02-19 15:46:38 -0500212 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
herb7022b772019-08-15 22:45:43 -0400213 ctxInfo.grContext()->supportsDistanceFieldText());
Hal Canarye107faa2019-10-23 12:52:33 -0400214 #ifdef SK_CAPTURE_DRAW_TEXT_BLOB
215 {
216 SkDynamicMemoryWStream wStream;
217 server.fCapture.reset(new SkTextBlobTrace::Capture);
218 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
219 server.fCapture->dump(&wStream);
220 std::unique_ptr<SkStreamAsset> stream = wStream.detachAsStream();
221 std::vector<SkTextBlobTrace::Record> trace = SkTextBlobTrace::CreateBlobTrace(stream.get());
222 REPORTER_ASSERT(reporter, trace.size() == 1);
223 }
224 #else
Khushal38a08432018-05-02 10:29:37 -0700225 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Hal Canarye107faa2019-10-23 12:52:33 -0400226 #endif
Khushal38a08432018-05-02 10:29:37 -0700227
228 std::vector<uint8_t> serverStrikeData;
229 server.writeStrikeData(&serverStrikeData);
230
231 // Client.
232 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
233 REPORTER_ASSERT(reporter,
234 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
235 auto clientBlob = buildTextBlob(clientTf, glyphCount);
236
Ravi Mistrycd21d672018-05-29 21:45:46 +0000237 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
238 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600239 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700240 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700241
242 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
243 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700244}
245
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400246DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
247 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
248 SkStrikeServer server(discardableManager.get());
249 SkStrikeClient client(discardableManager, false);
250
251 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500252 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400253 auto serverTfData = server.serializeTypeface(serverTf.get());
254 REPORTER_ASSERT(reporter, serverTf->unique());
255
256 {
257 const SkPaint paint;
258 int glyphCount = 10;
259 auto serverBlob = buildTextBlob(serverTf, glyphCount);
260 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400261 SkTextBlobCacheDiffCanvas cache_diff_canvas(
262 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400263 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
264 REPORTER_ASSERT(reporter, !serverTf->unique());
265
266 std::vector<uint8_t> serverStrikeData;
267 server.writeStrikeData(&serverStrikeData);
268 }
269 REPORTER_ASSERT(reporter, serverTf->unique());
270
271 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
272 discardableManager->unlockAndDeleteAll();
273}
274
Khushal38a08432018-05-02 10:29:37 -0700275DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
276 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
277 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400278 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700279
280 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
281 server.serializeTypeface(serverTf.get());
282 int glyphCount = 10;
283 auto serverBlob = buildTextBlob(serverTf, glyphCount);
284
285 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500286 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700287 SkPaint paint;
288 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
289
290 // The strike from the blob should be locked after it has been drawn on the canvas.
291 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
292 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
293
294 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
295 // again.
296 std::vector<uint8_t> fontData;
297 server.writeStrikeData(&fontData);
298 discardableManager->unlockAll();
299 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
300
301 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
302 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
303 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700304
305 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
306 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700307}
308
309DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
310 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
311 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400312 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700313
314 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
315 server.serializeTypeface(serverTf.get());
316 int glyphCount = 10;
317 auto serverBlob = buildTextBlob(serverTf, glyphCount);
318
319 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500320 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700321 SkPaint paint;
322 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
323 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
324
325 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
326 // handles.
327 std::vector<uint8_t> fontData;
328 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700329
330 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
331 // works. This is a regression test for crbug.com/999682.
332 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
333 server.writeStrikeData(&fontData);
334 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
335
Khushal38a08432018-05-02 10:29:37 -0700336 discardableManager->unlockAndDeleteAll();
337 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700338 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700339
340 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
341 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700342}
343
344DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
345 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
346 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400347 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700348
349 // Server.
350 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
351 auto serverTfData = server.serializeTypeface(serverTf.get());
352
353 int glyphCount = 10;
354 auto serverBlob = buildTextBlob(serverTf, glyphCount);
355
356 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500357 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700358 SkPaint paint;
359 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
360
361 std::vector<uint8_t> serverStrikeData;
362 server.writeStrikeData(&serverStrikeData);
363
364 // Client.
365 REPORTER_ASSERT(reporter,
366 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
367 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
368
369 // The cache remains alive until it is pinned in the discardable manager.
370 SkGraphics::PurgeFontCache();
371 REPORTER_ASSERT(reporter, !clientTf->unique());
372
373 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
374 // clientTf.
375 discardableManager->unlockAndDeleteAll();
376 SkGraphics::PurgeFontCache();
377 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700378
379 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
380 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700381}
Khushalb2e71272018-05-15 12:59:48 -0700382
383DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
384 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
385 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400386 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700387
388 // Server.
389 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
390 auto serverTfData = server.serializeTypeface(serverTf.get());
391
392 int glyphCount = 10;
393 auto serverBlob = buildTextBlob(serverTf, glyphCount);
394
395 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500396 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700397 SkPaint paint;
398 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
399
400 std::vector<uint8_t> serverStrikeData;
401 server.writeStrikeData(&serverStrikeData);
402
403 // Client.
404 REPORTER_ASSERT(reporter,
405 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Khushal3e7548c2018-05-23 15:45:01 -0700406
407 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
408 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700409}
Khushal51371a42018-05-17 10:41:40 -0700410
Khushalcf33b1b2018-08-29 16:16:25 -0700411DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
412 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
413 SkStrikeServer server(discardableManager.get());
414 server.setMaxEntriesInDescriptorMapForTesting(1u);
415 SkStrikeClient client(discardableManager, false);
416
417 {
418 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
419 int glyphCount = 10;
420 auto serverBlob = buildTextBlob(serverTf, glyphCount);
421
422 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500423 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700424 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400425 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700426 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400427 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700428 }
429
430 // Serialize to release the lock from the strike server and delete all current
431 // handles.
432 std::vector<uint8_t> fontData;
433 server.writeStrikeData(&fontData);
434 discardableManager->unlockAndDeleteAll();
435
436 // Use a different typeface. Creating a new strike should evict the previous
437 // one.
438 {
439 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
440 int glyphCount = 10;
441 auto serverBlob = buildTextBlob(serverTf, glyphCount);
442
443 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500444 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700445 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400446 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700447 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400448 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700449 }
450
451 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
452 discardableManager->unlockAndDeleteAll();
453}
454
Khushal3e7548c2018-05-23 15:45:01 -0700455DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700456 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
457 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400458 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700459 SkPaint paint;
460 paint.setStyle(SkPaint::kStroke_Style);
461 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400462 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400463 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700464
465 // Server.
466 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
467 auto serverTfData = server.serializeTypeface(serverTf.get());
468
469 int glyphCount = 10;
470 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500471 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400472 SkTextBlobCacheDiffCanvas cache_diff_canvas(
473 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700474 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
475
476 std::vector<uint8_t> serverStrikeData;
477 server.writeStrikeData(&serverStrikeData);
478
479 // Client.
480 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
481 REPORTER_ASSERT(reporter,
482 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
483 auto clientBlob = buildTextBlob(clientTf, glyphCount);
484
Ravi Mistrycd21d672018-05-29 21:45:46 +0000485 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
486 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600487 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700488 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700489
490 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
491 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700492}
Khushal3e7548c2018-05-23 15:45:01 -0700493
Herb Derby8e318fd2018-08-29 11:04:18 -0400494sk_sp<SkTextBlob> make_blob_causing_fallback(
495 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500496 SkFont font;
497 font.setSubpixel(true);
498 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400499 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500500 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400501
Herb Derbyd249e8c2019-06-03 11:36:01 -0400502 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400503 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400504
505 char s[] = "Skia";
506 int runSize = strlen(s);
507
508 SkTextBlobBuilder builder;
509 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500510 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400511 SkASSERT(runBuffer.utf8text == nullptr);
512 SkASSERT(runBuffer.clusters == nullptr);
513
Mike Reed64670cb2019-04-16 11:37:38 -0700514 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
515 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400516
517 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500518 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400519
Herb Derby5fd955e2019-01-16 11:23:29 -0500520 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400521
522 for (int i = 0; i < runSize; i++) {
523 runBuffer.pos[i] = i * 10;
524 }
525
526 return builder.make();
527}
528
529DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
530 reporter, ctxInfo) {
531 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
532 SkStrikeServer server(discardableManager.get());
533 SkStrikeClient client(discardableManager, false);
534
535 SkPaint paint;
536
537 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
538 // TODO: when the cq bots can handle this font remove the check.
539 if (serverTf == nullptr) {
540 return;
541 }
542 auto serverTfData = server.serializeTypeface(serverTf.get());
543
544 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
545
Herb Derbyc3415002018-11-08 16:40:26 -0500546 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400547 SkTextBlobCacheDiffCanvas cache_diff_canvas(
548 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400549 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
550
551 std::vector<uint8_t> serverStrikeData;
552 server.writeStrikeData(&serverStrikeData);
553
554 // Client.
555 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
556 REPORTER_ASSERT(reporter,
557 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
558
559 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
560
561 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
562 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
563 compare_blobs(expected, actual, reporter);
564 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby8e318fd2018-08-29 11:04:18 -0400565
566 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
567 discardableManager->unlockAndDeleteAll();
568}
569
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400570#if 0
571// TODO: turn this one when I figure out how to deal with the pixel variance from linear
572// interpolation from GPU to GPU.
573DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
574 reporter, ctxInfo) {
575 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
576 SkStrikeServer server(discardableManager.get());
577 SkStrikeClient client(discardableManager, false);
578
579 SkPaint paint;
580
581 auto serverTf = ToolUtils::planet_typeface();
582 // TODO: when the cq bots can handle this font remove the check.
583 if (serverTf == nullptr) {
584 return;
585 }
586 auto serverTfData = server.serializeTypeface(serverTf.get());
587
588 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
589 SkFont font;
590 font.setSubpixel(true);
591 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400592 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400593 font.setTypeface(typeface);
594
595 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
596
597 // Mercury to Uranus.
598 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
599
600 SkTextBlobBuilder builder;
601 SkRect bounds = SkRect::MakeIWH(100, 100);
602 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
603 SkASSERT(runBuffer.utf8text == nullptr);
604 SkASSERT(runBuffer.clusters == nullptr);
605
606 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
607
608 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
609 runBuffer.pos[i] = i * 100;
610 }
611
612 return builder.make();
613 };
614
615 auto serverBlob = makeBlob(serverTf);
616
617 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400618 SkTextBlobCacheDiffCanvas cache_diff_canvas(
619 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400620 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
621
622 std::vector<uint8_t> serverStrikeData;
623 server.writeStrikeData(&serverStrikeData);
624
625 // Client.
626 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
627 REPORTER_ASSERT(reporter,
628 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
629
630 auto clientBlob = makeBlob(clientTf);
631
632 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
633 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
634
635 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
636 // interpolation.
637 compare_blobs(expected, actual, reporter, 36);
638 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400639
640 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
641 discardableManager->unlockAndDeleteAll();
642}
643#endif
644
Herb Derby1a9971e2018-07-19 13:41:15 -0400645DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
646 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
647 SkStrikeServer server(discardableManager.get());
648 SkStrikeClient client(discardableManager, false);
649 SkPaint paint;
650 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400651
652 // Server.
653 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
654 auto serverTfData = server.serializeTypeface(serverTf.get());
655
656 int glyphCount = 10;
657 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500658 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400659 SkTextBlobCacheDiffCanvas cache_diff_canvas(
660 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400661 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
662
663 std::vector<uint8_t> serverStrikeData;
664 server.writeStrikeData(&serverStrikeData);
665
666 // Client.
667 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
668 REPORTER_ASSERT(reporter,
669 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
670 auto clientBlob = buildTextBlob(clientTf, glyphCount);
671
672 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
673 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600674 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400675 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derby1a9971e2018-07-19 13:41:15 -0400676
677 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
678 discardableManager->unlockAndDeleteAll();
679}
680
Khushal3e7548c2018-05-23 15:45:01 -0700681DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
682 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
683 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400684 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700685 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500686 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700687
Jim Van Verthce3cf802019-10-10 11:06:20 -0400688 // A scale transform forces fallback to dft.
689 SkMatrix matrix = SkMatrix::MakeScale(16);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000690 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400691 GrTextContext::Options options;
692 GrTextContext::SanitizeOptions(&options);
693 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500694 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700695
696 // Server.
697 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
698 auto serverTfData = server.serializeTypeface(serverTf.get());
699
700 int glyphCount = 10;
701 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000702 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400703 SkTextBlobCacheDiffCanvas cache_diff_canvas(
704 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700705 cache_diff_canvas.concat(matrix);
706 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
707
708 std::vector<uint8_t> serverStrikeData;
709 server.writeStrikeData(&serverStrikeData);
710
711 // Client.
712 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
713 REPORTER_ASSERT(reporter,
714 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
715 auto clientBlob = buildTextBlob(clientTf, glyphCount);
716
Ravi Mistrycd21d672018-05-29 21:45:46 +0000717 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
718 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600719 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700720 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700721
722 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
723 discardableManager->unlockAndDeleteAll();
724}
Khushald4160832018-05-23 18:16:00 -0700725
726DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
727 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
728 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400729 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700730
731 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
732 auto tfData = server.serializeTypeface(serverTf.get());
733 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
734 REPORTER_ASSERT(reporter, clientTf);
735 int glyphCount = 10;
736 auto clientBlob = buildTextBlob(clientTf, glyphCount);
737
738 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000739 SkPaint paint;
740 SkMatrix matrix = SkMatrix::I();
741 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700742 REPORTER_ASSERT(reporter,
743 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
744 REPORTER_ASSERT(reporter,
745 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
746
747 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
748 // miss.
749 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
750 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
751
752 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
753 discardableManager->unlockAndDeleteAll();
754}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400755
Herb Derbye384a1e2019-05-21 11:27:40 -0400756sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
757 sk_sp<SkTypeface> clientTf = nullptr) {
758 SkFont font;
759 font.setTypeface(serverTf);
760 font.setSize(textSize);
761
762 const char* text = ToolUtils::emoji_sample_text();
763 SkFont serverFont = font;
764 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
765 if (clientTf == nullptr) return blob;
766
767 SkSerialProcs s_procs;
768 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
769 return SkData::MakeUninitialized(1u);
770 };
771 auto serialized = blob->serialize(s_procs);
772
773 SkDeserialProcs d_procs;
774 d_procs.fTypefaceCtx = &clientTf;
775 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
776 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
777 };
778 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
779}
780
781DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
782 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
783 SkStrikeServer server(discardableManager.get());
784 SkStrikeClient client(discardableManager, false);
785
786 auto serverTf = ToolUtils::emoji_typeface();
787 auto serverTfData = server.serializeTypeface(serverTf.get());
788 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
789
Mike Reed69aaee02019-05-30 11:40:51 +0000790 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400791 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
792 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400793 SkTextBlobCacheDiffCanvas cache_diff_canvas(
794 500, 500, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400795 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000796 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400797
798 std::vector<uint8_t> serverStrikeData;
799 server.writeStrikeData(&serverStrikeData);
Herb Derbyf5e9b422019-10-22 16:06:22 -0400800 if (!serverStrikeData.empty()) {
801 REPORTER_ASSERT(reporter,
802 client.readStrikeData(serverStrikeData.data(),
803 serverStrikeData.size()));
804 }
Herb Derbye384a1e2019-05-21 11:27:40 -0400805 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
806 REPORTER_ASSERT(reporter, clientBlob);
807
Mike Reed69aaee02019-05-30 11:40:51 +0000808 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400809 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbye384a1e2019-05-21 11:27:40 -0400810 discardableManager->resetCacheMissCounts();
811 }
812
813 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
814 discardableManager->unlockAndDeleteAll();
815}
816