Add serialize + catalog api to SkTextBlob

Bug: skia:6836
Change-Id: I858cf936b015c14f12a41a4912e19bb15de8abaa
Reviewed-on: https://skia-review.googlesource.com/21730
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/tests/TextBlobTest.cpp b/tests/TextBlobTest.cpp
index 3834116..238d734 100644
--- a/tests/TextBlobTest.cpp
+++ b/tests/TextBlobTest.cpp
@@ -383,3 +383,82 @@
         REPORTER_ASSERT(reporter, 0 == strncmp(text2, it.text(), it.textSize()));
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkCanvas.h"
+#include "SkSurface.h"
+#include "SkTDArray.h"
+
+static void add_run(SkTextBlobBuilder* builder, const char text[], SkScalar x, SkScalar y,
+                    sk_sp<SkTypeface> tf) {
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setSubpixelText(true);
+    paint.setTextSize(16);
+    paint.setTypeface(tf);
+
+    int glyphCount = paint.textToGlyphs(text, strlen(text), nullptr);
+
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    SkTextBlobBuilder::RunBuffer buffer = builder->allocRun(paint, glyphCount, x, y);
+
+    paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+    (void)paint.textToGlyphs(text, strlen(text), buffer.glyphs);
+}
+
+static sk_sp<SkImage> render(const SkTextBlob* blob) {
+    auto surf = SkSurface::MakeRasterN32Premul(SkScalarRoundToInt(blob->bounds().width()),
+                                               SkScalarRoundToInt(blob->bounds().height()));
+    surf->getCanvas()->clear(SK_ColorWHITE);
+    surf->getCanvas()->drawTextBlob(blob, -blob->bounds().left(), -blob->bounds().top(), SkPaint());
+    return surf->makeImageSnapshot();
+}
+
+/*
+ *  Build a blob with more than one typeface.
+ *  Draw it into an offscreen,
+ *  then serialize and deserialize,
+ *  Then draw the new instance and assert it draws the same as the original.
+ */
+DEF_TEST(TextBlob_serialize, reporter) {
+    SkTextBlobBuilder builder;
+
+    sk_sp<SkTypeface> tf0;
+    sk_sp<SkTypeface> tf1 = SkTypeface::MakeFromName("Times", SkFontStyle());
+
+    add_run(&builder, "Hello", 10, 20, tf0);
+    add_run(&builder, "World", 10, 40, tf1);
+    sk_sp<SkTextBlob> blob0 = builder.make();
+    sk_sp<SkImage> img0 = render(blob0.get());
+
+    SkTDArray<SkTypeface*> array;
+    sk_sp<SkData> data = blob0->serialize([&array](SkTypeface* tf) {
+        if (array.find(tf) < 0) {
+            *array.append() = tf;
+        }
+    });
+    REPORTER_ASSERT(reporter, array.count() > 0);
+
+    sk_sp<SkTextBlob> blob1 = SkTextBlob::Deserialize(data->data(), data->size(),
+                                                      [&array, reporter](uint32_t uniqueID) {
+        for (int i = 0; i < array.count(); ++i) {
+            if (array[i]->uniqueID() == uniqueID) {
+                return sk_ref_sp(array[i]);
+            }
+        }
+        REPORTER_ASSERT(reporter, false);
+        return sk_sp<SkTypeface>(nullptr);
+    });
+    sk_sp<SkImage> img1 = render(blob1.get());
+
+    REPORTER_ASSERT(reporter, img0->width() == img1->width());
+    REPORTER_ASSERT(reporter, img0->height() == img1->height());
+
+    sk_sp<SkData> enc0(img0->encode());
+    sk_sp<SkData> enc1(img1->encode());
+    REPORTER_ASSERT(reporter, enc0->equals(enc1.get()));
+    if (false) {    // in case you want to actually see the images...
+        SkFILEWStream("textblob_serialize_img0.png").write(enc0->data(), enc0->size());
+        SkFILEWStream("textblob_serialize_img1.png").write(enc1->data(), enc1->size());
+    }
+}