Home | History | Annotate | Download | only in tests
      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 
      8 #include "Resources.h"
      9 #include "SkDraw.h"
     10 #include "SkGraphics.h"
     11 #include "SkMutex.h"
     12 #include "SkRemoteGlyphCache.h"
     13 #include "SkRemoteGlyphCacheImpl.h"
     14 #include "SkStrike.h"
     15 #include "SkStrikeCache.h"
     16 #include "SkSurface.h"
     17 #include "SkSurfacePriv.h"
     18 #include "SkTestEmptyTypeface.h"
     19 #include "SkTextBlob.h"
     20 #include "SkTypeface_remote.h"
     21 #include "Test.h"
     22 
     23 #include "text/GrTextContext.h"
     24 
     25 class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
     26                            public SkStrikeClient::DiscardableHandleManager {
     27 public:
     28     DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
     29     ~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; }
     45     void notifyCacheMiss(SkStrikeClient::CacheMissType type) override { fCacheMissCount[type]++; }
     46     bool isHandleDeleted(SkDiscardableHandleId id) override { return id <= fLastDeletedHandleId; }
     47 
     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; }
     55     int cacheMissCount(uint32_t type) { return fCacheMissCount[type]; }
     56     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     }
     62 
     63 private:
     64     SkDiscardableHandleId fNextHandleId = 0u;
     65     SkDiscardableHandleId fLastDeletedHandleId = 0u;
     66     SkTHashSet<SkDiscardableHandleId> fLockedHandles;
     67     int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
     68 };
     69 
     70 sk_sp<SkTextBlob> buildTextBlob(sk_sp<SkTypeface> tf, int glyphCount) {
     71     SkFont font;
     72     font.setTypeface(tf);
     73     font.setHinting(kNormal_SkFontHinting);
     74     font.setSize(1u);
     75     font.setEdging(SkFont::Edging::kAntiAlias);
     76     font.setSubpixel(true);
     77 
     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 
     91 static 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         }
    109     }
    110 }
    111 
    112 SkTextBlobCacheDiffCanvas::Settings MakeSettings(GrContext* context) {
    113     SkTextBlobCacheDiffCanvas::Settings settings;
    114     settings.fContextSupportsDistanceFieldText = context->supportsDistanceFieldText();
    115     settings.fMaxTextureSize = context->maxTextureSize();
    116     settings.fMaxTextureBytes = GrContextOptions().fGlyphCacheTextureMaximumBytes;
    117     return settings;
    118 }
    119 
    120 sk_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 
    126 const SkSurfaceProps FindSurfaceProps(GrContext* context) {
    127     auto surface = MakeSurface(1, 1, context);
    128     return surface->props();
    129 }
    130 
    131 SkBitmap RasterBlob(sk_sp<SkTextBlob> blob, int width, int height, const SkPaint& paint,
    132                     GrContext* context, const SkMatrix* matrix = nullptr,
    133                     SkScalar x = 0) {
    134     auto surface = MakeSurface(width, height, context);
    135     if (matrix) surface->getCanvas()->concat(*matrix);
    136     surface->getCanvas()->drawTextBlob(blob.get(), x, 0, paint);
    137     SkBitmap bitmap;
    138     bitmap.allocN32Pixels(width, height);
    139     surface->readPixels(bitmap, 0, 0);
    140     return bitmap;
    141 }
    142 
    143 DEF_TEST(SkRemoteGlyphCache_TypefaceSerialization, reporter) {
    144     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    145     SkStrikeServer server(discardableManager.get());
    146     SkStrikeClient client(discardableManager, false);
    147 
    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);
    153     REPORTER_ASSERT(reporter, static_cast<SkTypefaceProxy*>(client_tf.get())->remoteTypefaceID() ==
    154                                       server_tf->uniqueID());
    155 
    156     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    157     discardableManager->unlockAndDeleteAll();
    158 }
    159 
    160 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_StrikeSerialization, reporter, ctxInfo) {
    161     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    162     SkStrikeServer server(discardableManager.get());
    163     SkStrikeClient client(discardableManager, false);
    164     const SkPaint paint;
    165 
    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);
    172     auto props = FindSurfaceProps(ctxInfo.grContext());
    173     SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
    174                                                 MakeSettings(ctxInfo.grContext()));
    175     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 
    186     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
    187     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
    188     compare_blobs(expected, actual, reporter);
    189     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
    190 
    191     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    192     discardableManager->unlockAndDeleteAll();
    193 }
    194 
    195 DEF_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, 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 
    224 DEF_TEST(SkRemoteGlyphCache_StrikeLockingServer, reporter) {
    225     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    226     SkStrikeServer server(discardableManager.get());
    227     SkStrikeClient client(discardableManager, false);
    228 
    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, 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);
    253 
    254     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    255     discardableManager->unlockAndDeleteAll();
    256 }
    257 
    258 DEF_TEST(SkRemoteGlyphCache_StrikeDeletionServer, reporter) {
    259     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    260     SkStrikeServer server(discardableManager.get());
    261     SkStrikeClient client(discardableManager, false);
    262 
    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, 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);
    280     REPORTER_ASSERT(reporter, discardableManager->handleCount() == 2u);
    281 
    282     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    283     discardableManager->unlockAndDeleteAll();
    284 }
    285 
    286 DEF_TEST(SkRemoteGlyphCache_StrikePinningClient, reporter) {
    287     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    288     SkStrikeServer server(discardableManager.get());
    289     SkStrikeClient client(discardableManager, false);
    290 
    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, 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());
    320 
    321     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    322     discardableManager->unlockAndDeleteAll();
    323 }
    324 
    325 DEF_TEST(SkRemoteGlyphCache_ClientMemoryAccounting, reporter) {
    326     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    327     SkStrikeServer server(discardableManager.get());
    328     SkStrikeClient client(discardableManager, false);
    329 
    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, 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()));
    348     SkStrikeCache::ValidateGlyphCacheDataSize();
    349 
    350     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    351     discardableManager->unlockAndDeleteAll();
    352 }
    353 
    354 DEF_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, 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, 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 
    398 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsPath, reporter, ctxInfo) {
    399     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    400     SkStrikeServer server(discardableManager.get());
    401     SkStrikeClient client(discardableManager, false);
    402     SkPaint paint;
    403     paint.setStyle(SkPaint::kStroke_Style);
    404     paint.setStrokeWidth(0);
    405     REPORTER_ASSERT(reporter, SkDraw::ShouldDrawTextAsPaths(SkFont(), paint, SkMatrix::I()));
    406 
    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);
    413     auto props = FindSurfaceProps(ctxInfo.grContext());
    414     SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
    415                                                 MakeSettings(ctxInfo.grContext()));
    416     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 
    427     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext());
    428     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext());
    429     compare_blobs(expected, actual, reporter, 1);
    430     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
    431     SkStrikeCache::ValidateGlyphCacheDataSize();
    432 
    433     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    434     discardableManager->unlockAndDeleteAll();
    435 }
    436 
    437 sk_sp<SkTextBlob> make_blob_causing_fallback(
    438         sk_sp<SkTypeface> targetTf, const SkTypeface* glyphTf, skiatest::Reporter* reporter) {
    439     SkFont font;
    440     font.setSubpixel(true);
    441     font.setSize(96);
    442     font.setHinting(kNormal_SkFontHinting);
    443     font.setTypeface(targetTf);
    444 
    445     REPORTER_ASSERT(reporter, !SkDraw::ShouldDrawTextAsPaths(font, SkPaint(), SkMatrix::I()));
    446 
    447     char s[] = "Skia";
    448     int runSize = strlen(s);
    449 
    450     SkTextBlobBuilder builder;
    451     SkRect bounds = SkRect::MakeIWH(100, 100);
    452     const auto& runBuffer = builder.allocRunPosH(font, runSize, 10, &bounds);
    453     SkASSERT(runBuffer.utf8text == nullptr);
    454     SkASSERT(runBuffer.clusters == nullptr);
    455 
    456     glyphTf->charsToGlyphs(s, SkTypeface::kUTF8_Encoding, runBuffer.glyphs, runSize);
    457 
    458     SkRect glyphBounds;
    459     font.getWidths(runBuffer.glyphs, 1, nullptr, &glyphBounds);
    460 
    461     REPORTER_ASSERT(reporter, glyphBounds.width() > SkStrikeCommon::kSkSideTooBigForAtlas);
    462 
    463     for (int i = 0; i < runSize; i++) {
    464         runBuffer.pos[i] = i * 10;
    465     }
    466 
    467     return builder.make();
    468 }
    469 
    470 DEF_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 
    487     auto props = FindSurfaceProps(ctxInfo.grContext());
    488     SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, 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 
    512 DEF_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);
    518 
    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);
    525     auto props = FindSurfaceProps(ctxInfo.grContext());
    526     SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, 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);
    541     compare_blobs(expected, actual, reporter);
    542     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 
    549 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_DrawTextAsDFT, reporter, ctxInfo) {
    550     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    551     SkStrikeServer server(discardableManager.get());
    552     SkStrikeClient client(discardableManager, false);
    553     SkPaint paint;
    554     SkFont font;
    555 
    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());
    560     SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
    561     GrTextContext::Options options;
    562     GrTextContext::SanitizeOptions(&options);
    563     REPORTER_ASSERT(reporter, GrTextContext::CanDrawAsDistanceFields(
    564                                       paint, font, matrix, surfaceProps, true, options));
    565 
    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);
    572     const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
    573     SkTextBlobCacheDiffCanvas cache_diff_canvas(10, 10, props, &server,
    574                                                 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 
    587     SkBitmap expected = RasterBlob(serverBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
    588     SkBitmap actual = RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
    589     compare_blobs(expected, actual, reporter);
    590     REPORTER_ASSERT(reporter, !discardableManager->hasCacheMiss());
    591     SkStrikeCache::ValidateGlyphCacheDataSize();
    592 
    593     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    594     discardableManager->unlockAndDeleteAll();
    595 }
    596 
    597 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRemoteGlyphCache_CacheMissReporting, reporter, ctxInfo) {
    598     sk_sp<DiscardableManager> discardableManager = sk_make_sp<DiscardableManager>();
    599     SkStrikeServer server(discardableManager.get());
    600     SkStrikeClient client(discardableManager, false);
    601 
    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.
    610     SkPaint paint;
    611     SkMatrix matrix = SkMatrix::I();
    612     RasterBlob(clientBlob, 10, 10, paint, ctxInfo.grContext(), &matrix);
    613     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 }
    626 
    627 DEF_TEST(SkRemoteGlyphCache_SearchOfDesperation, reporter) {
    628     // 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 
    638     SkFont font;
    639     font.setTypeface(clientTf);
    640     SkPaint paint;
    641     paint.setAntiAlias(true);
    642     paint.setColor(SK_ColorRED);
    643 
    644     auto lostGlyphID = SkPackedGlyphID(1, SK_FixedHalf, SK_FixedHalf);
    645     const uint8_t glyphImage[] = {0xFF, 0xFF};
    646 
    647     SkStrikeCache strikeCache;
    648 
    649     // Build a fallback cache.
    650     {
    651         SkAutoDescriptor ad;
    652         SkScalerContextRec rec;
    653         SkScalerContextEffects effects;
    654         SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
    655         SkScalerContext::MakeRecAndEffects(
    656                 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
    657                 SkMatrix::I(), &rec, &effects);
    658         auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    659 
    660         auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
    661         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;
    675         SkScalerContext::MakeRecAndEffects(
    676                 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
    677                 SkMatrix::I(), &rec, &effects);
    678         auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    679         auto testCache = strikeCache.findStrikeExclusive(*desc);
    680         REPORTER_ASSERT(reporter, !(testCache == nullptr));
    681     }
    682 
    683     // Create the target cache.
    684     SkExclusiveStrikePtr testCache;
    685     SkAutoDescriptor ad;
    686     SkScalerContextRec rec;
    687     SkScalerContextEffects effects;
    688     SkScalerContextFlags flags = SkScalerContextFlags::kNone;
    689     SkScalerContext::MakeRecAndEffects(
    690             font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
    691             SkMatrix::I(), &rec, &effects);
    692     auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    693     testCache = strikeCache.findStrikeExclusive(*desc);
    694     REPORTER_ASSERT(reporter, testCache == nullptr);
    695     testCache = strikeCache.createStrikeExclusive(*desc,
    696                                                      clientTf->createScalerContext(effects, desc));
    697     auto scalerProxy = static_cast<SkScalerContextProxy*>(testCache->getScalerContext());
    698     scalerProxy->initCache(testCache.get(), &strikeCache);
    699 
    700     // Look for the lost glyph.
    701     {
    702         const auto& lostGlyph = testCache->getGlyphIDMetrics(
    703                 lostGlyphID.code(), lostGlyphID.getSubXFixed(), lostGlyphID.getSubYFixed());
    704         testCache->findImage(lostGlyph);
    705 
    706         REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
    707         REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
    708         REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
    709         REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
    710     }
    711 
    712     // Look for the lost glyph with a different sub-pix position.
    713     {
    714         const auto& lostGlyph =
    715                 testCache->getGlyphIDMetrics(lostGlyphID.code(), SK_FixedQuarter, SK_FixedQuarter);
    716         testCache->findImage(lostGlyph);
    717 
    718         REPORTER_ASSERT(reporter, lostGlyph.fHeight == 1);
    719         REPORTER_ASSERT(reporter, lostGlyph.fWidth == 2);
    720         REPORTER_ASSERT(reporter, lostGlyph.fMaskFormat == SkMask::kA8_Format);
    721         REPORTER_ASSERT(reporter, memcmp(lostGlyph.fImage, glyphImage, sizeof(glyphImage)) == 0);
    722     }
    723 
    724     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         }
    731     }
    732     strikeCache.validateGlyphCacheDataSize();
    733 
    734     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    735     discardableManager->unlockAndDeleteAll();
    736 }
    737 
    738 DEF_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 
    749     SkFont font;
    750     font.setEdging(SkFont::Edging::kAntiAlias);
    751     SkPaint paint;
    752     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 
    759     SkStrikeCache strikeCache;
    760 
    761     {
    762         SkAutoDescriptor ad;
    763         SkScalerContextRec rec;
    764         SkScalerContextEffects effects;
    765         SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
    766         font.setTypeface(serverTf);
    767         SkScalerContext::MakeRecAndEffects(
    768                 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
    769                 SkMatrix::I(), &rec, &effects);
    770         auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    771 
    772         auto context = serverTf->createScalerContext(effects, desc, false);
    773         SkGlyph glyph{lostGlyphID};
    774         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;
    785         font.setTypeface(clientTf);
    786         SkScalerContext::MakeRecAndEffects(
    787                 font, paint, SkSurfacePropsCopyOrDefault(nullptr), flags,
    788                 SkMatrix::I(), &rec, &effects);
    789         auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    790 
    791         auto fallbackCache = strikeCache.findOrCreateStrikeExclusive(*desc, effects, *clientTf);
    792         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;
    803         SkScalerContextEffects effects;
    804         SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
    805         font.setTypeface(serverTf);
    806         auto* cacheState = server.getOrCreateCache(
    807                 paint, font, SkSurfacePropsCopyOrDefault(nullptr),
    808                 SkMatrix::I(), flags, &effects);
    809         cacheState->addGlyph(lostGlyphID, false);
    810 
    811         std::vector<uint8_t> serverStrikeData;
    812         server.writeStrikeData(&serverStrikeData);
    813         REPORTER_ASSERT(reporter,
    814                         client.readStrikeData(
    815                                 serverStrikeData.data(),
    816                                 serverStrikeData.size()));
    817     }
    818 
    819     {
    820         SkAutoDescriptor ad;
    821         SkScalerContextRec rec;
    822         SkScalerContextEffects effects;
    823         SkScalerContextFlags flags = SkScalerContextFlags::kFakeGammaAndBoostContrast;
    824         font.setTypeface(clientTf);
    825         SkScalerContext::MakeRecAndEffects(
    826                 font, paint, SkSurfaceProps(0, kUnknown_SkPixelGeometry), flags,
    827                 SkMatrix::I(), &rec, &effects);
    828         auto desc = SkScalerContext::AutoDescriptorGivenRecAndEffects(rec, effects, &ad);
    829 
    830         auto fallbackCache = strikeCache.findStrikeExclusive(*desc);
    831         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 
    844     strikeCache.validateGlyphCacheDataSize();
    845 
    846     // Must unlock everything on termination, otherwise valgrind complains about memory leaks.
    847     discardableManager->unlockAndDeleteAll();
    848 }
    849