SkRemoteGlyphCacheTest.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. /*
  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. #include "include/core/SkGraphics.h"
  8. #include "include/core/SkSurface.h"
  9. #include "include/core/SkTextBlob.h"
  10. #include "include/private/SkMutex.h"
  11. #include "src/core/SkDraw.h"
  12. #include "src/core/SkRemoteGlyphCache.h"
  13. #include "src/core/SkRemoteGlyphCacheImpl.h"
  14. #include "src/core/SkStrike.h"
  15. #include "src/core/SkStrikeCache.h"
  16. #include "src/core/SkStrikeSpec.h"
  17. #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"
  23. #include "src/gpu/text/GrTextContext.h"
  24. class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
  25. public SkStrikeClient::DiscardableHandleManager {
  26. public:
  27. DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
  28. ~DiscardableManager() override = default;
  29. // Server implementation.
  30. SkDiscardableHandleId createHandle() override {
  31. SkAutoMutexExclusive l(fMutex);
  32. // Handles starts as locked.
  33. fLockedHandles.add(++fNextHandleId);
  34. return fNextHandleId;
  35. }
  36. bool lockHandle(SkDiscardableHandleId id) override {
  37. SkAutoMutexExclusive l(fMutex);
  38. if (id <= fLastDeletedHandleId) return false;
  39. fLockedHandles.add(id);
  40. return true;
  41. }
  42. // Client implementation.
  43. bool deleteHandle(SkDiscardableHandleId id) override {
  44. SkAutoMutexExclusive l(fMutex);
  45. return id <= fLastDeletedHandleId;
  46. }
  47. void notifyCacheMiss(SkStrikeClient::CacheMissType type) override {
  48. SkAutoMutexExclusive l(fMutex);
  49. fCacheMissCount[type]++;
  50. }
  51. bool isHandleDeleted(SkDiscardableHandleId id) override {
  52. SkAutoMutexExclusive l(fMutex);
  53. return id <= fLastDeletedHandleId;
  54. }
  55. void unlockAll() {
  56. SkAutoMutexExclusive l(fMutex);
  57. fLockedHandles.reset();
  58. }
  59. void unlockAndDeleteAll() {
  60. SkAutoMutexExclusive l(fMutex);
  61. fLockedHandles.reset();
  62. fLastDeletedHandleId = fNextHandleId;
  63. }
  64. const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
  65. SkAutoMutexExclusive l(fMutex);
  66. return fLockedHandles;
  67. }
  68. SkDiscardableHandleId handleCount() {
  69. SkAutoMutexExclusive l(fMutex);
  70. return fNextHandleId;
  71. }
  72. int cacheMissCount(uint32_t type) {
  73. SkAutoMutexExclusive l(fMutex);
  74. return fCacheMissCount[type];
  75. }
  76. bool hasCacheMiss() const {
  77. SkAutoMutexExclusive l(fMutex);
  78. for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
  79. if (fCacheMissCount[i] > 0) return true;
  80. }
  81. return false;
  82. }
  83. void resetCacheMissCounts() {
  84. SkAutoMutexExclusive l(fMutex);
  85. sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
  86. }
  87. private:
  88. // The tests below run in parallel on multiple threads and use the same
  89. // process global SkStrikeCache. So the implementation needs to be
  90. // thread-safe.
  91. mutable SkMutex fMutex;
  92. SkDiscardableHandleId fNextHandleId = 0u;
  93. SkDiscardableHandleId fLastDeletedHandleId = 0u;
  94. SkTHashSet<SkDiscardableHandleId> fLockedHandles;
  95. int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
  96. };
  97. sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
  98. SkFont font;
  99. font.setTypeface(tf);
  100. font.setHinting(SkFontHinting::kNormal);
  101. font.setSize(1u);
  102. font.setEdging(SkFont::Edging::kAntiAlias);
  103. font.setSubpixel(true);
  104. SkTextBlobBuilder builder;
  105. SkRect bounds = SkRect::MakeWH(10, 10);
  106. const auto& runBuffer = builder.allocRunPosH(font, glyphCount, 0, &bounds);
  107. SkASSERT(runBuffer.utf8text == nullptr);
  108. SkASSERT(runBuffer.clusters == nullptr);
  109. for (int i = 0; i < glyphCount; i++) {
  110. runBuffer.glyphs[i] = static_cast<SkGlyphID>(i);
  111. runBuffer.pos[i] = SkIntToScalar(i);
  112. }
  113. return builder.make();
  114. }
  115. static void compare_blobs(const SkBitmap& expected, const SkBitmap& actual,
  116. skiatest::Reporter* reporter, int tolerance = 0) {
  117. SkASSERT(expected.width() == actual.width());
  118. SkASSERT(expected.height() == actual.height());
  119. for (int i = 0; i < expected.width(); ++i) {
  120. for (int j = 0; j < expected.height(); ++j) {
  121. SkColor expectedColor = expected.getColor(i, j);
  122. SkColor actualColor = actual.getColor(i, j);
  123. if (0 == tolerance) {
  124. REPORTER_ASSERT(reporter, expectedColor == actualColor);
  125. } else {
  126. for (int k = 0; k < 4; ++k) {
  127. int expectedChannel = (expectedColor >> (k*8)) & 0xff;
  128. int actualChannel = (actualColor >> (k*8)) & 0xff;
  129. REPORTER_ASSERT(reporter, abs(expectedChannel - actualChannel) <= tolerance);
  130. }
  131. }
  132. }
  133. }
  134. }
  135. SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
  136. SkTextBlobCacheDiffCanvas::Settings settings;
  137. settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
  138. settings.fMaxTextureSize = context->maxTextureSize();
  139. settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
  140. return settings;
  141. }
  142. sk_sp<SkSurface> MakeSurface(int width, int height, GrContext* context) {
  143. const SkImageInfo info =
  144. SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
  145. return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
  146. }
  147. const SkSurfaceProps FindSurfaceProps(GrContext* context) {
  148. auto surface = MakeSurface(1, 1, context);
  149. return surface->props();
  150. }
  151. SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
  152. GrContext* context, const SkMatrix* matrix = nullptr,
  153. SkScalar x = 0) {
  154. auto surface = MakeSurface(width, height, context);
  155. if (matrix) surface->getCanvas()->concat(*matrix);
  156. surface->getCanvas()->drawTextBlob(blob.get(), x, height/2, paint);
  157. SkBitmap bitmap;
  158. bitmap.allocN32Pixels(width, height);
  159. surface->readPixels(bitmap, 0, 0);
  160. return bitmap;
  161. }
  162. DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
  163. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  164. SkStrikeServer server(discardableManager.get());
  165. SkStrikeClient client(discardableManager, false);
  166. auto server_tf = SkTypeface::MakeDefault();
  167. auto tf_data = server.serializeTypeface(server_tf.get());
  168. auto client_tf = client.deserializeTypeface(tf_data->data(), tf_data->size());
  169. REPORTER_ASSERT(reporter, client_tf);
  170. REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
  171. server_tf->uniqueID());
  172. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  173. discardableManager->unlockAndDeleteAll();
  174. }
  175. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
  176. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  177. SkStrikeServer server(discardableManager.get());
  178. SkStrikeClient client(discardableManager, false);
  179. const SkPaint paint;
  180. // Server.
  181. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  182. auto serverTfData = server.serializeTypeface(serverTf.get());
  183. int glyphCount = 10;
  184. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  185. auto props = FindSurfaceProps(ctxInfo.grContext());
  186. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  187. MakeSettings(ctxInfo.grContext()));
  188. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  189. std::vector<uint8_t> serverStrikeData;
  190. server.writeStrikeData(&serverStrikeData);
  191. // Client.
  192. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  193. REPORTER_ASSERT(reporter,
  194. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  195. auto clientBlob = buildTextBlob(clientTf, glyphCount);
  196. SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
  197. SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
  198. compare_blobs(expected, actual, reporter);
  199. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  200. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  201. discardableManager->unlockAndDeleteAll();
  202. }
  203. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_ReleaseTypeFace, reporter, ctxInfo) {
  204. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  205. SkStrikeServer server(discardableManager.get());
  206. SkStrikeClient client(discardableManager, false);
  207. // Server.
  208. auto serverTf = TestEmptyTypeface::Make();
  209. auto serverTfData = server.serializeTypeface(serverTf.get());
  210. REPORTER_ASSERT(reporter, serverTf->unique());
  211. {
  212. const SkPaint paint;
  213. int glyphCount = 10;
  214. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  215. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  216. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  217. MakeSettings(ctxInfo.grContext()));
  218. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  219. REPORTER_ASSERT(reporter, !serverTf->unique());
  220. std::vector<uint8_t> serverStrikeData;
  221. server.writeStrikeData(&serverStrikeData);
  222. }
  223. REPORTER_ASSERT(reporter, serverTf->unique());
  224. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  225. discardableManager->unlockAndDeleteAll();
  226. }
  227. DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
  228. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  229. SkStrikeServer server(discardableManager.get());
  230. SkStrikeClient client(discardableManager, false);
  231. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  232. server.serializeTypeface(serverTf.get());
  233. int glyphCount = 10;
  234. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  235. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  236. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  237. SkPaint paint;
  238. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  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. // Write the strike data and unlock everything. Re-analyzing the blob should lock the handle
  243. // again.
  244. std::vector<uint8_t> fontData;
  245. server.writeStrikeData(&fontData);
  246. discardableManager->unlockAll();
  247. REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 0u);
  248. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  249. REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
  250. REPORTER_ASSERT(reporter, discardableManager->lockedHandles().count() == 1u);
  251. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  252. discardableManager->unlockAndDeleteAll();
  253. }
  254. DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
  255. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  256. SkStrikeServer server(discardableManager.get());
  257. SkStrikeClient client(discardableManager, false);
  258. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  259. server.serializeTypeface(serverTf.get());
  260. int glyphCount = 10;
  261. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  262. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  263. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  264. SkPaint paint;
  265. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  266. REPORTER_ASSERT(reporter, discardableManager->handleCount() == 1u);
  267. // Write the strike data and delete all the handles. Re-analyzing the blob should create new
  268. // handles.
  269. std::vector<uint8_t> fontData;
  270. server.writeStrikeData(&fontData);
  271. discardableManager->unlockAndDeleteAll();
  272. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  273. REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
  274. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  275. discardableManager->unlockAndDeleteAll();
  276. }
  277. DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
  278. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  279. SkStrikeServer server(discardableManager.get());
  280. SkStrikeClient client(discardableManager, false);
  281. // Server.
  282. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  283. auto serverTfData = server.serializeTypeface(serverTf.get());
  284. int glyphCount = 10;
  285. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  286. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  287. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  288. SkPaint paint;
  289. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  290. std::vector<uint8_t> serverStrikeData;
  291. server.writeStrikeData(&serverStrikeData);
  292. // Client.
  293. REPORTER_ASSERT(reporter,
  294. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  295. auto* clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size()).get();
  296. // The cache remains alive until it is pinned in the discardable manager.
  297. SkGraphics::PurgeFontCache();
  298. REPORTER_ASSERT(reporter, !clientTf->unique());
  299. // Once the strike is unpinned and purged, SkStrikeClient should be the only owner of the
  300. // clientTf.
  301. discardableManager->unlockAndDeleteAll();
  302. SkGraphics::PurgeFontCache();
  303. REPORTER_ASSERT(reporter, clientTf->unique());
  304. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  305. discardableManager->unlockAndDeleteAll();
  306. }
  307. DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
  308. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  309. SkStrikeServer server(discardableManager.get());
  310. SkStrikeClient client(discardableManager, false);
  311. // Server.
  312. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  313. auto serverTfData = server.serializeTypeface(serverTf.get());
  314. int glyphCount = 10;
  315. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  316. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  317. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  318. SkPaint paint;
  319. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  320. std::vector<uint8_t> serverStrikeData;
  321. server.writeStrikeData(&serverStrikeData);
  322. // Client.
  323. REPORTER_ASSERT(reporter,
  324. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  325. SkStrikeCache::ValidateGlyphCacheDataSize();
  326. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  327. discardableManager->unlockAndDeleteAll();
  328. }
  329. DEF_TEST(SkRemoteGlyphCache_PurgesServerEntries, reporter) {
  330. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  331. SkStrikeServer server(discardableManager.get());
  332. server.setMaxEntriesInDescriptorMapForTesting(1u);
  333. SkStrikeClient client(discardableManager, false);
  334. {
  335. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  336. int glyphCount = 10;
  337. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  338. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  339. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  340. SkPaint paint;
  341. REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 0u);
  342. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  343. REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
  344. }
  345. // Serialize to release the lock from the strike server and delete all current
  346. // handles.
  347. std::vector<uint8_t> fontData;
  348. server.writeStrikeData(&fontData);
  349. discardableManager->unlockAndDeleteAll();
  350. // Use a different typeface. Creating a new strike should evict the previous
  351. // one.
  352. {
  353. auto serverTf = SkTypeface::MakeFromName("Georgia", SkFontStyle());
  354. int glyphCount = 10;
  355. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  356. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  357. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server);
  358. SkPaint paint;
  359. REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
  360. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  361. REPORTER_ASSERT(reporter, server.remoteGlyphStateMapSizeForTesting() == 1u);
  362. }
  363. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  364. discardableManager->unlockAndDeleteAll();
  365. }
  366. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
  367. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  368. SkStrikeServer server(discardableManager.get());
  369. SkStrikeClient client(discardableManager, false);
  370. SkPaint paint;
  371. paint.setStyle(SkPaint::kStroke_Style);
  372. paint.setStrokeWidth(0);
  373. REPORTER_ASSERT(reporter,
  374. SkStrikeSpec::ShouldDrawAsPath(paint, SkFont(), SkMatrix::I()));
  375. // Server.
  376. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  377. auto serverTfData = server.serializeTypeface(serverTf.get());
  378. int glyphCount = 10;
  379. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  380. auto props = FindSurfaceProps(ctxInfo.grContext());
  381. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  382. MakeSettings(ctxInfo.grContext()));
  383. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  384. std::vector<uint8_t> serverStrikeData;
  385. server.writeStrikeData(&serverStrikeData);
  386. // Client.
  387. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  388. REPORTER_ASSERT(reporter,
  389. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  390. auto clientBlob = buildTextBlob(clientTf, glyphCount);
  391. SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
  392. SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
  393. compare_blobs(expected, actual, reporter, 1);
  394. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  395. SkStrikeCache::ValidateGlyphCacheDataSize();
  396. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  397. discardableManager->unlockAndDeleteAll();
  398. }
  399. sk_sp<SkTextBlob> make_blob_causing_fallback(
  400. sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
  401. SkFont font;
  402. font.setSubpixel(true);
  403. font.setSize(96);
  404. font.setHinting(SkFontHinting::kNormal);
  405. font.setTypeface(targetTf);
  406. REPORTER_ASSERT(reporter,
  407. !SkStrikeSpec::ShouldDrawAsPath(SkPaint(), font, SkMatrix::I()));
  408. char s[] = "Skia";
  409. int runSize = strlen(s);
  410. SkTextBlobBuilder builder;
  411. SkRect bounds = SkRect::MakeIWH(100, 100);
  412. const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
  413. SkASSERT(runBuffer.utf8text == nullptr);
  414. SkASSERT(runBuffer.clusters == nullptr);
  415. SkFont(sk_ref_sp(glyphTf)).textToGlyphs(s, strlen(s), SkTextEncoding::kUTF8,
  416. runBuffer.glyphs, runSize);
  417. SkRect glyphBounds;
  418. font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
  419. REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
  420. for (int i = 0; i < runSize; i++) {
  421. runBuffer.pos[i] = i * 10;
  422. }
  423. return builder.make();
  424. }
  425. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsMaskWithPathFallback,
  426. reporter, ctxInfo) {
  427. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  428. SkStrikeServer server(discardableManager.get());
  429. SkStrikeClient client(discardableManager, false);
  430. SkPaint paint;
  431. auto serverTf = MakeResourceAsTypeface("fonts/HangingS.ttf");
  432. // TODO: when the cq bots can handle this font remove the check.
  433. if (serverTf == nullptr) {
  434. return;
  435. }
  436. auto serverTfData = server.serializeTypeface(serverTf.get());
  437. auto serverBlob = make_blob_causing_fallback(serverTf, serverTf.get(), reporter);
  438. auto props = FindSurfaceProps(ctxInfo.grContext());
  439. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  440. MakeSettings(ctxInfo.grContext()));
  441. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  442. std::vector<uint8_t> serverStrikeData;
  443. server.writeStrikeData(&serverStrikeData);
  444. // Client.
  445. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  446. REPORTER_ASSERT(reporter,
  447. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  448. auto clientBlob = make_blob_causing_fallback(clientTf, serverTf.get(), reporter);
  449. SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
  450. SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
  451. compare_blobs(expected, actual, reporter);
  452. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  453. SkStrikeCache::ValidateGlyphCacheDataSize();
  454. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  455. discardableManager->unlockAndDeleteAll();
  456. }
  457. #if 0
  458. // TODO: turn this one when I figure out how to deal with the pixel variance from linear
  459. // interpolation from GPU to GPU.
  460. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsSDFTWithAllARGBFallback,
  461. reporter, ctxInfo) {
  462. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  463. SkStrikeServer server(discardableManager.get());
  464. SkStrikeClient client(discardableManager, false);
  465. SkPaint paint;
  466. auto serverTf = ToolUtils::planet_typeface();
  467. // TODO: when the cq bots can handle this font remove the check.
  468. if (serverTf == nullptr) {
  469. return;
  470. }
  471. auto serverTfData = server.serializeTypeface(serverTf.get());
  472. auto makeBlob = [&reporter](sk_sp<SkTypeface> typeface) {
  473. SkFont font;
  474. font.setSubpixel(true);
  475. font.setSize(96);
  476. font.setHinting(SkFontHinting::kNormal);
  477. font.setTypeface(typeface);
  478. REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
  479. // Mercury to Uranus.
  480. SkGlyphID glyphs[] = {1, 2, 3, 4, 5, 6, 7, 8};
  481. SkTextBlobBuilder builder;
  482. SkRect bounds = SkRect::MakeIWH(100, 100);
  483. const auto& runBuffer = builder.allocRunPosH(font, SK_ARRAY_COUNT(glyphs), 100, &bounds);
  484. SkASSERT(runBuffer.utf8text == nullptr);
  485. SkASSERT(runBuffer.clusters == nullptr);
  486. std::copy(std::begin(glyphs), std::end(glyphs), runBuffer.glyphs);
  487. for (size_t i = 0; i < SK_ARRAY_COUNT(glyphs); i++) {
  488. runBuffer.pos[i] = i * 100;
  489. }
  490. return builder.make();
  491. };
  492. auto serverBlob = makeBlob(serverTf);
  493. auto props = FindSurfaceProps(ctxInfo.grContext());
  494. SkTextBlobCacheDiffCanvas cache_diff_canvas(800, 800, props, &server,
  495. MakeSettings(ctxInfo.grContext()));
  496. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 400, paint);
  497. std::vector<uint8_t> serverStrikeData;
  498. server.writeStrikeData(&serverStrikeData);
  499. // Client.
  500. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  501. REPORTER_ASSERT(reporter,
  502. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  503. auto clientBlob = makeBlob(clientTf);
  504. SkBitmap expected = RasterBlob(serverBlob, 800, 800, paint, ctxInfo.grContext());
  505. SkBitmap actual = RasterBlob(clientBlob, 800, 800, paint, ctxInfo.grContext());
  506. // Pixel variance can be high because of the atlas placement, and large scaling in the linear
  507. // interpolation.
  508. compare_blobs(expected, actual, reporter, 36);
  509. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  510. SkStrikeCache::ValidateGlyphCacheDataSize();
  511. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  512. discardableManager->unlockAndDeleteAll();
  513. }
  514. #endif
  515. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextXY, reporter, ctxInfo) {
  516. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  517. SkStrikeServer server(discardableManager.get());
  518. SkStrikeClient client(discardableManager, false);
  519. SkPaint paint;
  520. paint.setAntiAlias(true);
  521. // Server.
  522. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  523. auto serverTfData = server.serializeTypeface(serverTf.get());
  524. int glyphCount = 10;
  525. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  526. auto props = FindSurfaceProps(ctxInfo.grContext());
  527. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  528. MakeSettings(ctxInfo.grContext()));
  529. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0.5, 0, paint);
  530. std::vector<uint8_t> serverStrikeData;
  531. server.writeStrikeData(&serverStrikeData);
  532. // Client.
  533. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  534. REPORTER_ASSERT(reporter,
  535. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  536. auto clientBlob = buildTextBlob(clientTf, glyphCount);
  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);
  539. compare_blobs(expected, actual, reporter);
  540. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  541. SkStrikeCache::ValidateGlyphCacheDataSize();
  542. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  543. discardableManager->unlockAndDeleteAll();
  544. }
  545. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
  546. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  547. SkStrikeServer server(discardableManager.get());
  548. SkStrikeClient client(discardableManager, false);
  549. SkPaint paint;
  550. SkFont font;
  551. // A perspective transform forces fallback to dft.
  552. SkMatrix matrix = SkMatrix::I();
  553. matrix[SkMatrix::kMPersp0] = 0.5f;
  554. REPORTER_ASSERT(reporter, matrix.hasPerspective());
  555. SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
  556. GrTextContext::Options options;
  557. GrTextContext::SanitizeOptions(&options);
  558. REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
  559. paint, font, matrix, surfaceProps, true, options));
  560. // Server.
  561. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  562. auto serverTfData = server.serializeTypeface(serverTf.get());
  563. int glyphCount = 10;
  564. auto serverBlob = buildTextBlob(serverTf, glyphCount);
  565. const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
  566. SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
  567. MakeSettings(ctxInfo.grContext()));
  568. cache_diff_canvas.concat(matrix);
  569. cache_diff_canvas.drawTextBlob(serverBlob.get(), 0, 0, paint);
  570. std::vector<uint8_t> serverStrikeData;
  571. server.writeStrikeData(&serverStrikeData);
  572. // Client.
  573. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  574. REPORTER_ASSERT(reporter,
  575. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  576. auto clientBlob = buildTextBlob(clientTf, glyphCount);
  577. SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
  578. SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
  579. compare_blobs(expected, actual, reporter);
  580. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  581. SkStrikeCache::ValidateGlyphCacheDataSize();
  582. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  583. discardableManager->unlockAndDeleteAll();
  584. }
  585. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
  586. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  587. SkStrikeServer server(discardableManager.get());
  588. SkStrikeClient client(discardableManager, false);
  589. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  590. auto tfData = server.serializeTypeface(serverTf.get());
  591. auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
  592. REPORTER_ASSERT(reporter, clientTf);
  593. int glyphCount = 10;
  594. auto clientBlob = buildTextBlob(clientTf, glyphCount);
  595. // Raster the client-side blob without the glyph data, we should get cache miss notifications.
  596. SkPaint paint;
  597. SkMatrix matrix = SkMatrix::I();
  598. RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
  599. REPORTER_ASSERT(reporter,
  600. discardableManager->cacheMissCount(SkStrikeClient::kFontMetrics) == 1);
  601. REPORTER_ASSERT(reporter,
  602. discardableManager->cacheMissCount(SkStrikeClient::kGlyphMetrics) == 10);
  603. // There shouldn't be any image or path requests, since we mark the glyph as empty on a cache
  604. // miss.
  605. REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphImage) == 0);
  606. REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(SkStrikeClient::kGlyphPath) == 0);
  607. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  608. discardableManager->unlockAndDeleteAll();
  609. }
  610. sk_sp<SkTextBlob> MakeEmojiBlob(sk_sp<SkTypeface> serverTf, SkScalar textSize,
  611. sk_sp<SkTypeface> clientTf = nullptr) {
  612. SkFont font;
  613. font.setTypeface(serverTf);
  614. font.setSize(textSize);
  615. const char* text = ToolUtils::emoji_sample_text();
  616. SkFont serverFont = font;
  617. auto blob = SkTextBlob::MakeFromText(text, strlen(text), font);
  618. if (clientTf == nullptr) return blob;
  619. SkSerialProcs s_procs;
  620. s_procs.fTypefaceProc = [](SkTypeface*, void* ctx) -> sk_sp<SkData> {
  621. return SkData::MakeUninitialized(1u);
  622. };
  623. auto serialized = blob->serialize(s_procs);
  624. SkDeserialProcs d_procs;
  625. d_procs.fTypefaceCtx = &clientTf;
  626. d_procs.fTypefaceProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
  627. return *(static_cast<sk_sp<SkTypeface>*>(ctx));
  628. };
  629. return SkTextBlob::Deserialize(serialized->data(), serialized->size(), d_procs);
  630. }
  631. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_TypefaceWithNoPaths, reporter, ctxInfo) {
  632. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  633. SkStrikeServer server(discardableManager.get());
  634. SkStrikeClient client(discardableManager, false);
  635. auto serverTf = ToolUtils::emoji_typeface();
  636. auto serverTfData = server.serializeTypeface(serverTf.get());
  637. auto clientTf = client.deserializeTypeface(serverTfData->data(), serverTfData->size());
  638. for (SkScalar textSize : { 70, 180, 270, 340}) {
  639. auto serverBlob = MakeEmojiBlob(serverTf, textSize);
  640. auto props = FindSurfaceProps(ctxInfo.grContext());
  641. SkTextBlobCacheDiffCanvas cache_diff_canvas(500, 500, props, &server,
  642. MakeSettings(ctxInfo.grContext()));
  643. SkPaint paint;
  644. cache_diff_canvas.drawTextBlob(serverBlob.get(), 100, 100, paint);
  645. std::vector<uint8_t> serverStrikeData;
  646. server.writeStrikeData(&serverStrikeData);
  647. REPORTER_ASSERT(reporter,
  648. client.readStrikeData(serverStrikeData.data(), serverStrikeData.size()));
  649. auto clientBlob = MakeEmojiBlob(serverTf, textSize, clientTf);
  650. REPORTER_ASSERT(reporter, clientBlob);
  651. RasterBlob(clientBlob, 500, 500, paint, ctxInfo.grContext());
  652. REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
  653. SkStrikeCache::ValidateGlyphCacheDataSize();
  654. discardableManager->resetCacheMissCounts();
  655. }
  656. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  657. discardableManager->unlockAndDeleteAll();
  658. }
  659. DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
  660. // Build proxy typeface on the client for initializing the cache.
  661. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  662. SkStrikeServer server(discardableManager.get());
  663. SkStrikeClient client(discardableManager, false);
  664. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  665. auto tfData = server.serializeTypeface(serverTf.get());
  666. auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
  667. REPORTER_ASSERT(reporter, clientTf);
  668. SkFont font;
  669. font.setTypeface(clientTf);
  670. font.setSubpixel(true);
  671. SkPaint paint;
  672. paint.setAntiAlias(true);
  673. paint.setColor(SK_ColorRED);
  674. auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
  675. const uint8_t glyphImage[] = {0xFF, 0xFF};
  676. SkStrikeCache strikeCache;
  677. // Build a fallback cache.
  678. {
  679. SkAutoDescriptor ad;
  680. SkScalerContextRec rec;
  681. SkScalerContextEffects effects;
  682. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  683. SkScalerContext::MakeRecAndEffects(
  684. font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
  685. SkMatrix::I(), &rec, &effects);
  686. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  687. auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
  688. SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, SkMask::kA8_Format, false};
  689. fallbackCache->glyphFromPrototype(proto, (void*)glyphImage);
  690. }
  691. // Make sure we can find the fall back cache.
  692. {
  693. SkAutoDescriptor ad;
  694. SkScalerContextRec rec;
  695. SkScalerContextEffects effects;
  696. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  697. SkScalerContext::MakeRecAndEffects(
  698. font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
  699. SkMatrix::I(), &rec, &effects);
  700. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  701. auto testCache = strikeCache.findStrikeExclusive(*desc);
  702. REPORTER_ASSERT(reporter, !(testCache == nullptr));
  703. }
  704. // Create the target cache.
  705. SkExclusiveStrikePtr testCache;
  706. SkAutoDescriptor ad;
  707. SkScalerContextRec rec;
  708. SkScalerContextEffects effects;
  709. SkScalerContextFlags flags = SkScalerContextFlags::kNone;
  710. SkScalerContext::MakeRecAndEffects(
  711. font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
  712. SkMatrix::I(), &rec, &effects);
  713. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  714. testCache = strikeCache.findStrikeExclusive(*desc);
  715. REPORTER_ASSERT(reporter, testCache == nullptr);
  716. testCache = strikeCache.createStrikeExclusive(*desc,
  717. clientTf->createScalerContext(effects, desc));
  718. auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
  719. scalerProxy->initCache(testCache.get(), &strikeCache);
  720. // Look for the lost glyph.
  721. {
  722. SkPoint pt{SkFixedToScalar(lostGlyphID.getSubXFixed()),
  723. SkFixedToScalar(lostGlyphID.getSubYFixed())};
  724. SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
  725. testCache->prepareImage(lostGlyph);
  726. REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
  727. REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
  728. REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
  729. REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
  730. }
  731. // Look for the lost glyph with a different sub-pix position.
  732. {
  733. SkPoint pt{SkFixedToScalar(SK_FixedQuarter),
  734. SkFixedToScalar(SK_FixedQuarter)};
  735. SkGlyph* lostGlyph = testCache->glyph(lostGlyphID.code(), pt);
  736. testCache->prepareImage(lostGlyph);
  737. REPORTER_ASSERT(reporter, lostGlyph->height() == 1);
  738. REPORTER_ASSERT(reporter, lostGlyph->width() == 2);
  739. REPORTER_ASSERT(reporter, lostGlyph->maskFormat() == SkMask::kA8_Format);
  740. REPORTER_ASSERT(reporter, memcmp(lostGlyph->image(), glyphImage, sizeof(glyphImage)) == 0);
  741. }
  742. for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
  743. if (i == SkStrikeClient::CacheMissType::kGlyphMetricsFallback ||
  744. i == SkStrikeClient::CacheMissType::kFontMetrics) {
  745. REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 2);
  746. } else {
  747. REPORTER_ASSERT(reporter, discardableManager->cacheMissCount(i) == 0);
  748. }
  749. }
  750. strikeCache.validateGlyphCacheDataSize();
  751. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  752. discardableManager->unlockAndDeleteAll();
  753. }
  754. DEF_TEST(SkRemoteGlyphCache_ReWriteGlyph, reporter) {
  755. // Build proxy typeface on the client for initializing the cache.
  756. sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
  757. SkStrikeServer server(discardableManager.get());
  758. SkStrikeClient client(discardableManager, false);
  759. auto serverTf = SkTypeface::MakeFromName("monospace", SkFontStyle());
  760. auto tfData = server.serializeTypeface(serverTf.get());
  761. auto clientTf = client.deserializeTypeface(tfData->data(), tfData->size());
  762. REPORTER_ASSERT(reporter, clientTf);
  763. SkFont font;
  764. font.setEdging(SkFont::Edging::kAntiAlias);
  765. SkPaint paint;
  766. paint.setColor(SK_ColorRED);
  767. auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
  768. const uint8_t glyphImage[] = {0xFF, 0xFF};
  769. SkMask::Format realMask;
  770. SkMask::Format fakeMask;
  771. SkStrikeCache strikeCache;
  772. {
  773. SkAutoDescriptor ad;
  774. SkScalerContextRec rec;
  775. SkScalerContextEffects effects;
  776. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  777. font.setTypeface(serverTf);
  778. SkScalerContext::MakeRecAndEffects(
  779. font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
  780. SkMatrix::I(), &rec, &effects);
  781. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  782. auto context = serverTf->createScalerContext(effects, desc, false);
  783. SkGlyph glyph{lostGlyphID};
  784. context->getMetrics(&glyph);
  785. realMask = glyph.maskFormat();
  786. }
  787. // Build a fallback cache.
  788. {
  789. SkAutoDescriptor ad;
  790. SkScalerContextRec rec;
  791. SkScalerContextEffects effects;
  792. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  793. font.setTypeface(clientTf);
  794. SkScalerContext::MakeRecAndEffects(
  795. font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
  796. SkMatrix::I(), &rec, &effects);
  797. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  798. auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
  799. fakeMask = (realMask == SkMask::kA8_Format) ? SkMask::kBW_Format : SkMask::kA8_Format;
  800. SkGlyphPrototype proto = {lostGlyphID, 0.f, 0.f, 2, 1, 0, 0, fakeMask, false};
  801. fallbackCache->glyphFromPrototype(proto, (void *)glyphImage);
  802. }
  803. // Send over the real glyph and make sure the client cache stays intact.
  804. {
  805. SkAutoDescriptor ad;
  806. SkScalerContextEffects effects;
  807. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  808. font.setTypeface(serverTf);
  809. auto* cacheState = server.getOrCreateCache(
  810. paint, font, SkSurfacePropsCopyOrDefault(nullptr),
  811. SkMatrix::I(), flags, &effects);
  812. cacheState->addGlyph(lostGlyphID, false);
  813. std::vector<uint8_t> serverStrikeData;
  814. server.writeStrikeData(&serverStrikeData);
  815. REPORTER_ASSERT(reporter,
  816. client.readStrikeData(
  817. serverStrikeData.data(),
  818. serverStrikeData.size()));
  819. }
  820. {
  821. SkAutoDescriptor ad;
  822. SkScalerContextRec rec;
  823. SkScalerContextEffects effects;
  824. SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
  825. font.setTypeface(clientTf);
  826. SkScalerContext::MakeRecAndEffects(
  827. font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
  828. SkMatrix::I(), &rec, &effects);
  829. auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
  830. auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
  831. REPORTER_ASSERT(reporter, fallbackCache.get() != nullptr);
  832. auto glyph = fallbackCache->glyphOrNull(lostGlyphID);
  833. REPORTER_ASSERT(reporter, glyph && glyph->maskFormat() == fakeMask);
  834. if (glyph) {
  835. REPORTER_ASSERT(reporter,
  836. memcmp(glyph->image(), glyphImage, glyph->imageSize()) == 0);
  837. }
  838. }
  839. strikeCache.validateGlyphCacheDataSize();
  840. // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
  841. discardableManager->unlockAndDeleteAll();
  842. }