blob: 92e1fecc4bb1ab65be2d4a81b5709a0df851ea0e [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkStrike.h"
15#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) {
96 if (fCacheMissCount[i] > 0) return true;
97 }
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());
Khushal38a08432018-05-02 10:29:37 -0700214 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
215
216 std::vector<uint8_t> serverStrikeData;
217 server.writeStrikeData(&serverStrikeData);
218
219 // Client.
220 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
221 REPORTER_ASSERT(reporter,
222 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
223 auto clientBlob = buildTextBlob(clientTf, glyphCount);
224
Ravi Mistrycd21d672018-05-29 21:45:46 +0000225 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
226 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600227 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700228 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700229
230 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
231 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700232}
233
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400234DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
235 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
236 SkStrikeServer server(discardableManager.get());
237 SkStrikeClient client(discardableManager, false);
238
239 // Server.
Mike Klein0cffcbf92019-03-20 11:08:46 -0500240 auto serverTf = TestEmptyTypeface::Make();
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400241 auto serverTfData = server.serializeTypeface(serverTf.get());
242 REPORTER_ASSERT(reporter, serverTf->unique());
243
244 {
245 const SkPaint paint;
246 int glyphCount = 10;
247 auto serverBlob = buildTextBlob(serverTf, glyphCount);
248 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400249 SkTextBlobCacheDiffCanvas cache_diff_canvas(
250 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400251 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
252 REPORTER_ASSERT(reporter, !serverTf->unique());
253
254 std::vector<uint8_t> serverStrikeData;
255 server.writeStrikeData(&serverStrikeData);
256 }
257 REPORTER_ASSERT(reporter, serverTf->unique());
258
259 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
260 discardableManager->unlockAndDeleteAll();
261}
262
Khushal38a08432018-05-02 10:29:37 -0700263DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
264 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
265 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400266 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700267
268 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
269 server.serializeTypeface(serverTf.get());
270 int glyphCount = 10;
271 auto serverBlob = buildTextBlob(serverTf, glyphCount);
272
273 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500274 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700275 SkPaint paint;
276 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
277
278 // The strike from the blob should be locked after it has been drawn on the canvas.
279 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
280 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
281
282 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
283 // again.
284 std::vector<uint8_t> fontData;
285 server.writeStrikeData(&fontData);
286 discardableManager->unlockAll();
287 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
288
289 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
290 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
291 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700292
293 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
294 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700295}
296
297DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
298 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
299 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400300 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700301
302 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
303 server.serializeTypeface(serverTf.get());
304 int glyphCount = 10;
305 auto serverBlob = buildTextBlob(serverTf, glyphCount);
306
307 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500308 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700309 SkPaint paint;
310 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
311 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
312
313 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
314 // handles.
315 std::vector<uint8_t> fontData;
316 server.writeStrikeData(&fontData);
Khushal498a9b22019-09-04 16:19:22 -0700317
318 // Another analysis pass, to ensure that deleting handles after a complete cache hit still
319 // works. This is a regression test for crbug.com/999682.
320 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
321 server.writeStrikeData(&fontData);
322 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
323
Khushal38a08432018-05-02 10:29:37 -0700324 discardableManager->unlockAndDeleteAll();
325 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700326 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700327
328 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
329 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700330}
331
332DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
333 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
334 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400335 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700336
337 // Server.
338 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
339 auto serverTfData = server.serializeTypeface(serverTf.get());
340
341 int glyphCount = 10;
342 auto serverBlob = buildTextBlob(serverTf, glyphCount);
343
344 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500345 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushal38a08432018-05-02 10:29:37 -0700346 SkPaint paint;
347 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
348
349 std::vector<uint8_t> serverStrikeData;
350 server.writeStrikeData(&serverStrikeData);
351
352 // Client.
353 REPORTER_ASSERT(reporter,
354 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
355 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
356
357 // The cache remains alive until it is pinned in the discardable manager.
358 SkGraphics::PurgeFontCache();
359 REPORTER_ASSERT(reporter, !clientTf->unique());
360
361 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
362 // clientTf.
363 discardableManager->unlockAndDeleteAll();
364 SkGraphics::PurgeFontCache();
365 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700366
367 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
368 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700369}
Khushalb2e71272018-05-15 12:59:48 -0700370
371DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
372 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
373 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400374 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700375
376 // Server.
377 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
378 auto serverTfData = server.serializeTypeface(serverTf.get());
379
380 int glyphCount = 10;
381 auto serverBlob = buildTextBlob(serverTf, glyphCount);
382
383 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500384 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalb2e71272018-05-15 12:59:48 -0700385 SkPaint paint;
386 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
387
388 std::vector<uint8_t> serverStrikeData;
389 server.writeStrikeData(&serverStrikeData);
390
391 // Client.
392 REPORTER_ASSERT(reporter,
393 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400394 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700395
396 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
397 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700398}
Khushal51371a42018-05-17 10:41:40 -0700399
Khushalcf33b1b2018-08-29 16:16:25 -0700400DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
401 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
402 SkStrikeServer server(discardableManager.get());
403 server.setMaxEntriesInDescriptorMapForTesting(1u);
404 SkStrikeClient client(discardableManager, false);
405
406 {
407 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
408 int glyphCount = 10;
409 auto serverBlob = buildTextBlob(serverTf, glyphCount);
410
411 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500412 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700413 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400414 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 0u);
Khushalcf33b1b2018-08-29 16:16:25 -0700415 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400416 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700417 }
418
419 // Serialize to release the lock from the strike server and delete all current
420 // handles.
421 std::vector<uint8_t> fontData;
422 server.writeStrikeData(&fontData);
423 discardableManager->unlockAndDeleteAll();
424
425 // Use a different typeface. Creating a new strike should evict the previous
426 // one.
427 {
428 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
429 int glyphCount = 10;
430 auto serverBlob = buildTextBlob(serverTf, glyphCount);
431
432 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Mike Reedf922c782019-02-19 15:46:38 -0500433 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
Khushalcf33b1b2018-08-29 16:16:25 -0700434 SkPaint paint;
Herb Derbya4c78832019-08-27 16:03:45 -0400435 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700436 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Herb Derbya4c78832019-08-27 16:03:45 -0400437 REPORTER_ASSERT(reporter, server.remoteStrikeMapSizeForTesting() == 1u);
Khushalcf33b1b2018-08-29 16:16:25 -0700438 }
439
440 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
441 discardableManager->unlockAndDeleteAll();
442}
443
Khushal3e7548c2018-05-23 15:45:01 -0700444DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700445 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
446 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400447 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700448 SkPaint paint;
449 paint.setStyle(SkPaint::kStroke_Style);
450 paint.setStrokeWidth(0);
Herb Derbyd249e8c2019-06-03 11:36:01 -0400451 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400452 SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700453
454 // Server.
455 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
456 auto serverTfData = server.serializeTypeface(serverTf.get());
457
458 int glyphCount = 10;
459 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500460 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400461 SkTextBlobCacheDiffCanvas cache_diff_canvas(
462 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal51371a42018-05-17 10:41:40 -0700463 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
464
465 std::vector<uint8_t> serverStrikeData;
466 server.writeStrikeData(&serverStrikeData);
467
468 // Client.
469 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
470 REPORTER_ASSERT(reporter,
471 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
472 auto clientBlob = buildTextBlob(clientTf, glyphCount);
473
Ravi Mistrycd21d672018-05-29 21:45:46 +0000474 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
475 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600476 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700477 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400478 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700479
480 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
481 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700482}
Khushal3e7548c2018-05-23 15:45:01 -0700483
Herb Derby8e318fd2018-08-29 11:04:18 -0400484sk_sp<SkTextBlob> make_blob_causing_fallback(
485 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500486 SkFont font;
487 font.setSubpixel(true);
488 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400489 font.setHinting(SkFontHinting::kNormal);
Mike Reed70914f52018-11-23 13:08:33 -0500490 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400491
Herb Derbyd249e8c2019-06-03 11:36:01 -0400492 REPORTER_ASSERT(reporter,
Herb Derby36a54c12019-06-06 10:50:56 -0400493 !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400494
495 char s[] = "Skia";
496 int runSize = strlen(s);
497
498 SkTextBlobBuilder builder;
499 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500500 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400501 SkASSERT(runBuffer.utf8text == nullptr);
502 SkASSERT(runBuffer.clusters == nullptr);
503
Mike Reed64670cb2019-04-16 11:37:38 -0700504 SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
505 runBuffer.glyphs, runSize);
Herb Derby8e318fd2018-08-29 11:04:18 -0400506
507 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500508 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400509
Herb Derby5fd955e2019-01-16 11:23:29 -0500510 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400511
512 for (int i = 0; i < runSize; i++) {
513 runBuffer.pos[i] = i * 10;
514 }
515
516 return builder.make();
517}
518
519DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
520 reporter, ctxInfo) {
521 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
522 SkStrikeServer server(discardableManager.get());
523 SkStrikeClient client(discardableManager, false);
524
525 SkPaint paint;
526
527 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
528 // TODO: when the cq bots can handle this font remove the check.
529 if (serverTf == nullptr) {
530 return;
531 }
532 auto serverTfData = server.serializeTypeface(serverTf.get());
533
534 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
535
Herb Derbyc3415002018-11-08 16:40:26 -0500536 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400537 SkTextBlobCacheDiffCanvas cache_diff_canvas(
538 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby8e318fd2018-08-29 11:04:18 -0400539 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
540
541 std::vector<uint8_t> serverStrikeData;
542 server.writeStrikeData(&serverStrikeData);
543
544 // Client.
545 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
546 REPORTER_ASSERT(reporter,
547 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
548
549 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
550
551 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
552 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
553 compare_blobs(expected, actual, reporter);
554 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
555 SkStrikeCache::ValidateGlyphCacheDataSize();
556
557 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
558 discardableManager->unlockAndDeleteAll();
559}
560
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400561#if 0
562// TODO: turn this one when I figure out how to deal with the pixel variance from linear
563// interpolation from GPU to GPU.
564DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
565 reporter, ctxInfo) {
566 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
567 SkStrikeServer server(discardableManager.get());
568 SkStrikeClient client(discardableManager, false);
569
570 SkPaint paint;
571
572 auto serverTf = ToolUtils::planet_typeface();
573 // TODO: when the cq bots can handle this font remove the check.
574 if (serverTf == nullptr) {
575 return;
576 }
577 auto serverTfData = server.serializeTypeface(serverTf.get());
578
579 auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
580 SkFont font;
581 font.setSubpixel(true);
582 font.setSize(96);
Ben Wagner5785e4a2019-05-07 16:50:29 -0400583 font.setHinting(SkFontHinting::kNormal);
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400584 font.setTypeface(typeface);
585
586 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
587
588 // Mercury to Uranus.
589 SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
590
591 SkTextBlobBuilder builder;
592 SkRect bounds = SkRect::MakeIWH(100, 100);
593 const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
594 SkASSERT(runBuffer.utf8text == nullptr);
595 SkASSERT(runBuffer.clusters == nullptr);
596
597 std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
598
599 for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
600 runBuffer.pos[i] = i * 100;
601 }
602
603 return builder.make();
604 };
605
606 auto serverBlob = makeBlob(serverTf);
607
608 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400609 SkTextBlobCacheDiffCanvas cache_diff_canvas(
610 800, 800, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbyb1dbbc82019-03-22 17:05:14 -0400611 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
612
613 std::vector<uint8_t> serverStrikeData;
614 server.writeStrikeData(&serverStrikeData);
615
616 // Client.
617 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
618 REPORTER_ASSERT(reporter,
619 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
620
621 auto clientBlob = makeBlob(clientTf);
622
623 SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
624 SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
625
626 // Pixel variance can be high because of the atlas placement, and large scaling in the linear
627 // interpolation.
628 compare_blobs(expected, actual, reporter, 36);
629 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
630 SkStrikeCache::ValidateGlyphCacheDataSize();
631
632 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
633 discardableManager->unlockAndDeleteAll();
634}
635#endif
636
Herb Derby1a9971e2018-07-19 13:41:15 -0400637DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
638 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
639 SkStrikeServer server(discardableManager.get());
640 SkStrikeClient client(discardableManager, false);
641 SkPaint paint;
642 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400643
644 // Server.
645 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
646 auto serverTfData = server.serializeTypeface(serverTf.get());
647
648 int glyphCount = 10;
649 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500650 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400651 SkTextBlobCacheDiffCanvas cache_diff_canvas(
652 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derby1a9971e2018-07-19 13:41:15 -0400653 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
654
655 std::vector<uint8_t> serverStrikeData;
656 server.writeStrikeData(&serverStrikeData);
657
658 // Client.
659 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
660 REPORTER_ASSERT(reporter,
661 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
662 auto clientBlob = buildTextBlob(clientTf, glyphCount);
663
664 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
665 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600666 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400667 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
668 SkStrikeCache::ValidateGlyphCacheDataSize();
669
670 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
671 discardableManager->unlockAndDeleteAll();
672}
673
Khushal3e7548c2018-05-23 15:45:01 -0700674DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
675 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
676 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400677 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700678 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500679 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700680
681 // A perspective transform forces fallback to dft.
682 SkMatrix matrix = SkMatrix::I();
683 matrix[SkMatrix::kMPersp0] = 0.5f;
684 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000685 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400686 GrTextContext::Options options;
687 GrTextContext::SanitizeOptions(&options);
688 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500689 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700690
691 // Server.
692 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
693 auto serverTfData = server.serializeTypeface(serverTf.get());
694
695 int glyphCount = 10;
696 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000697 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
herb7022b772019-08-15 22:45:43 -0400698 SkTextBlobCacheDiffCanvas cache_diff_canvas(
699 10, 10, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Khushal3e7548c2018-05-23 15:45:01 -0700700 cache_diff_canvas.concat(matrix);
701 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
702
703 std::vector<uint8_t> serverStrikeData;
704 server.writeStrikeData(&serverStrikeData);
705
706 // Client.
707 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
708 REPORTER_ASSERT(reporter,
709 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
710 auto clientBlob = buildTextBlob(clientTf, glyphCount);
711
Ravi Mistrycd21d672018-05-29 21:45:46 +0000712 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
713 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600714 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700715 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400716 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700717
718 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
719 discardableManager->unlockAndDeleteAll();
720}
Khushald4160832018-05-23 18:16:00 -0700721
722DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
723 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
724 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400725 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700726
727 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
728 auto tfData = server.serializeTypeface(serverTf.get());
729 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
730 REPORTER_ASSERT(reporter, clientTf);
731 int glyphCount = 10;
732 auto clientBlob = buildTextBlob(clientTf, glyphCount);
733
734 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000735 SkPaint paint;
736 SkMatrix matrix = SkMatrix::I();
737 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700738 REPORTER_ASSERT(reporter,
739 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
740 REPORTER_ASSERT(reporter,
741 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
742
743 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
744 // miss.
745 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
746 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
747
748 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
749 discardableManager->unlockAndDeleteAll();
750}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400751
Herb Derbye384a1e2019-05-21 11:27:40 -0400752sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
753 sk_sp<SkTypeface> clientTf = nullptr) {
754 SkFont font;
755 font.setTypeface(serverTf);
756 font.setSize(textSize);
757
758 const char* text = ToolUtils::emoji_sample_text();
759 SkFont serverFont = font;
760 auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
761 if (clientTf == nullptr) return blob;
762
763 SkSerialProcs s_procs;
764 s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
765 return SkData::MakeUninitialized(1u);
766 };
767 auto serialized = blob->serialize(s_procs);
768
769 SkDeserialProcs d_procs;
770 d_procs.fTypefaceCtx = &clientTf;
771 d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
772 return *(static_cast<sk_sp<SkTypeface>*>(ctx));
773 };
774 return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
775}
776
777DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
778 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
779 SkStrikeServer server(discardableManager.get());
780 SkStrikeClient client(discardableManager, false);
781
782 auto serverTf = ToolUtils::emoji_typeface();
783 auto serverTfData = server.serializeTypeface(serverTf.get());
784 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
785
Mike Reed69aaee02019-05-30 11:40:51 +0000786 for (SkScalar textSize : { 70, 180, 270, 340}) {
Herb Derbye384a1e2019-05-21 11:27:40 -0400787 auto serverBlob = MakeEmojiBlob(serverTf, textSize);
788 auto props = FindSurfaceProps(ctxInfo.grContext());
herb7022b772019-08-15 22:45:43 -0400789 SkTextBlobCacheDiffCanvas cache_diff_canvas(
790 500, 500, props, &server, ctxInfo.grContext()->supportsDistanceFieldText());
Herb Derbye384a1e2019-05-21 11:27:40 -0400791 SkPaint paint;
Mike Reed69aaee02019-05-30 11:40:51 +0000792 cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
Herb Derbye384a1e2019-05-21 11:27:40 -0400793
794 std::vector<uint8_t> serverStrikeData;
795 server.writeStrikeData(&serverStrikeData);
796
797 REPORTER_ASSERT(reporter,
798 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
799 auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
800 REPORTER_ASSERT(reporter, clientBlob);
801
Mike Reed69aaee02019-05-30 11:40:51 +0000802 RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
Herb Derbye384a1e2019-05-21 11:27:40 -0400803 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
804 SkStrikeCache::ValidateGlyphCacheDataSize();
805 discardableManager->resetCacheMissCounts();
806 }
807
808 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
809 discardableManager->unlockAndDeleteAll();
810}
811
Herb Derby65b7bfc2018-06-05 13:32:12 -0400812DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700813 // Build proxy typeface on the client for initializing the cache.
814 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
815 SkStrikeServer server(discardableManager.get());
816 SkStrikeClient client(discardableManager, false);
817
818 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
819 auto tfData = server.serializeTypeface(serverTf.get());
820 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
821 REPORTER_ASSERT(reporter, clientTf);
822
Mike Reed4529cb52018-11-06 08:03:42 -0500823 SkFont font;
824 font.setTypeface(clientTf);
Herb Derby511dcfc2019-06-24 12:58:41 -0400825 font.setSubpixel(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400826 SkPaint paint;
827 paint.setAntiAlias(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400828 paint.setColor(SK_ColorRED);
829
830 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400831 const uint8_t glyphImage[] = {0xFF, 0xFF};
832
Herb Derby5c0c7982018-06-21 15:15:50 -0400833 SkStrikeCache strikeCache;
834
Herb Derby65b7bfc2018-06-05 13:32:12 -0400835 // Build a fallback cache.
836 {
837 SkAutoDescriptor ad;
838 SkScalerContextRec rec;
839 SkScalerContextEffects effects;
840 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500841 SkScalerContext::MakeRecAndEffects(
842 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500843 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400844 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
845
Herb Derby5c0c7982018-06-21 15:15:50 -0400846 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby37216882019-06-13 17:24:24 -0400847 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, SkMask::kA8_Format, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400848 fallbackCache->glyphFromPrototype(proto, (void*)glyphImage);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400849 }
850
851 // Make sure we can find the fall back cache.
852 {
853 SkAutoDescriptor ad;
854 SkScalerContextRec rec;
855 SkScalerContextEffects effects;
856 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500857 SkScalerContext::MakeRecAndEffects(
858 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500859 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400860 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400861 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400862 REPORTER_ASSERT(reporter, !(testCache == nullptr));
863 }
864
Khushal8523b6b2018-06-12 11:26:17 -0700865 // Create the target cache.
866 SkExclusiveStrikePtr testCache;
867 SkAutoDescriptor ad;
868 SkScalerContextRec rec;
869 SkScalerContextEffects effects;
870 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
Herb Derbyc3415002018-11-08 16:40:26 -0500871 SkScalerContext::MakeRecAndEffects(
872 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500873 SkMatrix::I(), &rec, &effects);
Khushal8523b6b2018-06-12 11:26:17 -0700874 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400875 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700876 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400877 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700878 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400879 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
880 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400881
Khushal8523b6b2018-06-12 11:26:17 -0700882 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400883 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400884 SkPoint pt{SkFixedToScalar(lostGlyphID.getSubXFixed()),
885 SkFixedToScalar(lostGlyphID.getSubYFixed())};
886 SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
Herb Derbya4eecd82019-06-25 15:05:30 -0400887 testCache->prepareImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400888
Herb Derby511dcfc2019-06-24 12:58:41 -0400889 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
890 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
891 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
892 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400893 }
894
Khushal8523b6b2018-06-12 11:26:17 -0700895 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400896 {
Herb Derby511dcfc2019-06-24 12:58:41 -0400897 SkPoint pt{SkFixedToScalar(SK_FixedQuarter),
898 SkFixedToScalar(SK_FixedQuarter)};
899 SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
Herb Derbya4eecd82019-06-25 15:05:30 -0400900 testCache->prepareImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400901
Herb Derby511dcfc2019-06-24 12:58:41 -0400902 REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
903 REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
904 REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
905 REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400906 }
907
Khushal8523b6b2018-06-12 11:26:17 -0700908 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
909 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
910 i == SkStrikeClient::CacheMissType::kFontMetrics) {
911 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
912 } else {
913 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
914 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400915 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400916 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400917
Khushal8523b6b2018-06-12 11:26:17 -0700918 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
919 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400920}
Khushal4010c792018-06-13 09:44:23 -0700921
922DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
923 // Build proxy typeface on the client for initializing the cache.
924 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
925 SkStrikeServer server(discardableManager.get());
926 SkStrikeClient client(discardableManager, false);
927
928 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
929 auto tfData = server.serializeTypeface(serverTf.get());
930 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
931 REPORTER_ASSERT(reporter, clientTf);
932
Mike Reed4529cb52018-11-06 08:03:42 -0500933 SkFont font;
Herb Derbye7f662b2018-12-17 12:12:56 -0500934 font.setEdging(SkFont::Edging::kAntiAlias);
Khushal4010c792018-06-13 09:44:23 -0700935 SkPaint paint;
Khushal4010c792018-06-13 09:44:23 -0700936 paint.setColor(SK_ColorRED);
937
938 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
939 const uint8_t glyphImage[] = {0xFF, 0xFF};
Herb Derby37216882019-06-13 17:24:24 -0400940 SkMask::Format realMask;
941 SkMask::Format fakeMask;
Khushal4010c792018-06-13 09:44:23 -0700942
Herb Derby5c0c7982018-06-21 15:15:50 -0400943 SkStrikeCache strikeCache;
944
Khushal4010c792018-06-13 09:44:23 -0700945 {
946 SkAutoDescriptor ad;
947 SkScalerContextRec rec;
948 SkScalerContextEffects effects;
949 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500950 font.setTypeface(serverTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500951 SkScalerContext::MakeRecAndEffects(
952 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500953 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700954 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
955
956 auto context = serverTf->createScalerContext(effects, desc, false);
Herb Derbyf6fca262019-01-09 15:13:54 -0500957 SkGlyph glyph{lostGlyphID};
Khushal4010c792018-06-13 09:44:23 -0700958 context->getMetrics(&glyph);
Herb Derby37216882019-06-13 17:24:24 -0400959 realMask = glyph.maskFormat();
Khushal4010c792018-06-13 09:44:23 -0700960 }
961
962 // Build a fallback cache.
963 {
964 SkAutoDescriptor ad;
965 SkScalerContextRec rec;
966 SkScalerContextEffects effects;
967 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500968 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500969 SkScalerContext::MakeRecAndEffects(
970 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500971 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700972 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
973
Herb Derby5c0c7982018-06-21 15:15:50 -0400974 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700975 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
Herb Derby37216882019-06-13 17:24:24 -0400976 SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, fakeMask, false};
Herb Derby511dcfc2019-06-24 12:58:41 -0400977 fallbackCache->glyphFromPrototype(proto, (void *)glyphImage);
Khushal4010c792018-06-13 09:44:23 -0700978 }
979
980 // Send over the real glyph and make sure the client cache stays intact.
981 {
982 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700983 SkScalerContextEffects effects;
984 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500985 font.setTypeface(serverTf);
Herb Derbyc03716d2018-09-17 11:39:51 -0400986 auto* cacheState = server.getOrCreateCache(
Herb Derbye7f662b2018-12-17 12:12:56 -0500987 paint, font, SkSurfacePropsCopyOrDefault(nullptr),
Herb Derbyc03716d2018-09-17 11:39:51 -0400988 SkMatrix::I(), flags, &effects);
Herb Derby82963a32019-08-15 16:18:44 -0400989 SkStrikeServer::AddGlyphForTesting(cacheState, lostGlyphID, false);
Khushal4010c792018-06-13 09:44:23 -0700990
991 std::vector<uint8_t> serverStrikeData;
992 server.writeStrikeData(&serverStrikeData);
993 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400994 client.readStrikeData(
995 serverStrikeData.data(),
996 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700997 }
998
999 {
1000 SkAutoDescriptor ad;
1001 SkScalerContextRec rec;
1002 SkScalerContextEffects effects;
1003 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -05001004 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -05001005 SkScalerContext::MakeRecAndEffects(
1006 font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -05001007 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -07001008 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
1009
Herb Derby5c0c7982018-06-21 15:15:50 -04001010 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -07001011 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
Herb Derby511dcfc2019-06-24 12:58:41 -04001012 auto glyph = fallbackCache->glyphOrNull(lostGlyphID);
1013 REPORTER_ASSERT(reporter, glyph && glyph->maskFormat() == fakeMask);
1014 if (glyph) {
1015 REPORTER_ASSERT(reporter,
1016 memcmp(glyph->image(), glyphImage, glyph->imageSize()) == 0);
1017 }
Khushal4010c792018-06-13 09:44:23 -07001018 }
1019
Herb Derby5c0c7982018-06-21 15:15:50 -04001020 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -07001021
1022 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
1023 discardableManager->unlockAndDeleteAll();
1024}