blob: 0dd504ee41cf0bf01eb77fe3ec30e92e94dc2a26 [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
Herb Derby8e318fd2018-08-29 11:04:18 -04008#include "Resources.h"
Khushal51371a42018-05-17 10:41:40 -07009#include "SkDraw.h"
Khushal38a08432018-05-02 10:29:37 -070010#include "SkGraphics.h"
11#include "SkMutex.h"
12#include "SkRemoteGlyphCache.h"
Herb Derbyd2fec232018-08-23 18:44:45 -040013#include "SkRemoteGlyphCacheImpl.h"
Herb Derby5fd955e2019-01-16 11:23:29 -050014#include "SkStrike.h"
Khushal38a08432018-05-02 10:29:37 -070015#include "SkStrikeCache.h"
16#include "SkSurface.h"
Herb Derbyc3415002018-11-08 16:40:26 -050017#include "SkSurfacePriv.h"
Herb Derbyaca2b9e2018-08-28 15:33:19 -040018#include "SkTestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070019#include "SkTextBlob.h"
20#include "SkTypeface_remote.h"
21#include "Test.h"
22
Herb Derby26cbe512018-05-24 14:39:01 -040023#include "text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070024
Khushal38a08432018-05-02 10:29:37 -070025class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
26 public SkStrikeClient::DiscardableHandleManager {
27public:
Khushald4160832018-05-23 18:16:00 -070028 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070029 ~DiscardableManager() override = default;
30
31 // Server implementation.
32 SkDiscardableHandleId createHandle() override {
33 // Handles starts as locked.
34 fLockedHandles.add(++fNextHandleId);
35 return fNextHandleId;
36 }
37 bool lockHandle(SkDiscardableHandleId id) override {
38 if (id <= fLastDeletedHandleId) return false;
39 fLockedHandles.add(id);
40 return true;
41 }
42
43 // Client implementation.
44 bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushalfa8ff092018-06-06 17:46:38 -070045 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
Khushalcf33b1b2018-08-29 16:16:25 -070046 bool isHandleDeleted(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushal38a08432018-05-02 10:29:37 -070047
48 void unlockAll() { fLockedHandles.reset(); }
49 void unlockAndDeleteAll() {
50 unlockAll();
51 fLastDeletedHandleId = fNextHandleId;
52 }
53 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
54 SkDiscardableHandleId handleCount() { return fNextHandleId; }
Khushal8523b6b2018-06-12 11:26:17 -070055 int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
Khushalfa8ff092018-06-06 17:46:38 -070056 bool hasCacheMiss() const {
57 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
58 if (fCacheMissCount[i] > 0) return true;
59 }
60 return false;
61 }
Khushal38a08432018-05-02 10:29:37 -070062
63private:
64 SkDiscardableHandleId fNextHandleId = 0u;
65 SkDiscardableHandleId fLastDeletedHandleId = 0u;
66 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -070067 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -070068};
69
70sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
Mike Reed2ed78202018-11-21 15:10:08 -050071 SkFont font;
Khushal38a08432018-05-02 10:29:37 -070072 font.setTypeface(tf);
Mike Reed9edbf422018-11-07 19:54:33 -050073 font.setHinting(kNormal_SkFontHinting);
Mike Reed2ed78202018-11-21 15:10:08 -050074 font.setSize(1u);
75 font.setEdging(SkFont::Edging::kAntiAlias);
76 font.setSubpixel(true);
Khushal38a08432018-05-02 10:29:37 -070077
78 SkTextBlobBuilder builder;
79 SkRect bounds = SkRect::MakeWH(10, 10);
80 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
81 SkASSERT(runBuffer.utf8text == nullptr);
82 SkASSERT(runBuffer.clusters == nullptr);
83
84 for (int i = 0; i < glyphCount; i++) {
85 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
86 runBuffer.pos[i] = SkIntToScalar(i);
87 }
88 return builder.make();
89}
90
Chris Daltonf9a90a22018-08-28 14:17:55 -060091static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
92 skiatest::Reporter* reporter, int tolerance = 0) {
93 SkASSERT(expected.width() == actual.width());
94 SkASSERT(expected.height() == actual.height());
95 for (int i = 0; i < expected.width(); ++i) {
96 for (int j = 0; j < expected.height(); ++j) {
97 SkColor expectedColor = expected.getColor(i, j);
98 SkColor actualColor = actual.getColor(i, j);
99 if (0 == tolerance) {
100 REPORTER_ASSERT(reporter, expectedColor == actualColor);
101 } else {
102 for (int k = 0; k < 4; ++k) {
103 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
104 int actualChannel = (actualColor >> (k*8)) & 0xff;
105 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
106 }
107 }
108 }
Khushal51371a42018-05-17 10:41:40 -0700109 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600110}
Khushal51371a42018-05-17 10:41:40 -0700111
Khushal3e7548c2018-05-23 15:45:01 -0700112SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
113 SkTextBlobCacheDiffCanvas::Settings settings;
114 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -0700115 settings.fMaxTextureSize = context->maxTextureSize();
116 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -0700117 return settings;
118}
119
Herb Derbyc3415002018-11-08 16:40:26 -0500120sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
121 const SkImageInfo info =
122 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
123 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
124}
125
126const SkSurfaceProps FindSurfaceProps(GrContext* context) {
127 auto surface = MakeSurface(1, 1, context);
128 return surface->props();
129}
130
Ravi Mistrycd21d672018-05-29 21:45:46 +0000131SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400132 GrContext* context, const SkMatrix* matrix = nullptr,
133 SkScalar x = 0) {
Herb Derbyc3415002018-11-08 16:40:26 -0500134 auto surface = MakeSurface(width, height, context);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000135 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derby1a9971e2018-07-19 13:41:15 -0400136 surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700137 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000138 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700139 surface->readPixels(bitmap, 0, 0);
140 return bitmap;
141}
142
143DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
144 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
145 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400146 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700147
148 auto server_tf = SkTypeface::MakeDefault();
149 auto tf_data = server.serializeTypeface(server_tf.get());
150
151 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
152 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700153 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700154 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700155
156 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
157 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700158}
159
Khushal3e7548c2018-05-23 15:45:01 -0700160DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700161 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
162 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400163 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700164 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700165
166 // Server.
167 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
168 auto serverTfData = server.serializeTypeface(serverTf.get());
169
170 int glyphCount = 10;
171 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500172 auto props = FindSurfaceProps(ctxInfo.grContext());
Khushal3e7548c2018-05-23 15:45:01 -0700173 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
174 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700175 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
176
177 std::vector<uint8_t> serverStrikeData;
178 server.writeStrikeData(&serverStrikeData);
179
180 // Client.
181 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
182 REPORTER_ASSERT(reporter,
183 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
184 auto clientBlob = buildTextBlob(clientTf, glyphCount);
185
Ravi Mistrycd21d672018-05-29 21:45:46 +0000186 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
187 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600188 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700189 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700190
191 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
192 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700193}
194
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400195DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
196 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
197 SkStrikeServer server(discardableManager.get());
198 SkStrikeClient client(discardableManager, false);
199
200 // Server.
201 auto serverTf = SkTestEmptyTypeface::Make();
202 auto serverTfData = server.serializeTypeface(serverTf.get());
203 REPORTER_ASSERT(reporter, serverTf->unique());
204
205 {
206 const SkPaint paint;
207 int glyphCount = 10;
208 auto serverBlob = buildTextBlob(serverTf, glyphCount);
209 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
210 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
211 MakeSettings(ctxInfo.grContext()));
212 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
213 REPORTER_ASSERT(reporter, !serverTf->unique());
214
215 std::vector<uint8_t> serverStrikeData;
216 server.writeStrikeData(&serverStrikeData);
217 }
218 REPORTER_ASSERT(reporter, serverTf->unique());
219
220 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
221 discardableManager->unlockAndDeleteAll();
222}
223
Khushal38a08432018-05-02 10:29:37 -0700224DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
225 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
226 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400227 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700228
229 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
230 server.serializeTypeface(serverTf.get());
231 int glyphCount = 10;
232 auto serverBlob = buildTextBlob(serverTf, glyphCount);
233
234 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
235 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
236 SkPaint paint;
237 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
238
239 // The strike from the blob should be locked after it has been drawn on the canvas.
240 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
241 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
242
243 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
244 // again.
245 std::vector<uint8_t> fontData;
246 server.writeStrikeData(&fontData);
247 discardableManager->unlockAll();
248 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
249
250 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
251 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
252 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700253
254 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
255 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700256}
257
258DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
259 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
260 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400261 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700262
263 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
264 server.serializeTypeface(serverTf.get());
265 int glyphCount = 10;
266 auto serverBlob = buildTextBlob(serverTf, glyphCount);
267
268 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
269 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
270 SkPaint paint;
271 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
272 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
273
274 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
275 // handles.
276 std::vector<uint8_t> fontData;
277 server.writeStrikeData(&fontData);
278 discardableManager->unlockAndDeleteAll();
279 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700280 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700281
282 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
283 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700284}
285
286DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
287 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
288 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400289 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700290
291 // Server.
292 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
293 auto serverTfData = server.serializeTypeface(serverTf.get());
294
295 int glyphCount = 10;
296 auto serverBlob = buildTextBlob(serverTf, glyphCount);
297
298 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
299 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
300 SkPaint paint;
301 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
302
303 std::vector<uint8_t> serverStrikeData;
304 server.writeStrikeData(&serverStrikeData);
305
306 // Client.
307 REPORTER_ASSERT(reporter,
308 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
309 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
310
311 // The cache remains alive until it is pinned in the discardable manager.
312 SkGraphics::PurgeFontCache();
313 REPORTER_ASSERT(reporter, !clientTf->unique());
314
315 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
316 // clientTf.
317 discardableManager->unlockAndDeleteAll();
318 SkGraphics::PurgeFontCache();
319 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700320
321 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
322 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700323}
Khushalb2e71272018-05-15 12:59:48 -0700324
325DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
326 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
327 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400328 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700329
330 // Server.
331 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
332 auto serverTfData = server.serializeTypeface(serverTf.get());
333
334 int glyphCount = 10;
335 auto serverBlob = buildTextBlob(serverTf, glyphCount);
336
337 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
338 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
339 SkPaint paint;
340 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
341
342 std::vector<uint8_t> serverStrikeData;
343 server.writeStrikeData(&serverStrikeData);
344
345 // Client.
346 REPORTER_ASSERT(reporter,
347 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400348 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700349
350 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
351 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700352}
Khushal51371a42018-05-17 10:41:40 -0700353
Khushalcf33b1b2018-08-29 16:16:25 -0700354DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
355 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
356 SkStrikeServer server(discardableManager.get());
357 server.setMaxEntriesInDescriptorMapForTesting(1u);
358 SkStrikeClient client(discardableManager, false);
359
360 {
361 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
362 int glyphCount = 10;
363 auto serverBlob = buildTextBlob(serverTf, glyphCount);
364
365 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
366 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
367 SkPaint paint;
368 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 0u);
369 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
370 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
371 }
372
373 // Serialize to release the lock from the strike server and delete all current
374 // handles.
375 std::vector<uint8_t> fontData;
376 server.writeStrikeData(&fontData);
377 discardableManager->unlockAndDeleteAll();
378
379 // Use a different typeface. Creating a new strike should evict the previous
380 // one.
381 {
382 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
383 int glyphCount = 10;
384 auto serverBlob = buildTextBlob(serverTf, glyphCount);
385
386 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
387 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
388 SkPaint paint;
389 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
390 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
391 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
392 }
393
394 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
395 discardableManager->unlockAndDeleteAll();
396}
397
Khushal3e7548c2018-05-23 15:45:01 -0700398DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700399 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
400 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400401 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700402 SkPaint paint;
403 paint.setStyle(SkPaint::kStroke_Style);
404 paint.setStrokeWidth(0);
Mike Reed77f94ea2019-01-22 16:30:40 -0500405 REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(SkFont(), paint, SkMatrix::I()));
Khushal51371a42018-05-17 10:41:40 -0700406
407 // Server.
408 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
409 auto serverTfData = server.serializeTypeface(serverTf.get());
410
411 int glyphCount = 10;
412 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500413 auto props = FindSurfaceProps(ctxInfo.grContext());
Khushal3e7548c2018-05-23 15:45:01 -0700414 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
415 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700416 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
417
418 std::vector<uint8_t> serverStrikeData;
419 server.writeStrikeData(&serverStrikeData);
420
421 // Client.
422 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
423 REPORTER_ASSERT(reporter,
424 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
425 auto clientBlob = buildTextBlob(clientTf, glyphCount);
426
Ravi Mistrycd21d672018-05-29 21:45:46 +0000427 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
428 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600429 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700430 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400431 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700432
433 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
434 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700435}
Khushal3e7548c2018-05-23 15:45:01 -0700436
Herb Derby8e318fd2018-08-29 11:04:18 -0400437sk_sp<SkTextBlob> make_blob_causing_fallback(
438 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
Mike Reed70914f52018-11-23 13:08:33 -0500439 SkFont font;
440 font.setSubpixel(true);
441 font.setSize(96);
442 font.setHinting(kNormal_SkFontHinting);
443 font.setTypeface(targetTf);
Herb Derby8e318fd2018-08-29 11:04:18 -0400444
Mike Reed70914f52018-11-23 13:08:33 -0500445 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
Herb Derby8e318fd2018-08-29 11:04:18 -0400446
447 char s[] = "Skia";
448 int runSize = strlen(s);
449
450 SkTextBlobBuilder builder;
451 SkRect bounds = SkRect::MakeIWH(100, 100);
Mike Reed70914f52018-11-23 13:08:33 -0500452 const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400453 SkASSERT(runBuffer.utf8text == nullptr);
454 SkASSERT(runBuffer.clusters == nullptr);
455
456 glyphTf->charsToGlyphs(s, SkTypeface::kUTF8_Encoding, runBuffer.glyphs, runSize);
457
458 SkRect glyphBounds;
Mike Reed70914f52018-11-23 13:08:33 -0500459 font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
Herb Derby8e318fd2018-08-29 11:04:18 -0400460
Herb Derby5fd955e2019-01-16 11:23:29 -0500461 REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
Herb Derby8e318fd2018-08-29 11:04:18 -0400462
463 for (int i = 0; i < runSize; i++) {
464 runBuffer.pos[i] = i * 10;
465 }
466
467 return builder.make();
468}
469
470DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
471 reporter, ctxInfo) {
472 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
473 SkStrikeServer server(discardableManager.get());
474 SkStrikeClient client(discardableManager, false);
475
476 SkPaint paint;
477
478 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
479 // TODO: when the cq bots can handle this font remove the check.
480 if (serverTf == nullptr) {
481 return;
482 }
483 auto serverTfData = server.serializeTypeface(serverTf.get());
484
485 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
486
Herb Derbyc3415002018-11-08 16:40:26 -0500487 auto props = FindSurfaceProps(ctxInfo.grContext());
Herb Derby8e318fd2018-08-29 11:04:18 -0400488 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
489 MakeSettings(ctxInfo.grContext()));
490 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
491
492 std::vector<uint8_t> serverStrikeData;
493 server.writeStrikeData(&serverStrikeData);
494
495 // Client.
496 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
497 REPORTER_ASSERT(reporter,
498 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
499
500 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
501
502 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
503 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
504 compare_blobs(expected, actual, reporter);
505 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
506 SkStrikeCache::ValidateGlyphCacheDataSize();
507
508 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
509 discardableManager->unlockAndDeleteAll();
510}
511
Herb Derby1a9971e2018-07-19 13:41:15 -0400512DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
513 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
514 SkStrikeServer server(discardableManager.get());
515 SkStrikeClient client(discardableManager, false);
516 SkPaint paint;
517 paint.setAntiAlias(true);
Herb Derby1a9971e2018-07-19 13:41:15 -0400518
519 // Server.
520 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
521 auto serverTfData = server.serializeTypeface(serverTf.get());
522
523 int glyphCount = 10;
524 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Herb Derbyc3415002018-11-08 16:40:26 -0500525 auto props = FindSurfaceProps(ctxInfo.grContext());
Herb Derby1a9971e2018-07-19 13:41:15 -0400526 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
527 MakeSettings(ctxInfo.grContext()));
528 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
529
530 std::vector<uint8_t> serverStrikeData;
531 server.writeStrikeData(&serverStrikeData);
532
533 // Client.
534 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
535 REPORTER_ASSERT(reporter,
536 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
537 auto clientBlob = buildTextBlob(clientTf, glyphCount);
538
539 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
540 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600541 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400542 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
543 SkStrikeCache::ValidateGlyphCacheDataSize();
544
545 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
546 discardableManager->unlockAndDeleteAll();
547}
548
Khushal3e7548c2018-05-23 15:45:01 -0700549DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
550 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
551 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400552 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700553 SkPaint paint;
Mike Reedf2b074e2018-12-03 16:52:59 -0500554 SkFont font;
Khushal3e7548c2018-05-23 15:45:01 -0700555
556 // A perspective transform forces fallback to dft.
557 SkMatrix matrix = SkMatrix::I();
558 matrix[SkMatrix::kMPersp0] = 0.5f;
559 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000560 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400561 GrTextContext::Options options;
562 GrTextContext::SanitizeOptions(&options);
563 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Mike Reedf2b074e2018-12-03 16:52:59 -0500564 paint, font, matrix, surfaceProps, true, options));
Khushal3e7548c2018-05-23 15:45:01 -0700565
566 // Server.
567 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
568 auto serverTfData = server.serializeTypeface(serverTf.get());
569
570 int glyphCount = 10;
571 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000572 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
573 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700574 MakeSettings(ctxInfo.grContext()));
575 cache_diff_canvas.concat(matrix);
576 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
577
578 std::vector<uint8_t> serverStrikeData;
579 server.writeStrikeData(&serverStrikeData);
580
581 // Client.
582 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
583 REPORTER_ASSERT(reporter,
584 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
585 auto clientBlob = buildTextBlob(clientTf, glyphCount);
586
Ravi Mistrycd21d672018-05-29 21:45:46 +0000587 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
588 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600589 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700590 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400591 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700592
593 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
594 discardableManager->unlockAndDeleteAll();
595}
Khushald4160832018-05-23 18:16:00 -0700596
597DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
598 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
599 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400600 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700601
602 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
603 auto tfData = server.serializeTypeface(serverTf.get());
604 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
605 REPORTER_ASSERT(reporter, clientTf);
606 int glyphCount = 10;
607 auto clientBlob = buildTextBlob(clientTf, glyphCount);
608
609 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000610 SkPaint paint;
611 SkMatrix matrix = SkMatrix::I();
612 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700613 REPORTER_ASSERT(reporter,
614 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
615 REPORTER_ASSERT(reporter,
616 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
617
618 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
619 // miss.
620 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
621 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
622
623 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
624 discardableManager->unlockAndDeleteAll();
625}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400626
627DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700628 // Build proxy typeface on the client for initializing the cache.
629 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
630 SkStrikeServer server(discardableManager.get());
631 SkStrikeClient client(discardableManager, false);
632
633 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
634 auto tfData = server.serializeTypeface(serverTf.get());
635 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
636 REPORTER_ASSERT(reporter, clientTf);
637
Mike Reed4529cb52018-11-06 08:03:42 -0500638 SkFont font;
639 font.setTypeface(clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400640 SkPaint paint;
641 paint.setAntiAlias(true);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400642 paint.setColor(SK_ColorRED);
643
644 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400645 const uint8_t glyphImage[] = {0xFF, 0xFF};
646
Herb Derby5c0c7982018-06-21 15:15:50 -0400647 SkStrikeCache strikeCache;
648
Herb Derby65b7bfc2018-06-05 13:32:12 -0400649 // Build a fallback cache.
650 {
651 SkAutoDescriptor ad;
652 SkScalerContextRec rec;
653 SkScalerContextEffects effects;
654 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500655 SkScalerContext::MakeRecAndEffects(
656 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500657 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400658 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
659
Herb Derby5c0c7982018-06-21 15:15:50 -0400660 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400661 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
662 glyph->fMaskFormat = SkMask::kA8_Format;
663 glyph->fHeight = 1;
664 glyph->fWidth = 2;
665 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
666 glyph->fImage = (void *)glyphImage;
667 }
668
669 // Make sure we can find the fall back cache.
670 {
671 SkAutoDescriptor ad;
672 SkScalerContextRec rec;
673 SkScalerContextEffects effects;
674 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbyc3415002018-11-08 16:40:26 -0500675 SkScalerContext::MakeRecAndEffects(
676 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500677 SkMatrix::I(), &rec, &effects);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400678 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400679 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400680 REPORTER_ASSERT(reporter, !(testCache == nullptr));
681 }
682
Khushal8523b6b2018-06-12 11:26:17 -0700683 // Create the target cache.
684 SkExclusiveStrikePtr testCache;
685 SkAutoDescriptor ad;
686 SkScalerContextRec rec;
687 SkScalerContextEffects effects;
688 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
Herb Derbyc3415002018-11-08 16:40:26 -0500689 SkScalerContext::MakeRecAndEffects(
690 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500691 SkMatrix::I(), &rec, &effects);
Khushal8523b6b2018-06-12 11:26:17 -0700692 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400693 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700694 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400695 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700696 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400697 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
698 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400699
Khushal8523b6b2018-06-12 11:26:17 -0700700 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400701 {
Khushal8523b6b2018-06-12 11:26:17 -0700702 const auto& lostGlyph = testCache->getGlyphIDMetrics(
703 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
704 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400705
Herb Derby65b7bfc2018-06-05 13:32:12 -0400706 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
707 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
708 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700709 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400710 }
711
Khushal8523b6b2018-06-12 11:26:17 -0700712 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400713 {
Khushal8523b6b2018-06-12 11:26:17 -0700714 const auto& lostGlyph =
715 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
716 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400717
Herb Derby65b7bfc2018-06-05 13:32:12 -0400718 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
719 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
720 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700721 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400722 }
723
Khushal8523b6b2018-06-12 11:26:17 -0700724 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
725 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
726 i == SkStrikeClient::CacheMissType::kFontMetrics) {
727 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
728 } else {
729 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
730 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400731 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400732 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400733
Khushal8523b6b2018-06-12 11:26:17 -0700734 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
735 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400736}
Khushal4010c792018-06-13 09:44:23 -0700737
738DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
739 // Build proxy typeface on the client for initializing the cache.
740 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
741 SkStrikeServer server(discardableManager.get());
742 SkStrikeClient client(discardableManager, false);
743
744 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
745 auto tfData = server.serializeTypeface(serverTf.get());
746 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
747 REPORTER_ASSERT(reporter, clientTf);
748
Mike Reed4529cb52018-11-06 08:03:42 -0500749 SkFont font;
Herb Derbye7f662b2018-12-17 12:12:56 -0500750 font.setEdging(SkFont::Edging::kAntiAlias);
Khushal4010c792018-06-13 09:44:23 -0700751 SkPaint paint;
Khushal4010c792018-06-13 09:44:23 -0700752 paint.setColor(SK_ColorRED);
753
754 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
755 const uint8_t glyphImage[] = {0xFF, 0xFF};
756 uint32_t realMask;
757 uint32_t fakeMask;
758
Herb Derby5c0c7982018-06-21 15:15:50 -0400759 SkStrikeCache strikeCache;
760
Khushal4010c792018-06-13 09:44:23 -0700761 {
762 SkAutoDescriptor ad;
763 SkScalerContextRec rec;
764 SkScalerContextEffects effects;
765 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500766 font.setTypeface(serverTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500767 SkScalerContext::MakeRecAndEffects(
768 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500769 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700770 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
771
772 auto context = serverTf->createScalerContext(effects, desc, false);
Herb Derbyf6fca262019-01-09 15:13:54 -0500773 SkGlyph glyph{lostGlyphID};
Khushal4010c792018-06-13 09:44:23 -0700774 context->getMetrics(&glyph);
775 realMask = glyph.fMaskFormat;
776 REPORTER_ASSERT(reporter, realMask != MASK_FORMAT_UNKNOWN);
777 }
778
779 // Build a fallback cache.
780 {
781 SkAutoDescriptor ad;
782 SkScalerContextRec rec;
783 SkScalerContextEffects effects;
784 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500785 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500786 SkScalerContext::MakeRecAndEffects(
787 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500788 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700789 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
790
Herb Derby5c0c7982018-06-21 15:15:50 -0400791 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700792 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
793 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
794 glyph->fMaskFormat = fakeMask;
795 glyph->fHeight = 1;
796 glyph->fWidth = 2;
797 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
798 }
799
800 // Send over the real glyph and make sure the client cache stays intact.
801 {
802 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700803 SkScalerContextEffects effects;
804 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500805 font.setTypeface(serverTf);
Herb Derbyc03716d2018-09-17 11:39:51 -0400806 auto* cacheState = server.getOrCreateCache(
Herb Derbye7f662b2018-12-17 12:12:56 -0500807 paint, font, SkSurfacePropsCopyOrDefault(nullptr),
Herb Derbyc03716d2018-09-17 11:39:51 -0400808 SkMatrix::I(), flags, &effects);
Herb Derbyb2c72162018-08-23 16:16:31 -0400809 cacheState->addGlyph(lostGlyphID, false);
Khushal4010c792018-06-13 09:44:23 -0700810
811 std::vector<uint8_t> serverStrikeData;
812 server.writeStrikeData(&serverStrikeData);
813 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400814 client.readStrikeData(
815 serverStrikeData.data(),
816 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700817 }
818
819 {
820 SkAutoDescriptor ad;
821 SkScalerContextRec rec;
822 SkScalerContextEffects effects;
823 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
Herb Derbye7f662b2018-12-17 12:12:56 -0500824 font.setTypeface(clientTf);
Herb Derbyc3415002018-11-08 16:40:26 -0500825 SkScalerContext::MakeRecAndEffects(
826 font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
Herb Derbyf272b8f2019-02-06 11:39:31 -0500827 SkMatrix::I(), &rec, &effects);
Khushal4010c792018-06-13 09:44:23 -0700828 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
829
Herb Derby5c0c7982018-06-21 15:15:50 -0400830 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -0700831 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
832 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
833 REPORTER_ASSERT(reporter, glyph->fMaskFormat == fakeMask);
834
835 // Try overriding the image, it should stay the same.
836 REPORTER_ASSERT(reporter,
837 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
838 const uint8_t newGlyphImage[] = {0, 0};
839 fallbackCache->initializeImage(newGlyphImage, glyph->computeImageSize(), glyph);
840 REPORTER_ASSERT(reporter,
841 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
842 }
843
Herb Derby5c0c7982018-06-21 15:15:50 -0400844 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -0700845
846 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
847 discardableManager->unlockAndDeleteAll();
848}