Consolidate all the id handling and caching code.

BUG=skia:7515

Change-Id: Iab31e8cadfaa1ce09d85aab9cc84a3e614ea5e45
Reviewed-on: https://skia-review.googlesource.com/100420
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Herb Derby <herb@google.com>
diff --git a/src/core/SkRemoteGlyphCache.cpp b/src/core/SkRemoteGlyphCache.cpp
new file mode 100644
index 0000000..a2044ff
--- /dev/null
+++ b/src/core/SkRemoteGlyphCache.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRemoteGlyphCache.h"
+
+struct WireTypeface {
+    // std::thread::id thread_id;  // TODO:need to figure a good solution
+    SkFontID        typeface_id;
+    SkFontStyle     style;
+    bool            is_fixed;
+};
+
+void SkRemoteGlyphCacheRenderer::prepareSerializeProcs(SkSerialProcs* procs) {
+    auto encode = [](SkTypeface* tf, void* ctx) {
+        return reinterpret_cast<SkRemoteGlyphCacheRenderer*>(ctx)->encodeTypeface(tf);
+    };
+    procs->fTypefaceProc = encode;
+    procs->fTypefaceCtx = this;
+}
+
+SkScalerContext* SkRemoteGlyphCacheRenderer::generateScalerContext(
+    const SkScalerContextRecDescriptor& desc, SkFontID typefaceId)
+{
+    auto scaler = fScalerContextMap.find(desc);
+    if (scaler == nullptr) {
+        auto typefaceIter = fTypefaceMap.find(typefaceId);
+        if (typefaceIter == nullptr) {
+            // TODO: handle this with some future fallback strategy.
+            SK_ABORT("unknown type face");
+            // Should never happen
+            return nullptr;
+        }
+        auto tf = typefaceIter->get();
+        SkScalerContextEffects effects;
+        auto mapSc = tf->createScalerContext(effects, &desc.desc(), false);
+        scaler = fScalerContextMap.set(desc, std::move(mapSc));
+    }
+    return scaler->get();
+}
+
+sk_sp<SkData> SkRemoteGlyphCacheRenderer::encodeTypeface(SkTypeface* tf) {
+    WireTypeface wire = {
+        SkTypeface::UniqueID(tf),
+        tf->fontStyle(),
+        tf->isFixedPitch()
+    };
+    auto typeFace = fTypefaceMap.find(SkTypeface::UniqueID(tf));
+    if (typeFace == nullptr) {
+        fTypefaceMap.set(SkTypeface::UniqueID(tf), sk_ref_sp(tf));
+    }
+    // Can this be done with no copy?
+    return SkData::MakeWithCopy(&wire, sizeof(wire));
+}
+
+SkRemoteGlyphCacheGPU::SkRemoteGlyphCacheGPU(
+    std::unique_ptr<SkRemoteScalerContext> remoteScalerContext)
+    : fRemoteScalerContext{std::move(remoteScalerContext)} { }
+
+void SkRemoteGlyphCacheGPU::prepareDeserializeProcs(SkDeserialProcs* procs) {
+    auto decode = [](const void* buf, size_t len, void* ctx) {
+        return reinterpret_cast<SkRemoteGlyphCacheGPU*>(ctx)->decodeTypeface(buf, len);
+    };
+    procs->fTypefaceProc = decode;
+    procs->fTypefaceCtx = this;
+}
+
+sk_sp<SkTypeface> SkRemoteGlyphCacheGPU::decodeTypeface(const void* buf, size_t len) {
+    WireTypeface wire;
+    if (len < sizeof(wire)) {
+        SK_ABORT("Incomplete transfer");
+        return nullptr;
+    }
+    memcpy(&wire, buf, sizeof(wire));
+    auto typeFace = fMapIdToTypeface.find(wire.typeface_id);
+    if (typeFace == nullptr) {
+
+        auto newTypeface = sk_make_sp<SkTypefaceProxy>(
+            wire.typeface_id,
+            wire.style,
+            wire.is_fixed,
+            fRemoteScalerContext.get());
+
+        typeFace = fMapIdToTypeface.set(wire.typeface_id, newTypeface);
+    }
+    return *typeFace;
+}
+
+
diff --git a/src/core/SkRemoteGlyphCache.h b/src/core/SkRemoteGlyphCache.h
new file mode 100644
index 0000000..3634ad0
--- /dev/null
+++ b/src/core/SkRemoteGlyphCache.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRemoteGlyphCache_DEFINED
+#define SkRemoteGlyphCache_DEFINED
+
+#include <memory>
+#include "SkData.h"
+#include "SkDescriptor.h"
+#include "SkSerialProcs.h"
+#include "SkTHash.h"
+#include "SkTypeface.h"
+#include "SkTypeface_remote.h"
+
+class SkScalerContextRecDescriptor {
+public:
+    SkScalerContextRecDescriptor() {}
+    explicit SkScalerContextRecDescriptor(const SkScalerContextRec& rec) {
+        auto desc = reinterpret_cast<SkDescriptor*>(&fDescriptor);
+        desc->init();
+        desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+        SkASSERT(sizeof(fDescriptor) == desc->getLength());
+    }
+
+    SkScalerContextRecDescriptor& operator=(const SkScalerContextRecDescriptor& rhs) {
+        std::memcpy(&fDescriptor, &rhs.fDescriptor, rhs.desc().getLength());
+        return *this;
+    }
+
+    const SkDescriptor& desc() const {
+        return *reinterpret_cast<const SkDescriptor*>(&fDescriptor);
+    }
+
+    struct Hash {
+        uint32_t operator()(SkScalerContextRecDescriptor const& s) const {
+            return s.desc().getChecksum();
+        }
+    };
+
+    friend bool operator==(const SkScalerContextRecDescriptor& lhs,
+                           const SkScalerContextRecDescriptor& rhs ) {
+        return lhs.desc() == rhs.desc();
+    }
+
+private:
+    // The system only passes descriptors without effects. That is why it uses a fixed size
+    // descriptor. storageFor is needed because some of the constructors below are private.
+    template <typename T>
+    using storageFor = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
+    struct {
+        storageFor<SkDescriptor>        dummy1;
+        storageFor<SkDescriptor::Entry> dummy2;
+        storageFor<SkScalerContextRec>  dummy3;
+    } fDescriptor;
+};
+
+class SkRemoteGlyphCacheRenderer {
+public:
+    void prepareSerializeProcs(SkSerialProcs* procs);
+
+    SkScalerContext* generateScalerContext(
+        const SkScalerContextRecDescriptor& desc, SkFontID typefaceId);
+
+private:
+
+    sk_sp<SkData> encodeTypeface(SkTypeface* tf);
+
+    SkTHashMap<SkFontID, sk_sp<SkTypeface>> fTypefaceMap;
+
+    using DescriptorToContextMap =
+    SkTHashMap<
+    SkScalerContextRecDescriptor,
+    std::unique_ptr<SkScalerContext>,
+    SkScalerContextRecDescriptor::Hash>;
+
+    DescriptorToContextMap fScalerContextMap;
+};
+
+class SkRemoteGlyphCacheGPU {
+public:
+    explicit SkRemoteGlyphCacheGPU(std::unique_ptr<SkRemoteScalerContext> remoteScalerContext);
+
+    void prepareDeserializeProcs(SkDeserialProcs* procs);
+
+private:
+    sk_sp<SkTypeface> decodeTypeface(const void* buf, size_t len);
+
+    std::unique_ptr<SkRemoteScalerContext> fRemoteScalerContext;
+    // TODO: Figure out how to manage the entries for the following maps.
+    SkTHashMap<SkFontID, sk_sp<SkTypefaceProxy>> fMapIdToTypeface;
+
+};
+
+
+#endif  // SkRemoteGlyphCache_DEFINED
diff --git a/src/core/SkTypeface_remote.h b/src/core/SkTypeface_remote.h
index 3302154..8f47434 100644
--- a/src/core/SkTypeface_remote.h
+++ b/src/core/SkTypeface_remote.h
@@ -71,13 +71,11 @@
 public:
     SkTypefaceProxy(
             SkFontID fontId,
-            std::thread::id threadId,
             const SkFontStyle& style,
             bool isFixed,
             SkRemoteScalerContext* rsc)
             : INHERITED{style, false}
             , fFontId{fontId}
-            , fThreadId{threadId}
             , fRsc{rsc} { }
     SkFontID fontID() const {return fFontId;}
 protected:
@@ -150,7 +148,7 @@
 
 private:
     const SkFontID fFontId;
-    const std::thread::id fThreadId;
+    // const std::thread::id fThreadId;  // TODO: figure out a good solutions for this.
     SkRemoteScalerContext* const fRsc;
 
     typedef SkTypeface INHERITED;