blob: 347cd47de16510d655e9abc163b4d2ac91f94e4e [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"
Khushal38a08432018-05-02 10:29:37 -070014#include "SkStrikeCache.h"
15#include "SkSurface.h"
Herb Derbyaca2b9e2018-08-28 15:33:19 -040016#include "SkTestEmptyTypeface.h"
Khushal38a08432018-05-02 10:29:37 -070017#include "SkTextBlob.h"
18#include "SkTypeface_remote.h"
19#include "Test.h"
20
Herb Derby26cbe512018-05-24 14:39:01 -040021#include "text/GrTextContext.h"
Khushal3e7548c2018-05-23 15:45:01 -070022
Khushal38a08432018-05-02 10:29:37 -070023class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
24 public SkStrikeClient::DiscardableHandleManager {
25public:
Khushald4160832018-05-23 18:16:00 -070026 DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
Khushal38a08432018-05-02 10:29:37 -070027 ~DiscardableManager() override = default;
28
29 // Server implementation.
30 SkDiscardableHandleId createHandle() override {
31 // Handles starts as locked.
32 fLockedHandles.add(++fNextHandleId);
33 return fNextHandleId;
34 }
35 bool lockHandle(SkDiscardableHandleId id) override {
36 if (id <= fLastDeletedHandleId) return false;
37 fLockedHandles.add(id);
38 return true;
39 }
40
41 // Client implementation.
42 bool deleteHandle(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushalfa8ff092018-06-06 17:46:38 -070043 void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
Khushalcf33b1b2018-08-29 16:16:25 -070044 bool isHandleDeleted(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
Khushal38a08432018-05-02 10:29:37 -070045
46 void unlockAll() { fLockedHandles.reset(); }
47 void unlockAndDeleteAll() {
48 unlockAll();
49 fLastDeletedHandleId = fNextHandleId;
50 }
51 const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const { return fLockedHandles; }
52 SkDiscardableHandleId handleCount() { return fNextHandleId; }
Khushal8523b6b2018-06-12 11:26:17 -070053 int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
Khushalfa8ff092018-06-06 17:46:38 -070054 bool hasCacheMiss() const {
55 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
56 if (fCacheMissCount[i] > 0) return true;
57 }
58 return false;
59 }
Khushal38a08432018-05-02 10:29:37 -070060
61private:
62 SkDiscardableHandleId fNextHandleId = 0u;
63 SkDiscardableHandleId fLastDeletedHandleId = 0u;
64 SkTHashSet<SkDiscardableHandleId> fLockedHandles;
Khushald4160832018-05-23 18:16:00 -070065 int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
Khushal38a08432018-05-02 10:29:37 -070066};
67
68sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
69 SkPaint font;
70 font.setTypeface(tf);
71 font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
72 font.setTextAlign(SkPaint::kLeft_Align);
73 font.setStyle(SkPaint::kFill_Style);
74 font.setHinting(SkPaint::kNormal_Hinting);
75 font.setTextSize(1u);
Herb Derby1a9971e2018-07-19 13:41:15 -040076 font.setAntiAlias(true);
77 font.setSubpixelText(true);
Khushal38a08432018-05-02 10:29:37 -070078
79 SkTextBlobBuilder builder;
80 SkRect bounds = SkRect::MakeWH(10, 10);
81 const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
82 SkASSERT(runBuffer.utf8text == nullptr);
83 SkASSERT(runBuffer.clusters == nullptr);
84
85 for (int i = 0; i < glyphCount; i++) {
86 runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
87 runBuffer.pos[i] = SkIntToScalar(i);
88 }
89 return builder.make();
90}
91
Chris Daltonf9a90a22018-08-28 14:17:55 -060092static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
93 skiatest::Reporter* reporter, int tolerance = 0) {
94 SkASSERT(expected.width() == actual.width());
95 SkASSERT(expected.height() == actual.height());
96 for (int i = 0; i < expected.width(); ++i) {
97 for (int j = 0; j < expected.height(); ++j) {
98 SkColor expectedColor = expected.getColor(i, j);
99 SkColor actualColor = actual.getColor(i, j);
100 if (0 == tolerance) {
101 REPORTER_ASSERT(reporter, expectedColor == actualColor);
102 } else {
103 for (int k = 0; k < 4; ++k) {
104 int expectedChannel = (expectedColor >> (k*8)) & 0xff;
105 int actualChannel = (actualColor >> (k*8)) & 0xff;
106 REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
107 }
108 }
109 }
Khushal51371a42018-05-17 10:41:40 -0700110 }
Chris Daltonf9a90a22018-08-28 14:17:55 -0600111}
Khushal51371a42018-05-17 10:41:40 -0700112
Khushal3e7548c2018-05-23 15:45:01 -0700113SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
114 SkTextBlobCacheDiffCanvas::Settings settings;
115 settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
Khushalfa8ff092018-06-06 17:46:38 -0700116 settings.fMaxTextureSize = context->maxTextureSize();
117 settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
Khushal3e7548c2018-05-23 15:45:01 -0700118 return settings;
119}
120
Ravi Mistrycd21d672018-05-29 21:45:46 +0000121SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
Herb Derby1a9971e2018-07-19 13:41:15 -0400122 GrContext* context, const SkMatrix* matrix = nullptr,
123 SkScalar x = 0) {
Ravi Mistrycd21d672018-05-29 21:45:46 +0000124 const SkImageInfo info =
125 SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
Khushal3e7548c2018-05-23 15:45:01 -0700126 auto surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000127 if (matrix) surface->getCanvas()->concat(*matrix);
Herb Derby1a9971e2018-07-19 13:41:15 -0400128 surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700129 SkBitmap bitmap;
Ravi Mistrycd21d672018-05-29 21:45:46 +0000130 bitmap.allocN32Pixels(width, height);
Khushal38a08432018-05-02 10:29:37 -0700131 surface->readPixels(bitmap, 0, 0);
132 return bitmap;
133}
134
135DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
136 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
137 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400138 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700139
140 auto server_tf = SkTypeface::MakeDefault();
141 auto tf_data = server.serializeTypeface(server_tf.get());
142
143 auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
144 REPORTER_ASSERT(reporter, client_tf);
Khushald4160832018-05-23 18:16:00 -0700145 REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
Khushal38a08432018-05-02 10:29:37 -0700146 server_tf->uniqueID());
Khushal3e7548c2018-05-23 15:45:01 -0700147
148 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
149 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700150}
151
Khushal3e7548c2018-05-23 15:45:01 -0700152DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
Khushal38a08432018-05-02 10:29:37 -0700153 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
154 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400155 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700156 const SkPaint paint;
Khushal38a08432018-05-02 10:29:37 -0700157
158 // Server.
159 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
160 auto serverTfData = server.serializeTypeface(serverTf.get());
161
162 int glyphCount = 10;
163 auto serverBlob = buildTextBlob(serverTf, glyphCount);
164 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700165 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
166 MakeSettings(ctxInfo.grContext()));
Khushal38a08432018-05-02 10:29:37 -0700167 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
168
169 std::vector<uint8_t> serverStrikeData;
170 server.writeStrikeData(&serverStrikeData);
171
172 // Client.
173 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
174 REPORTER_ASSERT(reporter,
175 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
176 auto clientBlob = buildTextBlob(clientTf, glyphCount);
177
Ravi Mistrycd21d672018-05-29 21:45:46 +0000178 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
179 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600180 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700181 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Khushal3e7548c2018-05-23 15:45:01 -0700182
183 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
184 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700185}
186
Herb Derbyaca2b9e2018-08-28 15:33:19 -0400187DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
188 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
189 SkStrikeServer server(discardableManager.get());
190 SkStrikeClient client(discardableManager, false);
191
192 // Server.
193 auto serverTf = SkTestEmptyTypeface::Make();
194 auto serverTfData = server.serializeTypeface(serverTf.get());
195 REPORTER_ASSERT(reporter, serverTf->unique());
196
197 {
198 const SkPaint paint;
199 int glyphCount = 10;
200 auto serverBlob = buildTextBlob(serverTf, glyphCount);
201 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
202 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
203 MakeSettings(ctxInfo.grContext()));
204 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
205 REPORTER_ASSERT(reporter, !serverTf->unique());
206
207 std::vector<uint8_t> serverStrikeData;
208 server.writeStrikeData(&serverStrikeData);
209 }
210 REPORTER_ASSERT(reporter, serverTf->unique());
211
212 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
213 discardableManager->unlockAndDeleteAll();
214}
215
Khushal38a08432018-05-02 10:29:37 -0700216DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
217 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
218 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400219 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700220
221 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
222 server.serializeTypeface(serverTf.get());
223 int glyphCount = 10;
224 auto serverBlob = buildTextBlob(serverTf, glyphCount);
225
226 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
227 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
228 SkPaint paint;
229 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
230
231 // The strike from the blob should be locked after it has been drawn on the canvas.
232 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
233 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
234
235 // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
236 // again.
237 std::vector<uint8_t> fontData;
238 server.writeStrikeData(&fontData);
239 discardableManager->unlockAll();
240 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
241
242 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
243 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
244 REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
Khushal3e7548c2018-05-23 15:45:01 -0700245
246 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
247 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700248}
249
250DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
251 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
252 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400253 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700254
255 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
256 server.serializeTypeface(serverTf.get());
257 int glyphCount = 10;
258 auto serverBlob = buildTextBlob(serverTf, glyphCount);
259
260 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
261 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
262 SkPaint paint;
263 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
264 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
265
266 // Write the strike data and delete all the handles. Re-analyzing the blob should create new
267 // handles.
268 std::vector<uint8_t> fontData;
269 server.writeStrikeData(&fontData);
270 discardableManager->unlockAndDeleteAll();
271 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
Khushal38a08432018-05-02 10:29:37 -0700272 REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
Khushal3e7548c2018-05-23 15:45:01 -0700273
274 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
275 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700276}
277
278DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
279 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
280 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400281 SkStrikeClient client(discardableManager, false);
Khushal38a08432018-05-02 10:29:37 -0700282
283 // Server.
284 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
285 auto serverTfData = server.serializeTypeface(serverTf.get());
286
287 int glyphCount = 10;
288 auto serverBlob = buildTextBlob(serverTf, glyphCount);
289
290 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
291 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
292 SkPaint paint;
293 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
294
295 std::vector<uint8_t> serverStrikeData;
296 server.writeStrikeData(&serverStrikeData);
297
298 // Client.
299 REPORTER_ASSERT(reporter,
300 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
301 auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
302
303 // The cache remains alive until it is pinned in the discardable manager.
304 SkGraphics::PurgeFontCache();
305 REPORTER_ASSERT(reporter, !clientTf->unique());
306
307 // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
308 // clientTf.
309 discardableManager->unlockAndDeleteAll();
310 SkGraphics::PurgeFontCache();
311 REPORTER_ASSERT(reporter, clientTf->unique());
Khushal3e7548c2018-05-23 15:45:01 -0700312
313 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
314 discardableManager->unlockAndDeleteAll();
Khushal38a08432018-05-02 10:29:37 -0700315}
Khushalb2e71272018-05-15 12:59:48 -0700316
317DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
318 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
319 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400320 SkStrikeClient client(discardableManager, false);
Khushalb2e71272018-05-15 12:59:48 -0700321
322 // Server.
323 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
324 auto serverTfData = server.serializeTypeface(serverTf.get());
325
326 int glyphCount = 10;
327 auto serverBlob = buildTextBlob(serverTf, glyphCount);
328
329 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
330 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
331 SkPaint paint;
332 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
333
334 std::vector<uint8_t> serverStrikeData;
335 server.writeStrikeData(&serverStrikeData);
336
337 // Client.
338 REPORTER_ASSERT(reporter,
339 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
Herb Derbyc113e9e2018-06-21 14:06:30 -0400340 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700341
342 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
343 discardableManager->unlockAndDeleteAll();
Khushalb2e71272018-05-15 12:59:48 -0700344}
Khushal51371a42018-05-17 10:41:40 -0700345
Khushalcf33b1b2018-08-29 16:16:25 -0700346DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
347 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
348 SkStrikeServer server(discardableManager.get());
349 server.setMaxEntriesInDescriptorMapForTesting(1u);
350 SkStrikeClient client(discardableManager, false);
351
352 {
353 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
354 int glyphCount = 10;
355 auto serverBlob = buildTextBlob(serverTf, glyphCount);
356
357 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
358 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
359 SkPaint paint;
360 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 0u);
361 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
362 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
363 }
364
365 // Serialize to release the lock from the strike server and delete all current
366 // handles.
367 std::vector<uint8_t> fontData;
368 server.writeStrikeData(&fontData);
369 discardableManager->unlockAndDeleteAll();
370
371 // Use a different typeface. Creating a new strike should evict the previous
372 // one.
373 {
374 auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
375 int glyphCount = 10;
376 auto serverBlob = buildTextBlob(serverTf, glyphCount);
377
378 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
379 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server);
380 SkPaint paint;
381 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
382 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
383 REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
384 }
385
386 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
387 discardableManager->unlockAndDeleteAll();
388}
389
Khushal3e7548c2018-05-23 15:45:01 -0700390DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
Khushal51371a42018-05-17 10:41:40 -0700391 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
392 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400393 SkStrikeClient client(discardableManager, false);
Khushal51371a42018-05-17 10:41:40 -0700394 SkPaint paint;
395 paint.setStyle(SkPaint::kStroke_Style);
396 paint.setStrokeWidth(0);
397 REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I()));
398
399 // Server.
400 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
401 auto serverTfData = server.serializeTypeface(serverTf.get());
402
403 int glyphCount = 10;
404 auto serverBlob = buildTextBlob(serverTf, glyphCount);
405 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
Khushal3e7548c2018-05-23 15:45:01 -0700406 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
407 MakeSettings(ctxInfo.grContext()));
Khushal51371a42018-05-17 10:41:40 -0700408 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
409
410 std::vector<uint8_t> serverStrikeData;
411 server.writeStrikeData(&serverStrikeData);
412
413 // Client.
414 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
415 REPORTER_ASSERT(reporter,
416 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
417 auto clientBlob = buildTextBlob(clientTf, glyphCount);
418
Ravi Mistrycd21d672018-05-29 21:45:46 +0000419 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
420 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
Chris Daltonf9a90a22018-08-28 14:17:55 -0600421 compare_blobs(expected, actual, reporter, 1);
Khushalfa8ff092018-06-06 17:46:38 -0700422 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400423 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700424
425 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
426 discardableManager->unlockAndDeleteAll();
Khushal51371a42018-05-17 10:41:40 -0700427}
Khushal3e7548c2018-05-23 15:45:01 -0700428
Herb Derby8e318fd2018-08-29 11:04:18 -0400429sk_sp<SkTextBlob> make_blob_causing_fallback(
430 sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
431 SkPaint paint;
432 paint.setSubpixelText(true);
433 paint.setTextSize(96);
434 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
435 paint.setTextAlign(SkPaint::kLeft_Align);
436 paint.setStyle(SkPaint::kFill_Style);
437 paint.setHinting(SkPaint::kNormal_Hinting);
438
439 paint.setTypeface(targetTf);
440
441 REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(paint, SkMatrix::I()));
442
443 char s[] = "Skia";
444 int runSize = strlen(s);
445
446 SkTextBlobBuilder builder;
447 SkRect bounds = SkRect::MakeIWH(100, 100);
448 const auto& runBuffer = builder.allocRunPosH(paint, runSize, 10, &bounds);
449 SkASSERT(runBuffer.utf8text == nullptr);
450 SkASSERT(runBuffer.clusters == nullptr);
451
452 glyphTf->charsToGlyphs(s, SkTypeface::kUTF8_Encoding, runBuffer.glyphs, runSize);
453
454 SkRect glyphBounds;
455 paint.measureText(runBuffer.glyphs, 2, &glyphBounds);
456
457 REPORTER_ASSERT(reporter, glyphBounds.width() > SkGlyphCacheCommon::kSkSideTooBigForAtlas);
458
459 for (int i = 0; i < runSize; i++) {
460 runBuffer.pos[i] = i * 10;
461 }
462
463 return builder.make();
464}
465
466DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
467 reporter, ctxInfo) {
468 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
469 SkStrikeServer server(discardableManager.get());
470 SkStrikeClient client(discardableManager, false);
471
472 SkPaint paint;
473
474 auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
475 // TODO: when the cq bots can handle this font remove the check.
476 if (serverTf == nullptr) {
477 return;
478 }
479 auto serverTfData = server.serializeTypeface(serverTf.get());
480
481 auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
482
483 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
484 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
485 MakeSettings(ctxInfo.grContext()));
486 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
487
488 std::vector<uint8_t> serverStrikeData;
489 server.writeStrikeData(&serverStrikeData);
490
491 // Client.
492 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
493 REPORTER_ASSERT(reporter,
494 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
495
496 auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
497
498 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
499 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
500 compare_blobs(expected, actual, reporter);
501 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
502 SkStrikeCache::ValidateGlyphCacheDataSize();
503
504 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
505 discardableManager->unlockAndDeleteAll();
506}
507
Herb Derby1a9971e2018-07-19 13:41:15 -0400508DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
509 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
510 SkStrikeServer server(discardableManager.get());
511 SkStrikeClient client(discardableManager, false);
512 SkPaint paint;
513 paint.setAntiAlias(true);
514 paint.setSubpixelText(true);
515 paint.setLCDRenderText(true);
516
517 // Server.
518 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
519 auto serverTfData = server.serializeTypeface(serverTf.get());
520
521 int glyphCount = 10;
522 auto serverBlob = buildTextBlob(serverTf, glyphCount);
523 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
524 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
525 MakeSettings(ctxInfo.grContext()));
526 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
527
528 std::vector<uint8_t> serverStrikeData;
529 server.writeStrikeData(&serverStrikeData);
530
531 // Client.
532 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
533 REPORTER_ASSERT(reporter,
534 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
535 auto clientBlob = buildTextBlob(clientTf, glyphCount);
536
537 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
538 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), nullptr, 0.5);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600539 compare_blobs(expected, actual, reporter);
Herb Derby1a9971e2018-07-19 13:41:15 -0400540 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
541 SkStrikeCache::ValidateGlyphCacheDataSize();
542
543 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
544 discardableManager->unlockAndDeleteAll();
545}
546
Khushal3e7548c2018-05-23 15:45:01 -0700547DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
548 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
549 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400550 SkStrikeClient client(discardableManager, false);
Khushal3e7548c2018-05-23 15:45:01 -0700551 SkPaint paint;
552
553 // A perspective transform forces fallback to dft.
554 SkMatrix matrix = SkMatrix::I();
555 matrix[SkMatrix::kMPersp0] = 0.5f;
556 REPORTER_ASSERT(reporter, matrix.hasPerspective());
Ravi Mistrycd21d672018-05-29 21:45:46 +0000557 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
Herb Derby26cbe512018-05-24 14:39:01 -0400558 GrTextContext::Options options;
559 GrTextContext::SanitizeOptions(&options);
560 REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
Khushal3e7548c2018-05-23 15:45:01 -0700561 paint, matrix, surfaceProps, true, options));
562
563 // Server.
564 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
565 auto serverTfData = server.serializeTypeface(serverTf.get());
566
567 int glyphCount = 10;
568 auto serverBlob = buildTextBlob(serverTf, glyphCount);
Ravi Mistrycd21d672018-05-29 21:45:46 +0000569 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
570 SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, SkMatrix::I(), props, &server,
Khushal3e7548c2018-05-23 15:45:01 -0700571 MakeSettings(ctxInfo.grContext()));
572 cache_diff_canvas.concat(matrix);
573 cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
574
575 std::vector<uint8_t> serverStrikeData;
576 server.writeStrikeData(&serverStrikeData);
577
578 // Client.
579 auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
580 REPORTER_ASSERT(reporter,
581 client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
582 auto clientBlob = buildTextBlob(clientTf, glyphCount);
583
Ravi Mistrycd21d672018-05-29 21:45:46 +0000584 SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
585 SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Chris Daltonf9a90a22018-08-28 14:17:55 -0600586 compare_blobs(expected, actual, reporter);
Khushalfa8ff092018-06-06 17:46:38 -0700587 REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
Herb Derbyc113e9e2018-06-21 14:06:30 -0400588 SkStrikeCache::ValidateGlyphCacheDataSize();
Khushal3e7548c2018-05-23 15:45:01 -0700589
590 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
591 discardableManager->unlockAndDeleteAll();
592}
Khushald4160832018-05-23 18:16:00 -0700593
594DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
595 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
596 SkStrikeServer server(discardableManager.get());
Herb Derbyfeb9fa92018-06-01 16:47:21 -0400597 SkStrikeClient client(discardableManager, false);
Khushald4160832018-05-23 18:16:00 -0700598
599 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
600 auto tfData = server.serializeTypeface(serverTf.get());
601 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
602 REPORTER_ASSERT(reporter, clientTf);
603 int glyphCount = 10;
604 auto clientBlob = buildTextBlob(clientTf, glyphCount);
605
606 // Raster the client-side blob without the glyph data, we should get cache miss notifications.
Ravi Mistrycd21d672018-05-29 21:45:46 +0000607 SkPaint paint;
608 SkMatrix matrix = SkMatrix::I();
609 RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
Khushald4160832018-05-23 18:16:00 -0700610 REPORTER_ASSERT(reporter,
611 discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
612 REPORTER_ASSERT(reporter,
613 discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
614
615 // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
616 // miss.
617 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
618 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
619
620 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
621 discardableManager->unlockAndDeleteAll();
622}
Herb Derby65b7bfc2018-06-05 13:32:12 -0400623
624DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
Khushal8523b6b2018-06-12 11:26:17 -0700625 // Build proxy typeface on the client for initializing the cache.
626 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
627 SkStrikeServer server(discardableManager.get());
628 SkStrikeClient client(discardableManager, false);
629
630 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
631 auto tfData = server.serializeTypeface(serverTf.get());
632 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
633 REPORTER_ASSERT(reporter, clientTf);
634
Herb Derby65b7bfc2018-06-05 13:32:12 -0400635 SkPaint paint;
636 paint.setAntiAlias(true);
Khushal8523b6b2018-06-12 11:26:17 -0700637 paint.setTypeface(clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400638 paint.setColor(SK_ColorRED);
639
640 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400641 const uint8_t glyphImage[] = {0xFF, 0xFF};
642
Herb Derby5c0c7982018-06-21 15:15:50 -0400643 SkStrikeCache strikeCache;
644
Herb Derby65b7bfc2018-06-05 13:32:12 -0400645 // Build a fallback cache.
646 {
647 SkAutoDescriptor ad;
648 SkScalerContextRec rec;
649 SkScalerContextEffects effects;
650 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
651 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
652 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
653
Herb Derby5c0c7982018-06-21 15:15:50 -0400654 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400655 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
656 glyph->fMaskFormat = SkMask::kA8_Format;
657 glyph->fHeight = 1;
658 glyph->fWidth = 2;
659 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
660 glyph->fImage = (void *)glyphImage;
661 }
662
663 // Make sure we can find the fall back cache.
664 {
665 SkAutoDescriptor ad;
666 SkScalerContextRec rec;
667 SkScalerContextEffects effects;
668 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
669 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
670 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400671 auto testCache = strikeCache.findStrikeExclusive(*desc);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400672 REPORTER_ASSERT(reporter, !(testCache == nullptr));
673 }
674
Khushal8523b6b2018-06-12 11:26:17 -0700675 // Create the target cache.
676 SkExclusiveStrikePtr testCache;
677 SkAutoDescriptor ad;
678 SkScalerContextRec rec;
679 SkScalerContextEffects effects;
680 SkScalerContextFlags flags = SkScalerContextFlags::kNone;
681 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
682 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
Herb Derby5c0c7982018-06-21 15:15:50 -0400683 testCache = strikeCache.findStrikeExclusive(*desc);
Khushal8523b6b2018-06-12 11:26:17 -0700684 REPORTER_ASSERT(reporter, testCache == nullptr);
Herb Derby5c0c7982018-06-21 15:15:50 -0400685 testCache = strikeCache.createStrikeExclusive(*desc,
Khushal8523b6b2018-06-12 11:26:17 -0700686 clientTf->createScalerContext(effects, desc));
Herb Derby5c0c7982018-06-21 15:15:50 -0400687 auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
688 scalerProxy->initCache(testCache.get(), &strikeCache);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400689
Khushal8523b6b2018-06-12 11:26:17 -0700690 // Look for the lost glyph.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400691 {
Khushal8523b6b2018-06-12 11:26:17 -0700692 const auto& lostGlyph = testCache->getGlyphIDMetrics(
693 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
694 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400695
Herb Derby65b7bfc2018-06-05 13:32:12 -0400696 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
697 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
698 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700699 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400700 }
701
Khushal8523b6b2018-06-12 11:26:17 -0700702 // Look for the lost glyph with a different sub-pix position.
Herb Derby65b7bfc2018-06-05 13:32:12 -0400703 {
Khushal8523b6b2018-06-12 11:26:17 -0700704 const auto& lostGlyph =
705 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
706 testCache->findImage(lostGlyph);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400707
Herb Derby65b7bfc2018-06-05 13:32:12 -0400708 REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
709 REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
710 REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
Khushal8523b6b2018-06-12 11:26:17 -0700711 REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
Herb Derby65b7bfc2018-06-05 13:32:12 -0400712 }
713
Khushal8523b6b2018-06-12 11:26:17 -0700714 for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
715 if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
716 i == SkStrikeClient::CacheMissType::kFontMetrics) {
717 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
718 } else {
719 REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
720 }
Herb Derby65b7bfc2018-06-05 13:32:12 -0400721 }
Herb Derby5c0c7982018-06-21 15:15:50 -0400722 strikeCache.validateGlyphCacheDataSize();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400723
Khushal8523b6b2018-06-12 11:26:17 -0700724 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
725 discardableManager->unlockAndDeleteAll();
Herb Derby65b7bfc2018-06-05 13:32:12 -0400726}
Khushal4010c792018-06-13 09:44:23 -0700727
728DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
729 // Build proxy typeface on the client for initializing the cache.
730 sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
731 SkStrikeServer server(discardableManager.get());
732 SkStrikeClient client(discardableManager, false);
733
734 auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
735 auto tfData = server.serializeTypeface(serverTf.get());
736 auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
737 REPORTER_ASSERT(reporter, clientTf);
738
739 SkPaint paint;
740 paint.setAntiAlias(true);
741 paint.setColor(SK_ColorRED);
742
743 auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
744 const uint8_t glyphImage[] = {0xFF, 0xFF};
745 uint32_t realMask;
746 uint32_t fakeMask;
747
Herb Derby5c0c7982018-06-21 15:15:50 -0400748 SkStrikeCache strikeCache;
749
Khushal4010c792018-06-13 09:44:23 -0700750 {
751 SkAutoDescriptor ad;
752 SkScalerContextRec rec;
753 SkScalerContextEffects effects;
754 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
755 paint.setTypeface(serverTf);
756 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
757 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
758
759 auto context = serverTf->createScalerContext(effects, desc, false);
760 SkGlyph glyph;
761 glyph.initWithGlyphID(lostGlyphID);
762 context->getMetrics(&glyph);
763 realMask = glyph.fMaskFormat;
764 REPORTER_ASSERT(reporter, realMask != MASK_FORMAT_UNKNOWN);
765 }
766
767 // Build a fallback cache.
768 {
769 SkAutoDescriptor ad;
770 SkScalerContextRec rec;
771 SkScalerContextEffects effects;
772 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
773 paint.setTypeface(clientTf);
774 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
775 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
776
Herb Derby5c0c7982018-06-21 15:15:50 -0400777 auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
Khushal4010c792018-06-13 09:44:23 -0700778 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
779 fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
780 glyph->fMaskFormat = fakeMask;
781 glyph->fHeight = 1;
782 glyph->fWidth = 2;
783 fallbackCache->initializeImage(glyphImage, glyph->computeImageSize(), glyph);
784 }
785
786 // Send over the real glyph and make sure the client cache stays intact.
787 {
788 SkAutoDescriptor ad;
Khushal4010c792018-06-13 09:44:23 -0700789 SkScalerContextEffects effects;
790 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
791 paint.setTypeface(serverTf);
Herb Derbyc03716d2018-09-17 11:39:51 -0400792 auto* cacheState = server.getOrCreateCache(
793 paint, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
794 SkMatrix::I(), flags, &effects);
Herb Derbyb2c72162018-08-23 16:16:31 -0400795 cacheState->addGlyph(lostGlyphID, false);
Khushal4010c792018-06-13 09:44:23 -0700796
797 std::vector<uint8_t> serverStrikeData;
798 server.writeStrikeData(&serverStrikeData);
799 REPORTER_ASSERT(reporter,
Herb Derby5c0c7982018-06-21 15:15:50 -0400800 client.readStrikeData(
801 serverStrikeData.data(),
802 serverStrikeData.size()));
Khushal4010c792018-06-13 09:44:23 -0700803 }
804
805 {
806 SkAutoDescriptor ad;
807 SkScalerContextRec rec;
808 SkScalerContextEffects effects;
809 SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
810 paint.setTypeface(clientTf);
811 SkScalerContext::MakeRecAndEffects(paint, nullptr, nullptr, flags, &rec, &effects, false);
812 auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
813
Herb Derby5c0c7982018-06-21 15:15:50 -0400814 auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
Khushal4010c792018-06-13 09:44:23 -0700815 REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
816 auto glyph = fallbackCache->getRawGlyphByID(lostGlyphID);
817 REPORTER_ASSERT(reporter, glyph->fMaskFormat == fakeMask);
818
819 // Try overriding the image, it should stay the same.
820 REPORTER_ASSERT(reporter,
821 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
822 const uint8_t newGlyphImage[] = {0, 0};
823 fallbackCache->initializeImage(newGlyphImage, glyph->computeImageSize(), glyph);
824 REPORTER_ASSERT(reporter,
825 memcmp(glyph->fImage, glyphImage, glyph->computeImageSize()) == 0);
826 }
827
Herb Derby5c0c7982018-06-21 15:15:50 -0400828 strikeCache.validateGlyphCacheDataSize();
Khushal4010c792018-06-13 09:44:23 -0700829
830 // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
831 discardableManager->unlockAndDeleteAll();
832}