fonts: Reland push font remoting.

This relands the following changes:
1) https://skia-review.googlesource.com/c/skia/+/120283
2) https://skia-review.googlesource.com/c/skia/+/125029
3) https://skia-review.googlesource.com/c/skia/+/125140

The original changes had to be reverted due to a memory leak in
SkBaseDevice from SkTextBlobCacheDiffCanvas. This has been addressed by
https://skia-review.googlesource.com/c/skia/+/125160

TBR=herb@google.com

Bug: skia:7515, 831354
Change-Id: I73f4fcb1c397f31bf01553ff48c71ed2d6dd0770
Reviewed-on: https://skia-review.googlesource.com/125326
Commit-Queue: Khusal Sagar <khushalsagar@chromium.org>
Reviewed-by: Khusal Sagar <khushalsagar@chromium.org>
diff --git a/tools/remote_demo.cpp b/tools/remote_demo.cpp
index 8fc96ca..105a9b3 100644
--- a/tools/remote_demo.cpp
+++ b/tools/remote_demo.cpp
@@ -16,8 +16,9 @@
 #include <thread>
 #include <unistd.h>
 
-#include "SkRemoteGlyphCache.h"
 #include "SkGraphics.h"
+#include "SkRemoteGlyphCache.h"
+#include "SkScalerContext.h"
 #include "SkSurface.h"
 
 static std::string gSkpName;
@@ -25,6 +26,46 @@
 static bool gPurgeFontCaches = true;
 static bool gUseProcess = true;
 
+class ServerDiscardableManager : public SkStrikeServer::DiscardableHandleManager {
+public:
+    ServerDiscardableManager() = default;
+    ~ServerDiscardableManager() override = default;
+
+    SkDiscardableHandleId createHandle() override { return ++nextHandleId; }
+    bool lockHandle(SkDiscardableHandleId handleId) override {
+        return handleId > lastPurgedHandleId;
+    }
+    void purgeAll() { lastPurgedHandleId = nextHandleId; }
+
+private:
+    SkDiscardableHandleId nextHandleId = 0u;
+    SkDiscardableHandleId lastPurgedHandleId = 0u;
+};
+
+class ClientDiscardableManager : public SkStrikeClient::DiscardableHandleManager {
+public:
+    class ScopedPurgeCache {
+    public:
+        ScopedPurgeCache(ClientDiscardableManager* manager) : fManager(manager) {
+            if (fManager) fManager->allowPurging = true;
+        }
+        ~ScopedPurgeCache() {
+            if (fManager) fManager->allowPurging = false;
+        }
+
+    private:
+        ClientDiscardableManager* fManager;
+    };
+
+    ClientDiscardableManager() = default;
+    ~ClientDiscardableManager() override = default;
+
+    bool deleteHandle(SkDiscardableHandleId) override { return allowPurging; }
+
+private:
+    bool allowPurging = false;
+};
+
 static bool write_SkData(int fd, const SkData& data) {
     size_t size = data.size();
     ssize_t bytesWritten = ::write(fd, &size, sizeof(size));
@@ -43,7 +84,6 @@
 }
 
 static sk_sp<SkData> read_SkData(int fd) {
-
     size_t size;
     ssize_t readSize = ::read(fd, &size, sizeof(size));
     if (readSize <= 0) {
@@ -92,44 +132,56 @@
     std::chrono::duration<double>                       fElapsedSeconds{0.0};
 };
 
-static void build_prime_cache_spec(const SkIRect &bounds,
-                                   const SkSurfaceProps &props,
-                                   const SkPicture &pic,
-                                   SkStrikeCacheDifferenceSpec *strikeDifference) {
+static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer, int writeFd) {
     SkMatrix deviceMatrix = SkMatrix::I();
-
-    SkTextBlobCacheDiffCanvas filter(
-            bounds.width(), bounds.height(), deviceMatrix, props,
-            SkScalerContextFlags::kFakeGammaAndBoostContrast,
-            strikeDifference);
-
+    const SkIRect bounds = pic.cullRect().round();
+    const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
+    SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), deviceMatrix, props,
+                                     strikeServer);
     pic.playback(&filter);
+
+    std::vector<uint8_t> fontData;
+    strikeServer->writeStrikeData(&fontData);
+    auto data = SkData::MakeWithoutCopy(fontData.data(), fontData.size());
+    return write_SkData(writeFd, *data);
 }
 
-static void final_draw(std::string outFilename,
-                       SkDeserialProcs* procs,
-                       SkData* picData,
-                       SkStrikeClient* client) {
+static void final_draw(std::string outFilename, SkData* picData, SkStrikeClient* client,
+                       ClientDiscardableManager* discardableManager, int readFd, int writeFd) {
+    SkDeserialProcs procs;
+    auto decode = [](const void* data, size_t length, void* ctx) -> sk_sp<SkTypeface> {
+        return reinterpret_cast<SkStrikeClient*>(ctx)->deserializeTypeface(data, length);
+    };
+    procs.fTypefaceProc = decode;
+    procs.fTypefaceCtx = client;
 
-    auto pic = SkPicture::MakeFromData(picData, procs);
+    auto pic = SkPicture::MakeFromData(picData, &procs);
 
     auto cullRect = pic->cullRect();
     auto r = cullRect.round();
 
     auto s = SkSurface::MakeRasterN32Premul(r.width(), r.height());
     auto c = s->getCanvas();
-    auto picUnderTest = SkPicture::MakeFromData(picData, procs);
+    auto picUnderTest = SkPicture::MakeFromData(picData, &procs);
 
     Timer drawTime;
+    auto randomData = SkData::MakeUninitialized(1u);
     for (int i = 0; i < 100; i++) {
         if (gPurgeFontCaches) {
+            ClientDiscardableManager::ScopedPurgeCache purge(discardableManager);
             SkGraphics::PurgeFontCache();
+            SkASSERT(SkGraphics::GetFontCacheUsed() == 0u);
         }
+
         drawTime.start();
         if (client != nullptr) {
-            SkStrikeCacheDifferenceSpec strikeDifference;
-            build_prime_cache_spec(r, s->props(), *picUnderTest, &strikeDifference);
-            client->primeStrikeCache(strikeDifference);
+            // Kick the renderer to send us the fonts.
+            write_SkData(writeFd, *randomData);
+            auto fontData = read_SkData(readFd);
+            if (fontData && !fontData->isEmpty()) {
+                if (!client->readStrikeData(fontData->data(), fontData->size()))
+                    SK_ABORT("Bad serialization");
+            }
         }
         c->drawPicture(picUnderTest);
         drawTime.stop();
@@ -150,22 +202,16 @@
 static void gpu(int readFd, int writeFd) {
 
     if (gUseGpu) {
-        auto clientRPC = [readFd, writeFd](const SkData& inBuffer) {
-            write_SkData(writeFd, inBuffer);
-            return read_SkData(readFd);
-        };
-
         auto picData = read_SkData(readFd);
         if (picData == nullptr) {
             return;
         }
 
-        SkStrikeClient client{clientRPC};
+        sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
+        SkStrikeClient strikeClient(discardableManager);
 
-        SkDeserialProcs procs;
-        client.prepareDeserializeProcs(&procs);
-
-        final_draw("test.png", &procs, picData.get(), &client);
+        final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
+                   writeFd);
     }
 
     ::close(writeFd);
@@ -177,7 +223,8 @@
 static int renderer(
     const std::string& skpName, int readFd, int writeFd)
 {
-    SkStrikeServer server{};
+    ServerDiscardableManager discardableManager;
+    SkStrikeServer server(&discardableManager);
     auto closeAll = [readFd, writeFd]() {
         ::close(writeFd);
         ::close(readFd);
@@ -186,11 +233,16 @@
     auto skpData = SkData::MakeFromFileName(skpName.c_str());
     std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
 
-    SkSerialProcs procs;
     sk_sp<SkData> stream;
     if (gUseGpu) {
         auto pic = SkPicture::MakeFromData(skpData.get());
-        server.prepareSerializeProcs(&procs);
+        SkSerialProcs procs;
+        auto encode = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
+            return reinterpret_cast<SkStrikeServer*>(ctx)->serializeTypeface(tf);
+        };
+        procs.fTypefaceProc = encode;
+        procs.fTypefaceCtx = &server;
+
         stream = pic->serialize(&procs);
 
         if (!write_SkData(writeFd, *stream)) {
@@ -198,22 +250,18 @@
             return 1;
         }
 
-        std::vector<uint8_t> tmpBuffer;
         while (true) {
             auto inBuffer = read_SkData(readFd);
             if (inBuffer == nullptr) {
                 closeAll();
                 return 0;
             }
-
-            tmpBuffer.clear();
-            server.serve(*inBuffer, &tmpBuffer);
-            auto outBuffer = SkData::MakeWithoutCopy(tmpBuffer.data(), tmpBuffer.size());
-            write_SkData(writeFd, *outBuffer);
+            if (gPurgeFontCaches) discardableManager.purgeAll();
+            push_font_data(*pic.get(), &server, writeFd);
         }
     } else {
         stream = skpData;
-        final_draw("test-correct.png", nullptr, stream.get(), nullptr);
+        final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
         closeAll();
         return 0;
     }