Import Cobalt 21.master.0.253153
diff --git a/src/third_party/skia/tools/AndroidSkDebugToStdOut.cpp b/src/third_party/skia/tools/AndroidSkDebugToStdOut.cpp
index 9dc9911..ad8c949 100644
--- a/src/third_party/skia/tools/AndroidSkDebugToStdOut.cpp
+++ b/src/third_party/skia/tools/AndroidSkDebugToStdOut.cpp
@@ -7,7 +7,7 @@
 
 // Need to include SkTypes before checking SK_BUILD_FOR_ANDROID, so it will be
 // set in the Android framework build.
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
 #ifdef SK_BUILD_FOR_ANDROID
 extern bool gSkDebugToStdOut;
 
diff --git a/src/third_party/skia/tools/AutoreleasePool.h b/src/third_party/skia/tools/AutoreleasePool.h
new file mode 100644
index 0000000..0582404
--- /dev/null
+++ b/src/third_party/skia/tools/AutoreleasePool.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAutoreleasePool_DEFINED
+#define SkAutoreleasePool_DEFINED
+
+/*
+ * Helper class for managing an autorelease pool for Metal. On other platforms this will
+ * do nothing so there's no need to #ifdef it out.
+ */
+#ifdef SK_METAL
+class AutoreleasePool {
+public:
+    AutoreleasePool();
+    ~AutoreleasePool();
+
+    void drain();
+
+private:
+    void* fPool;
+};
+#else
+class AutoreleasePool {
+public:
+    AutoreleasePool() {}
+    ~AutoreleasePool() = default;
+
+    void drain() {}
+};
+#endif
+
+#endif
diff --git a/src/third_party/skia/tools/AutoreleasePool.mm b/src/third_party/skia/tools/AutoreleasePool.mm
new file mode 100644
index 0000000..6116115
--- /dev/null
+++ b/src/third_party/skia/tools/AutoreleasePool.mm
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkTypes.h"
+#include "tools/AutoreleasePool.h"
+
+#import <Foundation/NSAutoreleasePool.h>
+
+AutoreleasePool::AutoreleasePool() {
+    fPool = (void*)[[NSAutoreleasePool alloc] init];
+}
+
+AutoreleasePool::~AutoreleasePool() {
+    [(NSAutoreleasePool*)fPool release];
+    fPool = nullptr;
+}
+
+void AutoreleasePool::drain() {
+    [(NSAutoreleasePool*)fPool drain];
+    fPool = (void*)[[NSAutoreleasePool alloc] init];
+}
diff --git a/src/third_party/skia/tools/CrashHandler.cpp b/src/third_party/skia/tools/CrashHandler.cpp
index f141e55..5a2186f 100644
--- a/src/third_party/skia/tools/CrashHandler.cpp
+++ b/src/third_party/skia/tools/CrashHandler.cpp
@@ -5,24 +5,19 @@
  * found in the LICENSE file.
  */
 
-#include "CrashHandler.h"
+#include "tools/CrashHandler.h"
 
-#include "../private/SkLeanWindows.h"
+#include "src/core/SkLeanWindows.h"
 
 #include <stdlib.h>
 
-// Disable SetupCrashHandler() unless SK_CRASH_HANDLER is defined.
-#ifndef SK_CRASH_HANDLER
-    void SetupCrashHandler() { }
-
-#elif defined(GOOGLE3)
+#if defined(SK_BUILD_FOR_GOOGLE3)
     #include "base/process_state.h"
     void SetupCrashHandler() { InstallSignalHandlers(); }
 
 #else
 
     #if defined(SK_BUILD_FOR_MAC)
-
         // We only use local unwinding, so we can define this to select a faster implementation.
         #define UNW_LOCAL_ONLY
         #include <libunwind.h>
@@ -55,18 +50,34 @@
         }
 
     #elif defined(SK_BUILD_FOR_UNIX)
-
         // We'd use libunwind here too, but it's a pain to get installed for
         // both 32 and 64 bit on bots.  Doesn't matter much: catchsegv is best anyway.
+        #include <cxxabi.h>
+        #include <dlfcn.h>
         #include <execinfo.h>
+        #include <string.h>
 
         static void handler(int sig) {
-            static const int kMax = 64;
-            void* stack[kMax];
-            const int count = backtrace(stack, kMax);
+            void* stack[64];
+            const int count = backtrace(stack, SK_ARRAY_COUNT(stack));
+            char** symbols = backtrace_symbols(stack, count);
 
             SkDebugf("\nSignal %d [%s]:\n", sig, strsignal(sig));
-            backtrace_symbols_fd(stack, count, 2/*stderr*/);
+            for (int i = 0; i < count; i++) {
+                Dl_info info;
+                if (dladdr(stack[i], &info) && info.dli_sname) {
+                    char demangled[256];
+                    size_t len = SK_ARRAY_COUNT(demangled);
+                    int ok;
+
+                    abi::__cxa_demangle(info.dli_sname, demangled, &len, &ok);
+                    if (ok == 0) {
+                        SkDebugf("    %s\n", demangled);
+                        continue;
+                    }
+                }
+                SkDebugf("    %s\n", symbols[i]);
+            }
 
             // Exit NOW.  Don't notify other threads, don't call anything registered with atexit().
             _Exit(sig);
@@ -84,6 +95,7 @@
                 SIGFPE,
                 SIGILL,
                 SIGSEGV,
+                SIGTRAP,
             };
 
             for (size_t i = 0; i < sizeof(kSignals) / sizeof(kSignals[0]); i++) {
@@ -95,9 +107,10 @@
             }
         }
 
-    #elif defined(SK_CRASH_HANDLER) && defined(SK_BUILD_FOR_WIN)
+    #elif defined(SK_BUILD_FOR_WIN)
 
         #include <DbgHelp.h>
+        #include "include/private/SkMalloc.h"
 
         static const struct {
             const char* name;
@@ -143,6 +156,11 @@
             frame.AddrStack.Offset = c->Rsp;
             frame.AddrFrame.Offset = c->Rbp;
             const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
+        #elif defined(_M_ARM64)
+            frame.AddrPC.Offset    = c->Pc;
+            frame.AddrStack.Offset = c->Sp;
+            frame.AddrFrame.Offset = c->Fp;
+            const DWORD machineType = IMAGE_FILE_MACHINE_ARM64;
         #endif
 
             while (StackWalk64(machineType,
@@ -184,9 +202,9 @@
             SetUnhandledExceptionFilter(handler);
         }
 
-    #else  // We asked for SK_CRASH_HANDLER, but it's not Mac, Linux, or Windows.  Sorry!
+    #else
 
         void SetupCrashHandler() { }
 
     #endif
-#endif // SK_CRASH_HANDLER
+#endif // SK_BUILD_FOR_GOOGLE3?
diff --git a/src/third_party/skia/tools/DDLPromiseImageHelper.cpp b/src/third_party/skia/tools/DDLPromiseImageHelper.cpp
new file mode 100644
index 0000000..5cfbb6e
--- /dev/null
+++ b/src/third_party/skia/tools/DDLPromiseImageHelper.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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 "tools/DDLPromiseImageHelper.h"
+
+#include "include/core/SkDeferredDisplayListRecorder.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkSerialProcs.h"
+#include "include/core/SkYUVAIndex.h"
+#include "include/core/SkYUVASizeInfo.h"
+#include "include/gpu/GrContext.h"
+#include "src/core/SkCachedData.h"
+#include "src/image/SkImage_Base.h"
+#include "src/image/SkImage_GpuYUVA.h"
+
+DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
+    SkASSERT(fDoneCnt == fNumImages);
+    SkASSERT(!fUnreleasedFulfills);
+    SkASSERT(fTotalReleases == fTotalFulfills);
+    SkASSERT(!fTotalFulfills || fDoneCnt);
+
+    if (fPromiseImageTexture) {
+        fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
+    }
+}
+
+void DDLPromiseImageHelper::PromiseImageCallbackContext::setBackendTexture(
+        const GrBackendTexture& backendTexture) {
+    SkASSERT(!fPromiseImageTexture);
+    fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
+    SkSerialProcs procs;
+
+    procs.fImageCtx = this;
+    procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
+        auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
+
+        int id = helper->findOrDefineImage(image);
+        if (id >= 0) {
+            SkASSERT(helper->isValidID(id));
+            return SkData::MakeWithCopy(&id, sizeof(id));
+        }
+
+        return nullptr;
+    };
+
+    return inputPicture->serialize(&procs);
+}
+
+static GrBackendTexture create_yuva_texture(GrContext* context, const SkPixmap& pm,
+                                            const SkYUVAIndex yuvaIndices[4], int texIndex) {
+    SkASSERT(texIndex >= 0 && texIndex <= 3);
+
+#ifdef SK_DEBUG
+    int channelCount = 0;
+    for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
+        if (yuvaIndices[i].fIndex == texIndex) {
+            ++channelCount;
+        }
+    }
+    if (2 == channelCount) {
+        SkASSERT(kR8G8_unorm_SkColorType == pm.colorType());
+    }
+#endif
+
+    return context->createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo);
+}
+
+void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
+    for (int i = 0; i < fImageInfo.count(); ++i) {
+        const PromiseImageInfo& info = fImageInfo[i];
+
+        // DDL TODO: how can we tell if we need mipmapping!
+        if (info.isYUV()) {
+            int numPixmaps;
+            SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
+            for (int j = 0; j < numPixmaps; ++j) {
+                const SkPixmap& yuvPixmap = info.yuvPixmap(j);
+
+                sk_sp<PromiseImageCallbackContext> callbackContext(
+                                                        new PromiseImageCallbackContext(context));
+
+                callbackContext->setBackendTexture(create_yuva_texture(context, yuvPixmap,
+                                                                       info.yuvaIndices(), j));
+                SkASSERT(callbackContext->promiseImageTexture());
+
+                fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
+            }
+        } else {
+            sk_sp<PromiseImageCallbackContext> callbackContext(
+                                                    new PromiseImageCallbackContext(context));
+
+            const SkBitmap& bm = info.normalBitmap();
+
+            GrBackendTexture backendTex = context->createBackendTexture(
+                                                        &bm.pixmap(), 1, GrRenderable::kNo,
+                                                        GrProtected::kNo);
+
+            callbackContext->setBackendTexture(backendTex);
+
+            // The GMs sometimes request too large an image
+            //SkAssertResult(callbackContext->backendTexture().isValid());
+
+            fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
+        }
+    }
+}
+
+sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
+                                                   SkDeferredDisplayListRecorder* recorder,
+                                                   SkData* compressedPictureData,
+                                                   SkTArray<sk_sp<SkImage>>* promiseImages) const {
+    PerRecorderContext perRecorderContext { recorder, this, promiseImages };
+
+    SkDeserialProcs procs;
+    procs.fImageCtx = (void*) &perRecorderContext;
+    procs.fImageProc = PromiseImageCreator;
+
+    return SkPicture::MakeFromData(compressedPictureData, &procs);
+}
+
+// This generates promise images to replace the indices in the compressed picture. This
+// reconstitution is performed separately in each thread so we end up with multiple
+// promise images referring to the same GrBackendTexture.
+sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
+                                                          size_t length, void* ctxIn) {
+    PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
+    const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
+    SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
+
+    SkASSERT(length == sizeof(int));
+
+    const int* indexPtr = static_cast<const int*>(rawData);
+    SkASSERT(helper->isValidID(*indexPtr));
+
+    const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
+
+    if (!curImage.promiseTexture(0)) {
+        SkASSERT(!curImage.isYUV());
+        // We weren't able to make a backend texture for this SkImage. In this case we create
+        // a separate bitmap-backed image for each thread.
+        SkASSERT(curImage.normalBitmap().isImmutable());
+        return SkImage::MakeFromBitmap(curImage.normalBitmap());
+    }
+    SkASSERT(curImage.index() == *indexPtr);
+
+    sk_sp<SkImage> image;
+    if (curImage.isYUV()) {
+        GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
+        void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
+        SkISize sizes[SkYUVASizeInfo::kMaxCount];
+        // TODO: store this value somewhere?
+        int textureCount;
+        SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
+        for (int i = 0; i < textureCount; ++i) {
+            const GrBackendTexture& backendTex = curImage.promiseTexture(i)->backendTexture();
+            backendFormats[i] = backendTex.getBackendFormat();
+            SkASSERT(backendFormats[i].isValid());
+            contexts[i] = curImage.refCallbackContext(i).release();
+            sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
+        }
+        for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
+            sizes[i] = SkISize::MakeEmpty();
+        }
+
+        image = recorder->makeYUVAPromiseTexture(
+                curImage.yuvColorSpace(),
+                backendFormats,
+                sizes,
+                curImage.yuvaIndices(),
+                curImage.overallWidth(),
+                curImage.overallHeight(),
+                GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+                curImage.refOverallColorSpace(),
+                DDLPromiseImageHelper::PromiseImageFulfillProc,
+                DDLPromiseImageHelper::PromiseImageReleaseProc,
+                DDLPromiseImageHelper::PromiseImageDoneProc,
+                contexts,
+                SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
+        for (int i = 0; i < textureCount; ++i) {
+            curImage.callbackContext(i)->wasAddedToImage();
+        }
+
+#ifdef SK_DEBUG
+        {
+            // By the peekProxy contract this image should not have a single backing proxy so
+            // should return null. The call should also not trigger the conversion to RGBA.
+            SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
+            SkASSERT(!yuva->peekProxy());
+            SkASSERT(!yuva->peekProxy());  // the first call didn't force a conversion to RGBA
+        }
+#endif
+    } else {
+        const GrBackendTexture& backendTex = curImage.promiseTexture(0)->backendTexture();
+        GrBackendFormat backendFormat = backendTex.getBackendFormat();
+        SkASSERT(backendFormat.isValid());
+
+        // Each DDL recorder gets its own ref on the promise callback context for the
+        // promise images it creates.
+        // DDL TODO: sort out mipmapping
+        image = recorder->makePromiseTexture(
+                backendFormat,
+                curImage.overallWidth(),
+                curImage.overallHeight(),
+                GrMipMapped::kNo,
+                GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+                curImage.overallColorType(),
+                curImage.overallAlphaType(),
+                curImage.refOverallColorSpace(),
+                DDLPromiseImageHelper::PromiseImageFulfillProc,
+                DDLPromiseImageHelper::PromiseImageReleaseProc,
+                DDLPromiseImageHelper::PromiseImageDoneProc,
+                (void*)curImage.refCallbackContext(0).release(),
+                SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
+        curImage.callbackContext(0)->wasAddedToImage();
+    }
+    perRecorderContext->fPromiseImages->push_back(image);
+    SkASSERT(image);
+    return image;
+}
+
+int DDLPromiseImageHelper::findImage(SkImage* image) const {
+    for (int i = 0; i < fImageInfo.count(); ++i) {
+        if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
+            SkASSERT(fImageInfo[i].index() == i);
+            SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
+            return i;
+        }
+    }
+    return -1;
+}
+
+int DDLPromiseImageHelper::addImage(SkImage* image) {
+    SkImage_Base* ib = as_IB(image);
+
+    SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
+                                              image->colorType() == kBGRA_8888_SkColorType
+                                                        ? kRGBA_8888_SkColorType
+                                                        : image->colorType(),
+                                              image->alphaType(),
+                                              image->refColorSpace());
+
+    PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
+                                                             image->uniqueID(),
+                                                             overallII);
+
+    SkYUVASizeInfo yuvaSizeInfo;
+    SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
+    SkYUVColorSpace yuvColorSpace;
+    const void* planes[SkYUVASizeInfo::kMaxCount];
+    sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
+    if (yuvData) {
+        newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
+
+        // determine colortypes from index data
+        // for testing we only ever use A8, RG_88
+        SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
+            kUnknown_SkColorType, kUnknown_SkColorType,
+            kUnknown_SkColorType, kUnknown_SkColorType
+        };
+        for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
+            int texIdx = yuvaIndices[yuvIndex].fIndex;
+            if (texIdx < 0) {
+                SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
+                continue;
+            }
+            if (kUnknown_SkColorType == colorTypes[texIdx]) {
+                colorTypes[texIdx] = kAlpha_8_SkColorType;
+            } else {
+                colorTypes[texIdx] = kR8G8_unorm_SkColorType;
+            }
+        }
+
+        for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
+            if (yuvaSizeInfo.fSizes[i].isEmpty()) {
+                SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
+                continue;
+            }
+
+            SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
+                                                    yuvaSizeInfo.fSizes[i].fHeight,
+                                                    colorTypes[i],
+                                                    kUnpremul_SkAlphaType);
+            newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
+        }
+    } else {
+        sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
+
+        SkBitmap tmp;
+        tmp.allocPixels(overallII);
+
+        if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
+            return -1;
+        }
+
+        tmp.setImmutable();
+        newImageInfo.setNormalBitmap(tmp);
+    }
+    // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
+
+    return fImageInfo.count()-1;
+}
+
+int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
+    int preExistingID = this->findImage(image);
+    if (preExistingID >= 0) {
+        SkASSERT(this->isValidID(preExistingID));
+        return preExistingID;
+    }
+
+    int newID = this->addImage(image);
+    SkASSERT(this->isValidID(newID));
+    return newID;
+}
diff --git a/src/third_party/skia/tools/DDLPromiseImageHelper.h b/src/third_party/skia/tools/DDLPromiseImageHelper.h
new file mode 100644
index 0000000..99d883e
--- /dev/null
+++ b/src/third_party/skia/tools/DDLPromiseImageHelper.h
@@ -0,0 +1,253 @@
+/*
+ * 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 PromiseImageHelper_DEFINED
+#define PromiseImageHelper_DEFINED
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkDeferredDisplayListRecorder.h"
+#include "include/core/SkPromiseImageTexture.h"
+#include "include/core/SkYUVAIndex.h"
+#include "include/core/SkYUVASizeInfo.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/private/SkTArray.h"
+#include "src/core/SkCachedData.h"
+#include "src/core/SkTLazy.h"
+
+class GrContext;
+class SkImage;
+class SkPicture;
+struct SkYUVAIndex;
+
+// This class consolidates tracking & extraction of the original image data from an skp,
+// the upload of said data to the GPU and the fulfillment of promise images.
+//
+// The way this works is:
+//    the original skp is converted to SkData and all its image info is extracted into this
+//       class and only indices into this class are left in the SkData (via deflateSKP)
+//
+//    Prior to replaying in threads, all the images stored in this class are uploaded to the
+//       gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
+//
+//    Each thread reinflates the SkData into an SkPicture replacing all the indices w/
+//       promise images (all using the same GrBackendTexture and getting a ref to the
+//       appropriate PromiseImageCallbackContext) (via reinflateSKP).
+//
+//    This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
+//
+//    Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
+//       are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
+//       from VRAM
+//
+// Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
+// all the replaying is complete. This will pin the GrBackendTextures in VRAM.
+class DDLPromiseImageHelper {
+public:
+    DDLPromiseImageHelper() = default;
+    ~DDLPromiseImageHelper() = default;
+
+    // Convert the SkPicture into SkData replacing all the SkImages with an index.
+    sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
+
+    void uploadAllToGPU(GrContext* context);
+
+    // reinflate a deflated SKP, replacing all the indices with promise images.
+    sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
+                                  SkData* compressedPicture,
+                                  SkTArray<sk_sp<SkImage>>* promiseImages) const;
+
+    // Remove this class' refs on the PromiseImageCallbackContexts
+    void reset() { fImageInfo.reset(); }
+
+private:
+    // This class acts as a proxy for a GrBackendTexture that is part of an image.
+    // Whenever a promise image is created for the image, the promise image receives a ref to
+    // potentially several of these objects. Once all the promise images receive their done
+    // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
+    // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
+    // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
+    // it drops all of its refs (via "reset").
+    class PromiseImageCallbackContext : public SkRefCnt {
+    public:
+        PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
+
+        ~PromiseImageCallbackContext();
+
+        void setBackendTexture(const GrBackendTexture& backendTexture);
+
+        sk_sp<SkPromiseImageTexture> fulfill() {
+            SkASSERT(fPromiseImageTexture);
+            SkASSERT(fUnreleasedFulfills >= 0);
+            ++fUnreleasedFulfills;
+            ++fTotalFulfills;
+            return fPromiseImageTexture;
+        }
+
+        void release() {
+            SkASSERT(fUnreleasedFulfills > 0);
+            --fUnreleasedFulfills;
+            ++fTotalReleases;
+        }
+
+        void done() {
+            ++fDoneCnt;
+            SkASSERT(fDoneCnt <= fNumImages);
+        }
+
+        void wasAddedToImage() { fNumImages++; }
+
+        const SkPromiseImageTexture* promiseImageTexture() const {
+          return fPromiseImageTexture.get();
+        }
+
+    private:
+        GrContext* fContext;
+        sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
+        int fNumImages = 0;
+        int fTotalFulfills = 0;
+        int fTotalReleases = 0;
+        int fUnreleasedFulfills = 0;
+        int fDoneCnt = 0;
+
+        typedef SkRefCnt INHERITED;
+    };
+
+    // This is the information extracted into this class from the parsing of the skp file.
+    // Once it has all been uploaded to the GPU and distributed to the promise images, it
+    // is all dropped via "reset".
+    class PromiseImageInfo {
+    public:
+        PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
+                : fIndex(index)
+                , fOriginalUniqueID(originalUniqueID)
+                , fImageInfo(ii) {
+        }
+        ~PromiseImageInfo() {}
+
+        int index() const { return fIndex; }
+        uint32_t originalUniqueID() const { return fOriginalUniqueID; }
+        bool isYUV() const { return SkToBool(fYUVData.get()); }
+
+        int overallWidth() const { return fImageInfo.width(); }
+        int overallHeight() const { return fImageInfo.height(); }
+        SkColorType overallColorType() const { return fImageInfo.colorType(); }
+        SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
+        sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
+
+        SkYUVColorSpace yuvColorSpace() const {
+            SkASSERT(this->isYUV());
+            return fYUVColorSpace;
+        }
+        const SkYUVAIndex* yuvaIndices() const {
+            SkASSERT(this->isYUV());
+            return fYUVAIndices;
+        }
+        const SkPixmap& yuvPixmap(int index) const {
+            SkASSERT(this->isYUV());
+            SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
+            return fYUVPlanes[index];
+        }
+        const SkBitmap& normalBitmap() const {
+            SkASSERT(!this->isYUV());
+            return fBitmap;
+        }
+
+        void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
+            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
+            fCallbackContexts[index] = callbackContext;
+        }
+        PromiseImageCallbackContext* callbackContext(int index) const {
+            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
+            return fCallbackContexts[index].get();
+        }
+        sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
+            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
+            return fCallbackContexts[index];
+        }
+
+        const SkPromiseImageTexture* promiseTexture(int index) const {
+            SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
+            return fCallbackContexts[index]->promiseImageTexture();
+        }
+
+        void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
+
+        void setYUVData(sk_sp<SkCachedData> yuvData,
+                        SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+                        SkYUVColorSpace cs) {
+            fYUVData = yuvData;
+            memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
+            fYUVColorSpace = cs;
+        }
+        void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
+            SkASSERT(this->isYUV());
+            SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
+            fYUVPlanes[index].reset(ii, plane, widthBytes);
+        }
+
+    private:
+        const int                          fIndex;                // index in the 'fImageInfo' array
+        const uint32_t                     fOriginalUniqueID;     // original ID for deduping
+
+        const SkImageInfo                  fImageInfo;            // info for the overarching image
+
+        // CPU-side cache of a normal SkImage's contents
+        SkBitmap                           fBitmap;
+
+        // CPU-side cache of a YUV SkImage's contents
+        sk_sp<SkCachedData>                fYUVData;       // when !null, this is a YUV image
+        SkYUVColorSpace                    fYUVColorSpace = kJPEG_SkYUVColorSpace;
+        SkYUVAIndex                        fYUVAIndices[SkYUVAIndex::kIndexCount];
+        SkPixmap                           fYUVPlanes[SkYUVASizeInfo::kMaxCount];
+
+        // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
+        sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
+    };
+
+    // This stack-based context allows each thread to re-inflate the image indices into
+    // promise images while still using the same GrBackendTexture.
+    struct PerRecorderContext {
+        SkDeferredDisplayListRecorder* fRecorder;
+        const DDLPromiseImageHelper*   fHelper;
+        SkTArray<sk_sp<SkImage>>*      fPromiseImages;
+    };
+
+    static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
+        auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
+        return callbackContext->fulfill();
+    }
+
+    static void PromiseImageReleaseProc(void* textureContext) {
+        auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
+        callbackContext->release();
+    }
+
+    static void PromiseImageDoneProc(void* textureContext) {
+        auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
+        callbackContext->done();
+        callbackContext->unref();
+    }
+
+    static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
+
+    bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
+    const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
+    void uploadImage(GrContext*, PromiseImageInfo*);
+
+    // returns -1 if not found
+    int findImage(SkImage* image) const;
+
+    // returns -1 on failure
+    int addImage(SkImage* image);
+
+    // returns -1 on failure
+    int findOrDefineImage(SkImage* image);
+
+    SkTArray<PromiseImageInfo> fImageInfo;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/DDLTileHelper.cpp b/src/third_party/skia/tools/DDLTileHelper.cpp
new file mode 100644
index 0000000..eb50f4e
--- /dev/null
+++ b/src/third_party/skia/tools/DDLTileHelper.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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 "tools/DDLTileHelper.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkDeferredDisplayListRecorder.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkSurfaceCharacterization.h"
+#include "src/core/SkDeferredDisplayListPriv.h"
+#include "src/core/SkTaskGroup.h"
+#include "src/image/SkImage_Gpu.h"
+#include "tools/DDLPromiseImageHelper.h"
+
+DDLTileHelper::TileData::TileData(sk_sp<SkSurface> s, const SkIRect& clip)
+        : fSurface(std::move(s))
+        , fClip(clip) {
+    SkAssertResult(fSurface->characterize(&fCharacterization));
+}
+
+void DDLTileHelper::TileData::createTileSpecificSKP(SkData* compressedPictureData,
+                                                    const DDLPromiseImageHelper& helper) {
+    SkASSERT(!fReconstitutedPicture);
+
+    // This is bending the DDLRecorder contract! The promise images in the SKP should be
+    // created by the same recorder used to create the matching DDL.
+    SkDeferredDisplayListRecorder recorder(fCharacterization);
+
+    fReconstitutedPicture = helper.reinflateSKP(&recorder, compressedPictureData, &fPromiseImages);
+
+    std::unique_ptr<SkDeferredDisplayList> ddl = recorder.detach();
+    if (ddl->priv().numRenderTasks()) {
+        // TODO: remove this once skbug.com/8424 is fixed. If the DDL resulting from the
+        // reinflation of the SKPs contains opsTasks that means some image subset operation
+        // created a draw.
+        fReconstitutedPicture.reset();
+    }
+}
+
+void DDLTileHelper::TileData::createDDL() {
+    SkASSERT(!fDisplayList);
+
+    SkDeferredDisplayListRecorder recorder(fCharacterization);
+
+    // DDL TODO: the DDLRecorder's GrContext isn't initialized until getCanvas is called.
+    // Maybe set it up in the ctor?
+    SkCanvas* subCanvas = recorder.getCanvas();
+
+    // Because we cheated in createTileSpecificSKP and used the wrong DDLRecorder, the GrContext's
+    // stored in fReconstitutedPicture's promise images are incorrect. Patch them with the correct
+    // one now.
+    for (int i = 0; i < fPromiseImages.count(); ++i) {
+        GrContext* newContext = subCanvas->getGrContext();
+
+        if (fPromiseImages[i]->isTextureBacked()) {
+            SkImage_GpuBase* gpuImage = (SkImage_GpuBase*) fPromiseImages[i].get();
+            gpuImage->resetContext(sk_ref_sp(newContext));
+        }
+    }
+
+    subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
+    subCanvas->translate(-fClip.fLeft, -fClip.fTop);
+
+    // Note: in this use case we only render a picture to the deferred canvas
+    // but, more generally, clients will use arbitrary draw calls.
+    if (fReconstitutedPicture) {
+        subCanvas->drawPicture(fReconstitutedPicture);
+    }
+
+    fDisplayList = recorder.detach();
+}
+
+void DDLTileHelper::TileData::draw() {
+    SkASSERT(fDisplayList);
+
+    fSurface->draw(fDisplayList.get());
+}
+
+void DDLTileHelper::TileData::compose(SkCanvas* dst) {
+    sk_sp<SkImage> img = fSurface->makeImageSnapshot();
+    dst->save();
+    dst->clipRect(SkRect::Make(fClip));
+    dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop);
+    dst->restore();
+}
+
+void DDLTileHelper::TileData::reset() {
+    // TODO: when DDLs are re-renderable we don't need to do this
+    fDisplayList = nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DDLTileHelper::DDLTileHelper(SkCanvas* canvas, const SkIRect& viewport, int numDivisions)
+        : fNumDivisions(numDivisions) {
+    SkASSERT(fNumDivisions > 0);
+    fTiles.reserve(fNumDivisions*fNumDivisions);
+
+    int xTileSize = viewport.width()/fNumDivisions;
+    int yTileSize = viewport.height()/fNumDivisions;
+
+    // Create the destination tiles
+    for (int y = 0, yOff = 0; y < fNumDivisions; ++y, yOff += yTileSize) {
+        int ySize = (y < fNumDivisions-1) ? yTileSize : viewport.height()-yOff;
+
+        for (int x = 0, xOff = 0; x < fNumDivisions; ++x, xOff += xTileSize) {
+            int xSize = (x < fNumDivisions-1) ? xTileSize : viewport.width()-xOff;
+
+            SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize);
+
+            SkASSERT(viewport.contains(clip));
+
+            SkImageInfo tileII = SkImageInfo::MakeN32Premul(xSize, ySize);
+
+            sk_sp<SkSurface> tileSurface = canvas->makeSurface(tileII);
+
+            // TODO: this is here to deal w/ a resource allocator bug (skbug.com/8007). If all
+            // the DDLs are flushed at the same time (w/o the composition draws) the allocator
+            // feels free to reuse the backing GrSurfaces!
+            tileSurface->flush();
+
+            fTiles.push_back(TileData(std::move(tileSurface), clip));
+        }
+    }
+}
+
+void DDLTileHelper::createSKPPerTile(SkData* compressedPictureData,
+                                     const DDLPromiseImageHelper& helper) {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].createTileSpecificSKP(compressedPictureData, helper);
+    }
+}
+
+void DDLTileHelper::createDDLsInParallel() {
+#if 1
+    SkTaskGroup().batch(fTiles.count(), [&](int i) { fTiles[i].createDDL(); });
+    SkTaskGroup().wait();
+#else
+    // Use this code path to debug w/o threads
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].createDDL();
+    }
+#endif
+
+}
+
+void DDLTileHelper::drawAllTilesAndFlush(GrContext* context, bool flush) {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].draw();
+    }
+    if (flush) {
+        context->flush();
+    }
+}
+
+void DDLTileHelper::composeAllTiles(SkCanvas* dstCanvas) {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].compose(dstCanvas);
+    }
+}
+
+void DDLTileHelper::resetAllTiles() {
+    for (int i = 0; i < fTiles.count(); ++i) {
+        fTiles[i].reset();
+    }
+}
diff --git a/src/third_party/skia/tools/DDLTileHelper.h b/src/third_party/skia/tools/DDLTileHelper.h
new file mode 100644
index 0000000..f7f45c0
--- /dev/null
+++ b/src/third_party/skia/tools/DDLTileHelper.h
@@ -0,0 +1,77 @@
+/*
+ * 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 DDLTileHelper_DEFINED
+#define DDLTileHelper_DEFINED
+
+#include "include/core/SkRect.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSurfaceCharacterization.h"
+
+class DDLPromiseImageHelper;
+class SkCanvas;
+class SkData;
+class SkDeferredDisplayList;
+class SkPicture;
+class SkSurface;
+class SkSurfaceCharacterization;
+
+class DDLTileHelper {
+public:
+    // TileData class encapsulates the information and behavior for a single tile/thread in
+    // a DDL rendering.
+    class TileData {
+    public:
+        TileData(sk_sp<SkSurface>, const SkIRect& clip);
+
+        // This method can be invoked in parallel
+        // In each thread we will reconvert the compressedPictureData into an SkPicture
+        // replacing each image-index with a promise image.
+        void createTileSpecificSKP(SkData* compressedPictureData,
+                                   const DDLPromiseImageHelper& helper);
+
+        // This method can be invoked in parallel
+        // Create the per-tile DDL from the per-tile SKP
+        void createDDL();
+
+        // This method operates serially and replays the recorded DDL into the tile surface.
+        void draw();
+
+        // This method also operates serially and composes the results of replaying the DDL into
+        // the final destination surface.
+        void compose(SkCanvas* dst);
+
+        void reset();
+
+    private:
+        sk_sp<SkSurface>                       fSurface;
+        SkSurfaceCharacterization              fCharacterization;
+        SkIRect                                fClip;    // in the device space of the dest canvas
+        sk_sp<SkPicture>                       fReconstitutedPicture;
+        SkTArray<sk_sp<SkImage>>               fPromiseImages; // All the promise images in the
+                                                               // reconstituted picture
+        std::unique_ptr<SkDeferredDisplayList> fDisplayList;
+    };
+
+    DDLTileHelper(SkCanvas* canvas, const SkIRect& viewport, int numDivisions);
+
+    void createSKPPerTile(SkData* compressedPictureData, const DDLPromiseImageHelper& helper);
+
+    void createDDLsInParallel();
+
+    void drawAllTilesAndFlush(GrContext*, bool flush);
+
+    void composeAllTiles(SkCanvas* dstCanvas);
+
+    void resetAllTiles();
+
+private:
+    int                fNumDivisions; // number of tiles along a side
+    SkTArray<TileData> fTiles;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/DumpRecord.cpp b/src/third_party/skia/tools/DumpRecord.cpp
index e9374fd..fb2fbb0 100644
--- a/src/third_party/skia/tools/DumpRecord.cpp
+++ b/src/third_party/skia/tools/DumpRecord.cpp
@@ -7,11 +7,12 @@
 
 #include <stdio.h>
 
-#include "SkRecord.h"
-#include "SkRecordDraw.h"
+#include "src/core/SkPicturePriv.h"
+#include "src/core/SkRecord.h"
+#include "src/core/SkRecordDraw.h"
 
-#include "DumpRecord.h"
-#include "SkTime.h"
+#include "include/core/SkTime.h"
+#include "tools/DumpRecord.h"
 
 namespace {
 
@@ -63,7 +64,7 @@
     void print(const SkRecords::DrawPicture& command, double ns) {
         this->printNameAndTime(command, ns);
 
-        if (auto bp = command.picture->asSkBigPicture()) {
+        if (auto bp = SkPicturePriv::AsSkBigPicture(command.picture)) {
             ++fIndent;
 
             const SkRecord& record = *bp->record();
@@ -114,8 +115,8 @@
     template <typename T>
     static const char* NameOf(const T&) {
     #define CASE(U) case SkRecords::U##_Type: return #U;
-        switch(T::kType) { SK_RECORD_TYPES(CASE); }
-    #undef CASE
+        switch (T::kType) { SK_RECORD_TYPES(CASE) }
+#undef CASE
         SkDEBUGFAIL("Unknown T");
         return "Unknown T";
     }
diff --git a/src/third_party/skia/tools/HashAndEncode.cpp b/src/third_party/skia/tools/HashAndEncode.cpp
new file mode 100644
index 0000000..76d4b76
--- /dev/null
+++ b/src/third_party/skia/tools/HashAndEncode.cpp
@@ -0,0 +1,163 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/core/SkICC.h"
+#include "include/core/SkString.h"
+#include "tools/HashAndEncode.h"
+#include "png.h"
+
+static sk_sp<SkColorSpace> rec2020() {
+    return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020);
+}
+
+HashAndEncode::HashAndEncode(const SkBitmap& bitmap) : fSize(bitmap.info().dimensions()) {
+    skcms_AlphaFormat srcAlpha;
+    switch (bitmap.alphaType()) {
+        case kUnknown_SkAlphaType: return;
+
+        case kOpaque_SkAlphaType:
+        case kUnpremul_SkAlphaType: srcAlpha = skcms_AlphaFormat_Unpremul;        break;
+        case kPremul_SkAlphaType:   srcAlpha = skcms_AlphaFormat_PremulAsEncoded; break;
+    }
+
+    skcms_PixelFormat srcFmt;
+    switch (bitmap.colorType()) {
+        case kUnknown_SkColorType:            return;
+
+        case kAlpha_8_SkColorType:            srcFmt = skcms_PixelFormat_A_8;          break;
+        case kRGB_565_SkColorType:            srcFmt = skcms_PixelFormat_BGR_565;      break;
+        case kARGB_4444_SkColorType:          srcFmt = skcms_PixelFormat_ABGR_4444;    break;
+        case kRGBA_8888_SkColorType:          srcFmt = skcms_PixelFormat_RGBA_8888;    break;
+        case kBGRA_8888_SkColorType:          srcFmt = skcms_PixelFormat_BGRA_8888;    break;
+        case kRGBA_1010102_SkColorType:       srcFmt = skcms_PixelFormat_RGBA_1010102; break;
+        case kGray_8_SkColorType:             srcFmt = skcms_PixelFormat_G_8;          break;
+        case kRGBA_F16Norm_SkColorType:       srcFmt = skcms_PixelFormat_RGBA_hhhh;    break;
+        case kRGBA_F16_SkColorType:           srcFmt = skcms_PixelFormat_RGBA_hhhh;    break;
+        case kRGBA_F32_SkColorType:           srcFmt = skcms_PixelFormat_RGBA_ffff;    break;
+
+        case kRGB_888x_SkColorType:           srcFmt = skcms_PixelFormat_RGBA_8888;
+                                              srcAlpha = skcms_AlphaFormat_Opaque;     break;
+        case kRGB_101010x_SkColorType:        srcFmt = skcms_PixelFormat_RGBA_1010102;
+                                              srcAlpha = skcms_AlphaFormat_Opaque;     break;
+        case kR8G8_unorm_SkColorType:         return;
+        case kR16G16_unorm_SkColorType:       return;
+        case kR16G16_float_SkColorType:       return;
+        case kA16_unorm_SkColorType:          return;
+        case kA16_float_SkColorType:          return;
+        case kR16G16B16A16_unorm_SkColorType: return;
+    }
+
+    skcms_ICCProfile srcProfile = *skcms_sRGB_profile();
+    if (auto cs = bitmap.colorSpace()) {
+        cs->toProfile(&srcProfile);
+    }
+
+    // Our common format that can represent anything we draw and encode as a PNG:
+    //   - 16-bit big-endian RGBA
+    //   - unpremul
+    //   - Rec. 2020 gamut and transfer function
+    skcms_PixelFormat dstFmt   = skcms_PixelFormat_RGBA_16161616BE;
+    skcms_AlphaFormat dstAlpha = skcms_AlphaFormat_Unpremul;
+    skcms_ICCProfile dstProfile;
+    rec2020()->toProfile(&dstProfile);
+
+    int N = fSize.width() * fSize.height();
+    fPixels.reset(new uint64_t[N]);
+
+    if (!skcms_Transform(bitmap.getPixels(), srcFmt, srcAlpha, &srcProfile,
+                         fPixels.get(),      dstFmt, dstAlpha, &dstProfile, N)) {
+        SkASSERT(false);
+        fPixels.reset(nullptr);
+    }
+}
+
+void HashAndEncode::write(SkWStream* st) const {
+    st->write(&fSize, sizeof(fSize));
+    if (const uint64_t* px = fPixels.get()) {
+        st->write(px, sizeof(*px) * fSize.width() * fSize.height());
+    }
+
+    // N.B. changing salt will change the hash of all images produced by DM,
+    // and will cause tens of thousands of new images to be uploaded to Gold.
+    int salt = 1;
+    st->write(&salt, sizeof(salt));
+}
+
+bool HashAndEncode::writePngTo(const char* path,
+                               const char* md5,
+                               CommandLineFlags::StringArray key,
+                               CommandLineFlags::StringArray properties) const {
+    if (!fPixels) {
+        return false;
+    }
+
+    FILE* f = fopen(path, "wb");
+    if (!f) {
+        return false;
+    }
+
+    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+    if (!png) {
+        fclose(f);
+        return false;
+    }
+
+    png_infop info = png_create_info_struct(png);
+    if (!info) {
+        png_destroy_write_struct(&png, &info);
+        fclose(f);
+        return false;
+    }
+
+    SkString description;
+    description.append("Key: ");
+    for (int i = 0; i < key.count(); i++) {
+        description.appendf("%s ", key[i]);
+    }
+    description.append("Properties: ");
+    for (int i = 0; i < properties.count(); i++) {
+        description.appendf("%s ", properties[i]);
+    }
+    description.appendf("MD5: %s", md5);
+
+    png_text text[2];
+    text[0].key  = (png_charp)"Author";
+    text[0].text = (png_charp)"DM unified Rec.2020";
+    text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+    text[1].key  = (png_charp)"Description";
+    text[1].text = (png_charp)description.c_str();
+    text[1].compression = PNG_TEXT_COMPRESSION_NONE;
+    png_set_text(png, info, text, SK_ARRAY_COUNT(text));
+
+    png_init_io(png, f);
+    png_set_IHDR(png, info, (png_uint_32)fSize.width()
+                          , (png_uint_32)fSize.height()
+                          , 16/*bits per channel*/
+                          , PNG_COLOR_TYPE_RGB_ALPHA
+                          , PNG_INTERLACE_NONE
+                          , PNG_COMPRESSION_TYPE_DEFAULT
+                          , PNG_FILTER_TYPE_DEFAULT);
+
+    // Fastest encoding and decoding, at slight file size cost is no filtering, compression 1.
+    png_set_filter(png, PNG_FILTER_TYPE_BASE, PNG_FILTER_NONE);
+    png_set_compression_level(png, 1);
+
+    static const sk_sp<SkData> profile =
+        SkWriteICCProfile(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020);
+    png_set_iCCP(png, info,
+                 "Rec.2020",
+                 0/*compression type... no idea what options are available here*/,
+                 (png_const_bytep)profile->data(),
+                 (png_uint_32)    profile->size());
+
+    png_write_info(png, info);
+    for (int y = 0; y < fSize.height(); y++) {
+        png_write_row(png, (png_bytep)(fPixels.get() + y*fSize.width()));
+    }
+    png_write_end(png, info);
+
+    png_destroy_write_struct(&png, &info);
+    fclose(f);
+    return true;
+}
+
diff --git a/src/third_party/skia/tools/HashAndEncode.h b/src/third_party/skia/tools/HashAndEncode.h
new file mode 100644
index 0000000..0447fc4
--- /dev/null
+++ b/src/third_party/skia/tools/HashAndEncode.h
@@ -0,0 +1,25 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#pragma once
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkStream.h"
+#include "tools/flags/CommandLineFlags.h"
+
+class HashAndEncode {
+public:
+    explicit HashAndEncode(const SkBitmap&);
+
+    void write(SkWStream*) const;
+
+    bool writePngTo(const char* path,
+                    const char* md5,
+                    CommandLineFlags::StringArray key,
+                    CommandLineFlags::StringArray properties) const;
+
+private:
+    const SkISize               fSize;
+    std::unique_ptr<uint64_t[]> fPixels;
+};
+
diff --git a/src/third_party/skia/tools/LsanSuppressions.cpp b/src/third_party/skia/tools/LsanSuppressions.cpp
index c81184f..4da984b 100644
--- a/src/third_party/skia/tools/LsanSuppressions.cpp
+++ b/src/third_party/skia/tools/LsanSuppressions.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
 
 #if !defined(__has_feature)
     #define __has_feature(x) 0
@@ -17,9 +17,10 @@
 
     const char* __lsan_default_suppressions();
     const char* __lsan_default_suppressions() {
-        return "leak:libfontconfig\n"    // FontConfig looks like it leaks, but it doesn't.
-               "leak:libGL.so\n"         // For NVidia driver.
-               "leak:__strdup\n"         // An eternal mystery, skia:2916.
+        return "leak:libfontconfig\n"       // FontConfig looks like it leaks, but it doesn't.
+               "leak:libGLX_nvidia.so\n"    // For NVidia driver.
+               "leak:libnvidia-glcore.so\n" // For NVidia driver.
+               "leak:libnvidia-tls.so\n"    // For NVidia driver.
                ;
     }
 
diff --git a/src/third_party/skia/tools/OverwriteLine.h b/src/third_party/skia/tools/OverwriteLine.h
index e8f0504..8985a6a 100644
--- a/src/third_party/skia/tools/OverwriteLine.h
+++ b/src/third_party/skia/tools/OverwriteLine.h
@@ -3,7 +3,7 @@
 
 // Print this string to reset and clear your current terminal line.
 static const char* kSkOverwriteLine =
-#ifdef SK_BUILD_FOR_WIN32
+#ifdef SK_BUILD_FOR_WIN
 "\r                                                                               \r"
 #elif defined(SK_BUILD_FOR_IOS)
 "\r"
diff --git a/src/third_party/skia/tools/ProcStats.cpp b/src/third_party/skia/tools/ProcStats.cpp
index 51ddf55..b9eae31 100644
--- a/src/third_party/skia/tools/ProcStats.cpp
+++ b/src/third_party/skia/tools/ProcStats.cpp
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#include "ProcStats.h"
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
+#include "tools/ProcStats.h"
 
 #if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) || defined(SK_BUILD_FOR_ANDROID)
     #include <sys/resource.h>
@@ -19,7 +19,7 @@
         return static_cast<int>(ru.ru_maxrss / 1024);  // Linux reports kilobytes.
     #endif
     }
-#elif defined(SK_BUILD_FOR_WIN32)
+#elif defined(SK_BUILD_FOR_WIN)
     #include <windows.h>
     #include <psapi.h>
     int sk_tools::getMaxResidentSetSizeMB() {
@@ -59,7 +59,7 @@
         return rssPages * pageSize / 1024 / 1024;
     }
 
-#elif defined(SK_BUILD_FOR_WIN32)
+#elif defined(SK_BUILD_FOR_WIN)
     int sk_tools::getCurrResidentSetSizeMB() {
         PROCESS_MEMORY_COUNTERS info;
         GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
diff --git a/src/third_party/skia/tools/Registry.h b/src/third_party/skia/tools/Registry.h
index 6a1e24a..d5731a7 100644
--- a/src/third_party/skia/tools/Registry.h
+++ b/src/third_party/skia/tools/Registry.h
@@ -8,7 +8,8 @@
 #ifndef sk_tools_Registry_DEFINED
 #define sk_tools_Registry_DEFINED
 
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkNoncopyable.h"
 
 namespace sk_tools {
 
@@ -18,9 +19,7 @@
  */
 template <typename T> class Registry : SkNoncopyable {
 public:
-    typedef T Factory;
-
-    explicit Registry(T fact) : fFact(fact) {
+    explicit Registry(T value) : fValue(value) {
 #ifdef SK_BUILD_FOR_ANDROID
         // work-around for double-initialization bug
         {
@@ -40,10 +39,22 @@
     static const Registry* Head() { return gHead; }
 
     const Registry* next() const { return fChain; }
-    const Factory& factory() const { return fFact; }
+    const T& get() const { return fValue; }
+
+    // for (const T& t : sk_tools::Registry<T>::Range()) { process(t); }
+    struct Range {
+        struct Iterator {
+            const Registry* fPtr;
+            const T& operator*() { return SkASSERT(fPtr), fPtr->get(); }
+            void operator++() { if (fPtr) { fPtr = fPtr->next(); } }
+            bool operator!=(const Iterator& other) const { return fPtr != other.fPtr; }
+        };
+        Iterator begin() const { return Iterator{Registry::Head()}; }
+        Iterator end() const { return Iterator{nullptr}; }
+    };
 
 private:
-    Factory   fFact;
+    T fValue;
     Registry* fChain;
 
     static Registry* gHead;
diff --git a/src/third_party/skia/tools/ResourceFactory.h b/src/third_party/skia/tools/ResourceFactory.h
new file mode 100644
index 0000000..542989e
--- /dev/null
+++ b/src/third_party/skia/tools/ResourceFactory.h
@@ -0,0 +1,14 @@
+/*
+ * 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 ResourceFactory_DEFINED
+#define ResourceFactory_DEFINED
+
+#include "include/core/SkData.h"
+
+extern sk_sp<SkData> (*gResourceFactory)(const char*);
+
+#endif  // ResourceFactory_DEFINED
diff --git a/src/third_party/skia/tools/Resources.cpp b/src/third_party/skia/tools/Resources.cpp
index f93cf24..89f857e 100644
--- a/src/third_party/skia/tools/Resources.cpp
+++ b/src/third_party/skia/tools/Resources.cpp
@@ -5,18 +5,22 @@
  * found in the LICENSE file.
  */
 
-#include "Resources.h"
-#include "SkBitmap.h"
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkImage.h"
-#include "SkImageGenerator.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkStream.h"
-#include "SkTypeface.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkImageGenerator.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTypeface.h"
+#include "src/core/SkOSFile.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/ResourceFactory.h"
+#include "tools/Resources.h"
+#include "tools/flags/CommandLineFlags.h"
 
-DEFINE_string2(resourcePath, i, "resources", "Directory with test resources: images, fonts, etc.");
+static DEFINE_string2(resourcePath, i, "resources",
+                      "Directory with test resources: images, fonts, etc.");
+
+sk_sp<SkData> (*gResourceFactory)(const char*) = nullptr;
 
 SkString GetResourcePath(const char* resource) {
     return SkOSPath::Join(FLAGS_resourcePath[0], resource);
@@ -26,43 +30,31 @@
     FLAGS_resourcePath.set(0, resource);
 }
 
-bool GetResourceAsBitmap(const char* resource, SkBitmap* dst) {
-    SkString resourcePath = GetResourcePath(resource);
-    sk_sp<SkData> resourceData(SkData::MakeFromFileName(resourcePath.c_str()));
-    std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::MakeFromEncoded(resourceData));
-    if (!gen) {
-        return false;
-    }
-    return dst->tryAllocPixels(gen->getInfo()) &&
-        gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst->getPixels(), dst->rowBytes(),
-                       nullptr);
+bool DecodeDataToBitmap(sk_sp<SkData> data, SkBitmap* dst) {
+    std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::MakeFromEncoded(std::move(data)));
+    return gen && dst->tryAllocPixels(gen->getInfo()) &&
+        gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst->getPixels(), dst->rowBytes());
 }
 
-sk_sp<SkImage> GetResourceAsImage(const char* resource) {
-    SkString path = GetResourcePath(resource);
-    sk_sp<SkData> resourceData(SkData::MakeFromFileName(path.c_str()));
-    return SkImage::MakeFromEncoded(resourceData);
-}
-
-SkStreamAsset* GetResourceAsStream(const char* resource) {
-    SkString resourcePath = GetResourcePath(resource);
-    std::unique_ptr<SkFILEStream> stream(new SkFILEStream(resourcePath.c_str()));
-    if (!stream->isValid()) {
-        SkDebugf("Resource %s not found.\n", resource);
-        return nullptr;
-    }
-    return stream.release();
+std::unique_ptr<SkStreamAsset> GetResourceAsStream(const char* resource) {
+    auto data = GetResourceAsData(resource);
+    return data ? std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data)))
+                : nullptr;
 }
 
 sk_sp<SkData> GetResourceAsData(const char* resource) {
-    SkString resourcePath = GetResourcePath(resource);
-    return SkData::MakeFromFileName(resourcePath.c_str());
+    if (sk_sp<SkData> data = gResourceFactory
+                           ? gResourceFactory(resource)
+                           : SkData::MakeFromFileName(GetResourcePath(resource).c_str())) {
+        return data;
+    }
+    SkDebugf("Resource \"%s\" not found.\n", GetResourcePath(resource).c_str());
+    #ifdef SK_TOOLS_REQUIRE_RESOURCES
+    SK_ABORT("missing resource");
+    #endif
+    return nullptr;
 }
 
-sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource) {
-    std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream(resource));
-    if (!stream) {
-        return nullptr;
-    }
-    return SkTypeface::MakeFromStream(stream.release());
+sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource, int ttcIndex) {
+    return SkTypeface::MakeFromStream(GetResourceAsStream(resource), ttcIndex);
 }
diff --git a/src/third_party/skia/tools/Resources.h b/src/third_party/skia/tools/Resources.h
index fa1ca45..81bdd1b 100644
--- a/src/third_party/skia/tools/Resources.h
+++ b/src/third_party/skia/tools/Resources.h
@@ -8,22 +8,32 @@
 #ifndef Resources_DEFINED
 #define Resources_DEFINED
 
-#include "SkRefCnt.h"
-#include "SkString.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkString.h"
 
 class SkBitmap;
 class SkData;
-class SkImage;
 class SkStreamAsset;
 class SkTypeface;
 
 SkString GetResourcePath(const char* resource = "");
+
 void SetResourcePath(const char* );
 
-bool GetResourceAsBitmap(const char* resource, SkBitmap* dst);
-sk_sp<SkImage> GetResourceAsImage(const char* resource);
-SkStreamAsset* GetResourceAsStream(const char* resource);
+bool DecodeDataToBitmap(sk_sp<SkData> data, SkBitmap* dst);
+
 sk_sp<SkData> GetResourceAsData(const char* resource);
-sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource);
+
+inline bool GetResourceAsBitmap(const char* resource, SkBitmap* dst) {
+    return DecodeDataToBitmap(GetResourceAsData(resource), dst);
+}
+
+inline sk_sp<SkImage> GetResourceAsImage(const char* resource) {
+    return SkImage::MakeFromEncoded(GetResourceAsData(resource));
+}
+
+std::unique_ptr<SkStreamAsset> GetResourceAsStream(const char* resource);
+
+sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource, int ttcIndex = 0);
 
 #endif  // Resources_DEFINED
diff --git a/src/third_party/skia/tools/SkJSONCPP.h b/src/third_party/skia/tools/SkJSONCPP.h
deleted file mode 100644
index 6baf223..0000000
--- a/src/third_party/skia/tools/SkJSONCPP.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * A common place to put the jsoncpp library includes, as opposed to littering
- * the pragmas repeatedly through our code.
- */
-#ifndef SkJSONCPP_DEFINED
-#define SkJSONCPP_DEFINED
-
-#ifdef GOOGLE3
-    #include "third_party/jsoncpp/reader.h"
-    #include "third_party/jsoncpp/value.h"
-    #include "third_party/jsoncpp/writer.h"
-#else
-    #ifdef SK_BUILD_FOR_WIN
-        // json includes xlocale which generates warning 4530 because we're
-        // compiling without exceptions;
-        // see https://code.google.com/p/skia/issues/detail?id=1067
-        #pragma warning(push)
-        #pragma warning(disable : 4530)
-    #endif
-    #include "json/reader.h"
-    #include "json/value.h"
-    #include "json/writer.h"
-    #ifdef SK_BUILD_FOR_WIN
-        #pragma warning(pop)
-    #endif
-#endif
-
-#endif // SkJSONCPP_DEFINED
diff --git a/src/third_party/skia/tools/SkMetaData.cpp b/src/third_party/skia/tools/SkMetaData.cpp
new file mode 100644
index 0000000..ede1921
--- /dev/null
+++ b/src/third_party/skia/tools/SkMetaData.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/SkMetaData.h"
+
+#include "include/private/SkMalloc.h"
+#include "include/private/SkTo.h"
+
+void SkMetaData::reset()
+{
+    Rec* rec = fRec;
+    while (rec) {
+        Rec* next = rec->fNext;
+        Rec::Free(rec);
+        rec = next;
+    }
+    fRec = nullptr;
+}
+
+void SkMetaData::setS32(const char name[], int32_t value)
+{
+    (void)this->set(name, &value, sizeof(int32_t), kS32_Type, 1);
+}
+
+void SkMetaData::setScalar(const char name[], SkScalar value)
+{
+    (void)this->set(name, &value, sizeof(SkScalar), kScalar_Type, 1);
+}
+
+SkScalar* SkMetaData::setScalars(const char name[], int count, const SkScalar values[])
+{
+    SkASSERT(count > 0);
+    if (count > 0)
+        return (SkScalar*)this->set(name, values, sizeof(SkScalar), kScalar_Type, count);
+    return nullptr;
+}
+
+void SkMetaData::setPtr(const char name[], void* ptr) {
+    (void)this->set(name, &ptr, sizeof(void*), kPtr_Type, 1);
+}
+
+void SkMetaData::setBool(const char name[], bool value)
+{
+    (void)this->set(name, &value, sizeof(bool), kBool_Type, 1);
+}
+
+void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type type, int count)
+{
+    SkASSERT(name);
+    SkASSERT(dataSize);
+    SkASSERT(count > 0);
+
+    (void)this->remove(name, type);
+
+    size_t  len = strlen(name);
+    Rec*    rec = Rec::Alloc(sizeof(Rec) + dataSize * count + len + 1);
+
+#ifndef SK_DEBUG
+    rec->fType = SkToU8(type);
+#else
+    rec->fType = type;
+#endif
+    rec->fDataLen = SkToU8(dataSize);
+    rec->fDataCount = SkToU16(count);
+    if (data)
+        memcpy(rec->data(), data, dataSize * count);
+    memcpy(rec->name(), name, len + 1);
+
+    rec->fNext = fRec;
+    fRec = rec;
+    return rec->data();
+}
+
+bool SkMetaData::findS32(const char name[], int32_t* value) const
+{
+    const Rec* rec = this->find(name, kS32_Type);
+    if (rec)
+    {
+        SkASSERT(rec->fDataCount == 1);
+        if (value)
+            *value = *(const int32_t*)rec->data();
+        return true;
+    }
+    return false;
+}
+
+bool SkMetaData::findScalar(const char name[], SkScalar* value) const
+{
+    const Rec* rec = this->find(name, kScalar_Type);
+    if (rec)
+    {
+        SkASSERT(rec->fDataCount == 1);
+        if (value)
+            *value = *(const SkScalar*)rec->data();
+        return true;
+    }
+    return false;
+}
+
+const SkScalar* SkMetaData::findScalars(const char name[], int* count, SkScalar values[]) const
+{
+    const Rec* rec = this->find(name, kScalar_Type);
+    if (rec)
+    {
+        if (count)
+            *count = rec->fDataCount;
+        if (values)
+            memcpy(values, rec->data(), rec->fDataCount * rec->fDataLen);
+        return (const SkScalar*)rec->data();
+    }
+    return nullptr;
+}
+
+bool SkMetaData::findPtr(const char name[], void** ptr) const {
+    const Rec* rec = this->find(name, kPtr_Type);
+    if (rec) {
+        SkASSERT(rec->fDataCount == 1);
+        void** found = (void**)rec->data();
+        if (ptr) {
+            *ptr = *found;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool SkMetaData::findBool(const char name[], bool* value) const
+{
+    const Rec* rec = this->find(name, kBool_Type);
+    if (rec)
+    {
+        SkASSERT(rec->fDataCount == 1);
+        if (value)
+            *value = *(const bool*)rec->data();
+        return true;
+    }
+    return false;
+}
+
+const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const
+{
+    const Rec* rec = fRec;
+    while (rec)
+    {
+        if (rec->fType == type && !strcmp(rec->name(), name))
+            return rec;
+        rec = rec->fNext;
+    }
+    return nullptr;
+}
+
+bool SkMetaData::remove(const char name[], Type type) {
+    Rec* rec = fRec;
+    Rec* prev = nullptr;
+    while (rec) {
+        Rec* next = rec->fNext;
+        if (rec->fType == type && !strcmp(rec->name(), name)) {
+            if (prev) {
+                prev->fNext = next;
+            } else {
+                fRec = next;
+            }
+            Rec::Free(rec);
+            return true;
+        }
+        prev = rec;
+        rec = next;
+    }
+    return false;
+}
+
+bool SkMetaData::removeS32(const char name[])
+{
+    return this->remove(name, kS32_Type);
+}
+
+bool SkMetaData::removeScalar(const char name[])
+{
+    return this->remove(name, kScalar_Type);
+}
+
+bool SkMetaData::removePtr(const char name[])
+{
+    return this->remove(name, kPtr_Type);
+}
+
+bool SkMetaData::removeBool(const char name[])
+{
+    return this->remove(name, kBool_Type);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkMetaData::Iter::Iter(const SkMetaData& metadata) {
+    fRec = metadata.fRec;
+}
+
+void SkMetaData::Iter::reset(const SkMetaData& metadata) {
+    fRec = metadata.fRec;
+}
+
+const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count) {
+    const char* name = nullptr;
+
+    if (fRec) {
+        if (t) {
+            *t = (SkMetaData::Type)fRec->fType;
+        }
+        if (count) {
+            *count = fRec->fDataCount;
+        }
+        name = fRec->name();
+
+        fRec = fRec->fNext;
+    }
+    return name;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size) {
+    return (Rec*)sk_malloc_throw(size);
+}
+
+void SkMetaData::Rec::Free(Rec* rec) {
+    sk_free(rec);
+}
diff --git a/src/third_party/skia/tools/SkMetaData.h b/src/third_party/skia/tools/SkMetaData.h
new file mode 100644
index 0000000..4ba5d8e
--- /dev/null
+++ b/src/third_party/skia/tools/SkMetaData.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkMetaData_DEFINED
+#define SkMetaData_DEFINED
+
+#include "include/core/SkScalar.h"
+
+/** A map from c-string keys to arrays of POD (int32_t, kScalar, void*, or bool)
+    values.
+*/
+class SkMetaData {
+public:
+    SkMetaData() {}
+    ~SkMetaData() { if (fRec) { this->reset(); } }
+    void reset();
+
+    bool findS32(const char name[], int32_t* value = nullptr) const;
+    bool findScalar(const char name[], SkScalar* value = nullptr) const;
+    const SkScalar* findScalars(const char name[], int* count,
+                                SkScalar values[] = nullptr) const;
+    bool findPtr(const char name[], void** value = nullptr) const;
+    bool findBool(const char name[], bool* value = nullptr) const;
+
+    bool hasS32(const char name[], int32_t value) const {
+        int32_t v;
+        return this->findS32(name, &v) && v == value;
+    }
+    bool hasScalar(const char name[], SkScalar value) const {
+        SkScalar v;
+        return this->findScalar(name, &v) && v == value;
+    }
+    bool hasPtr(const char name[], void* value) const {
+        void* v;
+        return this->findPtr(name, &v) && v == value;
+    }
+    bool hasBool(const char name[], bool value) const {
+        bool    v;
+        return this->findBool(name, &v) && v == value;
+    }
+
+    void setS32(const char name[], int32_t value);
+    void setScalar(const char name[], SkScalar value);
+    SkScalar* setScalars(const char name[], int count, const SkScalar values[] = nullptr);
+    void setPtr(const char name[], void* value);
+    void setBool(const char name[], bool value);
+
+    bool removeS32(const char name[]);
+    bool removeScalar(const char name[]);
+    bool removePtr(const char name[]);
+    bool removeBool(const char name[]);
+
+    enum Type {
+        kS32_Type,
+        kScalar_Type,
+        kPtr_Type,
+        kBool_Type,
+
+        kTypeCount
+    };
+
+    struct Rec;
+    class Iter;
+    friend class Iter;
+
+    class Iter {
+    public:
+        Iter() : fRec(nullptr) {}
+        Iter(const SkMetaData&);
+
+        /** Reset the iterator, so that calling next() will return the first
+            data element. This is done implicitly in the constructor.
+        */
+        void reset(const SkMetaData&);
+
+        /** Each time next is called, it returns the name of the next data element,
+            or null when there are no more elements. If non-null is returned, then the
+            element's type is returned (if not null), and the number of data values
+            is returned in count (if not null).
+        */
+        const char* next(Type*, int* count);
+
+    private:
+        Rec* fRec;
+    };
+
+public:
+    struct Rec {
+        Rec*        fNext;
+        uint16_t    fDataCount; // number of elements
+        uint8_t     fDataLen;   // sizeof a single element
+        uint8_t     fType;
+
+        const void* data() const { return (this + 1); }
+        void*       data() { return (this + 1); }
+        const char* name() const { return (const char*)this->data() + fDataLen * fDataCount; }
+        char*       name() { return (char*)this->data() + fDataLen * fDataCount; }
+
+        static Rec* Alloc(size_t);
+        static void Free(Rec*);
+    };
+    Rec*    fRec = nullptr;
+
+    const Rec* find(const char name[], Type) const;
+    void* set(const char name[], const void* data, size_t len, Type, int count);
+    bool remove(const char name[], Type);
+
+    SkMetaData(const SkMetaData&) = delete;
+    SkMetaData& operator=(const SkMetaData&) = delete;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/SkShaper.h b/src/third_party/skia/tools/SkShaper.h
deleted file mode 100644
index bc78be7..0000000
--- a/src/third_party/skia/tools/SkShaper.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkShaper_DEFINED
-#define SkShaper_DEFINED
-
-#include <memory>
-
-#include "SkPoint.h"
-#include "SkTypeface.h"
-
-class SkPaint;
-class SkTextBlobBuilder;
-
-/**
-   Shapes text using HarfBuzz and places the shaped text into a
-   TextBlob.
-
-   If compiled without HarfBuzz, fall back on SkPaint::textToGlyphs.
- */
-class SkShaper {
-public:
-    SkShaper(sk_sp<SkTypeface> face);
-    ~SkShaper();
-
-    bool good() const;
-    SkScalar shape(SkTextBlobBuilder* dest,
-                   const SkPaint& srcPaint,
-                   const char* utf8text,
-                   size_t textBytes,
-                   SkPoint point) const;
-
-private:
-    SkShaper(const SkShaper&) = delete;
-    SkShaper& operator=(const SkShaper&) = delete;
-
-    struct Impl;
-    std::unique_ptr<Impl> fImpl;
-};
-
-#endif  // SkShaper_DEFINED
diff --git a/src/third_party/skia/tools/SkShaper_harfbuzz.cpp b/src/third_party/skia/tools/SkShaper_harfbuzz.cpp
deleted file mode 100644
index 9c7d69e..0000000
--- a/src/third_party/skia/tools/SkShaper_harfbuzz.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <hb-ot.h>
-
-#include "SkShaper.h"
-#include "SkStream.h"
-#include "SkTextBlob.h"
-#include "SkTypeface.h"
-
-static const int FONT_SIZE_SCALE = 512;
-
-namespace {
-struct HBFBlobDel {
-    void operator()(hb_blob_t* b) { hb_blob_destroy(b); }
-};
-
-std::unique_ptr<hb_blob_t, HBFBlobDel> stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
-    size_t size = asset->getLength();
-    std::unique_ptr<hb_blob_t, HBFBlobDel> blob;
-    if (const void* base = asset->getMemoryBase()) {
-        blob.reset(hb_blob_create((char*)base, SkToUInt(size),
-                                  HB_MEMORY_MODE_READONLY, asset.release(),
-                                  [](void* p) { delete (SkStreamAsset*)p; }));
-    } else {
-        // SkDebugf("Extra SkStreamAsset copy\n");
-        void* ptr = size ? sk_malloc_throw(size) : nullptr;
-        asset->read(ptr, size);
-        blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
-                                  HB_MEMORY_MODE_READONLY, ptr, sk_free));
-    }
-    SkASSERT(blob);
-    hb_blob_make_immutable(blob.get());
-    return blob;
-}
-}  // namespace
-
-struct SkShaper::Impl {
-    struct HBFontDel {
-        void operator()(hb_font_t* f) { hb_font_destroy(f); }
-    };
-    std::unique_ptr<hb_font_t, HBFontDel> fHarfBuzzFont;
-    struct HBBufDel {
-        void operator()(hb_buffer_t* b) { hb_buffer_destroy(b); }
-    };
-    std::unique_ptr<hb_buffer_t, HBBufDel> fBuffer;
-    sk_sp<SkTypeface> fTypeface;
-};
-
-SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
-    fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
-    int index;
-    std::unique_ptr<hb_blob_t, HBFBlobDel> blob(
-            stream_to_blob(std::unique_ptr<SkStreamAsset>(
-                                   fImpl->fTypeface->openStream(&index))));
-    struct HBFaceDel {
-        void operator()(hb_face_t* f) { hb_face_destroy(f); }
-    };
-    std::unique_ptr<hb_face_t, HBFaceDel> face(
-            hb_face_create(blob.get(), (unsigned)index));
-    SkASSERT(face);
-    if (!face) {
-        return;
-    }
-    hb_face_set_index(face.get(), (unsigned)index);
-    hb_face_set_upem(face.get(), fImpl->fTypeface->getUnitsPerEm());
-
-    fImpl->fHarfBuzzFont.reset(hb_font_create(face.get()));
-    SkASSERT(fImpl->fHarfBuzzFont);
-    hb_font_set_scale(fImpl->fHarfBuzzFont.get(), FONT_SIZE_SCALE, FONT_SIZE_SCALE);
-    hb_ot_font_set_funcs(fImpl->fHarfBuzzFont.get());
-
-    fImpl->fBuffer.reset(hb_buffer_create());
-}
-
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const { return fImpl->fHarfBuzzFont != nullptr; }
-
-SkScalar SkShaper::shape(SkTextBlobBuilder* builder,
-                         const SkPaint& srcPaint,
-                         const char* utf8text,
-                         size_t textBytes,
-                         SkPoint point) const {
-    SkPaint paint(srcPaint);
-    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-    paint.setTypeface(fImpl->fTypeface);
-
-    SkASSERT(builder);
-    hb_buffer_t* buffer = fImpl->fBuffer.get();
-    hb_buffer_add_utf8(buffer, utf8text, -1, 0, -1);
-    hb_buffer_guess_segment_properties(buffer);
-    hb_shape(fImpl->fHarfBuzzFont.get(), buffer, nullptr, 0);
-    unsigned len = hb_buffer_get_length(buffer);
-    if (len == 0) {
-        hb_buffer_clear_contents(buffer);
-        return 0;
-    }
-
-    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, NULL);
-    hb_glyph_position_t* pos =
-            hb_buffer_get_glyph_positions(buffer, NULL);
-    auto runBuffer = builder->allocRunTextPos(
-            paint, SkToInt(len), SkToInt(textBytes), SkString());
-    memcpy(runBuffer.utf8text, utf8text, textBytes);
-
-    double x = point.x();
-    double y = point.y();
-
-    double textSizeY = paint.getTextSize() / (double)FONT_SIZE_SCALE;
-    double textSizeX = textSizeY * paint.getTextScaleX();
-
-    for (unsigned i = 0; i < len; i++) {
-        runBuffer.glyphs[i] = info[i].codepoint;
-        runBuffer.clusters[i] = info[i].cluster;
-        reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
-                SkPoint::Make(SkDoubleToScalar(x + pos[i].x_offset * textSizeX),
-                              SkDoubleToScalar(y - pos[i].y_offset * textSizeY));
-        x += pos[i].x_advance * textSizeX;
-        y += pos[i].y_advance * textSizeY;
-    }
-
-    hb_buffer_clear_contents(buffer);
-    return (SkScalar)x;
-}
diff --git a/src/third_party/skia/tools/SkShaper_primitive.cpp b/src/third_party/skia/tools/SkShaper_primitive.cpp
deleted file mode 100644
index b165285..0000000
--- a/src/third_party/skia/tools/SkShaper_primitive.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "SkShaper.h"
-#include "SkStream.h"
-#include "SkTextBlob.h"
-#include "SkTypeface.h"
-
-struct SkShaper::Impl {
-    sk_sp<SkTypeface> fTypeface;
-};
-
-SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
-    fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
-}
-
-SkShaper::~SkShaper() {}
-
-bool SkShaper::good() const { return true; }
-
-// This example only uses public API, so we don't use SkUTF8_NextUnichar.
-unsigned utf8_lead_byte_to_count(const char* ptr) {
-    uint8_t c = *(const uint8_t*)ptr;
-    SkASSERT(c <= 0xF7);
-    SkASSERT((c & 0xC0) != 0x80);
-    return (((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1;
-}
-
-SkScalar SkShaper::shape(SkTextBlobBuilder* builder,
-                         const SkPaint& srcPaint,
-                         const char* utf8text,
-                         size_t textBytes,
-                         SkPoint point) const {
-    SkPaint paint(srcPaint);
-    paint.setTypeface(fImpl->fTypeface);
-    paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
-    int glyphCount = paint.countText(utf8text, textBytes);
-    if (glyphCount <= 0) {
-        return 0;
-    }
-    SkRect bounds;
-    (void)paint.measureText(utf8text, textBytes, &bounds);
-    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-    const SkTextBlobBuilder::RunBuffer& runBuffer =
-        builder->allocRunTextPosH(paint, glyphCount, point.y(), textBytes, SkString(), &bounds);
-    memcpy(runBuffer.utf8text, utf8text, textBytes);
-    const char* txtPtr = utf8text;
-    for (int i = 0; i < glyphCount; ++i) {
-        // Each charater maps to exactly one glyph via SkGlyphCache::unicharToGlyph().
-        runBuffer.clusters[i] = SkToU32(txtPtr - utf8text);
-        txtPtr += utf8_lead_byte_to_count(txtPtr);
-        SkASSERT(txtPtr <= utf8text + textBytes);
-    }
-    paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
-    (void)paint.textToGlyphs(utf8text, textBytes, runBuffer.glyphs);
-    (void)paint.getTextWidths(utf8text, textBytes, runBuffer.pos);
-    SkScalar x = point.x();
-    for (int i = 0; i < glyphCount; ++i) {
-        SkScalar w = runBuffer.pos[i];
-        runBuffer.pos[i] = x;
-        x += w;
-    }
-    return (SkScalar)x;
-}
diff --git a/src/third_party/skia/tools/SkSharingProc.cpp b/src/third_party/skia/tools/SkSharingProc.cpp
new file mode 100644
index 0000000..803f766
--- /dev/null
+++ b/src/third_party/skia/tools/SkSharingProc.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/SkSharingProc.h"
+
+#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkSerialProcs.h"
+
+sk_sp<SkData> SkSharingSerialContext::serializeImage(SkImage* img, void* ctx) {
+    SkSharingSerialContext* context = reinterpret_cast<SkSharingSerialContext*>(ctx);
+    uint32_t id = img->uniqueID(); // get this process's id for the image. these are not hashes.
+    // find out if we have already serialized this, and if so, what its in-file id is.
+    auto iter = context->fImageMap.find(id);
+    if (iter == context->fImageMap.end()) {
+        // When not present, add its id to the map and return its usual serialized form.
+        context->fImageMap[id] = context->fImageMap.size();
+        return img->encodeToData();
+    }
+    uint32_t fid = context->fImageMap[id];
+    // if present, return only the in-file id we registered the first time we serialized it.
+    return SkData::MakeWithCopy(&fid, sizeof(fid));
+}
+
+sk_sp<SkImage> SkSharingDeserialContext::deserializeImage(
+  const void* data, size_t length, void* ctx) {
+    SkSharingDeserialContext* context = reinterpret_cast<SkSharingDeserialContext*>(ctx);
+    uint32_t fid;
+    // If the data is an image fid, look up an already deserialized image from our map
+    if (length == sizeof(fid)) {
+        memcpy(&fid, data, sizeof(fid));
+        if (fid >= context->fImages.size()) {
+            SkDebugf("We do not have the data for image %d.\n", fid);
+            return nullptr;
+        }
+        return context->fImages[fid];
+    }
+    // Otherwise, the data is an image, deserialise it, store it in our map at its fid.
+    // TODO(nifong): make DeserialProcs accept sk_sp<SkData> so we don't have to copy this.
+    sk_sp<SkData> dataView = SkData::MakeWithCopy(data, length);
+    const sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(dataView));
+    context->fImages.push_back(image);
+    return image;
+}
diff --git a/src/third_party/skia/tools/SkSharingProc.h b/src/third_party/skia/tools/SkSharingProc.h
new file mode 100644
index 0000000..12a7b80
--- /dev/null
+++ b/src/third_party/skia/tools/SkSharingProc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSharingProc_DEFINED
+#define SkSharingProc_DEFINED
+
+#include <unordered_map>
+#include <vector>
+
+#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkSerialProcs.h"
+
+struct SkSharingSerialContext {
+    // A map from the ids from SkImage::uniqueID() to ids used within the file
+    std::unordered_map<uint32_t, uint32_t> fImageMap;
+
+    // A serial proc that shares images between subpictures
+    // To use this, create an instance of SkSerialProcs and populate it this way.
+    // The client must retain ownership of the context.
+    // auto ctx = std::make_unique<SkSharingSerialContext>()
+    // SkSerialProcs procs;
+    // procs.fImageProc = SkSharingSerialContext::serializeImage;
+    // procs.fImageCtx = ctx.get();
+    static sk_sp<SkData> serializeImage(SkImage* img, void* ctx);
+};
+
+struct SkSharingDeserialContext {
+    // a list of unique images in the order they were encountered in the file
+    // Subsequent occurrences of an image refer to it by it's index in this list.
+    std::vector<sk_sp<SkImage>> fImages;
+
+    // A deserial proc that can interpret id's in place of images as references to previous images.
+    // Can also deserialize a SKP where all images are inlined (it's backwards compatible)
+    static sk_sp<SkImage> deserializeImage(const void* data, size_t length, void* ctx);
+};
+
+#endif
diff --git a/src/third_party/skia/tools/SkVMBuilders.cpp b/src/third_party/skia/tools/SkVMBuilders.cpp
new file mode 100644
index 0000000..1902b0e
--- /dev/null
+++ b/src/third_party/skia/tools/SkVMBuilders.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/SkVMBuilders.h"
+
+// Some parts of this builder code are written less fluently than possible,
+// to avoid any ambiguity of function argument evaluation order.  This lets
+// our golden tests work portably.  In general there's no reason to fear
+// nesting calls to Builder routines.
+
+SrcoverBuilder_F32::SrcoverBuilder_F32(Fmt srcFmt, Fmt dstFmt) {
+    auto byte_to_f32 = [&](skvm::I32 byte) {
+        skvm::F32 _1_255 = splat(1/255.0f);
+        return mul(_1_255, to_f32(byte));
+    };
+
+    auto load = [&](Fmt fmt, skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) {
+        skvm::Arg ptr;
+        switch (fmt) {
+            case Fmt::A8: {
+                ptr = varying<uint8_t>();
+                *r = *g = *b = splat(0.0f);
+                *a = byte_to_f32(load8(ptr));
+            } break;
+
+            case Fmt::G8: {
+                ptr = varying<uint8_t>();
+                *r = *g = *b = byte_to_f32(load8(ptr));
+                *a = splat(1.0f);
+            } break;
+
+            case Fmt::RGBA_8888: {
+                ptr = varying<int>();
+                skvm::I32 rgba = load32(ptr);
+                *r = byte_to_f32(extract(rgba,  0, splat(0xff)));
+                *g = byte_to_f32(extract(rgba,  8, splat(0xff)));
+                *b = byte_to_f32(extract(rgba, 16, splat(0xff)));
+                *a = byte_to_f32(extract(rgba, 24, splat(0xff)));
+            } break;
+        }
+        return ptr;
+    };
+
+    skvm::F32 r,g,b,a;
+    (void)load(srcFmt, &r,&g,&b,&a);
+
+    skvm::F32 dr,dg,db,da;
+    skvm::Arg dst = load(dstFmt, &dr,&dg,&db,&da);
+
+    skvm::F32 invA = sub(splat(1.0f), a);
+    r = mad(dr, invA, r);
+    g = mad(dg, invA, g);
+    b = mad(db, invA, b);
+    a = mad(da, invA, a);
+
+    auto f32_to_byte = [&](skvm::F32 f32) {
+        skvm::F32 _255 = splat(255.0f),
+                  _0_5 = splat(0.5f);
+        return to_i32(mad(f32, _255, _0_5));
+    };
+    switch (dstFmt) {
+        case Fmt::A8: {
+            store8(dst, f32_to_byte(a));
+        } break;
+
+        case Fmt::G8: {
+            skvm::F32 _2126 = splat(0.2126f),
+                      _7152 = splat(0.7152f),
+                      _0722 = splat(0.0722f);
+            store8(dst, f32_to_byte(mad(r, _2126,
+                                    mad(g, _7152,
+                                    mul(b, _0722)))));
+        } break;
+
+        case Fmt::RGBA_8888: {
+            skvm::I32 R = f32_to_byte(r),
+                      G = f32_to_byte(g),
+                      B = f32_to_byte(b),
+                      A = f32_to_byte(a);
+
+            R = pack(R, G, 8);
+            B = pack(B, A, 8);
+            R = pack(R, B, 16);
+
+            store32(dst, R);
+        } break;
+    }
+}
+
+SrcoverBuilder_I32_Naive::SrcoverBuilder_I32_Naive() {
+    skvm::Arg src = varying<int>(),
+              dst = varying<int>();
+
+    auto load = [&](skvm::Arg ptr,
+                    skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) {
+        skvm::I32 rgba = load32(ptr);
+        *r = extract(rgba,  0, splat(0xff));
+        *g = extract(rgba,  8, splat(0xff));
+        *b = extract(rgba, 16, splat(0xff));
+        *a = extract(rgba, 24, splat(0xff));
+    };
+
+    skvm::I32 r,g,b,a;
+    load(src, &r,&g,&b,&a);
+
+    skvm::I32 dr,dg,db,da;
+    load(dst, &dr,&dg,&db,&da);
+
+    // (xy + x)/256 is a good approximation of (xy + 127)/255
+    //
+    //   == (d*(255-a) + d)/256
+    //   == (d*(255-a+1)  )/256
+    //   == (d*(256-a  )  )/256
+
+    skvm::I32 invA = sub(splat(256), a);
+    r = add(r, shr(mul(dr, invA), 8));
+    g = add(g, shr(mul(dg, invA), 8));
+    b = add(b, shr(mul(db, invA), 8));
+    a = add(a, shr(mul(da, invA), 8));
+
+    r = pack(r, g, 8);
+    b = pack(b, a, 8);
+    r = pack(r, b, 16);
+    store32(dst, r);
+}
+
+SrcoverBuilder_I32::SrcoverBuilder_I32() {
+    skvm::Arg src = varying<int>(),
+              dst = varying<int>();
+
+    auto load = [&](skvm::Arg ptr,
+                    skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) {
+        skvm::I32 rgba = load32(ptr);
+        *r = bit_and(rgba, splat(0xff));
+        *g = bytes  (rgba, 0x0002);
+        *b = bytes  (rgba, 0x0003);
+        *a = shr    (rgba, 24);
+    };
+
+    skvm::I32 r,g,b,a;
+    load(src, &r,&g,&b,&a);
+
+    skvm::I32 dr,dg,db,da;
+    load(dst, &dr,&dg,&db,&da);
+
+    // (xy + x)/256 is a good approximation of (xy + 127)/255
+    //
+    //   == (d*(255-a) + d)/256
+    //   == (d*(255-a+1)  )/256
+    //   == (d*(256-a  )  )/256
+
+    // We're doing 8x8 bit multiplies in 32-bit lanes.
+    // Since the inputs and results both fit in 16 bits,
+    // we can use mul_16x2, which tends to be faster than mul.
+    //
+    // (The top 2 zero bytes of the inputs will also multiply
+    // with each other to produce zero... perfect.)
+
+    skvm::I32 invA = sub(splat(256), a);
+    r = add(r, shr(mul_16x2(dr, invA), 8));
+    g = add(g, shr(mul_16x2(dg, invA), 8));
+    b = add(b, shr(mul_16x2(db, invA), 8));
+    a = add(a, shr(mul_16x2(da, invA), 8));
+
+    r = pack(r, g, 8);
+    b = pack(b, a, 8);
+    r = pack(r, b, 16);
+    store32(dst, r);
+}
+
+SrcoverBuilder_I32_SWAR::SrcoverBuilder_I32_SWAR() {
+    skvm::Arg src = varying<int>(),
+              dst = varying<int>();
+
+    // The s += d*invA adds won't overflow,
+    // so we don't have to unpack s beyond grabbing the alpha channel.
+    skvm::I32 s = load32(src),
+            ax2 = bytes(s, 0x0404);  // rgba -> a0a0
+
+    // We'll use the same approximation math as above, this time making sure to
+    // use both i16 multiplies to our benefit, one for r/g, the other for b/a.
+    skvm::I32 invAx2 = sub_16x2(splat(0x01000100), ax2);
+
+    skvm::I32 d  = load32(dst),
+              rb = bit_and (d, splat(0x00ff00ff)),
+              ga = shr_16x2(d, 8);
+
+    rb = shr_16x2(mul_16x2(rb, invAx2), 8);  // Put the high 8 bits back in the low lane.
+    ga =          mul_16x2(ga, invAx2);      // Keep the high 8 bits up high...
+    ga = bit_clear(ga, splat(0x00ff00ff));     // ...and mask off the low bits.
+
+    store32(dst, add(s, bit_or(rb, ga)));
+}
diff --git a/src/third_party/skia/tools/SkVMBuilders.h b/src/third_party/skia/tools/SkVMBuilders.h
new file mode 100644
index 0000000..261c423
--- /dev/null
+++ b/src/third_party/skia/tools/SkVMBuilders.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkVMBuilders_DEFINED
+#define SkVMBuilders_DEFINED
+
+#include "src/core/SkVM.h"
+
+// SkVM builders used by both SkVMBench.cpp and SkVMTest.cpp.
+
+struct SrcoverBuilder_F32 : public skvm::Builder {
+    enum class Fmt { A8, G8, RGBA_8888 };
+    SrcoverBuilder_F32(Fmt srcFmt = Fmt::RGBA_8888,
+                       Fmt dstFmt = Fmt::RGBA_8888);
+};
+
+struct SrcoverBuilder_I32_Naive : public skvm::Builder {
+    SrcoverBuilder_I32_Naive();  // 8888 over 8888
+};
+
+struct SrcoverBuilder_I32 : public skvm::Builder {
+    SrcoverBuilder_I32();  // 8888 over 8888
+};
+
+struct SrcoverBuilder_I32_SWAR : public skvm::Builder {
+    SrcoverBuilder_I32_SWAR();  // 8888 over 8888
+};
+
+#endif//SkVMBuilders_DEFINED
diff --git a/src/third_party/skia/tools/Stats.h b/src/third_party/skia/tools/Stats.h
index 557a2a5..526198e 100644
--- a/src/third_party/skia/tools/Stats.h
+++ b/src/third_party/skia/tools/Stats.h
@@ -8,8 +8,9 @@
 #ifndef Stats_DEFINED
 #define Stats_DEFINED
 
-#include "SkString.h"
-#include "SkTSort.h"
+#include "include/core/SkString.h"
+#include "include/private/SkFloatingPoint.h"
+#include "src/core/SkTSort.h"
 
 #ifdef SK_BUILD_FOR_WIN
     static const char* kBars[] = { ".", "o", "O" };
@@ -18,7 +19,7 @@
 #endif
 
 struct Stats {
-    Stats(const SkTArray<double>& samples) {
+    Stats(const SkTArray<double>& samples, bool want_plot) {
         int n = samples.count();
         if (!n) {
             min = max = mean = var = median = 0;
@@ -42,7 +43,7 @@
         for (int i = 0 ; i < n; i++) {
             err += (samples[i] - mean) * (samples[i] - mean);
         }
-        var = err / (n-1);
+        var = sk_ieee_double_divide(err, n-1);
 
         SkAutoTMalloc<double> sorted(n);
         memcpy(sorted.get(), samples.begin(), n * sizeof(double));
@@ -50,7 +51,7 @@
         median = sorted[n/2];
 
         // Normalize samples to [min, max] in as many quanta as we have distinct bars to print.
-        for (int i = 0; i < n; i++) {
+        for (int i = 0; want_plot && i < n; i++) {
             if (min == max) {
                 // All samples are the same value.  Don't divide by zero.
                 plot.append(kBars[0]);
diff --git a/src/third_party/skia/tools/ThermalManager.cpp b/src/third_party/skia/tools/ThermalManager.cpp
deleted file mode 100644
index e0c7c44..0000000
--- a/src/third_party/skia/tools/ThermalManager.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "ThermalManager.h"
-
-#include "SkOSFile.h"
-
-#include <stdio.h>
-
-#ifndef SK_BUILD_FOR_WIN32
-    #include <unistd.h>
-#endif
-
-#ifdef THERMAL_MANAGER_SUPPORTED
-
-/*
- * ThermalManager is completely dependent on sysfs to monitor thermal temperatures.  In sysfs
- * thermal management is controlled by a number of thermal zones.  They are laid out as follows:
- * /sys/class/thermal/thermal_zoneN where N is the number of the thermal zone starting at 0.
- *
- * Inside each thermal_zone folder is a file called 'temp,' which has the current temperature
- * reading from the sensor in that zone, as well as 0 or more files called 'trip_point_N_temp.'
- *
- * When the reading in temp is greater than one of the numbers in the trip_point files, then the
- * kernel will take some kind of action.  This is all documented online.
- *
- * In any case, the goal of this class is to sleep right before a trip point is about to be
- * triggered, thus naturally cooling the system and preventing thermal throttling.
- */
-
-ThermalManager::ThermalManager(int32_t threshold, uint32_t sleepIntervalMs, uint32_t timeoutMs)
-    : fSleepIntervalMs(sleepIntervalMs)
-    , fTimeoutMs(timeoutMs) {
-    static const char* kThermalZonePath = "/sys/class/thermal/";
-    SkOSFile::Iter it(kThermalZonePath);
-    SkString path;
-    while (it.next(&path, true)) {
-        if (!path.contains("thermal_zone")) {
-            continue;
-        }
-
-        SkString fullPath(kThermalZonePath);
-        fullPath.append(path);
-        SkOSFile::Iter thermalZoneIt(fullPath.c_str());
-
-        SkString filename;
-        while (thermalZoneIt.next(&filename)) {
-            if (!(filename.contains("trip_point") && filename.contains("temp"))) {
-                continue;
-            }
-
-            fTripPoints.push_back(TripPoint(fullPath, filename, threshold));
-        }
-    }
-}
-
-bool ThermalManager::coolOffIfNecessary() {
-    uint32_t i = 0, totalTimeSleptMs = 0;
-    while (i < (uint32_t)fTripPoints.count() && totalTimeSleptMs < fTimeoutMs) {
-        if (fTripPoints[i].willTrip()) {
-            sleep(fSleepIntervalMs);
-            totalTimeSleptMs += fSleepIntervalMs;
-        } else {
-            i++;
-        }
-    }
-
-    return totalTimeSleptMs < fTimeoutMs;
-}
-
-int32_t ThermalManager::OpenFileAndReadInt32(const char* path) {
-    FILE* tempFile = fopen(path, "r");
-    SkASSERT(tempFile);
-    int32_t value;
-    int ret = fscanf(tempFile, "%d", &value);
-    if (!ret) {
-        SkDebugf("Could not read temperature\n");
-        SkASSERT(false);
-    }
-
-    fclose(tempFile);
-    return value;
-}
-
-ThermalManager::TripPoint::TripPoint(SkString thermalZoneRoot, SkString pointName,
-                                     int32_t threshold)
-    : fThermalZoneRoot(thermalZoneRoot)
-    , fPointName(pointName) {
-    SkString fullPath(thermalZoneRoot);
-    fullPath.appendf("/%s", pointName.c_str());
-    fPoint = OpenFileAndReadInt32(fullPath.c_str());
-    fBase = GetTemp(fThermalZoneRoot);
-    fThreshold = threshold;
-    fDisabled = fBase + fThreshold >= fPoint;  // We disable any trip point which start off
-                                               // triggered
-}
-
-bool ThermalManager::TripPoint::willTrip() {
-    int32_t currentTemp = GetTemp(fThermalZoneRoot);
-    bool wouldTrip = !fDisabled && currentTemp + fThreshold >= fPoint;
-
-    if (wouldTrip) {
-        SkDebugf("%s/%s would trip {%d,%d,%d,%d}\n", fThermalZoneRoot.c_str(),
-                 fPointName.c_str(), fBase, currentTemp, fPoint, fThreshold);
-    }
-    return wouldTrip;
-}
-
-#endif
diff --git a/src/third_party/skia/tools/ThermalManager.h b/src/third_party/skia/tools/ThermalManager.h
deleted file mode 100644
index 747cf52..0000000
--- a/src/third_party/skia/tools/ThermalManager.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef ThermalManager_DEFINED
-#define ThermalManager_DEFINED
-
-#include "../private/SkTArray.h"
-#include "SkString.h"
-
-#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
-#    define THERMAL_MANAGER_SUPPORTED
-#endif
-
-#ifdef THERMAL_MANAGER_SUPPORTED
-
-/*
- * This simple class monitors the thermal part of sysfs to ensure we don't trigger thermal events
- */
-
-class ThermalManager {
-public:
-    ThermalManager(int32_t threshold, uint32_t sleepIntervalMs, uint32_t timeoutMs);
-
-    bool coolOffIfNecessary();
-
-private:
-    static int32_t OpenFileAndReadInt32(const char* path);
-
-    // current temperature can be read from /thermalZonePath/temp
-    static int32_t GetTemp(SkString thermalZonePath) {
-        SkString temperatureFilePath(thermalZonePath);
-        temperatureFilePath.appendf("/temp");
-        return OpenFileAndReadInt32(temperatureFilePath.c_str());
-    }
-
-    struct TripPoint {
-        TripPoint(SkString thermalZoneRoot, SkString pointName, int32_t threshold);
-
-        bool willTrip();
-
-        SkString fThermalZoneRoot;
-        SkString fPointName;
-        int32_t fBase;
-        int32_t fPoint;
-        int32_t fThreshold;
-
-        // Certain trip points seem to start tripped.  For example, I have seen trip points of 0 or
-        // negative numbers.
-        bool fDisabled;
-    };
-
-    SkTArray<TripPoint> fTripPoints;
-    uint32_t fSleepIntervalMs;
-    uint32_t fTimeoutMs;
-};
-#endif
-#endif
diff --git a/src/third_party/skia/tools/ToolUtils.cpp b/src/third_party/skia/tools/ToolUtils.cpp
new file mode 100644
index 0000000..99e25ee
--- /dev/null
+++ b/src/third_party/skia/tools/ToolUtils.cpp
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkBlendMode.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColorPriv.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkPixelRef.h"
+#include "include/core/SkPixmap.h"
+#include "include/core/SkPoint3.h"
+#include "include/core/SkRRect.h"
+#include "include/core/SkShader.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkTextBlob.h"
+#include "include/ports/SkTypeface_win.h"
+#include "include/private/SkColorData.h"
+#include "include/private/SkFloatingPoint.h"
+#include "src/core/SkFontMgrPriv.h"
+#include "src/core/SkFontPriv.h"
+#include "tools/ToolUtils.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/fonts/TestFontMgr.h"
+
+#include <cmath>
+#include <cstring>
+#include <memory>
+
+namespace ToolUtils {
+
+const char* alphatype_name(SkAlphaType at) {
+    switch (at) {
+        case kUnknown_SkAlphaType:  return "Unknown";
+        case kOpaque_SkAlphaType:   return "Opaque";
+        case kPremul_SkAlphaType:   return "Premul";
+        case kUnpremul_SkAlphaType: return "Unpremul";
+    }
+    SkASSERT(false);
+    return "unexpected alphatype";
+}
+
+const char* colortype_name(SkColorType ct) {
+    switch (ct) {
+        case kUnknown_SkColorType:            return "Unknown";
+        case kAlpha_8_SkColorType:            return "Alpha_8";
+        case kA16_unorm_SkColorType:          return "Alpha_16";
+        case kA16_float_SkColorType:          return "A16_float";
+        case kRGB_565_SkColorType:            return "RGB_565";
+        case kARGB_4444_SkColorType:          return "ARGB_4444";
+        case kRGBA_8888_SkColorType:          return "RGBA_8888";
+        case kRGB_888x_SkColorType:           return "RGB_888x";
+        case kBGRA_8888_SkColorType:          return "BGRA_8888";
+        case kRGBA_1010102_SkColorType:       return "RGBA_1010102";
+        case kRGB_101010x_SkColorType:        return "RGB_101010x";
+        case kGray_8_SkColorType:             return "Gray_8";
+        case kRGBA_F16Norm_SkColorType:       return "RGBA_F16Norm";
+        case kRGBA_F16_SkColorType:           return "RGBA_F16";
+        case kRGBA_F32_SkColorType:           return "RGBA_F32";
+        case kR8G8_unorm_SkColorType:         return "R8G8_unorm";
+        case kR16G16_unorm_SkColorType:       return "R16G16_unorm";
+        case kR16G16_float_SkColorType:       return "R16G16_float";
+        case kR16G16B16A16_unorm_SkColorType: return "R16G16B16A16_unorm";
+    }
+    SkASSERT(false);
+    return "unexpected colortype";
+}
+
+const char* colortype_depth(SkColorType ct) {
+    switch (ct) {
+        case kUnknown_SkColorType:            return "Unknown";
+        case kAlpha_8_SkColorType:            return "A8";
+        case kA16_unorm_SkColorType:          return "A16";
+        case kA16_float_SkColorType:          return "AF16";
+        case kRGB_565_SkColorType:            return "565";
+        case kARGB_4444_SkColorType:          return "4444";
+        case kRGBA_8888_SkColorType:          return "8888";
+        case kRGB_888x_SkColorType:           return "888";
+        case kBGRA_8888_SkColorType:          return "8888";
+        case kRGBA_1010102_SkColorType:       return "1010102";
+        case kRGB_101010x_SkColorType:        return "101010";
+        case kGray_8_SkColorType:             return "G8";
+        case kRGBA_F16Norm_SkColorType:       return "F16Norm";  // TODO: "F16"?
+        case kRGBA_F16_SkColorType:           return "F16";
+        case kRGBA_F32_SkColorType:           return "F32";
+        case kR8G8_unorm_SkColorType:         return "88";
+        case kR16G16_unorm_SkColorType:       return "1616";
+        case kR16G16_float_SkColorType:       return "F16F16";
+        case kR16G16B16A16_unorm_SkColorType: return "16161616";
+    }
+    SkASSERT(false);
+    return "unexpected colortype";
+}
+
+const char* tilemode_name(SkTileMode mode) {
+    switch (mode) {
+        case SkTileMode::kClamp:  return "clamp";
+        case SkTileMode::kRepeat: return "repeat";
+        case SkTileMode::kMirror: return "mirror";
+        case SkTileMode::kDecal:  return "decal";
+    }
+    SkASSERT(false);
+    return "unexpected tilemode";
+}
+
+SkColor color_to_565(SkColor color) {
+    // Not a good idea to use this function for greyscale colors...
+    // it will add an obvious purple or green tint.
+    SkASSERT(SkColorGetR(color) != SkColorGetG(color) || SkColorGetR(color) != SkColorGetB(color) ||
+             SkColorGetG(color) != SkColorGetB(color));
+
+    SkPMColor pmColor = SkPreMultiplyColor(color);
+    U16CPU    color16 = SkPixel32ToPixel16(pmColor);
+    return SkPixel16ToColor(color16);
+}
+
+sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size) {
+    SkBitmap bm;
+    bm.allocPixels(SkImageInfo::MakeS32(2 * size, 2 * size, kPremul_SkAlphaType));
+    bm.eraseColor(c1);
+    bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
+    bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
+    return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat);
+}
+
+SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) {
+    SkBitmap bitmap;
+    bitmap.allocPixels(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
+    SkCanvas canvas(bitmap);
+
+    ToolUtils::draw_checkerboard(&canvas, c1, c2, checkSize);
+    return bitmap;
+}
+
+void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) {
+    SkPaint paint;
+    paint.setShader(create_checkerboard_shader(c1, c2, size));
+    paint.setBlendMode(SkBlendMode::kSrc);
+    canvas->drawPaint(paint);
+}
+
+SkBitmap
+create_string_bitmap(int w, int h, SkColor c, int x, int y, int textSize, const char* str) {
+    SkBitmap bitmap;
+    bitmap.allocN32Pixels(w, h);
+    SkCanvas canvas(bitmap);
+
+    SkPaint paint;
+    paint.setColor(c);
+
+    SkFont font(ToolUtils::create_portable_typeface(), textSize);
+
+    canvas.clear(0x00000000);
+    canvas.drawSimpleText(str,
+                          strlen(str),
+                          SkTextEncoding::kUTF8,
+                          SkIntToScalar(x),
+                          SkIntToScalar(y),
+                          font,
+                          paint);
+
+    // Tag data as sRGB (without doing any color space conversion). Color-space aware configs
+    // will process this correctly but legacy configs will render as if this returned N32.
+    SkBitmap result;
+    result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
+    result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0);
+    return result;
+}
+
+void add_to_text_blob_w_len(SkTextBlobBuilder* builder,
+                            const char*        text,
+                            size_t             len,
+                            SkTextEncoding     encoding,
+                            const SkFont&      font,
+                            SkScalar           x,
+                            SkScalar           y) {
+    int  count = font.countText(text, len, encoding);
+    auto run   = builder->allocRun(font, count, x, y);
+    font.textToGlyphs(text, len, encoding, run.glyphs, count);
+}
+
+void add_to_text_blob(SkTextBlobBuilder* builder,
+                      const char*        text,
+                      const SkFont&      font,
+                      SkScalar           x,
+                      SkScalar           y) {
+    add_to_text_blob_w_len(builder, text, strlen(text), SkTextEncoding::kUTF8, font, x, y);
+}
+
+void get_text_path(const SkFont&  font,
+                   const void*    text,
+                   size_t         length,
+                   SkTextEncoding encoding,
+                   SkPath*        dst,
+                   const SkPoint  pos[]) {
+    SkAutoToGlyphs        atg(font, text, length, encoding);
+    const int             count = atg.count();
+    SkAutoTArray<SkPoint> computedPos;
+    if (pos == nullptr) {
+        computedPos.reset(count);
+        font.getPos(atg.glyphs(), count, &computedPos[0]);
+        pos = computedPos.get();
+    }
+
+    struct Rec {
+        SkPath*        fDst;
+        const SkPoint* fPos;
+    } rec = {dst, pos};
+    font.getPaths(atg.glyphs(),
+                  atg.count(),
+                  [](const SkPath* src, const SkMatrix& mx, void* ctx) {
+                      Rec* rec = (Rec*)ctx;
+                      if (src) {
+                          SkMatrix tmp(mx);
+                          tmp.postTranslate(rec->fPos->fX, rec->fPos->fY);
+                          rec->fDst->addPath(*src, tmp);
+                      }
+                      rec->fPos += 1;
+                  },
+                  &rec);
+}
+
+SkPath make_star(const SkRect& bounds, int numPts, int step) {
+    SkASSERT(numPts != step);
+    SkPath path;
+    path.setFillType(SkPath::kEvenOdd_FillType);
+    path.moveTo(0, -1);
+    for (int i = 1; i < numPts; ++i) {
+        int      idx   = i * step % numPts;
+        SkScalar theta = idx * 2 * SK_ScalarPI / numPts + SK_ScalarPI / 2;
+        SkScalar x     = SkScalarCos(theta);
+        SkScalar y     = -SkScalarSin(theta);
+        path.lineTo(x, y);
+    }
+    path.transform(SkMatrix::MakeRectToRect(path.getBounds(), bounds, SkMatrix::kFill_ScaleToFit));
+    return path;
+}
+
+static inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) {
+    SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
+    unsigned char r      = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255);
+    unsigned char g      = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
+    unsigned char b      = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255);
+    *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
+}
+
+void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) {
+    const SkPoint center =
+            SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
+    const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f);
+
+    SkVector3 norm;
+
+    for (int y = dst.fTop; y < dst.fBottom; ++y) {
+        for (int x = dst.fLeft; x < dst.fRight; ++x) {
+            norm.fX = (x + 0.5f - center.fX) / halfSize.fX;
+            norm.fY = (y + 0.5f - center.fY) / halfSize.fY;
+
+            SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY;
+            if (tmp >= 1.0f) {
+                norm.set(0.0f, 0.0f, 1.0f);
+            } else {
+                norm.fZ = sqrtf(1.0f - tmp);
+            }
+
+            norm_to_rgb(bm, x, y, norm);
+        }
+    }
+}
+
+void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) {
+    const SkPoint center =
+            SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
+
+    SkIRect inner = dst;
+    inner.inset(dst.width() / 4, dst.height() / 4);
+
+    SkPoint3       norm;
+    const SkPoint3 left  = SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
+    const SkPoint3 up    = SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
+    const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
+    const SkPoint3 down  = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
+
+    for (int y = dst.fTop; y < dst.fBottom; ++y) {
+        for (int x = dst.fLeft; x < dst.fRight; ++x) {
+            if (inner.contains(x, y)) {
+                norm.set(0.0f, 0.0f, 1.0f);
+            } else {
+                SkScalar locX = x + 0.5f - center.fX;
+                SkScalar locY = y + 0.5f - center.fY;
+
+                if (locX >= 0.0f) {
+                    if (locY > 0.0f) {
+                        norm = locX >= locY ? right : down;  // LR corner
+                    } else {
+                        norm = locX > -locY ? right : up;  // UR corner
+                    }
+                } else {
+                    if (locY > 0.0f) {
+                        norm = -locX > locY ? left : down;  // LL corner
+                    } else {
+                        norm = locX > locY ? up : left;  // UL corner
+                    }
+                }
+            }
+
+            norm_to_rgb(bm, x, y, norm);
+        }
+    }
+}
+
+void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) {
+    const SkPoint center =
+            SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
+
+    static const SkScalar k1OverRoot3 = 0.5773502692f;
+
+    SkPoint3       norm;
+    const SkPoint3 leftUp  = SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3);
+    const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3, -k1OverRoot3, k1OverRoot3);
+    const SkPoint3 down    = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
+
+    for (int y = dst.fTop; y < dst.fBottom; ++y) {
+        for (int x = dst.fLeft; x < dst.fRight; ++x) {
+            SkScalar locX = x + 0.5f - center.fX;
+            SkScalar locY = y + 0.5f - center.fY;
+
+            if (locX >= 0.0f) {
+                if (locY > 0.0f) {
+                    norm = locX >= locY ? rightUp : down;  // LR corner
+                } else {
+                    norm = rightUp;
+                }
+            } else {
+                if (locY > 0.0f) {
+                    norm = -locX > locY ? leftUp : down;  // LL corner
+                } else {
+                    norm = leftUp;
+                }
+            }
+
+            norm_to_rgb(bm, x, y, norm);
+        }
+    }
+}
+
+#if !defined(__clang__) && defined(_MSC_VER)
+// MSVC takes ~2 minutes to compile this function with optimization.
+// We don't really care to wait that long for this function.
+#pragma optimize("", off)
+#endif
+void make_big_path(SkPath& path) {
+#include "BigPathBench.inc"  // IWYU pragma: keep
+}
+
+bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
+    SkPixmap srcPM;
+    if (!src.peekPixels(&srcPM)) {
+        return false;
+    }
+
+    SkBitmap    tmpDst;
+    SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
+    if (!tmpDst.setInfo(dstInfo)) {
+        return false;
+    }
+
+    if (!tmpDst.tryAllocPixels()) {
+        return false;
+    }
+
+    SkPixmap dstPM;
+    if (!tmpDst.peekPixels(&dstPM)) {
+        return false;
+    }
+
+    if (!srcPM.readPixels(dstPM)) {
+        return false;
+    }
+
+    dst->swap(tmpDst);
+    return true;
+}
+
+void copy_to_g8(SkBitmap* dst, const SkBitmap& src) {
+    SkASSERT(kBGRA_8888_SkColorType == src.colorType() ||
+             kRGBA_8888_SkColorType == src.colorType());
+
+    SkImageInfo grayInfo = src.info().makeColorType(kGray_8_SkColorType);
+    dst->allocPixels(grayInfo);
+    uint8_t*        dst8  = (uint8_t*)dst->getPixels();
+    const uint32_t* src32 = (const uint32_t*)src.getPixels();
+
+    const int  w      = src.width();
+    const int  h      = src.height();
+    const bool isBGRA = (kBGRA_8888_SkColorType == src.colorType());
+    for (int y = 0; y < h; ++y) {
+        if (isBGRA) {
+            // BGRA
+            for (int x = 0; x < w; ++x) {
+                uint32_t s = src32[x];
+                dst8[x]    = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF);
+            }
+        } else {
+            // RGBA
+            for (int x = 0; x < w; ++x) {
+                uint32_t s = src32[x];
+                dst8[x]    = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF);
+            }
+        }
+        src32 = (const uint32_t*)((const char*)src32 + src.rowBytes());
+        dst8 += dst->rowBytes();
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+bool equal_pixels(const SkPixmap& a, const SkPixmap& b) {
+    if (a.width() != b.width() || a.height() != b.height() || a.colorType() != b.colorType()) {
+        return false;
+    }
+
+    for (int y = 0; y < a.height(); ++y) {
+        const char* aptr = (const char*)a.addr(0, y);
+        const char* bptr = (const char*)b.addr(0, y);
+        if (memcmp(aptr, bptr, a.width() * a.info().bytesPerPixel())) {
+            return false;
+        }
+        aptr += a.rowBytes();
+        bptr += b.rowBytes();
+    }
+    return true;
+}
+
+bool equal_pixels(const SkBitmap& bm0, const SkBitmap& bm1) {
+    SkPixmap pm0, pm1;
+    return bm0.peekPixels(&pm0) && bm1.peekPixels(&pm1) && equal_pixels(pm0, pm1);
+}
+
+bool equal_pixels(const SkImage* a, const SkImage* b) {
+    // ensure that peekPixels will succeed
+    auto imga = a->makeRasterImage();
+    auto imgb = b->makeRasterImage();
+
+    SkPixmap pm0, pm1;
+    return imga->peekPixels(&pm0) && imgb->peekPixels(&pm1) && equal_pixels(pm0, pm1);
+}
+
+sk_sp<SkSurface> makeSurface(SkCanvas*             canvas,
+                             const SkImageInfo&    info,
+                             const SkSurfaceProps* props) {
+    auto surf = canvas->makeSurface(info, props);
+    if (!surf) {
+        surf = SkSurface::MakeRaster(info, props);
+    }
+    return surf;
+}
+
+static DEFINE_bool(nativeFonts, true,
+                   "If true, use native font manager and rendering. "
+                   "If false, fonts will draw as portably as possible.");
+#if defined(SK_BUILD_FOR_WIN)
+    static DEFINE_bool(gdi, false,
+                       "Use GDI instead of DirectWrite for font rendering.");
+#endif
+
+void SetDefaultFontMgr() {
+    if (!FLAGS_nativeFonts) {
+        gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr;
+    }
+#if defined(SK_BUILD_FOR_WIN)
+    if (FLAGS_gdi) {
+        gSkFontMgr_DefaultFactory = &SkFontMgr_New_GDI;
+    }
+#endif
+}
+
+}  // namespace ToolUtils
diff --git a/src/third_party/skia/tools/ToolUtils.h b/src/third_party/skia/tools/ToolUtils.h
new file mode 100644
index 0000000..5c3edfb
--- /dev/null
+++ b/src/third_party/skia/tools/ToolUtils.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ToolUtils_DEFINED
+#define ToolUtils_DEFINED
+
+#include "include/core/SkColor.h"
+#include "include/core/SkData.h"
+#include "include/core/SkEncodedImageFormat.h"
+#include "include/core/SkFont.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkFontTypes.h"
+#include "include/core/SkImageEncoder.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkPixmap.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkScalar.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkTypeface.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkTArray.h"
+#include "include/private/SkTDArray.h"
+#include "include/utils/SkRandom.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkFontStyle;
+class SkImage;
+class SkPath;
+class SkPixmap;
+class SkRRect;
+class SkShader;
+class SkSurface;
+class SkSurfaceProps;
+class SkTextBlobBuilder;
+class SkTypeface;
+
+namespace ToolUtils {
+
+const char* alphatype_name (SkAlphaType);
+const char* colortype_name (SkColorType);
+const char* colortype_depth(SkColorType);  // like colortype_name, but channel order agnostic
+const char* tilemode_name(SkTileMode);
+
+/**
+ * Map opaque colors from 8888 to 565.
+ */
+SkColor color_to_565(SkColor color);
+
+/* Return a color emoji typeface with planets to scale if available. */
+sk_sp<SkTypeface> planet_typeface();
+
+/** Return a color emoji typeface if available. */
+sk_sp<SkTypeface> emoji_typeface();
+
+/** Sample text for the emoji_typeface font. */
+const char* emoji_sample_text();
+
+/**
+ * Returns a platform-independent text renderer.
+ */
+sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style);
+
+static inline sk_sp<SkTypeface> create_portable_typeface() {
+    return create_portable_typeface(nullptr, SkFontStyle());
+}
+
+/**
+ *  Turn on portable (--nonativeFonts) or GDI font rendering (--gdi).
+ */
+void SetDefaultFontMgr();
+
+
+void get_text_path(const SkFont&,
+                   const void* text,
+                   size_t      length,
+                   SkTextEncoding,
+                   SkPath*,
+                   const SkPoint* positions = nullptr);
+
+/**
+ *  Returns true iff all of the pixels between the two images are identical.
+ *
+ *  If the configs differ, return false.
+ */
+bool equal_pixels(const SkPixmap&, const SkPixmap&);
+bool equal_pixels(const SkBitmap&, const SkBitmap&);
+bool equal_pixels(const SkImage* a, const SkImage* b);
+
+/** Returns a newly created CheckerboardShader. */
+sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size);
+
+/** Draw a checkerboard pattern in the current canvas, restricted to
+    the current clip, using SkXfermode::kSrc_Mode. */
+void draw_checkerboard(SkCanvas* canvas, SkColor color1, SkColor color2, int checkSize);
+
+/** Make it easier to create a bitmap-based checkerboard */
+SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize);
+
+/** A default checkerboard. */
+inline void draw_checkerboard(SkCanvas* canvas) {
+    ToolUtils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8);
+}
+
+SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y, int textSize, const char* str);
+
+// If the canvas does't make a surface (e.g. recording), make a raster surface
+sk_sp<SkSurface> makeSurface(SkCanvas*, const SkImageInfo&, const SkSurfaceProps* = nullptr);
+
+// A helper for inserting a drawtext call into a SkTextBlobBuilder
+void add_to_text_blob_w_len(SkTextBlobBuilder*,
+                            const char* text,
+                            size_t      len,
+                            SkTextEncoding,
+                            const SkFont&,
+                            SkScalar x,
+                            SkScalar y);
+
+void add_to_text_blob(SkTextBlobBuilder*, const char* text, const SkFont&, SkScalar x, SkScalar y);
+
+// Constructs a star by walking a 'numPts'-sided regular polygon with even/odd fill:
+//
+//   moveTo(pts[0]);
+//   lineTo(pts[step % numPts]);
+//   ...
+//   lineTo(pts[(step * (N - 1)) % numPts]);
+//
+// numPts=5, step=2 will produce a classic five-point star.
+//
+// numPts and step must be co-prime.
+SkPath make_star(const SkRect& bounds, int numPts = 5, int step = 2);
+
+void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst);
+
+void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst);
+
+void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst);
+
+void make_big_path(SkPath& path);
+
+// A helper object to test the topological sorting code (TopoSortBench.cpp & TopoSortTest.cpp)
+class TopoTestNode : public SkRefCnt {
+public:
+    TopoTestNode(int id) : fID(id), fOutputPos(-1), fTempMark(false) {}
+
+    void dependsOn(TopoTestNode* src) { *fDependencies.append() = src; }
+
+    int  id() const { return fID; }
+    void reset() { fOutputPos = -1; }
+
+    int outputPos() const { return fOutputPos; }
+
+    // check that the topological sort is valid for this node
+    bool check() {
+        if (-1 == fOutputPos) {
+            return false;
+        }
+
+        for (int i = 0; i < fDependencies.count(); ++i) {
+            if (-1 == fDependencies[i]->outputPos()) {
+                return false;
+            }
+            // This node should've been output after all the nodes on which it depends
+            if (fOutputPos < fDependencies[i]->outputPos()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    // The following 7 methods are needed by the topological sort
+    static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; }
+    static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; }
+    static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; }
+    static void Output(TopoTestNode* node, int outputPos) {
+        SkASSERT(-1 != outputPos);
+        node->fOutputPos = outputPos;
+    }
+    static bool          WasOutput(TopoTestNode* node) { return (-1 != node->fOutputPos); }
+    static int           NumDependencies(TopoTestNode* node) { return node->fDependencies.count(); }
+    static TopoTestNode* Dependency(TopoTestNode* node, int index) {
+        return node->fDependencies[index];
+    }
+
+    // Helper functions for TopoSortBench & TopoSortTest
+    static void AllocNodes(SkTArray<sk_sp<ToolUtils::TopoTestNode>>* graph, int num) {
+        graph->reserve(num);
+
+        for (int i = 0; i < num; ++i) {
+            graph->push_back(sk_sp<TopoTestNode>(new TopoTestNode(i)));
+        }
+    }
+
+#ifdef SK_DEBUG
+    static void Print(const SkTArray<TopoTestNode*>& graph) {
+        for (int i = 0; i < graph.count(); ++i) {
+            SkDebugf("%d, ", graph[i]->id());
+        }
+        SkDebugf("\n");
+    }
+#endif
+
+    // randomize the array
+    static void Shuffle(SkTArray<sk_sp<TopoTestNode>>* graph, SkRandom* rand) {
+        for (int i = graph->count() - 1; i > 0; --i) {
+            int swap = rand->nextU() % (i + 1);
+
+            (*graph)[i].swap((*graph)[swap]);
+        }
+    }
+
+private:
+    int  fID;
+    int  fOutputPos;
+    bool fTempMark;
+
+    SkTDArray<TopoTestNode*> fDependencies;
+};
+
+template <typename T>
+inline bool EncodeImageToFile(const char* path, const T& src, SkEncodedImageFormat f, int q) {
+    SkFILEWStream file(path);
+    return file.isValid() && SkEncodeImage(&file, src, f, q);
+}
+
+bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src);
+void copy_to_g8(SkBitmap* dst, const SkBitmap& src);
+
+class PixelIter {
+public:
+    PixelIter();
+    PixelIter(SkSurface* surf) {
+        SkPixmap pm;
+        if (!surf->peekPixels(&pm)) {
+            pm.reset();
+        }
+        this->reset(pm);
+    }
+
+    void reset(const SkPixmap& pm) {
+        fPM  = pm;
+        fLoc = {-1, 0};
+    }
+
+    void* next(SkIPoint* loc = nullptr) {
+        if (!fPM.addr()) {
+            return nullptr;
+        }
+        fLoc.fX += 1;
+        if (fLoc.fX >= fPM.width()) {
+            fLoc.fX = 0;
+            if (++fLoc.fY >= fPM.height()) {
+                this->setDone();
+                return nullptr;
+            }
+        }
+        if (loc) {
+            *loc = fLoc;
+        }
+        return fPM.writable_addr(fLoc.fX, fLoc.fY);
+    }
+
+    void setDone() { fPM.reset(); }
+
+private:
+    SkPixmap fPM;
+    SkIPoint fLoc;
+};
+
+}  // namespace ToolUtils
+
+#endif  // ToolUtils_DEFINED
diff --git a/src/third_party/skia/tools/UrlDataManager.cpp b/src/third_party/skia/tools/UrlDataManager.cpp
index a30d8ba..40d909f 100644
--- a/src/third_party/skia/tools/UrlDataManager.cpp
+++ b/src/third_party/skia/tools/UrlDataManager.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "UrlDataManager.h"
+#include "tools/UrlDataManager.h"
 
 bool operator==(const SkData& a, const SkData& b) {
     return a.equals(&b);
diff --git a/src/third_party/skia/tools/UrlDataManager.h b/src/third_party/skia/tools/UrlDataManager.h
index bae1dc7..d68b119 100644
--- a/src/third_party/skia/tools/UrlDataManager.h
+++ b/src/third_party/skia/tools/UrlDataManager.h
@@ -8,10 +8,10 @@
 #ifndef SkUrlDataManager_DEFINED
 #define SkUrlDataManager_DEFINED
 
-#include "SkData.h"
-#include "SkOpts.h"
-#include "SkString.h"
-#include "SkTDynamicHash.h"
+#include "include/core/SkData.h"
+#include "include/core/SkString.h"
+#include "src/core/SkOpts.h"
+#include "src/core/SkTDynamicHash.h"
 
 /*
  * A simple class which allows clients to add opaque data types, and returns a url where this data
diff --git a/src/third_party/skia/tools/add_codereview_message.py b/src/third_party/skia/tools/add_codereview_message.py
index 296a894..ea4afd8 100755
--- a/src/third_party/skia/tools/add_codereview_message.py
+++ b/src/third_party/skia/tools/add_codereview_message.py
@@ -39,10 +39,10 @@
           this url, or this could simply be the issue number.
       message: (string) message to add.
   """
-  # Passing None for the email and password will result in a prompt or
+  # Passing None for the email and auth_config will result in a prompt or
   # reuse of existing cached credentials.
-  my_rietveld = rietveld.Rietveld(RIETVELD_URL, email=None, password=None)
-  
+  my_rietveld = rietveld.Rietveld(RIETVELD_URL, email=None, auth_config=None)
+
   my_rietveld.add_comment(issue, message)
 
 
diff --git a/src/third_party/skia/tools/android/measure_fps.py b/src/third_party/skia/tools/android/measure_fps.py
new file mode 100644
index 0000000..7ec80dc
--- /dev/null
+++ b/src/third_party/skia/tools/android/measure_fps.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import optparse
+import re
+import subprocess
+import time
+
+
+def query_surfaceflinger_frame_count():
+  parcel = subprocess.Popen("adb shell service call SurfaceFlinger 1013",
+                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                            shell=True).communicate()[0]
+  if not parcel:
+    raise Exception("FAILED: adb shell service call SurfaceFlinger 1013")
+
+  framecount = re.search("Result: Parcel\(([a-f0-9]+) ", parcel)
+  if not framecount:
+    raise Exception("Unexpected result from SurfaceFlinger: " + parcel)
+
+  return int(framecount.group(1), 16)
+
+
+def main(interval):
+  startframe = query_surfaceflinger_frame_count()
+  starttime = time.time()
+
+  while True:
+    time.sleep(interval)
+
+    endframe = query_surfaceflinger_frame_count()
+    endtime = time.time()
+    fps = (endframe - startframe) / (endtime - starttime)
+    print "%.2f" % fps
+
+    startframe = endframe
+    starttime = endtime
+
+
+if __name__ == '__main__':
+  parser = optparse.OptionParser()
+  parser.add_option("-i", "--interval", type="int", default="2",
+                    help="Number of seconds to count frames.")
+  options, args = parser.parse_args()
+  main(options.interval)
+
diff --git a/src/third_party/skia/tools/android/upload_to_android.py b/src/third_party/skia/tools/android/upload_to_android.py
new file mode 100644
index 0000000..dba0c16
--- /dev/null
+++ b/src/third_party/skia/tools/android/upload_to_android.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+# Copyright (c) 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script that uploads the specified Skia Gerrit change to Android.
+
+This script does the following:
+* Downloads the repo tool.
+* Inits and checks out the bare-minimum required Android checkout.
+* Sets the required git config options in external/skia.
+* Cherry-picks the specified Skia patch.
+* Modifies the change subject to append a "Test:" line required for presubmits.
+* Uploads the Skia change to Android's Gerrit instance.
+
+After the change is uploaded to Android, developers can trigger TH and download
+binaries (if required) after runs complete.
+
+The script re-uses the workdir when it is run again. To start from a clean slate
+delete the workdir.
+
+Timings:
+* ~1m15s when using an empty/non-existent workdir for the first time.
+* ~15s when using a workdir previously populated by the script.
+
+Example usage:
+  $ python upload_to_android.py -w /repos/testing -c 44200
+"""
+
+import argparse
+import getpass
+import json
+import os
+import subprocess
+import stat
+import urllib2
+
+
+REPO_TOOL_URL = 'https://storage.googleapis.com/git-repo-downloads/repo'
+SKIA_PATH_IN_ANDROID = os.path.join('external', 'skia')
+ANDROID_REPO_URL = 'https://googleplex-android.googlesource.com'
+REPO_BRANCH_NAME = 'experiment'
+SKIA_GERRIT_INSTANCE = 'https://skia-review.googlesource.com'
+SK_USER_CONFIG_PATH = os.path.join('include', 'config', 'SkUserConfig.h')
+
+
+def get_change_details(change_num):
+  response = urllib2.urlopen('%s/changes/%s/detail?o=ALL_REVISIONS' % (
+                                 SKIA_GERRIT_INSTANCE, change_num), timeout=5)
+  content = response.read()
+  # Remove the first line which contains ")]}'\n".
+  return json.loads(content[5:])
+
+
+def init_work_dir(work_dir):
+  if not os.path.isdir(work_dir):
+    print 'Creating %s' % work_dir
+    os.makedirs(work_dir)
+
+  # Ensure the repo tool exists in the work_dir.
+  repo_dir = os.path.join(work_dir, 'bin')
+  repo_binary = os.path.join(repo_dir, 'repo')
+  if not os.path.isdir(repo_dir):
+    print 'Creating %s' % repo_dir
+    os.makedirs(repo_dir)
+  if not os.path.exists(repo_binary):
+    print 'Downloading %s from %s' % (repo_binary, REPO_TOOL_URL)
+    response = urllib2.urlopen(REPO_TOOL_URL, timeout=5)
+    content = response.read()
+    with open(repo_binary, 'w') as f:
+      f.write(content)
+    # Set executable bit.
+    st = os.stat(repo_binary)
+    os.chmod(repo_binary, st.st_mode | stat.S_IEXEC)
+
+  # Create android-repo directory in the work_dir.
+  android_dir = os.path.join(work_dir, 'android-repo')
+  if not os.path.isdir(android_dir):
+    print 'Creating %s' % android_dir
+    os.makedirs(android_dir)
+
+  print """
+
+About to run repo init. If it hangs asking you to run glogin then please:
+* Exit the script (ctrl-c).
+* Run 'glogin'.
+* Re-run the script.
+
+"""
+  os.chdir(android_dir)
+  subprocess.check_call(
+      '%s init -u %s/a/platform/manifest -g "all,-notdefault,-darwin" '
+      '-b master --depth=1'
+          % (repo_binary, ANDROID_REPO_URL), shell=True)
+
+  print 'Syncing the Android checkout at %s' % android_dir
+  subprocess.check_call('%s sync %s tools/repohooks -j 32 -c' % (
+                            repo_binary, SKIA_PATH_IN_ANDROID), shell=True)
+
+  # Set the necessary git config options.
+  os.chdir(SKIA_PATH_IN_ANDROID)
+  subprocess.check_call(
+      'git config remote.goog.review %s/' % ANDROID_REPO_URL, shell=True)
+  subprocess.check_call(
+      'git config review.%s/.autoupload true' % ANDROID_REPO_URL, shell=True)
+  subprocess.check_call(
+      'git config user.email %s@google.com' % getpass.getuser(), shell=True)
+
+  return repo_binary
+
+
+class Modifier:
+  def modify(self):
+    raise NotImplementedError
+  def get_user_msg(self):
+    raise NotImplementedError
+
+
+class FetchModifier(Modifier):
+  def __init__(self, change_num, debug):
+    self.change_num = change_num
+    self.debug = debug
+
+  def modify(self):
+    # Download and cherry-pick the patch.
+    change_details = get_change_details(self.change_num)
+    latest_patchset = len(change_details['revisions'])
+    mod = int(self.change_num) % 100
+    download_ref = 'refs/changes/%s/%s/%s' % (
+                       str(mod).zfill(2), self.change_num, latest_patchset)
+    subprocess.check_call(
+        'git fetch https://skia.googlesource.com/skia %s' % download_ref,
+        shell=True)
+    subprocess.check_call('git cherry-pick FETCH_HEAD', shell=True)
+
+    if self.debug:
+      # Add SK_DEBUG to SkUserConfig.h.
+      with open(SK_USER_CONFIG_PATH, 'a') as f:
+        f.write('#ifndef SK_DEBUG\n')
+        f.write('#define SK_DEBUG\n')
+        f.write('#endif//SK_DEBUG\n')
+      subprocess.check_call('git add %s' % SK_USER_CONFIG_PATH, shell=True)
+
+    # Amend the commit message to add a prefix that makes it clear that the
+    # change should not be submitted and a "Test:" line which is required by
+    # Android presubmit checks.
+    original_commit_message = change_details['subject']
+    new_commit_message = (
+        # Intentionally breaking up the below string because some presubmits
+        # complain about it.
+        '[DO ' + 'NOT ' + 'SUBMIT] %s\n\n'
+        'Test: Presubmit checks will test this change.' % (
+            original_commit_message))
+
+    subprocess.check_call('git commit --amend -m "%s"' % new_commit_message,
+                          shell=True)
+
+  def get_user_msg(self):
+    return """
+
+Open the above URL and trigger TH by checking 'Presubmit-Ready'.
+You can download binaries (if required) from the TH link after it completes.
+"""
+
+
+# Add a legacy flag if it doesn't exist, or remove it if it exists.
+class AndroidLegacyFlagModifier(Modifier):
+  def __init__(self, flag):
+    self.flag = flag
+    self.verb = "Unknown"
+
+  def modify(self):
+    flag_line = "  #define %s\n" % self.flag
+
+    config_file = os.path.join('include', 'config', 'SkUserConfigManual.h')
+
+    with open(config_file) as f:
+      lines = f.readlines()
+
+    if flag_line not in lines:
+      lines.insert(
+          lines.index("#endif // SkUserConfigManual_DEFINED\n"), flag_line)
+      verb = "Add"
+    else:
+      lines.remove(flag_line)
+      verb = "Remove"
+
+    with open(config_file, 'w') as f:
+      for line in lines:
+        f.write(line)
+
+    subprocess.check_call('git add %s' % config_file, shell=True)
+    message = '%s %s\n\nTest: Presubmit checks will test this change.' % (
+        verb, self.flag)
+
+    subprocess.check_call('git commit -m "%s"' % message, shell=True)
+
+  def get_user_msg(self):
+      return """
+
+  Please open the above URL to review and land the change.
+"""
+
+
+def upload_to_android(work_dir, modifier):
+  repo_binary = init_work_dir(work_dir)
+
+  # Create repo branch.
+  subprocess.check_call('%s start %s .' % (repo_binary, REPO_BRANCH_NAME),
+                        shell=True)
+  try:
+    modifier.modify()
+
+    # Upload to Android Gerrit.
+    subprocess.check_call('%s upload --verify' % repo_binary, shell=True)
+
+    print modifier.get_user_msg()
+  finally:
+    # Abandon repo branch.
+    subprocess.call('%s abandon %s' % (repo_binary, REPO_BRANCH_NAME),
+                    shell=True)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--work-dir', '-w', required=True,
+      help='Directory where an Android checkout will be created (if it does '
+           'not already exist). Note: ~1GB space will be used.')
+  parser.add_argument(
+      '--change-num', '-c', required=True,
+      help='The skia-rev Gerrit change number that should be patched into '
+           'Android.')
+  parser.add_argument(
+      '--debug', '-d', action='store_true', default=False,
+      help='Adds SK_DEBUG to SkUserConfig.h.')
+  args = parser.parse_args()
+  upload_to_android(args.work_dir, FetchModifier(args.change_num, args.debug))
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/third_party/skia/tools/build_workaround_header.py b/src/third_party/skia/tools/build_workaround_header.py
new file mode 100755
index 0000000..f1d45de
--- /dev/null
+++ b/src/third_party/skia/tools/build_workaround_header.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# Copyright (c) 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""code generator for gpu workaround definitions"""
+
+import os
+import os.path
+import sys
+from optparse import OptionParser
+
+_LICENSE = """// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"""
+
+_DO_NOT_EDIT_WARNING = ("// This file is auto-generated from " +
+                        os.path.basename(__file__) + "\n" +
+                        "// DO NOT EDIT!\n\n")
+
+def merge_files_into_workarounds(files):
+  workarounds = set()
+  for filename in files:
+    with open(filename, 'r') as f:
+      workarounds.update([workaround.strip() for workaround in f])
+  return sorted(list(workarounds))
+
+
+def write_header(filename, workarounds):
+  max_workaround_len = len(max(workarounds, key=len))
+
+  with open(filename, 'w') as f:
+    f.write(_LICENSE)
+    f.write(_DO_NOT_EDIT_WARNING)
+
+    indent = '  '
+    macro = 'GPU_OP'
+
+    # length of max string passed to write + 1
+    max_len = len(indent) + len(macro) + 1 + max_workaround_len + 1 + 1
+    write = lambda line: f.write(line + ' ' * (max_len - len(line)) + '\\\n')
+
+    write('#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)')
+    for w in workarounds:
+      write(indent + macro + '(' + w.upper() + ',')
+      write(indent + ' ' * (len(macro) + 1) + w + ')')
+
+    # one extra line to consume the the last \
+    f.write('// The End\n')
+
+
+def main(argv):
+  usage = "usage: %prog [options] file1 file2 file3 etc"
+  parser = OptionParser(usage=usage)
+  parser.add_option(
+      "--output-file",
+      dest="output_file",
+      default="gpu_driver_bug_workaround_autogen.h",
+      help="the name of the header file to write")
+
+  (options, _) = parser.parse_args(args=argv)
+
+  workarounds = merge_files_into_workarounds(parser.largs)
+  write_header(options.output_file, workarounds)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/src/third_party/skia/tools/calmbench/ab.py b/src/third_party/skia/tools/calmbench/ab.py
new file mode 100644
index 0000000..6a45fe4
--- /dev/null
+++ b/src/third_party/skia/tools/calmbench/ab.py
@@ -0,0 +1,407 @@
+#!/usr/bin/python
+# encoding: utf-8
+
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be found
+# in the LICENSE file.
+#
+# This is an A/B test utility script used by calmbench.py
+#
+# For each bench, we get a distribution of min_ms measurements from nanobench.
+# From that, we try to recover the 1/3 and 2/3 quantiles of the distribution.
+# If range (1/3 quantile, 2/3 quantile) is completely disjoint between A and B,
+# we report that as a regression.
+#
+# The more measurements we have for a bench, the more accurate our quantiles
+# are. However, taking more measurements is time consuming. Hence we'll prune
+# out benches and only take more measurements for benches whose current quantile
+# ranges are disjoint.
+#
+# P.S. The current script is brute forcely translated from a ruby script. So it
+# may be ugly...
+
+import re
+import os
+import sys
+import time
+import json
+import subprocess
+import shlex
+import multiprocessing
+import traceback
+from argparse import ArgumentParser
+from multiprocessing import Process
+from threading import Thread
+from threading import Lock
+from pdb import set_trace
+
+
+HELP = """
+\033[31mPlease call calmbench.py to drive this script if you're not doing so.
+This script is not supposed to be used by itself. (At least, it's not easy to
+use by itself. The calmbench bots may use this script directly.)
+\033[0m
+"""
+
+FACTOR  = 3     # lower/upper quantile factor
+DIFF_T  = 0.99  # different enough threshold
+TERM    = 10    # terminate after this no. of iterations without suspect changes
+MAXTRY  = 30    # max number of nanobench tries to narrow down suspects
+
+UNITS   = "ns µs ms s".split()
+
+
+timesLock = Lock()
+timesA  = {}
+timesB  = {}
+
+
+def parse_args():
+  parser = ArgumentParser(description=HELP)
+
+  parser.add_argument('outdir', type=str, help="output directory")
+  parser.add_argument('a', type=str, help="name of A")
+  parser.add_argument('b', type=str, help="name of B")
+  parser.add_argument('nano_a', type=str, help="path to A's nanobench binary")
+  parser.add_argument('nano_b', type=str, help="path to B's nanobench binary")
+  parser.add_argument('arg_a', type=str, help="args for A's nanobench run")
+  parser.add_argument('arg_b', type=str, help="args for B's nanobench run")
+  parser.add_argument('repeat', type=int, help="number of initial runs")
+  parser.add_argument('skip_b', type=str, help=("whether to skip running B"
+                                                " ('true' or 'false')"))
+  parser.add_argument('config', type=str, help="nanobenh config")
+  parser.add_argument('threads', type=int, help="number of threads to run")
+  parser.add_argument('noinit', type=str, help=("whether to skip running B"
+                                                " ('true' or 'false')"))
+
+  parser.add_argument('--concise', dest='concise', action="store_true",
+      help="If set, no verbose thread info will be printed.")
+  parser.set_defaults(concise=False)
+
+  # Additional args for bots
+  BHELP = "bot specific options"
+  parser.add_argument('--githash', type=str, default="", help=BHELP)
+  parser.add_argument('--keys', type=str, default=[], nargs='+', help=BHELP)
+
+  args = parser.parse_args()
+  args.skip_b = args.skip_b == "true"
+  args.noinit = args.noinit == "true"
+
+  if args.threads == -1:
+    args.threads = 1
+    if args.config in ["8888", "565"]: # multi-thread for CPU only
+        args.threads = max(1, multiprocessing.cpu_count() / 2)
+
+  return args
+
+def append_dict_sorted_array(dict_array, key, value):
+  if key not in dict_array:
+    dict_array[key] = []
+  dict_array[key].append(value)
+  dict_array[key].sort()
+
+
+def add_time(args, name, bench, t, unit):
+  normalized_t = t * 1000 ** UNITS.index(unit);
+  if name.startswith(args.a):
+    append_dict_sorted_array(timesA, bench, normalized_t)
+  else:
+    append_dict_sorted_array(timesB, bench, normalized_t)
+
+
+def append_times_from_file(args, name, filename):
+  with open(filename) as f:
+    lines = f.readlines()
+  for line in lines:
+    items = line.split()
+    if len(items) > 10:
+      bench = items[10]
+      matches = re.search("([+-]?\d*.?\d+)(s|ms|µs|ns)", items[3])
+      if (not matches or items[9] != args.config):
+        continue
+      time_num = matches.group(1)
+      time_unit = matches.group(2)
+      add_time(args, name, bench, float(time_num), time_unit)
+
+
+class ThreadWithException(Thread):
+  def __init__(self, target):
+    super(ThreadWithException, self).__init__(target = target)
+    self.exception = None
+
+  def run(self):
+    try:
+      self._Thread__target(*self._Thread__args, **self._Thread__kwargs)
+    except BaseException as e:
+      self.exception = e
+
+  def join(self, timeout=None):
+    super(ThreadWithException, self).join(timeout)
+
+
+class ThreadRunner:
+  """Simplest and stupidiest threaded executer."""
+  def __init__(self, args):
+    self.concise = args.concise
+    self.threads = []
+
+  def add(self, args, fn):
+    if len(self.threads) >= args.threads:
+      self.wait()
+    t = ThreadWithException(target = fn)
+    t.daemon = True
+    self.threads.append(t)
+    t.start()
+
+  def wait(self):
+    def spin():
+      i = 0
+      spinners = [".  ", ".. ", "..."]
+      while len(self.threads) > 0:
+        timesLock.acquire()
+        sys.stderr.write(
+            "\r" + spinners[i % len(spinners)] +
+            " (%d threads running)" % len(self.threads) +
+            "           \r" # spaces for erasing characters
+        )
+        timesLock.release()
+        time.sleep(0.5)
+        i += 1
+
+    if not self.concise:
+      ts = Thread(target = spin);
+      ts.start()
+
+    for t in self.threads:
+      t.join()
+
+    exceptions = []
+    for t in self.threads:
+      if t.exception:
+        exceptions.append(t.exception)
+
+    self.threads = []
+
+    if not self.concise:
+      ts.join()
+
+    if len(exceptions):
+      for exc in exceptions:
+        print exc
+      raise exceptions[0]
+
+
+def split_arg(arg):
+  raw = shlex.split(arg)
+  result = []
+  for r in raw:
+    if '~' in r:
+      result.append(os.path.expanduser(r))
+    else:
+      result.append(r)
+  return result
+
+
+def run(args, threadRunner, name, nano, arg, i):
+  def task():
+    file_i = "%s/%s.out%d" % (args.outdir, name, i)
+
+    should_run = not args.noinit and not (name == args.b and args.skip_b)
+    if i <= 0:
+      should_run = True # always run for suspects
+
+    if should_run:
+      if i > 0:
+        timesLock.acquire()
+        print "Init run %d for %s..." % (i, name)
+        timesLock.release()
+      subprocess.check_call(["touch", file_i])
+      with open(file_i, 'w') as f:
+        subprocess.check_call([nano] + split_arg(arg) +
+                              ["--config", args.config], stderr=f, stdout=f)
+
+    timesLock.acquire()
+    append_times_from_file(args, name, file_i)
+    timesLock.release()
+
+  threadRunner.add(args, task)
+
+
+def init_run(args):
+  threadRunner = ThreadRunner(args)
+  for i in range(1, max(args.repeat, args.threads / 2) + 1):
+    run(args, threadRunner, args.a, args.nano_a, args.arg_a, i)
+    run(args, threadRunner, args.b, args.nano_b, args.arg_b, i)
+  threadRunner.wait()
+
+
+def get_lower_upper(values):
+  i = max(0, (len(values) - 1) / FACTOR)
+  return values[i], values[-i - 1]
+
+
+def different_enough(lower1, upper2):
+  return upper2 < DIFF_T * lower1
+
+
+# TODO(liyuqian): we used this hacky criteria mainly because that I didn't have
+# time to study more rigorous statistical tests. We should adopt a more rigorous
+# test in the future.
+def get_suspects():
+  suspects = []
+  for bench in timesA.keys():
+    if bench not in timesB:
+      continue
+    lowerA, upperA = get_lower_upper(timesA[bench])
+    lowerB, upperB = get_lower_upper(timesB[bench])
+    if different_enough(lowerA, upperB) or different_enough(lowerB, upperA):
+      suspects.append(bench)
+  return suspects
+
+
+def process_bench_pattern(s):
+  if ".skp" in s: # skp bench won't match their exact names...
+    return "^\"" + s[0:(s.index(".skp") + 3)] + "\""
+  else:
+    return "^\"" + s + "\"$"
+
+
+def suspects_arg(suspects):
+  patterns = map(process_bench_pattern, suspects)
+  return " --match " + (" ".join(patterns))
+
+
+def median(array):
+  return array[len(array) / 2]
+
+
+def regression(bench):
+  a = median(timesA[bench])
+  b = median(timesB[bench])
+  if (a == 0): # bad bench, just return no regression
+    return 1
+  return b / a
+
+
+def percentage(x):
+  return (x - 1) * 100
+
+
+def format_r(r):
+  return ('%6.2f' % percentage(r)) + "%"
+
+
+def normalize_r(r):
+  if r > 1.0:
+    return r - 1.0
+  else:
+    return 1.0 - 1/r
+
+
+def test():
+  args = parse_args()
+
+  init_run(args)
+  last_unchanged_iter = 0
+  last_suspect_number = -1
+  tryCnt = 0
+  it = 0
+  while tryCnt < MAXTRY:
+    it += 1
+    suspects = get_suspects()
+    if len(suspects) != last_suspect_number:
+      last_suspect_number = len(suspects)
+      last_unchanged_iter = it
+    if (len(suspects) == 0 or it - last_unchanged_iter >= TERM):
+      break
+
+    print "Number of suspects at iteration %d: %d" % (it, len(suspects))
+    threadRunner = ThreadRunner(args)
+    for j in range(1, max(1, args.threads / 2) + 1):
+      run(args, threadRunner, args.a, args.nano_a,
+          args.arg_a + suspects_arg(suspects), -j)
+      run(args, threadRunner, args.b, args.nano_b,
+          args.arg_b + suspects_arg(suspects), -j)
+      tryCnt += 1
+    threadRunner.wait()
+
+  suspects = get_suspects()
+  if len(suspects) == 0:
+    print ("%s and %s does not seem to have significant " + \
+           "performance differences.") % (args.a, args.b)
+  else:
+    suspects.sort(key = regression)
+    print "%s (compared to %s) is likely" % (args.a, args.b)
+    for suspect in suspects:
+      r = regression(suspect)
+      if r < 1:
+        print "\033[31m  %s slower in %s\033[0m" % \
+                (format_r(1/r), suspect)
+      else:
+        print "\033[32m  %s faster in %s\033[0m" % \
+                (format_r(r), suspect)
+
+  with open("%s/bench_%s_%s.json" % (args.outdir, args.a, args.b), 'w') as f:
+    results = {}
+    for bench in timesA:
+      r = regression(bench) if bench in suspects else 1.0
+      results[bench] = {
+        args.config: {
+          "signed_regression": normalize_r(r),
+          "lower_quantile_ms": get_lower_upper(timesA[bench])[0] * 1e-6,
+          "upper_quantile_ms": get_lower_upper(timesA[bench])[1] * 1e-6,
+          "options": {
+            # TODO(liyuqian): let ab.py call nanobench with --outResultsFile so
+            # nanobench could generate the json for us that's exactly the same
+            # as that being used by perf bots. Currently, we cannot guarantee
+            # that bench is the name (e.g., bench may have additional resolution
+            # information appended after name).
+            "name": bench
+          }
+        }
+      }
+
+    output = {"results": results}
+    if args.githash:
+      output["gitHash"] = args.githash
+    if args.keys:
+      keys = {}
+      for i in range(len(args.keys) / 2):
+        keys[args.keys[i * 2]] = args.keys[i * 2 + 1]
+      output["key"] = keys
+    f.write(json.dumps(output, indent=4))
+    print ("\033[36mJSON results available in %s\033[0m" % f.name)
+
+  with open("%s/bench_%s_%s.csv" % (args.outdir, args.a, args.b), 'w') as out:
+    out.write(("bench, significant?, raw regresion, " +
+                   "%(A)s quantile (ns), %(B)s quantile (ns), " +
+                   "%(A)s (ns), %(B)s (ns)\n") % {'A': args.a, 'B': args.b})
+    for bench in suspects + timesA.keys():
+      if (bench not in timesA or bench not in timesB):
+        continue
+      ta = timesA[bench]
+      tb = timesB[bench]
+      out.write(
+          "%s, %s, %f, " % (bench, bench in suspects, regression(bench)) +
+          ' '.join(map(str, get_lower_upper(ta))) + ", " +
+          ' '.join(map(str, get_lower_upper(tb))) + ", " +
+          ("%s, %s\n" % (' '.join(map(str, ta)), ' '.join(map(str, tb))))
+      )
+    print (("\033[36m" +
+           "Compared %d benches. " +
+           "%d of them seem to be significantly differrent." +
+           "\033[0m") %
+           (len([x for x in timesA if x in timesB]), len(suspects)))
+    print ("\033[36mPlease see detailed bench results in %s\033[0m" %
+            out.name)
+
+
+if __name__ == "__main__":
+  try:
+    test()
+  except Exception as e:
+    print e
+    print HELP
+    traceback.print_exc()
+    raise e
diff --git a/src/third_party/skia/tools/calmbench/calmbench.py b/src/third_party/skia/tools/calmbench/calmbench.py
new file mode 100644
index 0000000..4bef485
--- /dev/null
+++ b/src/third_party/skia/tools/calmbench/calmbench.py
@@ -0,0 +1,216 @@
+#!/usr/bin/pyton
+
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import subprocess
+import multiprocessing
+
+from argparse import ArgumentParser
+
+
+README = """
+Simply run
+\033[36m
+    python {0} TEST_GIT_BRANCH
+\033[0m
+to see if TEST_GIT_BRANCH has performance regressions against master in 8888.
+
+To compare a specific config with svg and skp resources included, add --config
+and --extraarg option. For exampe,
+\033[36m
+    python {0} TEST_GIT_BRANCH --config gl \\
+        --extraarg "--svgs ~/Desktop/bots/svgs --skps ~/Desktop/bots/skps"
+\033[0m
+For more options, please see
+
+    python {0} --help
+""".format(__file__)
+
+
+CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
+AB_SCRIPT = "ab.py"
+
+
+def parse_args():
+  if len(sys.argv) <= 1 or sys.argv[1] == '-h' or sys.argv[1] == '--help':
+    print README
+
+  parser = ArgumentParser(
+    description='Noiselessly (hence calm) becnhmark a git branch against ' +
+                'another baseline branch (e.g., master) using multiple ' +
+                ' nanobench runs.'
+  )
+
+  default_threads = max(1, multiprocessing.cpu_count() / 2);
+  default_skiadir = os.path.normpath(CURRENT_DIR + "/../../")
+
+  config_help = (
+      'nanobench config; we currently support only one config '
+      'at a time (default: %(default)s)')
+  reps_help = (
+      'initial repititions of the nanobench run; this may be '
+      'overridden when we have many threads (default: %(default)s)')
+  extraarg_help = (
+      'nanobench args (example: --svgs ~/Desktop/bots/svgs --skps '
+      '~/Desktop/bots/skps)')
+  baseline_help = (
+      'baseline branch to compare against (default: %(default)s)')
+  basearg_help = (
+      'nanobench arg for the baseline branch; if not given, we use '
+      ' the same arg for both the test branch and the baseline branch')
+  threads_help = (
+      'number of threads to be used (default: %(default)s); '
+      'for GPU config, this will always be 1')
+  no_compile_help = (
+      'whether NOT to compile nanobench and copy it to WRITEDIR '
+      '(i.e., reuse previous nanobench compiled)')
+  skip_base_help = (
+      'whether NOT to run nanobench on baseline branch '
+      '(i.e., reuse previous baseline measurements)')
+  noinit_help = (
+      'whether to skip initial nanobench runs (default: %(default)s)')
+  branch_help = (
+      "the test branch to benchmark; if it's 'modified', we'll benchmark the "
+      "current modified code against 'git stash'.")
+
+  definitions = [
+    # argname, type, default value, help
+    ['--config',    str, '8888', config_help],
+    ['--skiadir',   str, default_skiadir, 'default: %(default)s'],
+    ['--ninjadir',  str, 'out/Release', 'default: %(default)s'],
+    ['--writedir',  str, '/var/tmp', 'default: %(default)s'],
+    ['--extraarg',  str, '', extraarg_help],
+    ['--baseline',  str, 'master', baseline_help],
+    ['--basearg',   str, '', basearg_help],
+    ['--reps',      int, 2, reps_help],
+    ['--threads',   int, default_threads, threads_help],
+  ]
+
+  for d in definitions:
+    parser.add_argument(d[0], type=d[1], default=d[2], help=d[3])
+
+  parser.add_argument('branch', type=str, help=branch_help)
+  parser.add_argument('--no-compile', dest='no_compile', action="store_true",
+      help=no_compile_help)
+  parser.add_argument('--skip-base', dest='skipbase', action="store_true",
+      help=skip_base_help)
+  parser.add_argument('--noinit', dest='noinit', action="store_true",
+      help=noinit_help)
+  parser.add_argument('--concise', dest='concise', action="store_true",
+      help="If set, no verbose thread info will be printed.")
+  parser.set_defaults(no_compile=False);
+  parser.set_defaults(skipbase=False);
+  parser.set_defaults(noinit=False);
+  parser.set_defaults(concise=False);
+
+  # Additional args for bots
+  BHELP = "bot specific options"
+  parser.add_argument('--githash', type=str, help=BHELP)
+  parser.add_argument('--keys', type=str, default=[], nargs='+', help=BHELP)
+
+  args = parser.parse_args()
+  if not args.basearg:
+    args.basearg = args.extraarg
+
+  return args
+
+
+def nano_path(args, branch):
+  return args.writedir + '/nanobench_' + branch
+
+
+def compile_branch(args, branch):
+  print "Compiling branch %s" % args.branch
+
+  commands = [
+    ['git', 'checkout', branch],
+    ['ninja', '-C', args.ninjadir, 'nanobench'],
+    ['cp', args.ninjadir + '/nanobench', nano_path(args, branch)]
+  ]
+  for command in commands:
+    subprocess.check_call(command, cwd=args.skiadir)
+
+
+def compile_modified(args):
+  print "Compiling modified code"
+  subprocess.check_call(
+      ['ninja', '-C', args.ninjadir, 'nanobench'], cwd=args.skiadir)
+  subprocess.check_call(
+      ['cp', args.ninjadir + '/nanobench', nano_path(args, args.branch)],
+      cwd=args.skiadir)
+
+  print "Compiling stashed code"
+  stash_output = subprocess.check_output(['git', 'stash'], cwd=args.skiadir)
+  if 'No local changes to save' in stash_output:
+    subprocess.check_call(['git', 'reset', 'HEAD^', '--soft'])
+    subprocess.check_call(['git', 'stash'])
+
+  subprocess.check_call(['gclient', 'sync'], cwd=args.skiadir)
+  subprocess.check_call(
+      ['ninja', '-C', args.ninjadir, 'nanobench'], cwd=args.skiadir)
+  subprocess.check_call(
+      ['cp', args.ninjadir + '/nanobench', nano_path(args, args.baseline)],
+      cwd=args.skiadir)
+  subprocess.check_call(['git', 'stash', 'pop'], cwd=args.skiadir)
+
+def compile_nanobench(args):
+  if args.branch == 'modified':
+    compile_modified(args)
+  else:
+    compile_branch(args, args.branch)
+    compile_branch(args, args.baseline)
+
+
+def main():
+  args = parse_args()
+
+  # copy in case that it will be gone after git branch switching
+  orig_ab_name = CURRENT_DIR + "/" + AB_SCRIPT
+  temp_ab_name = args.writedir + "/" + AB_SCRIPT
+  subprocess.check_call(['cp', orig_ab_name, temp_ab_name])
+
+  if not args.no_compile:
+    compile_nanobench(args)
+
+  command = [
+    'python',
+    temp_ab_name,
+    args.writedir,
+    args.branch + ("_A" if args.branch == args.baseline else ""),
+    args.baseline + ("_B" if args.branch == args.baseline else ""),
+    nano_path(args, args.branch),
+    nano_path(args, args.baseline),
+    args.extraarg,
+    args.basearg,
+    str(args.reps),
+    "true" if args.skipbase else "false",
+    args.config,
+    str(args.threads if args.config in ["8888", "565"] else 1),
+    "true" if args.noinit else "false"
+  ]
+
+  if args.githash:
+    command += ['--githash', args.githash]
+  if args.keys:
+    command += (['--keys'] + args.keys)
+
+  if args.concise:
+    command.append("--concise")
+
+  p = subprocess.Popen(command, cwd=args.skiadir)
+  try:
+    p.wait()
+  except KeyboardInterrupt:
+    try:
+      p.terminate()
+    except OSError as e:
+      print e
+
+
+if __name__ == "__main__":
+  main()
diff --git a/src/third_party/skia/tools/check-headers-self-sufficient b/src/third_party/skia/tools/check-headers-self-sufficient
index 9b676c1..8ecb76b 100755
--- a/src/third_party/skia/tools/check-headers-self-sufficient
+++ b/src/third_party/skia/tools/check-headers-self-sufficient
@@ -5,9 +5,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import fnmatch
 import multiprocessing
 import os
+import re
 import subprocess
 import sys
 
@@ -18,118 +18,55 @@
 Otherwise, test all checked-in headers except for those in the ignore list.
 '''
 
-public_header_args = [
-    '-Iinclude/core',
-    '-Iinclude/config',
-    '-Iinclude/android',
-    '-Iinclude/codec',
-    '-Iinclude/effects',
-    '-Iinclude/gpu',
-    '-Iinclude/gpu/gl',
-    '-Iinclude/pathops',
-    '-Iinclude/ports',
-    '-Iinclude/private',
-    '-Iinclude/svg',
-    '-Iinclude/utils',
-    '-Iinclude/utils/mac',
-    '-Iinclude/views',
-    '-Ithird_party/vulkan',
-]
+ignore = re.compile('|'.join([
+    r'debugger/QT/.*',
+    r'example/.*',
+    r'experimental/.*',
+    r'include/config/.*',
+    r'include/core/SkPostConfig\.h',
+    r'include/gpu/mtl/.*',
+    r'include/gpu/vk/.*',
+    r'include/ports/SkFontMgr_android\.h',
+    r'include/ports/SkFontMgr_fontconfig\.h',
+    r'include/ports/SkFontMgr_fuchsia\.h',
+    r'include/ports/SkTypeface_win\.h',
+    r'include/private/.*_impl\.h',
+    r'include/private/.*_neon\.h',
+    r'include/private/.*_sse\.h',
+    r'include/third_party/vulkan/.*',
+    r'include/utils/mac/SkCGUtils\.h',
+    r'include/views/SkOSWindow_.*\.h',
+    r'modules/.*',
+    r'platform_tools/.*',
+    r'src/c/sk_c_from_to\.h',
+    r'src/core/.*Template\.h',
+    r'src/core/SkBitmapProcState_.*\.h',
+    r'src/core/SkLinearBitmapPipeline\.h',
+    r'src/core/SkLinearBitmapPipeline_.*\.h',
+    r'src/gpu/mtl/.*',
+    r'src/gpu/vk/.*',
+    r'src/opts/.*_SSE2\.h',
+    r'src/opts/.*_SSSE3\.h',
+    r'src/opts/.*_neon\.h',
+    r'src/opts/.*_sse\.h',
+    r'src/opts/Sk4px_.*\.h',
+    r'src/ports/.*',
+    r'src/utils/.*_win\.h',
+    r'src/utils/win/.*',
+    r'src/views/.*',
+    r'third_party/.*',
+    r'tools/fiddle/.*',
+    r'tools/gpu/vk/.*',
+    r'tools/mdbviz/.*',
+    r'tools/sk_app/.*',
+    r'tools/viewer/.*',
+    ]))
 
-all_header_args = [
-    '-Iinclude/core',
-    '-Iinclude/config',
-    '-Iinclude/android',
-    '-Iinclude/c',
-    '-Iinclude/codec',
-    '-Iinclude/effects',
-    '-Iinclude/gpu',
-    '-Iinclude/gpu/gl',
-    '-Iinclude/pathops',
-    '-Iinclude/ports',
-    '-Iinclude/private',
-    '-Iinclude/svg',
-    '-Iinclude/utils',
-    '-Iinclude/utils/mac',
-    '-Iinclude/views',
-    '-Isrc/codec',
-    '-Isrc/core',
-    '-Isrc/effects',
-    '-Isrc/effects/gradients',
-    '-Isrc/fonts',
-    '-Isrc/gpu',
-    '-Isrc/image',
-    '-Isrc/images',
-    '-Isrc/lazy',
-    '-Isrc/opts',
-    '-Isrc/pathops',
-    '-Isrc/ports',
-    '-Isrc/sfnt',
-    '-Isrc/shaders',
-    '-Isrc/sksl',
-    '-Isrc/utils',
-    '-Isrc/utils/win',
-    '-Isrc/xml',
-    '-Igm',
-    '-Itests',
-    '-Itools',
-    '-Itools/debugger',
-    '-Itools/flags',
-    '-Itools/gpu',
-    '-Itools/timer',
-    '-Ithird_party/etc1',
-    '-Ithird_party/externals/jsoncpp/include',
-    '-Ithird_party/externals/libjpeg-turbo',
-    '-Ithird_party/externals/sfntly/cpp/src',
-    '-Ithird_party/externals/zlib',
-    '-Ithird_party/gif',
-    '-Ithird_party/vulkan',
-]
-
-ignore = [
-    '*/lex.*.h',
-    '*/osmesa_wrapper.h',
-    'debugger/QT/*',
-    'example/*',
-    'experimental/*',
-    'include/config/*',
-    'include/core/SkPostConfig.h',
-    'include/gpu/vk/*',
-    'include/ports/SkFontMgr_android.h',
-    'include/ports/SkFontMgr_fontconfig.h',
-    'include/ports/SkTypeface_win.h',
-    'include/private/*_impl.h',
-    'include/utils/mac/SkCGUtils.h',
-    'include/views/SkOSWindow_*.h',
-    'src/c/sk_c_from_to.h',
-    'src/core/*Template.h',
-    'src/core/SkBitmapProcState_*.h',
-    'src/core/SkFDot6Constants.h',
-    'src/core/SkLinearBitmapPipeline.h',
-    'src/core/SkLinearBitmapPipeline_*.h',
-    'src/core/SkUnPreMultiplyPriv.h',
-    'src/gpu/vk/*',
-    'src/opts/*_SSE2.h',
-    'src/opts/*_SSSE3.h',
-    'src/opts/*_neon.h',
-    'src/opts/*_sse.h',
-    'src/opts/Sk4px_*.h',
-    'src/ports/*',
-    'src/utils/*_win.h',
-    'src/utils/win/*',
-    'src/views/*',
-    'third_party/*',
-    'tools/fiddle/*',
-    'tools/viewer/*',
-]
 
 # test header for self-sufficiency and idempotency.
 # Returns a string containing errors, or None iff there are no errors.
 def compile_header(header):
-    args = ([]                 if fnmatch.fnmatch(header, 'include/c/*') else
-            public_header_args if fnmatch.fnmatch(header, 'include/*')   else
-            all_header_args)
-    cmd = ['c++', '--std=c++11'] + args + [ '-o', '/dev/null', '-c', '-x', 'c++', '-']
+    cmd = ['c++', '--std=c++14', '-I.', '-o', '/dev/null', '-c', '-x', 'c++', '-']
     proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
     proc.stdin.write('#include "%s"\n#include "%s"\n' % (header, header))
@@ -139,6 +76,7 @@
         return '\n\033[7m ERROR: %s \033[0m\n%s\n\n' % (header, errors)
     return None
 
+
 #     for h in headers:
 #         compile_header(h)
 # ...Except use a multiprocessing pool.
@@ -171,8 +109,7 @@
     else:
         os.chdir(skia_dir)
         paths = [path for path in subprocess.check_output(['git', 'ls-files']).splitlines()
-                 if path.endswith('.h')
-                 and not any(fnmatch.fnmatch(path, pattern) for pattern in ignore)]
+                 if path.endswith('.h') and not ignore.match(path)]
     compile_headers(paths)
 
 
diff --git a/src/third_party/skia/tools/chrome_fuzz.cpp b/src/third_party/skia/tools/chrome_fuzz.cpp
index fcc0db2..3ae775e 100644
--- a/src/third_party/skia/tools/chrome_fuzz.cpp
+++ b/src/third_party/skia/tools/chrome_fuzz.cpp
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "SkCanvas.h"
+#include "include/core/SkCanvas.h"
 #include "SkFlattenableSerialization.h"
-#include "SkImageFilter.h"
-#include "SkOSFile.h"
-#include "SkString.h"
+#include "include/core/SkImageFilter.h"
+#include "include/core/SkString.h"
+#include "src/core/SkOSFile.h"
 
 #include <stdio.h>
 
diff --git a/src/third_party/skia/tools/chrome_release_branch b/src/third_party/skia/tools/chrome_release_branch
new file mode 100755
index 0000000..8a6cffc
--- /dev/null
+++ b/src/third_party/skia/tools/chrome_release_branch
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+base_dir=$(dirname "$0")
+
+PYTHONDONTWRITEBYTECODE=1 exec python -u "$base_dir/chrome_release_branch.py" "$@"
diff --git a/src/third_party/skia/tools/chrome_release_branch.bat b/src/third_party/skia/tools/chrome_release_branch.bat
new file mode 100644
index 0000000..1f61fe2
--- /dev/null
+++ b/src/third_party/skia/tools/chrome_release_branch.bat
@@ -0,0 +1,7 @@
+@echo off
+:: Copyright 2019 Google Inc.
+::
+:: Use of this source code is governed by a BSD-style license that can be
+:: found in the LICENSE file.
+setlocal
+python -u "%~dp0\chrome_release_branch.py" %*
diff --git a/src/third_party/skia/tools/chrome_release_branch.py b/src/third_party/skia/tools/chrome_release_branch.py
new file mode 100644
index 0000000..d9085aa
--- /dev/null
+++ b/src/third_party/skia/tools/chrome_release_branch.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import os
+import re
+import subprocess
+import sys
+
+from infra import git
+from infra import go
+
+_TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
+_REPO_ROOT = os.path.realpath(os.path.join(_TOOLS_DIR, os.pardir))
+_INFRA_BOTS = os.path.join(_REPO_ROOT, 'infra', 'bots')
+sys.path.insert(0, _INFRA_BOTS)
+import git_utils
+
+
+REFS_HEADS_PREFIX = 'refs/heads/'
+CHROME_REF_PREFIX = REFS_HEADS_PREFIX + 'chrome/m'
+SK_MILESTONE_H = os.path.join('include', 'core', 'SkMilestone.h')
+SK_MILESTONE_TMPL = r'#define SK_MILESTONE %s'
+SK_MILESTONE_RE = SK_MILESTONE_TMPL % r'(\d+)'
+SKIA_REPO = 'https://skia.googlesource.com/skia.git'
+SUPPORTED_CHROME_BRANCHES = 2  # Per infra policy; see skbug.com/8940
+UPDATE_MILESTONE_COMMIT_MSG = '''Update Skia milestone to %d'''
+
+
+def get_current_milestone():
+  '''Read SkMilestone.h and parse out the current milestone.'''
+  sk_milestone = os.path.join(_REPO_ROOT, SK_MILESTONE_H)
+  with open(sk_milestone, 'r') as f:
+    contents = f.read()
+  for line in contents.splitlines():
+    m = re.match(SK_MILESTONE_RE, line)
+    if m:
+      return int(m.groups()[0])
+  print >> sys.stderr, (
+      'Failed to parse %s; has the format changed?' % SK_MILESTONE_H)
+  sys.exit(1)
+
+
+def create_new_branch(new_branch, branch_at):
+  '''Create a temporary checkout of the repo, create the new branch and push.'''
+  b = new_branch[len(REFS_HEADS_PREFIX):]
+  with git_utils.NewGitCheckout(SKIA_REPO, local=_REPO_ROOT):
+    git.git('checkout', '-b', b)
+    git.git('reset', '--hard', branch_at)
+    git.git('push', '--set-upstream', 'origin', b)
+
+
+def update_milestone(m):
+  '''Update SkMilestone.h to match the given milestone number.'''
+  with git_utils.NewGitCheckout(SKIA_REPO, local=_REPO_ROOT):
+    with git_utils.GitBranch(
+        'update_milestone', UPDATE_MILESTONE_COMMIT_MSG % m):
+      with open(SK_MILESTONE_H, 'r+') as f:
+        contents = re.sub(
+            SK_MILESTONE_RE, SK_MILESTONE_TMPL % str(m), f.read(), flags=re.M)
+        f.seek(0)
+        f.write(contents)
+        f.truncate()
+      git.git('diff')
+
+
+def update_infra_config(old_branch, new_branch):
+  '''Create a CL to add infra support for the new branch and remove the old.'''
+  owner = git.git('config', 'user.email').rstrip()
+  if not owner:
+    print >> sys.stderr, ('No configured git user; please run '
+                          '"git config user.email <your email>".')
+    sys.exit(1)
+  go.get(go.INFRA_GO+'/go/supported_branches/cmd/new-branch')
+  subprocess.check_call(['new-branch',
+                         '--branch', new_branch[len(REFS_HEADS_PREFIX):],
+                         '--delete', old_branch[len(REFS_HEADS_PREFIX):],
+                         '--owner', owner,
+                         '--exclude-trybots=chromium.*',
+                         '--exclude-trybots=.*Android_Framework.*'])
+
+
+def main():
+  if len(sys.argv) != 2 or '--help' in sys.argv or '-h' in sys.argv:
+    print >> sys.stderr, 'Usage: %s <commit hash for branch>' % sys.argv[0]
+    sys.exit(1)
+  go.check()
+  branch_at = sys.argv[1]
+  m = get_current_milestone()
+  new_branch = '%s%d' % (CHROME_REF_PREFIX, m)
+  old_branch = '%s%d' % (CHROME_REF_PREFIX, m-SUPPORTED_CHROME_BRANCHES)
+  print 'Creating branch %s and removing support (eg. CQ) for %s' % (
+      new_branch, old_branch)
+  create_new_branch(new_branch, branch_at)
+  update_milestone(m+1)
+  update_infra_config(old_branch, new_branch)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/third_party/skia/tools/clang-tidy.sh b/src/third_party/skia/tools/clang-tidy.sh
new file mode 100755
index 0000000..addbee3
--- /dev/null
+++ b/src/third_party/skia/tools/clang-tidy.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 2018 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+args=""
+src=""
+
+while [ "$1" ]; do
+    arg=$1
+
+    args="$args $1"
+    shift
+
+    if [ "$arg" == "-c" ]; then
+        src=$1
+
+        args="$args $1"
+        shift
+    fi
+done
+
+if [ "$src" ]; then
+    clang-tidy -quiet -header-filter='.*' -warnings-as-errors='*' $src -- $args
+fi
+exec clang++ $args
+
diff --git a/src/third_party/skia/tools/colorspaceinfo.cpp b/src/third_party/skia/tools/colorspaceinfo.cpp
deleted file mode 100644
index 0542d88..0000000
--- a/src/third_party/skia/tools/colorspaceinfo.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Resources.h"
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkCodec.h"
-#include "SkColorSpace_A2B.h"
-#include "SkColorSpace_XYZ.h"
-#include "SkColorSpacePriv.h"
-#include "SkCommandLineFlags.h"
-#include "SkICCPriv.h"
-#include "SkImageEncoder.h"
-#include "SkMatrix44.h"
-#include "SkOSFile.h"
-
-#include "sk_tool_utils.h"
-
-#include <sstream>
-#include <string>
-#include <vector>
-
-DEFINE_string(input, "input.png", "A path to the input image (or icc profile with --icc).");
-DEFINE_string(output, ".", "A path to the output image directory.");
-DEFINE_bool(icc, false, "Indicates that the input is an icc profile.");
-DEFINE_bool(sRGB_gamut, false, "Draws the sRGB gamut on the gamut visualization.");
-DEFINE_bool(adobeRGB, false, "Draws the Adobe RGB gamut on the gamut visualization.");
-DEFINE_bool(sRGB_gamma, false, "Draws the sRGB gamma on all gamma output images.");
-DEFINE_string(uncorrected, "", "A path to reencode the uncorrected input image.");
-
-
-//-------------------------------------------------------------------------------------------------
-//------------------------------------ Gamma visualizations ---------------------------------------
-
-static const char* kRGBChannelNames[3] = {
-    "Red  ",
-    "Green",
-    "Blue "
-};
-static const SkColor kRGBChannelColors[3] = {
-    SkColorSetARGB(128, 255, 0, 0),
-    SkColorSetARGB(128, 0, 255, 0),
-    SkColorSetARGB(128, 0, 0, 255)
-};
-
-static const char* kGrayChannelNames[1] = { "Gray"};
-static const SkColor kGrayChannelColors[1] = { SkColorSetRGB(128, 128, 128) };
-
-static const char* kCMYKChannelNames[4] = {
-    "Cyan   ",
-    "Magenta",
-    "Yellow ",
-    "Black  "
-};
-static const SkColor kCMYKChannelColors[4] = {
-    SkColorSetARGB(128, 0, 255, 255),
-    SkColorSetARGB(128, 255, 0, 255),
-    SkColorSetARGB(128, 255, 255, 0),
-    SkColorSetARGB(128, 16, 16, 16)
-};
-
-static const char*const*const kChannelNames[4] = {
-    kGrayChannelNames,
-    kRGBChannelNames,
-    kRGBChannelNames,
-    kCMYKChannelNames
-};
-static const SkColor*const kChannelColors[4] = {
-    kGrayChannelColors,
-    kRGBChannelColors,
-    kRGBChannelColors,
-    kCMYKChannelColors
-};
-
-static void dump_transfer_fn(SkGammaNamed gammaNamed) {
-    switch (gammaNamed) {
-        case kSRGB_SkGammaNamed:
-            SkDebugf("Transfer Function: sRGB\n");
-            return;
-        case k2Dot2Curve_SkGammaNamed:
-            SkDebugf("Exponential Transfer Function: Exponent 2.2\n");
-            return;
-        case kLinear_SkGammaNamed:
-            SkDebugf("Transfer Function: Linear\n");
-            return;
-        default:
-            break;
-    }
-
-}
-
-static constexpr int kGammaImageWidth = 500;
-static constexpr int kGammaImageHeight = 500;
-
-static void dump_transfer_fn(const SkGammas& gammas) {
-    SkASSERT(gammas.channels() <= 4);
-    const char*const*const channels = kChannelNames[gammas.channels() - 1];
-    for (int i = 0; i < gammas.channels(); i++) {
-        if (gammas.isNamed(i)) {
-            switch (gammas.data(i).fNamed) {
-                case kSRGB_SkGammaNamed:
-                    SkDebugf("%s Transfer Function: sRGB\n", channels[i]);
-                    return;
-                case k2Dot2Curve_SkGammaNamed:
-                    SkDebugf("%s Transfer Function: Exponent 2.2\n", channels[i]);
-                    return;
-                case kLinear_SkGammaNamed:
-                    SkDebugf("%s Transfer Function: Linear\n", channels[i]);
-                    return;
-                default:
-                    SkASSERT(false);
-                    continue;
-            }
-        } else if (gammas.isValue(i)) {
-            SkDebugf("%s Transfer Function: Exponent %.3f\n", channels[i], gammas.data(i).fValue);
-        } else if (gammas.isParametric(i)) {
-            const SkColorSpaceTransferFn& fn = gammas.data(i).params(&gammas);
-            SkDebugf("%s Transfer Function: Parametric A = %.3f, B = %.3f, C = %.3f, D = %.3f, "
-                     "E = %.3f, F = %.3f, G = %.3f\n", channels[i], fn.fA, fn.fB, fn.fC, fn.fD,
-                     fn.fE, fn.fF, fn.fG);
-        } else {
-            SkASSERT(gammas.isTable(i));
-            SkDebugf("%s Transfer Function: Table (%d entries)\n", channels[i],
-                    gammas.data(i).fTable.fSize);
-        }
-    }
-}
-
-static inline float parametric(const SkColorSpaceTransferFn& fn, float x) {
-    return x >= fn.fD ? powf(fn.fA*x + fn.fB, fn.fG) + fn.fE
-                      : fn.fC*x + fn.fF;
-}
-
-static void draw_transfer_fn(SkCanvas* canvas, SkGammaNamed gammaNamed, const SkGammas* gammas,
-                             SkColor color) {
-    SkColorSpaceTransferFn fn[4];
-    struct TableInfo {
-        const float* fTable;
-        int          fSize;
-    };
-    TableInfo table[4];
-    bool isTable[4] = {false, false, false, false};
-    const int channels = gammas ? gammas->channels() : 1;
-    SkASSERT(channels <= 4);
-    if (kNonStandard_SkGammaNamed != gammaNamed) {
-        dump_transfer_fn(gammaNamed);
-        for (int i = 0; i < channels; ++i) {
-            named_to_parametric(&fn[i], gammaNamed);
-        }
-    } else {
-        SkASSERT(gammas);
-        dump_transfer_fn(*gammas);
-        for (int i = 0; i < channels; ++i) {
-            if (gammas->isTable(i)) {
-                table[i].fTable = gammas->table(i);
-                table[i].fSize = gammas->data(i).fTable.fSize;
-                isTable[i] = true;
-            } else {
-                switch (gammas->type(i)) {
-                    case SkGammas::Type::kNamed_Type:
-                        named_to_parametric(&fn[i], gammas->data(i).fNamed);
-                        break;
-                    case SkGammas::Type::kValue_Type:
-                        value_to_parametric(&fn[i], gammas->data(i).fValue);
-                        break;
-                    case SkGammas::Type::kParam_Type:
-                        fn[i] = gammas->params(i);
-                        break;
-                    default:
-                        SkASSERT(false);
-                }
-            }
-        }
-    }
-    SkPaint paint;
-    paint.setStyle(SkPaint::kStroke_Style);
-    paint.setColor(color);
-    paint.setStrokeWidth(2.0f);
-    // note: gamma has positive values going up in this image so this origin is
-    //       the bottom left and we must subtract y instead of adding.
-    const float gap         = 16.0f;
-    const float gammaWidth  = kGammaImageWidth - 2 * gap;
-    const float gammaHeight = kGammaImageHeight - 2 * gap;
-    // gamma origin point
-    const float ox = gap;
-    const float oy = gap + gammaHeight;
-    for (int i = 0; i < channels; ++i) {
-        if (kNonStandard_SkGammaNamed == gammaNamed) {
-            paint.setColor(kChannelColors[channels - 1][i]);
-        } else {
-            paint.setColor(color);
-        }
-        if (isTable[i]) {
-            auto tx = [&table,i](int index) {
-                return index / (table[i].fSize - 1.0f);
-            };
-            for (int ti = 1; ti < table[i].fSize; ++ti) {
-                canvas->drawLine(ox + gammaWidth * tx(ti - 1),
-                                 oy - gammaHeight * table[i].fTable[ti - 1],
-                                 ox + gammaWidth * tx(ti),
-                                 oy - gammaHeight * table[i].fTable[ti],
-                                 paint);
-            }
-        } else {
-            const float step = 0.01f;
-            float yPrev = parametric(fn[i], 0.0f);
-            for (float x = step; x <= 1.0f; x += step) {
-                const float y = parametric(fn[i], x);
-                canvas->drawLine(ox + gammaWidth * (x - step), oy - gammaHeight * yPrev,
-                                 ox + gammaWidth * x, oy - gammaHeight * y,
-                                 paint);
-                yPrev = y;
-            }
-        }
-    }
-    paint.setColor(0xFF000000);
-    paint.setStrokeWidth(3.0f);
-    canvas->drawRect({ ox, oy - gammaHeight, ox + gammaWidth, oy }, paint);
-}
-
-//-------------------------------------------------------------------------------------------------
-//------------------------------------ CLUT visualizations ----------------------------------------
-static void dump_clut(const SkColorLookUpTable& clut) {
-    SkDebugf("CLUT: ");
-    for (int i = 0; i < clut.inputChannels(); ++i) {
-        SkDebugf("[%d]", clut.gridPoints(i));
-    }
-    SkDebugf(" -> [%d]\n", clut.outputChannels());
-}
-
-constexpr int kClutGap = 8;
-constexpr float kClutCanvasSize = 2000;
-
-static inline int usedGridPoints(const SkColorLookUpTable& clut, int dimension) {
-    const int gp = clut.gridPoints(dimension);
-    return gp <= 16 ? gp : 16;
-}
-
-// how many rows of cross-section cuts to display
-static inline int cut_rows(const SkColorLookUpTable& clut, int dimOrder[4]) {
-    // and vertical ones for the 4th dimension (if applicable)
-    return clut.inputChannels() >= 4 ? usedGridPoints(clut, dimOrder[3]) : 1;
-}
-
-// how many columns of cross-section cuts to display
-static inline int cut_cols(const SkColorLookUpTable& clut, int dimOrder[4]) {
-    // do horizontal cuts for the 3rd dimension (if applicable)
-    return clut.inputChannels() >= 3 ? usedGridPoints(clut, dimOrder[2]) : 1;
-}
-
-// gets the width/height to use for cross-sections of a CLUT
-static int cut_size(const SkColorLookUpTable& clut, int dimOrder[4]) {
-    const int rows = cut_rows(clut, dimOrder);
-    const int cols = cut_cols(clut, dimOrder);
-    // make sure the cross-section CLUT cuts are square still by using the
-    // smallest of the width/height, then adjust the gaps between accordingly
-    const int cutWidth = (kClutCanvasSize - kClutGap * (1 + cols)) / cols;
-    const int cutHeight = (kClutCanvasSize - kClutGap * (1 + rows)) / rows;
-    return cutWidth < cutHeight ? cutWidth : cutHeight;
-}
-
-static void draw_clut(SkCanvas* canvas, const SkColorLookUpTable& clut, int dimOrder[4]) {
-    dump_clut(clut);
-
-    const int cutSize = cut_size(clut, dimOrder);
-    const int rows = cut_rows(clut, dimOrder);
-    const int cols = cut_cols(clut, dimOrder);
-    const int cutHorizGap = (kClutCanvasSize - cutSize * cols) / (1 + cols);
-    const int cutVertGap = (kClutCanvasSize - cutSize * rows) / (1 + rows);
-
-    SkPaint paint;
-    for (int row = 0; row < rows; ++row) {
-        for (int col = 0; col < cols; ++col) {
-            // make sure to move at least one pixel, but otherwise move per-gridpoint
-            const float xStep = 1.0f / (SkTMin(cutSize, clut.gridPoints(dimOrder[0])) - 1);
-            const float yStep = 1.0f / (SkTMin(cutSize, clut.gridPoints(dimOrder[1])) - 1);
-            const float ox = clut.inputChannels() >= 3 ? (1 + col) * cutHorizGap + col * cutSize
-                                                       : kClutGap;
-            const float oy = clut.inputChannels() >= 4 ? (1 + row) * cutVertGap + row * cutSize
-                                                       : kClutGap;
-            // for each cross-section cut, draw a bunch of squares whose colour is the top-left's
-            // colour in the CLUT (usually this will just draw the gridpoints)
-            for (float x = 0.0f; x < 1.0f; x += xStep) {
-                for (float y = 0.0f; y < 1.0f; y += yStep) {
-                    const float z = col / (cols - 1.0f);
-                    const float w = row / (rows - 1.0f);
-                    const float input[4] = {x, y, z, w};
-                    float output[3];
-                    clut.interp(output, input);
-                    paint.setColor(SkColorSetRGB(255*output[0], 255*output[1], 255*output[2]));
-                    canvas->drawRect(SkRect::MakeLTRB(ox + cutSize * x, oy + cutSize * y,
-                                                      ox + cutSize * (x + xStep),
-                                                      oy + cutSize * (y + yStep)), paint);
-                }
-            }
-        }
-    }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-//------------------------------------ Gamut visualizations ---------------------------------------
-static void dump_matrix(const SkMatrix44& m) {
-    for (int r = 0; r < 4; ++r) {
-        SkDebugf("|");
-        for (int c = 0; c < 4; ++c) {
-            SkDebugf(" %f ", m.get(r, c));
-        }
-        SkDebugf("|\n");
-    }
-}
-
-/**
- *  Loads the triangular gamut as a set of three points.
- */
-static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) {
-    // rx = rX / (rX + rY + rZ)
-    // ry = rX / (rX + rY + rZ)
-    // gx, gy, bx, and gy are calulcated similarly.
-    float rSum = xyz.get(0, 0) + xyz.get(1, 0) + xyz.get(2, 0);
-    float gSum = xyz.get(0, 1) + xyz.get(1, 1) + xyz.get(2, 1);
-    float bSum = xyz.get(0, 2) + xyz.get(1, 2) + xyz.get(2, 2);
-    rgb[0].fX = xyz.get(0, 0) / rSum;
-    rgb[0].fY = xyz.get(1, 0) / rSum;
-    rgb[1].fX = xyz.get(0, 1) / gSum;
-    rgb[1].fY = xyz.get(1, 1) / gSum;
-    rgb[2].fX = xyz.get(0, 2) / bSum;
-    rgb[2].fY = xyz.get(1, 2) / bSum;
-}
-
-/**
- *  Calculates the area of the triangular gamut.
- */
-static float calculate_area(SkPoint abc[]) {
-    SkPoint a = abc[0];
-    SkPoint b = abc[1];
-    SkPoint c = abc[2];
-    return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY);
-}
-
-static void draw_gamut(SkCanvas* canvas, const SkMatrix44& xyz, const char* name, SkColor color,
-                       bool label) {
-    // Report the XYZ values.
-    SkDebugf("%s\n", name);
-    SkDebugf("       R     G     B\n");
-    SkDebugf("X  %.3f %.3f %.3f\n", xyz.get(0, 0), xyz.get(0, 1), xyz.get(0, 2));
-    SkDebugf("Y  %.3f %.3f %.3f\n", xyz.get(1, 0), xyz.get(1, 1), xyz.get(1, 2));
-    SkDebugf("Z  %.3f %.3f %.3f\n", xyz.get(2, 0), xyz.get(2, 1), xyz.get(2, 2));
-
-    // Calculate the points in the gamut from the XYZ values.
-    SkPoint rgb[4];
-    load_gamut(rgb, xyz);
-
-    // Report the area of the gamut.
-    SkDebugf("Area of Gamut: %.3f\n\n", calculate_area(rgb));
-
-    // Magic constants that help us place the gamut triangles in the appropriate position
-    // on the canvas.
-    const float xScale = 2071.25f;  // Num pixels from 0 to 1 in x
-    const float xOffset = 241.0f;   // Num pixels until start of x-axis
-    const float yScale = 2067.78f;  // Num pixels from 0 to 1 in y
-    const float yOffset = -144.78f; // Num pixels until start of y-axis
-                                    // (negative because y extends beyond image bounds)
-
-    // Now transform the points so they can be drawn on our canvas.
-    // Note that y increases as we move down the canvas.
-    rgb[0].fX = xOffset + xScale * rgb[0].fX;
-    rgb[0].fY = yOffset + yScale * (1.0f - rgb[0].fY);
-    rgb[1].fX = xOffset + xScale * rgb[1].fX;
-    rgb[1].fY = yOffset + yScale * (1.0f - rgb[1].fY);
-    rgb[2].fX = xOffset + xScale * rgb[2].fX;
-    rgb[2].fY = yOffset + yScale * (1.0f - rgb[2].fY);
-
-    // Repeat the first point to connect the polygon.
-    rgb[3] = rgb[0];
-    SkPaint paint;
-    paint.setColor(color);
-    paint.setStrokeWidth(6.0f);
-    paint.setTextSize(75.0f);
-    canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, rgb, paint);
-    if (label) {
-        canvas->drawString("R", rgb[0].fX + 5.0f, rgb[0].fY + 75.0f, paint);
-        canvas->drawString("G", rgb[1].fX + 5.0f, rgb[1].fY - 5.0f, paint);
-        canvas->drawString("B", rgb[2].fX - 75.0f, rgb[2].fY - 5.0f, paint);
-    }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-//----------------------------------------- Main code ---------------------------------------------
-static SkBitmap transparentBitmap(int width, int height) {
-    SkBitmap bitmap;
-    bitmap.allocN32Pixels(width, height);
-    bitmap.eraseColor(SkColorSetARGB(0, 0, 0, 0));
-    return bitmap;
-}
-
-class OutputCanvas {
-public:
-    OutputCanvas(SkBitmap&& bitmap)
-        :fBitmap(bitmap)
-        ,fCanvas(fBitmap)
-    {}
-
-    bool save(std::vector<std::string>* output, const std::string& filename) {
-        // Finally, encode the result to the output file.
-        sk_sp<SkData> out = sk_tool_utils::EncodeImageToData(fBitmap, SkEncodedImageFormat::kPNG,
-                                                             100);
-        if (!out) {
-            SkDebugf("Failed to encode %s output.\n", filename.c_str());
-            return false;
-        }
-        SkFILEWStream stream(filename.c_str());
-        if (!stream.write(out->data(), out->size())) {
-            SkDebugf("Failed to write %s output.\n", filename.c_str());
-            return false;
-        }
-        // record name of canvas
-        output->push_back(filename);
-        return true;
-    }
-
-    SkCanvas* canvas() { return &fCanvas; }
-
-private:
-    SkBitmap fBitmap;
-    SkCanvas fCanvas;
-};
-
-int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage(
-            "Usage: colorspaceinfo --input <path to input image (or icc profile with --icc)> "
-                                  "--output <directory to output images> "
-                                  "--icc <indicates that the input is an icc profile>"
-                                  "--sRGB_gamut <draw canonical sRGB gamut> "
-                                  "--adobeRGB <draw canonical Adobe RGB gamut> "
-                                  "--sRGB_gamma <draw sRGB gamma> "
-                                  "--uncorrected <path to reencoded, uncorrected input image>\n"
-            "Description: Writes visualizations of the color space to the output image(s)  ."
-                         "Also, if a path is provided, writes uncorrected bytes to an unmarked "
-                         "png, for comparison with the input image.\n");
-    SkCommandLineFlags::Parse(argc, argv);
-    const char* input = FLAGS_input[0];
-    const char* output = FLAGS_output[0];
-    if (!input || !output) {
-        SkCommandLineFlags::PrintUsage();
-        return -1;
-    }
-
-    sk_sp<SkData> data(SkData::MakeFromFileName(input));
-    if (!data) {
-        SkDebugf("Cannot find input image.\n");
-        return -1;
-    }
-
-    std::unique_ptr<SkCodec> codec = nullptr;
-    sk_sp<SkColorSpace> colorSpace = nullptr;
-    if (FLAGS_icc) {
-        colorSpace = SkColorSpace::MakeICC(data->bytes(), data->size());
-    } else {
-        codec.reset(SkCodec::NewFromData(data));
-        colorSpace = sk_ref_sp(codec->getInfo().colorSpace());
-    }
-
-    if (!colorSpace) {
-        SkDebugf("Cannot create codec or icc profile from input file.\n");
-        return -1;
-    }
-
-    {
-        SkColorSpaceTransferFn colorSpaceTransferFn;
-        SkMatrix44 toXYZD50;
-        if (colorSpace->isNumericalTransferFn(&colorSpaceTransferFn) &&
-            colorSpace->toXYZD50(&toXYZD50)) {
-            SkString description = SkICCGetColorProfileTag(colorSpaceTransferFn, toXYZD50);
-            SkDebugf("Color Profile Description: \"%s\"\n", description.c_str());
-        }
-    }
-
-    // TODO: command line tweaking of this order
-    int dimOrder[4] = {0, 1, 2, 3};
-
-    std::vector<std::string> outputFilenames;
-
-    auto createOutputFilename = [output](const char* category, int index) -> std::string {
-        std::stringstream ss;
-        ss << output << '/' << category << '_' << index << ".png";
-        return ss.str();
-    };
-
-    if (SkColorSpace_Base::Type::kXYZ == as_CSB(colorSpace)->type()) {
-        SkDebugf("XYZ/TRC color space\n");
-
-        // Load a graph of the CIE XYZ color gamut.
-        SkBitmap gamutCanvasBitmap;
-        if (!GetResourceAsBitmap("gamut.png", &gamutCanvasBitmap)) {
-            SkDebugf("Program failure (could not load gamut.png).\n");
-            return -1;
-        }
-        OutputCanvas gamutCanvas(std::move(gamutCanvasBitmap));
-        // Draw the sRGB gamut if requested.
-        if (FLAGS_sRGB_gamut) {
-            sk_sp<SkColorSpace> sRGBSpace = SkColorSpace::MakeSRGB();
-            const SkMatrix44* mat = as_CSB(sRGBSpace)->toXYZD50();
-            SkASSERT(mat);
-            draw_gamut(gamutCanvas.canvas(), *mat, "sRGB", 0xFFFF9394, false);
-        }
-
-        // Draw the Adobe RGB gamut if requested.
-        if (FLAGS_adobeRGB) {
-            sk_sp<SkColorSpace> adobeRGBSpace = SkColorSpace::MakeRGB(
-                    SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kAdobeRGB_Gamut);
-            const SkMatrix44* mat = as_CSB(adobeRGBSpace)->toXYZD50();
-            SkASSERT(mat);
-            draw_gamut(gamutCanvas.canvas(), *mat, "Adobe RGB", 0xFF31a9e1, false);
-        }
-        const SkMatrix44* mat = as_CSB(colorSpace)->toXYZD50();
-        SkASSERT(mat);
-        auto xyz = static_cast<SkColorSpace_XYZ*>(colorSpace.get());
-        draw_gamut(gamutCanvas.canvas(), *mat, input, 0xFF000000, true);
-        if (!gamutCanvas.save(&outputFilenames, createOutputFilename("gamut", 0))) {
-            return -1;
-        }
-
-        OutputCanvas gammaCanvas(transparentBitmap(kGammaImageWidth, kGammaImageHeight));
-        if (FLAGS_sRGB_gamma) {
-            draw_transfer_fn(gammaCanvas.canvas(), kSRGB_SkGammaNamed, nullptr, 0xFFFF9394);
-        }
-        draw_transfer_fn(gammaCanvas.canvas(), xyz->gammaNamed(), xyz->gammas(), 0xFF000000);
-        if (!gammaCanvas.save(&outputFilenames, createOutputFilename("gamma", 0))) {
-            return -1;
-        }
-    } else {
-        SkDebugf("A2B color space");
-        SkColorSpace_A2B* a2b = static_cast<SkColorSpace_A2B*>(colorSpace.get());
-        SkDebugf("Conversion type: ");
-        switch (a2b->iccType()) {
-            case SkColorSpace_Base::kRGB_ICCTypeFlag:
-                SkDebugf("RGB");
-                break;
-            case SkColorSpace_Base::kCMYK_ICCTypeFlag:
-                SkDebugf("CMYK");
-                break;
-            case SkColorSpace_Base::kGray_ICCTypeFlag:
-                SkDebugf("Gray");
-                break;
-            default:
-                SkASSERT(false);
-                break;
-
-        }
-        SkDebugf(" -> ");
-        switch (a2b->pcs()) {
-            case SkColorSpace_A2B::PCS::kXYZ:
-                SkDebugf("XYZ\n");
-                break;
-            case SkColorSpace_A2B::PCS::kLAB:
-                SkDebugf("LAB\n");
-                break;
-        }
-        int clutCount = 0;
-        int gammaCount = 0;
-        for (int i = 0; i < a2b->count(); ++i) {
-            const SkColorSpace_A2B::Element& e = a2b->element(i);
-            switch (e.type()) {
-                case SkColorSpace_A2B::Element::Type::kGammaNamed: {
-                    OutputCanvas gammaCanvas(transparentBitmap(kGammaImageWidth,
-                                                               kGammaImageHeight));
-                    if (FLAGS_sRGB_gamma) {
-                        draw_transfer_fn(gammaCanvas.canvas(), kSRGB_SkGammaNamed, nullptr,
-                                         0xFFFF9394);
-                    }
-                    draw_transfer_fn(gammaCanvas.canvas(), e.gammaNamed(), nullptr,
-                                     0xFF000000);
-                    if (!gammaCanvas.save(&outputFilenames,
-                                          createOutputFilename("gamma", gammaCount++))) {
-                        return -1;
-                    }
-                }
-                break;
-                case SkColorSpace_A2B::Element::Type::kGammas: {
-                    OutputCanvas gammaCanvas(transparentBitmap(kGammaImageWidth,
-                                                               kGammaImageHeight));
-                    if (FLAGS_sRGB_gamma) {
-                        draw_transfer_fn(gammaCanvas.canvas(), kSRGB_SkGammaNamed, nullptr,
-                                         0xFFFF9394);
-                    }
-                    draw_transfer_fn(gammaCanvas.canvas(), kNonStandard_SkGammaNamed,
-                                     &e.gammas(), 0xFF000000);
-                    if (!gammaCanvas.save(&outputFilenames,
-                                          createOutputFilename("gamma", gammaCount++))) {
-                        return -1;
-                    }
-                }
-                break;
-                case SkColorSpace_A2B::Element::Type::kCLUT: {
-                    const SkColorLookUpTable& clut = e.colorLUT();
-                    const int cutSize = cut_size(clut, dimOrder);
-                    const int clutWidth = clut.inputChannels() >= 3 ? kClutCanvasSize
-                                                                    : 2 * kClutGap + cutSize;
-                    const int clutHeight = clut.inputChannels() >= 4 ? kClutCanvasSize
-                                                                     : 2 * kClutGap + cutSize;
-                    OutputCanvas clutCanvas(transparentBitmap(clutWidth, clutHeight));
-                    draw_clut(clutCanvas.canvas(), e.colorLUT(), dimOrder);
-                    if (!clutCanvas.save(&outputFilenames,
-                                         createOutputFilename("clut", clutCount++))) {
-                        return -1;
-                    }
-                }
-                break;
-                case SkColorSpace_A2B::Element::Type::kMatrix:
-                    dump_matrix(e.matrix());
-                    break;
-            }
-        }
-    }
-
-    // marker to tell the web-tool the names of all images output
-    SkDebugf("=========\n");
-    for (const std::string& filename : outputFilenames) {
-        SkDebugf("%s\n", filename.c_str());
-    }
-    if (!FLAGS_icc) {
-        SkDebugf("%s\n", input);
-    }
-    // Also, if requested, decode and reencode the uncorrected input image.
-    if (!FLAGS_uncorrected.isEmpty() && !FLAGS_icc) {
-        SkBitmap bitmap;
-        int width = codec->getInfo().width();
-        int height = codec->getInfo().height();
-        bitmap.allocN32Pixels(width, height, kOpaque_SkAlphaType == codec->getInfo().alphaType());
-        SkImageInfo decodeInfo = SkImageInfo::MakeN32(width, height, kUnpremul_SkAlphaType);
-        if (SkCodec::kSuccess != codec->getPixels(decodeInfo, bitmap.getPixels(),
-                                                  bitmap.rowBytes())) {
-            SkDebugf("Could not decode input image.\n");
-            return -1;
-        }
-        sk_sp<SkData> out = sk_tool_utils::EncodeImageToData(bitmap, SkEncodedImageFormat::kPNG,
-                                                             100);
-        if (!out) {
-            SkDebugf("Failed to encode uncorrected image.\n");
-            return -1;
-        }
-        SkFILEWStream bitmapStream(FLAGS_uncorrected[0]);
-        if (!bitmapStream.write(out->data(), out->size())) {
-            SkDebugf("Failed to write uncorrected image output.\n");
-            return -1;
-        }
-        SkDebugf("%s\n", FLAGS_uncorrected[0]);
-    }
-
-    return 0;
-}
diff --git a/src/third_party/skia/tools/copyright/main.py b/src/third_party/skia/tools/copyright/main.py
index 24969a7..e428448 100644
--- a/src/third_party/skia/tools/copyright/main.py
+++ b/src/third_party/skia/tools/copyright/main.py
@@ -67,7 +67,7 @@
     @param root_directory root directory within which to find all files
     """
     path_list = []
-    for dirpath, dirnames, filenames in os.walk(root_directory):
+    for dirpath, _, filenames in os.walk(root_directory):
         for filename in filenames:
             path_list.append(os.path.abspath(os.path.join(dirpath, filename)))
     return path_list
diff --git a/src/third_party/skia/tools/cpu_modules.cpp b/src/third_party/skia/tools/cpu_modules.cpp
new file mode 100644
index 0000000..a749ebf
--- /dev/null
+++ b/src/third_party/skia/tools/cpu_modules.cpp
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "modules/particles/include/SkParticleEffect.h"
+
+// Doesn't do anything important; just exists to show we can use modules/particles without the GPU
+// backend being available.
+int main(int argc, char** argv) {
+    // Register types for serialization
+    SkParticleEffect::RegisterParticleTypes();
+    return 0;
+}
diff --git a/src/third_party/skia/tools/create_flutter_test_images.cpp b/src/third_party/skia/tools/create_flutter_test_images.cpp
deleted file mode 100644
index 69a0d11..0000000
--- a/src/third_party/skia/tools/create_flutter_test_images.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColorSpacePriv.h"
-#include "SkImage.h"
-#include "SkPngEncoder.h"
-
-#include "Resources.h"
-
-/**
- *  Create a color space that swaps the red, green, and blue channels.
- */
-static sk_sp<SkColorSpace> gbr_color_space() {
-    float gbr[9];
-    gbr[0] = gSRGB_toXYZD50[1];
-    gbr[1] = gSRGB_toXYZD50[2];
-    gbr[2] = gSRGB_toXYZD50[0];
-    gbr[3] = gSRGB_toXYZD50[4];
-    gbr[4] = gSRGB_toXYZD50[5];
-    gbr[5] = gSRGB_toXYZD50[3];
-    gbr[6] = gSRGB_toXYZD50[7];
-    gbr[7] = gSRGB_toXYZD50[8];
-    gbr[8] = gSRGB_toXYZD50[6];
-    SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
-    toXYZD50.set3x3RowMajorf(gbr);
-    return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
-}
-
-/**
- *  Create a color space with a steep transfer function.
- */
-static sk_sp<SkColorSpace> tf_color_space() {
-    SkColorSpaceTransferFn fn;
-    fn.fA = 1.f; fn.fB = 0.f; fn.fC = 0.f; fn.fD = 0.f; fn.fE = 0.f; fn.fF = 0.f; fn.fG = 50.f;
-    return SkColorSpace::MakeRGB(fn, SkColorSpace::kSRGB_Gamut);
-}
-
-/**
- *  Create a wide gamut color space.
- */
-static sk_sp<SkColorSpace> wide_gamut_color_space() {
-    return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
-                                 SkColorSpace::kRec2020_Gamut);
-}
-
-int main(int argc, char** argv) {
-    sk_sp<SkImage> image = GetResourceAsImage("flutter_logo.jpg");
-    if (!image) {
-        SkDebugf("Cannot find flutter_logo.jpg in resources.\n");
-        return 1;
-    }
-
-    // Encode an image with a gbr color space.
-    SkImageInfo info = SkImageInfo::MakeN32(image->width(), image->height(), kOpaque_SkAlphaType,
-                                            gbr_color_space());
-    size_t rowBytes = info.minRowBytes();
-    SkAutoTMalloc<uint8_t> storage(rowBytes * image->height());
-    SkPixmap src(info, storage.get(), rowBytes);
-    image->readPixels(src, 0, 0, SkImage::kDisallow_CachingHint);
-    SkFILEWStream dst0("gbr.png");
-    SkPngEncoder::Options opts;
-    opts.fUnpremulBehavior = SkTransferFunctionBehavior::kIgnore; // Does not matter for opaque src
-    SkAssertResult(SkPngEncoder::Encode(&dst0, src, opts));
-
-    // Encode an image with steep transfer function.
-    src.setColorSpace(tf_color_space());
-    image->readPixels(src, 0, 0, SkImage::kDisallow_CachingHint);
-    SkFILEWStream dst1("tf.png");
-    SkAssertResult(SkPngEncoder::Encode(&dst1, src, opts));
-
-    // Encode a wide gamut image.
-    src.setColorSpace(wide_gamut_color_space());
-    image->readPixels(src, 0, 0, SkImage::kDisallow_CachingHint);
-    SkFILEWStream dst2("wide-gamut.png");
-    SkAssertResult(SkPngEncoder::Encode(&dst2, src, opts));
-
-    return 0;
-}
diff --git a/src/third_party/skia/tools/create_test_font.cpp b/src/third_party/skia/tools/create_test_font.cpp
deleted file mode 100644
index 5183981..0000000
--- a/src/third_party/skia/tools/create_test_font.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// running create_test_font generates ./tools/test_font_data.cpp
-// which is read by ./tools/sk_tool_utils_font.cpp
-
-#include "Resources.h"
-#include "SkOSFile.h"
-#include "SkPaint.h"
-#include "SkPath.h"
-#include "SkStream.h"
-#include "SkTArray.h"
-#include "SkTSort.h"
-#include "SkTypeface.h"
-#include "SkUtils.h"
-#include <stdio.h>
-
-#define DEFAULT_FONT_NAME "sans-serif"
-
-static struct FontDesc {
-    const char* fName;
-    SkTypeface::Style fStyle;
-    const char* fFont;
-    const char* fFile;
-    int fFontIndex;
-} gFonts[] = {
-    {"monospace",   SkTypeface::kNormal,  "Liberation Mono",     "LiberationMono-Regular.ttf",  -1},
-    {"monospace",   SkTypeface::kBold,    "Liberation Mono",     "LiberationMono-Bold.ttf",     -1},
-    {"monospace",   SkTypeface::kItalic,  "Liberation Mono",     "LiberationMono-Italic.ttf",   -1},
-    {"monospace",  SkTypeface::kBoldItalic, "Liberation Mono", "LiberationMono-BoldItalic.ttf", -1},
-    {"sans-serif",  SkTypeface::kNormal,  "Liberation Sans",     "LiberationSans-Regular.ttf",  -1},
-    {"sans-serif",  SkTypeface::kBold,    "Liberation Sans",     "LiberationSans-Bold.ttf",     -1},
-    {"sans-serif",  SkTypeface::kItalic,  "Liberation Sans",     "LiberationSans-Italic.ttf",   -1},
-    {"sans-serif", SkTypeface::kBoldItalic, "Liberation Sans", "LiberationSans-BoldItalic.ttf", -1},
-    {"serif",       SkTypeface::kNormal,  "Liberation Serif",    "LiberationSerif-Regular.ttf", -1},
-    {"serif",       SkTypeface::kBold,    "Liberation Serif",    "LiberationSerif-Bold.ttf",    -1},
-    {"serif",       SkTypeface::kItalic,  "Liberation Serif",    "LiberationSerif-Italic.ttf",  -1},
-    {"serif",    SkTypeface::kBoldItalic, "Liberation Serif", "LiberationSerif-BoldItalic.ttf", -1},
-};
-
-const int gFontsCount = (int) SK_ARRAY_COUNT(gFonts);
-
-const char* gStyleName[] = {
-    "Normal",
-    "Bold",
-    "Italic",
-    "BoldItalic",
-};
-
-const char gHeader[] =
-"/*\n"
-" * Copyright 2015 Google Inc.\n"
-" *\n"
-" * Use of this source code is governed by a BSD-style license that can be\n"
-" * found in the LICENSE file.\n"
-" */\n"
-"\n"
-"// Auto-generated by ";
-
-static FILE* font_header(const char* family) {
-    SkString outPath(SkOSPath::Join(".", "tools"));
-    outPath = SkOSPath::Join(outPath.c_str(), "test_font_");
-    SkString fam(family);
-    do {
-        int dashIndex = fam.find("-");
-        if (dashIndex < 0) {
-            break;
-        }
-        fam.writable_str()[dashIndex] = '_';
-    } while (true);
-    outPath.append(fam);
-    outPath.append(".cpp");
-    FILE* out = fopen(outPath.c_str(), "w");
-    fprintf(out, "%s%s\n\n", gHeader, SkOSPath::Basename(__FILE__).c_str());
-    return out;
-}
-
-enum {
-    kMaxLineLength = 80,
-};
-
-static ptrdiff_t last_line_length(const SkString& str) {
-    const char* first = str.c_str();
-    const char* last = first + str.size();
-    const char* ptr = last;
-    while (ptr > first && *--ptr != '\n')
-        ;
-    return last - ptr - 1;
-}
-
-static void output_fixed(SkScalar num, int emSize, SkString* out) {
-    int hex = (int) (num * 65536 / emSize);
-    out->appendf("0x%08x,", hex);
-    *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
-}
-
-static void output_scalar(SkScalar num, int emSize, SkString* out) {
-    num /= emSize;
-    if (num == (int) num) {
-       out->appendS32((int) num);
-    } else {
-        SkString str;
-        str.printf("%1.6g", num);
-        int width = (int) str.size();
-        const char* cStr = str.c_str();
-        while (cStr[width - 1] == '0') {
-            --width;
-        }
-        str.remove(width, str.size() - width);
-        out->appendf("%sf", str.c_str());
-    }
-    *out += ',';
-    *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
-}
-
-static int output_points(const SkPoint* pts, int emSize, int count, SkString* ptsOut) {
-    for (int index = 0; index < count; ++index) {
-//        SkASSERT(floor(pts[index].fX) == pts[index].fX);
-        output_scalar(pts[index].fX, emSize, ptsOut);
-//        SkASSERT(floor(pts[index].fY) == pts[index].fY);
-        output_scalar(pts[index].fY, emSize, ptsOut);
-    }
-    return count;
-}
-
-static void output_path_data(const SkPaint& paint,
-        int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs,
-        SkTDArray<unsigned>* charCodes, SkTDArray<SkScalar>* widths) {
-    for (int ch = 0x00; ch < 0x7f; ++ch) {
-        char str[1];
-        str[0] = ch;
-        const char* used = str;
-        SkUnichar index = SkUTF8_NextUnichar(&used);
-        SkPath path;
-        paint.getTextPath((const void*) &index, 2, 0, 0, &path);
-        SkPath::RawIter iter(path);
-        SkPath::Verb verb;
-        SkPoint pts[4];
-        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
-            *verbs->append() = verb;
-            switch (verb) {
-                case SkPath::kMove_Verb:
-                    output_points(&pts[0], emSize, 1, ptsOut);
-                    break;
-                case SkPath::kLine_Verb:
-                    output_points(&pts[1], emSize, 1, ptsOut);
-                    break;
-                case SkPath::kQuad_Verb:
-                    output_points(&pts[1], emSize, 2, ptsOut);
-                    break;
-                case SkPath::kCubic_Verb:
-                    output_points(&pts[1], emSize, 3, ptsOut);
-                    break;
-                case SkPath::kClose_Verb:
-                    break;
-                default:
-                    SkDEBUGFAIL("bad verb");
-                    SkASSERT(0);
-            }
-        }
-        *verbs->append() = SkPath::kDone_Verb;
-        *charCodes->append() = index;
-        SkScalar width;
-        SkDEBUGCODE(int charCount =) paint.getTextWidths((const void*) &index, 2, &width);
-        SkASSERT(charCount == 1);
-     // SkASSERT(floor(width) == width);  // not true for Hiragino Maru Gothic Pro
-        *widths->append() = width;
-        if (!ch) {
-            ch = 0x1f;  // skip the rest of the control codes
-        }
-    }
-}
-
-static int offset_str_len(unsigned num) {
-    if (num == (unsigned) -1) {
-        return 10;
-    }
-    unsigned result = 1;
-    unsigned ref = 10;
-    while (ref <= num) {
-        ++result;
-        ref *= 10;
-    }
-    return result;
-}
-
-static SkString strip_spaces(const SkString& str) {
-    SkString result;
-    int count = (int) str.size();
-    for (int index = 0; index < count; ++index) {
-        char c = str[index];
-        if (c != ' ' && c != '-') {
-            result += c;
-        }
-    }
-    return result;
-}
-
-static SkString strip_final(const SkString& str) {
-    SkString result(str);
-    if (result.endsWith("\n")) {
-        result.remove(result.size() - 1, 1);
-    }
-    if (result.endsWith(" ")) {
-        result.remove(result.size() - 1, 1);
-    }
-    if (result.endsWith(",")) {
-        result.remove(result.size() - 1, 1);
-    }
-    return result;
-}
-
-static void output_font(SkTypeface* face, const char* name, SkTypeface::Style style, FILE* out) {
-    int emSize = face->getUnitsPerEm() * 2;
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    paint.setTextAlign(SkPaint::kLeft_Align);
-    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
-    paint.setTextSize(emSize);
-    SkSafeUnref(paint.setTypeface(face));
-    SkTDArray<SkPath::Verb> verbs;
-    SkTDArray<unsigned> charCodes;
-    SkTDArray<SkScalar> widths;
-    SkString ptsOut;
-    output_path_data(paint, emSize, &ptsOut, &verbs, &charCodes, &widths);
-    SkString fontnameStr(name);
-    SkString strippedStr = strip_spaces(fontnameStr);
-    strippedStr.appendf("%s", gStyleName[style]);
-    const char* fontname = strippedStr.c_str();
-    fprintf(out, "const SkScalar %sPoints[] = {\n", fontname);
-    ptsOut = strip_final(ptsOut);
-    fprintf(out, "%s", ptsOut.c_str());
-    fprintf(out, "\n};\n\n");
-    fprintf(out, "const unsigned char %sVerbs[] = {\n", fontname);
-    int verbCount = verbs.count();
-    int outChCount = 0;
-    for (int index = 0; index < verbCount;) {
-        SkPath::Verb verb = verbs[index];
-        SkASSERT(verb >= SkPath::kMove_Verb && verb <= SkPath::kDone_Verb);
-        SkASSERT((unsigned) verb == (unsigned char) verb);
-        fprintf(out, "%u", verb);
-        if (++index < verbCount) {
-            outChCount += 3;
-            fprintf(out, "%c", ',');
-            if (outChCount >= kMaxLineLength) {
-                outChCount = 0;
-                fprintf(out, "%c", '\n');
-            } else {
-                fprintf(out, "%c", ' ');
-            }
-        }
-    }
-    fprintf(out, "\n};\n\n");
-
-    // all fonts are now 0x00, 0x20 - 0xFE
-    // don't need to generate or output character codes?
-    fprintf(out, "const unsigned %sCharCodes[] = {\n", fontname);
-    int offsetCount = charCodes.count();
-    for (int index = 0; index < offsetCount;) {
-        unsigned offset = charCodes[index];
-        fprintf(out, "%u", offset);
-        if (++index < offsetCount) {
-            outChCount += offset_str_len(offset) + 2;
-            fprintf(out, "%c", ',');
-            if (outChCount >= kMaxLineLength) {
-                outChCount = 0;
-                fprintf(out, "%c", '\n');
-            } else {
-                fprintf(out, "%c", ' ');
-            }
-        }
-    }
-    fprintf(out, "\n};\n\n");
-
-    SkString widthsStr;
-    fprintf(out, "const SkFixed %sWidths[] = {\n", fontname);
-    for (int index = 0; index < offsetCount; ++index) {
-        output_fixed(widths[index], emSize, &widthsStr);
-    }
-    widthsStr = strip_final(widthsStr);
-    fprintf(out, "%s\n};\n\n", widthsStr.c_str());
-
-    fprintf(out, "const int %sCharCodesCount = (int) SK_ARRAY_COUNT(%sCharCodes);\n\n",
-            fontname, fontname);
-
-    SkPaint::FontMetrics metrics;
-    paint.getFontMetrics(&metrics);
-    fprintf(out, "const SkPaint::FontMetrics %sMetrics = {\n", fontname);
-    SkString metricsStr;
-    metricsStr.printf("0x%08x, ", metrics.fFlags);
-    output_scalar(metrics.fTop, emSize, &metricsStr);
-    output_scalar(metrics.fAscent, emSize, &metricsStr);
-    output_scalar(metrics.fDescent, emSize, &metricsStr);
-    output_scalar(metrics.fBottom, emSize, &metricsStr);
-    output_scalar(metrics.fLeading, emSize, &metricsStr);
-    output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr);
-    output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr);
-    output_scalar(metrics.fXMin, emSize, &metricsStr);
-    output_scalar(metrics.fXMax, emSize, &metricsStr);
-    output_scalar(metrics.fXHeight, emSize, &metricsStr);
-    output_scalar(metrics.fCapHeight, emSize, &metricsStr);
-    output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr);
-    output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr);
-    metricsStr = strip_final(metricsStr);
-    fprintf(out, "%s\n};\n\n", metricsStr.c_str());
-}
-
-struct FontWritten {
-    const char* fName;
-    SkTypeface::Style fStyle;
-};
-
-static SkTDArray<FontWritten> gWritten;
-
-static int written_index(const FontDesc& fontDesc) {
-    for (int index = 0; index < gWritten.count(); ++index) {
-        const FontWritten& writ = gWritten[index];
-        if (!strcmp(fontDesc.fFont, writ.fName) && fontDesc.fStyle == writ.fStyle) {
-            return index;
-        }
-    }
-    return -1;
-}
-
-static void generate_fonts() {
-    FILE* out = nullptr;
-    for (int index = 0; index < gFontsCount; ++index) {
-        FontDesc& fontDesc = gFonts[index];
-        if ((index & 3) == 0) {
-            out = font_header(fontDesc.fName);
-        }
-        int fontIndex = written_index(fontDesc);
-        if (fontIndex >= 0) {
-            fontDesc.fFontIndex = fontIndex;
-            continue;
-        }
-        SkTypeface* systemTypeface = SkTypeface::CreateFromName(fontDesc.fFont, fontDesc.fStyle);
-        SkASSERT(systemTypeface);
-        SkString filepath("/Library/Fonts/");
-        filepath.append(fontDesc.fFile);
-        SkASSERT(sk_exists(filepath.c_str()));
-        SkTypeface* resourceTypeface = SkTypeface::CreateFromFile(filepath.c_str());
-        SkASSERT(resourceTypeface);
-        output_font(resourceTypeface, fontDesc.fFont, fontDesc.fStyle, out);
-        fontDesc.fFontIndex = gWritten.count();
-        FontWritten* writ = gWritten.append();
-        writ->fName = fontDesc.fFont;
-        writ->fStyle = fontDesc.fStyle;
-        if ((index & 3) == 3) {
-            fclose(out);
-        }
-    }
-}
-
-static void generate_index(const char* defaultName) {
-    int fontCount = gWritten.count();
-    FILE* out = font_header("index");
-    int fontIndex;
-#if 0
-    // currently generated files are inlined one after the other.
-    // if the inlining is undesirable, generate externs using the code below
-    // (additional code required to add include files)
-    for (fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
-        const FontWritten& writ = gWritten[fontIndex];
-        const char* name = writ.fName;
-        SkString strippedStr = strip_spaces(SkString(name));
-        strippedStr.appendf("%s", gStyleName[writ.fStyle]);
-        const char* strip = strippedStr.c_str();
-        fprintf(out,
-                "extern const SkScalar %sPoints[];\n"
-                "extern const unsigned char %sVerbs[];\n"
-                "extern const unsigned %sCharCodes[];\n"
-                "extern const int %sCharCodesCount;\n"
-                "extern const SkFixed %sWidths[];\n"
-                "extern const SkPaint::FontMetrics %sMetrics;\n",
-                strip, strip, strip, strip, strip, strip);
-    }
-    fprintf(out, "\n");
-#endif
-    fprintf(out, "static SkTestFontData gTestFonts[] = {\n");
-    for (fontIndex = 0; fontIndex < fontCount; ++fontIndex) {
-        const FontWritten& writ = gWritten[fontIndex];
-        const char* name = writ.fName;
-        SkString strippedStr = strip_spaces(SkString(name));
-        strippedStr.appendf("%s", gStyleName[writ.fStyle]);
-        const char* strip = strippedStr.c_str();
-        fprintf(out,
-                "    {    %sPoints, %sVerbs, %sCharCodes,\n"
-                "         %sCharCodesCount, %sWidths,\n"
-                "         %sMetrics, \"Toy %s\", SkTypeface::k%s, nullptr\n"
-                "    },\n",
-                strip, strip, strip, strip, strip, strip, name, gStyleName[writ.fStyle]);
-    }
-    fprintf(out, "};\n\n");
-    fprintf(out, "const int gTestFontsCount = (int) SK_ARRAY_COUNT(gTestFonts);\n\n");
-    fprintf(out,
-                "struct SubFont {\n"
-                "    const char* fName;\n"
-                "    SkTypeface::Style fStyle;\n"
-                "    SkTestFontData& fFont;\n"
-                "    const char* fFile;\n"
-                "};\n\n"
-                "const SubFont gSubFonts[] = {\n");
-    int defaultIndex = -1;
-    for (int subIndex = 0; subIndex < gFontsCount; subIndex++) {
-        const FontDesc& desc = gFonts[subIndex];
-        if (defaultIndex < 0 && !strcmp(defaultName, desc.fName)) {
-            defaultIndex = subIndex;
-        }
-        fprintf(out,
-                "    { \"%s\", SkTypeface::k%s, gTestFonts[%d], \"%s\" },\n", desc.fName,
-                gStyleName[desc.fStyle], desc.fFontIndex, desc.fFile);
-    }
-    for (int subIndex = 0; subIndex < gFontsCount; subIndex++) {
-        const FontDesc& desc = gFonts[subIndex];
-        fprintf(out,
-                "    { \"Toy %s\", SkTypeface::k%s, gTestFonts[%d], \"%s\" },\n", desc.fFont,
-                gStyleName[desc.fStyle], desc.fFontIndex, desc.fFile);
-    }
-    fprintf(out, "};\n\n");
-    fprintf(out, "const int gSubFontsCount = (int) SK_ARRAY_COUNT(gSubFonts);\n\n");
-    SkASSERT(defaultIndex >= 0);
-    fprintf(out, "const int gDefaultFontIndex = %d;\n", defaultIndex);
-    fclose(out);
-}
-
-int main(int , char * const []) {
-#ifndef SK_BUILD_FOR_MAC
-    #error "use fonts installed on Mac"
-#endif
-    generate_fonts();
-    generate_index(DEFAULT_FONT_NAME);
-    return 0;
-}
diff --git a/src/third_party/skia/tools/debugger/DebugCanvas.cpp b/src/third_party/skia/tools/debugger/DebugCanvas.cpp
new file mode 100644
index 0000000..9f6776a
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/DebugCanvas.cpp
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkPicture.h"
+#include "include/core/SkTextBlob.h"
+#include "include/utils/SkPaintFilterCanvas.h"
+#include "src/core/SkCanvasPriv.h"
+#include "src/core/SkClipOpPriv.h"
+#include "src/core/SkRectPriv.h"
+#include "src/utils/SkJSONWriter.h"
+#include "tools/debugger/DebugCanvas.h"
+#include "tools/debugger/DrawCommand.h"
+
+#include "include/gpu/GrContext.h"
+#include "src/gpu/GrAuditTrail.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrRenderTargetContext.h"
+
+#define SKDEBUGCANVAS_VERSION 1
+#define SKDEBUGCANVAS_ATTRIBUTE_VERSION "version"
+#define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS "commands"
+#define SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL "auditTrail"
+
+class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
+public:
+    DebugPaintFilterCanvas(SkCanvas* canvas, bool overdrawViz)
+            : INHERITED(canvas), fOverdrawViz(overdrawViz) {}
+
+protected:
+    bool onFilter(SkPaint& paint) const override {
+        if (fOverdrawViz) {
+            paint.setColor(SK_ColorRED);
+            paint.setAlpha(0x08);
+            paint.setBlendMode(SkBlendMode::kSrcOver);
+        }
+        return true;
+    }
+
+    void onDrawPicture(const SkPicture* picture,
+                       const SkMatrix*  matrix,
+                       const SkPaint*   paint) override {
+        // We need to replay the picture onto this canvas in order to filter its internal paints.
+        this->SkCanvas::onDrawPicture(picture, matrix, paint);
+    }
+
+private:
+    bool fOverdrawViz;
+
+    typedef SkPaintFilterCanvas INHERITED;
+};
+
+DebugCanvas::DebugCanvas(int width, int height)
+        : INHERITED(width, height)
+        , fOverdrawViz(false)
+        , fClipVizColor(SK_ColorTRANSPARENT)
+        , fDrawGpuOpBounds(false) {
+    // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
+    // operations. This can lead to problems in the debugger which expects all
+    // the operations in the captured skp to appear in the debug canvas. To
+    // circumvent this we create a wide open clip here (an empty clip rect
+    // is not sufficient).
+    // Internally, the SkRect passed to clipRect is converted to an SkIRect and
+    // rounded out. The following code creates a nearly maximal rect that will
+    // not get collapsed by the coming conversions (Due to precision loss the
+    // inset has to be surprisingly large).
+    SkIRect largeIRect = SkRectPriv::MakeILarge();
+    largeIRect.inset(1024, 1024);
+    SkRect large = SkRect::Make(largeIRect);
+#ifdef SK_DEBUG
+    SkASSERT(!large.roundOut().isEmpty());
+#endif
+    // call the base class' version to avoid adding a draw command
+    this->INHERITED::onClipRect(large, kReplace_SkClipOp, kHard_ClipEdgeStyle);
+}
+
+DebugCanvas::DebugCanvas(SkIRect bounds) { DebugCanvas(bounds.width(), bounds.height()); }
+
+DebugCanvas::~DebugCanvas() { fCommandVector.deleteAll(); }
+
+void DebugCanvas::addDrawCommand(DrawCommand* command) { fCommandVector.push_back(command); }
+
+void DebugCanvas::draw(SkCanvas* canvas) {
+    if (!fCommandVector.isEmpty()) {
+        this->drawTo(canvas, fCommandVector.count() - 1);
+    }
+}
+
+void DebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
+    SkASSERT(!fCommandVector.isEmpty());
+    SkASSERT(index < fCommandVector.count());
+
+    int saveCount = originalCanvas->save();
+
+    SkRect windowRect = SkRect::MakeWH(SkIntToScalar(originalCanvas->getBaseLayerSize().width()),
+                                       SkIntToScalar(originalCanvas->getBaseLayerSize().height()));
+
+    originalCanvas->clear(SK_ColorTRANSPARENT);
+    originalCanvas->resetMatrix();
+    if (!windowRect.isEmpty()) {
+        originalCanvas->clipRect(windowRect, kReplace_SkClipOp);
+    }
+
+    DebugPaintFilterCanvas filterCanvas(originalCanvas, fOverdrawViz);
+
+    // If we have a GPU backend we can also visualize the op information
+    GrAuditTrail* at = nullptr;
+    if (fDrawGpuOpBounds || m != -1) {
+        // The audit trail must be obtained from the original canvas.
+        at = this->getAuditTrail(originalCanvas);
+    }
+
+    for (int i = 0; i <= index; i++) {
+        // We need to flush any pending operations, or they might combine with commands below.
+        // Previous operations were not registered with the audit trail when they were
+        // created, so if we allow them to combine, the audit trail will fail to find them.
+        filterCanvas.flush();
+
+        GrAuditTrail::AutoCollectOps* acb = nullptr;
+        if (at) {
+            acb = new GrAuditTrail::AutoCollectOps(at, i);
+        }
+
+        if (fCommandVector[i]->isVisible()) {
+            fCommandVector[i]->execute(&filterCanvas);
+        }
+        if (at && acb) {
+            delete acb;
+        }
+    }
+
+    if (SkColorGetA(fClipVizColor) != 0) {
+        filterCanvas.save();
+#define LARGE_COORD 1000000000
+        filterCanvas.clipRect(
+                SkRect::MakeLTRB(-LARGE_COORD, -LARGE_COORD, LARGE_COORD, LARGE_COORD),
+                kReverseDifference_SkClipOp);
+        SkPaint clipPaint;
+        clipPaint.setColor(fClipVizColor);
+        filterCanvas.drawPaint(clipPaint);
+        filterCanvas.restore();
+    }
+
+    fMatrix = filterCanvas.getTotalMatrix();
+    fClip   = filterCanvas.getDeviceClipBounds();
+    filterCanvas.restoreToCount(saveCount);
+
+    // draw any ops if required and issue a full reset onto GrAuditTrail
+    if (at) {
+        // just in case there is global reordering, we flush the canvas before querying
+        // GrAuditTrail
+        GrAuditTrail::AutoEnable ae(at);
+        filterCanvas.flush();
+
+        // we pick three colorblind-safe colors, 75% alpha
+        static const SkColor kTotalBounds     = SkColorSetARGB(0xC0, 0x6A, 0x3D, 0x9A);
+        static const SkColor kCommandOpBounds = SkColorSetARGB(0xC0, 0xE3, 0x1A, 0x1C);
+        static const SkColor kOtherOpBounds   = SkColorSetARGB(0xC0, 0xFF, 0x7F, 0x00);
+
+        // get the render target of the top device (from the original canvas) so we can ignore ops
+        // drawn offscreen
+        GrRenderTargetContext* rtc =
+                originalCanvas->internal_private_accessTopLayerRenderTargetContext();
+        GrSurfaceProxy::UniqueID proxyID = rtc->asSurfaceProxy()->uniqueID();
+
+        // get the bounding boxes to draw
+        SkTArray<GrAuditTrail::OpInfo> childrenBounds;
+        if (m == -1) {
+            at->getBoundsByClientID(&childrenBounds, index);
+        } else {
+            // the client wants us to draw the mth op
+            at->getBoundsByOpsTaskID(&childrenBounds.push_back(), m);
+        }
+        SkPaint paint;
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(1);
+        for (int i = 0; i < childrenBounds.count(); i++) {
+            if (childrenBounds[i].fProxyUniqueID != proxyID) {
+                // offscreen draw, ignore for now
+                continue;
+            }
+            paint.setColor(kTotalBounds);
+            filterCanvas.drawRect(childrenBounds[i].fBounds, paint);
+            for (int j = 0; j < childrenBounds[i].fOps.count(); j++) {
+                const GrAuditTrail::OpInfo::Op& op = childrenBounds[i].fOps[j];
+                if (op.fClientID != index) {
+                    paint.setColor(kOtherOpBounds);
+                } else {
+                    paint.setColor(kCommandOpBounds);
+                }
+                filterCanvas.drawRect(op.fBounds, paint);
+            }
+        }
+    }
+    this->cleanupAuditTrail(originalCanvas);
+}
+
+void DebugCanvas::deleteDrawCommandAt(int index) {
+    SkASSERT(index < fCommandVector.count());
+    delete fCommandVector[index];
+    fCommandVector.remove(index);
+}
+
+DrawCommand* DebugCanvas::getDrawCommandAt(int index) {
+    SkASSERT(index < fCommandVector.count());
+    return fCommandVector[index];
+}
+
+GrAuditTrail* DebugCanvas::getAuditTrail(SkCanvas* canvas) {
+    GrAuditTrail* at  = nullptr;
+    GrContext*    ctx = canvas->getGrContext();
+    if (ctx) {
+        at = ctx->priv().auditTrail();
+    }
+    return at;
+}
+
+void DebugCanvas::drawAndCollectOps(int n, SkCanvas* canvas) {
+    GrAuditTrail* at = this->getAuditTrail(canvas);
+    if (at) {
+        // loop over all of the commands and draw them, this is to collect reordering
+        // information
+        for (int i = 0; i < this->getSize() && i <= n; i++) {
+            GrAuditTrail::AutoCollectOps enable(at, i);
+            fCommandVector[i]->execute(canvas);
+        }
+
+        // in case there is some kind of global reordering
+        {
+            GrAuditTrail::AutoEnable ae(at);
+            canvas->flush();
+        }
+    }
+}
+
+void DebugCanvas::cleanupAuditTrail(SkCanvas* canvas) {
+    GrAuditTrail* at = this->getAuditTrail(canvas);
+    if (at) {
+        GrAuditTrail::AutoEnable ae(at);
+        at->fullReset();
+    }
+}
+
+void DebugCanvas::toJSON(SkJSONWriter&   writer,
+                         UrlDataManager& urlDataManager,
+                         int             n,
+                         SkCanvas*       canvas) {
+    this->drawAndCollectOps(n, canvas);
+
+    // now collect json
+    GrAuditTrail* at = this->getAuditTrail(canvas);
+    writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_VERSION, SKDEBUGCANVAS_VERSION);
+    writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_COMMANDS);
+
+    for (int i = 0; i < this->getSize() && i <= n; i++) {
+        writer.beginObject();  // command
+        this->getDrawCommandAt(i)->toJSON(writer, urlDataManager);
+
+        if (at) {
+            writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL);
+            at->toJson(writer, i);
+        }
+        writer.endObject();  // command
+    }
+
+    writer.endArray();  // commands
+    this->cleanupAuditTrail(canvas);
+}
+
+void DebugCanvas::toJSONOpsTask(SkJSONWriter& writer, int n, SkCanvas* canvas) {
+    this->drawAndCollectOps(n, canvas);
+
+    GrAuditTrail* at = this->getAuditTrail(canvas);
+    if (at) {
+        GrAuditTrail::AutoManageOpsTask enable(at);
+        at->toJson(writer);
+    } else {
+        writer.beginObject();
+        writer.endObject();
+    }
+    this->cleanupAuditTrail(canvas);
+}
+
+void DebugCanvas::setOverdrawViz(bool overdrawViz) { fOverdrawViz = overdrawViz; }
+
+void DebugCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
+    this->addDrawCommand(new ClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void DebugCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
+    this->addDrawCommand(new ClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void DebugCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
+    this->addDrawCommand(new ClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void DebugCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
+    this->addDrawCommand(new ClipRegionCommand(region, op));
+}
+
+void DebugCanvas::didConcat(const SkMatrix& matrix) {
+    this->addDrawCommand(new ConcatCommand(matrix));
+    this->INHERITED::didConcat(matrix);
+}
+
+void DebugCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    this->addDrawCommand(new DrawAnnotationCommand(rect, key, sk_ref_sp(value)));
+}
+
+void DebugCanvas::onDrawBitmap(const SkBitmap& bitmap,
+                               SkScalar        left,
+                               SkScalar        top,
+                               const SkPaint*  paint) {
+    this->addDrawCommand(new DrawBitmapCommand(bitmap, left, top, paint));
+}
+
+void DebugCanvas::onDrawBitmapLattice(const SkBitmap& bitmap,
+                                      const Lattice&  lattice,
+                                      const SkRect&   dst,
+                                      const SkPaint*  paint) {
+    this->addDrawCommand(new DrawBitmapLatticeCommand(bitmap, lattice, dst, paint));
+}
+
+void DebugCanvas::onDrawBitmapRect(const SkBitmap&   bitmap,
+                                   const SkRect*     src,
+                                   const SkRect&     dst,
+                                   const SkPaint*    paint,
+                                   SrcRectConstraint constraint) {
+    this->addDrawCommand(
+            new DrawBitmapRectCommand(bitmap, src, dst, paint, (SrcRectConstraint)constraint));
+}
+
+void DebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
+                                   const SkIRect&  center,
+                                   const SkRect&   dst,
+                                   const SkPaint*  paint) {
+    this->addDrawCommand(new DrawBitmapNineCommand(bitmap, center, dst, paint));
+}
+
+void DebugCanvas::onDrawImage(const SkImage* image,
+                              SkScalar       left,
+                              SkScalar       top,
+                              const SkPaint* paint) {
+    this->addDrawCommand(new DrawImageCommand(image, left, top, paint));
+}
+
+void DebugCanvas::onDrawImageLattice(const SkImage* image,
+                                     const Lattice& lattice,
+                                     const SkRect&  dst,
+                                     const SkPaint* paint) {
+    this->addDrawCommand(new DrawImageLatticeCommand(image, lattice, dst, paint));
+}
+
+void DebugCanvas::onDrawImageRect(const SkImage*    image,
+                                  const SkRect*     src,
+                                  const SkRect&     dst,
+                                  const SkPaint*    paint,
+                                  SrcRectConstraint constraint) {
+    this->addDrawCommand(new DrawImageRectCommand(image, src, dst, paint, constraint));
+}
+
+void DebugCanvas::onDrawImageNine(const SkImage* image,
+                                  const SkIRect& center,
+                                  const SkRect&  dst,
+                                  const SkPaint* paint) {
+    this->addDrawCommand(new DrawImageNineCommand(image, center, dst, paint));
+}
+
+void DebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
+    this->addDrawCommand(new DrawOvalCommand(oval, paint));
+}
+
+void DebugCanvas::onDrawArc(const SkRect&  oval,
+                            SkScalar       startAngle,
+                            SkScalar       sweepAngle,
+                            bool           useCenter,
+                            const SkPaint& paint) {
+    this->addDrawCommand(new DrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint));
+}
+
+void DebugCanvas::onDrawPaint(const SkPaint& paint) {
+    this->addDrawCommand(new DrawPaintCommand(paint));
+}
+
+void DebugCanvas::onDrawBehind(const SkPaint& paint) {
+    this->addDrawCommand(new DrawBehindCommand(paint));
+}
+
+void DebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
+    this->addDrawCommand(new DrawPathCommand(path, paint));
+}
+
+void DebugCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    this->addDrawCommand(new DrawRegionCommand(region, paint));
+}
+
+void DebugCanvas::onDrawPicture(const SkPicture* picture,
+                                const SkMatrix*  matrix,
+                                const SkPaint*   paint) {
+    this->addDrawCommand(new BeginDrawPictureCommand(picture, matrix, paint));
+    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
+    picture->playback(this);
+    this->addDrawCommand(new EndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
+}
+
+void DebugCanvas::onDrawPoints(PointMode      mode,
+                               size_t         count,
+                               const SkPoint  pts[],
+                               const SkPaint& paint) {
+    this->addDrawCommand(new DrawPointsCommand(mode, count, pts, paint));
+}
+
+void DebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+    // NOTE(chudy): Messing up when renamed to DrawRect... Why?
+    addDrawCommand(new DrawRectCommand(rect, paint));
+}
+
+void DebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
+    this->addDrawCommand(new DrawRRectCommand(rrect, paint));
+}
+
+void DebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
+    this->addDrawCommand(new DrawDRRectCommand(outer, inner, paint));
+}
+
+void DebugCanvas::onDrawTextBlob(const SkTextBlob* blob,
+                                 SkScalar          x,
+                                 SkScalar          y,
+                                 const SkPaint&    paint) {
+    this->addDrawCommand(
+            new DrawTextBlobCommand(sk_ref_sp(const_cast<SkTextBlob*>(blob)), x, y, paint));
+}
+
+void DebugCanvas::onDrawPatch(const SkPoint  cubics[12],
+                              const SkColor  colors[4],
+                              const SkPoint  texCoords[4],
+                              SkBlendMode    bmode,
+                              const SkPaint& paint) {
+    this->addDrawCommand(new DrawPatchCommand(cubics, colors, texCoords, bmode, paint));
+}
+
+void DebugCanvas::onDrawVerticesObject(const SkVertices*      vertices,
+                                       const SkVertices::Bone bones[],
+                                       int                    boneCount,
+                                       SkBlendMode            bmode,
+                                       const SkPaint&         paint) {
+    // TODO: ANIMATION NOT LOGGED
+    this->addDrawCommand(
+            new DrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode, paint));
+}
+
+void DebugCanvas::onDrawAtlas(const SkImage*  image,
+                              const SkRSXform xform[],
+                              const SkRect    tex[],
+                              const SkColor   colors[],
+                              int             count,
+                              SkBlendMode     bmode,
+                              const SkRect*   cull,
+                              const SkPaint*  paint) {
+    this->addDrawCommand(
+            new DrawAtlasCommand(image, xform, tex, colors, count, bmode, cull, paint));
+}
+
+void DebugCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
+    this->addDrawCommand(new DrawShadowCommand(path, rec));
+}
+
+void DebugCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
+    this->addDrawCommand(new DrawDrawableCommand(drawable, matrix));
+}
+
+void DebugCanvas::onDrawEdgeAAQuad(const SkRect&    rect,
+                                   const SkPoint    clip[4],
+                                   QuadAAFlags      aa,
+                                   const SkColor4f& color,
+                                   SkBlendMode      mode) {
+    this->addDrawCommand(new DrawEdgeAAQuadCommand(rect, clip, aa, color, mode));
+}
+
+void DebugCanvas::onDrawEdgeAAImageSet(const ImageSetEntry set[],
+                                       int                 count,
+                                       const SkPoint       dstClips[],
+                                       const SkMatrix      preViewMatrices[],
+                                       const SkPaint*      paint,
+                                       SrcRectConstraint   constraint) {
+    this->addDrawCommand(new DrawEdgeAAImageSetCommand(
+            set, count, dstClips, preViewMatrices, paint, constraint));
+}
+
+void DebugCanvas::willRestore() {
+    this->addDrawCommand(new RestoreCommand());
+    this->INHERITED::willRestore();
+}
+
+void DebugCanvas::willSave() {
+    this->addDrawCommand(new SaveCommand());
+    this->INHERITED::willSave();
+}
+
+SkCanvas::SaveLayerStrategy DebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
+    this->addDrawCommand(new SaveLayerCommand(rec));
+    (void)this->INHERITED::getSaveLayerStrategy(rec);
+    // No need for a full layer.
+    return kNoLayer_SaveLayerStrategy;
+}
+
+bool DebugCanvas::onDoSaveBehind(const SkRect* subset) {
+    // TODO
+    return false;
+}
+
+void DebugCanvas::didSetMatrix(const SkMatrix& matrix) {
+    this->addDrawCommand(new SetMatrixCommand(matrix));
+    this->INHERITED::didSetMatrix(matrix);
+}
+
+void DebugCanvas::toggleCommand(int index, bool toggle) {
+    SkASSERT(index < fCommandVector.count());
+    fCommandVector[index]->setVisible(toggle);
+}
diff --git a/src/third_party/skia/tools/debugger/DebugCanvas.h b/src/third_party/skia/tools/debugger/DebugCanvas.h
new file mode 100644
index 0000000..d7917ab
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/DebugCanvas.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKDEBUGCANVAS_H_
+#define SKDEBUGCANVAS_H_
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkCanvasVirtualEnforcer.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkString.h"
+#include "include/core/SkVertices.h"
+#include "include/pathops/SkPathOps.h"
+#include "include/private/SkTArray.h"
+#include "tools/UrlDataManager.h"
+#include "tools/debugger/DrawCommand.h"
+
+class GrAuditTrail;
+class SkNWayCanvas;
+class SkPicture;
+
+class DebugCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
+public:
+    DebugCanvas(int width, int height);
+
+    DebugCanvas(SkIRect bounds);
+
+    ~DebugCanvas() override;
+
+    /**
+     * Enable or disable overdraw visualization
+     */
+    void setOverdrawViz(bool overdrawViz);
+
+    bool getOverdrawViz() const { return fOverdrawViz; }
+
+    /**
+     * Set the color of the clip visualization. An alpha of zero renders the clip invisible.
+     */
+    void setClipVizColor(SkColor clipVizColor) { this->fClipVizColor = clipVizColor; }
+
+    void setDrawGpuOpBounds(bool drawGpuOpBounds) { fDrawGpuOpBounds = drawGpuOpBounds; }
+
+    bool getDrawGpuOpBounds() const { return fDrawGpuOpBounds; }
+
+    /**
+        Executes all draw calls to the canvas.
+        @param canvas  The canvas being drawn to
+     */
+    void draw(SkCanvas* canvas);
+
+    /**
+        Executes the draw calls up to the specified index.
+        @param canvas  The canvas being drawn to
+        @param index  The index of the final command being executed
+        @param m an optional Mth gpu op to highlight, or -1
+     */
+    void drawTo(SkCanvas* canvas, int index, int m = -1);
+
+    /**
+        Returns the most recently calculated transformation matrix
+     */
+    const SkMatrix& getCurrentMatrix() { return fMatrix; }
+
+    /**
+        Returns the most recently calculated clip
+     */
+    const SkIRect& getCurrentClip() { return fClip; }
+
+    /**
+        Removes the command at the specified index
+        @param index  The index of the command to delete
+     */
+    void deleteDrawCommandAt(int index);
+
+    /**
+        Returns the draw command at the given index.
+        @param index  The index of the command
+     */
+    DrawCommand* getDrawCommandAt(int index);
+
+    /**
+        Returns length of draw command vector.
+     */
+    int getSize() const { return fCommandVector.count(); }
+
+    /**
+        Toggles the visibility / execution of the draw command at index i with
+        the value of toggle.
+     */
+    void toggleCommand(int index, bool toggle);
+
+    /**
+        Returns a JSON object representing up to the Nth draw, where N is less than
+        DebugCanvas::getSize(). The encoder may use the UrlDataManager to store binary data such
+        as images, referring to them via URLs embedded in the JSON.
+     */
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager, int n, SkCanvas*);
+
+    void toJSONOpsTask(SkJSONWriter& writer, int n, SkCanvas*);
+
+    void detachCommands(SkTDArray<DrawCommand*>* dst) { fCommandVector.swap(*dst); }
+
+protected:
+    void              willSave() override;
+    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+    bool              onDoSaveBehind(const SkRect*) override;
+    void              willRestore() override;
+
+    void didConcat(const SkMatrix&) override;
+
+    void didSetMatrix(const SkMatrix&) override;
+
+    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
+    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+    void onDrawTextBlob(const SkTextBlob* blob,
+                        SkScalar          x,
+                        SkScalar          y,
+                        const SkPaint&    paint) override;
+
+    void onDrawPatch(const SkPoint cubics[12],
+                     const SkColor colors[4],
+                     const SkPoint texCoords[4],
+                     SkBlendMode,
+                     const SkPaint& paint) override;
+    void onDrawPaint(const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
+
+    void onDrawRect(const SkRect&, const SkPaint&) override;
+    void onDrawOval(const SkRect&, const SkPaint&) override;
+    void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
+    void onDrawRRect(const SkRRect&, const SkPaint&) override;
+    void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*,
+                              const SkVertices::Bone bones[],
+                              int                    boneCount,
+                              SkBlendMode,
+                              const SkPaint&) override;
+    void onDrawPath(const SkPath&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
+    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
+    void onDrawBitmapLattice(const SkBitmap&,
+                             const Lattice&,
+                             const SkRect&,
+                             const SkPaint*) override;
+    void onDrawBitmapRect(const SkBitmap&,
+                          const SkRect* src,
+                          const SkRect& dst,
+                          const SkPaint*,
+                          SrcRectConstraint) override;
+    void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
+    void onDrawImageLattice(const SkImage* image,
+                            const Lattice& lattice,
+                            const SkRect&  dst,
+                            const SkPaint* paint) override;
+    void onDrawImageRect(const SkImage*,
+                         const SkRect* src,
+                         const SkRect& dst,
+                         const SkPaint*,
+                         SrcRectConstraint) override;
+    void onDrawBitmapNine(const SkBitmap&,
+                          const SkIRect& center,
+                          const SkRect&  dst,
+                          const SkPaint*) override;
+    void onDrawImageNine(const SkImage*,
+                         const SkIRect& center,
+                         const SkRect&  dst,
+                         const SkPaint*) override;
+    void onDrawAtlas(const SkImage*,
+                     const SkRSXform[],
+                     const SkRect[],
+                     const SkColor[],
+                     int,
+                     SkBlendMode,
+                     const SkRect*,
+                     const SkPaint*) override;
+    void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
+    void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
+    void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
+    void onClipRegion(const SkRegion& region, SkClipOp) override;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
+
+    void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
+    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+
+    void onDrawEdgeAAQuad(const SkRect&,
+                          const SkPoint[4],
+                          QuadAAFlags,
+                          const SkColor4f&,
+                          SkBlendMode) override;
+    void onDrawEdgeAAImageSet(const ImageSetEntry[],
+                              int count,
+                              const SkPoint[],
+                              const SkMatrix[],
+                              const SkPaint*,
+                              SrcRectConstraint) override;
+
+private:
+    SkTDArray<DrawCommand*> fCommandVector;
+    SkMatrix                fMatrix;
+    SkIRect                 fClip;
+
+    bool    fOverdrawViz;
+    SkColor fClipVizColor;
+    bool    fDrawGpuOpBounds;
+
+    /**
+        Adds the command to the class' vector of commands.
+        @param command  The draw command for execution
+     */
+    void addDrawCommand(DrawCommand* command);
+
+    GrAuditTrail* getAuditTrail(SkCanvas*);
+
+    void drawAndCollectOps(int n, SkCanvas*);
+    void cleanupAuditTrail(SkCanvas*);
+
+    typedef SkCanvasVirtualEnforcer<SkCanvas> INHERITED;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/debugger/DrawCommand.cpp b/src/third_party/skia/tools/debugger/DrawCommand.cpp
new file mode 100644
index 0000000..7571a48
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/DrawCommand.cpp
@@ -0,0 +1,2125 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/debugger/DrawCommand.h"
+
+#include <algorithm>
+#include "include/core/SkColorFilter.h"
+#include "include/core/SkDrawable.h"
+#include "include/core/SkImageFilter.h"
+#include "include/core/SkPathEffect.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkTypeface.h"
+#include "include/effects/SkDashPathEffect.h"
+#include "include/encode/SkPngEncoder.h"
+#include "include/private/SkShadowFlags.h"
+#include "include/private/SkTHash.h"
+#include "src/core/SkAutoMalloc.h"
+#include "src/core/SkCanvasPriv.h"
+#include "src/core/SkClipOpPriv.h"
+#include "src/core/SkLatticeIter.h"
+#include "src/core/SkMaskFilterBase.h"
+#include "src/core/SkPaintDefaults.h"
+#include "src/core/SkReadBuffer.h"
+#include "src/core/SkRectPriv.h"
+#include "src/core/SkTextBlobPriv.h"
+#include "src/core/SkWriteBuffer.h"
+#include "tools/debugger/JsonWriteBuffer.h"
+
+#define DEBUGCANVAS_ATTRIBUTE_COMMAND "command"
+#define DEBUGCANVAS_ATTRIBUTE_VISIBLE "visible"
+#define DEBUGCANVAS_ATTRIBUTE_MATRIX "matrix"
+#define DEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS "drawDepthTranslation"
+#define DEBUGCANVAS_ATTRIBUTE_COORDS "coords"
+#define DEBUGCANVAS_ATTRIBUTE_EDGING "edging"
+#define DEBUGCANVAS_ATTRIBUTE_HINTING "hinting"
+#define DEBUGCANVAS_ATTRIBUTE_BOUNDS "bounds"
+#define DEBUGCANVAS_ATTRIBUTE_PAINT "paint"
+#define DEBUGCANVAS_ATTRIBUTE_OUTER "outer"
+#define DEBUGCANVAS_ATTRIBUTE_INNER "inner"
+#define DEBUGCANVAS_ATTRIBUTE_MODE "mode"
+#define DEBUGCANVAS_ATTRIBUTE_POINTS "points"
+#define DEBUGCANVAS_ATTRIBUTE_PATH "path"
+#define DEBUGCANVAS_ATTRIBUTE_TEXT "text"
+#define DEBUGCANVAS_ATTRIBUTE_COLOR "color"
+#define DEBUGCANVAS_ATTRIBUTE_ALPHA "alpha"
+#define DEBUGCANVAS_ATTRIBUTE_BLENDMODE "blendMode"
+#define DEBUGCANVAS_ATTRIBUTE_STYLE "style"
+#define DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth"
+#define DEBUGCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter"
+#define DEBUGCANVAS_ATTRIBUTE_STROKEJOIN "strokeJoin"
+#define DEBUGCANVAS_ATTRIBUTE_CAP "cap"
+#define DEBUGCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias"
+#define DEBUGCANVAS_ATTRIBUTE_DITHER "dither"
+#define DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT "fakeBoldText"
+#define DEBUGCANVAS_ATTRIBUTE_LINEARTEXT "linearText"
+#define DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT "subpixelText"
+#define DEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT "devKernText"
+#define DEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT "lcdRenderText"
+#define DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText"
+#define DEBUGCANVAS_ATTRIBUTE_AUTOHINTING "forceAutoHinting"
+#define DEBUGCANVAS_ATTRIBUTE_REGION "region"
+#define DEBUGCANVAS_ATTRIBUTE_REGIONOP "op"
+#define DEBUGCANVAS_ATTRIBUTE_EDGESTYLE "edgeStyle"
+#define DEBUGCANVAS_ATTRIBUTE_DEVICEREGION "deviceRegion"
+#define DEBUGCANVAS_ATTRIBUTE_BLUR "blur"
+#define DEBUGCANVAS_ATTRIBUTE_SIGMA "sigma"
+#define DEBUGCANVAS_ATTRIBUTE_QUALITY "quality"
+#define DEBUGCANVAS_ATTRIBUTE_TEXTSIZE "textSize"
+#define DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX "textScaleX"
+#define DEBUGCANVAS_ATTRIBUTE_TEXTSKEWX "textSkewX"
+#define DEBUGCANVAS_ATTRIBUTE_DASHING "dashing"
+#define DEBUGCANVAS_ATTRIBUTE_INTERVALS "intervals"
+#define DEBUGCANVAS_ATTRIBUTE_PHASE "phase"
+#define DEBUGCANVAS_ATTRIBUTE_FILLTYPE "fillType"
+#define DEBUGCANVAS_ATTRIBUTE_VERBS "verbs"
+#define DEBUGCANVAS_ATTRIBUTE_NAME "name"
+#define DEBUGCANVAS_ATTRIBUTE_DATA "data"
+#define DEBUGCANVAS_ATTRIBUTE_VALUES "values"
+#define DEBUGCANVAS_ATTRIBUTE_SHADER "shader"
+#define DEBUGCANVAS_ATTRIBUTE_PATHEFFECT "pathEffect"
+#define DEBUGCANVAS_ATTRIBUTE_MASKFILTER "maskFilter"
+#define DEBUGCANVAS_ATTRIBUTE_XFERMODE "xfermode"
+#define DEBUGCANVAS_ATTRIBUTE_BACKDROP "backdrop"
+#define DEBUGCANVAS_ATTRIBUTE_COLORFILTER "colorfilter"
+#define DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER "imagefilter"
+#define DEBUGCANVAS_ATTRIBUTE_IMAGE "image"
+#define DEBUGCANVAS_ATTRIBUTE_BITMAP "bitmap"
+#define DEBUGCANVAS_ATTRIBUTE_SRC "src"
+#define DEBUGCANVAS_ATTRIBUTE_DST "dst"
+#define DEBUGCANVAS_ATTRIBUTE_CENTER "center"
+#define DEBUGCANVAS_ATTRIBUTE_STRICT "strict"
+#define DEBUGCANVAS_ATTRIBUTE_DESCRIPTION "description"
+#define DEBUGCANVAS_ATTRIBUTE_X "x"
+#define DEBUGCANVAS_ATTRIBUTE_Y "y"
+#define DEBUGCANVAS_ATTRIBUTE_RUNS "runs"
+#define DEBUGCANVAS_ATTRIBUTE_POSITIONS "positions"
+#define DEBUGCANVAS_ATTRIBUTE_GLYPHS "glyphs"
+#define DEBUGCANVAS_ATTRIBUTE_FONT "font"
+#define DEBUGCANVAS_ATTRIBUTE_TYPEFACE "typeface"
+#define DEBUGCANVAS_ATTRIBUTE_CUBICS "cubics"
+#define DEBUGCANVAS_ATTRIBUTE_COLORS "colors"
+#define DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS "textureCoords"
+#define DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY "filterQuality"
+#define DEBUGCANVAS_ATTRIBUTE_STARTANGLE "startAngle"
+#define DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE "sweepAngle"
+#define DEBUGCANVAS_ATTRIBUTE_USECENTER "useCenter"
+#define DEBUGCANVAS_ATTRIBUTE_SHORTDESC "shortDesc"
+#define DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID "uniqueID"
+#define DEBUGCANVAS_ATTRIBUTE_WIDTH "width"
+#define DEBUGCANVAS_ATTRIBUTE_HEIGHT "height"
+#define DEBUGCANVAS_ATTRIBUTE_ALPHA "alpha"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICE "lattice"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT "xCount"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT "yCount"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS "xDivs"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS "yDivs"
+#define DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS "flags"
+#define DEBUGCANVAS_ATTRIBUTE_ZPLANE "zPlane"
+#define DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION "lightPositions"
+#define DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR "ambientColor"
+#define DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR "spotColor"
+#define DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS "lightRadius"
+
+#define DEBUGCANVAS_VERB_MOVE "move"
+#define DEBUGCANVAS_VERB_LINE "line"
+#define DEBUGCANVAS_VERB_QUAD "quad"
+#define DEBUGCANVAS_VERB_CUBIC "cubic"
+#define DEBUGCANVAS_VERB_CONIC "conic"
+#define DEBUGCANVAS_VERB_CLOSE "close"
+
+#define DEBUGCANVAS_STYLE_FILL "fill"
+#define DEBUGCANVAS_STYLE_STROKE "stroke"
+#define DEBUGCANVAS_STYLE_STROKEANDFILL "strokeAndFill"
+
+#define DEBUGCANVAS_POINTMODE_POINTS "points"
+#define DEBUGCANVAS_POINTMODE_LINES "lines"
+#define DEBUGCANVAS_POINTMODE_POLYGON "polygon"
+
+#define DEBUGCANVAS_REGIONOP_DIFFERENCE "difference"
+#define DEBUGCANVAS_REGIONOP_INTERSECT "intersect"
+#define DEBUGCANVAS_REGIONOP_UNION "union"
+#define DEBUGCANVAS_REGIONOP_XOR "xor"
+#define DEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference"
+#define DEBUGCANVAS_REGIONOP_REPLACE "replace"
+
+#define DEBUGCANVAS_BLURSTYLE_NORMAL "normal"
+#define DEBUGCANVAS_BLURSTYLE_SOLID "solid"
+#define DEBUGCANVAS_BLURSTYLE_OUTER "outer"
+#define DEBUGCANVAS_BLURSTYLE_INNER "inner"
+
+#define DEBUGCANVAS_BLURQUALITY_LOW "low"
+#define DEBUGCANVAS_BLURQUALITY_HIGH "high"
+
+#define DEBUGCANVAS_FILLTYPE_WINDING "winding"
+#define DEBUGCANVAS_FILLTYPE_EVENODD "evenOdd"
+#define DEBUGCANVAS_FILLTYPE_INVERSEWINDING "inverseWinding"
+#define DEBUGCANVAS_FILLTYPE_INVERSEEVENODD "inverseEvenOdd"
+
+#define DEBUGCANVAS_CAP_BUTT "butt"
+#define DEBUGCANVAS_CAP_ROUND "round"
+#define DEBUGCANVAS_CAP_SQUARE "square"
+
+#define DEBUGCANVAS_MITER_JOIN "miter"
+#define DEBUGCANVAS_ROUND_JOIN "round"
+#define DEBUGCANVAS_BEVEL_JOIN "bevel"
+
+#define DEBUGCANVAS_COLORTYPE_ARGB4444 "ARGB4444"
+#define DEBUGCANVAS_COLORTYPE_RGBA8888 "RGBA8888"
+#define DEBUGCANVAS_COLORTYPE_BGRA8888 "BGRA8888"
+#define DEBUGCANVAS_COLORTYPE_565 "565"
+#define DEBUGCANVAS_COLORTYPE_GRAY8 "Gray8"
+#define DEBUGCANVAS_COLORTYPE_INDEX8 "Index8"
+#define DEBUGCANVAS_COLORTYPE_ALPHA8 "Alpha8"
+
+#define DEBUGCANVAS_ALPHATYPE_OPAQUE "opaque"
+#define DEBUGCANVAS_ALPHATYPE_PREMUL "premul"
+#define DEBUGCANVAS_ALPHATYPE_UNPREMUL "unpremul"
+#define DEBUGCANVAS_ALPHATYPE_UNKNOWN "unknown"
+
+#define DEBUGCANVAS_FILTERQUALITY_NONE "none"
+#define DEBUGCANVAS_FILTERQUALITY_LOW "low"
+#define DEBUGCANVAS_FILTERQUALITY_MEDIUM "medium"
+#define DEBUGCANVAS_FILTERQUALITY_HIGH "high"
+
+#define DEBUGCANVAS_HINTING_NONE "none"
+#define DEBUGCANVAS_HINTING_SLIGHT "slight"
+#define DEBUGCANVAS_HINTING_NORMAL "normal"
+#define DEBUGCANVAS_HINTING_FULL "full"
+
+#define DEBUGCANVAS_EDGING_ALIAS "alias"
+#define DEBUGCANVAS_EDGING_ANTIALIAS "antialias"
+#define DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS "subpixelantialias"
+
+#define DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC "transparentOccluder"
+#define DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY "geometricOnly"
+
+static SkString* str_append(SkString* str, const SkRect& r) {
+    str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom());
+    return str;
+}
+
+DrawCommand::DrawCommand(OpType type) : fOpType(type), fVisible(true) {}
+
+const char* DrawCommand::GetCommandString(OpType type) {
+    switch (type) {
+        case kBeginDrawPicture_OpType: return "BeginDrawPicture";
+        case kClear_OpType: return "DrawClear";
+        case kClipPath_OpType: return "ClipPath";
+        case kClipRegion_OpType: return "ClipRegion";
+        case kClipRect_OpType: return "ClipRect";
+        case kClipRRect_OpType: return "ClipRRect";
+        case kConcat_OpType: return "Concat";
+        case kDrawAnnotation_OpType: return "DrawAnnotation";
+        case kDrawBitmap_OpType: return "DrawBitmap";
+        case kDrawBitmapLattice_OpType: return "DrawBitmapLattice";
+        case kDrawBitmapNine_OpType: return "DrawBitmapNine";
+        case kDrawBitmapRect_OpType: return "DrawBitmapRect";
+        case kDrawDRRect_OpType: return "DrawDRRect";
+        case kDrawImage_OpType: return "DrawImage";
+        case kDrawImageLattice_OpType: return "DrawImageLattice";
+        case kDrawImageNine_OpType: return "DrawImageNine";
+        case kDrawImageRect_OpType: return "DrawImageRect";
+        case kDrawOval_OpType: return "DrawOval";
+        case kDrawPaint_OpType: return "DrawPaint";
+        case kDrawPatch_OpType: return "DrawPatch";
+        case kDrawPath_OpType: return "DrawPath";
+        case kDrawArc_OpType: return "DrawArc";
+        case kDrawPoints_OpType: return "DrawPoints";
+        case kDrawRect_OpType: return "DrawRect";
+        case kDrawRRect_OpType: return "DrawRRect";
+        case kDrawRegion_OpType: return "DrawRegion";
+        case kDrawShadow_OpType: return "DrawShadow";
+        case kDrawTextBlob_OpType: return "DrawTextBlob";
+        case kDrawVertices_OpType: return "DrawVertices";
+        case kDrawAtlas_OpType: return "DrawAtlas";
+        case kDrawDrawable_OpType: return "DrawDrawable";
+        case kDrawEdgeAAQuad_OpType: return "DrawEdgeAAQuad";
+        case kDrawEdgeAAImageSet_OpType: return "DrawEdgeAAImageSet";
+        case kEndDrawPicture_OpType: return "EndDrawPicture";
+        case kRestore_OpType: return "Restore";
+        case kSave_OpType: return "Save";
+        case kSaveLayer_OpType: return "SaveLayer";
+        case kSetMatrix_OpType: return "SetMatrix";
+        default:
+            SkDebugf("OpType error 0x%08x\n", type);
+            SkASSERT(0);
+            break;
+    }
+    SkDEBUGFAIL("DrawType UNUSED\n");
+    return nullptr;
+}
+
+void DrawCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_COMMAND, this->GetCommandString(fOpType));
+    writer.appendBool(DEBUGCANVAS_ATTRIBUTE_VISIBLE, this->isVisible());
+}
+
+namespace {
+
+void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
+    const SkISize& size = canvas->getBaseLayerSize();
+
+    static const SkScalar kInsetFrac = 0.9f;  // Leave a border around object
+
+    canvas->translate(size.fWidth / 2.0f, size.fHeight / 2.0f);
+    if (bounds.width() > bounds.height()) {
+        canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.width()),
+                      SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.width()));
+    } else {
+        canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.height()),
+                      SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.height()));
+    }
+    canvas->translate(-bounds.centerX(), -bounds.centerY());
+}
+
+void render_path(SkCanvas* canvas, const SkPath& path) {
+    canvas->clear(0xFFFFFFFF);
+
+    const SkRect& bounds = path.getBounds();
+    if (bounds.isEmpty()) {
+        return;
+    }
+
+    SkAutoCanvasRestore acr(canvas, true);
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawPath(path, p);
+}
+
+void render_region(SkCanvas* canvas, const SkRegion& region) {
+    canvas->clear(0xFFFFFFFF);
+
+    const SkIRect& bounds = region.getBounds();
+    if (bounds.isEmpty()) {
+        return;
+    }
+
+    SkAutoCanvasRestore acr(canvas, true);
+    xlate_and_scale_to_bounds(canvas, SkRect::Make(bounds));
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawRegion(region, p);
+}
+
+void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) {
+    const SkISize& size = canvas->getBaseLayerSize();
+
+    SkScalar xScale = SkIntToScalar(size.fWidth - 2) / input.width();
+    SkScalar yScale = SkIntToScalar(size.fHeight - 2) / input.height();
+
+    if (input.width() > input.height()) {
+        yScale *= input.height() / (float)input.width();
+    } else {
+        xScale *= input.width() / (float)input.height();
+    }
+
+    SkRect dst = SkRect::MakeXYWH(
+            SK_Scalar1, SK_Scalar1, xScale * input.width(), yScale * input.height());
+
+    static const int kNumBlocks = 8;
+
+    canvas->clear(0xFFFFFFFF);
+    SkISize block = {canvas->imageInfo().width() / kNumBlocks,
+                     canvas->imageInfo().height() / kNumBlocks};
+    for (int y = 0; y < kNumBlocks; ++y) {
+        for (int x = 0; x < kNumBlocks; ++x) {
+            SkPaint paint;
+            paint.setColor((x + y) % 2 ? SK_ColorLTGRAY : SK_ColorDKGRAY);
+            SkRect r = SkRect::MakeXYWH(SkIntToScalar(x * block.width()),
+                                        SkIntToScalar(y * block.height()),
+                                        SkIntToScalar(block.width()),
+                                        SkIntToScalar(block.height()));
+            canvas->drawRect(r, paint);
+        }
+    }
+
+    canvas->drawBitmapRect(input, dst, nullptr);
+
+    if (srcRect) {
+        SkRect  r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
+                                    srcRect->fTop * yScale + SK_Scalar1,
+                                    srcRect->fRight * xScale + SK_Scalar1,
+                                    srcRect->fBottom * yScale + SK_Scalar1);
+        SkPaint p;
+        p.setColor(SK_ColorRED);
+        p.setStyle(SkPaint::kStroke_Style);
+
+        canvas->drawRect(r, p);
+    }
+}
+
+void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    const SkRect& bounds = rrect.getBounds();
+
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawRRect(rrect, p);
+    canvas->restore();
+}
+
+void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    const SkRect& bounds = outer.getBounds();
+
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawDRRect(outer, inner, p);
+    canvas->restore();
+}
+
+void render_shadow(SkCanvas* canvas, const SkPath& path, SkDrawShadowRec rec) {
+    canvas->clear(0xFFFFFFFF);
+
+    const SkRect& bounds = path.getBounds();
+    if (bounds.isEmpty()) {
+        return;
+    }
+
+    SkAutoCanvasRestore acr(canvas, true);
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    rec.fAmbientColor = SK_ColorBLACK;
+    rec.fSpotColor    = SK_ColorBLACK;
+    canvas->private_draw_shadow_rec(path, rec);
+}
+
+static const char* const gBlendModeMap[] = {
+        "clear",      "src",        "dst",      "srcOver",    "dstOver",   "srcIn",     "dstIn",
+        "srcOut",     "dstOut",     "srcATop",  "dstATop",    "xor",       "plus",      "modulate",
+
+        "screen",
+
+        "overlay",    "darken",     "lighten",  "colorDodge", "colorBurn", "hardLight", "softLight",
+        "difference", "exclusion",  "multiply",
+
+        "hue",        "saturation", "color",    "luminosity",
+};
+
+static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLastMode) + 1,
+              "blendMode mismatch");
+static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLuminosity) + 1,
+              "blendMode mismatch");
+
+void apply_paint_blend_mode(const SkPaint& paint, SkJSONWriter& writer) {
+    const auto mode = paint.getBlendMode();
+    if (mode != SkBlendMode::kSrcOver) {
+        SkASSERT(static_cast<size_t>(mode) < SK_ARRAY_COUNT(gBlendModeMap));
+        writer.appendString(DEBUGCANVAS_ATTRIBUTE_BLENDMODE,
+                            gBlendModeMap[static_cast<size_t>(mode)]);
+    }
+}
+
+};  // namespace
+
+void DrawCommand::MakeJsonColor(SkJSONWriter& writer, const SkColor color) {
+    writer.beginArray(nullptr, false);
+    writer.appendS32(SkColorGetA(color));
+    writer.appendS32(SkColorGetR(color));
+    writer.appendS32(SkColorGetG(color));
+    writer.appendS32(SkColorGetB(color));
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonColor4f(SkJSONWriter& writer, const SkColor4f& color) {
+    writer.beginArray(nullptr, false);
+    writer.appendFloat(color.fA);
+    writer.appendFloat(color.fR);
+    writer.appendFloat(color.fG);
+    writer.appendFloat(color.fB);
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, const SkPoint& point) {
+    writer.beginArray(nullptr, false);
+    writer.appendFloat(point.x());
+    writer.appendFloat(point.y());
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, SkScalar x, SkScalar y) {
+    writer.beginArray(nullptr, false);
+    writer.appendFloat(x);
+    writer.appendFloat(y);
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint3(SkJSONWriter& writer, const SkPoint3& point) {
+    writer.beginArray(nullptr, false);
+    writer.appendFloat(point.x());
+    writer.appendFloat(point.y());
+    writer.appendFloat(point.z());
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonRect(SkJSONWriter& writer, const SkRect& rect) {
+    writer.beginArray(nullptr, false);
+    writer.appendFloat(rect.left());
+    writer.appendFloat(rect.top());
+    writer.appendFloat(rect.right());
+    writer.appendFloat(rect.bottom());
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonIRect(SkJSONWriter& writer, const SkIRect& rect) {
+    writer.beginArray(nullptr, false);
+    writer.appendS32(rect.left());
+    writer.appendS32(rect.top());
+    writer.appendS32(rect.right());
+    writer.appendS32(rect.bottom());
+    writer.endArray();
+}
+
+static void make_json_rrect(SkJSONWriter& writer, const SkRRect& rrect) {
+    writer.beginArray(nullptr, false);
+    DrawCommand::MakeJsonRect(writer, rrect.rect());
+    DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperLeft_Corner));
+    DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperRight_Corner));
+    DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerRight_Corner));
+    DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerLeft_Corner));
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonMatrix(SkJSONWriter& writer, const SkMatrix& matrix) {
+    writer.beginArray();
+    for (int r = 0; r < 3; ++r) {
+        writer.beginArray(nullptr, false);
+        for (int c = 0; c < 3; ++c) {
+            writer.appendFloat(matrix[r * 3 + c]);
+        }
+        writer.endArray();
+    }
+    writer.endArray();
+}
+
+void DrawCommand::MakeJsonPath(SkJSONWriter& writer, const SkPath& path) {
+    writer.beginObject();
+    switch (path.getFillType()) {
+        case SkPath::kWinding_FillType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_WINDING);
+            break;
+        case SkPath::kEvenOdd_FillType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_EVENODD);
+            break;
+        case SkPath::kInverseWinding_FillType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE,
+                                DEBUGCANVAS_FILLTYPE_INVERSEWINDING);
+            break;
+        case SkPath::kInverseEvenOdd_FillType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE,
+                                DEBUGCANVAS_FILLTYPE_INVERSEEVENODD);
+            break;
+    }
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_VERBS);
+    SkPath::Iter iter(path, false);
+    SkPoint      pts[4];
+    SkPath::Verb verb;
+    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+        if (verb == SkPath::kClose_Verb) {
+            writer.appendString(DEBUGCANVAS_VERB_CLOSE);
+            continue;
+        }
+        writer.beginObject();  // verb
+        switch (verb) {
+            case SkPath::kLine_Verb: {
+                writer.appendName(DEBUGCANVAS_VERB_LINE);
+                MakeJsonPoint(writer, pts[1]);
+                break;
+            }
+            case SkPath::kQuad_Verb: {
+                writer.beginArray(DEBUGCANVAS_VERB_QUAD);
+                MakeJsonPoint(writer, pts[1]);
+                MakeJsonPoint(writer, pts[2]);
+                writer.endArray();  // quad coords
+                break;
+            }
+            case SkPath::kCubic_Verb: {
+                writer.beginArray(DEBUGCANVAS_VERB_CUBIC);
+                MakeJsonPoint(writer, pts[1]);
+                MakeJsonPoint(writer, pts[2]);
+                MakeJsonPoint(writer, pts[3]);
+                writer.endArray();  // cubic coords
+                break;
+            }
+            case SkPath::kConic_Verb: {
+                writer.beginArray(DEBUGCANVAS_VERB_CONIC);
+                MakeJsonPoint(writer, pts[1]);
+                MakeJsonPoint(writer, pts[2]);
+                writer.appendFloat(iter.conicWeight());
+                writer.endArray();  // conic coords
+                break;
+            }
+            case SkPath::kMove_Verb: {
+                writer.appendName(DEBUGCANVAS_VERB_MOVE);
+                MakeJsonPoint(writer, pts[0]);
+                break;
+            }
+            case SkPath::kClose_Verb:
+            case SkPath::kDone_Verb:
+                // Unreachable
+                break;
+        }
+        writer.endObject();  // verb
+    }
+    writer.endArray();   // verbs
+    writer.endObject();  // path
+}
+
+void DrawCommand::MakeJsonRegion(SkJSONWriter& writer, const SkRegion& region) {
+    // TODO: Actually serialize the rectangles, rather than just devolving to path
+    SkPath path;
+    region.getBoundaryPath(&path);
+    MakeJsonPath(writer, path);
+}
+
+static const char* regionop_name(SkClipOp op) {
+    switch (op) {
+        case kDifference_SkClipOp: return DEBUGCANVAS_REGIONOP_DIFFERENCE;
+        case kIntersect_SkClipOp: return DEBUGCANVAS_REGIONOP_INTERSECT;
+        case kUnion_SkClipOp: return DEBUGCANVAS_REGIONOP_UNION;
+        case kXOR_SkClipOp: return DEBUGCANVAS_REGIONOP_XOR;
+        case kReverseDifference_SkClipOp: return DEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE;
+        case kReplace_SkClipOp: return DEBUGCANVAS_REGIONOP_REPLACE;
+        default: SkASSERT(false); return "<invalid region op>";
+    }
+}
+
+static const char* pointmode_name(SkCanvas::PointMode mode) {
+    switch (mode) {
+        case SkCanvas::kPoints_PointMode: return DEBUGCANVAS_POINTMODE_POINTS;
+        case SkCanvas::kLines_PointMode: return DEBUGCANVAS_POINTMODE_LINES;
+        case SkCanvas::kPolygon_PointMode: return DEBUGCANVAS_POINTMODE_POLYGON;
+        default: SkASSERT(false); return "<invalid point mode>";
+    }
+}
+
+static void store_scalar(SkJSONWriter& writer,
+                         const char*   key,
+                         SkScalar      value,
+                         SkScalar      defaultValue) {
+    if (value != defaultValue) {
+        writer.appendFloat(key, value);
+    }
+}
+
+static void store_bool(SkJSONWriter& writer, const char* key, bool value, bool defaultValue) {
+    if (value != defaultValue) {
+        writer.appendBool(key, value);
+    }
+}
+
+static SkString encode_data(const void*     bytes,
+                            size_t          count,
+                            const char*     contentType,
+                            UrlDataManager& urlDataManager) {
+    sk_sp<SkData> data(SkData::MakeWithCopy(bytes, count));
+    return urlDataManager.addData(data.get(), contentType);
+}
+
+void DrawCommand::flatten(const SkFlattenable* flattenable,
+                          SkJSONWriter&        writer,
+                          UrlDataManager&      urlDataManager) {
+    SkBinaryWriteBuffer buffer;
+    flattenable->flatten(buffer);
+    void* data = sk_malloc_throw(buffer.bytesWritten());
+    buffer.writeToMemory(data);
+    SkString url =
+            encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_NAME, flattenable->getTypeName());
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_VALUES);
+    JsonWriteBuffer jsonBuffer(&writer, &urlDataManager);
+    flattenable->flatten(jsonBuffer);
+    writer.endObject();  // values
+
+    sk_free(data);
+}
+
+void DrawCommand::WritePNG(SkBitmap bitmap, SkWStream& out) {
+    SkPixmap pm;
+    SkAssertResult(bitmap.peekPixels(&pm));
+
+    SkPngEncoder::Options options;
+    options.fZLibLevel   = 1;
+    options.fFilterFlags = SkPngEncoder::FilterFlag::kNone;
+    SkPngEncoder::Encode(&out, pm, options);
+}
+
+bool DrawCommand::flatten(const SkImage&  image,
+                          SkJSONWriter&   writer,
+                          UrlDataManager& urlDataManager) {
+    size_t       rowBytes = 4 * image.width();
+    SkAutoMalloc buffer(rowBytes * image.height());
+    SkImageInfo  dstInfo =
+            SkImageInfo::Make(image.dimensions(), kN32_SkColorType, kPremul_SkAlphaType);
+    if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) {
+        SkDebugf("readPixels failed\n");
+        return false;
+    }
+
+    SkBitmap bm;
+    bm.installPixels(dstInfo, buffer.get(), rowBytes);
+
+    SkDynamicMemoryWStream out;
+    DrawCommand::WritePNG(bm, out);
+    sk_sp<SkData> encoded = out.detachAsData();
+    SkString      url = encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+    return true;
+}
+
+static const char* color_type_name(SkColorType colorType) {
+    switch (colorType) {
+        case kARGB_4444_SkColorType: return DEBUGCANVAS_COLORTYPE_ARGB4444;
+        case kRGBA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_RGBA8888;
+        case kBGRA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_BGRA8888;
+        case kRGB_565_SkColorType: return DEBUGCANVAS_COLORTYPE_565;
+        case kGray_8_SkColorType: return DEBUGCANVAS_COLORTYPE_GRAY8;
+        case kAlpha_8_SkColorType: return DEBUGCANVAS_COLORTYPE_ALPHA8;
+        default: SkASSERT(false); return DEBUGCANVAS_COLORTYPE_RGBA8888;
+    }
+}
+
+static const char* alpha_type_name(SkAlphaType alphaType) {
+    switch (alphaType) {
+        case kOpaque_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_OPAQUE;
+        case kPremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_PREMUL;
+        case kUnpremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_UNPREMUL;
+        default: SkASSERT(false); return DEBUGCANVAS_ALPHATYPE_OPAQUE;
+    }
+}
+
+bool DrawCommand::flatten(const SkBitmap& bitmap,
+                          SkJSONWriter&   writer,
+                          UrlDataManager& urlDataManager) {
+    sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap));
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_COLOR, color_type_name(bitmap.colorType()));
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, alpha_type_name(bitmap.alphaType()));
+    bool success = flatten(*image, writer, urlDataManager);
+    return success;
+}
+
+static void apply_font_hinting(const SkFont& font, SkJSONWriter& writer) {
+    SkFontHinting hinting = font.getHinting();
+    if (hinting != SkPaintDefaults_Hinting) {
+        switch (hinting) {
+            case SkFontHinting::kNone:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NONE);
+                break;
+            case SkFontHinting::kSlight:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_SLIGHT);
+                break;
+            case SkFontHinting::kNormal:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NORMAL);
+                break;
+            case SkFontHinting::kFull:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_FULL);
+                break;
+        }
+    }
+}
+
+static void apply_font_edging(const SkFont& font, SkJSONWriter& writer) {
+    switch (font.getEdging()) {
+        case SkFont::Edging::kAlias:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ALIAS);
+            break;
+        case SkFont::Edging::kAntiAlias:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ANTIALIAS);
+            break;
+        case SkFont::Edging::kSubpixelAntiAlias:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS);
+            break;
+    }
+}
+
+static void apply_paint_color(const SkPaint& paint, SkJSONWriter& writer) {
+    SkColor color = paint.getColor();
+    if (color != SK_ColorBLACK) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR);
+        DrawCommand::MakeJsonColor(writer, color);
+    }
+}
+
+static void apply_paint_style(const SkPaint& paint, SkJSONWriter& writer) {
+    SkPaint::Style style = paint.getStyle();
+    if (style != SkPaint::kFill_Style) {
+        switch (style) {
+            case SkPaint::kStroke_Style: {
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKE);
+                break;
+            }
+            case SkPaint::kStrokeAndFill_Style: {
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKEANDFILL);
+                break;
+            }
+            default: SkASSERT(false);
+        }
+    }
+}
+
+static void apply_paint_cap(const SkPaint& paint, SkJSONWriter& writer) {
+    SkPaint::Cap cap = paint.getStrokeCap();
+    if (cap != SkPaint::kDefault_Cap) {
+        switch (cap) {
+            case SkPaint::kButt_Cap:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_BUTT);
+                break;
+            case SkPaint::kRound_Cap:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_ROUND);
+                break;
+            case SkPaint::kSquare_Cap:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_SQUARE);
+                break;
+            default: SkASSERT(false);
+        }
+    }
+}
+
+static void apply_paint_join(const SkPaint& paint, SkJSONWriter& writer) {
+    SkPaint::Join join = paint.getStrokeJoin();
+    if (join != SkPaint::kDefault_Join) {
+        switch (join) {
+            case SkPaint::kMiter_Join:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_MITER_JOIN);
+                break;
+            case SkPaint::kRound_Join:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_ROUND_JOIN);
+                break;
+            case SkPaint::kBevel_Join:
+                writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_BEVEL_JOIN);
+                break;
+            default: SkASSERT(false);
+        }
+    }
+}
+
+static void apply_paint_filterquality(const SkPaint& paint, SkJSONWriter& writer) {
+    SkFilterQuality quality = paint.getFilterQuality();
+    switch (quality) {
+        case kNone_SkFilterQuality: break;
+        case kLow_SkFilterQuality:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY, DEBUGCANVAS_FILTERQUALITY_LOW);
+            break;
+        case kMedium_SkFilterQuality:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
+                                DEBUGCANVAS_FILTERQUALITY_MEDIUM);
+            break;
+        case kHigh_SkFilterQuality:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
+                                DEBUGCANVAS_FILTERQUALITY_HIGH);
+            break;
+    }
+}
+
+static void apply_paint_maskfilter(const SkPaint&  paint,
+                                   SkJSONWriter&   writer,
+                                   UrlDataManager& urlDataManager) {
+    SkMaskFilter* maskFilter = paint.getMaskFilter();
+    if (maskFilter != nullptr) {
+        SkMaskFilterBase::BlurRec blurRec;
+        if (as_MFB(maskFilter)->asABlur(&blurRec)) {
+            writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BLUR);
+            writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SIGMA, blurRec.fSigma);
+            switch (blurRec.fStyle) {
+                case SkBlurStyle::kNormal_SkBlurStyle:
+                    writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_NORMAL);
+                    break;
+                case SkBlurStyle::kSolid_SkBlurStyle:
+                    writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_SOLID);
+                    break;
+                case SkBlurStyle::kOuter_SkBlurStyle:
+                    writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_OUTER);
+                    break;
+                case SkBlurStyle::kInner_SkBlurStyle:
+                    writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_INNER);
+                    break;
+                default: SkASSERT(false);
+            }
+            writer.endObject();  // blur
+        } else {
+            writer.beginObject(DEBUGCANVAS_ATTRIBUTE_MASKFILTER);
+            DrawCommand::flatten(maskFilter, writer, urlDataManager);
+            writer.endObject();  // maskFilter
+        }
+    }
+}
+
+static void apply_paint_patheffect(const SkPaint&  paint,
+                                   SkJSONWriter&   writer,
+                                   UrlDataManager& urlDataManager) {
+    SkPathEffect* pathEffect = paint.getPathEffect();
+    if (pathEffect != nullptr) {
+        SkPathEffect::DashInfo dashInfo;
+        SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
+        if (dashType == SkPathEffect::kDash_DashType) {
+            dashInfo.fIntervals = (SkScalar*)sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
+            pathEffect->asADash(&dashInfo);
+            writer.beginObject(DEBUGCANVAS_ATTRIBUTE_DASHING);
+            writer.beginArray(DEBUGCANVAS_ATTRIBUTE_INTERVALS, false);
+            for (int32_t i = 0; i < dashInfo.fCount; i++) {
+                writer.appendFloat(dashInfo.fIntervals[i]);
+            }
+            writer.endArray();  // intervals
+            sk_free(dashInfo.fIntervals);
+            writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_PHASE, dashInfo.fPhase);
+            writer.endObject();  // dashing
+        } else {
+            writer.beginObject(DEBUGCANVAS_ATTRIBUTE_PATHEFFECT);
+            DrawCommand::flatten(pathEffect, writer, urlDataManager);
+            writer.endObject();  // pathEffect
+        }
+    }
+}
+
+static void apply_font_typeface(const SkFont&   font,
+                                SkJSONWriter&   writer,
+                                UrlDataManager& urlDataManager) {
+    SkTypeface* typeface = font.getTypefaceOrDefault();
+    if (typeface != nullptr) {
+        writer.beginObject(DEBUGCANVAS_ATTRIBUTE_TYPEFACE);
+        SkDynamicMemoryWStream buffer;
+        typeface->serialize(&buffer);
+        void* data = sk_malloc_throw(buffer.bytesWritten());
+        buffer.copyTo(data);
+        SkString url = encode_data(
+                data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
+        writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+        sk_free(data);
+        writer.endObject();
+    }
+}
+
+static void apply_flattenable(const char*     key,
+                              SkFlattenable*  flattenable,
+                              SkJSONWriter&   writer,
+                              UrlDataManager& urlDataManager) {
+    if (flattenable != nullptr) {
+        writer.beginObject(key);
+        DrawCommand::flatten(flattenable, writer, urlDataManager);
+        writer.endObject();
+    }
+}
+
+void DrawCommand::MakeJsonPaint(SkJSONWriter&   writer,
+                                const SkPaint&  paint,
+                                UrlDataManager& urlDataManager) {
+    writer.beginObject();
+    store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
+    store_scalar(writer,
+                 DEBUGCANVAS_ATTRIBUTE_STROKEMITER,
+                 paint.getStrokeMiter(),
+                 SkPaintDefaults_MiterLimit);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false);
+
+    apply_paint_color(paint, writer);
+    apply_paint_style(paint, writer);
+    apply_paint_blend_mode(paint, writer);
+    apply_paint_cap(paint, writer);
+    apply_paint_join(paint, writer);
+    apply_paint_filterquality(paint, writer);
+    apply_paint_patheffect(paint, writer, urlDataManager);
+    apply_paint_maskfilter(paint, writer, urlDataManager);
+    apply_flattenable(DEBUGCANVAS_ATTRIBUTE_SHADER, paint.getShader(), writer, urlDataManager);
+    apply_flattenable(
+            DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER, paint.getImageFilter(), writer, urlDataManager);
+    apply_flattenable(
+            DEBUGCANVAS_ATTRIBUTE_COLORFILTER, paint.getColorFilter(), writer, urlDataManager);
+    writer.endObject();  // paint
+}
+
+static void MakeJsonFont(const SkFont& font, SkJSONWriter& writer, UrlDataManager& urlDataManager) {
+    writer.beginObject();
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, font.isEmbolden(), false);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_LINEARTEXT, font.isLinearMetrics(), false);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, font.isSubpixel(), false);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, font.isEmbeddedBitmaps(), false);
+    store_bool(writer, DEBUGCANVAS_ATTRIBUTE_AUTOHINTING, font.isForceAutoHinting(), false);
+
+    store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSIZE, font.getSize(), SkPaintDefaults_TextSize);
+    store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getScaleX(), SK_Scalar1);
+    store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getSkewX(), 0.0f);
+    apply_font_edging(font, writer);
+    apply_font_hinting(font, writer);
+    apply_font_typeface(font, writer, urlDataManager);
+    writer.endObject();  // font
+}
+
+void DrawCommand::MakeJsonLattice(SkJSONWriter& writer, const SkCanvas::Lattice& lattice) {
+    writer.beginObject();
+    writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT, lattice.fXCount);
+    writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT, lattice.fYCount);
+    if (nullptr != lattice.fBounds) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS);
+        MakeJsonIRect(writer, *lattice.fBounds);
+    }
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS);
+    for (int i = 0; i < lattice.fXCount; i++) {
+        writer.appendS32(lattice.fXDivs[i]);
+    }
+    writer.endArray();  // xdivs
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS);
+    for (int i = 0; i < lattice.fYCount; i++) {
+        writer.appendS32(lattice.fYDivs[i]);
+    }
+    writer.endArray();  // ydivs
+    if (nullptr != lattice.fRectTypes) {
+        writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS);
+        int flagCount = 0;
+        for (int row = 0; row < lattice.fYCount + 1; row++) {
+            writer.beginArray();
+            for (int column = 0; column < lattice.fXCount + 1; column++) {
+                writer.appendS32(lattice.fRectTypes[flagCount++]);
+            }
+            writer.endArray();  // row
+        }
+        writer.endArray();
+    }
+    writer.endObject();
+}
+
+ClearCommand::ClearCommand(SkColor color) : INHERITED(kClear_OpType) { fColor = color; }
+
+void ClearCommand::execute(SkCanvas* canvas) const { canvas->clear(fColor); }
+
+void ClearCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR);
+    MakeJsonColor(writer, fColor);
+}
+
+ClipPathCommand::ClipPathCommand(const SkPath& path, SkClipOp op, bool doAA)
+        : INHERITED(kClipPath_OpType) {
+    fPath = path;
+    fOp   = op;
+    fDoAA = doAA;
+}
+
+void ClipPathCommand::execute(SkCanvas* canvas) const { canvas->clipPath(fPath, fOp, fDoAA); }
+
+bool ClipPathCommand::render(SkCanvas* canvas) const {
+    render_path(canvas, fPath);
+    return true;
+}
+
+void ClipPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
+    MakeJsonPath(writer, fPath);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+    writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+}
+
+ClipRegionCommand::ClipRegionCommand(const SkRegion& region, SkClipOp op)
+        : INHERITED(kClipRegion_OpType) {
+    fRegion = region;
+    fOp     = op;
+}
+
+void ClipRegionCommand::execute(SkCanvas* canvas) const { canvas->clipRegion(fRegion, fOp); }
+
+void ClipRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION);
+    MakeJsonRegion(writer, fRegion);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+}
+
+ClipRectCommand::ClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
+        : INHERITED(kClipRect_OpType) {
+    fRect = rect;
+    fOp   = op;
+    fDoAA = doAA;
+}
+
+void ClipRectCommand::execute(SkCanvas* canvas) const { canvas->clipRect(fRect, fOp, fDoAA); }
+
+void ClipRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, fRect);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+    writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
+}
+
+ClipRRectCommand::ClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA)
+        : INHERITED(kClipRRect_OpType) {
+    fRRect = rrect;
+    fOp    = op;
+    fDoAA  = doAA;
+}
+
+void ClipRRectCommand::execute(SkCanvas* canvas) const { canvas->clipRRect(fRRect, fOp, fDoAA); }
+
+bool ClipRRectCommand::render(SkCanvas* canvas) const {
+    render_rrect(canvas, fRRect);
+    return true;
+}
+
+void ClipRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    make_json_rrect(writer, fRRect);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+    writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+}
+
+ConcatCommand::ConcatCommand(const SkMatrix& matrix) : INHERITED(kConcat_OpType) {
+    fMatrix = matrix;
+}
+
+void ConcatCommand::execute(SkCanvas* canvas) const { canvas->concat(fMatrix); }
+
+void ConcatCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX);
+    MakeJsonMatrix(writer, fMatrix);
+}
+
+////
+
+DrawAnnotationCommand::DrawAnnotationCommand(const SkRect& rect,
+                                             const char    key[],
+                                             sk_sp<SkData> value)
+        : INHERITED(kDrawAnnotation_OpType), fRect(rect), fKey(key), fValue(std::move(value)) {}
+
+void DrawAnnotationCommand::execute(SkCanvas* canvas) const {
+    canvas->drawAnnotation(fRect, fKey.c_str(), fValue);
+}
+
+void DrawAnnotationCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, fRect);
+    writer.appendString("key", fKey.c_str());
+    if (fValue.get()) {
+        // TODO: dump out the "value"
+    }
+
+    SkString desc;
+    str_append(&desc, fRect)->appendf(" %s", fKey.c_str());
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, desc.c_str());
+}
+
+////
+
+DrawBitmapCommand::DrawBitmapCommand(const SkBitmap& bitmap,
+                                     SkScalar        left,
+                                     SkScalar        top,
+                                     const SkPaint*  paint)
+        : INHERITED(kDrawBitmap_OpType), fBitmap(bitmap), fLeft(left), fTop(top), fPaint(paint) {}
+
+void DrawBitmapCommand::execute(SkCanvas* canvas) const {
+    canvas->drawBitmap(fBitmap, fLeft, fTop, fPaint.getMaybeNull());
+}
+
+bool DrawBitmapCommand::render(SkCanvas* canvas) const {
+    render_bitmap(canvas, fBitmap);
+    return true;
+}
+
+void DrawBitmapCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BITMAP);
+    flatten(fBitmap, writer, urlDataManager);
+    writer.endObject();
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonPoint(writer, fLeft, fTop);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+}
+
+DrawBitmapLatticeCommand::DrawBitmapLatticeCommand(const SkBitmap&          bitmap,
+                                                   const SkCanvas::Lattice& lattice,
+                                                   const SkRect&            dst,
+                                                   const SkPaint*           paint)
+        : INHERITED(kDrawBitmapLattice_OpType)
+        , fBitmap(bitmap)
+        , fLattice(lattice)
+        , fDst(dst)
+        , fPaint(paint) {}
+
+void DrawBitmapLatticeCommand::execute(SkCanvas* canvas) const {
+    canvas->drawBitmapLattice(fBitmap, fLattice, fDst, fPaint.getMaybeNull());
+}
+
+bool DrawBitmapLatticeCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(canvas, fDst);
+
+    this->execute(canvas);
+    return true;
+}
+
+void DrawBitmapLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BITMAP);
+    flatten(fBitmap, writer, urlDataManager);
+    writer.endObject();  // bitmap
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_LATTICE);
+    MakeJsonLattice(writer, fLattice);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+DrawBitmapNineCommand::DrawBitmapNineCommand(const SkBitmap& bitmap,
+                                             const SkIRect&  center,
+                                             const SkRect&   dst,
+                                             const SkPaint*  paint)
+        : INHERITED(kDrawBitmapNine_OpType)
+        , fBitmap(bitmap)
+        , fCenter(center)
+        , fDst(dst)
+        , fPaint(paint) {}
+
+void DrawBitmapNineCommand::execute(SkCanvas* canvas) const {
+    canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaint.getMaybeNull());
+}
+
+bool DrawBitmapNineCommand::render(SkCanvas* canvas) const {
+    SkRect tmp = SkRect::Make(fCenter);
+    render_bitmap(canvas, fBitmap, &tmp);
+    return true;
+}
+
+void DrawBitmapNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BITMAP);
+    flatten(fBitmap, writer, urlDataManager);
+    writer.endObject();  // bitmap
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_CENTER);
+    MakeJsonIRect(writer, fCenter);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+}
+
+DrawBitmapRectCommand::DrawBitmapRectCommand(const SkBitmap&             bitmap,
+                                             const SkRect*               src,
+                                             const SkRect&               dst,
+                                             const SkPaint*              paint,
+                                             SkCanvas::SrcRectConstraint constraint)
+        : INHERITED(kDrawBitmapRect_OpType)
+        , fBitmap(bitmap)
+        , fSrc(src)
+        , fDst(dst)
+        , fPaint(paint)
+        , fConstraint(constraint) {}
+
+void DrawBitmapRectCommand::execute(SkCanvas* canvas) const {
+    canvas->legacy_drawBitmapRect(
+            fBitmap, fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
+}
+
+bool DrawBitmapRectCommand::render(SkCanvas* canvas) const {
+    render_bitmap(canvas, fBitmap, fSrc.getMaybeNull());
+    return true;
+}
+
+void DrawBitmapRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BITMAP);
+    flatten(fBitmap, writer, urlDataManager);
+    writer.endObject();  // bitmap
+
+    if (fSrc.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC);
+        MakeJsonRect(writer, *fSrc);
+    }
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+    if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
+        writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true);
+    }
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+DrawImageCommand::DrawImageCommand(const SkImage* image,
+                                   SkScalar       left,
+                                   SkScalar       top,
+                                   const SkPaint* paint)
+        : INHERITED(kDrawImage_OpType)
+        , fImage(SkRef(image))
+        , fLeft(left)
+        , fTop(top)
+        , fPaint(paint) {}
+
+void DrawImageCommand::execute(SkCanvas* canvas) const {
+    canvas->drawImage(fImage.get(), fLeft, fTop, fPaint.getMaybeNull());
+}
+
+bool DrawImageCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(
+            canvas,
+            SkRect::MakeXYWH(
+                    fLeft, fTop, SkIntToScalar(fImage->width()), SkIntToScalar(fImage->height())));
+    this->execute(canvas);
+    return true;
+}
+
+void DrawImageCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
+    flatten(*fImage, writer, urlDataManager);
+    writer.endObject();  // image
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonPoint(writer, fLeft, fTop);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+
+    writer.appendU32(DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID, fImage->uniqueID());
+    writer.appendS32(DEBUGCANVAS_ATTRIBUTE_WIDTH, fImage->width());
+    writer.appendS32(DEBUGCANVAS_ATTRIBUTE_HEIGHT, fImage->height());
+    switch (fImage->alphaType()) {
+        case kOpaque_SkAlphaType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_OPAQUE);
+            break;
+        case kPremul_SkAlphaType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_PREMUL);
+            break;
+        case kUnpremul_SkAlphaType:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNPREMUL);
+            break;
+        default:
+            writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNKNOWN);
+            break;
+    }
+}
+
+DrawImageLatticeCommand::DrawImageLatticeCommand(const SkImage*           image,
+                                                 const SkCanvas::Lattice& lattice,
+                                                 const SkRect&            dst,
+                                                 const SkPaint*           paint)
+        : INHERITED(kDrawImageLattice_OpType)
+        , fImage(SkRef(image))
+        , fLattice(lattice)
+        , fDst(dst)
+        , fPaint(paint) {}
+
+void DrawImageLatticeCommand::execute(SkCanvas* canvas) const {
+    canvas->drawImageLattice(fImage.get(), fLattice, fDst, fPaint.getMaybeNull());
+}
+
+bool DrawImageLatticeCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(canvas, fDst);
+
+    this->execute(canvas);
+    return true;
+}
+
+void DrawImageLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
+    flatten(*fImage, writer, urlDataManager);
+    writer.endObject();  // image
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_LATTICE);
+    MakeJsonLattice(writer, fLattice);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+DrawImageRectCommand::DrawImageRectCommand(const SkImage*              image,
+                                           const SkRect*               src,
+                                           const SkRect&               dst,
+                                           const SkPaint*              paint,
+                                           SkCanvas::SrcRectConstraint constraint)
+        : INHERITED(kDrawImageRect_OpType)
+        , fImage(SkRef(image))
+        , fSrc(src)
+        , fDst(dst)
+        , fPaint(paint)
+        , fConstraint(constraint) {}
+
+void DrawImageRectCommand::execute(SkCanvas* canvas) const {
+    canvas->legacy_drawImageRect(
+            fImage.get(), fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
+}
+
+bool DrawImageRectCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(canvas, fDst);
+
+    this->execute(canvas);
+    return true;
+}
+
+void DrawImageRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
+    flatten(*fImage, writer, urlDataManager);
+    writer.endObject();  // image
+
+    if (fSrc.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC);
+        MakeJsonRect(writer, *fSrc);
+    }
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+    if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
+        writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true);
+    }
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+DrawImageNineCommand::DrawImageNineCommand(const SkImage* image,
+                                           const SkIRect& center,
+                                           const SkRect&  dst,
+                                           const SkPaint* paint)
+        : INHERITED(kDrawImageNine_OpType)
+        , fImage(SkRef(image))
+        , fCenter(center)
+        , fDst(dst)
+        , fPaint(paint) {}
+
+void DrawImageNineCommand::execute(SkCanvas* canvas) const {
+    canvas->drawImageNine(fImage.get(), fCenter, fDst, fPaint.getMaybeNull());
+}
+
+bool DrawImageNineCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(canvas, fDst);
+
+    this->execute(canvas);
+    return true;
+}
+
+void DrawImageNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
+    flatten(*fImage, writer, urlDataManager);
+    writer.endObject();  // image
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_CENTER);
+    MakeJsonIRect(writer, fCenter);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
+    MakeJsonRect(writer, fDst);
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+}
+
+DrawOvalCommand::DrawOvalCommand(const SkRect& oval, const SkPaint& paint)
+        : INHERITED(kDrawOval_OpType) {
+    fOval  = oval;
+    fPaint = paint;
+}
+
+void DrawOvalCommand::execute(SkCanvas* canvas) const { canvas->drawOval(fOval, fPaint); }
+
+bool DrawOvalCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    xlate_and_scale_to_bounds(canvas, fOval);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawOval(fOval, p);
+    canvas->restore();
+
+    return true;
+}
+
+void DrawOvalCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, fOval);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawArcCommand::DrawArcCommand(const SkRect&  oval,
+                               SkScalar       startAngle,
+                               SkScalar       sweepAngle,
+                               bool           useCenter,
+                               const SkPaint& paint)
+        : INHERITED(kDrawArc_OpType) {
+    fOval       = oval;
+    fStartAngle = startAngle;
+    fSweepAngle = sweepAngle;
+    fUseCenter  = useCenter;
+    fPaint      = paint;
+}
+
+void DrawArcCommand::execute(SkCanvas* canvas) const {
+    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint);
+}
+
+bool DrawArcCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    xlate_and_scale_to_bounds(canvas, fOval);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p);
+    canvas->restore();
+
+    return true;
+}
+
+void DrawArcCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, fOval);
+    writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_STARTANGLE, fStartAngle);
+    writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE, fSweepAngle);
+    writer.appendBool(DEBUGCANVAS_ATTRIBUTE_USECENTER, fUseCenter);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawPaintCommand::DrawPaintCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) {
+    fPaint = paint;
+}
+
+void DrawPaintCommand::execute(SkCanvas* canvas) const { canvas->drawPaint(fPaint); }
+
+bool DrawPaintCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    canvas->drawPaint(fPaint);
+    return true;
+}
+
+void DrawPaintCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawBehindCommand::DrawBehindCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) {
+    fPaint = paint;
+}
+
+void DrawBehindCommand::execute(SkCanvas* canvas) const {
+    SkCanvasPriv::DrawBehind(canvas, fPaint);
+}
+
+bool DrawBehindCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    SkCanvasPriv::DrawBehind(canvas, fPaint);
+    return true;
+}
+
+void DrawBehindCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawPathCommand::DrawPathCommand(const SkPath& path, const SkPaint& paint)
+        : INHERITED(kDrawPath_OpType) {
+    fPath  = path;
+    fPaint = paint;
+}
+
+void DrawPathCommand::execute(SkCanvas* canvas) const { canvas->drawPath(fPath, fPaint); }
+
+bool DrawPathCommand::render(SkCanvas* canvas) const {
+    render_path(canvas, fPath);
+    return true;
+}
+
+void DrawPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
+    MakeJsonPath(writer, fPath);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawRegionCommand::DrawRegionCommand(const SkRegion& region, const SkPaint& paint)
+        : INHERITED(kDrawRegion_OpType) {
+    fRegion = region;
+    fPaint  = paint;
+}
+
+void DrawRegionCommand::execute(SkCanvas* canvas) const { canvas->drawRegion(fRegion, fPaint); }
+
+bool DrawRegionCommand::render(SkCanvas* canvas) const {
+    render_region(canvas, fRegion);
+    return true;
+}
+
+void DrawRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION);
+    MakeJsonRegion(writer, fRegion);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+BeginDrawPictureCommand::BeginDrawPictureCommand(const SkPicture* picture,
+                                                 const SkMatrix*  matrix,
+                                                 const SkPaint*   paint)
+        : INHERITED(kBeginDrawPicture_OpType)
+        , fPicture(SkRef(picture))
+        , fMatrix(matrix)
+        , fPaint(paint) {}
+
+void BeginDrawPictureCommand::execute(SkCanvas* canvas) const {
+    if (fPaint.isValid()) {
+        SkRect bounds = fPicture->cullRect();
+        if (fMatrix.isValid()) {
+            fMatrix->mapRect(&bounds);
+        }
+        canvas->saveLayer(&bounds, fPaint.get());
+    }
+
+    if (fMatrix.isValid()) {
+        if (!fPaint.isValid()) {
+            canvas->save();
+        }
+        canvas->concat(*fMatrix);
+    }
+}
+
+bool BeginDrawPictureCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
+
+    canvas->drawPicture(fPicture.get());
+
+    canvas->restore();
+
+    return true;
+}
+
+EndDrawPictureCommand::EndDrawPictureCommand(bool restore)
+        : INHERITED(kEndDrawPicture_OpType), fRestore(restore) {}
+
+void EndDrawPictureCommand::execute(SkCanvas* canvas) const {
+    if (fRestore) {
+        canvas->restore();
+    }
+}
+
+DrawPointsCommand::DrawPointsCommand(SkCanvas::PointMode mode,
+                                     size_t              count,
+                                     const SkPoint       pts[],
+                                     const SkPaint&      paint)
+        : INHERITED(kDrawPoints_OpType), fMode(mode), fPts(pts, count), fPaint(paint) {}
+
+void DrawPointsCommand::execute(SkCanvas* canvas) const {
+    canvas->drawPoints(fMode, fPts.count(), fPts.begin(), fPaint);
+}
+
+bool DrawPointsCommand::render(SkCanvas* canvas) const {
+    canvas->clear(0xFFFFFFFF);
+    canvas->save();
+
+    SkRect bounds;
+
+    bounds.setEmpty();
+    for (int i = 0; i < fPts.count(); ++i) {
+        SkRectPriv::GrowToInclude(&bounds, fPts[i]);
+    }
+
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawPoints(fMode, fPts.count(), fPts.begin(), p);
+    canvas->restore();
+
+    return true;
+}
+
+void DrawPointsCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_MODE, pointmode_name(fMode));
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POINTS);
+    for (int i = 0; i < fPts.count(); i++) {
+        MakeJsonPoint(writer, fPts[i]);
+    }
+    writer.endArray();  // points
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawTextBlobCommand::DrawTextBlobCommand(sk_sp<SkTextBlob> blob,
+                                         SkScalar          x,
+                                         SkScalar          y,
+                                         const SkPaint&    paint)
+        : INHERITED(kDrawTextBlob_OpType)
+        , fBlob(std::move(blob))
+        , fXPos(x)
+        , fYPos(y)
+        , fPaint(paint) {}
+
+void DrawTextBlobCommand::execute(SkCanvas* canvas) const {
+    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
+}
+
+bool DrawTextBlobCommand::render(SkCanvas* canvas) const {
+    canvas->clear(SK_ColorWHITE);
+    canvas->save();
+
+    SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
+    xlate_and_scale_to_bounds(canvas, bounds);
+
+    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
+
+    canvas->restore();
+
+    return true;
+}
+
+void DrawTextBlobCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_RUNS);
+    SkTextBlobRunIterator iter(fBlob.get());
+    while (!iter.done()) {
+        writer.beginObject();  // run
+        writer.beginArray(DEBUGCANVAS_ATTRIBUTE_GLYPHS);
+        for (uint32_t i = 0; i < iter.glyphCount(); i++) {
+            writer.appendU32(iter.glyphs()[i]);
+        }
+        writer.endArray();  // glyphs
+        if (iter.positioning() != SkTextBlobRunIterator::kDefault_Positioning) {
+            writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POSITIONS);
+            const SkScalar* iterPositions = iter.pos();
+            for (uint32_t i = 0; i < iter.glyphCount(); i++) {
+                switch (iter.positioning()) {
+                    case SkTextBlobRunIterator::kFull_Positioning:
+                        MakeJsonPoint(writer, iterPositions[i * 2], iterPositions[i * 2 + 1]);
+                        break;
+                    case SkTextBlobRunIterator::kHorizontal_Positioning:
+                        writer.appendFloat(iterPositions[i]);
+                        break;
+                    case SkTextBlobRunIterator::kDefault_Positioning: break;
+                    case SkTextBlobRunIterator::kRSXform_Positioning:
+                        // TODO_RSXFORM_BLOB
+                        break;
+                }
+            }
+            writer.endArray();  // positions
+        }
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_FONT);
+        MakeJsonFont(iter.font(), writer, urlDataManager);
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+        MakeJsonPoint(writer, iter.offset());
+
+        writer.endObject();  // run
+        iter.next();
+    }
+    writer.endArray();  // runs
+    writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_X, fXPos);
+    writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_Y, fYPos);
+    SkRect bounds = fBlob->bounds();
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, bounds);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+
+    SkString desc;
+    // make the bounds local by applying the x,y
+    bounds.offset(fXPos, fYPos);
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, bounds)->c_str());
+}
+
+DrawPatchCommand::DrawPatchCommand(const SkPoint  cubics[12],
+                                   const SkColor  colors[4],
+                                   const SkPoint  texCoords[4],
+                                   SkBlendMode    bmode,
+                                   const SkPaint& paint)
+        : INHERITED(kDrawPatch_OpType), fBlendMode(bmode) {
+    memcpy(fCubics, cubics, sizeof(fCubics));
+    if (colors != nullptr) {
+        memcpy(fColors, colors, sizeof(fColors));
+        fColorsPtr = fColors;
+    } else {
+        fColorsPtr = nullptr;
+    }
+    if (texCoords != nullptr) {
+        memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
+        fTexCoordsPtr = fTexCoords;
+    } else {
+        fTexCoordsPtr = nullptr;
+    }
+    fPaint = paint;
+}
+
+void DrawPatchCommand::execute(SkCanvas* canvas) const {
+    canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint);
+}
+
+void DrawPatchCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.beginArray(DEBUGCANVAS_ATTRIBUTE_CUBICS);
+    for (int i = 0; i < 12; i++) {
+        MakeJsonPoint(writer, fCubics[i]);
+    }
+    writer.endArray();  // cubics
+    if (fColorsPtr != nullptr) {
+        writer.beginArray(DEBUGCANVAS_ATTRIBUTE_COLORS);
+        for (int i = 0; i < 4; i++) {
+            MakeJsonColor(writer, fColorsPtr[i]);
+        }
+        writer.endArray();  // colors
+    }
+    if (fTexCoordsPtr != nullptr) {
+        writer.beginArray(DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS);
+        for (int i = 0; i < 4; i++) {
+            MakeJsonPoint(writer, fTexCoords[i]);
+        }
+        writer.endArray();  // texCoords
+    }
+    // fBlendMode
+}
+
+DrawRectCommand::DrawRectCommand(const SkRect& rect, const SkPaint& paint)
+        : INHERITED(kDrawRect_OpType) {
+    fRect  = rect;
+    fPaint = paint;
+}
+
+void DrawRectCommand::execute(SkCanvas* canvas) const { canvas->drawRect(fRect, fPaint); }
+
+void DrawRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    MakeJsonRect(writer, fRect);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+
+    SkString desc;
+    writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
+}
+
+DrawRRectCommand::DrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
+        : INHERITED(kDrawRRect_OpType) {
+    fRRect = rrect;
+    fPaint = paint;
+}
+
+void DrawRRectCommand::execute(SkCanvas* canvas) const { canvas->drawRRect(fRRect, fPaint); }
+
+bool DrawRRectCommand::render(SkCanvas* canvas) const {
+    render_rrect(canvas, fRRect);
+    return true;
+}
+
+void DrawRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
+    make_json_rrect(writer, fRRect);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawDRRectCommand::DrawDRRectCommand(const SkRRect& outer,
+                                     const SkRRect& inner,
+                                     const SkPaint& paint)
+        : INHERITED(kDrawDRRect_OpType) {
+    fOuter = outer;
+    fInner = inner;
+    fPaint = paint;
+}
+
+void DrawDRRectCommand::execute(SkCanvas* canvas) const {
+    canvas->drawDRRect(fOuter, fInner, fPaint);
+}
+
+bool DrawDRRectCommand::render(SkCanvas* canvas) const {
+    render_drrect(canvas, fOuter, fInner);
+    return true;
+}
+
+void DrawDRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_OUTER);
+    make_json_rrect(writer, fOuter);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_INNER);
+    make_json_rrect(writer, fInner);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+    MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+DrawShadowCommand::DrawShadowCommand(const SkPath& path, const SkDrawShadowRec& rec)
+        : INHERITED(kDrawShadow_OpType) {
+    fPath      = path;
+    fShadowRec = rec;
+}
+
+void DrawShadowCommand::execute(SkCanvas* canvas) const {
+    canvas->private_draw_shadow_rec(fPath, fShadowRec);
+}
+
+bool DrawShadowCommand::render(SkCanvas* canvas) const {
+    render_shadow(canvas, fPath, fShadowRec);
+    return true;
+}
+
+void DrawShadowCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+
+    bool geometricOnly = SkToBool(fShadowRec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+    bool transparentOccluder =
+            SkToBool(fShadowRec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
+    MakeJsonPath(writer, fPath);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_ZPLANE);
+    MakeJsonPoint3(writer, fShadowRec.fZPlaneParams);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION);
+    MakeJsonPoint3(writer, fShadowRec.fLightPos);
+    writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS, fShadowRec.fLightRadius);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR);
+    MakeJsonColor(writer, fShadowRec.fAmbientColor);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR);
+    MakeJsonColor(writer, fShadowRec.fSpotColor);
+    store_bool(writer, DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC, transparentOccluder, false);
+    store_bool(writer, DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY, geometricOnly, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DrawEdgeAAQuadCommand::DrawEdgeAAQuadCommand(const SkRect&         rect,
+                                             const SkPoint         clip[],
+                                             SkCanvas::QuadAAFlags aa,
+                                             const SkColor4f&      color,
+                                             SkBlendMode           mode)
+        : INHERITED(kDrawEdgeAAQuad_OpType)
+        , fRect(rect)
+        , fHasClip(clip != nullptr)
+        , fAA(aa)
+        , fColor(color)
+        , fMode(mode) {
+    if (clip) {
+        for (int i = 0; i < 4; ++i) {
+            fClip[i] = clip[i];
+        }
+    }
+}
+
+void DrawEdgeAAQuadCommand::execute(SkCanvas* canvas) const {
+    canvas->experimental_DrawEdgeAAQuad(fRect, fHasClip ? fClip : nullptr, fAA, fColor, fMode);
+}
+
+DrawEdgeAAImageSetCommand::DrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry set[],
+                                                     int                           count,
+                                                     const SkPoint                 dstClips[],
+                                                     const SkMatrix              preViewMatrices[],
+                                                     const SkPaint*              paint,
+                                                     SkCanvas::SrcRectConstraint constraint)
+        : INHERITED(kDrawEdgeAAImageSet_OpType)
+        , fSet(count)
+        , fCount(count)
+        , fPaint(paint)
+        , fConstraint(constraint) {
+    int totalDstClipCount, totalMatrixCount;
+    SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount);
+
+    std::copy_n(set, count, fSet.get());
+    fDstClips.reset(totalDstClipCount);
+    std::copy_n(dstClips, totalDstClipCount, fDstClips.get());
+    fPreViewMatrices.reset(totalMatrixCount);
+    std::copy_n(preViewMatrices, totalMatrixCount, fPreViewMatrices.get());
+}
+
+void DrawEdgeAAImageSetCommand::execute(SkCanvas* canvas) const {
+    canvas->experimental_DrawEdgeAAImageSet(fSet.get(),
+                                            fCount,
+                                            fDstClips.get(),
+                                            fPreViewMatrices.get(),
+                                            fPaint.getMaybeNull(),
+                                            fConstraint);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DrawDrawableCommand::DrawDrawableCommand(SkDrawable* drawable, const SkMatrix* matrix)
+        : INHERITED(kDrawDrawable_OpType), fDrawable(SkRef(drawable)), fMatrix(matrix) {}
+
+void DrawDrawableCommand::execute(SkCanvas* canvas) const {
+    canvas->drawDrawable(fDrawable.get(), fMatrix.getMaybeNull());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DrawVerticesCommand::DrawVerticesCommand(sk_sp<SkVertices> vertices,
+                                         SkBlendMode       bmode,
+                                         const SkPaint&    paint)
+        : INHERITED(kDrawVertices_OpType)
+        , fVertices(std::move(vertices))
+        , fBlendMode(bmode)
+        , fPaint(paint) {}
+
+void DrawVerticesCommand::execute(SkCanvas* canvas) const {
+    canvas->drawVertices(fVertices, fBlendMode, fPaint);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DrawAtlasCommand::DrawAtlasCommand(const SkImage*  image,
+                                   const SkRSXform xform[],
+                                   const SkRect    tex[],
+                                   const SkColor   colors[],
+                                   int             count,
+                                   SkBlendMode     bmode,
+                                   const SkRect*   cull,
+                                   const SkPaint*  paint)
+        : INHERITED(kDrawAtlas_OpType)
+        , fImage(SkRef(image))
+        , fXform(xform, count)
+        , fTex(tex, count)
+        , fColors(colors, colors ? count : 0)
+        , fBlendMode(bmode)
+        , fCull(cull)
+        , fPaint(paint) {}
+
+void DrawAtlasCommand::execute(SkCanvas* canvas) const {
+    canvas->drawAtlas(fImage.get(),
+                      fXform.begin(),
+                      fTex.begin(),
+                      fColors.isEmpty() ? nullptr : fColors.begin(),
+                      fXform.count(),
+                      fBlendMode,
+                      fCull.getMaybeNull(),
+                      fPaint.getMaybeNull());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+RestoreCommand::RestoreCommand() : INHERITED(kRestore_OpType) {}
+
+void RestoreCommand::execute(SkCanvas* canvas) const { canvas->restore(); }
+
+SaveCommand::SaveCommand() : INHERITED(kSave_OpType) {}
+
+void SaveCommand::execute(SkCanvas* canvas) const { canvas->save(); }
+
+SaveLayerCommand::SaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
+        : INHERITED(kSaveLayer_OpType)
+        , fBounds(rec.fBounds)
+        , fPaint(rec.fPaint)
+        , fBackdrop(SkSafeRef(rec.fBackdrop))
+        , fSaveLayerFlags(rec.fSaveLayerFlags) {}
+
+void SaveLayerCommand::execute(SkCanvas* canvas) const {
+    canvas->saveLayer(
+            SkCanvas::SaveLayerRec(fBounds.getMaybeNull(), fPaint.getMaybeNull(), fSaveLayerFlags));
+}
+
+void SaveLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    if (fBounds.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS);
+        MakeJsonRect(writer, *fBounds);
+    }
+    if (fPaint.isValid()) {
+        writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
+        MakeJsonPaint(writer, *fPaint, urlDataManager);
+    }
+    if (fBackdrop != nullptr) {
+        writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BACKDROP);
+        flatten(fBackdrop.get(), writer, urlDataManager);
+        writer.endObject();  // backdrop
+    }
+    if (fSaveLayerFlags != 0) {
+        SkDebugf("unsupported: saveLayer flags\n");
+        SkASSERT(false);
+    }
+}
+
+SetMatrixCommand::SetMatrixCommand(const SkMatrix& matrix) : INHERITED(kSetMatrix_OpType) {
+    fMatrix = matrix;
+}
+
+void SetMatrixCommand::execute(SkCanvas* canvas) const { canvas->setMatrix(fMatrix); }
+
+void SetMatrixCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+    INHERITED::toJSON(writer, urlDataManager);
+    writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX);
+    MakeJsonMatrix(writer, fMatrix);
+}
diff --git a/src/third_party/skia/tools/debugger/DrawCommand.h b/src/third_party/skia/tools/debugger/DrawCommand.h
new file mode 100644
index 0000000..84e1ec0
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/DrawCommand.h
@@ -0,0 +1,728 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKDRAWCOMMAND_H_
+#define SKDRAWCOMMAND_H_
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFlattenable.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkRRect.h"
+#include "include/core/SkRSXform.h"
+#include "include/core/SkRegion.h"
+#include "include/core/SkString.h"
+#include "include/core/SkVertices.h"
+#include "include/private/SkTDArray.h"
+#include "src/core/SkDrawShadowInfo.h"
+#include "src/core/SkTLazy.h"
+#include "src/utils/SkJSONWriter.h"
+#include "tools/UrlDataManager.h"
+
+class DrawCommand {
+public:
+    enum OpType {
+        kBeginDrawPicture_OpType,
+        kClear_OpType,
+        kClipPath_OpType,
+        kClipRegion_OpType,
+        kClipRect_OpType,
+        kClipRRect_OpType,
+        kConcat_OpType,
+        kDrawAnnotation_OpType,
+        kDrawBitmap_OpType,
+        kDrawBitmapLattice_OpType,
+        kDrawBitmapNine_OpType,
+        kDrawBitmapRect_OpType,
+        kDrawDRRect_OpType,
+        kDrawImage_OpType,
+        kDrawImageLattice_OpType,
+        kDrawImageNine_OpType,
+        kDrawImageRect_OpType,
+        kDrawOval_OpType,
+        kDrawArc_OpType,
+        kDrawPaint_OpType,
+        kDrawPatch_OpType,
+        kDrawPath_OpType,
+        kDrawPoints_OpType,
+        kDrawRect_OpType,
+        kDrawRRect_OpType,
+        kDrawRegion_OpType,
+        kDrawShadow_OpType,
+        kDrawTextBlob_OpType,
+        kDrawVertices_OpType,
+        kDrawAtlas_OpType,
+        kDrawDrawable_OpType,
+        kDrawEdgeAAQuad_OpType,
+        kDrawEdgeAAImageSet_OpType,
+        kEndDrawPicture_OpType,
+        kRestore_OpType,
+        kSave_OpType,
+        kSaveLayer_OpType,
+        kSetMatrix_OpType,
+
+        kLast_OpType = kSetMatrix_OpType
+    };
+
+    static const int kOpTypeCount = kLast_OpType + 1;
+
+    static void WritePNG(SkBitmap bitmap, SkWStream& out);
+
+    DrawCommand(OpType opType);
+
+    virtual ~DrawCommand() {}
+
+    bool isVisible() const { return fVisible; }
+
+    void setVisible(bool toggle) { fVisible = toggle; }
+
+    virtual void execute(SkCanvas*) const = 0;
+
+    virtual bool render(SkCanvas* canvas) const { return false; }
+
+    virtual void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const;
+
+    static const char* GetCommandString(OpType type);
+
+    // Helper methods for converting things to JSON
+    static void MakeJsonColor(SkJSONWriter&, const SkColor color);
+    static void MakeJsonColor4f(SkJSONWriter&, const SkColor4f& color);
+    static void MakeJsonPoint(SkJSONWriter&, const SkPoint& point);
+    static void MakeJsonPoint(SkJSONWriter&, SkScalar x, SkScalar y);
+    static void MakeJsonPoint3(SkJSONWriter&, const SkPoint3& point);
+    static void MakeJsonRect(SkJSONWriter&, const SkRect& rect);
+    static void MakeJsonIRect(SkJSONWriter&, const SkIRect&);
+    static void MakeJsonMatrix(SkJSONWriter&, const SkMatrix&);
+    static void MakeJsonPath(SkJSONWriter&, const SkPath& path);
+    static void MakeJsonRegion(SkJSONWriter&, const SkRegion& region);
+    static void MakeJsonPaint(SkJSONWriter&, const SkPaint& paint, UrlDataManager& urlDataManager);
+    static void MakeJsonLattice(SkJSONWriter&, const SkCanvas::Lattice& lattice);
+
+    static void flatten(const SkFlattenable* flattenable,
+                        SkJSONWriter&        writer,
+                        UrlDataManager&      urlDataManager);
+    static bool flatten(const SkImage& image, SkJSONWriter& writer, UrlDataManager& urlDataManager);
+    static bool flatten(const SkBitmap& bitmap,
+                        SkJSONWriter&   writer,
+                        UrlDataManager& urlDataManager);
+
+private:
+    OpType fOpType;
+    bool   fVisible;
+};
+
+class RestoreCommand : public DrawCommand {
+public:
+    RestoreCommand();
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    typedef DrawCommand INHERITED;
+};
+
+class ClearCommand : public DrawCommand {
+public:
+    ClearCommand(SkColor color);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkColor fColor;
+
+    typedef DrawCommand INHERITED;
+};
+
+class ClipPathCommand : public DrawCommand {
+public:
+    ClipPathCommand(const SkPath& path, SkClipOp op, bool doAA);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPath   fPath;
+    SkClipOp fOp;
+    bool     fDoAA;
+
+    typedef DrawCommand INHERITED;
+};
+
+class ClipRegionCommand : public DrawCommand {
+public:
+    ClipRegionCommand(const SkRegion& region, SkClipOp op);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRegion fRegion;
+    SkClipOp fOp;
+
+    typedef DrawCommand INHERITED;
+};
+
+class ClipRectCommand : public DrawCommand {
+public:
+    ClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRect   fRect;
+    SkClipOp fOp;
+    bool     fDoAA;
+
+    typedef DrawCommand INHERITED;
+};
+
+class ClipRRectCommand : public DrawCommand {
+public:
+    ClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRRect  fRRect;
+    SkClipOp fOp;
+    bool     fDoAA;
+
+    typedef DrawCommand INHERITED;
+};
+
+class ConcatCommand : public DrawCommand {
+public:
+    ConcatCommand(const SkMatrix& matrix);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkMatrix fMatrix;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawAnnotationCommand : public DrawCommand {
+public:
+    DrawAnnotationCommand(const SkRect&, const char key[], sk_sp<SkData> value);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRect        fRect;
+    SkString      fKey;
+    sk_sp<SkData> fValue;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawBitmapCommand : public DrawCommand {
+public:
+    DrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkBitmap         fBitmap;
+    SkScalar         fLeft;
+    SkScalar         fTop;
+    SkTLazy<SkPaint> fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawBitmapLatticeCommand : public DrawCommand {
+public:
+    DrawBitmapLatticeCommand(const SkBitmap&          bitmap,
+                             const SkCanvas::Lattice& lattice,
+                             const SkRect&            dst,
+                             const SkPaint*           paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkBitmap          fBitmap;
+    SkCanvas::Lattice fLattice;
+    SkRect            fDst;
+    SkTLazy<SkPaint>  fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawBitmapNineCommand : public DrawCommand {
+public:
+    DrawBitmapNineCommand(const SkBitmap& bitmap,
+                          const SkIRect&  center,
+                          const SkRect&   dst,
+                          const SkPaint*  paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkBitmap         fBitmap;
+    SkIRect          fCenter;
+    SkRect           fDst;
+    SkTLazy<SkPaint> fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawBitmapRectCommand : public DrawCommand {
+public:
+    DrawBitmapRectCommand(const SkBitmap& bitmap,
+                          const SkRect*   src,
+                          const SkRect&   dst,
+                          const SkPaint*  paint,
+                          SkCanvas::SrcRectConstraint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkBitmap                    fBitmap;
+    SkTLazy<SkRect>             fSrc;
+    SkRect                      fDst;
+    SkTLazy<SkPaint>            fPaint;
+    SkCanvas::SrcRectConstraint fConstraint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawImageCommand : public DrawCommand {
+public:
+    DrawImageCommand(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<const SkImage> fImage;
+    SkScalar             fLeft;
+    SkScalar             fTop;
+    SkTLazy<SkPaint>     fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawImageLatticeCommand : public DrawCommand {
+public:
+    DrawImageLatticeCommand(const SkImage*           image,
+                            const SkCanvas::Lattice& lattice,
+                            const SkRect&            dst,
+                            const SkPaint*           paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<const SkImage> fImage;
+    SkCanvas::Lattice    fLattice;
+    SkRect               fDst;
+    SkTLazy<SkPaint>     fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawImageNineCommand : public DrawCommand {
+public:
+    DrawImageNineCommand(const SkImage* image,
+                         const SkIRect& center,
+                         const SkRect&  dst,
+                         const SkPaint* paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<const SkImage> fImage;
+    SkIRect              fCenter;
+    SkRect               fDst;
+    SkTLazy<SkPaint>     fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawImageRectCommand : public DrawCommand {
+public:
+    DrawImageRectCommand(const SkImage*              image,
+                         const SkRect*               src,
+                         const SkRect&               dst,
+                         const SkPaint*              paint,
+                         SkCanvas::SrcRectConstraint constraint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<const SkImage>        fImage;
+    SkTLazy<SkRect>             fSrc;
+    SkRect                      fDst;
+    SkTLazy<SkPaint>            fPaint;
+    SkCanvas::SrcRectConstraint fConstraint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawOvalCommand : public DrawCommand {
+public:
+    DrawOvalCommand(const SkRect& oval, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRect  fOval;
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawArcCommand : public DrawCommand {
+public:
+    DrawArcCommand(const SkRect&  oval,
+                   SkScalar       startAngle,
+                   SkScalar       sweepAngle,
+                   bool           useCenter,
+                   const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRect   fOval;
+    SkScalar fStartAngle;
+    SkScalar fSweepAngle;
+    bool     fUseCenter;
+    SkPaint  fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawPaintCommand : public DrawCommand {
+public:
+    DrawPaintCommand(const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawBehindCommand : public DrawCommand {
+public:
+    DrawBehindCommand(const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawPathCommand : public DrawCommand {
+public:
+    DrawPathCommand(const SkPath& path, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPath  fPath;
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class BeginDrawPictureCommand : public DrawCommand {
+public:
+    BeginDrawPictureCommand(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint);
+
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+
+private:
+    sk_sp<const SkPicture> fPicture;
+    SkTLazy<SkMatrix>      fMatrix;
+    SkTLazy<SkPaint>       fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class EndDrawPictureCommand : public DrawCommand {
+public:
+    EndDrawPictureCommand(bool restore);
+
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    bool fRestore;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawPointsCommand : public DrawCommand {
+public:
+    DrawPointsCommand(SkCanvas::PointMode mode,
+                      size_t              count,
+                      const SkPoint       pts[],
+                      const SkPaint&      paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkCanvas::PointMode fMode;
+    SkTDArray<SkPoint>  fPts;
+    SkPaint             fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawRegionCommand : public DrawCommand {
+public:
+    DrawRegionCommand(const SkRegion& region, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRegion fRegion;
+    SkPaint  fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawTextBlobCommand : public DrawCommand {
+public:
+    DrawTextBlobCommand(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const SkPaint& paint);
+
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<SkTextBlob> fBlob;
+    SkScalar          fXPos;
+    SkScalar          fYPos;
+    SkPaint           fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawPatchCommand : public DrawCommand {
+public:
+    DrawPatchCommand(const SkPoint  cubics[12],
+                     const SkColor  colors[4],
+                     const SkPoint  texCoords[4],
+                     SkBlendMode    bmode,
+                     const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPoint     fCubics[12];
+    SkColor*    fColorsPtr;
+    SkColor     fColors[4];
+    SkPoint*    fTexCoordsPtr;
+    SkPoint     fTexCoords[4];
+    SkBlendMode fBlendMode;
+    SkPaint     fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawRectCommand : public DrawCommand {
+public:
+    DrawRectCommand(const SkRect& rect, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRect  fRect;
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawRRectCommand : public DrawCommand {
+public:
+    DrawRRectCommand(const SkRRect& rrect, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRRect fRRect;
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawDRRectCommand : public DrawCommand {
+public:
+    DrawDRRectCommand(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkRRect fOuter;
+    SkRRect fInner;
+    SkPaint fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawVerticesCommand : public DrawCommand {
+public:
+    DrawVerticesCommand(sk_sp<SkVertices>, SkBlendMode, const SkPaint&);
+
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    sk_sp<SkVertices> fVertices;
+    SkBlendMode       fBlendMode;
+    SkPaint           fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawAtlasCommand : public DrawCommand {
+public:
+    DrawAtlasCommand(const SkImage*,
+                     const SkRSXform[],
+                     const SkRect[],
+                     const SkColor[],
+                     int,
+                     SkBlendMode,
+                     const SkRect*,
+                     const SkPaint*);
+
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    sk_sp<const SkImage> fImage;
+    SkTDArray<SkRSXform> fXform;
+    SkTDArray<SkRect>    fTex;
+    SkTDArray<SkColor>   fColors;
+    SkBlendMode          fBlendMode;
+    SkTLazy<SkRect>      fCull;
+    SkTLazy<SkPaint>     fPaint;
+
+    typedef DrawCommand INHERITED;
+};
+
+class SaveCommand : public DrawCommand {
+public:
+    SaveCommand();
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    typedef DrawCommand INHERITED;
+};
+
+class SaveLayerCommand : public DrawCommand {
+public:
+    SaveLayerCommand(const SkCanvas::SaveLayerRec&);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkTLazy<SkRect>            fBounds;
+    SkTLazy<SkPaint>           fPaint;
+    sk_sp<const SkImageFilter> fBackdrop;
+    uint32_t                   fSaveLayerFlags;
+
+    typedef DrawCommand INHERITED;
+};
+
+class SetMatrixCommand : public DrawCommand {
+public:
+    SetMatrixCommand(const SkMatrix& matrix);
+    void execute(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkMatrix fMatrix;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawShadowCommand : public DrawCommand {
+public:
+    DrawShadowCommand(const SkPath& path, const SkDrawShadowRec& rec);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    void toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const override;
+
+private:
+    SkPath          fPath;
+    SkDrawShadowRec fShadowRec;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawDrawableCommand : public DrawCommand {
+public:
+    DrawDrawableCommand(SkDrawable*, const SkMatrix*);
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    sk_sp<SkDrawable> fDrawable;
+    SkTLazy<SkMatrix> fMatrix;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawEdgeAAQuadCommand : public DrawCommand {
+public:
+    DrawEdgeAAQuadCommand(const SkRect&         rect,
+                          const SkPoint         clip[4],
+                          SkCanvas::QuadAAFlags aa,
+                          const SkColor4f&      color,
+                          SkBlendMode           mode);
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    SkRect                fRect;
+    SkPoint               fClip[4];
+    int                   fHasClip;
+    SkCanvas::QuadAAFlags fAA;
+    SkColor4f             fColor;
+    SkBlendMode           fMode;
+
+    typedef DrawCommand INHERITED;
+};
+
+class DrawEdgeAAImageSetCommand : public DrawCommand {
+public:
+    DrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry[],
+                              int count,
+                              const SkPoint[],
+                              const SkMatrix[],
+                              const SkPaint*,
+                              SkCanvas::SrcRectConstraint);
+    void execute(SkCanvas* canvas) const override;
+
+private:
+    SkAutoTArray<SkCanvas::ImageSetEntry> fSet;
+    int                                   fCount;
+    SkAutoTArray<SkPoint>                 fDstClips;
+    SkAutoTArray<SkMatrix>                fPreViewMatrices;
+    SkTLazy<SkPaint>                      fPaint;
+    SkCanvas::SrcRectConstraint           fConstraint;
+
+    typedef DrawCommand INHERITED;
+};
+#endif
diff --git a/src/third_party/skia/tools/debugger/JsonWriteBuffer.cpp b/src/third_party/skia/tools/debugger/JsonWriteBuffer.cpp
new file mode 100644
index 0000000..7257167
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/JsonWriteBuffer.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/debugger/JsonWriteBuffer.h"
+
+#include "tools/debugger/DrawCommand.h"
+
+void JsonWriteBuffer::append(const char* type) {
+    SkString fullName = SkStringPrintf("%02d_%s", fCount++, type);
+    fWriter->appendName(fullName.c_str());
+}
+
+void JsonWriteBuffer::writePad32(const void* data, size_t size) {
+    this->append("rawBytes");
+    fWriter->beginArray();
+    const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
+    for (size_t i = 0; i < size; ++i) {
+        SkString hexByte = SkStringPrintf("%02x", bytes[i]);
+        fWriter->appendString(hexByte.c_str());
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeByteArray(const void* data, size_t size) {
+    this->append("byteArray");
+    fWriter->beginArray();
+    const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
+    for (size_t i = 0; i < size; ++i) {
+        SkString hexByte = SkStringPrintf("%02x", bytes[i]);
+        fWriter->appendString(hexByte.c_str());
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeBool(bool value) {
+    this->append("bool");
+    fWriter->appendBool(value);
+}
+
+void JsonWriteBuffer::writeScalar(SkScalar value) {
+    this->append("scalar");
+    fWriter->appendFloat(value);
+}
+
+void JsonWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
+    this->append("scalarArray");
+    fWriter->beginArray();
+    for (uint32_t i = 0; i < count; ++i) {
+        fWriter->appendFloat(value[i]);
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeInt(int32_t value) {
+    this->append("int");
+    fWriter->appendS32(value);
+}
+
+void JsonWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
+    this->append("intArray");
+    fWriter->beginArray();
+    for (uint32_t i = 0; i < count; ++i) {
+        fWriter->appendS32(value[i]);
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeUInt(uint32_t value) {
+    this->append("uint");
+    fWriter->appendU32(value);
+}
+
+void JsonWriteBuffer::writeString(const char* value) {
+    this->append("string");
+    fWriter->appendString(value);
+}
+
+void JsonWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
+    if (flattenable) {
+        this->append(flattenable->getTypeName());
+        fWriter->beginObject();
+        JsonWriteBuffer flattenableBuffer(fWriter, fUrlDataManager);
+        flattenable->flatten(flattenableBuffer);
+        fWriter->endObject();
+    } else {
+        this->append("flattenable");
+        fWriter->appendPointer(nullptr);
+    }
+}
+
+void JsonWriteBuffer::writeColor(SkColor color) {
+    this->append("color");
+    DrawCommand::MakeJsonColor(*fWriter, color);
+}
+
+void JsonWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
+    this->append("colorArray");
+    fWriter->beginArray();
+    for (uint32_t i = 0; i < count; ++i) {
+        DrawCommand::MakeJsonColor(*fWriter, color[i]);
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeColor4f(const SkColor4f& color) {
+    this->append("color");
+    DrawCommand::MakeJsonColor4f(*fWriter, color);
+}
+
+void JsonWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
+    this->append("colorArray");
+    fWriter->beginArray();
+    for (uint32_t i = 0; i < count; ++i) {
+        DrawCommand::MakeJsonColor4f(*fWriter, color[i]);
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writePoint(const SkPoint& point) {
+    this->append("point");
+    DrawCommand::MakeJsonPoint(*fWriter, point);
+}
+
+void JsonWriteBuffer::writePoint3(const SkPoint3& point) {
+    this->append("point3");
+    DrawCommand::MakeJsonPoint3(*fWriter, point);
+}
+
+void JsonWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
+    this->append("pointArray");
+    fWriter->beginArray();
+    for (uint32_t i = 0; i < count; ++i) {
+        DrawCommand::MakeJsonPoint(*fWriter, point[i]);
+    }
+    fWriter->endArray();
+}
+
+void JsonWriteBuffer::writeMatrix(const SkMatrix& matrix) {
+    this->append("matrix");
+    DrawCommand::MakeJsonMatrix(*fWriter, matrix);
+}
+
+void JsonWriteBuffer::writeIRect(const SkIRect& rect) {
+    this->append("irect");
+    DrawCommand::MakeJsonIRect(*fWriter, rect);
+}
+
+void JsonWriteBuffer::writeRect(const SkRect& rect) {
+    this->append("rect");
+    DrawCommand::MakeJsonRect(*fWriter, rect);
+}
+
+void JsonWriteBuffer::writeRegion(const SkRegion& region) {
+    this->append("region");
+    DrawCommand::MakeJsonRegion(*fWriter, region);
+}
+
+void JsonWriteBuffer::writePath(const SkPath& path) {
+    this->append("path");
+    DrawCommand::MakeJsonPath(*fWriter, path);
+}
+
+size_t JsonWriteBuffer::writeStream(SkStream* stream, size_t length) {
+    // Contents not supported
+    this->append("stream");
+    fWriter->appendU64(static_cast<uint64_t>(length));
+    return 0;
+}
+
+void JsonWriteBuffer::writeImage(const SkImage* image) {
+    this->append("image");
+    fWriter->beginObject();
+    DrawCommand::flatten(*image, *fWriter, *fUrlDataManager);
+    fWriter->endObject();
+}
+
+void JsonWriteBuffer::writeTypeface(SkTypeface* typeface) {
+    // Unsupported
+    this->append("typeface");
+    fWriter->appendPointer(typeface);
+}
+
+void JsonWriteBuffer::writePaint(const SkPaint& paint) {
+    this->append("paint");
+    DrawCommand::MakeJsonPaint(*fWriter, paint, *fUrlDataManager);
+}
diff --git a/src/third_party/skia/tools/debugger/JsonWriteBuffer.h b/src/third_party/skia/tools/debugger/JsonWriteBuffer.h
new file mode 100644
index 0000000..78ed4d2
--- /dev/null
+++ b/src/third_party/skia/tools/debugger/JsonWriteBuffer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef JsonWriteBuffer_DEFINED
+#define JsonWriteBuffer_DEFINED
+
+#include "src/core/SkWriteBuffer.h"
+
+class SkJSONWriter;
+class SkPath;
+class UrlDataManager;
+
+class JsonWriteBuffer final : public SkWriteBuffer {
+public:
+    JsonWriteBuffer(SkJSONWriter* writer, UrlDataManager* urlDataManager)
+            : fUrlDataManager(urlDataManager), fWriter(writer), fCount(0) {}
+
+    void writePad32(const void* buffer, size_t bytes) override;
+    void writeByteArray(const void* data, size_t size) override;
+    void writeBool(bool value) override;
+    void writeScalar(SkScalar value) override;
+    void writeScalarArray(const SkScalar* value, uint32_t count) override;
+    void writeInt(int32_t value) override;
+    void writeIntArray(const int32_t* value, uint32_t count) override;
+    void writeUInt(uint32_t value) override;
+    void writeString(const char* value) override;
+
+    void   writeFlattenable(const SkFlattenable* flattenable) override;
+    void   writeColor(SkColor color) override;
+    void   writeColorArray(const SkColor* color, uint32_t count) override;
+    void   writeColor4f(const SkColor4f& color) override;
+    void   writeColor4fArray(const SkColor4f* color, uint32_t count) override;
+    void   writePoint(const SkPoint& point) override;
+    void   writePointArray(const SkPoint* point, uint32_t count) override;
+    void   writePoint3(const SkPoint3& point) override;
+    void   writeMatrix(const SkMatrix& matrix) override;
+    void   writeIRect(const SkIRect& rect) override;
+    void   writeRect(const SkRect& rect) override;
+    void   writeRegion(const SkRegion& region) override;
+    void   writePath(const SkPath& path) override;
+    size_t writeStream(SkStream* stream, size_t length) override;
+    void   writeImage(const SkImage*) override;
+    void   writeTypeface(SkTypeface* typeface) override;
+    void   writePaint(const SkPaint& paint) override;
+
+private:
+    void append(const char* type);
+
+    UrlDataManager* fUrlDataManager;
+    SkJSONWriter*   fWriter;
+    int             fCount;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/debugger/SkDebugCanvas.cpp b/src/third_party/skia/tools/debugger/SkDebugCanvas.cpp
deleted file mode 100644
index fdde0a6..0000000
--- a/src/third_party/skia/tools/debugger/SkDebugCanvas.cpp
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkCanvasPriv.h"
-#include "SkClipStack.h"
-#include "SkDebugCanvas.h"
-#include "SkDrawCommand.h"
-#include "SkPaintFilterCanvas.h"
-#include "SkTextBlob.h"
-#include "SkClipOpPriv.h"
-
-#if SK_SUPPORT_GPU
-#include "GrAuditTrail.h"
-#include "GrContext.h"
-#include "GrRenderTargetContext.h"
-#endif
-
-#define SKDEBUGCANVAS_VERSION                     1
-#define SKDEBUGCANVAS_ATTRIBUTE_VERSION           "version"
-#define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS          "commands"
-#define SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL        "auditTrail"
-
-class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
-public:
-    DebugPaintFilterCanvas(SkCanvas* canvas,
-                           bool overdrawViz,
-                           bool overrideFilterQuality,
-                           SkFilterQuality quality)
-        : INHERITED(canvas)
-        , fOverdrawViz(overdrawViz)
-        , fOverrideFilterQuality(overrideFilterQuality)
-        , fFilterQuality(quality) {}
-
-protected:
-    bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type) const override {
-        if (*paint) {
-            if (fOverdrawViz) {
-                paint->writable()->setColor(SK_ColorRED);
-                paint->writable()->setAlpha(0x08);
-                paint->writable()->setBlendMode(SkBlendMode::kSrcOver);
-            }
-
-            if (fOverrideFilterQuality) {
-                paint->writable()->setFilterQuality(fFilterQuality);
-            }
-        }
-        return true;
-    }
-
-    void onDrawPicture(const SkPicture* picture,
-                       const SkMatrix* matrix,
-                       const SkPaint* paint) override {
-        // We need to replay the picture onto this canvas in order to filter its internal paints.
-        this->SkCanvas::onDrawPicture(picture, matrix, paint);
-    }
-
-private:
-    bool fOverdrawViz;
-    bool fOverrideFilterQuality;
-    SkFilterQuality fFilterQuality;
-
-    typedef SkPaintFilterCanvas INHERITED;
-};
-
-SkDebugCanvas::SkDebugCanvas(int width, int height)
-        : INHERITED(width, height)
-        , fPicture(nullptr)
-        , fFilter(false)
-        , fMegaVizMode(false)
-        , fOverdrawViz(false)
-        , fOverrideFilterQuality(false)
-        , fFilterQuality(kNone_SkFilterQuality)
-        , fClipVizColor(SK_ColorTRANSPARENT)
-        , fDrawGpuOpBounds(false) {
-    fUserMatrix.reset();
-
-    // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
-    // operations. This can lead to problems in the debugger which expects all
-    // the operations in the captured skp to appear in the debug canvas. To
-    // circumvent this we create a wide open clip here (an empty clip rect
-    // is not sufficient).
-    // Internally, the SkRect passed to clipRect is converted to an SkIRect and
-    // rounded out. The following code creates a nearly maximal rect that will
-    // not get collapsed by the coming conversions (Due to precision loss the
-    // inset has to be surprisingly large).
-    SkIRect largeIRect = SkIRect::MakeLargest();
-    largeIRect.inset(1024, 1024);
-    SkRect large = SkRect::Make(largeIRect);
-#ifdef SK_DEBUG
-    SkASSERT(!large.roundOut().isEmpty());
-#endif
-    // call the base class' version to avoid adding a draw command
-    this->INHERITED::onClipRect(large, kReplace_SkClipOp, kHard_ClipEdgeStyle);
-}
-
-SkDebugCanvas::~SkDebugCanvas() {
-    fCommandVector.deleteAll();
-}
-
-void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
-    fCommandVector.push(command);
-}
-
-void SkDebugCanvas::draw(SkCanvas* canvas) {
-    if (!fCommandVector.isEmpty()) {
-        this->drawTo(canvas, fCommandVector.count() - 1);
-    }
-}
-
-void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
-    canvas->concat(fUserMatrix);
-}
-
-int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
-    SkBitmap bitmap;
-    bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
-
-    SkCanvas canvas(bitmap);
-    canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
-    this->applyUserTransform(&canvas);
-
-    int layer = 0;
-    SkColor prev = bitmap.getColor(0,0);
-    for (int i = 0; i < index; i++) {
-        if (fCommandVector[i]->isVisible()) {
-            fCommandVector[i]->setUserMatrix(fUserMatrix);
-            fCommandVector[i]->execute(&canvas);
-        }
-        if (prev != bitmap.getColor(0,0)) {
-            layer = i;
-        }
-        prev = bitmap.getColor(0,0);
-    }
-    return layer;
-}
-
-// set up the saveLayer commands so that the active ones
-// return true in their 'active' method
-void SkDebugCanvas::markActiveCommands(int index) {
-    fActiveLayers.rewind();
-
-    for (int i = 0; i < fCommandVector.count(); ++i) {
-        fCommandVector[i]->setActive(false);
-    }
-
-    for (int i = 0; i < index; ++i) {
-        SkDrawCommand::Action result = fCommandVector[i]->action();
-        if (SkDrawCommand::kPushLayer_Action == result) {
-            fActiveLayers.push(fCommandVector[i]);
-        } else if (SkDrawCommand::kPopLayer_Action == result) {
-            fActiveLayers.pop();
-        }
-    }
-
-    for (int i = 0; i < fActiveLayers.count(); ++i) {
-        fActiveLayers[i]->setActive(true);
-    }
-
-}
-
-void SkDebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
-    SkASSERT(!fCommandVector.isEmpty());
-    SkASSERT(index < fCommandVector.count());
-
-    int saveCount = originalCanvas->save();
-
-    SkRect windowRect = SkRect::MakeWH(SkIntToScalar(originalCanvas->getBaseLayerSize().width()),
-                                       SkIntToScalar(originalCanvas->getBaseLayerSize().height()));
-
-    bool pathOpsMode = getAllowSimplifyClip();
-    originalCanvas->setAllowSimplifyClip(pathOpsMode);
-    originalCanvas->clear(SK_ColorWHITE);
-    originalCanvas->resetMatrix();
-    if (!windowRect.isEmpty()) {
-        originalCanvas->clipRect(windowRect, kReplace_SkClipOp);
-    }
-    this->applyUserTransform(originalCanvas);
-
-    DebugPaintFilterCanvas filterCanvas(originalCanvas, fOverdrawViz, fOverrideFilterQuality,
-                                        fFilterQuality);
-
-    if (fMegaVizMode) {
-        this->markActiveCommands(index);
-    }
-
-#if SK_SUPPORT_GPU
-    // If we have a GPU backend we can also visualize the op information
-    GrAuditTrail* at = nullptr;
-    if (fDrawGpuOpBounds || m != -1) {
-        // The audit trail must be obtained from the original canvas.
-        at = this->getAuditTrail(originalCanvas);
-    }
-#endif
-
-    for (int i = 0; i <= index; i++) {
-        if (i == index && fFilter) {
-            filterCanvas.clear(0xAAFFFFFF);
-        }
-
-#if SK_SUPPORT_GPU
-        // We need to flush any pending operations, or they might combine with commands below.
-        // Previous operations were not registered with the audit trail when they were
-        // created, so if we allow them to combine, the audit trail will fail to find them.
-        filterCanvas.flush();
-
-        GrAuditTrail::AutoCollectOps* acb = nullptr;
-        if (at) {
-            acb = new GrAuditTrail::AutoCollectOps(at, i);
-        }
-#endif
-
-        if (fCommandVector[i]->isVisible()) {
-            if (fMegaVizMode && fCommandVector[i]->active()) {
-                // "active" commands execute their visualization behaviors:
-                //     All active saveLayers get replaced with saves so all draws go to the
-                //     visible canvas.
-                //     All active culls draw their cull box
-                fCommandVector[i]->vizExecute(&filterCanvas);
-            } else {
-                fCommandVector[i]->setUserMatrix(fUserMatrix);
-                fCommandVector[i]->execute(&filterCanvas);
-            }
-        }
-#if SK_SUPPORT_GPU
-        if (at && acb) {
-            delete acb;
-        }
-#endif
-    }
-
-    if (SkColorGetA(fClipVizColor) != 0) {
-        filterCanvas.save();
-        #define LARGE_COORD 1000000000
-        filterCanvas.clipRect(
-                SkRect::MakeLTRB(-LARGE_COORD, -LARGE_COORD, LARGE_COORD, LARGE_COORD),
-                kReverseDifference_SkClipOp);
-        SkPaint clipPaint;
-        clipPaint.setColor(fClipVizColor);
-        filterCanvas.drawPaint(clipPaint);
-        filterCanvas.restore();
-    }
-
-    if (pathOpsMode) {
-        this->resetClipStackData();
-        const SkClipStack* clipStack = nullptr;//HACK filterCanvas.getClipStack();
-        SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
-        const SkClipStack::Element* element;
-        SkPath devPath;
-        while ((element = iter.next())) {
-            SkClipStack::Element::Type type = element->getType();
-            SkPath operand;
-            if (type != SkClipStack::Element::kEmpty_Type) {
-               element->asPath(&operand);
-            }
-            SkClipOp elementOp = element->getOp();
-            this->addClipStackData(devPath, operand, elementOp);
-            if (elementOp == kReplace_SkClipOp) {
-                devPath = operand;
-            } else {
-                Op(devPath, operand, (SkPathOp) elementOp, &devPath);
-            }
-        }
-        this->lastClipStackData(devPath);
-    }
-    fMatrix = filterCanvas.getTotalMatrix();
-    fClip = filterCanvas.getDeviceClipBounds();
-    filterCanvas.restoreToCount(saveCount);
-
-#if SK_SUPPORT_GPU
-    // draw any ops if required and issue a full reset onto GrAuditTrail
-    if (at) {
-        // just in case there is global reordering, we flush the canvas before querying
-        // GrAuditTrail
-        GrAuditTrail::AutoEnable ae(at);
-        filterCanvas.flush();
-
-        // we pick three colorblind-safe colors, 75% alpha
-        static const SkColor kTotalBounds = SkColorSetARGB(0xC0, 0x6A, 0x3D, 0x9A);
-        static const SkColor kCommandOpBounds = SkColorSetARGB(0xC0, 0xE3, 0x1A, 0x1C);
-        static const SkColor kOtherOpBounds = SkColorSetARGB(0xC0, 0xFF, 0x7F, 0x00);
-
-        // get the render target of the top device (from the original canvas) so we can ignore ops
-        // drawn offscreen
-        GrRenderTargetContext* rtc =
-                originalCanvas->internal_private_accessTopLayerRenderTargetContext();
-        GrSurfaceProxy::UniqueID proxyID = rtc->asSurfaceProxy()->uniqueID();
-
-        // get the bounding boxes to draw
-        SkTArray<GrAuditTrail::OpInfo> childrenBounds;
-        if (m == -1) {
-            at->getBoundsByClientID(&childrenBounds, index);
-        } else {
-            // the client wants us to draw the mth op
-            at->getBoundsByOpListID(&childrenBounds.push_back(), m);
-        }
-        SkPaint paint;
-        paint.setStyle(SkPaint::kStroke_Style);
-        paint.setStrokeWidth(1);
-        for (int i = 0; i < childrenBounds.count(); i++) {
-            if (childrenBounds[i].fProxyUniqueID != proxyID) {
-                // offscreen draw, ignore for now
-                continue;
-            }
-            paint.setColor(kTotalBounds);
-            filterCanvas.drawRect(childrenBounds[i].fBounds, paint);
-            for (int j = 0; j < childrenBounds[i].fOps.count(); j++) {
-                const GrAuditTrail::OpInfo::Op& op = childrenBounds[i].fOps[j];
-                if (op.fClientID != index) {
-                    paint.setColor(kOtherOpBounds);
-                } else {
-                    paint.setColor(kCommandOpBounds);
-                }
-                filterCanvas.drawRect(op.fBounds, paint);
-            }
-        }
-    }
-#endif
-    this->cleanupAuditTrail(originalCanvas);
-}
-
-void SkDebugCanvas::deleteDrawCommandAt(int index) {
-    SkASSERT(index < fCommandVector.count());
-    delete fCommandVector[index];
-    fCommandVector.remove(index);
-}
-
-SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
-    SkASSERT(index < fCommandVector.count());
-    return fCommandVector[index];
-}
-
-void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
-    SkASSERT(index < fCommandVector.count());
-    delete fCommandVector[index];
-    fCommandVector[index] = command;
-}
-
-const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
-    SkASSERT(index < fCommandVector.count());
-    return fCommandVector[index]->Info();
-}
-
-bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
-    SkASSERT(index < fCommandVector.count());
-    return fCommandVector[index]->isVisible();
-}
-
-const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
-    return fCommandVector;
-}
-
-SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
-    return fCommandVector;
-}
-
-GrAuditTrail* SkDebugCanvas::getAuditTrail(SkCanvas* canvas) {
-    GrAuditTrail* at = nullptr;
-#if SK_SUPPORT_GPU
-    GrContext* ctx = canvas->getGrContext();
-    if (ctx) {
-        at = ctx->getAuditTrail();
-    }
-#endif
-    return at;
-}
-
-void SkDebugCanvas::drawAndCollectOps(int n, SkCanvas* canvas) {
-#if SK_SUPPORT_GPU
-    GrAuditTrail* at = this->getAuditTrail(canvas);
-    if (at) {
-        // loop over all of the commands and draw them, this is to collect reordering
-        // information
-        for (int i = 0; i < this->getSize() && i <= n; i++) {
-            GrAuditTrail::AutoCollectOps enable(at, i);
-            fCommandVector[i]->execute(canvas);
-        }
-
-        // in case there is some kind of global reordering
-        {
-            GrAuditTrail::AutoEnable ae(at);
-            canvas->flush();
-        }
-    }
-#endif
-}
-
-void SkDebugCanvas::cleanupAuditTrail(SkCanvas* canvas) {
-    GrAuditTrail* at = this->getAuditTrail(canvas);
-    if (at) {
-#if SK_SUPPORT_GPU
-        GrAuditTrail::AutoEnable ae(at);
-        at->fullReset();
-#endif
-    }
-}
-
-Json::Value SkDebugCanvas::toJSON(UrlDataManager& urlDataManager, int n, SkCanvas* canvas) {
-    this->drawAndCollectOps(n, canvas);
-
-    // now collect json
-#if SK_SUPPORT_GPU
-    GrAuditTrail* at = this->getAuditTrail(canvas);
-#endif
-    Json::Value result = Json::Value(Json::objectValue);
-    result[SKDEBUGCANVAS_ATTRIBUTE_VERSION] = Json::Value(SKDEBUGCANVAS_VERSION);
-    Json::Value commands = Json::Value(Json::arrayValue);
-    for (int i = 0; i < this->getSize() && i <= n; i++) {
-        commands[i] = this->getDrawCommandAt(i)->toJSON(urlDataManager);
-#if SK_SUPPORT_GPU
-        if (at) {
-            // TODO if this is inefficient we could add a method to GrAuditTrail which takes
-            // a Json::Value and is only compiled in this file
-            Json::Value parsedFromString;
-            Json::Reader reader;
-            SkAssertResult(reader.parse(at->toJson(i).c_str(), parsedFromString));
-
-            commands[i][SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL] = parsedFromString;
-        }
-#endif
-    }
-    this->cleanupAuditTrail(canvas);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COMMANDS] = commands;
-    return result;
-}
-
-Json::Value SkDebugCanvas::toJSONOpList(int n, SkCanvas* canvas) {
-    this->drawAndCollectOps(n, canvas);
-
-    Json::Value parsedFromString;
-#if SK_SUPPORT_GPU
-    GrAuditTrail* at = this->getAuditTrail(canvas);
-    if (at) {
-        GrAuditTrail::AutoManageOpList enable(at);
-        Json::Reader reader;
-        SkAssertResult(reader.parse(at->toJson().c_str(), parsedFromString));
-    }
-#endif
-    this->cleanupAuditTrail(canvas);
-    return parsedFromString;
-}
-
-void SkDebugCanvas::setOverdrawViz(bool overdrawViz) {
-    fOverdrawViz = overdrawViz;
-}
-
-void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality quality) {
-    fOverrideFilterQuality = overrideTexFiltering;
-    fFilterQuality = quality;
-}
-
-void SkDebugCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
-    this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
-}
-
-void SkDebugCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
-    this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
-}
-
-void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
-    this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
-}
-
-void SkDebugCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
-    this->addDrawCommand(new SkClipRegionCommand(region, op));
-}
-
-void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
-    this->addDrawCommand(new SkConcatCommand(matrix));
-    this->INHERITED::didConcat(matrix);
-}
-
-void SkDebugCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
-    this->addDrawCommand(new SkDrawAnnotationCommand(rect, key, sk_ref_sp(value)));
-}
-
-void SkDebugCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
-                                 SkScalar top, const SkPaint* paint) {
-    this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
-}
-
-void SkDebugCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
-                                     const SkPaint* paint, SrcRectConstraint constraint) {
-    this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint,
-                                                     (SrcRectConstraint)constraint));
-}
-
-void SkDebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
-                                     const SkRect& dst, const SkPaint* paint) {
-    this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
-}
-
-void SkDebugCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
-                                const SkPaint* paint) {
-    this->addDrawCommand(new SkDrawImageCommand(image, left, top, paint));
-}
-
-void SkDebugCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
-                                       const SkRect& dst, const SkPaint* paint) {
-    this->addDrawCommand(new SkDrawImageLatticeCommand(image, lattice, dst, paint));
-}
-
-void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
-                                    const SkPaint* paint, SrcRectConstraint constraint) {
-    this->addDrawCommand(new SkDrawImageRectCommand(image, src, dst, paint, constraint));
-}
-
-void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
-}
-
-void SkDebugCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
-                               bool useCenter, const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint));
-}
-
-void SkDebugCanvas::onDrawPaint(const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawPaintCommand(paint));
-}
-
-void SkDebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawPathCommand(path, paint));
-}
-
-void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
-                                  const SkMatrix* matrix,
-                                  const SkPaint* paint) {
-    this->addDrawCommand(new SkBeginDrawPictureCommand(picture, matrix, paint));
-    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
-    picture->playback(this);
-    this->addDrawCommand(new SkEndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
-}
-
-void SkDebugCanvas::onDrawPoints(PointMode mode, size_t count,
-                                 const SkPoint pts[], const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
-}
-
-void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
-                                  const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
-}
-
-void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
-                                   SkScalar constY, const SkPaint& paint) {
-    this->addDrawCommand(
-        new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
-}
-
-void SkDebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
-    // NOTE(chudy): Messing up when renamed to DrawRect... Why?
-    addDrawCommand(new SkDrawRectCommand(rect, paint));
-}
-
-void SkDebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
-}
-
-void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
-                                 const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
-}
-
-void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
-                               const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
-}
-
-void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
-                                     const SkMatrix* matrix, const SkPaint& paint) {
-    this->addDrawCommand(
-        new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
-}
-
-void SkDebugCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
-                                      const SkRect* cull, const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawTextRSXformCommand(text, byteLength, xform, cull, paint));
-}
-
-void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
-                                   const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawTextBlobCommand(sk_ref_sp(const_cast<SkTextBlob*>(blob)),
-                                                   x, y, paint));
-}
-
-void SkDebugCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
-                                const SkPoint texCoords[4], SkBlendMode bmode,
-                                const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawPatchCommand(cubics, colors, texCoords, bmode, paint));
-}
-
-void SkDebugCanvas::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
-                                         const SkPaint& paint) {
-    this->addDrawCommand(new SkDrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)),
-                                                   bmode, paint));
-}
-
-void SkDebugCanvas::willRestore() {
-    this->addDrawCommand(new SkRestoreCommand());
-    this->INHERITED::willRestore();
-}
-
-void SkDebugCanvas::willSave() {
-    this->addDrawCommand(new SkSaveCommand());
-    this->INHERITED::willSave();
-}
-
-SkCanvas::SaveLayerStrategy SkDebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
-    this->addDrawCommand(new SkSaveLayerCommand(rec));
-    (void)this->INHERITED::getSaveLayerStrategy(rec);
-    // No need for a full layer.
-    return kNoLayer_SaveLayerStrategy;
-}
-
-void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
-    this->addDrawCommand(new SkSetMatrixCommand(matrix));
-    this->INHERITED::didSetMatrix(matrix);
-}
-
-void SkDebugCanvas::toggleCommand(int index, bool toggle) {
-    SkASSERT(index < fCommandVector.count());
-    fCommandVector[index]->setVisible(toggle);
-}
-
-static const char* gFillTypeStrs[] = {
-    "kWinding_FillType",
-    "kEvenOdd_FillType",
-    "kInverseWinding_FillType",
-    "kInverseEvenOdd_FillType"
-};
-
-static const char* gOpStrs[] = {
-    "kDifference_PathOp",
-    "kIntersect_PathOp",
-    "kUnion_PathOp",
-    "kXor_PathOp",
-    "kReverseDifference_PathOp",
-};
-
-static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
-
-void SkDebugCanvas::outputScalar(SkScalar num) {
-    if (num == (int) num) {
-        fClipStackData.appendf("%d", (int) num);
-    } else {
-        SkString str;
-        str.printf("%1.9g", num);
-        int width = (int) str.size();
-        const char* cStr = str.c_str();
-        while (cStr[width - 1] == '0') {
-            --width;
-        }
-        str.resize(width);
-        fClipStackData.appendf("%sf", str.c_str());
-    }
-}
-
-void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
-    for (int index = 0; index < count; ++index) {
-        this->outputScalar(pts[index].fX);
-        fClipStackData.appendf(", ");
-        this->outputScalar(pts[index].fY);
-        if (index + 1 < count) {
-            fClipStackData.appendf(", ");
-        }
-    }
-}
-
-void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
-    this->outputPointsCommon(pts, count);
-    fClipStackData.appendf(");<br>");
-}
-
-void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
-    this->outputPointsCommon(pts, 2);
-    fClipStackData.appendf(", ");
-    this->outputScalar(weight);
-    fClipStackData.appendf(");<br>");
-}
-
-void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
-    SkPath::RawIter iter(path);
-    SkPath::FillType fillType = path.getFillType();
-    fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
-    fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
-            gFillTypeStrs[fillType]);
-    iter.setPath(path);
-    uint8_t verb;
-    SkPoint pts[4];
-    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
-        switch (verb) {
-            case SkPath::kMove_Verb:
-                fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
-                this->outputPoints(&pts[0], 1);
-                continue;
-            case SkPath::kLine_Verb:
-                fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
-                this->outputPoints(&pts[1], 1);
-                break;
-            case SkPath::kQuad_Verb:
-                fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
-                this->outputPoints(&pts[1], 2);
-                break;
-            case SkPath::kConic_Verb:
-                fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
-                this->outputConicPoints(&pts[1], iter.conicWeight());
-                break;
-            case SkPath::kCubic_Verb:
-                fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
-                this->outputPoints(&pts[1], 3);
-                break;
-            case SkPath::kClose_Verb:
-                fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
-                break;
-            default:
-                SkDEBUGFAIL("bad verb");
-                return;
-        }
-    }
-}
-
-void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
-                                     SkClipOp elementOp) {
-    if (elementOp == kReplace_SkClipOp) {
-        if (!lastClipStackData(devPath)) {
-            fSaveDevPath = operand;
-        }
-        fCalledAddStackData = false;
-    } else {
-        fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
-            " const char* filename) {<br>");
-        addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
-        addPathData(operand, "pathB");
-        fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
-            kHTML4SpaceIndent, gOpStrs[static_cast<int>(elementOp)]);
-        fClipStackData.appendf("}<br>");
-        fCalledAddStackData = true;
-    }
-}
-
-bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
-    if (fCalledAddStackData) {
-        fClipStackData.appendf("<br>");
-        addPathData(devPath, "pathOut");
-        return true;
-    }
-    return false;
-}
diff --git a/src/third_party/skia/tools/debugger/SkDebugCanvas.h b/src/third_party/skia/tools/debugger/SkDebugCanvas.h
deleted file mode 100644
index 9b944f7..0000000
--- a/src/third_party/skia/tools/debugger/SkDebugCanvas.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef SKDEBUGCANVAS_H_
-#define SKDEBUGCANVAS_H_
-
-#include "SkCanvas.h"
-#include "SkDrawCommand.h"
-#include "SkPath.h"
-#include "SkPathOps.h"
-#include "SkPicture.h"
-#include "SkString.h"
-#include "SkTArray.h"
-#include "SkVertices.h"
-#include "UrlDataManager.h"
-
-class GrAuditTrail;
-class SkNWayCanvas;
-
-class SkDebugCanvas : public SkCanvas {
-public:
-    SkDebugCanvas(int width, int height);
-
-    ~SkDebugCanvas() override;
-
-    void toggleFilter(bool toggle) { fFilter = toggle; }
-
-    void setMegaVizMode(bool megaVizMode) { fMegaVizMode = megaVizMode; }
-
-    bool getMegaVizMode() const { return fMegaVizMode; }
-
-    /**
-     * Enable or disable overdraw visualization
-     */
-    void setOverdrawViz(bool overdrawViz);
-
-    bool getOverdrawViz() const { return fOverdrawViz; }
-
-    /**
-     * Set the color of the clip visualization. An alpha of zero renders the clip invisible.
-     */
-    void setClipVizColor(SkColor clipVizColor) { this->fClipVizColor = clipVizColor; }
-
-    SkColor getClipVizColor() const { return fClipVizColor; }
-
-    void setDrawGpuOpBounds(bool drawGpuOpBounds) { fDrawGpuOpBounds = drawGpuOpBounds; }
-
-    bool getDrawGpuOpBounds() const { return fDrawGpuOpBounds; }
-
-    bool getAllowSimplifyClip() const { return fAllowSimplifyClip; }
-
-    void setPicture(SkPicture *picture) { fPicture = picture; }
-
-    /**
-     * Enable or disable texure filtering override
-     */
-    void overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality);
-
-    /**
-        Executes all draw calls to the canvas.
-        @param canvas  The canvas being drawn to
-     */
-    void draw(SkCanvas *canvas);
-
-    /**
-        Executes the draw calls up to the specified index.
-        @param canvas  The canvas being drawn to
-        @param index  The index of the final command being executed
-        @param m an optional Mth gpu op to highlight, or -1
-     */
-    void drawTo(SkCanvas *canvas, int index, int m = -1);
-
-    /**
-        Returns the most recently calculated transformation matrix
-     */
-    const SkMatrix &getCurrentMatrix() {
-        return fMatrix;
-    }
-
-    /**
-        Returns the most recently calculated clip
-     */
-    const SkIRect &getCurrentClip() {
-        return fClip;
-    }
-
-    /**
-        Returns the index of the last draw command to write to the pixel at (x,y)
-     */
-    int getCommandAtPoint(int x, int y, int index);
-
-    /**
-        Removes the command at the specified index
-        @param index  The index of the command to delete
-     */
-    void deleteDrawCommandAt(int index);
-
-    /**
-        Returns the draw command at the given index.
-        @param index  The index of the command
-     */
-    SkDrawCommand *getDrawCommandAt(int index);
-
-    /**
-        Sets the draw command for a given index.
-        @param index  The index to overwrite
-        @param command The new command
-     */
-    void setDrawCommandAt(int index, SkDrawCommand *command);
-
-    /**
-        Returns information about the command at the given index.
-        @param index  The index of the command
-     */
-    const SkTDArray<SkString *> *getCommandInfo(int index) const;
-
-    /**
-        Returns the visibility of the command at the given index.
-        @param index  The index of the command
-     */
-    bool getDrawCommandVisibilityAt(int index);
-
-    /**
-        Returns the vector of draw commands
-     */
-    SK_ATTR_DEPRECATED("please use getDrawCommandAt and getSize instead")
-    const SkTDArray<SkDrawCommand *> &getDrawCommands() const;
-
-    /**
-        Returns the vector of draw commands. Do not use this entry
-        point - it is going away!
-     */
-    SkTDArray<SkDrawCommand *> &getDrawCommands();
-
-    /**
-        Returns length of draw command vector.
-     */
-    int getSize() const {
-        return fCommandVector.count();
-    }
-
-    /**
-        Toggles the visibility / execution of the draw command at index i with
-        the value of toggle.
-     */
-    void toggleCommand(int index, bool toggle);
-
-    void setUserMatrix(SkMatrix matrix) {
-        fUserMatrix = matrix;
-    }
-
-    SkString clipStackData() const { return fClipStackData; }
-
-    /**
-        Returns a JSON object representing up to the Nth draw, where N is less than
-        SkDebugCanvas::getSize(). The encoder may use the UrlDataManager to store binary data such
-        as images, referring to them via URLs embedded in the JSON.
-     */
-    Json::Value toJSON(UrlDataManager &urlDataManager, int n, SkCanvas *);
-
-    Json::Value toJSONOpList(int n, SkCanvas*);
-
-    ////////////////////////////////////////////////////////////////////////////////
-    // Inherited from SkCanvas
-    ////////////////////////////////////////////////////////////////////////////////
-
-    static const int kVizImageHeight = 256;
-    static const int kVizImageWidth = 256;
-
-    bool isClipEmpty() const override { return false; }
-
-    bool isClipRect() const override { return true; }
-
-    SkRect onGetLocalClipBounds() const override {
-        return SkRect::MakeIWH(this->imageInfo().width(), this->imageInfo().height());
-    }
-
-    SkIRect onGetDeviceClipBounds() const override {
-        return SkIRect::MakeWH(this->imageInfo().width(), this->imageInfo().height());
-    }
-
-protected:
-    void willSave() override;
-
-    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec &) override;
-
-    void willRestore() override;
-
-    void didConcat(const SkMatrix &) override;
-
-    void didSetMatrix(const SkMatrix &) override;
-
-    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
-    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
-    void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
-                    const SkPaint&) override;
-    void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
-                       const SkPaint&) override;
-    void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
-                        SkScalar constY, const SkPaint&) override;
-    void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
-                          const SkMatrix* matrix, const SkPaint&) override;
-    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], const SkRect*,
-                           const SkPaint&) override;
-    void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
-                        const SkPaint& paint) override;
-
-    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
-                     const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint) override;
-    void onDrawPaint(const SkPaint&) override;
-
-    void onDrawRect(const SkRect&, const SkPaint&) override;
-    void onDrawOval(const SkRect&, const SkPaint&) override;
-    void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
-    void onDrawRRect(const SkRRect&, const SkPaint&) override;
-    void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
-    void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
-    void onDrawPath(const SkPath&, const SkPaint&) override;
-    void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
-    void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
-                          SrcRectConstraint) override;
-    void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
-    void onDrawImageLattice(const SkImage* image, const Lattice& lattice,
-                            const SkRect& dst, const SkPaint* paint) override;
-    void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
-                         const SkPaint*, SrcRectConstraint) override;
-    void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
-                          const SkPaint*) override;
-    void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
-    void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
-    void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
-    void onClipRegion(const SkRegion& region, SkClipOp) override;
-
-    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
-
-    void markActiveCommands(int index);
-
-private:
-    SkTDArray<SkDrawCommand*> fCommandVector;
-    SkPicture* fPicture;
-    bool fFilter;
-    bool fMegaVizMode;
-    SkMatrix fUserMatrix;
-    SkMatrix fMatrix;
-    SkIRect fClip;
-
-    SkString fClipStackData;
-    bool fCalledAddStackData;
-    SkPath fSaveDevPath;
-
-    bool fOverdrawViz;
-    bool fOverrideFilterQuality;
-    SkFilterQuality fFilterQuality;
-    SkColor fClipVizColor;
-    bool fDrawGpuOpBounds;
-
-    /**
-        The active saveLayer commands at a given point in the renderering.
-        Only used when "mega" visualization is enabled.
-    */
-    SkTDArray<SkDrawCommand*> fActiveLayers;
-
-    /**
-        Adds the command to the classes vector of commands.
-        @param command  The draw command for execution
-     */
-    void addDrawCommand(SkDrawCommand* command);
-
-    /**
-        Applies any panning and zooming the user has specified before
-        drawing anything else into the canvas.
-     */
-    void applyUserTransform(SkCanvas* canvas);
-
-    void resetClipStackData() { fClipStackData.reset(); fCalledAddStackData = false; }
-
-    void addClipStackData(const SkPath& devPath, const SkPath& operand, SkClipOp elementOp);
-    void addPathData(const SkPath& path, const char* pathName);
-    bool lastClipStackData(const SkPath& devPath);
-    void outputConicPoints(const SkPoint* pts, SkScalar weight);
-    void outputPoints(const SkPoint* pts, int count);
-    void outputPointsCommon(const SkPoint* pts, int count);
-    void outputScalar(SkScalar num);
-
-    GrAuditTrail* getAuditTrail(SkCanvas*);
-
-    void drawAndCollectOps(int n, SkCanvas*);
-    void cleanupAuditTrail(SkCanvas*);
-
-    typedef SkCanvas INHERITED;
-};
-
-#endif
diff --git a/src/third_party/skia/tools/debugger/SkDrawCommand.cpp b/src/third_party/skia/tools/debugger/SkDrawCommand.cpp
deleted file mode 100644
index 5ae0307..0000000
--- a/src/third_party/skia/tools/debugger/SkDrawCommand.cpp
+++ /dev/null
@@ -1,3591 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkDrawCommand.h"
-
-#include "png.h"
-
-#include "SkAutoMalloc.h"
-#include "SkBlurMaskFilter.h"
-#include "SkColorFilter.h"
-#include "SkDashPathEffect.h"
-#include "SkImageFilter.h"
-#include "SkJsonWriteBuffer.h"
-#include "SkMaskFilter.h"
-#include "SkObjectParser.h"
-#include "SkPaintDefaults.h"
-#include "SkPathEffect.h"
-#include "SkPicture.h"
-#include "SkTextBlob.h"
-#include "SkTextBlobRunIterator.h"
-#include "SkTHash.h"
-#include "SkTypeface.h"
-#include "SkValidatingReadBuffer.h"
-#include "SkWriteBuffer.h"
-#include "picture_utils.h"
-#include "SkClipOpPriv.h"
-#include <SkLatticeIter.h>
-
-#define SKDEBUGCANVAS_ATTRIBUTE_COMMAND           "command"
-#define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE           "visible"
-#define SKDEBUGCANVAS_ATTRIBUTE_MATRIX            "matrix"
-#define SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS    "drawDepthTranslation"
-#define SKDEBUGCANVAS_ATTRIBUTE_COORDS            "coords"
-#define SKDEBUGCANVAS_ATTRIBUTE_HINTING           "hinting"
-#define SKDEBUGCANVAS_ATTRIBUTE_BOUNDS            "bounds"
-#define SKDEBUGCANVAS_ATTRIBUTE_PAINT             "paint"
-#define SKDEBUGCANVAS_ATTRIBUTE_OUTER             "outer"
-#define SKDEBUGCANVAS_ATTRIBUTE_INNER             "inner"
-#define SKDEBUGCANVAS_ATTRIBUTE_MODE              "mode"
-#define SKDEBUGCANVAS_ATTRIBUTE_POINTS            "points"
-#define SKDEBUGCANVAS_ATTRIBUTE_PATH              "path"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXT              "text"
-#define SKDEBUGCANVAS_ATTRIBUTE_COLOR             "color"
-#define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha"
-#define SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE         "blendMode"
-#define SKDEBUGCANVAS_ATTRIBUTE_STYLE             "style"
-#define SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH       "strokeWidth"
-#define SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER       "strokeMiter"
-#define SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN        "strokeJoin"
-#define SKDEBUGCANVAS_ATTRIBUTE_CAP               "cap"
-#define SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS         "antiAlias"
-#define SKDEBUGCANVAS_ATTRIBUTE_DITHER            "dither"
-#define SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT      "fakeBoldText"
-#define SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT        "linearText"
-#define SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT      "subpixelText"
-#define SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT       "devKernText"
-#define SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT     "lcdRenderText"
-#define SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText"
-#define SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING       "forceAutoHinting"
-#define SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT      "verticalText"
-#define SKDEBUGCANVAS_ATTRIBUTE_REGION            "region"
-#define SKDEBUGCANVAS_ATTRIBUTE_REGIONOP          "op"
-#define SKDEBUGCANVAS_ATTRIBUTE_EDGESTYLE         "edgeStyle"
-#define SKDEBUGCANVAS_ATTRIBUTE_DEVICEREGION      "deviceRegion"
-#define SKDEBUGCANVAS_ATTRIBUTE_BLUR              "blur"
-#define SKDEBUGCANVAS_ATTRIBUTE_SIGMA             "sigma"
-#define SKDEBUGCANVAS_ATTRIBUTE_QUALITY           "quality"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN         "textAlign"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE          "textSize"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX        "textScaleX"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX         "textSkewX"
-#define SKDEBUGCANVAS_ATTRIBUTE_DASHING           "dashing"
-#define SKDEBUGCANVAS_ATTRIBUTE_INTERVALS         "intervals"
-#define SKDEBUGCANVAS_ATTRIBUTE_PHASE             "phase"
-#define SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE          "fillType"
-#define SKDEBUGCANVAS_ATTRIBUTE_VERBS             "verbs"
-#define SKDEBUGCANVAS_ATTRIBUTE_NAME              "name"
-#define SKDEBUGCANVAS_ATTRIBUTE_DATA              "data"
-#define SKDEBUGCANVAS_ATTRIBUTE_VALUES            "values"
-#define SKDEBUGCANVAS_ATTRIBUTE_SHADER            "shader"
-#define SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT        "pathEffect"
-#define SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER        "maskFilter"
-#define SKDEBUGCANVAS_ATTRIBUTE_XFERMODE          "xfermode"
-#define SKDEBUGCANVAS_ATTRIBUTE_LOOPER            "looper"
-#define SKDEBUGCANVAS_ATTRIBUTE_BACKDROP          "backdrop"
-#define SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER       "colorfilter"
-#define SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER       "imagefilter"
-#define SKDEBUGCANVAS_ATTRIBUTE_IMAGE             "image"
-#define SKDEBUGCANVAS_ATTRIBUTE_BITMAP            "bitmap"
-#define SKDEBUGCANVAS_ATTRIBUTE_SRC               "src"
-#define SKDEBUGCANVAS_ATTRIBUTE_DST               "dst"
-#define SKDEBUGCANVAS_ATTRIBUTE_CENTER            "center"
-#define SKDEBUGCANVAS_ATTRIBUTE_STRICT            "strict"
-#define SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION       "description"
-#define SKDEBUGCANVAS_ATTRIBUTE_X                 "x"
-#define SKDEBUGCANVAS_ATTRIBUTE_Y                 "y"
-#define SKDEBUGCANVAS_ATTRIBUTE_RUNS              "runs"
-#define SKDEBUGCANVAS_ATTRIBUTE_POSITIONS         "positions"
-#define SKDEBUGCANVAS_ATTRIBUTE_GLYPHS            "glyphs"
-#define SKDEBUGCANVAS_ATTRIBUTE_FONT              "font"
-#define SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE          "typeface"
-#define SKDEBUGCANVAS_ATTRIBUTE_CUBICS            "cubics"
-#define SKDEBUGCANVAS_ATTRIBUTE_COLORS            "colors"
-#define SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS     "textureCoords"
-#define SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY     "filterQuality"
-#define SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE        "startAngle"
-#define SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE        "sweepAngle"
-#define SKDEBUGCANVAS_ATTRIBUTE_USECENTER         "useCenter"
-#define SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC         "shortDesc"
-#define SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID         "uniqueID"
-#define SKDEBUGCANVAS_ATTRIBUTE_WIDTH             "width"
-#define SKDEBUGCANVAS_ATTRIBUTE_HEIGHT            "height"
-#define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICE           "lattice"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT     "xCount"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT     "yCount"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS      "xDivs"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS      "yDivs"
-#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS      "flags"
-
-#define SKDEBUGCANVAS_VERB_MOVE                   "move"
-#define SKDEBUGCANVAS_VERB_LINE                   "line"
-#define SKDEBUGCANVAS_VERB_QUAD                   "quad"
-#define SKDEBUGCANVAS_VERB_CUBIC                  "cubic"
-#define SKDEBUGCANVAS_VERB_CONIC                  "conic"
-#define SKDEBUGCANVAS_VERB_CLOSE                  "close"
-
-#define SKDEBUGCANVAS_STYLE_FILL                  "fill"
-#define SKDEBUGCANVAS_STYLE_STROKE                "stroke"
-#define SKDEBUGCANVAS_STYLE_STROKEANDFILL         "strokeAndFill"
-
-#define SKDEBUGCANVAS_POINTMODE_POINTS            "points"
-#define SKDEBUGCANVAS_POINTMODE_LINES             "lines"
-#define SKDEBUGCANVAS_POINTMODE_POLYGON           "polygon"
-
-#define SKDEBUGCANVAS_REGIONOP_DIFFERENCE         "difference"
-#define SKDEBUGCANVAS_REGIONOP_INTERSECT          "intersect"
-#define SKDEBUGCANVAS_REGIONOP_UNION              "union"
-#define SKDEBUGCANVAS_REGIONOP_XOR                "xor"
-#define SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference"
-#define SKDEBUGCANVAS_REGIONOP_REPLACE            "replace"
-
-#define SKDEBUGCANVAS_BLURSTYLE_NORMAL            "normal"
-#define SKDEBUGCANVAS_BLURSTYLE_SOLID             "solid"
-#define SKDEBUGCANVAS_BLURSTYLE_OUTER             "outer"
-#define SKDEBUGCANVAS_BLURSTYLE_INNER             "inner"
-
-#define SKDEBUGCANVAS_BLURQUALITY_LOW             "low"
-#define SKDEBUGCANVAS_BLURQUALITY_HIGH            "high"
-
-#define SKDEBUGCANVAS_ALIGN_LEFT                  "left"
-#define SKDEBUGCANVAS_ALIGN_CENTER                "center"
-#define SKDEBUGCANVAS_ALIGN_RIGHT                 "right"
-
-#define SKDEBUGCANVAS_FILLTYPE_WINDING            "winding"
-#define SKDEBUGCANVAS_FILLTYPE_EVENODD            "evenOdd"
-#define SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING     "inverseWinding"
-#define SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD     "inverseEvenOdd"
-
-#define SKDEBUGCANVAS_CAP_BUTT                    "butt"
-#define SKDEBUGCANVAS_CAP_ROUND                   "round"
-#define SKDEBUGCANVAS_CAP_SQUARE                  "square"
-
-#define SKDEBUGCANVAS_MITER_JOIN                  "miter"
-#define SKDEBUGCANVAS_ROUND_JOIN                  "round"
-#define SKDEBUGCANVAS_BEVEL_JOIN                  "bevel"
-
-#define SKDEBUGCANVAS_COLORTYPE_ARGB4444          "ARGB4444"
-#define SKDEBUGCANVAS_COLORTYPE_RGBA8888          "RGBA8888"
-#define SKDEBUGCANVAS_COLORTYPE_BGRA8888          "BGRA8888"
-#define SKDEBUGCANVAS_COLORTYPE_565               "565"
-#define SKDEBUGCANVAS_COLORTYPE_GRAY8             "Gray8"
-#define SKDEBUGCANVAS_COLORTYPE_INDEX8            "Index8"
-#define SKDEBUGCANVAS_COLORTYPE_ALPHA8            "Alpha8"
-
-#define SKDEBUGCANVAS_ALPHATYPE_OPAQUE            "opaque"
-#define SKDEBUGCANVAS_ALPHATYPE_PREMUL            "premul"
-#define SKDEBUGCANVAS_ALPHATYPE_UNPREMUL          "unpremul"
-#define SKDEBUGCANVAS_ALPHATYPE_UNKNOWN           "unknown"
-
-#define SKDEBUGCANVAS_FILTERQUALITY_NONE          "none"
-#define SKDEBUGCANVAS_FILTERQUALITY_LOW           "low"
-#define SKDEBUGCANVAS_FILTERQUALITY_MEDIUM        "medium"
-#define SKDEBUGCANVAS_FILTERQUALITY_HIGH          "high"
-
-#define SKDEBUGCANVAS_HINTING_NONE                "none"
-#define SKDEBUGCANVAS_HINTING_SLIGHT              "slight"
-#define SKDEBUGCANVAS_HINTING_NORMAL              "normal"
-#define SKDEBUGCANVAS_HINTING_FULL                "full"
-
-typedef SkDrawCommand* (*FROM_JSON)(Json::Value&, UrlDataManager&);
-
-static SkString* str_append(SkString* str, const SkRect& r) {
-    str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom());
-    return str;
-}
-
-// TODO(chudy): Refactor into non subclass model.
-
-SkDrawCommand::SkDrawCommand(OpType type)
-    : fOpType(type)
-    , fVisible(true) {
-}
-
-SkDrawCommand::~SkDrawCommand() {
-    fInfo.deleteAll();
-}
-
-const char* SkDrawCommand::GetCommandString(OpType type) {
-    switch (type) {
-        case kBeginDrawPicture_OpType: return "BeginDrawPicture";
-        case kClipPath_OpType: return "ClipPath";
-        case kClipRegion_OpType: return "ClipRegion";
-        case kClipRect_OpType: return "ClipRect";
-        case kClipRRect_OpType: return "ClipRRect";
-        case kConcat_OpType: return "Concat";
-        case kDrawAnnotation_OpType: return "DrawAnnotation";
-        case kDrawBitmap_OpType: return "DrawBitmap";
-        case kDrawBitmapNine_OpType: return "DrawBitmapNine";
-        case kDrawBitmapRect_OpType: return "DrawBitmapRect";
-        case kDrawClear_OpType: return "DrawClear";
-        case kDrawDRRect_OpType: return "DrawDRRect";
-        case kDrawImage_OpType: return "DrawImage";
-        case kDrawImageLattice_OpType: return "DrawImageLattice";
-        case kDrawImageRect_OpType: return "DrawImageRect";
-        case kDrawOval_OpType: return "DrawOval";
-        case kDrawPaint_OpType: return "DrawPaint";
-        case kDrawPatch_OpType: return "DrawPatch";
-        case kDrawPath_OpType: return "DrawPath";
-        case kDrawPoints_OpType: return "DrawPoints";
-        case kDrawPosText_OpType: return "DrawPosText";
-        case kDrawPosTextH_OpType: return "DrawPosTextH";
-        case kDrawRect_OpType: return "DrawRect";
-        case kDrawRRect_OpType: return "DrawRRect";
-        case kDrawText_OpType: return "DrawText";
-        case kDrawTextBlob_OpType: return "DrawTextBlob";
-        case kDrawTextOnPath_OpType: return "DrawTextOnPath";
-        case kDrawTextRSXform_OpType: return "DrawTextRSXform";
-        case kDrawVertices_OpType: return "DrawVertices";
-        case kEndDrawPicture_OpType: return "EndDrawPicture";
-        case kRestore_OpType: return "Restore";
-        case kSave_OpType: return "Save";
-        case kSaveLayer_OpType: return "SaveLayer";
-        case kSetMatrix_OpType: return "SetMatrix";
-        default:
-            SkDebugf("OpType error 0x%08x\n", type);
-            SkASSERT(0);
-            break;
-    }
-    SkDEBUGFAIL("DrawType UNUSED\n");
-    return nullptr;
-}
-
-SkString SkDrawCommand::toString() const {
-    return SkString(GetCommandString(fOpType));
-}
-
-Json::Value SkDrawCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result;
-    result[SKDEBUGCANVAS_ATTRIBUTE_COMMAND] = this->GetCommandString(fOpType);
-    result[SKDEBUGCANVAS_ATTRIBUTE_VISIBLE] = Json::Value(this->isVisible());
-    return result;
-}
-
-#define INSTALL_FACTORY(name) factories.set(SkString(GetCommandString(k ## name ##_OpType)), \
-                                            (FROM_JSON) Sk ## name ## Command::fromJSON)
-SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
-    static SkTHashMap<SkString, FROM_JSON> factories;
-    static bool initialized = false;
-    if (!initialized) {
-        initialized = true;
-        INSTALL_FACTORY(Restore);
-        INSTALL_FACTORY(ClipPath);
-        INSTALL_FACTORY(ClipRegion);
-        INSTALL_FACTORY(ClipRect);
-        INSTALL_FACTORY(ClipRRect);
-        INSTALL_FACTORY(Concat);
-        INSTALL_FACTORY(DrawAnnotation);
-        INSTALL_FACTORY(DrawBitmap);
-        INSTALL_FACTORY(DrawBitmapRect);
-        INSTALL_FACTORY(DrawBitmapNine);
-        INSTALL_FACTORY(DrawImage);
-        INSTALL_FACTORY(DrawImageRect);
-        INSTALL_FACTORY(DrawOval);
-        INSTALL_FACTORY(DrawPaint);
-        INSTALL_FACTORY(DrawPath);
-        INSTALL_FACTORY(DrawPoints);
-        INSTALL_FACTORY(DrawText);
-        INSTALL_FACTORY(DrawPosText);
-        INSTALL_FACTORY(DrawPosTextH);
-        INSTALL_FACTORY(DrawTextOnPath);
-        INSTALL_FACTORY(DrawTextRSXform);
-        INSTALL_FACTORY(DrawTextBlob);
-
-        INSTALL_FACTORY(DrawRect);
-        INSTALL_FACTORY(DrawRRect);
-        INSTALL_FACTORY(DrawDRRect);
-        INSTALL_FACTORY(DrawPatch);
-        INSTALL_FACTORY(Save);
-        INSTALL_FACTORY(SaveLayer);
-        INSTALL_FACTORY(SetMatrix);
-    }
-    SkString name = SkString(command[SKDEBUGCANVAS_ATTRIBUTE_COMMAND].asCString());
-    FROM_JSON* factory = factories.find(name);
-    if (factory == nullptr) {
-        SkDebugf("no JSON factory for '%s'\n", name.c_str());
-        return nullptr;
-    }
-    return (*factory)(command, urlDataManager);
-}
-
-namespace {
-
-void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
-    const SkISize& size = canvas->getBaseLayerSize();
-
-    static const SkScalar kInsetFrac = 0.9f; // Leave a border around object
-
-    canvas->translate(size.fWidth/2.0f, size.fHeight/2.0f);
-    if (bounds.width() > bounds.height()) {
-        canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.width()),
-                      SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.width()));
-    } else {
-        canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.height()),
-                      SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.height()));
-    }
-    canvas->translate(-bounds.centerX(), -bounds.centerY());
-}
-
-
-void render_path(SkCanvas* canvas, const SkPath& path) {
-    canvas->clear(0xFFFFFFFF);
-
-    const SkRect& bounds = path.getBounds();
-    if (bounds.isEmpty()) {
-        return;
-    }
-
-    SkAutoCanvasRestore acr(canvas, true);
-    xlate_and_scale_to_bounds(canvas, bounds);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawPath(path, p);
-}
-
-void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) {
-    const SkISize& size = canvas->getBaseLayerSize();
-
-    SkScalar xScale = SkIntToScalar(size.fWidth-2) / input.width();
-    SkScalar yScale = SkIntToScalar(size.fHeight-2) / input.height();
-
-    if (input.width() > input.height()) {
-        yScale *= input.height() / (float) input.width();
-    } else {
-        xScale *= input.width() / (float) input.height();
-    }
-
-    SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
-                                  xScale * input.width(),
-                                  yScale * input.height());
-
-    static const int kNumBlocks = 8;
-
-    canvas->clear(0xFFFFFFFF);
-    SkISize block = {
-        canvas->imageInfo().width()/kNumBlocks,
-        canvas->imageInfo().height()/kNumBlocks
-    };
-    for (int y = 0; y < kNumBlocks; ++y) {
-        for (int x = 0; x < kNumBlocks; ++x) {
-            SkPaint paint;
-            paint.setColor((x+y)%2 ? SK_ColorLTGRAY : SK_ColorDKGRAY);
-            SkRect r = SkRect::MakeXYWH(SkIntToScalar(x*block.width()),
-                                        SkIntToScalar(y*block.height()),
-                                        SkIntToScalar(block.width()),
-                                        SkIntToScalar(block.height()));
-            canvas->drawRect(r, paint);
-        }
-    }
-
-    canvas->drawBitmapRect(input, dst, nullptr);
-
-    if (srcRect) {
-        SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
-                                    srcRect->fTop * yScale + SK_Scalar1,
-                                    srcRect->fRight * xScale + SK_Scalar1,
-                                    srcRect->fBottom * yScale + SK_Scalar1);
-        SkPaint p;
-        p.setColor(SK_ColorRED);
-        p.setStyle(SkPaint::kStroke_Style);
-
-        canvas->drawRect(r, p);
-    }
-}
-
-void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    const SkRect& bounds = rrect.getBounds();
-
-    xlate_and_scale_to_bounds(canvas, bounds);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawRRect(rrect, p);
-    canvas->restore();
-}
-
-void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    const SkRect& bounds = outer.getBounds();
-
-    xlate_and_scale_to_bounds(canvas, bounds);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawDRRect(outer, inner, p);
-    canvas->restore();
-}
-
-static const char* const gBlendModeMap[] = {
-    "clear",
-    "src",
-    "dst",
-    "srcOver",
-    "dstOver",
-    "srcIn",
-    "dstIn",
-    "srcOut",
-    "dstOut",
-    "srcATop",
-    "dstATop",
-    "xor",
-    "plus",
-    "modulate",
-
-    "screen",
-
-    "overlay",
-    "darken",
-    "lighten",
-    "colorDodge",
-    "colorBurn",
-    "hardLight",
-    "softLight",
-    "difference",
-    "exclusion",
-    "multiply",
-
-    "hue",
-    "saturation",
-    "color",
-    "luminosity",
-};
-
-static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLastMode) + 1,
-              "blendMode mismatch");
-static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLuminosity) + 1,
-              "blendMode mismatch");
-
-void apply_paint_blend_mode(const SkPaint& paint, Json::Value* target) {
-    const auto mode = paint.getBlendMode();
-    if (mode != SkBlendMode::kSrcOver) {
-        SkASSERT(static_cast<size_t>(mode) < SK_ARRAY_COUNT(gBlendModeMap));
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE] =
-            Json::Value(gBlendModeMap[static_cast<size_t>(mode)]);
-    }
-}
-
-void extract_json_paint_blend_mode(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE)) {
-        const char* mode = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE].asCString();
-
-        for (size_t i = 0; i < SK_ARRAY_COUNT(gBlendModeMap); ++i) {
-            if (!strcmp(mode, gBlendModeMap[i])) {
-                target->setBlendMode(static_cast<SkBlendMode>(i));
-                break;
-            }
-        }
-    }
-}
-
-};
-
-Json::Value SkDrawCommand::MakeJsonColor(const SkColor color) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(SkColorGetA(color)));
-    result.append(Json::Value(SkColorGetR(color)));
-    result.append(Json::Value(SkColorGetG(color)));
-    result.append(Json::Value(SkColorGetB(color)));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonColor4f(const SkColor4f& color) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(color.fA));
-    result.append(Json::Value(color.fR));
-    result.append(Json::Value(color.fG));
-    result.append(Json::Value(color.fB));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonPoint(const SkPoint& point) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(point.x()));
-    result.append(Json::Value(point.y()));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonPoint(SkScalar x, SkScalar y) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(x));
-    result.append(Json::Value(y));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonRect(const SkRect& rect) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(rect.left()));
-    result.append(Json::Value(rect.top()));
-    result.append(Json::Value(rect.right()));
-    result.append(Json::Value(rect.bottom()));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonIRect(const SkIRect& rect) {
-    Json::Value result(Json::arrayValue);
-    result.append(Json::Value(rect.left()));
-    result.append(Json::Value(rect.top()));
-    result.append(Json::Value(rect.right()));
-    result.append(Json::Value(rect.bottom()));
-    return result;
-}
-
-static Json::Value make_json_rrect(const SkRRect& rrect) {
-    Json::Value result(Json::arrayValue);
-    result.append(SkDrawCommand::MakeJsonRect(rrect.rect()));
-    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kUpperLeft_Corner)));
-    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kUpperRight_Corner)));
-    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kLowerRight_Corner)));
-    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kLowerLeft_Corner)));
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonMatrix(const SkMatrix& matrix) {
-    Json::Value result(Json::arrayValue);
-    Json::Value row1(Json::arrayValue);
-    row1.append(Json::Value(matrix[0]));
-    row1.append(Json::Value(matrix[1]));
-    row1.append(Json::Value(matrix[2]));
-    result.append(row1);
-    Json::Value row2(Json::arrayValue);
-    row2.append(Json::Value(matrix[3]));
-    row2.append(Json::Value(matrix[4]));
-    row2.append(Json::Value(matrix[5]));
-    result.append(row2);
-    Json::Value row3(Json::arrayValue);
-    row3.append(Json::Value(matrix[6]));
-    row3.append(Json::Value(matrix[7]));
-    row3.append(Json::Value(matrix[8]));
-    result.append(row3);
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonScalar(SkScalar z) {
-    Json::Value result(z);
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonPath(const SkPath& path) {
-    Json::Value result(Json::objectValue);
-    switch (path.getFillType()) {
-        case SkPath::kWinding_FillType:
-            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_WINDING;
-            break;
-        case SkPath::kEvenOdd_FillType:
-            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_EVENODD;
-            break;
-        case SkPath::kInverseWinding_FillType:
-            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING;
-            break;
-        case SkPath::kInverseEvenOdd_FillType:
-            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD;
-            break;
-    }
-    Json::Value verbs(Json::arrayValue);
-    SkPath::Iter iter(path, false);
-    SkPoint pts[4];
-    SkPath::Verb verb;
-    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
-        switch (verb) {
-            case SkPath::kLine_Verb: {
-                Json::Value line(Json::objectValue);
-                line[SKDEBUGCANVAS_VERB_LINE] = MakeJsonPoint(pts[1]);
-                verbs.append(line);
-                break;
-            }
-            case SkPath::kQuad_Verb: {
-                Json::Value quad(Json::objectValue);
-                Json::Value coords(Json::arrayValue);
-                coords.append(MakeJsonPoint(pts[1]));
-                coords.append(MakeJsonPoint(pts[2]));
-                quad[SKDEBUGCANVAS_VERB_QUAD] = coords;
-                verbs.append(quad);
-                break;
-            }
-            case SkPath::kCubic_Verb: {
-                Json::Value cubic(Json::objectValue);
-                Json::Value coords(Json::arrayValue);
-                coords.append(MakeJsonPoint(pts[1]));
-                coords.append(MakeJsonPoint(pts[2]));
-                coords.append(MakeJsonPoint(pts[3]));
-                cubic[SKDEBUGCANVAS_VERB_CUBIC] = coords;
-                verbs.append(cubic);
-                break;
-            }
-            case SkPath::kConic_Verb: {
-                Json::Value conic(Json::objectValue);
-                Json::Value coords(Json::arrayValue);
-                coords.append(MakeJsonPoint(pts[1]));
-                coords.append(MakeJsonPoint(pts[2]));
-                coords.append(Json::Value(iter.conicWeight()));
-                conic[SKDEBUGCANVAS_VERB_CONIC] = coords;
-                verbs.append(conic);
-                break;
-            }
-            case SkPath::kMove_Verb: {
-                Json::Value move(Json::objectValue);
-                move[SKDEBUGCANVAS_VERB_MOVE] = MakeJsonPoint(pts[0]);
-                verbs.append(move);
-                break;
-            }
-            case SkPath::kClose_Verb:
-                verbs.append(Json::Value(SKDEBUGCANVAS_VERB_CLOSE));
-                break;
-            case SkPath::kDone_Verb:
-                break;
-        }
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_VERBS] = verbs;
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonRegion(const SkRegion& region) {
-    return Json::Value("<unimplemented>");
-}
-
-static Json::Value make_json_regionop(SkClipOp op) {
-    switch (op) {
-        case kDifference_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_DIFFERENCE);
-        case kIntersect_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_INTERSECT);
-        case kUnion_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_UNION);
-        case kXOR_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_XOR);
-        case kReverseDifference_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE);
-        case kReplace_SkClipOp:
-            return Json::Value(SKDEBUGCANVAS_REGIONOP_REPLACE);
-        default:
-            SkASSERT(false);
-            return Json::Value("<invalid region op>");
-    };
-}
-
-static Json::Value make_json_pointmode(SkCanvas::PointMode mode) {
-    switch (mode) {
-        case SkCanvas::kPoints_PointMode:
-            return Json::Value(SKDEBUGCANVAS_POINTMODE_POINTS);
-        case SkCanvas::kLines_PointMode:
-            return Json::Value(SKDEBUGCANVAS_POINTMODE_LINES);
-        case SkCanvas::kPolygon_PointMode:
-            return Json::Value(SKDEBUGCANVAS_POINTMODE_POLYGON);
-        default:
-            SkASSERT(false);
-            return Json::Value("<invalid point mode>");
-    };
-}
-
-static void store_scalar(Json::Value* target, const char* key, SkScalar value,
-                         SkScalar defaultValue) {
-    if (value != defaultValue) {
-        (*target)[key] = Json::Value(value);
-    }
-}
-
-static void store_bool(Json::Value* target, const char* key, bool value, bool defaultValue) {
-    if (value != defaultValue) {
-        (*target)[key] = Json::Value(value);
-    }
-}
-
-static void encode_data(const void* bytes, size_t count, const char* contentType,
-                        UrlDataManager& urlDataManager, Json::Value* target) {
-    sk_sp<SkData> data(SkData::MakeWithCopy(bytes, count));
-    SkString url = urlDataManager.addData(data.get(), contentType);
-    *target = Json::Value(url.c_str());
-}
-
-void SkDrawCommand::flatten(const SkFlattenable* flattenable, Json::Value* target,
-                            UrlDataManager& urlDataManager) {
-    SkBinaryWriteBuffer buffer;
-    flattenable->flatten(buffer);
-    void* data = sk_malloc_throw(buffer.bytesWritten());
-    buffer.writeToMemory(data);
-    Json::Value jsonData;
-    encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager, &jsonData);
-    Json::Value jsonFlattenable;
-    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName());
-    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
-
-    SkJsonWriteBuffer jsonBuffer(&urlDataManager);
-    flattenable->flatten(jsonBuffer);
-    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_VALUES] = jsonBuffer.getValue();
-
-    (*target) = jsonFlattenable;
-    sk_free(data);
-}
-
-static void write_png_callback(png_structp png_ptr, png_bytep data, png_size_t length) {
-    SkWStream* out = (SkWStream*) png_get_io_ptr(png_ptr);
-    out->write(data, length);
-}
-
-void SkDrawCommand::WritePNG(const uint8_t* rgba, unsigned width, unsigned height,
-                             SkWStream& out, bool isOpaque) {
-    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    SkASSERT(png != nullptr);
-    png_infop info_ptr = png_create_info_struct(png);
-    SkASSERT(info_ptr != nullptr);
-    if (setjmp(png_jmpbuf(png))) {
-        SkFAIL("png encode error");
-    }
-    png_set_write_fn(png, &out, write_png_callback, NULL);
-    int colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA;
-    png_set_IHDR(png, info_ptr, width, height, 8, colorType, PNG_INTERLACE_NONE,
-                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-    png_set_compression_level(png, 1);
-    png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*));
-    png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 4);
-    for (png_size_t y = 0; y < height; ++y) {
-        const uint8_t* src = rgba + y * width * 4;
-        rows[y] = pixels + y * width * 4;
-        for (png_size_t x = 0; x < width; ++x) {
-            rows[y][x * 4] = src[x * 4];
-            rows[y][x * 4 + 1] = src[x * 4 + 1];
-            rows[y][x * 4 + 2] = src[x * 4 + 2];
-            rows[y][x * 4 + 3] = src[x * 4 + 3];
-        }
-    }
-    png_write_info(png, info_ptr);
-    if (isOpaque) {
-        png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
-    }
-    png_set_filter(png, 0, PNG_NO_FILTERS);
-    png_write_image(png, &rows[0]);
-    png_destroy_write_struct(&png, NULL);
-    sk_free(rows);
-    sk_free(pixels);
-}
-
-bool SkDrawCommand::flatten(const SkImage& image, Json::Value* target,
-                            UrlDataManager& urlDataManager) {
-    size_t rowBytes = 4 * image.width();
-    SkAutoMalloc buffer(rowBytes * image.height());
-    SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(),
-                                            kN32_SkColorType, kPremul_SkAlphaType);
-    if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) {
-        SkDebugf("readPixels failed\n");
-        return false;
-    }
-
-    SkBitmap bm;
-    bm.installPixels(dstInfo, buffer.get(), rowBytes);
-    sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(bm);
-
-    SkDynamicMemoryWStream out;
-    SkDrawCommand::WritePNG(encodedBitmap->bytes(), image.width(), image.height(),
-                            out, false);
-    sk_sp<SkData> encoded = out.detachAsData();
-    Json::Value jsonData;
-    encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager, &jsonData);
-    (*target)[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
-    return true;
-}
-
-static const char* color_type_name(SkColorType colorType) {
-    switch (colorType) {
-        case kARGB_4444_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_ARGB4444;
-        case kRGBA_8888_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
-        case kBGRA_8888_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_BGRA8888;
-        case kRGB_565_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_565;
-        case kGray_8_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_GRAY8;
-        case kAlpha_8_SkColorType:
-            return SKDEBUGCANVAS_COLORTYPE_ALPHA8;
-        default:
-            SkASSERT(false);
-            return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
-    }
-}
-
-static const char* alpha_type_name(SkAlphaType alphaType) {
-    switch (alphaType) {
-        case kOpaque_SkAlphaType:
-            return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
-        case kPremul_SkAlphaType:
-            return SKDEBUGCANVAS_ALPHATYPE_PREMUL;
-        case kUnpremul_SkAlphaType:
-            return SKDEBUGCANVAS_ALPHATYPE_UNPREMUL;
-        default:
-            SkASSERT(false);
-            return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
-    }
-}
-
-static Json::ArrayIndex decode_data(Json::Value data, UrlDataManager& urlDataManager,
-                                    const void** target) {
-    UrlDataManager::UrlData* urlData = urlDataManager.getDataFromUrl(SkString(data.asCString()));
-    if (urlData == nullptr) {
-        SkASSERT(false);
-        *target = nullptr;
-        return 0;
-    }
-    *target = urlData->fData->data();
-    // cast should be safe for any reasonably-sized object...
-    return (Json::ArrayIndex) urlData->fData->size();
-}
-
-static SkFlattenable* load_flattenable(Json::Value jsonFlattenable,
-                                       UrlDataManager& urlDataManager) {
-    if (!jsonFlattenable.isMember(SKDEBUGCANVAS_ATTRIBUTE_NAME)) {
-        return nullptr;
-    }
-    const char* name = jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME].asCString();
-    SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name);
-    if (factory == nullptr) {
-        SkDebugf("no factory for loading '%s'\n", name);
-        return nullptr;
-    }
-    const void* data;
-    int size = decode_data(jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
-    SkValidatingReadBuffer buffer(data, size);
-    sk_sp<SkFlattenable> result = factory(buffer);
-    if (!buffer.isValid()) {
-        SkDebugf("invalid buffer loading flattenable\n");
-        return nullptr;
-    }
-    return result.release();
-}
-
-static SkColorType colortype_from_name(const char* name) {
-    if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ARGB4444)) {
-        return kARGB_4444_SkColorType;
-    }
-    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_RGBA8888)) {
-        return kRGBA_8888_SkColorType;
-    }
-    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_BGRA8888)) {
-        return kBGRA_8888_SkColorType;
-    }
-    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_565)) {
-        return kRGB_565_SkColorType;
-    }
-    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_GRAY8)) {
-        return kGray_8_SkColorType;
-    }
-    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ALPHA8)) {
-        return kAlpha_8_SkColorType;
-    }
-    SkASSERT(false);
-    return kN32_SkColorType;
-}
-
-static SkBitmap* convert_colortype(SkBitmap* bitmap, SkColorType colorType) {
-    if (bitmap->colorType() == colorType  ) {
-        return bitmap;
-    }
-    SkBitmap* dst = new SkBitmap();
-    if (dst->tryAllocPixels(bitmap->info().makeColorType(colorType)) &&
-        bitmap->readPixels(dst->info(), dst->getPixels(), dst->rowBytes(), 0, 0))
-    {
-        delete bitmap;
-        return dst;
-    }
-    SkASSERT(false);
-    delete dst;
-    return bitmap;
-}
-
-// caller is responsible for freeing return value
-static SkBitmap* load_bitmap(const Json::Value& jsonBitmap, UrlDataManager& urlDataManager) {
-    if (!jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_DATA)) {
-        SkDebugf("invalid bitmap\n");
-        return nullptr;
-    }
-    const void* data;
-    int size = decode_data(jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
-    sk_sp<SkData> encoded(SkData::MakeWithoutCopy(data, size));
-    sk_sp<SkImage> image(SkImage::MakeFromEncoded(std::move(encoded), nullptr));
-
-    std::unique_ptr<SkBitmap> bitmap(new SkBitmap());
-    if (nullptr != image) {
-        if (!image->asLegacyBitmap(bitmap.get(), SkImage::kRW_LegacyBitmapMode)) {
-            SkDebugf("image decode failed\n");
-            return nullptr;
-        }
-
-        if (jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) {
-            const char* ctName = jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_COLOR].asCString();
-            SkColorType ct = colortype_from_name(ctName);
-            bitmap.reset(convert_colortype(bitmap.release(), ct));
-        }
-        return bitmap.release();
-    }
-    SkDebugf("image decode failed\n");
-    return nullptr;
-}
-
-static sk_sp<SkImage> load_image(const Json::Value& jsonImage, UrlDataManager& urlDataManager) {
-    SkBitmap* bitmap = load_bitmap(jsonImage, urlDataManager);
-    if (bitmap == nullptr) {
-        return nullptr;
-    }
-    auto result = SkImage::MakeFromBitmap(*bitmap);
-    delete bitmap;
-    return result;
-}
-
-bool SkDrawCommand::flatten(const SkBitmap& bitmap, Json::Value* target,
-                            UrlDataManager& urlDataManager) {
-    sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap));
-    (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = Json::Value(color_type_name(bitmap.colorType()));
-    (*target)[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = Json::Value(alpha_type_name(bitmap.alphaType()));
-    bool success = flatten(*image, target, urlDataManager);
-    return success;
-}
-
-static void apply_paint_hinting(const SkPaint& paint, Json::Value* target) {
-    SkPaint::Hinting hinting = paint.getHinting();
-    if (hinting != SkPaintDefaults_Hinting) {
-        switch (hinting) {
-            case SkPaint::kNo_Hinting:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_NONE;
-                break;
-            case SkPaint::kSlight_Hinting:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_SLIGHT;
-                break;
-            case SkPaint::kNormal_Hinting:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_NORMAL;
-                break;
-            case SkPaint::kFull_Hinting:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_FULL;
-                break;
-        }
-    }
-}
-
-static void apply_paint_color(const SkPaint& paint, Json::Value* target) {
-    SkColor color = paint.getColor();
-    if (color != SK_ColorBLACK) {
-        Json::Value colorValue(Json::arrayValue);
-        colorValue.append(Json::Value(SkColorGetA(color)));
-        colorValue.append(Json::Value(SkColorGetR(color)));
-        colorValue.append(Json::Value(SkColorGetG(color)));
-        colorValue.append(Json::Value(SkColorGetB(color)));
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = colorValue;;
-    }
-}
-
-static void apply_paint_style(const SkPaint& paint, Json::Value* target) {
-    SkPaint::Style style = paint.getStyle();
-    if (style != SkPaint::kFill_Style) {
-        switch (style) {
-            case SkPaint::kStroke_Style: {
-                Json::Value stroke(SKDEBUGCANVAS_STYLE_STROKE);
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = stroke;
-                break;
-            }
-            case SkPaint::kStrokeAndFill_Style: {
-                Json::Value strokeAndFill(SKDEBUGCANVAS_STYLE_STROKEANDFILL);
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = strokeAndFill;
-                break;
-            }
-            default: SkASSERT(false);
-        }
-    }
-}
-
-static void apply_paint_cap(const SkPaint& paint, Json::Value* target) {
-    SkPaint::Cap cap = paint.getStrokeCap();
-    if (cap != SkPaint::kDefault_Cap) {
-        switch (cap) {
-            case SkPaint::kButt_Cap:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_BUTT);
-                break;
-            case SkPaint::kRound_Cap:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_ROUND);
-                break;
-            case SkPaint::kSquare_Cap:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_SQUARE);
-                break;
-            default: SkASSERT(false);
-        }
-    }
-}
-
-static void apply_paint_join(const SkPaint& paint, Json::Value* target) {
-    SkPaint::Join join = paint.getStrokeJoin();
-    if (join != SkPaint::kDefault_Join) {
-        switch (join) {
-            case SkPaint::kMiter_Join:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
-                                                                          SKDEBUGCANVAS_MITER_JOIN);
-                break;
-            case SkPaint::kRound_Join:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
-                                                                          SKDEBUGCANVAS_ROUND_JOIN);
-                break;
-            case SkPaint::kBevel_Join:
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
-                                                                        SKDEBUGCANVAS_BEVEL_JOIN);
-                break;
-            default: SkASSERT(false);
-        }
-    }
-}
-
-static void apply_paint_filterquality(const SkPaint& paint, Json::Value* target) {
-    SkFilterQuality quality = paint.getFilterQuality();
-    switch (quality) {
-        case kNone_SkFilterQuality:
-            break;
-        case kLow_SkFilterQuality:
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
-                                                                   SKDEBUGCANVAS_FILTERQUALITY_LOW);
-            break;
-        case kMedium_SkFilterQuality:
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
-                                                                SKDEBUGCANVAS_FILTERQUALITY_MEDIUM);
-            break;
-        case kHigh_SkFilterQuality:
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
-                                                                  SKDEBUGCANVAS_FILTERQUALITY_HIGH);
-            break;
-    }
-}
-
-static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target,
-                                   UrlDataManager& urlDataManager) {
-    SkMaskFilter* maskFilter = paint.getMaskFilter();
-    if (maskFilter != nullptr) {
-        SkMaskFilter::BlurRec blurRec;
-        if (maskFilter->asABlur(&blurRec)) {
-            Json::Value blur(Json::objectValue);
-            blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma);
-            switch (blurRec.fStyle) {
-                case SkBlurStyle::kNormal_SkBlurStyle:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
-                                                                    SKDEBUGCANVAS_BLURSTYLE_NORMAL);
-                    break;
-                case SkBlurStyle::kSolid_SkBlurStyle:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
-                                                                     SKDEBUGCANVAS_BLURSTYLE_SOLID);
-                    break;
-                case SkBlurStyle::kOuter_SkBlurStyle:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
-                                                                     SKDEBUGCANVAS_BLURSTYLE_OUTER);
-                    break;
-                case SkBlurStyle::kInner_SkBlurStyle:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
-                                                                     SKDEBUGCANVAS_BLURSTYLE_INNER);
-                    break;
-                default:
-                    SkASSERT(false);
-            }
-            switch (blurRec.fQuality) {
-                case SkBlurQuality::kLow_SkBlurQuality:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value(
-                                                                     SKDEBUGCANVAS_BLURQUALITY_LOW);
-                    break;
-                case SkBlurQuality::kHigh_SkBlurQuality:
-                    blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value(
-                                                                    SKDEBUGCANVAS_BLURQUALITY_HIGH);
-                    break;
-                default:
-                    SkASSERT(false);
-            }
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLUR] = blur;
-        } else {
-            Json::Value jsonMaskFilter;
-            SkDrawCommand::flatten(maskFilter, &jsonMaskFilter, urlDataManager);
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter;
-        }
-    }
-}
-
-static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target,
-                                   UrlDataManager& urlDataManager) {
-    SkPathEffect* pathEffect = paint.getPathEffect();
-    if (pathEffect != nullptr) {
-        SkPathEffect::DashInfo dashInfo;
-        SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
-        if (dashType == SkPathEffect::kDash_DashType) {
-            dashInfo.fIntervals = (SkScalar*) sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
-            pathEffect->asADash(&dashInfo);
-            Json::Value dashing(Json::objectValue);
-            Json::Value intervals(Json::arrayValue);
-            for (int32_t i = 0; i < dashInfo.fCount; i++) {
-                intervals.append(Json::Value(dashInfo.fIntervals[i]));
-            }
-            sk_free(dashInfo.fIntervals);
-            dashing[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS] = intervals;
-            dashing[SKDEBUGCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase;
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_DASHING] = dashing;
-        } else {
-            Json::Value jsonPathEffect;
-            SkDrawCommand::flatten(pathEffect, &jsonPathEffect, urlDataManager);
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect;
-        }
-    }
-}
-
-static void apply_paint_textalign(const SkPaint& paint, Json::Value* target) {
-    SkPaint::Align textAlign = paint.getTextAlign();
-    if (textAlign != SkPaint::kLeft_Align) {
-        switch (textAlign) {
-            case SkPaint::kCenter_Align: {
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_CENTER;
-                break;
-            }
-            case SkPaint::kRight_Align: {
-                (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_RIGHT;
-                break;
-            }
-            default: SkASSERT(false);
-        }
-    }
-}
-
-static void apply_paint_typeface(const SkPaint& paint, Json::Value* target,
-                                 UrlDataManager& urlDataManager) {
-    SkTypeface* typeface = paint.getTypeface();
-    if (typeface != nullptr) {
-        Json::Value jsonTypeface;
-        SkDynamicMemoryWStream buffer;
-        typeface->serialize(&buffer);
-        void* data = sk_malloc_throw(buffer.bytesWritten());
-        buffer.copyTo(data);
-        Json::Value jsonData;
-        encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager,
-                    &jsonData);
-        jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
-        sk_free(data);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE] = jsonTypeface;
-    }
-}
-
-static void apply_paint_shader(const SkPaint& paint, Json::Value* target,
-                               UrlDataManager& urlDataManager) {
-    SkFlattenable* shader = paint.getShader();
-    if (shader != nullptr) {
-        Json::Value jsonShader;
-        SkDrawCommand::flatten(shader, &jsonShader, urlDataManager);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_SHADER] = jsonShader;
-    }
-}
-
-static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target,
-                                    UrlDataManager& urlDataManager) {
-    SkFlattenable* imageFilter = paint.getImageFilter();
-    if (imageFilter != nullptr) {
-        Json::Value jsonImageFilter;
-        SkDrawCommand::flatten(imageFilter, &jsonImageFilter, urlDataManager);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter;
-    }
-}
-
-static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target,
-                                    UrlDataManager& urlDataManager) {
-    SkFlattenable* colorFilter = paint.getColorFilter();
-    if (colorFilter != nullptr) {
-        Json::Value jsonColorFilter;
-        SkDrawCommand::flatten(colorFilter, &jsonColorFilter, urlDataManager);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER] = jsonColorFilter;
-    }
-}
-
-static void apply_paint_looper(const SkPaint& paint, Json::Value* target,
-                               UrlDataManager& urlDataManager) {
-    SkFlattenable* looper = paint.getLooper();
-    if (looper != nullptr) {
-        Json::Value jsonLooper;
-        SkDrawCommand::flatten(looper, &jsonLooper, urlDataManager);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_LOOPER] = jsonLooper;
-    }
-}
-
-Json::Value SkDrawCommand::MakeJsonPaint(const SkPaint& paint, UrlDataManager& urlDataManager) {
-    Json::Value result(Json::objectValue);
-    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
-    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(),
-                 SkPaintDefaults_MiterLimit);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, paint.isFakeBoldText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT, paint.isLinearText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, paint.isSubpixelText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT, paint.isDevKernText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT, paint.isLCDRenderText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, paint.isEmbeddedBitmapText(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING, paint.isAutohinted(), false);
-    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT, paint.isVerticalText(), false);
-    //kGenA8FromLCD_Flag
-
-    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(),
-                 SkPaintDefaults_TextSize);
-    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1);
-    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f);
-    apply_paint_hinting(paint, &result);
-    apply_paint_color(paint, &result);
-    apply_paint_style(paint, &result);
-    apply_paint_blend_mode(paint, &result);
-    apply_paint_cap(paint, &result);
-    apply_paint_join(paint, &result);
-    apply_paint_filterquality(paint, &result);
-    apply_paint_textalign(paint, &result);
-    apply_paint_patheffect(paint, &result, urlDataManager);
-    apply_paint_maskfilter(paint, &result, urlDataManager);
-    apply_paint_shader(paint, &result, urlDataManager);
-    apply_paint_looper(paint, &result, urlDataManager);
-    apply_paint_imagefilter(paint, &result, urlDataManager);
-    apply_paint_colorfilter(paint, &result, urlDataManager);
-    apply_paint_typeface(paint, &result, urlDataManager);
-    return result;
-}
-
-Json::Value SkDrawCommand::MakeJsonLattice(const SkCanvas::Lattice& lattice) {
-    Json::Value result(Json::objectValue);
-    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT] = Json::Value(lattice.fXCount);
-    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT] = Json::Value(lattice.fYCount);
-    if (nullptr != lattice.fBounds) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = MakeJsonIRect(*lattice.fBounds);
-    }
-    Json::Value XDivs(Json::arrayValue);
-    for (int i = 0; i < lattice.fXCount; i++) {
-        XDivs.append(Json::Value(lattice.fXDivs[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS] = XDivs;
-    Json::Value YDivs(Json::arrayValue);
-    for (int i = 0; i < lattice.fYCount; i++) {
-        YDivs.append(Json::Value(lattice.fYDivs[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS] = YDivs;
-    if (nullptr != lattice.fFlags) {
-        Json::Value flags(Json::arrayValue);
-        int flagCount = 0;
-        for (int row = 0; row < lattice.fYCount+1; row++) {
-            Json::Value flagsRow(Json::arrayValue);
-            for (int column = 0; column < lattice.fXCount+1; column++) {
-                flagsRow.append(Json::Value(lattice.fFlags[flagCount++]));
-            }
-            flags.append(flagsRow);
-        }
-        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS] = flags;
-    }
-    return result;
-}
-
-static SkPoint get_json_point(Json::Value point) {
-    return SkPoint::Make(point[0].asFloat(), point[1].asFloat());
-}
-
-static SkColor get_json_color(Json::Value color) {
-    return SkColorSetARGB(color[0].asInt(), color[1].asInt(), color[2].asInt(), color[3].asInt());
-}
-
-static void extract_json_paint_color(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) {
-        target->setColor(get_json_color(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLOR]));
-    }
-}
-
-static void extract_json_paint_shader(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                      SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_SHADER)) {
-        Json::Value jsonShader = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_SHADER];
-        SkShader* shader = (SkShader*) load_flattenable(jsonShader, urlDataManager);
-        if (shader != nullptr) {
-            target->setShader(sk_ref_sp(shader));
-        }
-    }
-}
-
-static void extract_json_paint_patheffect(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                          SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT)) {
-        Json::Value jsonPathEffect = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT];
-        sk_sp<SkPathEffect> pathEffect((SkPathEffect*)load_flattenable(jsonPathEffect,
-                                                                       urlDataManager));
-        if (pathEffect != nullptr) {
-            target->setPathEffect(pathEffect);
-        }
-    }
-}
-
-static void extract_json_paint_maskfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                          SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER)) {
-        Json::Value jsonMaskFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER];
-        sk_sp<SkMaskFilter> maskFilter((SkMaskFilter*)load_flattenable(jsonMaskFilter,
-                                                                       urlDataManager));
-        if (maskFilter) {
-            target->setMaskFilter(std::move(maskFilter));
-        }
-    }
-}
-
-static void extract_json_paint_colorfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                           SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER)) {
-        Json::Value jsonColorFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER];
-        sk_sp<SkColorFilter> colorFilter((SkColorFilter*)load_flattenable(jsonColorFilter,
-                                                                          urlDataManager));
-        if (colorFilter != nullptr) {
-            target->setColorFilter(colorFilter);
-        }
-    }
-}
-
-static void extract_json_paint_looper(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                      SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LOOPER)) {
-        Json::Value jsonLooper = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LOOPER];
-        sk_sp<SkDrawLooper> looper((SkDrawLooper*) load_flattenable(jsonLooper, urlDataManager));
-        if (looper != nullptr) {
-            target->setLooper(std::move(looper));
-        }
-    }
-}
-
-static void extract_json_paint_imagefilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                           SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER)) {
-        Json::Value jsonImageFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER];
-        sk_sp<SkImageFilter> imageFilter((SkImageFilter*) load_flattenable(jsonImageFilter,
-                                                                           urlDataManager));
-        if (imageFilter != nullptr) {
-            target->setImageFilter(imageFilter);
-        }
-    }
-}
-
-static void extract_json_paint_typeface(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
-                                        SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE)) {
-        Json::Value jsonTypeface = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE];
-        Json::Value jsonData = jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA];
-        const void* data;
-        Json::ArrayIndex length = decode_data(jsonData, urlDataManager, &data);
-        SkMemoryStream buffer(data, length);
-        target->setTypeface(SkTypeface::MakeDeserialize(&buffer));
-    }
-}
-
-static void extract_json_paint_hinting(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_HINTING)) {
-        const char* hinting = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_HINTING].asCString();
-        if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_NONE)) {
-            target->setHinting(SkPaint::kNo_Hinting);
-        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_SLIGHT)) {
-            target->setHinting(SkPaint::kSlight_Hinting);
-        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_NORMAL)) {
-            target->setHinting(SkPaint::kNormal_Hinting);
-        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_FULL)) {
-            target->setHinting(SkPaint::kFull_Hinting);
-        }
-    }
-}
-
-static void extract_json_paint_style(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STYLE)) {
-        const char* style = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString();
-        if (!strcmp(style, SKDEBUGCANVAS_STYLE_FILL)) {
-            target->setStyle(SkPaint::kFill_Style);
-        }
-        else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKE)) {
-            target->setStyle(SkPaint::kStroke_Style);
-        }
-        else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKEANDFILL)) {
-            target->setStyle(SkPaint::kStrokeAndFill_Style);
-        }
-    }
-}
-
-static void extract_json_paint_strokewidth(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH)) {
-        float strokeWidth = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH].asFloat();
-        target->setStrokeWidth(strokeWidth);
-    }
-}
-
-static void extract_json_paint_strokemiter(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER)) {
-        float strokeMiter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER].asFloat();
-        target->setStrokeMiter(strokeMiter);
-    }
-}
-
-static void extract_json_paint_strokejoin(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN)) {
-        const char* join = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN].asCString();
-        if (!strcmp(join, SKDEBUGCANVAS_MITER_JOIN)) {
-            target->setStrokeJoin(SkPaint::kMiter_Join);
-        }
-        else if (!strcmp(join, SKDEBUGCANVAS_ROUND_JOIN)) {
-            target->setStrokeJoin(SkPaint::kRound_Join);
-        }
-        else if (!strcmp(join, SKDEBUGCANVAS_BEVEL_JOIN)) {
-            target->setStrokeJoin(SkPaint::kBevel_Join);
-        }
-        else {
-            SkASSERT(false);
-        }
-    }
-}
-
-static void extract_json_paint_cap(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_CAP)) {
-        const char* cap = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_CAP].asCString();
-        if (!strcmp(cap, SKDEBUGCANVAS_CAP_BUTT)) {
-            target->setStrokeCap(SkPaint::kButt_Cap);
-        }
-        else if (!strcmp(cap, SKDEBUGCANVAS_CAP_ROUND)) {
-            target->setStrokeCap(SkPaint::kRound_Cap);
-        }
-        else if (!strcmp(cap, SKDEBUGCANVAS_CAP_SQUARE)) {
-            target->setStrokeCap(SkPaint::kSquare_Cap);
-        }
-    }
-}
-
-static void extract_json_paint_filterquality(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY)) {
-        const char* quality = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY].asCString();
-        if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_NONE)) {
-            target->setFilterQuality(kNone_SkFilterQuality);
-        }
-        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_LOW)) {
-            target->setFilterQuality(kLow_SkFilterQuality);
-        }
-        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_MEDIUM)) {
-            target->setFilterQuality(kMedium_SkFilterQuality);
-        }
-        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_HIGH)) {
-            target->setFilterQuality(kHigh_SkFilterQuality);
-        }
-    }
-}
-
-static void extract_json_paint_antialias(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS)) {
-        target->setAntiAlias(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
-    }
-}
-
-static void extract_json_paint_dither(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DITHER)) {
-        target->setDither(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DITHER].asBool());
-    }
-}
-
-static void extract_json_paint_fakeboldtext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT)) {
-        target->setFakeBoldText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_lineartext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT)) {
-        target->setLinearText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_subpixeltext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT)) {
-        target->setSubpixelText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_devkerntext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT)) {
-        target->setDevKernText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_lcdrendertext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT)) {
-        target->setLCDRenderText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_embeddedbitmaptext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT)) {
-        target->setEmbeddedBitmapText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_autohinting(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING)) {
-        target->setAutohinted(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING].asBool());
-    }
-}
-
-static void extract_json_paint_verticaltext(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT)) {
-        target->setVerticalText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT].asBool());
-    }
-}
-
-static void extract_json_paint_blur(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_BLUR)) {
-        Json::Value blur = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_BLUR];
-        SkScalar sigma = blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA].asFloat();
-        SkBlurStyle style;
-        const char* jsonStyle = blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString();
-        if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_NORMAL)) {
-            style = SkBlurStyle::kNormal_SkBlurStyle;
-        }
-        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_SOLID)) {
-            style = SkBlurStyle::kSolid_SkBlurStyle;
-        }
-        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_OUTER)) {
-            style = SkBlurStyle::kOuter_SkBlurStyle;
-        }
-        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_INNER)) {
-            style = SkBlurStyle::kInner_SkBlurStyle;
-        }
-        else {
-            SkASSERT(false);
-            style = SkBlurStyle::kNormal_SkBlurStyle;
-        }
-        SkBlurMaskFilter::BlurFlags flags;
-        const char* jsonQuality = blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY].asCString();
-        if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_LOW)) {
-            flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag;
-        }
-        else if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_HIGH)) {
-            flags = SkBlurMaskFilter::BlurFlags::kHighQuality_BlurFlag;
-        }
-        else {
-            SkASSERT(false);
-            flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag;
-        }
-        target->setMaskFilter(SkBlurMaskFilter::Make(style, sigma, flags));
-    }
-}
-
-static void extract_json_paint_dashing(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DASHING)) {
-        Json::Value dash = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DASHING];
-        Json::Value jsonIntervals = dash[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS];
-        Json::ArrayIndex count = jsonIntervals.size();
-        SkScalar* intervals = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar));
-        for (Json::ArrayIndex i = 0; i < count; i++) {
-            intervals[i] = jsonIntervals[i].asFloat();
-        }
-        SkScalar phase = dash[SKDEBUGCANVAS_ATTRIBUTE_PHASE].asFloat();
-        target->setPathEffect(SkDashPathEffect::Make(intervals, count, phase));
-        sk_free(intervals);
-    }
-}
-
-static void extract_json_paint_textalign(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN)) {
-        SkPaint::Align textAlign;
-        const char* jsonAlign = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN].asCString();
-        if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_LEFT)) {
-            textAlign = SkPaint::kLeft_Align;
-        }
-        else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_CENTER)) {
-            textAlign = SkPaint::kCenter_Align;
-        }
-        else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_RIGHT)) {
-            textAlign = SkPaint::kRight_Align;
-        }
-        else {
-            SkASSERT(false);
-            textAlign = SkPaint::kLeft_Align;
-        }
-        target->setTextAlign(textAlign);
-    }
-}
-
-static void extract_json_paint_textsize(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE)) {
-        float textSize = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE].asFloat();
-        target->setTextSize(textSize);
-    }
-}
-
-static void extract_json_paint_textscalex(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX)) {
-        float textScaleX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX].asFloat();
-        target->setTextScaleX(textScaleX);
-    }
-}
-
-static void extract_json_paint_textskewx(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX)) {
-        float textSkewX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX].asFloat();
-        target->setTextSkewX(textSkewX);
-    }
-}
-
-static void extract_json_paint(Json::Value& paint, UrlDataManager& urlDataManager,
-                               SkPaint* result) {
-    extract_json_paint_hinting(paint, result);
-    extract_json_paint_color(paint, result);
-    extract_json_paint_shader(paint, urlDataManager, result);
-    extract_json_paint_patheffect(paint, urlDataManager, result);
-    extract_json_paint_maskfilter(paint, urlDataManager, result);
-    extract_json_paint_colorfilter(paint, urlDataManager, result);
-    extract_json_paint_looper(paint, urlDataManager, result);
-    extract_json_paint_imagefilter(paint, urlDataManager, result);
-    extract_json_paint_typeface(paint, urlDataManager, result);
-    extract_json_paint_style(paint, result);
-    extract_json_paint_blend_mode(paint, result);
-    extract_json_paint_strokewidth(paint, result);
-    extract_json_paint_strokemiter(paint, result);
-    extract_json_paint_strokejoin(paint, result);
-    extract_json_paint_cap(paint, result);
-    extract_json_paint_filterquality(paint, result);
-    extract_json_paint_antialias(paint, result);
-    extract_json_paint_dither(paint, result);
-    extract_json_paint_fakeboldtext(paint, result);
-    extract_json_paint_lineartext(paint, result);
-    extract_json_paint_subpixeltext(paint, result);
-    extract_json_paint_devkerntext(paint, result);
-    extract_json_paint_lcdrendertext(paint, result);
-    extract_json_paint_embeddedbitmaptext(paint, result);
-    extract_json_paint_autohinting(paint, result);
-    extract_json_paint_verticaltext(paint, result);
-    extract_json_paint_blur(paint, result);
-    extract_json_paint_dashing(paint, result);
-    extract_json_paint_textalign(paint, result);
-    extract_json_paint_textsize(paint, result);
-    extract_json_paint_textscalex(paint, result);
-    extract_json_paint_textskewx(paint, result);
-}
-
-static void extract_json_rect(Json::Value& rect, SkRect* result) {
-    result->set(rect[0].asFloat(), rect[1].asFloat(), rect[2].asFloat(), rect[3].asFloat());
-}
-
-static void extract_json_irect(Json::Value& rect, SkIRect* result) {
-    result->set(rect[0].asInt(), rect[1].asInt(), rect[2].asInt(), rect[3].asInt());
-}
-
-static void extract_json_rrect(Json::Value& rrect, SkRRect* result) {
-    SkVector radii[4] = {
-                            { rrect[1][0].asFloat(), rrect[1][1].asFloat() },
-                            { rrect[2][0].asFloat(), rrect[2][1].asFloat() },
-                            { rrect[3][0].asFloat(), rrect[3][1].asFloat() },
-                            { rrect[4][0].asFloat(), rrect[4][1].asFloat() }
-                        };
-    result->setRectRadii(SkRect::MakeLTRB(rrect[0][0].asFloat(), rrect[0][1].asFloat(),
-                                          rrect[0][2].asFloat(), rrect[0][3].asFloat()),
-                                          radii);
-}
-
-static void extract_json_matrix(Json::Value& matrix, SkMatrix* result) {
-    SkScalar values[] = {
-        matrix[0][0].asFloat(), matrix[0][1].asFloat(), matrix[0][2].asFloat(),
-        matrix[1][0].asFloat(), matrix[1][1].asFloat(), matrix[1][2].asFloat(),
-        matrix[2][0].asFloat(), matrix[2][1].asFloat(), matrix[2][2].asFloat()
-    };
-    result->set9(values);
-}
-
-static void extract_json_path(Json::Value& path, SkPath* result) {
-    const char* fillType = path[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE].asCString();
-    if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_WINDING)) {
-        result->setFillType(SkPath::kWinding_FillType);
-    }
-    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_EVENODD)) {
-        result->setFillType(SkPath::kEvenOdd_FillType);
-    }
-    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING)) {
-        result->setFillType(SkPath::kInverseWinding_FillType);
-    }
-    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD)) {
-        result->setFillType(SkPath::kInverseEvenOdd_FillType);
-    }
-    Json::Value verbs = path[SKDEBUGCANVAS_ATTRIBUTE_VERBS];
-    for (Json::ArrayIndex i = 0; i < verbs.size(); i++) {
-        Json::Value verb = verbs[i];
-        if (verb.isString()) {
-            SkASSERT(!strcmp(verb.asCString(), SKDEBUGCANVAS_VERB_CLOSE));
-            result->close();
-        }
-        else {
-            if (verb.isMember(SKDEBUGCANVAS_VERB_MOVE)) {
-                Json::Value move = verb[SKDEBUGCANVAS_VERB_MOVE];
-                result->moveTo(move[0].asFloat(), move[1].asFloat());
-            }
-            else if (verb.isMember(SKDEBUGCANVAS_VERB_LINE)) {
-                Json::Value line = verb[SKDEBUGCANVAS_VERB_LINE];
-                result->lineTo(line[0].asFloat(), line[1].asFloat());
-            }
-            else if (verb.isMember(SKDEBUGCANVAS_VERB_QUAD)) {
-                Json::Value quad = verb[SKDEBUGCANVAS_VERB_QUAD];
-                result->quadTo(quad[0][0].asFloat(), quad[0][1].asFloat(),
-                               quad[1][0].asFloat(), quad[1][1].asFloat());
-            }
-            else if (verb.isMember(SKDEBUGCANVAS_VERB_CUBIC)) {
-                Json::Value cubic = verb[SKDEBUGCANVAS_VERB_CUBIC];
-                result->cubicTo(cubic[0][0].asFloat(), cubic[0][1].asFloat(),
-                                cubic[1][0].asFloat(), cubic[1][1].asFloat(),
-                                cubic[2][0].asFloat(), cubic[2][1].asFloat());
-            }
-            else if (verb.isMember(SKDEBUGCANVAS_VERB_CONIC)) {
-                Json::Value conic = verb[SKDEBUGCANVAS_VERB_CONIC];
-                result->conicTo(conic[0][0].asFloat(), conic[0][1].asFloat(),
-                                conic[1][0].asFloat(), conic[1][1].asFloat(),
-                                conic[2].asFloat());
-            }
-            else {
-                SkASSERT(false);
-            }
-        }
-    }
-}
-
-SkClipOp get_json_clipop(Json::Value& jsonOp) {
-    const char* op = jsonOp.asCString();
-    if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_DIFFERENCE)) {
-        return kDifference_SkClipOp;
-    }
-    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_INTERSECT)) {
-        return kIntersect_SkClipOp;
-    }
-    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_UNION)) {
-        return kUnion_SkClipOp;
-    }
-    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_XOR)) {
-        return kXOR_SkClipOp;
-    }
-    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE)) {
-        return kReverseDifference_SkClipOp;
-    }
-    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REPLACE)) {
-        return kReplace_SkClipOp;
-    }
-    SkASSERT(false);
-    return kIntersect_SkClipOp;
-}
-
-SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kDrawClear_OpType) {
-    fColor = color;
-    fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
-}
-
-void SkClearCommand::execute(SkCanvas* canvas) const {
-    canvas->clear(fColor);
-}
-
-Json::Value SkClearCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = MakeJsonColor(fColor);
-    return result;
-}
-
- SkClearCommand* SkClearCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
-    Json::Value color = command[SKDEBUGCANVAS_ATTRIBUTE_COLOR];
-    return new SkClearCommand(get_json_color(color));
-}
-
-SkClipPathCommand::SkClipPathCommand(const SkPath& path, SkClipOp op, bool doAA)
-    : INHERITED(kClipPath_OpType) {
-    fPath = path;
-    fOp = op;
-    fDoAA = doAA;
-
-    fInfo.push(SkObjectParser::PathToString(path));
-    fInfo.push(SkObjectParser::ClipOpToString(op));
-    fInfo.push(SkObjectParser::BoolToString(doAA));
-}
-
-void SkClipPathCommand::execute(SkCanvas* canvas) const {
-    canvas->clipPath(fPath, fOp, fDoAA);
-}
-
-bool SkClipPathCommand::render(SkCanvas* canvas) const {
-    render_path(canvas, fPath);
-    return true;
-}
-
-Json::Value SkClipPathCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
-    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
-    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = fDoAA;
-    return result;
-}
-
-SkClipPathCommand* SkClipPathCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    SkPath path;
-    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
-    return new SkClipPathCommand(path, get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
-                                 command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
-}
-
-SkClipRegionCommand::SkClipRegionCommand(const SkRegion& region, SkClipOp op)
-    : INHERITED(kClipRegion_OpType) {
-    fRegion = region;
-    fOp = op;
-
-    fInfo.push(SkObjectParser::RegionToString(region));
-    fInfo.push(SkObjectParser::ClipOpToString(op));
-}
-
-void SkClipRegionCommand::execute(SkCanvas* canvas) const {
-    canvas->clipRegion(fRegion, fOp);
-}
-
-Json::Value SkClipRegionCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_REGION] = MakeJsonRegion(fRegion);
-    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
-    return result;
-}
-
-SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command,
-                                                   UrlDataManager& urlDataManager) {
-    SkASSERT(false);
-    return nullptr;
-}
-
-SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
-    : INHERITED(kClipRect_OpType) {
-    fRect = rect;
-    fOp = op;
-    fDoAA = doAA;
-
-    fInfo.push(SkObjectParser::RectToString(rect));
-    fInfo.push(SkObjectParser::ClipOpToString(op));
-    fInfo.push(SkObjectParser::BoolToString(doAA));
-}
-
-void SkClipRectCommand::execute(SkCanvas* canvas) const {
-    canvas->clipRect(fRect, fOp, fDoAA);
-}
-
-Json::Value SkClipRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
-    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
-    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA);
-
-    SkString desc;
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fRect)->c_str());
-
-    return result;
-}
-
-SkClipRectCommand* SkClipRectCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    SkRect rect;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect);
-    return new SkClipRectCommand(rect, get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
-                                 command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
-}
-
-SkClipRRectCommand::SkClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA)
-    : INHERITED(kClipRRect_OpType) {
-    fRRect = rrect;
-    fOp = op;
-    fDoAA = doAA;
-
-    fInfo.push(SkObjectParser::RRectToString(rrect));
-    fInfo.push(SkObjectParser::ClipOpToString(op));
-    fInfo.push(SkObjectParser::BoolToString(doAA));
-}
-
-void SkClipRRectCommand::execute(SkCanvas* canvas) const {
-    canvas->clipRRect(fRRect, fOp, fDoAA);
-}
-
-bool SkClipRRectCommand::render(SkCanvas* canvas) const {
-    render_rrect(canvas, fRRect);
-    return true;
-}
-
-Json::Value SkClipRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect);
-    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
-    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA);
-    return result;
-}
-
-SkClipRRectCommand* SkClipRRectCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    SkRRect rrect;
-    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rrect);
-    return new SkClipRRectCommand(rrect,
-                                  get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
-                                  command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
-}
-
-SkConcatCommand::SkConcatCommand(const SkMatrix& matrix)
-    : INHERITED(kConcat_OpType) {
-    fMatrix = matrix;
-
-    fInfo.push(SkObjectParser::MatrixToString(matrix));
-}
-
-void SkConcatCommand::execute(SkCanvas* canvas) const {
-    canvas->concat(fMatrix);
-}
-
-Json::Value SkConcatCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
-    return result;
-}
-
-SkConcatCommand* SkConcatCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
-    SkMatrix matrix;
-    extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
-    return new SkConcatCommand(matrix);
-}
-
-////
-
-SkDrawAnnotationCommand::SkDrawAnnotationCommand(const SkRect& rect, const char key[],
-                                                 sk_sp<SkData> value)
-    : INHERITED(kDrawAnnotation_OpType)
-    , fRect(rect)
-    , fKey(key)
-    , fValue(std::move(value))
-{
-    SkString str;
-    str.appendf("Key: %s Value: ", key);
-    if (fValue && fValue->size()) {
-        str.append((const char*) fValue->bytes(), fValue->size());
-    } else {
-        str.appendf("no value");
-    }
-    str.appendf("\n");
-    fInfo.push(new SkString(str));
-}
-
-void SkDrawAnnotationCommand::execute(SkCanvas* canvas) const {
-    canvas->drawAnnotation(fRect, fKey.c_str(), fValue);
-}
-
-Json::Value SkDrawAnnotationCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
-    result["key"] = Json::Value(fKey.c_str());
-    if (fValue.get()) {
-        // TODO: dump out the "value"
-    }
-
-    SkString desc;
-    str_append(&desc, fRect)->appendf(" %s", fKey.c_str());
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(desc.c_str());
-
-    return result;
-}
-
-SkDrawAnnotationCommand* SkDrawAnnotationCommand::fromJSON(Json::Value& command,
-                                                           UrlDataManager& urlDataManager) {
-    SkRect rect;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect);
-    sk_sp<SkData> data(nullptr); // TODO: extract "value" from the Json
-    return new SkDrawAnnotationCommand(rect, command["key"].asCString(), data);
-}
-
-////
-
-SkDrawBitmapCommand::SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top,
-                                         const SkPaint* paint)
-    : INHERITED(kDrawBitmap_OpType) {
-    fBitmap = bitmap;
-    fLeft = left;
-    fTop = top;
-    if (paint) {
-        fPaint = *paint;
-        fPaintPtr = &fPaint;
-    } else {
-        fPaintPtr = nullptr;
-    }
-
-    fInfo.push(SkObjectParser::BitmapToString(bitmap));
-    fInfo.push(SkObjectParser::ScalarToString(left, "SkScalar left: "));
-    fInfo.push(SkObjectParser::ScalarToString(top, "SkScalar top: "));
-    if (paint) {
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-}
-
-void SkDrawBitmapCommand::execute(SkCanvas* canvas) const {
-    canvas->drawBitmap(fBitmap, fLeft, fTop, fPaintPtr);
-}
-
-bool SkDrawBitmapCommand::render(SkCanvas* canvas) const {
-    render_bitmap(canvas, fBitmap);
-    return true;
-}
-
-Json::Value SkDrawBitmapCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(fBitmap, &encoded, urlDataManager)) {
-        Json::Value command(Json::objectValue);
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
-        result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fLeft, fTop);
-        if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
-        }
-    }
-    return result;
-}
-
-SkDrawBitmapCommand* SkDrawBitmapCommand::fromJSON(Json::Value& command,
-                                                   UrlDataManager& urlDataManager) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
-    if (bitmap == nullptr) {
-        return nullptr;
-    }
-    Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
-    SkPaint* paintPtr;
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        paintPtr = &paint;
-    }
-    else {
-        paintPtr = nullptr;
-    }
-    SkDrawBitmapCommand* result = new SkDrawBitmapCommand(*bitmap, point[0].asFloat(),
-                                                          point[1].asFloat(), paintPtr);
-    delete bitmap;
-    return result;
-}
-
-SkDrawBitmapNineCommand::SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center,
-                                                 const SkRect& dst, const SkPaint* paint)
-    : INHERITED(kDrawBitmapNine_OpType) {
-    fBitmap = bitmap;
-    fCenter = center;
-    fDst = dst;
-    if (paint) {
-        fPaint = *paint;
-        fPaintPtr = &fPaint;
-    } else {
-        fPaintPtr = nullptr;
-    }
-
-    fInfo.push(SkObjectParser::BitmapToString(bitmap));
-    fInfo.push(SkObjectParser::IRectToString(center));
-    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
-    if (paint) {
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-}
-
-void SkDrawBitmapNineCommand::execute(SkCanvas* canvas) const {
-    canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaintPtr);
-}
-
-bool SkDrawBitmapNineCommand::render(SkCanvas* canvas) const {
-    SkRect tmp = SkRect::Make(fCenter);
-    render_bitmap(canvas, fBitmap, &tmp);
-    return true;
-}
-
-Json::Value SkDrawBitmapNineCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(fBitmap, &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
-        result[SKDEBUGCANVAS_ATTRIBUTE_CENTER] = MakeJsonIRect(fCenter);
-        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
-        if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
-        }
-    }
-    return result;
-}
-
-SkDrawBitmapNineCommand* SkDrawBitmapNineCommand::fromJSON(Json::Value& command,
-                                                           UrlDataManager& urlDataManager) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
-    if (bitmap == nullptr) {
-        return nullptr;
-    }
-    SkIRect center;
-    extract_json_irect(command[SKDEBUGCANVAS_ATTRIBUTE_CENTER], &center);
-    SkRect dst;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
-    SkPaint* paintPtr;
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        paintPtr = &paint;
-    }
-    else {
-        paintPtr = nullptr;
-    }
-    SkDrawBitmapNineCommand* result = new SkDrawBitmapNineCommand(*bitmap, center, dst, paintPtr);
-    delete bitmap;
-    return result;
-}
-
-SkDrawBitmapRectCommand::SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src,
-                                                 const SkRect& dst, const SkPaint* paint,
-                                                 SkCanvas::SrcRectConstraint constraint)
-    : INHERITED(kDrawBitmapRect_OpType) {
-    fBitmap = bitmap;
-    if (src) {
-        fSrc = *src;
-    } else {
-        fSrc.setEmpty();
-    }
-    fDst = dst;
-
-    if (paint) {
-        fPaint = *paint;
-        fPaintPtr = &fPaint;
-    } else {
-        fPaintPtr = nullptr;
-    }
-    fConstraint = constraint;
-
-    fInfo.push(SkObjectParser::BitmapToString(bitmap));
-    if (src) {
-        fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
-    }
-    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
-    if (paint) {
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-    fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
-}
-
-void SkDrawBitmapRectCommand::execute(SkCanvas* canvas) const {
-    canvas->legacy_drawBitmapRect(fBitmap, this->srcRect(), fDst, fPaintPtr, fConstraint);
-}
-
-bool SkDrawBitmapRectCommand::render(SkCanvas* canvas) const {
-    render_bitmap(canvas, fBitmap, this->srcRect());
-    return true;
-}
-
-Json::Value SkDrawBitmapRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(fBitmap, &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
-        if (!fSrc.isEmpty()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = MakeJsonRect(fSrc);
-        }
-        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
-        if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
-        }
-        if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
-        }
-    }
-
-    SkString desc;
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
-
-    return result;
-}
-
-SkDrawBitmapRectCommand* SkDrawBitmapRectCommand::fromJSON(Json::Value& command,
-                                                           UrlDataManager& urlDataManager) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
-    if (bitmap == nullptr) {
-        return nullptr;
-    }
-    SkRect dst;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
-    SkPaint* paintPtr;
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        paintPtr = &paint;
-    }
-    else {
-        paintPtr = nullptr;
-    }
-    SkCanvas::SrcRectConstraint constraint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) &&
-        command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) {
-        constraint = SkCanvas::kStrict_SrcRectConstraint;
-    }
-    else {
-        constraint = SkCanvas::kFast_SrcRectConstraint;
-    }
-    SkRect* srcPtr;
-    SkRect src;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) {
-        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src);
-        srcPtr = &src;
-    }
-    else {
-        srcPtr = nullptr;
-    }
-    SkDrawBitmapRectCommand* result = new SkDrawBitmapRectCommand(*bitmap, srcPtr, dst, paintPtr,
-                                                                  constraint);
-    delete bitmap;
-    return result;
-}
-
-SkDrawImageCommand::SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top,
-                                       const SkPaint* paint)
-    : INHERITED(kDrawImage_OpType)
-    , fImage(SkRef(image))
-    , fLeft(left)
-    , fTop(top) {
-
-    fInfo.push(SkObjectParser::ImageToString(image));
-    fInfo.push(SkObjectParser::ScalarToString(left, "Left: "));
-    fInfo.push(SkObjectParser::ScalarToString(top, "Top: "));
-
-    if (paint) {
-        fPaint.set(*paint);
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-}
-
-void SkDrawImageCommand::execute(SkCanvas* canvas) const {
-    canvas->drawImage(fImage.get(), fLeft, fTop, fPaint.getMaybeNull());
-}
-
-bool SkDrawImageCommand::render(SkCanvas* canvas) const {
-    SkAutoCanvasRestore acr(canvas, true);
-    canvas->clear(0xFFFFFFFF);
-
-    xlate_and_scale_to_bounds(canvas, SkRect::MakeXYWH(fLeft, fTop,
-                                                       SkIntToScalar(fImage->width()),
-                                                       SkIntToScalar(fImage->height())));
-    this->execute(canvas);
-    return true;
-}
-
-Json::Value SkDrawImageCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(*fImage, &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
-        result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fLeft, fTop);
-        if (fPaint.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
-        }
-
-        result[SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID] = fImage->uniqueID();
-        result[SKDEBUGCANVAS_ATTRIBUTE_WIDTH] = fImage->width();
-        result[SKDEBUGCANVAS_ATTRIBUTE_HEIGHT] = fImage->height();
-        switch (fImage->alphaType()) {
-            case kOpaque_SkAlphaType:
-                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
-                break;
-            case kPremul_SkAlphaType:
-                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_PREMUL;
-                break;
-            case kUnpremul_SkAlphaType:
-                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_UNPREMUL;
-                break;
-            default:
-                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_UNKNOWN;
-                break;
-        }
-    }
-    return result;
-}
-
-SkDrawImageCommand* SkDrawImageCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
-    if (image == nullptr) {
-        return nullptr;
-    }
-    Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
-    SkPaint* paintPtr;
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        paintPtr = &paint;
-    }
-    else {
-        paintPtr = nullptr;
-    }
-    SkDrawImageCommand* result = new SkDrawImageCommand(image.get(), point[0].asFloat(),
-                                                        point[1].asFloat(), paintPtr);
-    return result;
-}
-
-SkDrawImageLatticeCommand::SkDrawImageLatticeCommand(const SkImage* image,
-                                                     const SkCanvas::Lattice& lattice,
-                                                     const SkRect& dst, const SkPaint* paint)
-    : INHERITED(kDrawImageLattice_OpType)
-    , fImage(SkRef(image))
-    , fLattice(lattice)
-    , fDst(dst) {
-
-      fInfo.push(SkObjectParser::ImageToString(image));
-      fInfo.push(SkObjectParser::LatticeToString(lattice));
-      fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
-      if (paint) {
-          fPaint.set(*paint);
-          fInfo.push(SkObjectParser::PaintToString(*paint));
-      }
-}
-
-void SkDrawImageLatticeCommand::execute(SkCanvas* canvas) const {
-    SkLatticeIter iter(fLattice, fDst);
-    SkRect srcR, dstR;
-    while (iter.next(&srcR, &dstR)) {
-        canvas->legacy_drawImageRect(fImage.get(), &srcR, dstR,
-                                     fPaint.getMaybeNull(), SkCanvas::kStrict_SrcRectConstraint);
-    }
-}
-
-bool SkDrawImageLatticeCommand::render(SkCanvas* canvas) const {
-    SkAutoCanvasRestore acr(canvas, true);
-    canvas->clear(0xFFFFFFFF);
-
-    xlate_and_scale_to_bounds(canvas, fDst);
-
-    this->execute(canvas);
-    return true;
-}
-
-Json::Value SkDrawImageLatticeCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
-        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICE] = MakeJsonLattice(fLattice);
-        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
-        if (fPaint.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
-        }
-    }
-
-    SkString desc;
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
-
-    return result;
-}
-
-SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src,
-                                               const SkRect& dst, const SkPaint* paint,
-                                               SkCanvas::SrcRectConstraint constraint)
-    : INHERITED(kDrawImageRect_OpType)
-    , fImage(SkRef(image))
-    , fDst(dst)
-    , fConstraint(constraint) {
-
-    if (src) {
-        fSrc.set(*src);
-    }
-
-    if (paint) {
-        fPaint.set(*paint);
-    }
-
-    fInfo.push(SkObjectParser::ImageToString(image));
-    if (src) {
-        fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
-    }
-    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
-    if (paint) {
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-    fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
-}
-
-void SkDrawImageRectCommand::execute(SkCanvas* canvas) const {
-    canvas->legacy_drawImageRect(fImage.get(), fSrc.getMaybeNull(), fDst,
-                                 fPaint.getMaybeNull(), fConstraint);
-}
-
-bool SkDrawImageRectCommand::render(SkCanvas* canvas) const {
-    SkAutoCanvasRestore acr(canvas, true);
-    canvas->clear(0xFFFFFFFF);
-
-    xlate_and_scale_to_bounds(canvas, fDst);
-
-    this->execute(canvas);
-    return true;
-}
-
-Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value encoded;
-    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
-        if (fSrc.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = MakeJsonRect(*fSrc.get());
-        }
-        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
-        if (fPaint.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
-        }
-        if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
-        }
-    }
-
-    SkString desc;
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
-
-    return result;
-}
-
-SkDrawImageRectCommand* SkDrawImageRectCommand::fromJSON(Json::Value& command,
-                                                         UrlDataManager& urlDataManager) {
-    sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
-    if (image == nullptr) {
-        return nullptr;
-    }
-    SkRect dst;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
-    SkPaint* paintPtr;
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        paintPtr = &paint;
-    }
-    else {
-        paintPtr = nullptr;
-    }
-    SkCanvas::SrcRectConstraint constraint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) &&
-        command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) {
-        constraint = SkCanvas::kStrict_SrcRectConstraint;
-    }
-    else {
-        constraint = SkCanvas::kFast_SrcRectConstraint;
-    }
-    SkRect* srcPtr;
-    SkRect src;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) {
-        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src);
-        srcPtr = &src;
-    }
-    else {
-        srcPtr = nullptr;
-    }
-    SkDrawImageRectCommand* result = new SkDrawImageRectCommand(image.get(), srcPtr, dst, paintPtr,
-                                                                constraint);
-    return result;
-}
-
-SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint)
-    : INHERITED(kDrawOval_OpType) {
-    fOval = oval;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::RectToString(oval));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawOvalCommand::execute(SkCanvas* canvas) const {
-    canvas->drawOval(fOval, fPaint);
-}
-
-bool SkDrawOvalCommand::render(SkCanvas* canvas) const {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    xlate_and_scale_to_bounds(canvas, fOval);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawOval(fOval, p);
-    canvas->restore();
-
-    return true;
-}
-
-Json::Value SkDrawOvalCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fOval);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawOvalCommand* SkDrawOvalCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    SkRect coords;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawOvalCommand(coords, paint);
-}
-
-SkDrawArcCommand::SkDrawArcCommand(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
-                                   bool useCenter, const SkPaint& paint)
-        : INHERITED(kDrawOval_OpType) {
-    fOval = oval;
-    fStartAngle = startAngle;
-    fSweepAngle = sweepAngle;
-    fUseCenter = useCenter;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::RectToString(oval));
-    fInfo.push(SkObjectParser::ScalarToString(startAngle, "StartAngle: "));
-    fInfo.push(SkObjectParser::ScalarToString(sweepAngle, "SweepAngle: "));
-    fInfo.push(SkObjectParser::BoolToString(useCenter));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawArcCommand::execute(SkCanvas* canvas) const {
-    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint);
-}
-
-bool SkDrawArcCommand::render(SkCanvas* canvas) const {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    xlate_and_scale_to_bounds(canvas, fOval);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p);
-    canvas->restore();
-
-    return true;
-}
-
-Json::Value SkDrawArcCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fOval);
-    result[SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE] = MakeJsonScalar(fStartAngle);
-    result[SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE] = MakeJsonScalar(fSweepAngle);
-    result[SKDEBUGCANVAS_ATTRIBUTE_USECENTER] = fUseCenter;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawArcCommand* SkDrawArcCommand::fromJSON(Json::Value& command,
-                                             UrlDataManager& urlDataManager) {
-    SkRect coords;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
-    SkScalar startAngle = command[SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE].asFloat();
-    SkScalar sweepAngle = command[SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE].asFloat();
-    bool useCenter = command[SKDEBUGCANVAS_ATTRIBUTE_USECENTER].asBool();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawArcCommand(coords, startAngle, sweepAngle, useCenter, paint);
-}
-
-SkDrawPaintCommand::SkDrawPaintCommand(const SkPaint& paint)
-    : INHERITED(kDrawPaint_OpType) {
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPaintCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPaint(fPaint);
-}
-
-bool SkDrawPaintCommand::render(SkCanvas* canvas) const {
-    canvas->clear(0xFFFFFFFF);
-    canvas->drawPaint(fPaint);
-    return true;
-}
-
-Json::Value SkDrawPaintCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawPaintCommand* SkDrawPaintCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawPaintCommand(paint);
-}
-
-SkDrawPathCommand::SkDrawPathCommand(const SkPath& path, const SkPaint& paint)
-    : INHERITED(kDrawPath_OpType) {
-    fPath = path;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::PathToString(path));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPathCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPath(fPath, fPaint);
-}
-
-bool SkDrawPathCommand::render(SkCanvas* canvas) const {
-    render_path(canvas, fPath);
-    return true;
-}
-
-Json::Value SkDrawPathCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawPathCommand* SkDrawPathCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    SkPath path;
-    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawPathCommand(path, paint);
-}
-
-SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture,
-                                                     const SkMatrix* matrix,
-                                                     const SkPaint* paint)
-    : INHERITED(kBeginDrawPicture_OpType)
-    , fPicture(SkRef(picture)) {
-
-    SkString* str = new SkString;
-    str->appendf("SkPicture: L: %f T: %f R: %f B: %f",
-                 picture->cullRect().fLeft, picture->cullRect().fTop,
-                 picture->cullRect().fRight, picture->cullRect().fBottom);
-    fInfo.push(str);
-
-    if (matrix) {
-        fMatrix.set(*matrix);
-        fInfo.push(SkObjectParser::MatrixToString(*matrix));
-    }
-
-    if (paint) {
-        fPaint.set(*paint);
-        fInfo.push(SkObjectParser::PaintToString(*paint));
-    }
-
-}
-
-void SkBeginDrawPictureCommand::execute(SkCanvas* canvas) const {
-    if (fPaint.isValid()) {
-        SkRect bounds = fPicture->cullRect();
-        if (fMatrix.isValid()) {
-            fMatrix.get()->mapRect(&bounds);
-        }
-        canvas->saveLayer(&bounds, fPaint.get());
-    }
-
-    if (fMatrix.isValid()) {
-        if (!fPaint.isValid()) {
-            canvas->save();
-        }
-        canvas->concat(*fMatrix.get());
-    }
-}
-
-bool SkBeginDrawPictureCommand::render(SkCanvas* canvas) const {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
-
-    canvas->drawPicture(fPicture.get());
-
-    canvas->restore();
-
-    return true;
-}
-
-SkEndDrawPictureCommand::SkEndDrawPictureCommand(bool restore)
-    : INHERITED(kEndDrawPicture_OpType) , fRestore(restore) { }
-
-void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const {
-    if (fRestore) {
-        canvas->restore();
-    }
-}
-
-SkDrawPointsCommand::SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count,
-                                         const SkPoint pts[], const SkPaint& paint)
-    : INHERITED(kDrawPoints_OpType) {
-    fMode = mode;
-    fCount = count;
-    fPts = new SkPoint[count];
-    memcpy(fPts, pts, count * sizeof(SkPoint));
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::PointsToString(pts, count));
-    fInfo.push(SkObjectParser::ScalarToString(SkIntToScalar((unsigned int)count),
-                                              "Points: "));
-    fInfo.push(SkObjectParser::PointModeToString(mode));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPointsCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPoints(fMode, fCount, fPts, fPaint);
-}
-
-bool SkDrawPointsCommand::render(SkCanvas* canvas) const {
-    canvas->clear(0xFFFFFFFF);
-    canvas->save();
-
-    SkRect bounds;
-
-    bounds.setEmpty();
-    for (unsigned int i = 0; i < fCount; ++i) {
-        bounds.growToInclude(fPts[i].fX, fPts[i].fY);
-    }
-
-    xlate_and_scale_to_bounds(canvas, bounds);
-
-    SkPaint p;
-    p.setColor(SK_ColorBLACK);
-    p.setStyle(SkPaint::kStroke_Style);
-
-    canvas->drawPoints(fMode, fCount, fPts, p);
-    canvas->restore();
-
-    return true;
-}
-
-Json::Value SkDrawPointsCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_MODE] = make_json_pointmode(fMode);
-    Json::Value points(Json::arrayValue);
-    for (size_t i = 0; i < fCount; i++) {
-        points.append(MakeJsonPoint(fPts[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_POINTS] = points;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawPointsCommand* SkDrawPointsCommand::fromJSON(Json::Value& command,
-                                                   UrlDataManager& urlDataManager) {
-    SkCanvas::PointMode mode;
-    const char* jsonMode = command[SKDEBUGCANVAS_ATTRIBUTE_MODE].asCString();
-    if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POINTS)) {
-        mode = SkCanvas::kPoints_PointMode;
-    }
-    else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_LINES)) {
-        mode = SkCanvas::kLines_PointMode;
-    }
-    else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POLYGON)) {
-        mode = SkCanvas::kPolygon_PointMode;
-    }
-    else {
-        SkASSERT(false);
-        return nullptr;
-    }
-    Json::Value jsonPoints = command[SKDEBUGCANVAS_ATTRIBUTE_POINTS];
-    int count = (int) jsonPoints.size();
-    SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint));
-    for (int i = 0; i < count; i++) {
-        points[i] = SkPoint::Make(jsonPoints[i][0].asFloat(), jsonPoints[i][1].asFloat());
-    }
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    SkDrawPointsCommand* result = new SkDrawPointsCommand(mode, count, points, paint);
-    sk_free(points);
-    return result;
-}
-
-SkDrawPosTextCommand::SkDrawPosTextCommand(const void* text, size_t byteLength,
-                                           const SkPoint pos[], const SkPaint& paint)
-    : INHERITED(kDrawPosText_OpType) {
-    size_t numPts = paint.countText(text, byteLength);
-
-    fText = new char[byteLength];
-    memcpy(fText, text, byteLength);
-    fByteLength = byteLength;
-
-    fPos = new SkPoint[numPts];
-    memcpy(fPos, pos, numPts * sizeof(SkPoint));
-
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
-    // TODO(chudy): Test that this works.
-    fInfo.push(SkObjectParser::PointsToString(pos, 1));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPosTextCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPosText(fText, fByteLength, fPos, fPaint);
-}
-
-Json::Value SkDrawPosTextCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
-                                                       ((const char*) fText) + fByteLength);
-    Json::Value coords(Json::arrayValue);
-    size_t numCoords = fPaint.textToGlyphs(fText, fByteLength, nullptr);
-    for (size_t i = 0; i < numCoords; i++) {
-        coords.append(MakeJsonPoint(fPos[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = coords;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawPosTextCommand* SkDrawPosTextCommand::fromJSON(Json::Value& command,
-                                                     UrlDataManager& urlDataManager) {
-    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
-    int count = (int) coords.size();
-    SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint));
-    for (int i = 0; i < count; i++) {
-        points[i] = SkPoint::Make(coords[i][0].asFloat(), coords[i][1].asFloat());
-    }
-    return new SkDrawPosTextCommand(text, strlen(text), points, paint);
-}
-
-SkDrawPosTextHCommand::SkDrawPosTextHCommand(const void* text, size_t byteLength,
-                                             const SkScalar xpos[], SkScalar constY,
-                                             const SkPaint& paint)
-    : INHERITED(kDrawPosTextH_OpType) {
-    size_t numPts = paint.countText(text, byteLength);
-
-    fText = new char[byteLength];
-    memcpy(fText, text, byteLength);
-    fByteLength = byteLength;
-
-    fXpos = new SkScalar[numPts];
-    memcpy(fXpos, xpos, numPts * sizeof(SkScalar));
-
-    fConstY = constY;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
-    fInfo.push(SkObjectParser::ScalarToString(xpos[0], "XPOS: "));
-    fInfo.push(SkObjectParser::ScalarToString(constY, "SkScalar constY: "));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPosTextHCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPosTextH(fText, fByteLength, fXpos, fConstY, fPaint);
-}
-
-Json::Value SkDrawPosTextHCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
-                                                       ((const char*) fText) + fByteLength);
-    result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fConstY);
-    Json::Value xpos(Json::arrayValue);
-    size_t numXpos = fPaint.textToGlyphs(fText, fByteLength, nullptr);
-    for (size_t i = 0; i < numXpos; i++) {
-        xpos.append(Json::Value(fXpos[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = xpos;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawPosTextHCommand* SkDrawPosTextHCommand::fromJSON(Json::Value& command,
-                                                       UrlDataManager& urlDataManager) {
-    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    Json::Value jsonXpos = command[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS];
-    int count = (int) jsonXpos.size();
-    SkScalar* xpos = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar));
-    for (int i = 0; i < count; i++) {
-        xpos[i] = jsonXpos[i].asFloat();
-    }
-    SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat();
-    return new SkDrawPosTextHCommand(text, strlen(text), xpos, y, paint);
-}
-
-static const char* gPositioningLabels[] = {
-    "kDefault_Positioning",
-    "kHorizontal_Positioning",
-    "kFull_Positioning",
-};
-
-SkDrawTextBlobCommand::SkDrawTextBlobCommand(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y,
-                                             const SkPaint& paint)
-    : INHERITED(kDrawTextBlob_OpType)
-    , fBlob(std::move(blob))
-    , fXPos(x)
-    , fYPos(y)
-    , fPaint(paint) {
-
-    std::unique_ptr<SkString> runsStr(new SkString);
-    fInfo.push(SkObjectParser::ScalarToString(x, "XPOS: "));
-    fInfo.push(SkObjectParser::ScalarToString(y, "YPOS: "));
-    fInfo.push(SkObjectParser::RectToString(fBlob->bounds(), "Bounds: "));
-    fInfo.push(runsStr.get());
-    fInfo.push(SkObjectParser::PaintToString(paint));
-
-    unsigned runs = 0;
-    SkPaint runPaint(paint);
-    SkTextBlobRunIterator iter(fBlob.get());
-    while (!iter.done()) {
-        std::unique_ptr<SkString> tmpStr(new SkString);
-        tmpStr->printf("==== Run [%d] ====", runs++);
-        fInfo.push(tmpStr.release());
-
-        fInfo.push(SkObjectParser::IntToString(iter.glyphCount(), "GlyphCount: "));
-        tmpStr.reset(new SkString("GlyphPositioning: "));
-        tmpStr->append(gPositioningLabels[iter.positioning()]);
-        fInfo.push(tmpStr.release());
-
-        iter.applyFontToPaint(&runPaint);
-        fInfo.push(SkObjectParser::PaintToString(runPaint));
-
-        iter.next();
-    }
-
-    runsStr->printf("Runs: %d", runs);
-    // runStr is owned by fInfo at this point.
-    runsStr.release();
-}
-
-void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const {
-    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
-}
-
-bool SkDrawTextBlobCommand::render(SkCanvas* canvas) const {
-    canvas->clear(SK_ColorWHITE);
-    canvas->save();
-
-    SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
-    xlate_and_scale_to_bounds(canvas, bounds);
-
-    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
-
-    canvas->restore();
-
-    return true;
-}
-
-Json::Value SkDrawTextBlobCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value runs(Json::arrayValue);
-    SkTextBlobRunIterator iter(fBlob.get());
-    while (!iter.done()) {
-        Json::Value run(Json::objectValue);
-        Json::Value jsonPositions(Json::arrayValue);
-        Json::Value jsonGlyphs(Json::arrayValue);
-        const SkScalar* iterPositions = iter.pos();
-        const uint16_t* iterGlyphs = iter.glyphs();
-        for (uint32_t i = 0; i < iter.glyphCount(); i++) {
-            switch (iter.positioning()) {
-                case SkTextBlob::kFull_Positioning:
-                    jsonPositions.append(MakeJsonPoint(iterPositions[i * 2],
-                                                       iterPositions[i * 2 + 1]));
-                    break;
-                case SkTextBlob::kHorizontal_Positioning:
-                    jsonPositions.append(Json::Value(iterPositions[i]));
-                    break;
-                case SkTextBlob::kDefault_Positioning:
-                    break;
-            }
-            jsonGlyphs.append(Json::Value(iterGlyphs[i]));
-        }
-        if (iter.positioning() != SkTextBlob::kDefault_Positioning) {
-            run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = jsonPositions;
-        }
-        run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS] = jsonGlyphs;
-        SkPaint fontPaint;
-        iter.applyFontToPaint(&fontPaint);
-        run[SKDEBUGCANVAS_ATTRIBUTE_FONT] = MakeJsonPaint(fontPaint, urlDataManager);
-        run[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(iter.offset());
-        runs.append(run);
-        iter.next();
-    }
-    SkRect bounds = fBlob->bounds();
-    result[SKDEBUGCANVAS_ATTRIBUTE_RUNS] = runs;
-    result[SKDEBUGCANVAS_ATTRIBUTE_X] = Json::Value(fXPos);
-    result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fYPos);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(bounds);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-
-    SkString desc;
-    // make the bounds local by applying the x,y
-    bounds.offset(fXPos, fYPos);
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, bounds)->c_str());
-
-    return result;
-}
-
-SkDrawTextBlobCommand* SkDrawTextBlobCommand::fromJSON(Json::Value& command,
-                                                       UrlDataManager& urlDataManager) {
-    SkTextBlobBuilder builder;
-    Json::Value runs = command[SKDEBUGCANVAS_ATTRIBUTE_RUNS];
-    for (Json::ArrayIndex i = 0 ; i < runs.size(); i++) {
-        Json::Value run = runs[i];
-        SkPaint font;
-        font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-        extract_json_paint(run[SKDEBUGCANVAS_ATTRIBUTE_FONT], urlDataManager, &font);
-        Json::Value glyphs = run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS];
-        int count = glyphs.size();
-        Json::Value coords = run[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
-        SkScalar x = coords[0].asFloat();
-        SkScalar y = coords[1].asFloat();
-        SkRect bounds;
-        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &bounds);
-
-        if (run.isMember(SKDEBUGCANVAS_ATTRIBUTE_POSITIONS)) {
-            Json::Value positions = run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS];
-            if (positions.size() > 0 && positions[0].isNumeric()) {
-                SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPosH(font, count, y, &bounds);
-                for (int j = 0; j < count; j++) {
-                    buffer.glyphs[j] = glyphs[j].asUInt();
-                    buffer.pos[j] = positions[j].asFloat();
-                }
-            }
-            else {
-                SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPos(font, count, &bounds);
-                for (int j = 0; j < count; j++) {
-                    buffer.glyphs[j] = glyphs[j].asUInt();
-                    buffer.pos[j * 2] = positions[j][0].asFloat();
-                    buffer.pos[j * 2 + 1] = positions[j][1].asFloat();
-                }
-            }
-        }
-        else {
-            SkTextBlobBuilder::RunBuffer buffer = builder.allocRun(font, count, x, y, &bounds);
-            for (int j = 0; j < count; j++) {
-                buffer.glyphs[j] = glyphs[j].asUInt();
-            }
-        }
-    }
-    SkScalar x = command[SKDEBUGCANVAS_ATTRIBUTE_X].asFloat();
-    SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawTextBlobCommand(builder.make(), x, y, paint);
-}
-
-SkDrawPatchCommand::SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4],
-                                       const SkPoint texCoords[4], SkBlendMode bmode,
-                                       const SkPaint& paint)
-    : INHERITED(kDrawPatch_OpType)
-    , fBlendMode(bmode)
-{
-    memcpy(fCubics, cubics, sizeof(fCubics));
-    if (colors != nullptr) {
-        memcpy(fColors, colors, sizeof(fColors));
-        fColorsPtr = fColors;
-    } else {
-        fColorsPtr = nullptr;
-    }
-    if (texCoords != nullptr) {
-        memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
-        fTexCoordsPtr = fTexCoords;
-    } else {
-        fTexCoordsPtr = nullptr;
-    }
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawPatchCommand::execute(SkCanvas* canvas) const {
-    canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint);
-}
-
-Json::Value SkDrawPatchCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    Json::Value cubics = Json::Value(Json::arrayValue);
-    for (int i = 0; i < 12; i++) {
-        cubics.append(MakeJsonPoint(fCubics[i]));
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_CUBICS] = cubics;
-    if (fColorsPtr != nullptr) {
-        Json::Value colors = Json::Value(Json::arrayValue);
-        for (int i = 0; i < 4; i++) {
-            colors.append(MakeJsonColor(fColorsPtr[i]));
-        }
-        result[SKDEBUGCANVAS_ATTRIBUTE_COLORS] = colors;
-    }
-    if (fTexCoordsPtr != nullptr) {
-        Json::Value texCoords = Json::Value(Json::arrayValue);
-        for (int i = 0; i < 4; i++) {
-            texCoords.append(MakeJsonPoint(fTexCoords[i]));
-        }
-        result[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS] = texCoords;
-    }
-    // fBlendMode
-    return result;
-}
-
-SkDrawPatchCommand* SkDrawPatchCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    Json::Value jsonCubics = command[SKDEBUGCANVAS_ATTRIBUTE_CUBICS];
-    SkPoint cubics[12];
-    for (int i = 0; i < 12; i++) {
-        cubics[i] = get_json_point(jsonCubics[i]);
-    }
-    SkColor* colorsPtr;
-    SkColor colors[4];
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORS)) {
-        Json::Value jsonColors = command[SKDEBUGCANVAS_ATTRIBUTE_COLORS];
-        for (int i = 0; i < 4; i++) {
-            colors[i] = get_json_color(jsonColors[i]);
-        }
-        colorsPtr = colors;
-    }
-    else {
-        colorsPtr = nullptr;
-    }
-    SkPoint* texCoordsPtr;
-    SkPoint texCoords[4];
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS)) {
-        Json::Value jsonTexCoords = command[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS];
-        for (int i = 0; i < 4; i++) {
-            texCoords[i] = get_json_point(jsonTexCoords[i]);
-        }
-        texCoordsPtr = texCoords;
-    }
-    else {
-        texCoordsPtr = nullptr;
-    }
-
-    SkBlendMode bmode = SkBlendMode::kSrcOver; // TODO: extract from json
-
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawPatchCommand(cubics, colorsPtr, texCoordsPtr, bmode, paint);
-}
-
-SkDrawRectCommand::SkDrawRectCommand(const SkRect& rect, const SkPaint& paint)
-    : INHERITED(kDrawRect_OpType) {
-    fRect = rect;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::RectToString(rect));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawRectCommand::execute(SkCanvas* canvas) const {
-    canvas->drawRect(fRect, fPaint);
-}
-
-Json::Value SkDrawRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-
-    SkString desc;
-    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fRect)->c_str());
-
-    return result;
-}
-
-SkDrawRectCommand* SkDrawRectCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    SkRect coords;
-    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawRectCommand(coords, paint);
-}
-
-SkDrawRRectCommand::SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
-    : INHERITED(kDrawRRect_OpType) {
-    fRRect = rrect;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::RRectToString(rrect));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawRRectCommand::execute(SkCanvas* canvas) const {
-    canvas->drawRRect(fRRect, fPaint);
-}
-
-bool SkDrawRRectCommand::render(SkCanvas* canvas) const {
-    render_rrect(canvas, fRRect);
-    return true;
-}
-
-Json::Value SkDrawRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawRRectCommand* SkDrawRRectCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    SkRRect coords;
-    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawRRectCommand(coords, paint);
-}
-
-SkDrawDRRectCommand::SkDrawDRRectCommand(const SkRRect& outer,
-                                         const SkRRect& inner,
-                                         const SkPaint& paint)
-    : INHERITED(kDrawDRRect_OpType) {
-    fOuter = outer;
-    fInner = inner;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::RRectToString(outer));
-    fInfo.push(SkObjectParser::RRectToString(inner));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawDRRectCommand::execute(SkCanvas* canvas) const {
-    canvas->drawDRRect(fOuter, fInner, fPaint);
-}
-
-bool SkDrawDRRectCommand::render(SkCanvas* canvas) const {
-    render_drrect(canvas, fOuter, fInner);
-    return true;
-}
-
-Json::Value SkDrawDRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_OUTER] = make_json_rrect(fOuter);
-    result[SKDEBUGCANVAS_ATTRIBUTE_INNER] = make_json_rrect(fInner);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawDRRectCommand* SkDrawDRRectCommand::fromJSON(Json::Value& command,
-                                                   UrlDataManager& urlDataManager) {
-    SkRRect outer;
-    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &outer);
-    SkRRect inner;
-    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &inner);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    return new SkDrawDRRectCommand(outer, inner, paint);
-}
-
-SkDrawTextCommand::SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,
-                                     const SkPaint& paint)
-    : INHERITED(kDrawText_OpType) {
-    fText = new char[byteLength];
-    memcpy(fText, text, byteLength);
-    fByteLength = byteLength;
-    fX = x;
-    fY = y;
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
-    fInfo.push(SkObjectParser::ScalarToString(x, "SkScalar x: "));
-    fInfo.push(SkObjectParser::ScalarToString(y, "SkScalar y: "));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawTextCommand::execute(SkCanvas* canvas) const {
-    canvas->drawText(fText, fByteLength, fX, fY, fPaint);
-}
-
-Json::Value SkDrawTextCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
-                                                       ((const char*) fText) + fByteLength);
-    Json::Value coords(Json::arrayValue);
-    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fX, fY);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawTextCommand* SkDrawTextCommand::fromJSON(Json::Value& command,
-                                               UrlDataManager& urlDataManager) {
-    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
-    return new SkDrawTextCommand(text, strlen(text), coords[0].asFloat(), coords[1].asFloat(),
-                                 paint);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-SkDrawTextOnPathCommand::SkDrawTextOnPathCommand(const void* text, size_t byteLength,
-                                                 const SkPath& path, const SkMatrix* matrix,
-                                                 const SkPaint& paint)
-    : INHERITED(kDrawTextOnPath_OpType) {
-    fText = new char[byteLength];
-    memcpy(fText, text, byteLength);
-    fByteLength = byteLength;
-    fPath = path;
-    if (matrix) {
-        fMatrix = *matrix;
-    } else {
-        fMatrix.setIdentity();
-    }
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
-    fInfo.push(SkObjectParser::PathToString(path));
-    if (matrix) {
-        fInfo.push(SkObjectParser::MatrixToString(*matrix));
-    }
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawTextOnPathCommand::execute(SkCanvas* canvas) const {
-    canvas->drawTextOnPath(fText, fByteLength, fPath,
-                           fMatrix.isIdentity() ? nullptr : &fMatrix,
-                           fPaint);
-}
-
-Json::Value SkDrawTextOnPathCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
-                                                       ((const char*) fText) + fByteLength);
-    Json::Value coords(Json::arrayValue);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
-    if (!fMatrix.isIdentity()) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
-    }
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawTextOnPathCommand* SkDrawTextOnPathCommand::fromJSON(Json::Value& command,
-                                                           UrlDataManager& urlDataManager) {
-    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-    SkPath path;
-    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
-    SkMatrix* matrixPtr;
-    SkMatrix matrix;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_MATRIX)) {
-        extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
-        matrixPtr = &matrix;
-    }
-    else {
-        matrixPtr = nullptr;
-    }
-    return new SkDrawTextOnPathCommand(text, strlen(text), path, matrixPtr, paint);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-SkDrawTextRSXformCommand::SkDrawTextRSXformCommand(const void* text, size_t byteLength,
-                                                   const SkRSXform xform[], const SkRect* cull,
-                                                   const SkPaint& paint)
-    : INHERITED(kDrawTextRSXform_OpType)
-{
-    fText = new char[byteLength];
-    memcpy(fText, text, byteLength);
-    fByteLength = byteLength;
-    int count = paint.countText(text, byteLength);
-    fXform = new SkRSXform[count];
-    memcpy(fXform, xform, count * sizeof(SkRSXform));
-    if (cull) {
-        fCullStorage = *cull;
-        fCull = &fCullStorage;
-    } else {
-        fCull = nullptr;
-    }
-    fPaint = paint;
-
-    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawTextRSXformCommand::execute(SkCanvas* canvas) const {
-    canvas->drawTextRSXform(fText, fByteLength, fXform, fCull, fPaint);
-}
-
-Json::Value SkDrawTextRSXformCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
-                                                       ((const char*) fText) + fByteLength);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
-    return result;
-}
-
-SkDrawTextRSXformCommand* SkDrawTextRSXformCommand::fromJSON(Json::Value& command,
-                                                             UrlDataManager& urlDataManager) {
-    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
-    size_t byteLength = strlen(text);
-    SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-
-    // TODO: handle xform and cull
-    int count = paint.countText(text, byteLength);
-    SkAutoTArray<SkRSXform> xform(count);
-    for (int i = 0; i < count; ++i) {
-        xform[i].fSCos = 1;
-        xform[i].fSSin = xform[i].fTx = xform[i].fTy = 0;
-    }
-    return new SkDrawTextRSXformCommand(text, byteLength, &xform[0], nullptr, paint);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-SkDrawVerticesCommand::SkDrawVerticesCommand(sk_sp<SkVertices> vertices, SkBlendMode bmode,
-                                             const SkPaint& paint)
-    : INHERITED(kDrawVertices_OpType)
-    , fVertices(std::move(vertices))
-    , fBlendMode(bmode)
-    , fPaint(paint)
-{
-    // TODO(chudy)
-    fInfo.push(SkObjectParser::CustomTextToString("To be implemented."));
-    fInfo.push(SkObjectParser::PaintToString(paint));
-}
-
-void SkDrawVerticesCommand::execute(SkCanvas* canvas) const {
-    canvas->drawVertices(fVertices, fBlendMode, fPaint);
-}
-
-SkRestoreCommand::SkRestoreCommand()
-    : INHERITED(kRestore_OpType) {
-    fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
-}
-
-void SkRestoreCommand::execute(SkCanvas* canvas) const {
-    canvas->restore();
-}
-
-SkRestoreCommand* SkRestoreCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
-    return new SkRestoreCommand();
-}
-
-SkSaveCommand::SkSaveCommand()
-    : INHERITED(kSave_OpType) {
-}
-
-void SkSaveCommand::execute(SkCanvas* canvas) const {
-    canvas->save();
-}
-
-SkSaveCommand* SkSaveCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
-    return new SkSaveCommand();
-}
-
-SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
-    : INHERITED(kSaveLayer_OpType) {
-    if (rec.fBounds) {
-        fBounds = *rec.fBounds;
-    } else {
-        fBounds.setEmpty();
-    }
-
-    if (rec.fPaint) {
-        fPaint = *rec.fPaint;
-        fPaintPtr = &fPaint;
-    } else {
-        fPaintPtr = nullptr;
-    }
-    fSaveLayerFlags = rec.fSaveLayerFlags;
-
-    if (rec.fBackdrop) {
-        fBackdrop = rec.fBackdrop;
-        fBackdrop->ref();
-    } else {
-        fBackdrop = nullptr;
-    }
-
-    if (rec.fBounds) {
-        fInfo.push(SkObjectParser::RectToString(*rec.fBounds, "Bounds: "));
-    }
-    if (rec.fPaint) {
-        fInfo.push(SkObjectParser::PaintToString(*rec.fPaint));
-    }
-    fInfo.push(SkObjectParser::SaveLayerFlagsToString(fSaveLayerFlags));
-}
-
-SkSaveLayerCommand::~SkSaveLayerCommand() {
-    if (fBackdrop != nullptr) {
-        fBackdrop->unref();
-    }
-}
-
-void SkSaveLayerCommand::execute(SkCanvas* canvas) const {
-    canvas->saveLayer(SkCanvas::SaveLayerRec(fBounds.isEmpty() ? nullptr : &fBounds,
-                                             fPaintPtr,
-                                             fSaveLayerFlags));
-}
-
-void SkSaveLayerCommand::vizExecute(SkCanvas* canvas) const {
-    canvas->save();
-}
-
-Json::Value SkSaveLayerCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    if (!fBounds.isEmpty()) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = MakeJsonRect(fBounds);
-    }
-    if (fPaintPtr != nullptr) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr,
-                                                                urlDataManager);
-    }
-    if (fBackdrop != nullptr) {
-        Json::Value jsonBackdrop;
-        flatten(fBackdrop, &jsonBackdrop, urlDataManager);
-        result[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP] = jsonBackdrop;
-    }
-    if (fSaveLayerFlags != 0) {
-        SkDebugf("unsupported: saveLayer flags\n");
-        SkASSERT(false);
-    }
-    return result;
-}
-
-SkSaveLayerCommand* SkSaveLayerCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    SkCanvas::SaveLayerRec rec;
-    SkRect bounds;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS)) {
-        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS], &bounds);
-        rec.fBounds = &bounds;
-    }
-    SkPaint paint;
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
-        rec.fPaint = &paint;
-    }
-    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BACKDROP)) {
-        Json::Value backdrop = command[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP];
-        rec.fBackdrop = (SkImageFilter*) load_flattenable(backdrop, urlDataManager);
-    }
-    SkSaveLayerCommand* result = new SkSaveLayerCommand(rec);
-    if (rec.fBackdrop != nullptr) {
-        rec.fBackdrop->unref();
-    }
-    return result;
-}
-
-SkSetMatrixCommand::SkSetMatrixCommand(const SkMatrix& matrix)
-    : INHERITED(kSetMatrix_OpType) {
-    fUserMatrix.reset();
-    fMatrix = matrix;
-    fInfo.push(SkObjectParser::MatrixToString(matrix));
-}
-
-void SkSetMatrixCommand::setUserMatrix(const SkMatrix& userMatrix) {
-    fUserMatrix = userMatrix;
-}
-
-void SkSetMatrixCommand::execute(SkCanvas* canvas) const {
-    SkMatrix temp = SkMatrix::Concat(fUserMatrix, fMatrix);
-    canvas->setMatrix(temp);
-}
-
-Json::Value SkSetMatrixCommand::toJSON(UrlDataManager& urlDataManager) const {
-    Json::Value result = INHERITED::toJSON(urlDataManager);
-    result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
-    return result;
-}
-
-SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command,
-                                                 UrlDataManager& urlDataManager) {
-    SkMatrix matrix;
-    extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
-    return new SkSetMatrixCommand(matrix);
-}
diff --git a/src/third_party/skia/tools/debugger/SkDrawCommand.h b/src/third_party/skia/tools/debugger/SkDrawCommand.h
deleted file mode 100644
index 654cbdd..0000000
--- a/src/third_party/skia/tools/debugger/SkDrawCommand.h
+++ /dev/null
@@ -1,766 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SKDRAWCOMMAND_H_
-#define SKDRAWCOMMAND_H_
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkFlattenable.h"
-#include "SkTLazy.h"
-#include "SkPath.h"
-#include "SkRegion.h"
-#include "SkRRect.h"
-#include "SkRSXform.h"
-#include "SkString.h"
-#include "SkTDArray.h"
-#include "SkVertices.h"
-#include "SkJSONCPP.h"
-#include "UrlDataManager.h"
-
-class SkDrawCommand {
-public:
-    enum OpType {
-        kBeginDrawPicture_OpType,
-        kClipPath_OpType,
-        kClipRegion_OpType,
-        kClipRect_OpType,
-        kClipRRect_OpType,
-        kConcat_OpType,
-        kDrawAnnotation_OpType,
-        kDrawBitmap_OpType,
-        kDrawBitmapNine_OpType,
-        kDrawBitmapRect_OpType,
-        kDrawClear_OpType,
-        kDrawDRRect_OpType,
-        kDrawImage_OpType,
-        kDrawImageLattice_OpType,
-        kDrawImageRect_OpType,
-        kDrawOval_OpType,
-        kDrawPaint_OpType,
-        kDrawPatch_OpType,
-        kDrawPath_OpType,
-        kDrawPoints_OpType,
-        kDrawPosText_OpType,
-        kDrawPosTextH_OpType,
-        kDrawRect_OpType,
-        kDrawRRect_OpType,
-        kDrawText_OpType,
-        kDrawTextBlob_OpType,
-        kDrawTextOnPath_OpType,
-        kDrawTextRSXform_OpType,
-        kDrawVertices_OpType,
-        kEndDrawPicture_OpType,
-        kRestore_OpType,
-        kSave_OpType,
-        kSaveLayer_OpType,
-        kSetMatrix_OpType,
-
-        kLast_OpType = kSetMatrix_OpType
-    };
-
-    static const int kOpTypeCount = kLast_OpType + 1;
-
-    static void WritePNG(const uint8_t* rgba, unsigned width, unsigned height,
-                         SkWStream& out, bool isOpaque);
-
-    SkDrawCommand(OpType opType);
-
-    virtual ~SkDrawCommand();
-
-    virtual SkString toString() const;
-
-    virtual const char* toCString() const {
-        return GetCommandString(fOpType);
-    }
-
-    bool isVisible() const {
-        return fVisible;
-    }
-
-    void setVisible(bool toggle) {
-        fVisible = toggle;
-    }
-
-    const SkTDArray<SkString*>* Info() const { return &fInfo; }
-    virtual void execute(SkCanvas*) const = 0;
-    virtual void vizExecute(SkCanvas*) const {}
-
-    virtual void setUserMatrix(const SkMatrix&) {}
-
-    // The next "active" system is only used by save, saveLayer, and restore.
-    // It is used to determine which saveLayers are currently active (at a
-    // given point in the rendering).
-    //      saves just return a kPushLayer action but don't track active state
-    //      restores just return a kPopLayer action
-    //      saveLayers return kPushLayer but also track the active state
-    enum Action {
-        kNone_Action,
-        kPopLayer_Action,
-        kPushLayer_Action,
-    };
-    virtual Action action() const { return kNone_Action; }
-    virtual void setActive(bool active) {}
-    virtual bool active() const { return false; }
-
-    OpType getType() const { return fOpType; }
-
-    virtual bool render(SkCanvas* canvas) const { return false; }
-
-    virtual Json::Value toJSON(UrlDataManager& urlDataManager) const;
-
-    /* Converts a JSON representation of a command into a newly-allocated SkDrawCommand object. It
-     * is the caller's responsibility to delete this object. This method may return null if an error
-     * occurs.
-     */
-    static SkDrawCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-    static const char* GetCommandString(OpType type);
-
-    // Helper methods for converting things to JSON
-    static Json::Value MakeJsonColor(const SkColor color);
-    static Json::Value MakeJsonColor4f(const SkColor4f& color);
-    static Json::Value MakeJsonPoint(const SkPoint& point);
-    static Json::Value MakeJsonPoint(SkScalar x, SkScalar y);
-    static Json::Value MakeJsonRect(const SkRect& rect);
-    static Json::Value MakeJsonIRect(const SkIRect&);
-    static Json::Value MakeJsonMatrix(const SkMatrix&);
-    static Json::Value MakeJsonScalar(SkScalar);
-    static Json::Value MakeJsonPath(const SkPath& path);
-    static Json::Value MakeJsonRegion(const SkRegion& region);
-    static Json::Value MakeJsonPaint(const SkPaint& paint, UrlDataManager& urlDataManager);
-    static Json::Value MakeJsonLattice(const SkCanvas::Lattice& lattice);
-
-    static void flatten(const SkFlattenable* flattenable, Json::Value* target,
-                        UrlDataManager& urlDataManager);
-    static bool flatten(const SkImage& image, Json::Value* target,
-                        UrlDataManager& urlDataManager);
-    static bool flatten(const SkBitmap& bitmap, Json::Value* target,
-                        UrlDataManager& urlDataManager);
-
-protected:
-    SkTDArray<SkString*> fInfo;
-
-private:
-    OpType fOpType;
-    bool   fVisible;
-};
-
-class SkRestoreCommand : public SkDrawCommand {
-public:
-    SkRestoreCommand();
-    void execute(SkCanvas* canvas) const override;
-    Action action() const override { return kPopLayer_Action; }
-    static SkRestoreCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkClearCommand : public SkDrawCommand {
-public:
-    SkClearCommand(SkColor color);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkClearCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkColor fColor;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkClipPathCommand : public SkDrawCommand {
-public:
-    SkClipPathCommand(const SkPath& path, SkClipOp op, bool doAA);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkClipPathCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkPath   fPath;
-    SkClipOp fOp;
-    bool     fDoAA;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkClipRegionCommand : public SkDrawCommand {
-public:
-    SkClipRegionCommand(const SkRegion& region, SkClipOp op);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkClipRegionCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRegion fRegion;
-    SkClipOp fOp;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkClipRectCommand : public SkDrawCommand {
-public:
-    SkClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkClipRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-    const SkRect& rect() const { return fRect; }
-    SkClipOp op() const { return fOp; }
-    bool doAA() const { return fDoAA; }
-
-private:
-    SkRect   fRect;
-    SkClipOp fOp;
-    bool     fDoAA;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkClipRRectCommand : public SkDrawCommand {
-public:
-    SkClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkClipRRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-    const SkRRect& rrect() const { return fRRect; }
-    SkClipOp op() const { return fOp; }
-    bool doAA() const { return fDoAA; }
-
-private:
-    SkRRect  fRRect;
-    SkClipOp fOp;
-    bool     fDoAA;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkConcatCommand : public SkDrawCommand {
-public:
-    SkConcatCommand(const SkMatrix& matrix);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkConcatCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkMatrix fMatrix;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawAnnotationCommand : public SkDrawCommand {
-public:
-    SkDrawAnnotationCommand(const SkRect&, const char key[], sk_sp<SkData> value);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawAnnotationCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRect          fRect;
-    SkString        fKey;
-    sk_sp<SkData>   fValue;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawBitmapCommand : public SkDrawCommand {
-public:
-    SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top,
-                        const SkPaint* paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawBitmapCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkBitmap fBitmap;
-    SkScalar fLeft;
-    SkScalar fTop;
-    SkPaint  fPaint;
-    SkPaint* fPaintPtr;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawBitmapNineCommand : public SkDrawCommand {
-public:
-    SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center,
-                            const SkRect& dst, const SkPaint* paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawBitmapNineCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkBitmap fBitmap;
-    SkIRect  fCenter;
-    SkRect   fDst;
-    SkPaint  fPaint;
-    SkPaint* fPaintPtr;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawBitmapRectCommand : public SkDrawCommand {
-public:
-    SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src,
-                            const SkRect& dst, const SkPaint* paint,
-                            SkCanvas::SrcRectConstraint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawBitmapRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-    const SkBitmap& bitmap() const { return fBitmap; }
-
-    // The non-const 'paint' method allows modification of this object's
-    // SkPaint. For this reason the ctor and setPaint method make a local copy.
-    // The 'fPaintPtr' member acts a signal that the local SkPaint is valid
-    // (since only an SkPaint* is passed into the ctor).
-    const SkPaint* paint() const { return fPaintPtr; }
-    SkPaint* paint() { return fPaintPtr; }
-
-    void setPaint(const SkPaint& paint) { fPaint = paint; fPaintPtr = &fPaint; }
-
-    const SkRect* srcRect() const { return fSrc.isEmpty() ? nullptr : &fSrc; }
-    void setSrcRect(const SkRect& src) { fSrc = src; }
-
-    const SkRect& dstRect() const { return fDst; }
-    void setDstRect(const SkRect& dst) { fDst = dst; }
-
-    SkCanvas::SrcRectConstraint constraint() const { return fConstraint; }
-    void setConstraint(SkCanvas::SrcRectConstraint constraint) { fConstraint = constraint; }
-
-private:
-    SkBitmap                      fBitmap;
-    SkRect                        fSrc;
-    SkRect                        fDst;
-    SkPaint                       fPaint;
-    SkPaint*                      fPaintPtr;
-    SkCanvas::SrcRectConstraint   fConstraint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawImageCommand : public SkDrawCommand {
-public:
-    SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawImageCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    sk_sp<const SkImage> fImage;
-    SkScalar             fLeft;
-    SkScalar             fTop;
-    SkTLazy<SkPaint>     fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawImageLatticeCommand : public SkDrawCommand {
-public:
-    SkDrawImageLatticeCommand(const SkImage* image, const SkCanvas::Lattice& lattice,
-                              const SkRect& dst, const SkPaint* paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-
-private:
-    sk_sp<const SkImage>        fImage;
-    SkCanvas::Lattice           fLattice;
-    SkRect                      fDst;
-    SkTLazy<SkPaint>            fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawImageRectCommand : public SkDrawCommand {
-public:
-    SkDrawImageRectCommand(const SkImage* image, const SkRect* src, const SkRect& dst,
-                           const SkPaint* paint, SkCanvas::SrcRectConstraint constraint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawImageRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    sk_sp<const SkImage>        fImage;
-    SkTLazy<SkRect>             fSrc;
-    SkRect                      fDst;
-    SkTLazy<SkPaint>            fPaint;
-    SkCanvas::SrcRectConstraint fConstraint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawOvalCommand : public SkDrawCommand {
-public:
-    SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawOvalCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRect  fOval;
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawArcCommand : public SkDrawCommand {
-public:
-    SkDrawArcCommand(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
-                     const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawArcCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRect   fOval;
-    SkScalar fStartAngle;
-    SkScalar fSweepAngle;
-    bool     fUseCenter;
-    SkPaint  fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPaintCommand : public SkDrawCommand {
-public:
-    SkDrawPaintCommand(const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPaintCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPathCommand : public SkDrawCommand {
-public:
-    SkDrawPathCommand(const SkPath& path, const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPathCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkPath   fPath;
-    SkPaint  fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkBeginDrawPictureCommand : public SkDrawCommand {
-public:
-    SkBeginDrawPictureCommand(const SkPicture* picture,
-                              const SkMatrix* matrix,
-                              const SkPaint* paint);
-
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-
-private:
-    sk_sp<const SkPicture> fPicture;
-    SkTLazy<SkMatrix>      fMatrix;
-    SkTLazy<SkPaint>       fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkEndDrawPictureCommand : public SkDrawCommand {
-public:
-    SkEndDrawPictureCommand(bool restore);
-
-    void execute(SkCanvas* canvas) const override;
-
-private:
-    bool fRestore;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPointsCommand : public SkDrawCommand {
-public:
-    SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
-                        const SkPaint& paint);
-    ~SkDrawPointsCommand() override { delete [] fPts; }
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPointsCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkCanvas::PointMode fMode;
-    size_t              fCount;
-    SkPoint*            fPts;
-    SkPaint             fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawTextCommand : public SkDrawCommand {
-public:
-    SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,
-                      const SkPaint& paint);
-    ~SkDrawTextCommand() override { delete [] fText; }
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawTextCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    char*    fText;
-    size_t   fByteLength;
-    SkScalar fX;
-    SkScalar fY;
-    SkPaint  fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPosTextCommand : public SkDrawCommand {
-public:
-    SkDrawPosTextCommand(const void* text, size_t byteLength, const SkPoint pos[],
-                         const SkPaint& paint);
-    ~SkDrawPosTextCommand() override { delete [] fPos; delete [] fText; }
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPosTextCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    char*    fText;
-    size_t   fByteLength;
-    SkPoint* fPos;
-    SkPaint  fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawTextOnPathCommand : public SkDrawCommand {
-public:
-    SkDrawTextOnPathCommand(const void* text, size_t byteLength, const SkPath& path,
-                            const SkMatrix* matrix, const SkPaint& paint);
-    ~SkDrawTextOnPathCommand() override { delete [] fText; }
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawTextOnPathCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    char*    fText;
-    size_t   fByteLength;
-    SkPath   fPath;
-    SkMatrix fMatrix;
-    SkPaint  fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawTextRSXformCommand : public SkDrawCommand {
-public:
-    SkDrawTextRSXformCommand(const void* text, size_t byteLength, const SkRSXform[],
-                             const SkRect*, const SkPaint& paint);
-    ~SkDrawTextRSXformCommand() override { delete[] fText; delete[] fXform; }
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawTextRSXformCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    char*       fText;
-    size_t      fByteLength;
-    SkRSXform*  fXform;
-    SkRect*     fCull;
-    SkRect      fCullStorage;
-    SkPaint     fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPosTextHCommand : public SkDrawCommand {
-public:
-    SkDrawPosTextHCommand(const void* text, size_t byteLength, const SkScalar xpos[],
-                          SkScalar constY, const SkPaint& paint);
-    ~SkDrawPosTextHCommand() override { delete [] fXpos; delete [] fText; }
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPosTextHCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkScalar* fXpos;
-    char*     fText;
-    size_t    fByteLength;
-    SkScalar  fConstY;
-    SkPaint   fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawTextBlobCommand : public SkDrawCommand {
-public:
-    SkDrawTextBlobCommand(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y, const SkPaint& paint);
-
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawTextBlobCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    sk_sp<SkTextBlob> fBlob;
-    SkScalar          fXPos;
-    SkScalar          fYPos;
-    SkPaint           fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawPatchCommand : public SkDrawCommand {
-public:
-    SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4],
-                       const SkPoint texCoords[4], SkBlendMode bmode,
-                       const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawPatchCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkPoint fCubics[12];
-    SkColor* fColorsPtr;
-    SkColor  fColors[4];
-    SkPoint* fTexCoordsPtr;
-    SkPoint  fTexCoords[4];
-    SkBlendMode fBlendMode;
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-
-class SkDrawRectCommand : public SkDrawCommand {
-public:
-    SkDrawRectCommand(const SkRect& rect, const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-    const SkRect& rect() const   { return fRect; }
-    const SkPaint& paint() const { return fPaint; }
-private:
-    SkRect  fRect;
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawRRectCommand : public SkDrawCommand {
-public:
-    SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawRRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRRect fRRect;
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawDRRectCommand : public SkDrawCommand {
-public:
-    SkDrawDRRectCommand(const SkRRect& outer, const SkRRect& inner,
-                        const SkPaint& paint);
-    void execute(SkCanvas* canvas) const override;
-    bool render(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkDrawDRRectCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkRRect fOuter;
-    SkRRect fInner;
-    SkPaint fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkDrawVerticesCommand : public SkDrawCommand {
-public:
-    SkDrawVerticesCommand(sk_sp<SkVertices>, SkBlendMode, const SkPaint&);
-
-    void execute(SkCanvas* canvas) const override;
-
-private:
-    sk_sp<SkVertices>   fVertices;
-    SkBlendMode         fBlendMode;
-    SkPaint             fPaint;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkSaveCommand : public SkDrawCommand {
-public:
-    SkSaveCommand();
-    void execute(SkCanvas* canvas) const override;
-    Action action() const override { return kPushLayer_Action; }
-    static SkSaveCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkSaveLayerCommand : public SkDrawCommand {
-public:
-    SkSaveLayerCommand(const SkCanvas::SaveLayerRec&);
-    ~SkSaveLayerCommand() override;
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkSaveLayerCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-    void vizExecute(SkCanvas* canvas) const override;
-    Action action() const override{ return kPushLayer_Action; }
-    void setActive(bool active) override { fActive = active; }
-    bool active() const override { return fActive; }
-
-    const SkPaint* paint() const { return fPaintPtr; }
-
-private:
-    SkRect               fBounds;
-    SkPaint              fPaint;
-    SkPaint*             fPaintPtr;
-    const SkImageFilter* fBackdrop;
-    uint32_t       fSaveLayerFlags;
-
-    bool        fActive;
-
-    typedef SkDrawCommand INHERITED;
-};
-
-class SkSetMatrixCommand : public SkDrawCommand {
-public:
-    SkSetMatrixCommand(const SkMatrix& matrix);
-    void setUserMatrix(const SkMatrix&) override;
-    void execute(SkCanvas* canvas) const override;
-    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
-    static SkSetMatrixCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
-
-private:
-    SkMatrix fUserMatrix;
-    SkMatrix fMatrix;
-
-    typedef SkDrawCommand INHERITED;
-};
-#endif
-
diff --git a/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.cpp b/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.cpp
deleted file mode 100644
index 4b075dd..0000000
--- a/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkJsonWriteBuffer.h"
-
-#include "SkDrawCommand.h"
-#include "SkObjectParser.h"
-
-void SkJsonWriteBuffer::append(const char* type, const Json::Value& value) {
-    SkString fullName = SkStringPrintf("%02d_%s", fJson.size(), type);
-    fJson[fullName.c_str()] = value;
-}
-
-void SkJsonWriteBuffer::writeByteArray(const void* data, size_t size) {
-    Json::Value jsonArray(Json::arrayValue);
-    const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
-    for (size_t i = 0; i < size; ++i) {
-        SkString hexByte = SkStringPrintf("%02x", bytes[i]);
-        jsonArray.append(hexByte.c_str());
-    }
-    this->append("byteArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writeBool(bool value) {
-    this->append("bool", value);
-}
-
-void SkJsonWriteBuffer::writeScalar(SkScalar value) {
-    this->append("scalar", value);
-}
-
-void SkJsonWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
-    Json::Value jsonArray(Json::arrayValue);
-    for (uint32_t i = 0; i < count; ++i) {
-        jsonArray.append(value[i]);
-    }
-    this->append("scalarArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writeInt(int32_t value) {
-    this->append("int", value);
-}
-
-void SkJsonWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
-    Json::Value jsonArray(Json::arrayValue);
-    for (uint32_t i = 0; i < count; ++i) {
-        jsonArray.append(value[i]);
-    }
-    this->append("intArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writeUInt(uint32_t value) {
-    this->append("uint", value);
-}
-
-void SkJsonWriteBuffer::writeString(const char* value) {
-    this->append("string", value);
-}
-
-void SkJsonWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
-    if (flattenable) {
-        SkJsonWriteBuffer flattenableBuffer(fUrlDataManager);
-        flattenable->flatten(flattenableBuffer);
-        this->append(flattenable->getTypeName(), flattenableBuffer.getValue());
-    } else {
-        this->append("flattenable", Json::Value());
-    }
-}
-
-void SkJsonWriteBuffer::writeColor(SkColor color) {
-    this->append("color", SkDrawCommand::MakeJsonColor(color));
-}
-
-void SkJsonWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
-    Json::Value jsonArray(Json::arrayValue);
-    for (uint32_t i = 0; i < count; ++i) {
-        jsonArray.append(SkDrawCommand::MakeJsonColor(color[i]));
-    }
-    this->append("colorArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writeColor4f(const SkColor4f& color) {
-    this->append("color", SkDrawCommand::MakeJsonColor4f(color));
-}
-
-void SkJsonWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
-    Json::Value jsonArray(Json::arrayValue);
-    for (uint32_t i = 0; i < count; ++i) {
-        jsonArray.append(SkDrawCommand::MakeJsonColor4f(color[i]));
-    }
-    this->append("colorArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writePoint(const SkPoint& point) {
-    this->append("point", SkDrawCommand::MakeJsonPoint(point));
-}
-
-void SkJsonWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
-    Json::Value jsonArray(Json::arrayValue);
-    for (uint32_t i = 0; i < count; ++i) {
-        jsonArray.append(SkDrawCommand::MakeJsonPoint(point[i]));
-    }
-    this->append("pointArray", jsonArray);
-}
-
-void SkJsonWriteBuffer::writeMatrix(const SkMatrix& matrix) {
-    this->append("matrix", SkDrawCommand::MakeJsonMatrix(matrix));
-}
-
-void SkJsonWriteBuffer::writeIRect(const SkIRect& rect) {
-    this->append("irect", SkDrawCommand::MakeJsonIRect(rect));
-}
-
-void SkJsonWriteBuffer::writeRect(const SkRect& rect) {
-    this->append("rect", SkDrawCommand::MakeJsonRect(rect));
-}
-
-void SkJsonWriteBuffer::writeRegion(const SkRegion& region) {
-    this->append("region", SkDrawCommand::MakeJsonRegion(region));
-}
-
-void SkJsonWriteBuffer::writePath(const SkPath& path) {
-    this->append("path", SkDrawCommand::MakeJsonPath(path));
-}
-
-size_t SkJsonWriteBuffer::writeStream(SkStream* stream, size_t length) {
-    // Contents not supported
-    SkASSERT(length < Json::Value::maxUInt);
-    this->append("stream", static_cast<Json::UInt>(length));
-    return 0;
-}
-
-void SkJsonWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
-    Json::Value jsonBitmap;
-    SkDrawCommand::flatten(bitmap, &jsonBitmap, *fUrlDataManager);
-    this->append("bitmap", jsonBitmap);
-}
-
-void SkJsonWriteBuffer::writeImage(const SkImage* image) {
-    Json::Value jsonImage;
-    SkDrawCommand::flatten(*image, &jsonImage, *fUrlDataManager);
-    this->append("image", jsonImage);
-}
-
-void SkJsonWriteBuffer::writeTypeface(SkTypeface* typeface) {
-    // Unsupported
-    this->append("typeface", Json::Value());
-}
-
-void SkJsonWriteBuffer::writePaint(const SkPaint& paint) {
-    this->append("paint", SkDrawCommand::MakeJsonPaint(paint, *fUrlDataManager));
-}
diff --git a/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.h b/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.h
deleted file mode 100644
index a0cf4e7..0000000
--- a/src/third_party/skia/tools/debugger/SkJsonWriteBuffer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkJsonWriteBuffer_DEFINED
-#define SkJsonWriteBuffer_DEFINED
-
-#include "SkWriteBuffer.h"
-
-#include "SkJSONCPP.h"
-
-class SkPath;
-class UrlDataManager;
-
-class SkJsonWriteBuffer final : public SkWriteBuffer {
-public:
-    SkJsonWriteBuffer(UrlDataManager* urlDataManager)
-        : fUrlDataManager(urlDataManager)
-        , fJson(Json::objectValue) {}
-
-    bool isCrossProcess() const override { return false; }
-
-    void writeByteArray(const void* data, size_t size) override;
-    void writeBool(bool value) override;
-    void writeScalar(SkScalar value) override;
-    void writeScalarArray(const SkScalar* value, uint32_t count) override;
-    void writeInt(int32_t value) override;
-    void writeIntArray(const int32_t* value, uint32_t count) override;
-    void writeUInt(uint32_t value) override;
-    void writeString(const char* value) override;
-
-    void writeFlattenable(const SkFlattenable* flattenable) override;
-    void writeColor(SkColor color) override;
-    void writeColorArray(const SkColor* color, uint32_t count) override;
-    void writeColor4f(const SkColor4f& color) override;
-    void writeColor4fArray(const SkColor4f* color, uint32_t count) override;
-    void writePoint(const SkPoint& point) override;
-    void writePointArray(const SkPoint* point, uint32_t count) override;
-    void writeMatrix(const SkMatrix& matrix) override;
-    void writeIRect(const SkIRect& rect) override;
-    void writeRect(const SkRect& rect) override;
-    void writeRegion(const SkRegion& region) override;
-    void writePath(const SkPath& path) override;
-    size_t writeStream(SkStream* stream, size_t length) override;
-    void writeBitmap(const SkBitmap& bitmap) override;
-    void writeImage(const SkImage*) override;
-    void writeTypeface(SkTypeface* typeface) override;
-    void writePaint(const SkPaint& paint) override;
-
-    const Json::Value& getValue() const { return fJson; }
-
-private:
-    void append(const char* type, const Json::Value& value);
-
-    UrlDataManager* fUrlDataManager;
-    Json::Value fJson;
-};
-
-#endif
diff --git a/src/third_party/skia/tools/debugger/SkObjectParser.cpp b/src/third_party/skia/tools/debugger/SkObjectParser.cpp
deleted file mode 100644
index 1f48319..0000000
--- a/src/third_party/skia/tools/debugger/SkObjectParser.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkObjectParser.h"
-#include "SkData.h"
-#include "SkFontDescriptor.h"
-#include "SkImage.h"
-#include "SkPath.h"
-#include "SkRRect.h"
-#include "SkShader.h"
-#include "SkStream.h"
-#include "SkStringUtils.h"
-#include "SkTypeface.h"
-#include "SkUtils.h"
-#include "SkClipOpPriv.h"
-
-/* TODO(chudy): Replace all std::strings with char */
-
-SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) {
-    SkString* mBitmap = new SkString("SkBitmap: ");
-    mBitmap->append("W: ");
-    mBitmap->appendS32(bitmap.width());
-    mBitmap->append(" H: ");
-    mBitmap->appendS32(bitmap.height());
-
-    const char* gColorTypeStrings[] = {
-        "None", "A8", "565", "4444", "RGBA", "BGRA",
-        "G8", "RGBAf16"
-    };
-    static_assert(kLastEnum_SkColorType + 1 == SK_ARRAY_COUNT(gColorTypeStrings),
-                  "colortype names do not match colortype enum");
-
-    mBitmap->append(" ColorType: ");
-    mBitmap->append(gColorTypeStrings[bitmap.colorType()]);
-
-    if (bitmap.isOpaque()) {
-        mBitmap->append(" opaque");
-    } else {
-        mBitmap->append(" not-opaque");
-    }
-
-    if (bitmap.isImmutable()) {
-        mBitmap->append(" immutable");
-    } else {
-        mBitmap->append(" not-immutable");
-    }
-
-    if (bitmap.isVolatile()) {
-        mBitmap->append(" volatile");
-    } else {
-        mBitmap->append(" not-volatile");
-    }
-
-    mBitmap->append(" genID: ");
-    mBitmap->appendS32(bitmap.getGenerationID());
-
-    return mBitmap;
-}
-
-SkString* SkObjectParser::ImageToString(const SkImage* image) {
-    SkString* str = new SkString("SkImage: ");
-    if (!image) {
-        return str;
-    }
-
-    str->append("W: ");
-    str->appendS32(image->width());
-    str->append(" H: ");
-    str->appendS32(image->height());
-
-    if (image->isOpaque()) {
-        str->append(" opaque");
-    } else {
-        str->append(" not-opaque");
-    }
-
-    str->append(" uniqueID: ");
-    str->appendS32(image->uniqueID());
-
-    return str;
-}
-
-SkString* SkObjectParser::BoolToString(bool doAA) {
-    SkString* mBool = new SkString("Bool doAA: ");
-    if (doAA) {
-        mBool->append("True");
-    } else {
-        mBool->append("False");
-    }
-    return mBool;
-}
-
-SkString* SkObjectParser::CustomTextToString(const char* text) {
-    SkString* mText = new SkString(text);
-    return mText;
-}
-
-SkString* SkObjectParser::IntToString(int x, const char* text) {
-    SkString* mInt = new SkString(text);
-    mInt->append(" ");
-    mInt->appendScalar(SkIntToScalar(x));
-    return mInt;
-}
-
-SkString* SkObjectParser::IRectToString(const SkIRect& rect) {
-    SkString* mRect = new SkString("SkIRect: ");
-    mRect->append("L: ");
-    mRect->appendS32(rect.left());
-    mRect->append(", T: ");
-    mRect->appendS32(rect.top());
-    mRect->append(", R: ");
-    mRect->appendS32(rect.right());
-    mRect->append(", B: ");
-    mRect->appendS32(rect.bottom());
-    return mRect;
-}
-
-SkString* SkObjectParser::MatrixToString(const SkMatrix& matrix) {
-    SkString* str = new SkString("SkMatrix: ");
-#ifndef SK_IGNORE_TO_STRING
-    matrix.toString(str);
-#endif
-    return str;
-}
-
-SkString* SkObjectParser::PaintToString(const SkPaint& paint) {
-    SkString* str = new SkString;
-#ifndef SK_IGNORE_TO_STRING
-    paint.toString(str);
-#endif
-    return str;
-}
-
-SkString* SkObjectParser::PathToString(const SkPath& path) {
-    SkString* mPath = new SkString;
-
-    mPath->appendf("Path (%d) (", path.getGenerationID());
-
-    static const char* gFillStrings[] = {
-        "Winding", "EvenOdd", "InverseWinding", "InverseEvenOdd"
-    };
-
-    mPath->append(gFillStrings[path.getFillType()]);
-    mPath->append(", ");
-
-    static const char* gConvexityStrings[] = {
-        "Unknown", "Convex", "Concave"
-    };
-    SkASSERT(SkPath::kConcave_Convexity == 2);
-
-    mPath->append(gConvexityStrings[path.getConvexity()]);
-    mPath->append(", ");
-
-    if (path.isRect(nullptr)) {
-        mPath->append("isRect, ");
-    } else {
-        mPath->append("isNotRect, ");
-    }
-
-    if (path.isOval(nullptr)) {
-        mPath->append("isOval, ");
-    } else {
-        mPath->append("isNotOval, ");
-    }
-
-    SkRRect rrect;
-    if (path.isRRect(&rrect)) {
-        mPath->append("isRRect, ");
-    } else {
-        mPath->append("isNotRRect, ");
-    }
-
-    mPath->appendS32(path.countVerbs());
-    mPath->append("V, ");
-    mPath->appendS32(path.countPoints());
-    mPath->append("P): ");
-
-    static const char* gVerbStrings[] = {
-        "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done"
-    };
-    static const int gPtsPerVerb[] = { 1, 1, 2, 2, 3, 0, 0 };
-    static const int gPtOffsetPerVerb[] = { 0, 1, 1, 1, 1, 0, 0 };
-    SkASSERT(SkPath::kDone_Verb == 6);
-
-    SkPath::Iter iter(const_cast<SkPath&>(path), false);
-    SkPath::Verb verb;
-    SkPoint points[4];
-
-    for(verb = iter.next(points, false);
-        verb != SkPath::kDone_Verb;
-        verb = iter.next(points, false)) {
-
-        mPath->append(gVerbStrings[verb]);
-        mPath->append(" ");
-
-        for (int i = 0; i < gPtsPerVerb[verb]; ++i) {
-            mPath->append("(");
-            mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fX);
-            mPath->append(", ");
-            mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fY);
-            mPath->append(")");
-        }
-
-        if (SkPath::kConic_Verb == verb) {
-            mPath->append("(");
-            mPath->appendScalar(iter.conicWeight());
-            mPath->append(")");
-        }
-
-        mPath->append(" ");
-    }
-
-    SkString* boundStr = SkObjectParser::RectToString(path.getBounds(), "    Bound: ");
-
-    if (boundStr) {
-        mPath->append(*boundStr);
-        delete boundStr;
-    }
-
-    return mPath;
-}
-
-SkString* SkObjectParser::PointsToString(const SkPoint pts[], size_t count) {
-    SkString* mPoints = new SkString("SkPoints pts[]: ");
-    for (unsigned int i = 0; i < count; i++) {
-        mPoints->append("(");
-        mPoints->appendScalar(pts[i].fX);
-        mPoints->append(",");
-        mPoints->appendScalar(pts[i].fY);
-        mPoints->append(")");
-    }
-    return mPoints;
-}
-
-SkString* SkObjectParser::PointModeToString(SkCanvas::PointMode mode) {
-    SkString* mMode = new SkString("SkCanvas::PointMode: ");
-    if (mode == SkCanvas::kPoints_PointMode) {
-        mMode->append("kPoints_PointMode");
-    } else if (mode == SkCanvas::kLines_PointMode) {
-        mMode->append("kLines_Mode");
-    } else if (mode == SkCanvas::kPolygon_PointMode) {
-        mMode->append("kPolygon_PointMode");
-    }
-    return mMode;
-}
-
-SkString* SkObjectParser::RectToString(const SkRect& rect, const char* title) {
-
-    SkString* mRect = new SkString;
-
-    if (nullptr == title) {
-        mRect->append("SkRect: ");
-    } else {
-        mRect->append(title);
-    }
-    mRect->append("(");
-    mRect->appendScalar(rect.left());
-    mRect->append(", ");
-    mRect->appendScalar(rect.top());
-    mRect->append(", ");
-    mRect->appendScalar(rect.right());
-    mRect->append(", ");
-    mRect->appendScalar(rect.bottom());
-    mRect->append(")");
-    return mRect;
-}
-
-SkString* SkObjectParser::RRectToString(const SkRRect& rrect, const char* title) {
-
-    SkString* mRRect = new SkString;
-
-    if (nullptr == title) {
-        mRRect->append("SkRRect (");
-        if (rrect.isEmpty()) {
-            mRRect->append("empty");
-        } else if (rrect.isRect()) {
-            mRRect->append("rect");
-        } else if (rrect.isOval()) {
-            mRRect->append("oval");
-        } else if (rrect.isSimple()) {
-            mRRect->append("simple");
-        } else if (rrect.isNinePatch()) {
-            mRRect->append("nine-patch");
-        } else {
-            SkASSERT(rrect.isComplex());
-            mRRect->append("complex");
-        }
-        mRRect->append("): ");
-    } else {
-        mRRect->append(title);
-    }
-    mRRect->append("(");
-    mRRect->appendScalar(rrect.rect().left());
-    mRRect->append(", ");
-    mRRect->appendScalar(rrect.rect().top());
-    mRRect->append(", ");
-    mRRect->appendScalar(rrect.rect().right());
-    mRRect->append(", ");
-    mRRect->appendScalar(rrect.rect().bottom());
-    mRRect->append(") radii: (");
-    for (int i = 0; i < 4; ++i) {
-        const SkVector& radii = rrect.radii((SkRRect::Corner) i);
-        mRRect->appendScalar(radii.fX);
-        mRRect->append(", ");
-        mRRect->appendScalar(radii.fY);
-        if (i < 3) {
-            mRRect->append(", ");
-        }
-    }
-    mRRect->append(")");
-    return mRRect;
-}
-
-SkString* SkObjectParser::ClipOpToString(SkClipOp op) {
-    SkString* mOp = new SkString("SkRegion::Op: ");
-    if (op == kDifference_SkClipOp) {
-        mOp->append("kDifference_Op");
-    } else if (op == kIntersect_SkClipOp) {
-        mOp->append("kIntersect_Op");
-    } else if (op == kUnion_SkClipOp) {
-        mOp->append("kUnion_Op");
-    } else if (op == kXOR_SkClipOp) {
-        mOp->append("kXOR_Op");
-    } else if (op == kReverseDifference_SkClipOp) {
-        mOp->append("kReverseDifference_Op");
-    } else if (op == kReplace_SkClipOp) {
-        mOp->append("kReplace_Op");
-    } else {
-        mOp->append("Unknown Type");
-    }
-    return mOp;
-}
-
-SkString* SkObjectParser::RegionToString(const SkRegion& region) {
-    SkString* mRegion = new SkString("SkRegion: Data unavailable.");
-    return mRegion;
-}
-
-SkString* SkObjectParser::SaveLayerFlagsToString(SkCanvas::SaveLayerFlags saveLayerFlags) {
-    SkString* mFlags = new SkString("SkCanvas::SaveFlags: ");
-    if (saveLayerFlags & SkCanvas::kIsOpaque_SaveLayerFlag) {
-        mFlags->append("kIsOpaque_SaveLayerFlag ");
-    }
-    if (saveLayerFlags & SkCanvas::kPreserveLCDText_SaveLayerFlag) {
-        mFlags->append("kPreserveLCDText_SaveLayerFlag ");
-    }
-    return mFlags;
-}
-
-SkString* SkObjectParser::ScalarToString(SkScalar x, const char* text) {
-    SkString* mScalar = new SkString(text);
-    mScalar->append(" ");
-    mScalar->appendScalar(x);
-    return mScalar;
-}
-
-SkString* SkObjectParser::TextToString(const void* text, size_t byteLength,
-                                       SkPaint::TextEncoding encoding) {
-
-    SkString* decodedText = new SkString();
-    switch (encoding) {
-        case SkPaint::kUTF8_TextEncoding: {
-            decodedText->append("UTF-8: ");
-            decodedText->append((const char*)text, byteLength);
-            break;
-        }
-        case SkPaint::kUTF16_TextEncoding: {
-            decodedText->append("UTF-16: ");
-            size_t sizeNeeded = SkUTF16_ToUTF8((uint16_t*)text,
-                                                SkToS32(byteLength / 2),
-                                                nullptr);
-            SkAutoSTMalloc<0x100, char> utf8(sizeNeeded);
-            SkUTF16_ToUTF8((uint16_t*)text, SkToS32(byteLength / 2), utf8);
-            decodedText->append(utf8, sizeNeeded);
-            break;
-        }
-        case SkPaint::kUTF32_TextEncoding: {
-            decodedText->append("UTF-32: ");
-            const SkUnichar* begin = (const SkUnichar*)text;
-            const SkUnichar* end = (const SkUnichar*)((const char*)text + byteLength);
-            for (const SkUnichar* unichar = begin; unichar < end; ++unichar) {
-                decodedText->appendUnichar(*unichar);
-            }
-            break;
-        }
-        case SkPaint::kGlyphID_TextEncoding: {
-            decodedText->append("GlyphID: ");
-            const uint16_t* begin = (const uint16_t*)text;
-            const uint16_t* end = (const uint16_t*)((const char*)text + byteLength);
-            for (const uint16_t* glyph = begin; glyph < end; ++glyph) {
-                decodedText->append("0x");
-                decodedText->appendHex(*glyph);
-                decodedText->append(" ");
-            }
-            break;
-        }
-        default:
-            decodedText->append("Unknown text encoding.");
-            break;
-    }
-
-    return decodedText;
-}
-
-SkString* SkObjectParser::LatticeToString(const SkCanvas::Lattice& lattice) {
-    SkString* mLattice = new SkString;
-    mLattice->append("Lattice: ");
-    mLattice->append("(X: ");
-    mLattice->appendS32(lattice.fXCount);
-    mLattice->append(", Y:");
-    mLattice->appendS32(lattice.fYCount);
-    mLattice->append(", Bounds:");
-    if (nullptr != lattice.fBounds) {
-        mLattice->append(*IRectToString(*lattice.fBounds));
-    } else {
-        mLattice->append("null");
-    }
-    mLattice->append(")");
-    return mLattice;
-}
diff --git a/src/third_party/skia/tools/debugger/SkObjectParser.h b/src/third_party/skia/tools/debugger/SkObjectParser.h
deleted file mode 100644
index 2532c5c..0000000
--- a/src/third_party/skia/tools/debugger/SkObjectParser.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SKOBJECTPARSER_H_
-#define SKOBJECTPARSER_H_
-
-#include "SkCanvas.h"
-#include "SkString.h"
-
-/** \class SkObjectParser
-
-    The ObjectParser is used to return string information about parameters
-    in each draw command.
- */
-class SkObjectParser {
-public:
-
-    /**
-        Returns a string about a bitmap's bounds and colortype.
-        @param bitmap  SkBitmap
-    */
-    static SkString* BitmapToString(const SkBitmap& bitmap);
-
-    /**
-        Returns a string about a image
-        @param image   SkImage
-    */
-    static SkString* ImageToString(const SkImage* image);
-
-    /**
-        Returns a string representation of a boolean.
-        @param doAA  boolean
-     */
-    static SkString* BoolToString(bool doAA);
-
-    /**
-        Returns a string representation of the text pointer passed in.
-     */
-    static SkString* CustomTextToString(const char* text);
-
-    /**
-        Returns a string representation of an integer with the text parameter
-        at the front of the string.
-        @param x  integer
-        @param text
-     */
-    static SkString* IntToString(int x, const char* text);
-    /**
-        Returns a string representation of the SkIRects coordinates.
-        @param rect  SkIRect
-     */
-    static SkString* IRectToString(const SkIRect& rect);
-
-    /**
-        Returns a string representation of an SkMatrix's contents
-        @param matrix  SkMatrix
-     */
-    static SkString* MatrixToString(const SkMatrix& matrix);
-
-    /**
-        Returns a string representation of an SkPaint's color
-        @param paint  SkPaint
-     */
-    static SkString* PaintToString(const SkPaint& paint);
-
-    /**
-        Returns a string representation of a SkPath's points.
-        @param path  SkPath
-     */
-    static SkString* PathToString(const SkPath& path);
-
-    /**
-        Returns a string representation of the points in the point array.
-        @param pts[]  Array of SkPoints
-        @param count
-     */
-    static SkString* PointsToString(const SkPoint pts[], size_t count);
-
-    /**
-        Returns a string representation of the SkCanvas PointMode enum.
-     */
-    static SkString* PointModeToString(SkCanvas::PointMode mode);
-
-    /**
-        Returns a string representation of the SkRects coordinates.
-        @param rect  SkRect
-     */
-    static SkString* RectToString(const SkRect& rect, const char* title = nullptr);
-
-    /**
-        Returns a string representation of an SkRRect.
-        @param rrect  SkRRect
-     */
-    static SkString* RRectToString(const SkRRect& rrect, const char* title = nullptr);
-
-    /**
-        Returns a string representation of the SkRegion enum.
-        @param op  SkRegion::op enum
-     */
-    static SkString* ClipOpToString(SkClipOp op);
-
-    /**
-        Returns a string representation of the SkRegion.
-        @param region  SkRegion
-     */
-    static SkString* RegionToString(const SkRegion& region);
-
-    /**
-        Returns a string representation of the SkCanvas::SaveLayerFlags enum.
-        @param flags  SkCanvas::SaveLayerFlags enum
-     */
-    static SkString* SaveLayerFlagsToString(uint32_t saveLayerFlags);
-
-    /**
-        Returns a string representation of an SkScalar with the text parameter
-        at the front of the string.
-        @param x  SkScalar
-        @param text
-     */
-    static SkString* ScalarToString(SkScalar x, const char* text);
-
-    /**
-        Returns a string representation of the char pointer passed in.
-        @param text  const void* that will be cast to a char*
-     */
-    static SkString* TextToString(const void* text, size_t byteLength,
-                                  SkPaint::TextEncoding encoding);
-
-    /**
-        Returns a string representation of the SkCanvas::Lattice.
-        @param lattice  SkCanvas::Lattice
-     */
-    static SkString* LatticeToString(const SkCanvas::Lattice& lattice);
-};
-
-#endif
diff --git a/src/third_party/skia/tools/doxygen/Doxyfile b/src/third_party/skia/tools/doxygen/Doxyfile
new file mode 100644
index 0000000..ada9cf1
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/Doxyfile
@@ -0,0 +1,2504 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "Skia"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "2D Graphics Library"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = logo.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = /tmp/doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = YES
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                = "copy{1}=\htmlonly <script>document.write('<div style=\'display:none;visibility:hidden;\'>');</script> \endhtmlonly \image html \1 \n \htmlonly <script>document.write('</div>');</script> \endhtmlonly"
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 2
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 8
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../../include/core \
+  ../../include/effects \
+  ../../include/gpu \
+  ../../include/pathops \
+  ../../third_party/skcms \
+  ../../modules/particles/include \
+  ../../modules/skottie/include \
+  ../../modules/sksg/include \
+  ../../modules/skshaper/include \
+  ./mainpage
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = ./mainpage/markdeep
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = ./footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = ./customdoxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         =  NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED = SkDEBUGCODE
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    =  NO
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
+
diff --git a/src/third_party/skia/tools/doxygen/ProdDoxyfile b/src/third_party/skia/tools/doxygen/ProdDoxyfile
new file mode 100644
index 0000000..afcacff
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/ProdDoxyfile
@@ -0,0 +1,5 @@
+# This config is used to generate the docs under continuous integration.
+
+@INCLUDE = Doxyfile
+
+OUTPUT_DIRECTORY       = /workspace/__doxygen_staging
diff --git a/src/third_party/skia/tools/doxygen/README.md b/src/third_party/skia/tools/doxygen/README.md
new file mode 100644
index 0000000..d01cecb
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/README.md
@@ -0,0 +1,31 @@
+Doxygen
+=======
+
+To generate all the documentation run the following
+from this directory:
+
+    doxygen Doxyfile
+
+The resulting output goes to
+
+    /tmp/doxygen
+
+To view those file locally in your browser run:
+
+    cd /tmp/doxygen/html; python -m SimpleHTTPServer 8000
+
+and visit
+
+    http://localhost:8000
+
+If you want to have the documentation regenerated on every save then
+you can install `entr` and run the following from this directory:
+
+    find  ../../include/ ../../src/ . | entr doxygen ./Doxyfile
+
+Install
+-------
+
+For a linux desktop you can install the doxygen tool via:
+
+    sudo apt install doxygen
diff --git a/src/third_party/skia/tools/doxygen/customdoxygen.css b/src/third_party/skia/tools/doxygen/customdoxygen.css
new file mode 100644
index 0000000..749cfb1
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/customdoxygen.css
@@ -0,0 +1,182 @@
+/* Skia overrides for doxygen CSS. */
+
+html {
+  --blue:          rgb(0,114,178);
+  --green:         rgb(0,158,115);
+  --red:           rgb(213,94,0);
+  --orange:        rgb(230,159,0);
+  --purple:        rgb(204,121,167);
+  --brown:         rgb(177,89,40);
+  --gray:          rgb(79,79,79);
+  --light-blue:    rgb(128,185,217);
+  --light-green:   rgb(128,207,185);
+  --light-red:     rgb(234,175,128);
+  --light-orange:  rgb(243,207,128);
+  --light-purple:  rgb(230,188,211);
+  --light-brown:   rgb(216,172,148);
+  --light-gray:    rgb(168,168,168);
+
+  --dark-blue:     rgb(0,65,101);
+  --dark-red:      rgb(156,44,8);
+
+  --white:         rgb(254,254,254);
+  --dark-white:    rgb(240,240,240);
+  --black:         rgb(10,10,10);
+}
+
+#titlearea {
+  /* background matches Skia logo. */
+  background: rgb(248,248,248);
+  color: var(--blue);
+}
+
+#main-nav .sm {
+  background-image: none;
+}
+
+h2.groupheader {
+  border-bottom: var(--gray);
+  color: var(--dark-blue);
+}
+
+div.qindex, div.navtab{
+  background-color: var(--light-gray);
+  border: 1px solid var(--light-blue);
+}
+
+a {
+  color: var(--blue);
+}
+
+.contents a:visited {
+  color: var(--blue);
+}
+
+a.qindexHL {
+  background-color: var(--light-gray);
+  color: var(--white);
+  border: 1px double var(--gray);
+}
+
+.contents a.qindexHL:visited {
+  color: var(--white);
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+  color: var(--blue);
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+  color: var(--blue);
+}
+
+pre.fragment {
+  border: 1px solid var(--orange);
+  background-color: var(--dark-white);
+}
+
+div.fragment {
+  background-color: var(--dark-white);
+  border: 1px solid var(--orange);
+}
+
+span.lineno {
+  border-right: 2px solid var(--green);
+  background-color: var(-light-gray);
+}
+span.lineno a {
+  background-color: var(--light-gray);
+}
+
+span.lineno a:hover {
+  background-color: var(--light-gray);
+  color: var(--blue);
+}
+
+div.ah, span.ah {
+  background-color: var(--black);
+  color: var(--white);
+  border: solid thin var(--gray);
+  box-shadow: 2px 2px 3px var(light-gray);
+  background-image: none;
+}
+
+td.indexkey {
+  background-color: var(--light-gray);
+  border: 1px solid var(--orange);
+}
+
+td.indexvalue {
+  background-color: var(--light-gray);
+  border: 1px solid var(--orange);
+}
+
+tr.memlist {
+  background-color: var(--light-gray);
+}
+
+span.keyword {
+  color: var(--green);
+}
+
+span.keywordtype {
+  color: var(--brown);
+}
+
+span.keywordflow {
+  color: var(--brown);
+}
+
+span.comment {
+  color: var(--brown);
+}
+
+span.charliteral {
+  color: var(--green);
+}
+
+span.vhdldigit { 
+  color: var(--purple);
+}
+
+span.vhdlchar {
+  color: var(--black);
+}
+
+blockquote {
+  background-color: var(--light-gray);
+  border-left: 2px solid var(--gray);
+}
+
+.memtitle {
+  background-image: none;
+}
+
+.memdoc, dl.reflist dd {
+  background-image: none;
+}
+
+.paramname {
+  color: var(--dark-red);
+}
+
+.tabsearch {
+  background-image: none;
+}
+
+.navpath ul {
+  background-image: none;
+}
+
+.navpath li {
+  background-image: none;
+}
+
+.navpath li.navelem a:hover {
+  color: var(--blue)
+}
+
+.navpath li.footer {
+  background-image:none;
+}
+
diff --git a/src/third_party/skia/tools/doxygen/footer.html b/src/third_party/skia/tools/doxygen/footer.html
new file mode 100644
index 0000000..4997206
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/footer.html
@@ -0,0 +1,24 @@
+<!-- HTML footer for doxygen 1.8.13-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby
+    <a href="http://www.doxygen.org/index.html">
+    Doxygen</a> $doxygenversion on $date</li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+  Doxygen
+</a> $doxygenversion on $date
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+
+<script>window.markdeepOptions = {mode: 'doxygen'};</script>
+<script src="https://casual-effects.com/markdeep/latest/markdeep.min.js"></script><script src="markdeep.min.js"></script>
+</body>
+</html>
diff --git a/src/third_party/skia/tools/doxygen/logo.png b/src/third_party/skia/tools/doxygen/logo.png
new file mode 100644
index 0000000..b250f7d
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/logo.png
Binary files differ
diff --git a/src/third_party/skia/tools/doxygen/mainpage/mainpage.dox b/src/third_party/skia/tools/doxygen/mainpage/mainpage.dox
new file mode 100644
index 0000000..4748d8c
--- /dev/null
+++ b/src/third_party/skia/tools/doxygen/mainpage/mainpage.dox
@@ -0,0 +1,24 @@
+/** \mainpage
+
+Skia is an open source 2D graphics library which provides common APIs that work
+across a variety of hardware and software platforms.  It serves as the graphics
+engine for Google Chrome and Chrome OS, Android, Mozilla Firefox and Firefox
+OS, and many other products.
+
+Skia is sponsored and managed by Google, but is available for use by anyone
+under the BSD Free Software License.  While engineering of the core components
+is done by the Skia development team, we consider contributions from any
+source.
+
+The site you are at is the API documentation for the Skia library. Other
+resources are:
+
+  - Canonical source tree:
+    [skia.googlesource.com/skia](https://skia.googlesource.com/skia).
+  - Issue tracker:
+    [bug.skia.org](https://bug.skia.org/).
+  - Discussion forum:
+    [skia-discuss@googlegroups.com](https://groups.google.com/forum/#!forum/skia-discuss).
+  - Skia Fiddle: [fiddle.skia.org](https://fiddle.skia.org/c/@skcanvas_paint).
+
+*/
diff --git a/src/third_party/skia/tools/dump_record.cpp b/src/third_party/skia/tools/dump_record.cpp
index 24017bd..abfb12f 100644
--- a/src/third_party/skia/tools/dump_record.cpp
+++ b/src/third_party/skia/tools/dump_record.cpp
@@ -5,26 +5,26 @@
  * found in the LICENSE file.
  */
 
-#include "DumpRecord.h"
-#include "SkBitmap.h"
-#include "SkCommandLineFlags.h"
-#include "SkDeferredCanvas.h"
-#include "SkPicture.h"
-#include "SkPictureRecorder.h"
-#include "SkRecordDraw.h"
-#include "SkRecordOpts.h"
-#include "SkRecorder.h"
-#include "SkStream.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkPictureRecorder.h"
+#include "include/core/SkStream.h"
+#include "src/core/SkRecordDraw.h"
+#include "src/core/SkRecordOpts.h"
+#include "src/core/SkRecorder.h"
+#include "tools/DumpRecord.h"
+#include "tools/flags/CommandLineFlags.h"
+
 #include <stdio.h>
 
-DEFINE_string2(skps, r, "", ".SKPs to dump.");
-DEFINE_string(match, "", "The usual filters on file names to dump.");
-DEFINE_bool2(optimize, O, false, "Run SkRecordOptimize before dumping.");
-DEFINE_bool(optimize2, false, "Run SkRecordOptimize2 before dumping.");
-DEFINE_int32(tile, 1000000000, "Simulated tile size.");
-DEFINE_bool(timeWithCommand, false, "If true, print time next to command, else in first column.");
-DEFINE_string2(write, w, "", "Write the (optimized) picture to the named file.");
-DEFINE_bool(defer, false, "Defer clips and translates");
+static DEFINE_string2(skps, r, "", ".SKPs to dump.");
+static DEFINE_string(match, "", "The usual filters on file names to dump.");
+static DEFINE_bool2(optimize, O, false, "Run SkRecordOptimize before dumping.");
+static DEFINE_bool(optimize2, false, "Run SkRecordOptimize2 before dumping.");
+static DEFINE_int(tile, 1000000000, "Simulated tile size.");
+static DEFINE_bool(timeWithCommand, false,
+                   "If true, print time next to command, else in first column.");
+static DEFINE_string2(write, w, "", "Write the (optimized) picture to the named file.");
 
 static void dump(const char* name, int w, int h, const SkRecord& record) {
     SkBitmap bitmap;
@@ -39,10 +39,10 @@
 }
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::Parse(argc, argv);
 
     for (int i = 0; i < FLAGS_skps.count(); i++) {
-        if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
+        if (CommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
             continue;
         }
 
@@ -56,13 +56,6 @@
             SkDebugf("Could not read %s as an SkPicture.\n", FLAGS_skps[i]);
             return 1;
         }
-        if (FLAGS_defer) {
-            SkPictureRecorder recorder;
-            SkDeferredCanvas deferred(recorder.beginRecording(src->cullRect()),
-                                      SkDeferredCanvas::kEager);
-            src->playback(&deferred);
-            src = recorder.finishRecordingAsPicture();
-        }
         const int w = SkScalarCeilToInt(src->cullRect().width());
         const int h = SkScalarCeilToInt(src->cullRect().height());
 
diff --git a/src/third_party/skia/tools/embed_resources.py b/src/third_party/skia/tools/embed_resources.py
index 56d5982..675a9fe 100644
--- a/src/third_party/skia/tools/embed_resources.py
+++ b/src/third_party/skia/tools/embed_resources.py
@@ -39,12 +39,13 @@
   args = parser.parse_args()
 
   out = args.output.write;
-  out('#include "SkTypes.h"\n')
+  out('#include <stddef.h>\n')
+  out('#include <stdint.h>\n')
 
   # Write the resources.
   index = 0
   for f in args.input:
-    out('static const uint8_t resource{0:d}[] SK_STRUCT_ALIGN({1:d}) = {{\n'
+    out('alignas({1:d}) static const uint8_t resource{0:d}[] = {{\n'
         .format(index, args.align))
     bytes_written = 0
     bytes_on_line = 0
diff --git a/src/third_party/skia/tools/fiddle/all_examples.cpp b/src/third_party/skia/tools/fiddle/all_examples.cpp
new file mode 100644
index 0000000..c3148d3
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/all_examples.cpp
@@ -0,0 +1,1074 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#include "../../docs/examples/Alpha_Constants_a.cpp"
+#include "../../docs/examples/Alpha_Constants_b.cpp"
+#include "../../docs/examples/Alpha_Type_Opaque.cpp"
+#include "../../docs/examples/Alpha_Type_Premul.cpp"
+#include "../../docs/examples/Alpha_Type_Unpremul.cpp"
+#include "../../docs/examples/Anti_Alias.cpp"
+#include "../../docs/examples/Arc.cpp"
+#include "../../docs/examples/AutoCanvasRestore_SkCanvas_star.cpp"
+#include "../../docs/examples/AutoCanvasRestore_restore.cpp"
+#include "../../docs/examples/Bitmap_012.cpp"
+#include "../../docs/examples/Bitmap_ComputeIsOpaque.cpp"
+#include "../../docs/examples/Bitmap_HeapAllocator_allocPixelRef.cpp"
+#include "../../docs/examples/Bitmap_allocN32Pixels.cpp"
+#include "../../docs/examples/Bitmap_allocPixels.cpp"
+#include "../../docs/examples/Bitmap_allocPixelsFlags.cpp"
+#include "../../docs/examples/Bitmap_allocPixels_2.cpp"
+#include "../../docs/examples/Bitmap_allocPixels_3.cpp"
+#include "../../docs/examples/Bitmap_allocPixels_4.cpp"
+#include "../../docs/examples/Bitmap_bounds.cpp"
+#include "../../docs/examples/Bitmap_bytesPerPixel.cpp"
+#include "../../docs/examples/Bitmap_colorSpace.cpp"
+#include "../../docs/examples/Bitmap_colorType.cpp"
+#include "../../docs/examples/Bitmap_computeByteSize.cpp"
+#include "../../docs/examples/Bitmap_copy_const_SkBitmap.cpp"
+#include "../../docs/examples/Bitmap_copy_operator.cpp"
+#include "../../docs/examples/Bitmap_dimensions.cpp"
+#include "../../docs/examples/Bitmap_drawsNothing.cpp"
+#include "../../docs/examples/Bitmap_empty.cpp"
+#include "../../docs/examples/Bitmap_empty_constructor.cpp"
+#include "../../docs/examples/Bitmap_erase.cpp"
+#include "../../docs/examples/Bitmap_eraseARGB.cpp"
+#include "../../docs/examples/Bitmap_eraseColor.cpp"
+#include "../../docs/examples/Bitmap_extractAlpha.cpp"
+#include "../../docs/examples/Bitmap_extractAlpha_2.cpp"
+#include "../../docs/examples/Bitmap_extractAlpha_3.cpp"
+#include "../../docs/examples/Bitmap_extractSubset.cpp"
+#include "../../docs/examples/Bitmap_getAddr.cpp"
+#include "../../docs/examples/Bitmap_getAddr16.cpp"
+#include "../../docs/examples/Bitmap_getAddr32.cpp"
+#include "../../docs/examples/Bitmap_getAddr8.cpp"
+#include "../../docs/examples/Bitmap_getBounds.cpp"
+#include "../../docs/examples/Bitmap_getBounds_2.cpp"
+#include "../../docs/examples/Bitmap_getColor.cpp"
+#include "../../docs/examples/Bitmap_getGenerationID.cpp"
+#include "../../docs/examples/Bitmap_getPixels.cpp"
+#include "../../docs/examples/Bitmap_getSubset.cpp"
+#include "../../docs/examples/Bitmap_height.cpp"
+#include "../../docs/examples/Bitmap_info.cpp"
+#include "../../docs/examples/Bitmap_installPixels.cpp"
+#include "../../docs/examples/Bitmap_installPixels_2.cpp"
+#include "../../docs/examples/Bitmap_installPixels_3.cpp"
+#include "../../docs/examples/Bitmap_isImmutable.cpp"
+#include "../../docs/examples/Bitmap_isNull.cpp"
+#include "../../docs/examples/Bitmap_isOpaque.cpp"
+#include "../../docs/examples/Bitmap_isVolatile.cpp"
+#include "../../docs/examples/Bitmap_move_SkBitmap.cpp"
+#include "../../docs/examples/Bitmap_move_operator.cpp"
+#include "../../docs/examples/Bitmap_notifyPixelsChanged.cpp"
+#include "../../docs/examples/Bitmap_peekPixels.cpp"
+#include "../../docs/examples/Bitmap_pixelRef.cpp"
+#include "../../docs/examples/Bitmap_pixelRefOrigin.cpp"
+#include "../../docs/examples/Bitmap_pixmap.cpp"
+#include "../../docs/examples/Bitmap_readPixels.cpp"
+#include "../../docs/examples/Bitmap_readPixels_2.cpp"
+#include "../../docs/examples/Bitmap_readPixels_3.cpp"
+#include "../../docs/examples/Bitmap_readyToDraw.cpp"
+#include "../../docs/examples/Bitmap_refColorSpace.cpp"
+#include "../../docs/examples/Bitmap_reset.cpp"
+#include "../../docs/examples/Bitmap_rowBytes.cpp"
+#include "../../docs/examples/Bitmap_rowBytesAsPixels.cpp"
+#include "../../docs/examples/Bitmap_setAlphaType.cpp"
+#include "../../docs/examples/Bitmap_setImmutable.cpp"
+#include "../../docs/examples/Bitmap_setInfo.cpp"
+#include "../../docs/examples/Bitmap_setIsVolatile.cpp"
+#include "../../docs/examples/Bitmap_setPixelRef.cpp"
+#include "../../docs/examples/Bitmap_setPixels.cpp"
+#include "../../docs/examples/Bitmap_shiftPerPixel.cpp"
+#include "../../docs/examples/Bitmap_swap.cpp"
+#include "../../docs/examples/Bitmap_tryAllocN32Pixels.cpp"
+#include "../../docs/examples/Bitmap_tryAllocPixels.cpp"
+#include "../../docs/examples/Bitmap_tryAllocPixelsFlags.cpp"
+#include "../../docs/examples/Bitmap_tryAllocPixels_2.cpp"
+#include "../../docs/examples/Bitmap_tryAllocPixels_3.cpp"
+#include "../../docs/examples/Bitmap_tryAllocPixels_4.cpp"
+#include "../../docs/examples/Bitmap_width.cpp"
+#include "../../docs/examples/Bitmap_writePixels.cpp"
+#include "../../docs/examples/Bitmap_writePixels_2.cpp"
+#include "../../docs/examples/BlendMode_Name.cpp"
+#include "../../docs/examples/Blend_Mode_Methods.cpp"
+#include "../../docs/examples/Canvas_129.cpp"
+#include "../../docs/examples/Canvas_MakeRasterDirect.cpp"
+#include "../../docs/examples/Canvas_MakeRasterDirectN32.cpp"
+#include "../../docs/examples/Canvas_PointMode.cpp"
+#include "../../docs/examples/Canvas_SaveLayerRec.cpp"
+#include "../../docs/examples/Canvas_SaveLayerRec_SaveLayerRec.cpp"
+#include "../../docs/examples/Canvas_SaveLayerRec_const_SkRect_star_const_SkPaint_star.cpp"
+#include "../../docs/examples/Canvas_SaveLayerRec_const_SkRect_star_const_SkPaint_star_const_SkImageFilter_star.cpp"
+#include "../../docs/examples/Canvas_SrcRectConstraint.cpp"
+#include "../../docs/examples/Canvas_accessTopLayerPixels_a.cpp"
+#include "../../docs/examples/Canvas_accessTopLayerPixels_b.cpp"
+#include "../../docs/examples/Canvas_accessTopRasterHandle.cpp"
+#include "../../docs/examples/Canvas_clear.cpp"
+#include "../../docs/examples/Canvas_clipPath.cpp"
+#include "../../docs/examples/Canvas_clipPath_2.cpp"
+#include "../../docs/examples/Canvas_clipPath_3.cpp"
+#include "../../docs/examples/Canvas_clipRRect.cpp"
+#include "../../docs/examples/Canvas_clipRRect_2.cpp"
+#include "../../docs/examples/Canvas_clipRRect_3.cpp"
+#include "../../docs/examples/Canvas_clipRect.cpp"
+#include "../../docs/examples/Canvas_clipRect_2.cpp"
+#include "../../docs/examples/Canvas_clipRect_3.cpp"
+#include "../../docs/examples/Canvas_clipRegion.cpp"
+#include "../../docs/examples/Canvas_concat.cpp"
+#include "../../docs/examples/Canvas_const_SkBitmap_const_SkSurfaceProps.cpp"
+#include "../../docs/examples/Canvas_copy_const_SkBitmap.cpp"
+#include "../../docs/examples/Canvas_destructor.cpp"
+#include "../../docs/examples/Canvas_drawAnnotation_2.cpp"
+#include "../../docs/examples/Canvas_drawArc_a.cpp"
+#include "../../docs/examples/Canvas_drawArc_b.cpp"
+#include "../../docs/examples/Canvas_drawAtlas.cpp"
+#include "../../docs/examples/Canvas_drawAtlas_2.cpp"
+#include "../../docs/examples/Canvas_drawAtlas_3.cpp"
+#include "../../docs/examples/Canvas_drawAtlas_4.cpp"
+#include "../../docs/examples/Canvas_drawBitmap.cpp"
+#include "../../docs/examples/Canvas_drawBitmapLattice.cpp"
+#include "../../docs/examples/Canvas_drawBitmapNine.cpp"
+#include "../../docs/examples/Canvas_drawBitmapRect.cpp"
+#include "../../docs/examples/Canvas_drawBitmapRect_2.cpp"
+#include "../../docs/examples/Canvas_drawBitmapRect_3.cpp"
+#include "../../docs/examples/Canvas_drawCircle.cpp"
+#include "../../docs/examples/Canvas_drawCircle_2.cpp"
+#include "../../docs/examples/Canvas_drawColor.cpp"
+#include "../../docs/examples/Canvas_drawDRRect_a.cpp"
+#include "../../docs/examples/Canvas_drawDRRect_b.cpp"
+#include "../../docs/examples/Canvas_drawDrawable.cpp"
+#include "../../docs/examples/Canvas_drawDrawable_2.cpp"
+#include "../../docs/examples/Canvas_drawIRect.cpp"
+#include "../../docs/examples/Canvas_drawImage.cpp"
+#include "../../docs/examples/Canvas_drawImageNine.cpp"
+#include "../../docs/examples/Canvas_drawImageNine_2.cpp"
+#include "../../docs/examples/Canvas_drawImageRect.cpp"
+#include "../../docs/examples/Canvas_drawImageRect_2.cpp"
+#include "../../docs/examples/Canvas_drawImageRect_3.cpp"
+#include "../../docs/examples/Canvas_drawImageRect_4.cpp"
+#include "../../docs/examples/Canvas_drawImageRect_5.cpp"
+#include "../../docs/examples/Canvas_drawImageRect_6.cpp"
+#include "../../docs/examples/Canvas_drawImage_2.cpp"
+#include "../../docs/examples/Canvas_drawLine.cpp"
+#include "../../docs/examples/Canvas_drawLine_2.cpp"
+#include "../../docs/examples/Canvas_drawOval.cpp"
+#include "../../docs/examples/Canvas_drawPaint.cpp"
+#include "../../docs/examples/Canvas_drawPatch.cpp"
+#include "../../docs/examples/Canvas_drawPatch_2_a.cpp"
+#include "../../docs/examples/Canvas_drawPatch_2_b.cpp"
+#include "../../docs/examples/Canvas_drawPath.cpp"
+#include "../../docs/examples/Canvas_drawPicture_2.cpp"
+#include "../../docs/examples/Canvas_drawPicture_3.cpp"
+#include "../../docs/examples/Canvas_drawPicture_4.cpp"
+#include "../../docs/examples/Canvas_drawPoint.cpp"
+#include "../../docs/examples/Canvas_drawPoint_2.cpp"
+#include "../../docs/examples/Canvas_drawPoints.cpp"
+#include "../../docs/examples/Canvas_drawPosText.cpp"
+#include "../../docs/examples/Canvas_drawPosTextH.cpp"
+#include "../../docs/examples/Canvas_drawRRect.cpp"
+#include "../../docs/examples/Canvas_drawRect.cpp"
+#include "../../docs/examples/Canvas_drawRegion.cpp"
+#include "../../docs/examples/Canvas_drawRoundRect.cpp"
+#include "../../docs/examples/Canvas_drawString.cpp"
+#include "../../docs/examples/Canvas_drawString_2.cpp"
+#include "../../docs/examples/Canvas_drawText.cpp"
+#include "../../docs/examples/Canvas_drawTextBlob.cpp"
+#include "../../docs/examples/Canvas_drawTextBlob_2.cpp"
+#include "../../docs/examples/Canvas_drawTextRSXform.cpp"
+#include "../../docs/examples/Canvas_drawVertices.cpp"
+#include "../../docs/examples/Canvas_drawVertices_2.cpp"
+#include "../../docs/examples/Canvas_empty_constructor.cpp"
+#include "../../docs/examples/Canvas_getBaseLayerSize.cpp"
+#include "../../docs/examples/Canvas_getDeviceClipBounds.cpp"
+#include "../../docs/examples/Canvas_getDeviceClipBounds_2.cpp"
+#include "../../docs/examples/Canvas_getGrContext.cpp"
+#include "../../docs/examples/Canvas_getLocalClipBounds.cpp"
+#include "../../docs/examples/Canvas_getLocalClipBounds_2.cpp"
+#include "../../docs/examples/Canvas_getProps.cpp"
+#include "../../docs/examples/Canvas_getSaveCount.cpp"
+#include "../../docs/examples/Canvas_getTotalMatrix.cpp"
+#include "../../docs/examples/Canvas_imageInfo.cpp"
+#include "../../docs/examples/Canvas_int_int_const_SkSurfaceProps_star.cpp"
+#include "../../docs/examples/Canvas_isClipEmpty.cpp"
+#include "../../docs/examples/Canvas_isClipRect.cpp"
+#include "../../docs/examples/Canvas_kInitWithPrevious_SaveLayerFlag.cpp"
+#include "../../docs/examples/Canvas_makeSurface.cpp"
+#include "../../docs/examples/Canvas_peekPixels.cpp"
+#include "../../docs/examples/Canvas_quickReject.cpp"
+#include "../../docs/examples/Canvas_quickReject_2.cpp"
+#include "../../docs/examples/Canvas_readPixels_2.cpp"
+#include "../../docs/examples/Canvas_readPixels_3.cpp"
+#include "../../docs/examples/Canvas_readPixels_a.cpp"
+#include "../../docs/examples/Canvas_readPixels_b.cpp"
+#include "../../docs/examples/Canvas_resetMatrix.cpp"
+#include "../../docs/examples/Canvas_restore.cpp"
+#include "../../docs/examples/Canvas_restoreToCount.cpp"
+#include "../../docs/examples/Canvas_rotate.cpp"
+#include "../../docs/examples/Canvas_rotate_2.cpp"
+#include "../../docs/examples/Canvas_save.cpp"
+#include "../../docs/examples/Canvas_saveLayer.cpp"
+#include "../../docs/examples/Canvas_saveLayerAlpha.cpp"
+#include "../../docs/examples/Canvas_saveLayerPreserveLCDTextRequests.cpp"
+#include "../../docs/examples/Canvas_saveLayer_2.cpp"
+#include "../../docs/examples/Canvas_saveLayer_3.cpp"
+#include "../../docs/examples/Canvas_scale.cpp"
+#include "../../docs/examples/Canvas_setMatrix.cpp"
+#include "../../docs/examples/Canvas_skew.cpp"
+#include "../../docs/examples/Canvas_translate.cpp"
+#include "../../docs/examples/Canvas_writePixels.cpp"
+#include "../../docs/examples/Canvas_writePixels_2.cpp"
+#include "../../docs/examples/Clear.cpp"
+#include "../../docs/examples/Clip.cpp"
+#include "../../docs/examples/Color.cpp"
+#include "../../docs/examples/ColorGetA.cpp"
+#include "../../docs/examples/ColorGetB.cpp"
+#include "../../docs/examples/ColorGetG.cpp"
+#include "../../docs/examples/ColorGetR.cpp"
+#include "../../docs/examples/ColorSetA.cpp"
+#include "../../docs/examples/ColorSetARGB.cpp"
+#include "../../docs/examples/ColorSetRGB.cpp"
+#include "../../docs/examples/ColorToHSV.cpp"
+#include "../../docs/examples/ColorTypeBytesPerPixel.cpp"
+#include "../../docs/examples/ColorTypeIsAlwaysOpaque.cpp"
+#include "../../docs/examples/ColorTypeValidateAlphaType.cpp"
+#include "../../docs/examples/Color_Burn.cpp"
+#include "../../docs/examples/Color_Constants_a.cpp"
+#include "../../docs/examples/Color_Constants_b.cpp"
+#include "../../docs/examples/Color_Constants_c.cpp"
+#include "../../docs/examples/Color_Constants_d.cpp"
+#include "../../docs/examples/Color_Dodge.cpp"
+#include "../../docs/examples/Color_Filter_Methods.cpp"
+#include "../../docs/examples/Color_Methods.cpp"
+#include "../../docs/examples/Color_Type_ARGB_4444.cpp"
+#include "../../docs/examples/Color_Type_Alpha_8.cpp"
+#include "../../docs/examples/Color_Type_BGRA_8888.cpp"
+#include "../../docs/examples/Color_Type_Gray_8.cpp"
+#include "../../docs/examples/Color_Type_RGBA_1010102.cpp"
+#include "../../docs/examples/Color_Type_RGBA_8888.cpp"
+#include "../../docs/examples/Color_Type_RGBA_F16.cpp"
+#include "../../docs/examples/Color_Type_RGB_101010.cpp"
+#include "../../docs/examples/Color_Type_RGB_565.cpp"
+#include "../../docs/examples/Color_Type_RGB_888.cpp"
+#include "../../docs/examples/Colors.cpp"
+#include "../../docs/examples/Conic_Weight_a.cpp"
+#include "../../docs/examples/Conic_Weight_b.cpp"
+#include "../../docs/examples/Conic_Weight_c.cpp"
+#include "../../docs/examples/Cubic.cpp"
+#include "../../docs/examples/Darken.cpp"
+#include "../../docs/examples/Device_Text.cpp"
+#include "../../docs/examples/Difference.cpp"
+#include "../../docs/examples/Dither_a.cpp"
+#include "../../docs/examples/Dither_b.cpp"
+#include "../../docs/examples/Draw_Looper_Methods.cpp"
+#include "../../docs/examples/Dst.cpp"
+#include "../../docs/examples/Dst_Atop.cpp"
+#include "../../docs/examples/Dst_In.cpp"
+#include "../../docs/examples/Dst_Out.cpp"
+#include "../../docs/examples/Dst_Over.cpp"
+#include "../../docs/examples/Exclusion.cpp"
+#include "../../docs/examples/Fake_Bold.cpp"
+#include "../../docs/examples/Filter_Quality_Methods.cpp"
+#include "../../docs/examples/Font_breakText.cpp"
+#include "../../docs/examples/HSVToColor.cpp"
+#include "../../docs/examples/HSVToColor_2.cpp"
+#include "../../docs/examples/Hard_Light.cpp"
+#include "../../docs/examples/Hue.cpp"
+#include "../../docs/examples/IPoint_Make.cpp"
+#include "../../docs/examples/IPoint_add_operator.cpp"
+#include "../../docs/examples/IPoint_addto_operator.cpp"
+#include "../../docs/examples/IPoint_equal_operator.cpp"
+#include "../../docs/examples/IPoint_equals.cpp"
+#include "../../docs/examples/IPoint_isZero.cpp"
+#include "../../docs/examples/IPoint_minus_operator.cpp"
+#include "../../docs/examples/IPoint_notequal_operator.cpp"
+#include "../../docs/examples/IPoint_set.cpp"
+#include "../../docs/examples/IPoint_subtract_operator.cpp"
+#include "../../docs/examples/IPoint_subtractfrom_operator.cpp"
+#include "../../docs/examples/IPoint_x.cpp"
+#include "../../docs/examples/IPoint_y.cpp"
+#include "../../docs/examples/IRect_EmptyIRect.cpp"
+#include "../../docs/examples/IRect_Intersects.cpp"
+#include "../../docs/examples/IRect_MakeEmpty.cpp"
+#include "../../docs/examples/IRect_MakeLTRB.cpp"
+#include "../../docs/examples/IRect_MakeSize.cpp"
+#include "../../docs/examples/IRect_MakeWH.cpp"
+#include "../../docs/examples/IRect_MakeXYWH.cpp"
+#include "../../docs/examples/IRect_adjust.cpp"
+#include "../../docs/examples/IRect_bottom.cpp"
+#include "../../docs/examples/IRect_contains.cpp"
+#include "../../docs/examples/IRect_containsNoEmptyCheck.cpp"
+#include "../../docs/examples/IRect_containsNoEmptyCheck_2.cpp"
+#include "../../docs/examples/IRect_contains_3.cpp"
+#include "../../docs/examples/IRect_contains_4.cpp"
+#include "../../docs/examples/IRect_equal_operator.cpp"
+#include "../../docs/examples/IRect_height.cpp"
+#include "../../docs/examples/IRect_height64.cpp"
+#include "../../docs/examples/IRect_inset.cpp"
+#include "../../docs/examples/IRect_intersect.cpp"
+#include "../../docs/examples/IRect_intersect_2.cpp"
+#include "../../docs/examples/IRect_isEmpty.cpp"
+#include "../../docs/examples/IRect_isEmpty64.cpp"
+#include "../../docs/examples/IRect_join_2.cpp"
+#include "../../docs/examples/IRect_left.cpp"
+#include "../../docs/examples/IRect_makeInset.cpp"
+#include "../../docs/examples/IRect_makeOffset.cpp"
+#include "../../docs/examples/IRect_makeOutset.cpp"
+#include "../../docs/examples/IRect_makeSorted.cpp"
+#include "../../docs/examples/IRect_notequal_operator.cpp"
+#include "../../docs/examples/IRect_offset.cpp"
+#include "../../docs/examples/IRect_offsetTo.cpp"
+#include "../../docs/examples/IRect_offset_2.cpp"
+#include "../../docs/examples/IRect_outset.cpp"
+#include "../../docs/examples/IRect_right.cpp"
+#include "../../docs/examples/IRect_setEmpty.cpp"
+#include "../../docs/examples/IRect_setLTRB.cpp"
+#include "../../docs/examples/IRect_setXYWH.cpp"
+#include "../../docs/examples/IRect_size.cpp"
+#include "../../docs/examples/IRect_sort.cpp"
+#include "../../docs/examples/IRect_top.cpp"
+#include "../../docs/examples/IRect_width.cpp"
+#include "../../docs/examples/IRect_width64.cpp"
+#include "../../docs/examples/IRect_x.cpp"
+#include "../../docs/examples/IRect_y.cpp"
+#include "../../docs/examples/ImageInfo_ByteSizeOverflowed.cpp"
+#include "../../docs/examples/ImageInfo_Make.cpp"
+#include "../../docs/examples/ImageInfo_MakeA8.cpp"
+#include "../../docs/examples/ImageInfo_MakeN32.cpp"
+#include "../../docs/examples/ImageInfo_MakeN32Premul.cpp"
+#include "../../docs/examples/ImageInfo_MakeN32Premul_2.cpp"
+#include "../../docs/examples/ImageInfo_MakeS32.cpp"
+#include "../../docs/examples/ImageInfo_MakeUnknown.cpp"
+#include "../../docs/examples/ImageInfo_MakeUnknown_2.cpp"
+#include "../../docs/examples/ImageInfo_alphaType.cpp"
+#include "../../docs/examples/ImageInfo_bounds.cpp"
+#include "../../docs/examples/ImageInfo_bytesPerPixel.cpp"
+#include "../../docs/examples/ImageInfo_colorSpace.cpp"
+#include "../../docs/examples/ImageInfo_colorType.cpp"
+#include "../../docs/examples/ImageInfo_computeByteSize.cpp"
+#include "../../docs/examples/ImageInfo_computeMinByteSize.cpp"
+#include "../../docs/examples/ImageInfo_computeOffset.cpp"
+#include "../../docs/examples/ImageInfo_dimensions.cpp"
+#include "../../docs/examples/ImageInfo_empty_constructor.cpp"
+#include "../../docs/examples/ImageInfo_equal1_operator.cpp"
+#include "../../docs/examples/ImageInfo_gammaCloseToSRGB.cpp"
+#include "../../docs/examples/ImageInfo_height.cpp"
+#include "../../docs/examples/ImageInfo_isEmpty.cpp"
+#include "../../docs/examples/ImageInfo_isOpaque.cpp"
+#include "../../docs/examples/ImageInfo_makeAlphaType.cpp"
+#include "../../docs/examples/ImageInfo_makeColorSpace.cpp"
+#include "../../docs/examples/ImageInfo_makeColorType.cpp"
+#include "../../docs/examples/ImageInfo_makeWH.cpp"
+#include "../../docs/examples/ImageInfo_minRowBytes.cpp"
+#include "../../docs/examples/ImageInfo_minRowBytes64.cpp"
+#include "../../docs/examples/ImageInfo_notequal1_operator.cpp"
+#include "../../docs/examples/ImageInfo_refColorSpace.cpp"
+#include "../../docs/examples/ImageInfo_reset.cpp"
+#include "../../docs/examples/ImageInfo_shiftPerPixel.cpp"
+#include "../../docs/examples/ImageInfo_validRowBytes.cpp"
+#include "../../docs/examples/ImageInfo_width.cpp"
+#include "../../docs/examples/Image_Filter_Methods.cpp"
+#include "../../docs/examples/Image_MakeBackendTextureFromSkImage.cpp"
+#include "../../docs/examples/Image_MakeCrossContextFromPixmap.cpp"
+#include "../../docs/examples/Image_MakeFromAdoptedTexture.cpp"
+#include "../../docs/examples/Image_MakeFromBitmap.cpp"
+#include "../../docs/examples/Image_MakeFromEncoded.cpp"
+#include "../../docs/examples/Image_MakeFromGenerator.cpp"
+#include "../../docs/examples/Image_MakeFromPicture.cpp"
+#include "../../docs/examples/Image_MakeFromRaster.cpp"
+#include "../../docs/examples/Image_MakeFromTexture.cpp"
+#include "../../docs/examples/Image_MakeFromTexture_2.cpp"
+#include "../../docs/examples/Image_MakeRasterCopy.cpp"
+#include "../../docs/examples/Image_MakeRasterData.cpp"
+#include "../../docs/examples/Image_alphaType.cpp"
+#include "../../docs/examples/Image_bounds.cpp"
+#include "../../docs/examples/Image_colorSpace.cpp"
+#include "../../docs/examples/Image_colorType.cpp"
+#include "../../docs/examples/Image_dimensions.cpp"
+#include "../../docs/examples/Image_encodeToData.cpp"
+#include "../../docs/examples/Image_encodeToData_2.cpp"
+#include "../../docs/examples/Image_getBackendTexture.cpp"
+#include "../../docs/examples/Image_height.cpp"
+#include "../../docs/examples/Image_isAlphaOnly.cpp"
+#include "../../docs/examples/Image_isLazyGenerated_a.cpp"
+#include "../../docs/examples/Image_isLazyGenerated_b.cpp"
+#include "../../docs/examples/Image_isOpaque.cpp"
+#include "../../docs/examples/Image_isTextureBacked.cpp"
+#include "../../docs/examples/Image_isValid.cpp"
+#include "../../docs/examples/Image_makeColorSpace.cpp"
+#include "../../docs/examples/Image_makeNonTextureImage.cpp"
+#include "../../docs/examples/Image_makeRasterImage.cpp"
+#include "../../docs/examples/Image_makeShader.cpp"
+#include "../../docs/examples/Image_makeShader_2.cpp"
+#include "../../docs/examples/Image_makeSubset.cpp"
+#include "../../docs/examples/Image_makeTextureImage.cpp"
+#include "../../docs/examples/Image_makeWithFilter.cpp"
+#include "../../docs/examples/Image_peekPixels.cpp"
+#include "../../docs/examples/Image_readPixels.cpp"
+#include "../../docs/examples/Image_readPixels_2.cpp"
+#include "../../docs/examples/Image_refColorSpace.cpp"
+#include "../../docs/examples/Image_refEncodedData.cpp"
+#include "../../docs/examples/Image_scalePixels.cpp"
+#include "../../docs/examples/Image_uniqueID.cpp"
+#include "../../docs/examples/Image_width.cpp"
+#include "../../docs/examples/Lighten.cpp"
+#include "../../docs/examples/Luminosity.cpp"
+#include "../../docs/examples/Mask_Filter_Methods.cpp"
+#include "../../docs/examples/Matrix_063.cpp"
+#include "../../docs/examples/Matrix_Concat.cpp"
+#include "../../docs/examples/Matrix_I.cpp"
+#include "../../docs/examples/Matrix_InvalidMatrix.cpp"
+#include "../../docs/examples/Matrix_MakeAll.cpp"
+#include "../../docs/examples/Matrix_MakeRectToRect.cpp"
+#include "../../docs/examples/Matrix_MakeScale.cpp"
+#include "../../docs/examples/Matrix_MakeScale_2.cpp"
+#include "../../docs/examples/Matrix_MakeTrans.cpp"
+#include "../../docs/examples/Matrix_ScaleToFit.cpp"
+#include "../../docs/examples/Matrix_SetAffineIdentity.cpp"
+#include "../../docs/examples/Matrix_TypeMask.cpp"
+#include "../../docs/examples/Matrix_array_operator.cpp"
+#include "../../docs/examples/Matrix_asAffine.cpp"
+#include "../../docs/examples/Matrix_cheapEqualTo.cpp"
+#include "../../docs/examples/Matrix_decomposeScale.cpp"
+#include "../../docs/examples/Matrix_dirtyMatrixTypeCache.cpp"
+#include "../../docs/examples/Matrix_dump.cpp"
+#include "../../docs/examples/Matrix_equal_operator.cpp"
+#include "../../docs/examples/Matrix_fixedStepInX.cpp"
+#include "../../docs/examples/Matrix_get.cpp"
+#include "../../docs/examples/Matrix_get9.cpp"
+#include "../../docs/examples/Matrix_getMaxScale.cpp"
+#include "../../docs/examples/Matrix_getMinMaxScales.cpp"
+#include "../../docs/examples/Matrix_getMinScale.cpp"
+#include "../../docs/examples/Matrix_getPerspX.cpp"
+#include "../../docs/examples/Matrix_getPerspY.cpp"
+#include "../../docs/examples/Matrix_getScaleX.cpp"
+#include "../../docs/examples/Matrix_getScaleY.cpp"
+#include "../../docs/examples/Matrix_getSkewX.cpp"
+#include "../../docs/examples/Matrix_getSkewY.cpp"
+#include "../../docs/examples/Matrix_getTranslateX.cpp"
+#include "../../docs/examples/Matrix_getTranslateY.cpp"
+#include "../../docs/examples/Matrix_getType.cpp"
+#include "../../docs/examples/Matrix_hasPerspective.cpp"
+#include "../../docs/examples/Matrix_invert.cpp"
+#include "../../docs/examples/Matrix_isFinite.cpp"
+#include "../../docs/examples/Matrix_isFixedStepInX.cpp"
+#include "../../docs/examples/Matrix_isIdentity.cpp"
+#include "../../docs/examples/Matrix_isScaleTranslate.cpp"
+#include "../../docs/examples/Matrix_isSimilarity.cpp"
+#include "../../docs/examples/Matrix_isTranslate.cpp"
+#include "../../docs/examples/Matrix_mapHomogeneousPoints.cpp"
+#include "../../docs/examples/Matrix_mapPoints.cpp"
+#include "../../docs/examples/Matrix_mapPoints_2.cpp"
+#include "../../docs/examples/Matrix_mapRadius.cpp"
+#include "../../docs/examples/Matrix_mapRect.cpp"
+#include "../../docs/examples/Matrix_mapRectScaleTranslate.cpp"
+#include "../../docs/examples/Matrix_mapRectToQuad.cpp"
+#include "../../docs/examples/Matrix_mapRect_2.cpp"
+#include "../../docs/examples/Matrix_mapRect_3.cpp"
+#include "../../docs/examples/Matrix_mapVector.cpp"
+#include "../../docs/examples/Matrix_mapVector_2.cpp"
+#include "../../docs/examples/Matrix_mapVectors.cpp"
+#include "../../docs/examples/Matrix_mapVectors_2.cpp"
+#include "../../docs/examples/Matrix_mapXY.cpp"
+#include "../../docs/examples/Matrix_mapXY_2.cpp"
+#include "../../docs/examples/Matrix_notequal_operator.cpp"
+#include "../../docs/examples/Matrix_postConcat.cpp"
+#include "../../docs/examples/Matrix_postRotate.cpp"
+#include "../../docs/examples/Matrix_postRotate_2.cpp"
+#include "../../docs/examples/Matrix_postScale.cpp"
+#include "../../docs/examples/Matrix_postScale_2.cpp"
+#include "../../docs/examples/Matrix_postSkew.cpp"
+#include "../../docs/examples/Matrix_postSkew_2.cpp"
+#include "../../docs/examples/Matrix_postTranslate.cpp"
+#include "../../docs/examples/Matrix_preConcat.cpp"
+#include "../../docs/examples/Matrix_preRotate.cpp"
+#include "../../docs/examples/Matrix_preRotate_2.cpp"
+#include "../../docs/examples/Matrix_preScale.cpp"
+#include "../../docs/examples/Matrix_preScale_2.cpp"
+#include "../../docs/examples/Matrix_preSkew.cpp"
+#include "../../docs/examples/Matrix_preSkew_2.cpp"
+#include "../../docs/examples/Matrix_preTranslate.cpp"
+#include "../../docs/examples/Matrix_preservesAxisAlignment.cpp"
+#include "../../docs/examples/Matrix_preservesRightAngles.cpp"
+#include "../../docs/examples/Matrix_rectStaysRect.cpp"
+#include "../../docs/examples/Matrix_reset.cpp"
+#include "../../docs/examples/Matrix_set.cpp"
+#include "../../docs/examples/Matrix_set9.cpp"
+#include "../../docs/examples/Matrix_setAffine.cpp"
+#include "../../docs/examples/Matrix_setAll.cpp"
+#include "../../docs/examples/Matrix_setConcat.cpp"
+#include "../../docs/examples/Matrix_setIdentity.cpp"
+#include "../../docs/examples/Matrix_setPerspX.cpp"
+#include "../../docs/examples/Matrix_setPerspY.cpp"
+#include "../../docs/examples/Matrix_setPolyToPoly.cpp"
+#include "../../docs/examples/Matrix_setRSXform.cpp"
+#include "../../docs/examples/Matrix_setRectToRect.cpp"
+#include "../../docs/examples/Matrix_setRotate.cpp"
+#include "../../docs/examples/Matrix_setRotate_2.cpp"
+#include "../../docs/examples/Matrix_setScale.cpp"
+#include "../../docs/examples/Matrix_setScaleTranslate.cpp"
+#include "../../docs/examples/Matrix_setScaleX.cpp"
+#include "../../docs/examples/Matrix_setScaleY.cpp"
+#include "../../docs/examples/Matrix_setScale_2.cpp"
+#include "../../docs/examples/Matrix_setSinCos.cpp"
+#include "../../docs/examples/Matrix_setSinCos_2.cpp"
+#include "../../docs/examples/Matrix_setSkew.cpp"
+#include "../../docs/examples/Matrix_setSkewX.cpp"
+#include "../../docs/examples/Matrix_setSkewY.cpp"
+#include "../../docs/examples/Matrix_setSkew_2.cpp"
+#include "../../docs/examples/Matrix_setTranslate.cpp"
+#include "../../docs/examples/Matrix_setTranslateX.cpp"
+#include "../../docs/examples/Matrix_setTranslateY.cpp"
+#include "../../docs/examples/Matrix_setTranslate_2.cpp"
+#include "../../docs/examples/MemberIndex.cpp"
+#include "../../docs/examples/Miter_Limit.cpp"
+#include "../../docs/examples/Modulate.cpp"
+#include "../../docs/examples/Multiply.cpp"
+#include "../../docs/examples/Overlay.cpp"
+#include "../../docs/examples/PDF.cpp"
+#include "../../docs/examples/Paint_053.cpp"
+#include "../../docs/examples/Paint_057.cpp"
+#include "../../docs/examples/Paint_containsText.cpp"
+#include "../../docs/examples/Paint_copy_const_SkPaint.cpp"
+#include "../../docs/examples/Paint_copy_operator.cpp"
+#include "../../docs/examples/Paint_countText.cpp"
+#include "../../docs/examples/Paint_empty_constructor.cpp"
+#include "../../docs/examples/Paint_equal_operator.cpp"
+#include "../../docs/examples/Paint_getAlpha.cpp"
+#include "../../docs/examples/Paint_getBlendMode.cpp"
+#include "../../docs/examples/Paint_getColor.cpp"
+#include "../../docs/examples/Paint_getColor4f.cpp"
+#include "../../docs/examples/Paint_getColorFilter.cpp"
+#include "../../docs/examples/Paint_getDrawLooper.cpp"
+#include "../../docs/examples/Paint_getFillPath.cpp"
+#include "../../docs/examples/Paint_getFillPath_2.cpp"
+#include "../../docs/examples/Paint_getFilterQuality.cpp"
+#include "../../docs/examples/Paint_getFlags.cpp"
+#include "../../docs/examples/Paint_getFontMetrics.cpp"
+#include "../../docs/examples/Paint_getFontSpacing.cpp"
+#include "../../docs/examples/Paint_getHash.cpp"
+#include "../../docs/examples/Paint_getHinting.cpp"
+#include "../../docs/examples/Paint_getImageFilter.cpp"
+#include "../../docs/examples/Paint_getMaskFilter.cpp"
+#include "../../docs/examples/Paint_getPathEffect.cpp"
+#include "../../docs/examples/Paint_getPosTextPath.cpp"
+#include "../../docs/examples/Paint_getShader.cpp"
+#include "../../docs/examples/Paint_getStrokeCap.cpp"
+#include "../../docs/examples/Paint_getStrokeJoin.cpp"
+#include "../../docs/examples/Paint_getStrokeMiter.cpp"
+#include "../../docs/examples/Paint_getStrokeWidth.cpp"
+#include "../../docs/examples/Paint_getStyle.cpp"
+#include "../../docs/examples/Paint_getTextEncoding.cpp"
+#include "../../docs/examples/Paint_getTextPath.cpp"
+#include "../../docs/examples/Paint_getTextScaleX.cpp"
+#include "../../docs/examples/Paint_getTextSize.cpp"
+#include "../../docs/examples/Paint_getTextSkewX.cpp"
+#include "../../docs/examples/Paint_getTextWidths.cpp"
+#include "../../docs/examples/Paint_getTypeface.cpp"
+#include "../../docs/examples/Paint_isAntiAlias.cpp"
+#include "../../docs/examples/Paint_isAutohinted.cpp"
+#include "../../docs/examples/Paint_isDither.cpp"
+#include "../../docs/examples/Paint_isEmbeddedBitmapText.cpp"
+#include "../../docs/examples/Paint_isFakeBoldText.cpp"
+#include "../../docs/examples/Paint_isLCDRenderText.cpp"
+#include "../../docs/examples/Paint_isLinearText.cpp"
+#include "../../docs/examples/Paint_isSubpixelText.cpp"
+#include "../../docs/examples/Paint_measureText.cpp"
+#include "../../docs/examples/Paint_measureText_2.cpp"
+#include "../../docs/examples/Paint_move_SkPaint.cpp"
+#include "../../docs/examples/Paint_move_operator.cpp"
+#include "../../docs/examples/Paint_notequal_operator.cpp"
+#include "../../docs/examples/Paint_nothingToDraw.cpp"
+#include "../../docs/examples/Paint_refColorFilter.cpp"
+#include "../../docs/examples/Paint_refDrawLooper.cpp"
+#include "../../docs/examples/Paint_refImageFilter.cpp"
+#include "../../docs/examples/Paint_refMaskFilter.cpp"
+#include "../../docs/examples/Paint_refPathEffect.cpp"
+#include "../../docs/examples/Paint_refShader.cpp"
+#include "../../docs/examples/Paint_refTypeface.cpp"
+#include "../../docs/examples/Paint_reset.cpp"
+#include "../../docs/examples/Paint_setARGB.cpp"
+#include "../../docs/examples/Paint_setAlpha.cpp"
+#include "../../docs/examples/Paint_setAntiAlias.cpp"
+#include "../../docs/examples/Paint_setAutohinted.cpp"
+#include "../../docs/examples/Paint_setBlendMode.cpp"
+#include "../../docs/examples/Paint_setColor.cpp"
+#include "../../docs/examples/Paint_setColor4f.cpp"
+#include "../../docs/examples/Paint_setColorFilter.cpp"
+#include "../../docs/examples/Paint_setDither.cpp"
+#include "../../docs/examples/Paint_setDrawLooper.cpp"
+#include "../../docs/examples/Paint_setEmbeddedBitmapText.cpp"
+#include "../../docs/examples/Paint_setFakeBoldText.cpp"
+#include "../../docs/examples/Paint_setFilterQuality.cpp"
+#include "../../docs/examples/Paint_setFlags.cpp"
+#include "../../docs/examples/Paint_setHinting.cpp"
+#include "../../docs/examples/Paint_setImageFilter.cpp"
+#include "../../docs/examples/Paint_setLCDRenderText.cpp"
+#include "../../docs/examples/Paint_setLinearText.cpp"
+#include "../../docs/examples/Paint_setMaskFilter.cpp"
+#include "../../docs/examples/Paint_setPathEffect.cpp"
+#include "../../docs/examples/Paint_setShader.cpp"
+#include "../../docs/examples/Paint_setStrokeCap_a.cpp"
+#include "../../docs/examples/Paint_setStrokeCap_b.cpp"
+#include "../../docs/examples/Paint_setStrokeJoin.cpp"
+#include "../../docs/examples/Paint_setStrokeMiter.cpp"
+#include "../../docs/examples/Paint_setStrokeWidth.cpp"
+#include "../../docs/examples/Paint_setStyle.cpp"
+#include "../../docs/examples/Paint_setSubpixelText.cpp"
+#include "../../docs/examples/Paint_setTextEncoding.cpp"
+#include "../../docs/examples/Paint_setTextScaleX.cpp"
+#include "../../docs/examples/Paint_setTextSize.cpp"
+#include "../../docs/examples/Paint_setTextSkewX.cpp"
+#include "../../docs/examples/Paint_setTypeface.cpp"
+#include "../../docs/examples/Paint_textToGlyphs.cpp"
+#include "../../docs/examples/Path_AddPathMode.cpp"
+#include "../../docs/examples/Path_ArcSize.cpp"
+#include "../../docs/examples/Path_ConvertConicToQuads.cpp"
+#include "../../docs/examples/Path_ConvertToNonInverseFillType.cpp"
+#include "../../docs/examples/Path_Convexity.cpp"
+#include "../../docs/examples/Path_Direction.cpp"
+#include "../../docs/examples/Path_Effect_Methods.cpp"
+#include "../../docs/examples/Path_FillType_a.cpp"
+#include "../../docs/examples/Path_FillType_b.cpp"
+#include "../../docs/examples/Path_IsCubicDegenerate.cpp"
+#include "../../docs/examples/Path_IsInverseFillType.cpp"
+#include "../../docs/examples/Path_IsLineDegenerate.cpp"
+#include "../../docs/examples/Path_IsQuadDegenerate.cpp"
+#include "../../docs/examples/Path_Iter.cpp"
+#include "../../docs/examples/Path_Iter_Iter.cpp"
+#include "../../docs/examples/Path_Iter_conicWeight.cpp"
+#include "../../docs/examples/Path_Iter_const_SkPath.cpp"
+#include "../../docs/examples/Path_Iter_isCloseLine.cpp"
+#include "../../docs/examples/Path_Iter_isClosedContour.cpp"
+#include "../../docs/examples/Path_Iter_next.cpp"
+#include "../../docs/examples/Path_Iter_setPath.cpp"
+#include "../../docs/examples/Path_RawIter_conicWeight.cpp"
+#include "../../docs/examples/Path_RawIter_next.cpp"
+#include "../../docs/examples/Path_RawIter_peek.cpp"
+#include "../../docs/examples/Path_SegmentMask.cpp"
+#include "../../docs/examples/Path_Verb.cpp"
+#include "../../docs/examples/Path_addArc.cpp"
+#include "../../docs/examples/Path_addCircle.cpp"
+#include "../../docs/examples/Path_addOval.cpp"
+#include "../../docs/examples/Path_addOval_2.cpp"
+#include "../../docs/examples/Path_addPath.cpp"
+#include "../../docs/examples/Path_addPath_2.cpp"
+#include "../../docs/examples/Path_addPath_3.cpp"
+#include "../../docs/examples/Path_addPoly.cpp"
+#include "../../docs/examples/Path_addPoly_2.cpp"
+#include "../../docs/examples/Path_addRRect.cpp"
+#include "../../docs/examples/Path_addRRect_2.cpp"
+#include "../../docs/examples/Path_addRect.cpp"
+#include "../../docs/examples/Path_addRect_2.cpp"
+#include "../../docs/examples/Path_addRect_3.cpp"
+#include "../../docs/examples/Path_addRoundRect.cpp"
+#include "../../docs/examples/Path_addRoundRect_2.cpp"
+#include "../../docs/examples/Path_arcTo.cpp"
+#include "../../docs/examples/Path_arcTo_2_a.cpp"
+#include "../../docs/examples/Path_arcTo_2_b.cpp"
+#include "../../docs/examples/Path_arcTo_2_c.cpp"
+#include "../../docs/examples/Path_arcTo_3.cpp"
+#include "../../docs/examples/Path_arcTo_4.cpp"
+#include "../../docs/examples/Path_close.cpp"
+#include "../../docs/examples/Path_computeTightBounds.cpp"
+#include "../../docs/examples/Path_conicTo.cpp"
+#include "../../docs/examples/Path_conicTo_2.cpp"
+#include "../../docs/examples/Path_conservativelyContainsRect.cpp"
+#include "../../docs/examples/Path_contains.cpp"
+#include "../../docs/examples/Path_copy_const_SkPath.cpp"
+#include "../../docs/examples/Path_copy_operator.cpp"
+#include "../../docs/examples/Path_countPoints.cpp"
+#include "../../docs/examples/Path_countVerbs.cpp"
+#include "../../docs/examples/Path_cubicTo.cpp"
+#include "../../docs/examples/Path_cubicTo_2.cpp"
+#include "../../docs/examples/Path_destructor.cpp"
+#include "../../docs/examples/Path_dump.cpp"
+#include "../../docs/examples/Path_dumpHex.cpp"
+#include "../../docs/examples/Path_dump_2.cpp"
+#include "../../docs/examples/Path_empty_constructor.cpp"
+#include "../../docs/examples/Path_equal_operator.cpp"
+#include "../../docs/examples/Path_getBounds.cpp"
+#include "../../docs/examples/Path_getConvexity.cpp"
+#include "../../docs/examples/Path_getConvexityOrUnknown.cpp"
+#include "../../docs/examples/Path_getFillType.cpp"
+#include "../../docs/examples/Path_getGenerationID.cpp"
+#include "../../docs/examples/Path_getLastPt.cpp"
+#include "../../docs/examples/Path_getPoint.cpp"
+#include "../../docs/examples/Path_getPoints.cpp"
+#include "../../docs/examples/Path_getSegmentMasks.cpp"
+#include "../../docs/examples/Path_getVerbs.cpp"
+#include "../../docs/examples/Path_incReserve.cpp"
+#include "../../docs/examples/Path_interpolate.cpp"
+#include "../../docs/examples/Path_isConvex.cpp"
+#include "../../docs/examples/Path_isEmpty.cpp"
+#include "../../docs/examples/Path_isFinite.cpp"
+#include "../../docs/examples/Path_isInterpolatable.cpp"
+#include "../../docs/examples/Path_isInverseFillType_2.cpp"
+#include "../../docs/examples/Path_isLastContourClosed.cpp"
+#include "../../docs/examples/Path_isLine.cpp"
+#include "../../docs/examples/Path_isOval.cpp"
+#include "../../docs/examples/Path_isRRect.cpp"
+#include "../../docs/examples/Path_isRect.cpp"
+#include "../../docs/examples/Path_isVolatile.cpp"
+#include "../../docs/examples/Path_lineTo.cpp"
+#include "../../docs/examples/Path_lineTo_2.cpp"
+#include "../../docs/examples/Path_moveTo.cpp"
+#include "../../docs/examples/Path_moveTo_2.cpp"
+#include "../../docs/examples/Path_notequal_operator.cpp"
+#include "../../docs/examples/Path_offset.cpp"
+#include "../../docs/examples/Path_offset_2.cpp"
+#include "../../docs/examples/Path_quadTo.cpp"
+#include "../../docs/examples/Path_quadTo_2.cpp"
+#include "../../docs/examples/Path_rArcTo.cpp"
+#include "../../docs/examples/Path_rConicTo.cpp"
+#include "../../docs/examples/Path_rCubicTo.cpp"
+#include "../../docs/examples/Path_rLineTo.cpp"
+#include "../../docs/examples/Path_rMoveTo.cpp"
+#include "../../docs/examples/Path_rQuadTo.cpp"
+#include "../../docs/examples/Path_readFromMemory.cpp"
+#include "../../docs/examples/Path_reset.cpp"
+#include "../../docs/examples/Path_reverseAddPath.cpp"
+#include "../../docs/examples/Path_rewind.cpp"
+#include "../../docs/examples/Path_serialize.cpp"
+#include "../../docs/examples/Path_setConvexity.cpp"
+#include "../../docs/examples/Path_setFillType.cpp"
+#include "../../docs/examples/Path_setIsVolatile.cpp"
+#include "../../docs/examples/Path_setLastPt.cpp"
+#include "../../docs/examples/Path_setLastPt_2.cpp"
+#include "../../docs/examples/Path_swap.cpp"
+#include "../../docs/examples/Path_toggleInverseFillType.cpp"
+#include "../../docs/examples/Path_transform.cpp"
+#include "../../docs/examples/Path_transform_2.cpp"
+#include "../../docs/examples/Path_updateBoundsCache.cpp"
+#include "../../docs/examples/Path_writeToMemory.cpp"
+#include "../../docs/examples/Picture_008.cpp"
+#include "../../docs/examples/Picture_AbortCallback_abort.cpp"
+#include "../../docs/examples/Picture_MakeFromData.cpp"
+#include "../../docs/examples/Picture_MakeFromStream.cpp"
+#include "../../docs/examples/Picture_MakePlaceholder.cpp"
+#include "../../docs/examples/Picture_approximateBytesUsed.cpp"
+#include "../../docs/examples/Picture_approximateOpCount.cpp"
+#include "../../docs/examples/Picture_cullRect.cpp"
+#include "../../docs/examples/Picture_playback.cpp"
+#include "../../docs/examples/Picture_serialize.cpp"
+#include "../../docs/examples/Picture_serialize_2.cpp"
+#include "../../docs/examples/Picture_uniqueID.cpp"
+#include "../../docs/examples/Pixmap_addr.cpp"
+#include "../../docs/examples/Pixmap_addr16.cpp"
+#include "../../docs/examples/Pixmap_addr16_2.cpp"
+#include "../../docs/examples/Pixmap_addr32.cpp"
+#include "../../docs/examples/Pixmap_addr32_2.cpp"
+#include "../../docs/examples/Pixmap_addr64.cpp"
+#include "../../docs/examples/Pixmap_addr64_2.cpp"
+#include "../../docs/examples/Pixmap_addr8.cpp"
+#include "../../docs/examples/Pixmap_addr8_2.cpp"
+#include "../../docs/examples/Pixmap_addrF16.cpp"
+#include "../../docs/examples/Pixmap_addrF16_2.cpp"
+#include "../../docs/examples/Pixmap_addr_2.cpp"
+#include "../../docs/examples/Pixmap_alphaType.cpp"
+#include "../../docs/examples/Pixmap_bounds.cpp"
+#include "../../docs/examples/Pixmap_colorSpace.cpp"
+#include "../../docs/examples/Pixmap_colorType.cpp"
+#include "../../docs/examples/Pixmap_computeByteSize.cpp"
+#include "../../docs/examples/Pixmap_computeIsOpaque.cpp"
+#include "../../docs/examples/Pixmap_const_SkImageInfo_const_star.cpp"
+#include "../../docs/examples/Pixmap_empty_constructor.cpp"
+#include "../../docs/examples/Pixmap_erase.cpp"
+#include "../../docs/examples/Pixmap_erase_2.cpp"
+#include "../../docs/examples/Pixmap_erase_3.cpp"
+#include "../../docs/examples/Pixmap_extractSubset.cpp"
+#include "../../docs/examples/Pixmap_getColor.cpp"
+#include "../../docs/examples/Pixmap_height.cpp"
+#include "../../docs/examples/Pixmap_info.cpp"
+#include "../../docs/examples/Pixmap_isOpaque.cpp"
+#include "../../docs/examples/Pixmap_readPixels.cpp"
+#include "../../docs/examples/Pixmap_readPixels_2.cpp"
+#include "../../docs/examples/Pixmap_readPixels_3.cpp"
+#include "../../docs/examples/Pixmap_readPixels_4.cpp"
+#include "../../docs/examples/Pixmap_reset.cpp"
+#include "../../docs/examples/Pixmap_reset_2.cpp"
+#include "../../docs/examples/Pixmap_rowBytes.cpp"
+#include "../../docs/examples/Pixmap_rowBytesAsPixels.cpp"
+#include "../../docs/examples/Pixmap_scalePixels.cpp"
+#include "../../docs/examples/Pixmap_setColorSpace.cpp"
+#include "../../docs/examples/Pixmap_shiftPerPixel.cpp"
+#include "../../docs/examples/Pixmap_width.cpp"
+#include "../../docs/examples/Pixmap_writable_addr.cpp"
+#include "../../docs/examples/Pixmap_writable_addr16.cpp"
+#include "../../docs/examples/Pixmap_writable_addr32.cpp"
+#include "../../docs/examples/Pixmap_writable_addr64.cpp"
+#include "../../docs/examples/Pixmap_writable_addr8.cpp"
+#include "../../docs/examples/Pixmap_writable_addrF16.cpp"
+#include "../../docs/examples/Pixmap_writable_addr_2.cpp"
+#include "../../docs/examples/Plus.cpp"
+#include "../../docs/examples/Point_CrossProduct.cpp"
+#include "../../docs/examples/Point_Distance.cpp"
+#include "../../docs/examples/Point_DotProduct.cpp"
+#include "../../docs/examples/Point_Length.cpp"
+#include "../../docs/examples/Point_Make.cpp"
+#include "../../docs/examples/Point_Normalize.cpp"
+#include "../../docs/examples/Point_Offset.cpp"
+#include "../../docs/examples/Point_Offset_2.cpp"
+#include "../../docs/examples/Point_add_operator.cpp"
+#include "../../docs/examples/Point_addto_operator.cpp"
+#include "../../docs/examples/Point_cross.cpp"
+#include "../../docs/examples/Point_distanceToOrigin.cpp"
+#include "../../docs/examples/Point_dot.cpp"
+#include "../../docs/examples/Point_equal_operator.cpp"
+#include "../../docs/examples/Point_equals.cpp"
+#include "../../docs/examples/Point_isFinite.cpp"
+#include "../../docs/examples/Point_isZero.cpp"
+#include "../../docs/examples/Point_iset.cpp"
+#include "../../docs/examples/Point_iset_2.cpp"
+#include "../../docs/examples/Point_length_2.cpp"
+#include "../../docs/examples/Point_minus_operator.cpp"
+#include "../../docs/examples/Point_multiply_operator.cpp"
+#include "../../docs/examples/Point_multiplyby_operator.cpp"
+#include "../../docs/examples/Point_negate.cpp"
+#include "../../docs/examples/Point_normalize_2.cpp"
+#include "../../docs/examples/Point_notequal_operator.cpp"
+#include "../../docs/examples/Point_offset_3.cpp"
+#include "../../docs/examples/Point_scale.cpp"
+#include "../../docs/examples/Point_scale_2.cpp"
+#include "../../docs/examples/Point_set.cpp"
+#include "../../docs/examples/Point_setAbs.cpp"
+#include "../../docs/examples/Point_setLength.cpp"
+#include "../../docs/examples/Point_setLength_2.cpp"
+#include "../../docs/examples/Point_setNormalize.cpp"
+#include "../../docs/examples/Point_subtract_operator.cpp"
+#include "../../docs/examples/Point_subtractfrom_operator.cpp"
+#include "../../docs/examples/Point_x.cpp"
+#include "../../docs/examples/Point_y.cpp"
+#include "../../docs/examples/PreMultiplyARGB.cpp"
+#include "../../docs/examples/PreMultiplyColor.cpp"
+#include "../../docs/examples/Quad_a.cpp"
+#include "../../docs/examples/Quad_b.cpp"
+#include "../../docs/examples/RGBA4f_FromColor.cpp"
+#include "../../docs/examples/RGBA4f_equal1_operator.cpp"
+#include "../../docs/examples/RGBA4f_notequal1_operator.cpp"
+#include "../../docs/examples/RGBA4f_toSkColor.cpp"
+#include "../../docs/examples/RGBA4f_vec.cpp"
+#include "../../docs/examples/RGBA4f_vec_2.cpp"
+#include "../../docs/examples/RGBToHSV.cpp"
+#include "../../docs/examples/RRect_Corner.cpp"
+#include "../../docs/examples/RRect_MakeEmpty.cpp"
+#include "../../docs/examples/RRect_MakeOval.cpp"
+#include "../../docs/examples/RRect_MakeRect.cpp"
+#include "../../docs/examples/RRect_MakeRectXY.cpp"
+#include "../../docs/examples/RRect_Type.cpp"
+#include "../../docs/examples/RRect_contains.cpp"
+#include "../../docs/examples/RRect_copy_const_SkRRect.cpp"
+#include "../../docs/examples/RRect_copy_operator.cpp"
+#include "../../docs/examples/RRect_dump.cpp"
+#include "../../docs/examples/RRect_dumpHex.cpp"
+#include "../../docs/examples/RRect_dump_2.cpp"
+#include "../../docs/examples/RRect_empty_constructor.cpp"
+#include "../../docs/examples/RRect_equal_operator.cpp"
+#include "../../docs/examples/RRect_getBounds.cpp"
+#include "../../docs/examples/RRect_getSimpleRadii.cpp"
+#include "../../docs/examples/RRect_getType.cpp"
+#include "../../docs/examples/RRect_height.cpp"
+#include "../../docs/examples/RRect_inset.cpp"
+#include "../../docs/examples/RRect_inset_2.cpp"
+#include "../../docs/examples/RRect_isComplex.cpp"
+#include "../../docs/examples/RRect_isEmpty.cpp"
+#include "../../docs/examples/RRect_isNinePatch.cpp"
+#include "../../docs/examples/RRect_isOval.cpp"
+#include "../../docs/examples/RRect_isRect.cpp"
+#include "../../docs/examples/RRect_isSimple.cpp"
+#include "../../docs/examples/RRect_isValid.cpp"
+#include "../../docs/examples/RRect_makeOffset.cpp"
+#include "../../docs/examples/RRect_notequal_operator.cpp"
+#include "../../docs/examples/RRect_offset.cpp"
+#include "../../docs/examples/RRect_outset.cpp"
+#include "../../docs/examples/RRect_outset_2.cpp"
+#include "../../docs/examples/RRect_radii.cpp"
+#include "../../docs/examples/RRect_readFromMemory.cpp"
+#include "../../docs/examples/RRect_rect.cpp"
+#include "../../docs/examples/RRect_setEmpty.cpp"
+#include "../../docs/examples/RRect_setNinePatch.cpp"
+#include "../../docs/examples/RRect_setOval.cpp"
+#include "../../docs/examples/RRect_setRect.cpp"
+#include "../../docs/examples/RRect_setRectRadii.cpp"
+#include "../../docs/examples/RRect_setRectXY.cpp"
+#include "../../docs/examples/RRect_transform.cpp"
+#include "../../docs/examples/RRect_type_2.cpp"
+#include "../../docs/examples/RRect_width.cpp"
+#include "../../docs/examples/RRect_writeToMemory.cpp"
+#include "../../docs/examples/Rect_Intersects.cpp"
+#include "../../docs/examples/Rect_Make.cpp"
+#include "../../docs/examples/Rect_MakeEmpty.cpp"
+#include "../../docs/examples/Rect_MakeIWH.cpp"
+#include "../../docs/examples/Rect_MakeLTRB.cpp"
+#include "../../docs/examples/Rect_MakeSize.cpp"
+#include "../../docs/examples/Rect_MakeWH.cpp"
+#include "../../docs/examples/Rect_MakeXYWH.cpp"
+#include "../../docs/examples/Rect_Make_2.cpp"
+#include "../../docs/examples/Rect_asScalars.cpp"
+#include "../../docs/examples/Rect_bottom.cpp"
+#include "../../docs/examples/Rect_centerX.cpp"
+#include "../../docs/examples/Rect_centerY.cpp"
+#include "../../docs/examples/Rect_contains.cpp"
+#include "../../docs/examples/Rect_contains_2.cpp"
+#include "../../docs/examples/Rect_contains_3.cpp"
+#include "../../docs/examples/Rect_dump.cpp"
+#include "../../docs/examples/Rect_dumpHex.cpp"
+#include "../../docs/examples/Rect_dump_2.cpp"
+#include "../../docs/examples/Rect_equal_operator.cpp"
+#include "../../docs/examples/Rect_height.cpp"
+#include "../../docs/examples/Rect_inset.cpp"
+#include "../../docs/examples/Rect_intersect.cpp"
+#include "../../docs/examples/Rect_intersect_2.cpp"
+#include "../../docs/examples/Rect_intersect_3.cpp"
+#include "../../docs/examples/Rect_intersects_2.cpp"
+#include "../../docs/examples/Rect_intersects_3.cpp"
+#include "../../docs/examples/Rect_isEmpty.cpp"
+#include "../../docs/examples/Rect_isFinite.cpp"
+#include "../../docs/examples/Rect_isSorted.cpp"
+#include "../../docs/examples/Rect_join.cpp"
+#include "../../docs/examples/Rect_joinNonEmptyArg.cpp"
+#include "../../docs/examples/Rect_joinPossiblyEmptyRect.cpp"
+#include "../../docs/examples/Rect_join_2.cpp"
+#include "../../docs/examples/Rect_left.cpp"
+#include "../../docs/examples/Rect_makeInset.cpp"
+#include "../../docs/examples/Rect_makeOffset.cpp"
+#include "../../docs/examples/Rect_makeOutset.cpp"
+#include "../../docs/examples/Rect_makeSorted.cpp"
+#include "../../docs/examples/Rect_notequal_operator.cpp"
+#include "../../docs/examples/Rect_offset.cpp"
+#include "../../docs/examples/Rect_offsetTo.cpp"
+#include "../../docs/examples/Rect_offset_2.cpp"
+#include "../../docs/examples/Rect_outset.cpp"
+#include "../../docs/examples/Rect_right.cpp"
+#include "../../docs/examples/Rect_round.cpp"
+#include "../../docs/examples/Rect_roundIn.cpp"
+#include "../../docs/examples/Rect_roundOut.cpp"
+#include "../../docs/examples/Rect_roundOut_2.cpp"
+#include "../../docs/examples/Rect_roundOut_3.cpp"
+#include "../../docs/examples/Rect_round_2.cpp"
+#include "../../docs/examples/Rect_set.cpp"
+#include "../../docs/examples/Rect_setBounds.cpp"
+#include "../../docs/examples/Rect_setBoundsCheck.cpp"
+#include "../../docs/examples/Rect_setBoundsNoCheck.cpp"
+#include "../../docs/examples/Rect_setEmpty.cpp"
+#include "../../docs/examples/Rect_setLTRB.cpp"
+#include "../../docs/examples/Rect_setWH.cpp"
+#include "../../docs/examples/Rect_setXYWH.cpp"
+#include "../../docs/examples/Rect_set_4.cpp"
+#include "../../docs/examples/Rect_sort.cpp"
+#include "../../docs/examples/Rect_toQuad.cpp"
+#include "../../docs/examples/Rect_top.cpp"
+#include "../../docs/examples/Rect_width.cpp"
+#include "../../docs/examples/Rect_x.cpp"
+#include "../../docs/examples/Rect_y.cpp"
+#include "../../docs/examples/Region_Cliperator_const_SkRegion_const_SkIRect.cpp"
+#include "../../docs/examples/Region_Cliperator_done.cpp"
+#include "../../docs/examples/Region_Cliperator_next.cpp"
+#include "../../docs/examples/Region_Cliperator_rect.cpp"
+#include "../../docs/examples/Region_Iterator_Iterator.cpp"
+#include "../../docs/examples/Region_Iterator_copy_const_SkRegion.cpp"
+#include "../../docs/examples/Region_Iterator_done.cpp"
+#include "../../docs/examples/Region_Iterator_next.cpp"
+#include "../../docs/examples/Region_Iterator_rect.cpp"
+#include "../../docs/examples/Region_Iterator_reset.cpp"
+#include "../../docs/examples/Region_Iterator_rewind.cpp"
+#include "../../docs/examples/Region_Iterator_rgn.cpp"
+#include "../../docs/examples/Region_Op.cpp"
+#include "../../docs/examples/Region_Spanerator_const_SkRegion_int_int_int.cpp"
+#include "../../docs/examples/Region_Spanerator_next.cpp"
+#include "../../docs/examples/Region_computeRegionComplexity.cpp"
+#include "../../docs/examples/Region_contains.cpp"
+#include "../../docs/examples/Region_contains_2.cpp"
+#include "../../docs/examples/Region_contains_3.cpp"
+#include "../../docs/examples/Region_copy_const_SkIRect.cpp"
+#include "../../docs/examples/Region_copy_const_SkRegion.cpp"
+#include "../../docs/examples/Region_copy_operator.cpp"
+#include "../../docs/examples/Region_destructor.cpp"
+#include "../../docs/examples/Region_empty_constructor.cpp"
+#include "../../docs/examples/Region_equal1_operator.cpp"
+#include "../../docs/examples/Region_getBoundaryPath.cpp"
+#include "../../docs/examples/Region_getBounds.cpp"
+#include "../../docs/examples/Region_intersects.cpp"
+#include "../../docs/examples/Region_intersects_2.cpp"
+#include "../../docs/examples/Region_isComplex.cpp"
+#include "../../docs/examples/Region_isEmpty.cpp"
+#include "../../docs/examples/Region_isRect.cpp"
+#include "../../docs/examples/Region_notequal1_operator.cpp"
+#include "../../docs/examples/Region_op_1.cpp"
+#include "../../docs/examples/Region_op_2.cpp"
+#include "../../docs/examples/Region_op_3.cpp"
+#include "../../docs/examples/Region_op_4.cpp"
+#include "../../docs/examples/Region_op_5.cpp"
+#include "../../docs/examples/Region_op_6.cpp"
+#include "../../docs/examples/Region_quickContains.cpp"
+#include "../../docs/examples/Region_quickReject.cpp"
+#include "../../docs/examples/Region_quickReject_2.cpp"
+#include "../../docs/examples/Region_readFromMemory.cpp"
+#include "../../docs/examples/Region_set.cpp"
+#include "../../docs/examples/Region_setEmpty.cpp"
+#include "../../docs/examples/Region_setPath.cpp"
+#include "../../docs/examples/Region_setRect.cpp"
+#include "../../docs/examples/Region_setRects.cpp"
+#include "../../docs/examples/Region_setRegion.cpp"
+#include "../../docs/examples/Region_swap.cpp"
+#include "../../docs/examples/Region_translate.cpp"
+#include "../../docs/examples/Region_translate_2.cpp"
+#include "../../docs/examples/Region_writeToMemory.cpp"
+#include "../../docs/examples/Saturation.cpp"
+#include "../../docs/examples/Screen.cpp"
+#include "../../docs/examples/Shader_Methods_a.cpp"
+#include "../../docs/examples/Shader_Methods_b.cpp"
+#include "../../docs/examples/Soft_Light.cpp"
+#include "../../docs/examples/Src.cpp"
+#include "../../docs/examples/Src_Atop.cpp"
+#include "../../docs/examples/Src_In.cpp"
+#include "../../docs/examples/Src_Out.cpp"
+#include "../../docs/examples/Src_Over.cpp"
+#include "../../docs/examples/State_Stack_a.cpp"
+#include "../../docs/examples/State_Stack_b.cpp"
+#include "../../docs/examples/Stroke_Width.cpp"
+#include "../../docs/examples/Surface_MakeFromBackendTexture.cpp"
+#include "../../docs/examples/Surface_MakeFromBackendTextureAsRenderTarget.cpp"
+#include "../../docs/examples/Surface_MakeNull.cpp"
+#include "../../docs/examples/Surface_MakeRaster.cpp"
+#include "../../docs/examples/Surface_MakeRasterDirect.cpp"
+#include "../../docs/examples/Surface_MakeRasterDirectReleaseProc.cpp"
+#include "../../docs/examples/Surface_MakeRasterN32Premul.cpp"
+#include "../../docs/examples/Surface_MakeRaster_2.cpp"
+#include "../../docs/examples/Surface_MakeRenderTarget.cpp"
+#include "../../docs/examples/Surface_MakeRenderTarget_2.cpp"
+#include "../../docs/examples/Surface_MakeRenderTarget_3.cpp"
+#include "../../docs/examples/Surface_characterize.cpp"
+#include "../../docs/examples/Surface_draw.cpp"
+#include "../../docs/examples/Surface_draw_2.cpp"
+#include "../../docs/examples/Surface_getCanvas.cpp"
+#include "../../docs/examples/Surface_height.cpp"
+#include "../../docs/examples/Surface_makeImageSnapshot.cpp"
+#include "../../docs/examples/Surface_makeImageSnapshot_2.cpp"
+#include "../../docs/examples/Surface_makeSurface.cpp"
+#include "../../docs/examples/Surface_notifyContentWillChange.cpp"
+#include "../../docs/examples/Surface_peekPixels.cpp"
+#include "../../docs/examples/Surface_props.cpp"
+#include "../../docs/examples/Surface_readPixels.cpp"
+#include "../../docs/examples/Surface_readPixels_2.cpp"
+#include "../../docs/examples/Surface_readPixels_3.cpp"
+#include "../../docs/examples/Surface_width.cpp"
+#include "../../docs/examples/Surface_writePixels.cpp"
+#include "../../docs/examples/Surface_writePixels_2.cpp"
+#include "../../docs/examples/TextBlobBuilder_allocRun.cpp"
+#include "../../docs/examples/TextBlobBuilder_allocRunPos.cpp"
+#include "../../docs/examples/TextBlobBuilder_allocRunPosH.cpp"
+#include "../../docs/examples/TextBlobBuilder_empty_constructor.cpp"
+#include "../../docs/examples/TextBlobBuilder_make.cpp"
+#include "../../docs/examples/TextBlob_Deserialize.cpp"
+#include "../../docs/examples/TextBlob_MakeFromString.cpp"
+#include "../../docs/examples/TextBlob_MakeFromText.cpp"
+#include "../../docs/examples/TextBlob_bounds.cpp"
+#include "../../docs/examples/TextBlob_getIntercepts.cpp"
+#include "../../docs/examples/TextBlob_serialize.cpp"
+#include "../../docs/examples/TextBlob_serialize_2.cpp"
+#include "../../docs/examples/TextBlob_uniqueID.cpp"
+#include "../../docs/examples/Text_Encoding.cpp"
+#include "../../docs/examples/Text_Scale_X.cpp"
+#include "../../docs/examples/Text_Size.cpp"
+#include "../../docs/examples/Text_Skew_X.cpp"
+#include "../../docs/examples/Typeface_Methods.cpp"
+#include "../../docs/examples/Xor.cpp"
+#include "../../docs/examples/incomplete.cpp"
diff --git a/src/third_party/skia/tools/fiddle/disabled_examples.txt b/src/third_party/skia/tools/fiddle/disabled_examples.txt
new file mode 100644
index 0000000..3970425
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/disabled_examples.txt
@@ -0,0 +1,202 @@
+docs/examples/Alpha_Type_Opaque.cpp
+docs/examples/Alpha_Type_Premul.cpp
+docs/examples/Alpha_Type_Unpremul.cpp
+docs/examples/Arc.cpp
+docs/examples/Canvas_129.cpp
+docs/examples/Canvas_SaveLayerRec_SaveLayerRec.cpp
+docs/examples/Canvas_drawAnnotation_2.cpp
+docs/examples/Canvas_drawPatch_2_a.cpp
+docs/examples/Canvas_drawPosText.cpp
+docs/examples/Canvas_drawPosTextH.cpp
+docs/examples/Canvas_drawTextBlob.cpp
+docs/examples/Canvas_saveLayerPreserveLCDTextRequests.cpp
+docs/examples/ColorGetB.cpp
+docs/examples/ColorGetG.cpp
+docs/examples/ColorGetR.cpp
+docs/examples/Color_Constants_a.cpp
+docs/examples/Device_Text.cpp
+docs/examples/Fake_Bold.cpp
+docs/examples/Font_breakText.cpp
+docs/examples/ImageInfo_MakeN32.cpp
+docs/examples/ImageInfo_MakeN32Premul.cpp
+docs/examples/ImageInfo_MakeN32Premul_2.cpp
+docs/examples/ImageInfo_MakeUnknown.cpp
+docs/examples/ImageInfo_MakeUnknown_2.cpp
+docs/examples/ImageInfo_empty_constructor.cpp
+docs/examples/ImageInfo_gammaCloseToSRGB.cpp
+docs/examples/ImageInfo_height.cpp
+docs/examples/ImageInfo_makeColorSpace.cpp
+docs/examples/ImageInfo_width.cpp
+docs/examples/Image_alphaType.cpp
+docs/examples/Image_colorSpace.cpp
+docs/examples/Image_getBackendTexture.cpp
+docs/examples/Image_height.cpp
+docs/examples/Image_isLazyGenerated_a.cpp
+docs/examples/Image_isLazyGenerated_b.cpp
+docs/examples/Image_isTextureBacked.cpp
+docs/examples/Image_isValid.cpp
+docs/examples/Image_makeColorSpace.cpp
+docs/examples/Image_makeNonTextureImage.cpp
+docs/examples/Image_makeRasterImage.cpp
+docs/examples/Image_makeTextureImage.cpp
+docs/examples/Image_peekPixels.cpp
+docs/examples/Image_refColorSpace.cpp
+docs/examples/Image_refEncodedData.cpp
+docs/examples/Image_uniqueID.cpp
+docs/examples/Image_width.cpp
+docs/examples/Matrix_MakeAll.cpp
+docs/examples/Matrix_ScaleToFit.cpp
+docs/examples/Matrix_getPerspX.cpp
+docs/examples/Matrix_getPerspY.cpp
+docs/examples/Matrix_hasPerspective.cpp
+docs/examples/Matrix_isSimilarity.cpp
+docs/examples/Matrix_mapRadius.cpp
+docs/examples/Matrix_mapVector.cpp
+docs/examples/Matrix_mapVector_2.cpp
+docs/examples/Matrix_preservesRightAngles.cpp
+docs/examples/Matrix_setAll.cpp
+docs/examples/Matrix_setPolyToPoly.cpp
+docs/examples/Matrix_setScale.cpp
+docs/examples/Matrix_setScaleX.cpp
+docs/examples/Matrix_setScaleY.cpp
+docs/examples/Matrix_setScale_2.cpp
+docs/examples/Matrix_setSkew.cpp
+docs/examples/Matrix_setSkewX.cpp
+docs/examples/Matrix_setSkewY.cpp
+docs/examples/Matrix_setSkew_2.cpp
+docs/examples/Matrix_setTranslate.cpp
+docs/examples/Matrix_setTranslateX.cpp
+docs/examples/Matrix_setTranslateY.cpp
+docs/examples/Matrix_setTranslate_2.cpp
+docs/examples/MemberIndex.cpp
+docs/examples/Paint_containsText.cpp
+docs/examples/Paint_countText.cpp
+docs/examples/Paint_getFlags.cpp
+docs/examples/Paint_getFontMetrics.cpp
+docs/examples/Paint_getFontSpacing.cpp
+docs/examples/Paint_getHinting.cpp
+docs/examples/Paint_getPosTextPath.cpp
+docs/examples/Paint_getTextEncoding.cpp
+docs/examples/Paint_getTextPath.cpp
+docs/examples/Paint_getTextScaleX.cpp
+docs/examples/Paint_getTextSize.cpp
+docs/examples/Paint_getTextSkewX.cpp
+docs/examples/Paint_getTextWidths.cpp
+docs/examples/Paint_getTypeface.cpp
+docs/examples/Paint_isAntiAlias.cpp
+docs/examples/Paint_isAutohinted.cpp
+docs/examples/Paint_isDither.cpp
+docs/examples/Paint_isEmbeddedBitmapText.cpp
+docs/examples/Paint_isFakeBoldText.cpp
+docs/examples/Paint_isLCDRenderText.cpp
+docs/examples/Paint_isLinearText.cpp
+docs/examples/Paint_isSubpixelText.cpp
+docs/examples/Paint_measureText.cpp
+docs/examples/Paint_measureText_2.cpp
+docs/examples/Paint_refTypeface.cpp
+docs/examples/Paint_setAntiAlias.cpp
+docs/examples/Paint_setAutohinted.cpp
+docs/examples/Paint_setDither.cpp
+docs/examples/Paint_setEmbeddedBitmapText.cpp
+docs/examples/Paint_setFakeBoldText.cpp
+docs/examples/Paint_setFlags.cpp
+docs/examples/Paint_setHinting.cpp
+docs/examples/Paint_setImageFilter.cpp
+docs/examples/Paint_setLCDRenderText.cpp
+docs/examples/Paint_setLinearText.cpp
+docs/examples/Paint_setSubpixelText.cpp
+docs/examples/Paint_setTextEncoding.cpp
+docs/examples/Paint_setTextScaleX.cpp
+docs/examples/Paint_setTextSize.cpp
+docs/examples/Paint_setTextSkewX.cpp
+docs/examples/Paint_setTypeface.cpp
+docs/examples/Paint_textToGlyphs.cpp
+docs/examples/Path_Convexity.cpp
+docs/examples/Path_Direction.cpp
+docs/examples/Path_FillType_b.cpp
+docs/examples/Path_Iter.cpp
+docs/examples/Path_addOval_2.cpp
+docs/examples/Path_addPath.cpp
+docs/examples/Path_arcTo_2_a.cpp
+docs/examples/Path_arcTo_2_b.cpp
+docs/examples/Path_contains.cpp
+docs/examples/Path_isConvex.cpp
+docs/examples/Path_lineTo.cpp
+docs/examples/Path_rMoveTo.cpp
+docs/examples/Path_setLastPt.cpp
+docs/examples/Path_setLastPt_2.cpp
+docs/examples/Path_toggleInverseFillType.cpp
+docs/examples/Picture_approximateBytesUsed.cpp
+docs/examples/Picture_approximateOpCount.cpp
+docs/examples/Pixmap_setColorSpace.cpp
+docs/examples/Point_CrossProduct.cpp
+docs/examples/Point_Distance.cpp
+docs/examples/Point_DotProduct.cpp
+docs/examples/Point_Length.cpp
+docs/examples/Point_Normalize.cpp
+docs/examples/Point_cross.cpp
+docs/examples/Point_distanceToOrigin.cpp
+docs/examples/Point_dot.cpp
+docs/examples/Point_length_2.cpp
+docs/examples/PreMultiplyARGB.cpp
+docs/examples/PreMultiplyColor.cpp
+docs/examples/RGBToHSV.cpp
+docs/examples/RRect_MakeEmpty.cpp
+docs/examples/RRect_Type.cpp
+docs/examples/RRect_contains.cpp
+docs/examples/RRect_equal_operator.cpp
+docs/examples/RRect_getSimpleRadii.cpp
+docs/examples/RRect_getType.cpp
+docs/examples/RRect_isComplex.cpp
+docs/examples/RRect_isEmpty.cpp
+docs/examples/RRect_isNinePatch.cpp
+docs/examples/RRect_isOval.cpp
+docs/examples/RRect_isRect.cpp
+docs/examples/RRect_isSimple.cpp
+docs/examples/RRect_isValid.cpp
+docs/examples/RRect_notequal_operator.cpp
+docs/examples/RRect_readFromMemory.cpp
+docs/examples/RRect_transform.cpp
+docs/examples/RRect_type_2.cpp
+docs/examples/RRect_writeToMemory.cpp
+docs/examples/Region_Op.cpp
+docs/examples/Region_contains.cpp
+docs/examples/Region_contains_2.cpp
+docs/examples/Region_contains_3.cpp
+docs/examples/Region_intersects.cpp
+docs/examples/Region_intersects_2.cpp
+docs/examples/Region_op_1.cpp
+docs/examples/Region_op_2.cpp
+docs/examples/Region_op_3.cpp
+docs/examples/Region_op_4.cpp
+docs/examples/Region_op_5.cpp
+docs/examples/Region_op_6.cpp
+docs/examples/Region_setPath.cpp
+docs/examples/Region_writeToMemory.cpp
+docs/examples/Surface_MakeFromBackendTexture.cpp
+docs/examples/Surface_MakeFromBackendTextureAsRenderTarget.cpp
+docs/examples/Surface_MakeRenderTarget.cpp
+docs/examples/Surface_MakeRenderTarget_2.cpp
+docs/examples/Surface_MakeRenderTarget_3.cpp
+docs/examples/Surface_characterize.cpp
+docs/examples/Surface_draw_2.cpp
+docs/examples/Surface_getCanvas.cpp
+docs/examples/Surface_peekPixels.cpp
+docs/examples/Surface_readPixels.cpp
+docs/examples/Surface_writePixels.cpp
+docs/examples/TextBlobBuilder_allocRun.cpp
+docs/examples/TextBlobBuilder_allocRunPos.cpp
+docs/examples/TextBlobBuilder_allocRunPosH.cpp
+docs/examples/TextBlobBuilder_make.cpp
+docs/examples/TextBlob_Deserialize.cpp
+docs/examples/TextBlob_MakeFromString.cpp
+docs/examples/TextBlob_MakeFromText.cpp
+docs/examples/TextBlob_bounds.cpp
+docs/examples/TextBlob_getIntercepts.cpp
+docs/examples/TextBlob_serialize.cpp
+docs/examples/TextBlob_uniqueID.cpp
+docs/examples/Text_Encoding.cpp
+docs/examples/Text_Scale_X.cpp
+docs/examples/Text_Size.cpp
+docs/examples/Text_Skew_X.cpp
+docs/examples/Typeface_Methods.cpp
diff --git a/src/third_party/skia/tools/fiddle/documumentation_examples_map.txt b/src/third_party/skia/tools/fiddle/documumentation_examples_map.txt
new file mode 100644
index 0000000..a1acd1c
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/documumentation_examples_map.txt
@@ -0,0 +1,4103 @@
+
+This file contains a mapping from where these documumentation examples
+should be inserted into the headers.
+
+###########################################################################
+
+[AutoCanvasRestore_SkCanvas_star]
+SkAutoCanvasRestore
+SkAutoCanvasRestore(SkCanvas* canvas, bool doSave);
+
+[AutoCanvasRestore_restore]
+SkAutoCanvasRestore
+void restore();
+
+[Bitmap_ComputeIsOpaque]
+SkBitmap
+static bool ComputeIsOpaque(const SkBitmap& bm);
+
+[Bitmap_empty_constructor]
+SkBitmap
+SkBitmap();
+
+[Bitmap_move_SkBitmap]
+SkBitmap
+SkBitmap(SkBitmap&& src);
+
+[Bitmap_copy_const_SkBitmap]
+SkBitmap
+SkBitmap(const SkBitmap& src);
+
+[Bitmap_allocN32Pixels]
+SkBitmap
+void allocN32Pixels(int width, int height, bool isOpaque = false);
+
+[Bitmap_HeapAllocator_allocPixelRef]
+SkBitmap
+bool allocPixelRef(SkBitmap* bitmap) override;
+
+[Bitmap_allocPixels_3]
+SkBitmap
+void allocPixels();
+
+[Bitmap_allocPixels_4]
+SkBitmap
+void allocPixels(Allocator* allocator);
+
+[Bitmap_allocPixels_2]
+SkBitmap
+void allocPixels(const SkImageInfo& info);
+
+[Bitmap_allocPixels]
+SkBitmap
+void allocPixels(const SkImageInfo& info, size_t rowBytes);
+
+[Bitmap_allocPixelsFlags]
+SkBitmap
+void allocPixelsFlags(const SkImageInfo& info, uint32_t flags);
+
+[Pixmap_alphaType]
+SkBitmap
+SkAlphaType alphaType() const;
+
+[Bitmap_bounds]
+SkBitmap
+SkIRect bounds() const;
+
+[Bitmap_bytesPerPixel]
+SkBitmap
+int bytesPerPixel() const;
+
+[Bitmap_colorSpace]
+SkBitmap
+SkColorSpace* colorSpace() const;
+
+[Bitmap_colorType]
+SkBitmap
+SkColorType colorType() const;
+
+[Bitmap_computeByteSize]
+SkBitmap
+size_t computeByteSize() const;
+
+[Bitmap_dimensions]
+SkBitmap
+SkISize dimensions() const;
+
+[Bitmap_drawsNothing]
+SkBitmap
+bool drawsNothing() const;
+
+[Bitmap_empty]
+SkBitmap
+bool empty() const;
+
+[Bitmap_erase]
+SkBitmap
+void erase(SkColor c, const SkIRect& area) const;
+
+[Bitmap_eraseARGB]
+SkBitmap
+void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const;
+
+[Bitmap_eraseColor]
+SkBitmap
+void eraseColor(SkColor c) const;
+
+[Bitmap_extractAlpha]
+SkBitmap
+bool extractAlpha(SkBitmap* dst) const;
+
+[Bitmap_extractAlpha_3]
+SkBitmap
+bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator, SkIPoint* offset) const;
+
+[Bitmap_extractAlpha_2]
+SkBitmap
+bool extractAlpha(SkBitmap* dst, const SkPaint* paint, SkIPoint* offset) const;
+
+[Bitmap_extractSubset]
+SkBitmap
+bool extractSubset(SkBitmap* dst, const SkIRect& subset) const;
+
+[Bitmap_getAddr]
+SkBitmap
+void* getAddr(int x, int y) const;
+
+[Bitmap_getAddr16]
+SkBitmap
+uint16_t* getAddr16(int x, int y) const;
+
+[Bitmap_getAddr32]
+SkBitmap
+uint32_t* getAddr32(int x, int y) const;
+
+[Bitmap_getAddr8]
+SkBitmap
+uint8_t* getAddr8(int x, int y) const;
+
+[Bitmap_getBounds_2]
+SkBitmap
+void getBounds(SkIRect* bounds) const;
+
+[Bitmap_getBounds]
+SkBitmap
+void getBounds(SkRect* bounds) const;
+
+[Bitmap_getColor]
+SkBitmap
+SkColor getColor(int x, int y) const;
+
+[Bitmap_getGenerationID]
+SkBitmap
+uint32_t getGenerationID() const;
+
+[Bitmap_getPixels]
+SkBitmap
+void* getPixels() const;
+
+[Bitmap_getSubset]
+SkBitmap
+SkIRect getSubset() const;
+
+[Bitmap_height]
+SkBitmap
+int height() const;
+
+[Bitmap_info]
+SkBitmap
+const SkImageInfo& info() const;
+
+[Bitmap_installPixels_2]
+SkBitmap
+bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
+
+[Bitmap_installPixels]
+SkBitmap
+bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, void (*releaseProc) (void* addr, void* context) , void* context);
+
+[Bitmap_installPixels_3]
+SkBitmap
+bool installPixels(const SkPixmap& pixmap);
+
+[Bitmap_isImmutable]
+SkBitmap
+bool isImmutable() const;
+
+[Bitmap_isNull]
+SkBitmap
+bool isNull() const;
+
+[Bitmap_isOpaque]
+SkBitmap
+bool isOpaque() const;
+
+[Bitmap_isVolatile]
+SkBitmap
+bool isVolatile() const;
+
+[Bitmap_notifyPixelsChanged]
+SkBitmap
+void notifyPixelsChanged() const;
+
+[Bitmap_move_operator]
+SkBitmap
+SkBitmap& operator=(SkBitmap&& src);
+
+[Bitmap_copy_operator]
+SkBitmap
+SkBitmap& operator=(const SkBitmap& src);
+
+[Bitmap_peekPixels]
+SkBitmap
+bool peekPixels(SkPixmap* pixmap) const;
+
+[Bitmap_pixelRef]
+SkBitmap
+SkPixelRef* pixelRef() const;
+
+[Bitmap_pixelRefOrigin]
+SkBitmap
+SkIPoint pixelRefOrigin() const;
+
+[Bitmap_pixmap]
+SkBitmap
+const SkPixmap& pixmap() const;
+
+[Bitmap_readPixels]
+SkBitmap
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) const;
+
+[Bitmap_readPixels_3]
+SkBitmap
+bool readPixels(const SkPixmap& dst) const;
+
+[Bitmap_readPixels_2]
+SkBitmap
+bool readPixels(const SkPixmap& dst, int srcX, int srcY) const;
+
+[Bitmap_readyToDraw]
+SkBitmap
+bool readyToDraw() const;
+
+[Bitmap_refColorSpace]
+SkBitmap
+sk_sp<SkColorSpace> refColorSpace() const;
+
+[Bitmap_reset]
+SkBitmap
+void reset();
+
+[Bitmap_rowBytes]
+SkBitmap
+size_t rowBytes() const;
+
+[Bitmap_rowBytesAsPixels]
+SkBitmap
+int rowBytesAsPixels() const;
+
+[Bitmap_setAlphaType]
+SkBitmap
+bool setAlphaType(SkAlphaType alphaType);
+
+[Bitmap_setImmutable]
+SkBitmap
+void setImmutable();
+
+[Bitmap_setInfo]
+SkBitmap
+bool setInfo(const SkImageInfo& imageInfo, size_t rowBytes = 0);
+
+[Bitmap_setIsVolatile]
+SkBitmap
+void setIsVolatile(bool isVolatile);
+
+[Bitmap_setPixelRef]
+SkBitmap
+void setPixelRef(sk_sp<SkPixelRef> pixelRef, int dx, int dy);
+
+[Bitmap_setPixels]
+SkBitmap
+void setPixels(void* pixels);
+
+[Bitmap_shiftPerPixel]
+SkBitmap
+int shiftPerPixel() const;
+
+[Bitmap_swap]
+SkBitmap
+void swap(SkBitmap& other);
+
+[Bitmap_tryAllocN32Pixels]
+SkBitmap
+bool tryAllocN32Pixels(int width, int height, bool isOpaque = false);
+
+[Bitmap_tryAllocPixels_3]
+SkBitmap
+bool tryAllocPixels();
+
+[Bitmap_tryAllocPixels_4]
+SkBitmap
+bool tryAllocPixels(Allocator* allocator);
+
+[Bitmap_tryAllocPixels_2]
+SkBitmap
+bool tryAllocPixels(const SkImageInfo& info);
+
+[Bitmap_tryAllocPixels]
+SkBitmap
+bool tryAllocPixels(const SkImageInfo& info, size_t rowBytes);
+
+[Bitmap_tryAllocPixelsFlags]
+SkBitmap
+bool tryAllocPixelsFlags(const SkImageInfo& info, uint32_t flags);
+
+[Bitmap_width]
+SkBitmap
+int width() const;
+
+[Bitmap_writePixels_2]
+SkBitmap
+bool writePixels(const SkPixmap& src);
+
+[Bitmap_writePixels]
+SkBitmap
+bool writePixels(const SkPixmap& src, int dstX, int dstY);
+
+[BlendMode_Name]
+SkBlendMode
+const char* SkBlendMode_Name(SkBlendMode blendMode);
+
+[Clear]
+[Color]
+[Color_Burn]
+[Color_Dodge]
+[Darken]
+[Difference]
+[Dst]
+[Dst_Atop]
+[Dst_In]
+[Dst_Out]
+[Dst_Over]
+[Exclusion]
+[Hard_Light]
+[Hue]
+[Lighten]
+[Luminosity]
+[Modulate]
+[Multiply]
+[Overlay]
+[Plus]
+[Saturation]
+[Screen]
+[Soft_Light]
+[Src]
+[Src_Atop]
+[Src_In]
+[Src_Out]
+[Src_Over]
+[Xor]
+SkBlendMode
+enum class SkBlendMode { kClear, kSrc, kDst, kSrcOver, kDstOver, kSrcIn, kDstIn, kSrcOut, kDstOut, kSrcATop, kDstATop, kXor, kPlus, kModulate, kScreen, kLastCoeffMode = kScreen, kOverlay, kDarken, kLighten, kColorDodge, kColorBurn, kHardLight, kSoftLight, kDifference, kExclusion, kMultiply, kLastSeparableMode = kMultiply, kHue, kSaturation, kColor, kLuminosity, kLastMode = kLuminosity, }; const char* SkBlendMode_Name(SkBlendMode blendMode);
+
+[Canvas_MakeRasterDirect]
+SkCanvas
+static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels, size_t rowBytes, const SkSurfaceProps* props = nullptr);
+
+[Canvas_MakeRasterDirectN32]
+SkCanvas
+static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels, size_t rowBytes);
+
+[Canvas_SaveLayerRec]
+SkCanvas
+struct SaveLayerRec { SaveLayerRec(); SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0); SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, SaveLayerFlags saveLayerFlags); const SkRect* fBounds = nullptr; const SkPaint* fPaint = nullptr; const SkImageFilter* fBackdrop = nullptr; const SkImage* fClipMask = nullptr; const SkMatrix* fClipMatrix = nullptr; SaveLayerFlags fSaveLayerFlags = 0; };
+
+[Canvas_SaveLayerRec_SaveLayerRec]
+SkCanvas
+SaveLayerRec();
+
+[Canvas_SaveLayerRec_const_SkRect_star_const_SkPaint_star]
+SkCanvas
+SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0);
+
+[Canvas_SaveLayerRec_const_SkRect_star_const_SkPaint_star_const_SkImageFilter_star]
+SkCanvas
+SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, SaveLayerFlags saveLayerFlags);
+
+[Canvas_copy_const_SkBitmap]
+SkCanvas
+explicit SkCanvas(const SkBitmap& bitmap);
+
+[Canvas_empty_constructor]
+SkCanvas
+SkCanvas();
+
+[Canvas_const_SkBitmap_const_SkSurfaceProps]
+SkCanvas
+SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props);
+
+[Canvas_int_int_const_SkSurfaceProps_star]
+SkCanvas
+SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr);
+
+[Canvas_accessTopLayerPixels_a]
+[Canvas_accessTopLayerPixels_b]
+SkCanvas
+void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr);
+
+[Canvas_accessTopRasterHandle]
+SkCanvas
+SkRasterHandleAllocator::Handle accessTopRasterHandle() const;
+
+[Canvas_clear]
+SkCanvas
+void clear(SkColor color);
+
+[Canvas_clipPath_2]
+SkCanvas
+void clipPath(const SkPath& path, SkClipOp op);
+
+[Canvas_clipPath]
+SkCanvas
+void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias);
+
+[Canvas_clipPath_3]
+SkCanvas
+void clipPath(const SkPath& path, bool doAntiAlias = false);
+
+[Canvas_clipRRect_2]
+SkCanvas
+void clipRRect(const SkRRect& rrect, SkClipOp op);
+
+[Canvas_clipRRect]
+SkCanvas
+void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias);
+
+[Canvas_clipRRect_3]
+SkCanvas
+void clipRRect(const SkRRect& rrect, bool doAntiAlias = false);
+
+[Canvas_clipRect_2]
+SkCanvas
+void clipRect(const SkRect& rect, SkClipOp op);
+
+[Canvas_clipRect]
+SkCanvas
+void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias);
+
+[Canvas_clipRect_3]
+SkCanvas
+void clipRect(const SkRect& rect, bool doAntiAlias = false);
+
+[Canvas_clipRegion]
+SkCanvas
+void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect);
+
+[Canvas_concat]
+SkCanvas
+void concat(const SkMatrix& matrix);
+
+[Canvas_drawAnnotation_2]
+SkCanvas
+void drawAnnotation(const SkRect& rect, const char key[], SkData* value);
+
+[Canvas_drawAnnotation_2]
+SkCanvas
+void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value);
+
+[Canvas_drawArc_a]
+[Canvas_drawArc_b]
+SkCanvas
+void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint);
+
+[Canvas_drawAtlas]
+SkCanvas
+void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, const SkPaint* paint);
+
+[Canvas_drawAtlas_3]
+SkCanvas
+void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint);
+
+[Canvas_drawAtlas_2]
+SkCanvas
+void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect, const SkPaint* paint);
+
+[Canvas_drawAtlas_4]
+SkCanvas
+void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[], int count, const SkRect* cullRect, const SkPaint* paint);
+
+[Canvas_drawBitmap]
+SkCanvas
+void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint = nullptr);
+
+[Canvas_drawBitmapLattice]
+SkCanvas
+void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, const SkPaint* paint = nullptr);
+
+[Canvas_drawBitmapNine]
+SkCanvas
+void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr);
+
+[Canvas_drawBitmapRect_2]
+SkCanvas
+void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawBitmapRect_3]
+SkCanvas
+void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawBitmapRect]
+SkCanvas
+void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawCircle_2]
+SkCanvas
+void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint);
+
+[Canvas_drawCircle]
+SkCanvas
+void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint);
+
+[Canvas_drawColor]
+SkCanvas
+void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver);
+
+[Canvas_drawDRRect_a]
+[Canvas_drawDRRect_b]
+SkCanvas
+void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint);
+
+[Canvas_drawDrawable_2]
+SkCanvas
+void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y);
+
+[Canvas_drawDrawable]
+SkCanvas
+void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr);
+
+[Canvas_drawIRect]
+SkCanvas
+void drawIRect(const SkIRect& rect, const SkPaint& paint);
+
+[Canvas_drawImage]
+SkCanvas
+void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr);
+
+[Canvas_drawImage_2]
+SkCanvas
+void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr);
+
+[Canvas_drawImageNine]
+SkCanvas
+void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, const SkPaint* paint = nullptr);
+
+[Canvas_drawImageNine]
+SkCanvas
+void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr);
+
+[Canvas_drawImageNine_2]
+SkCanvas
+void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst, const SkPaint* paint = nullptr);
+
+[Canvas_drawImageRect_2]
+SkCanvas
+void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawImageRect_3]
+SkCanvas
+void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint);
+
+[Canvas_drawImageRect]
+SkCanvas
+void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawImageRect_5]
+SkCanvas
+void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawImageRect_6]
+SkCanvas
+void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint);
+
+[Canvas_drawImageRect_4]
+SkCanvas
+void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+[Canvas_drawLine_2]
+SkCanvas
+void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint);
+
+[Canvas_drawLine]
+SkCanvas
+void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint);
+
+[Canvas_drawOval]
+SkCanvas
+void drawOval(const SkRect& oval, const SkPaint& paint);
+
+[Canvas_drawPaint]
+SkCanvas
+void drawPaint(const SkPaint& paint);
+
+[Canvas_drawPatch]
+SkCanvas
+void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint);
+
+[Canvas_drawPatch_2_a]
+[Canvas_drawPatch_2_b]
+SkCanvas
+void drawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], const SkPaint& paint);
+
+[Canvas_drawPath]
+SkCanvas
+void drawPath(const SkPath& path, const SkPaint& paint);
+
+[Canvas_drawPicture_2]
+SkCanvas
+void drawPicture(const SkPicture* picture);
+
+[Canvas_drawPicture_3]
+SkCanvas
+void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint);
+
+[Canvas_drawPicture_2]
+SkCanvas
+void drawPicture(const sk_sp<SkPicture>& picture);
+
+[Canvas_drawPicture_4]
+SkCanvas
+void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix, const SkPaint* paint);
+
+[Canvas_drawPoint_2]
+SkCanvas
+void drawPoint(SkPoint p, const SkPaint& paint);
+
+[Canvas_drawPoint]
+SkCanvas
+void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawPoints]
+SkCanvas
+void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint);
+
+[Canvas_drawPosText]
+SkCanvas
+void drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint);
+
+[Canvas_drawPosTextH]
+SkCanvas
+void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint);
+
+[Canvas_drawRRect]
+SkCanvas
+void drawRRect(const SkRRect& rrect, const SkPaint& paint);
+
+[Canvas_drawRect]
+SkCanvas
+void drawRect(const SkRect& rect, const SkPaint& paint);
+
+[Canvas_drawRegion]
+SkCanvas
+void drawRegion(const SkRegion& region, const SkPaint& paint);
+
+[Canvas_drawRoundRect]
+SkCanvas
+void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint);
+
+[Canvas_drawString_2]
+SkCanvas
+void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawString]
+SkCanvas
+void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawText]
+SkCanvas
+void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawTextBlob]
+SkCanvas
+void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawTextBlob_2]
+SkCanvas
+void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint);
+
+[Canvas_drawTextRSXform]
+SkCanvas
+void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint);
+
+[Canvas_drawVertices]
+SkCanvas
+void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint);
+
+[Canvas_drawVertices_2]
+SkCanvas
+void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint);
+
+[Canvas_PointMode]
+SkCanvas
+enum PointMode { kPoints_PointMode, kLines_PointMode, kPolygon_PointMode, };
+
+[Canvas_kInitWithPrevious_SaveLayerFlag]
+SkCanvas
+enum SaveLayerFlagsSet { kPreserveLCDText_SaveLayerFlag = 1 << 1, kInitWithPrevious_SaveLayerFlag = 1 << 2, };
+
+[Canvas_SrcRectConstraint]
+SkCanvas
+enum SrcRectConstraint { kStrict_SrcRectConstraint, kFast_SrcRectConstraint, };
+
+[Canvas_getBaseLayerSize]
+SkCanvas
+virtual SkISize getBaseLayerSize() const;
+
+[Canvas_getDeviceClipBounds]
+SkCanvas
+SkIRect getDeviceClipBounds() const;
+
+[Canvas_getDeviceClipBounds_2]
+SkCanvas
+bool getDeviceClipBounds(SkIRect* bounds) const;
+
+[Canvas_getGrContext]
+SkCanvas
+virtual GrContext* getGrContext();
+
+[Canvas_getLocalClipBounds]
+SkCanvas
+SkRect getLocalClipBounds() const;
+
+[Canvas_getLocalClipBounds_2]
+SkCanvas
+bool getLocalClipBounds(SkRect* bounds) const;
+
+[Canvas_getProps]
+SkCanvas
+bool getProps(SkSurfaceProps* props) const;
+
+[Canvas_getSaveCount]
+SkCanvas
+int getSaveCount() const;
+
+[Canvas_getTotalMatrix]
+[Clip]
+SkCanvas
+const SkMatrix& getTotalMatrix() const;
+
+[Canvas_imageInfo]
+SkCanvas
+SkImageInfo imageInfo() const;
+
+[Canvas_isClipEmpty]
+SkCanvas
+virtual bool isClipEmpty() const;
+
+[Canvas_isClipRect]
+SkCanvas
+virtual bool isClipRect() const;
+
+[Canvas_makeSurface]
+SkCanvas
+sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr);
+
+[Canvas_peekPixels]
+SkCanvas
+bool peekPixels(SkPixmap* pixmap);
+
+[Canvas_quickReject_2]
+SkCanvas
+bool quickReject(const SkPath& path) const;
+
+[Canvas_quickReject]
+SkCanvas
+bool quickReject(const SkRect& rect) const;
+
+[Canvas_readPixels_3]
+SkCanvas
+bool readPixels(const SkBitmap& bitmap, int srcX, int srcY);
+
+[Canvas_readPixels_a]
+[Canvas_readPixels_b]
+SkCanvas
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY);
+
+[Canvas_readPixels_2]
+SkCanvas
+bool readPixels(const SkPixmap& pixmap, int srcX, int srcY);
+
+[Canvas_resetMatrix]
+SkCanvas
+void resetMatrix();
+
+[Canvas_restore]
+SkCanvas
+void restore();
+
+[Canvas_restoreToCount]
+SkCanvas
+void restoreToCount(int saveCount);
+
+[Canvas_rotate]
+SkCanvas
+void rotate(SkScalar degrees);
+
+[Canvas_rotate_2]
+SkCanvas
+void rotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+[Canvas_save]
+SkCanvas
+int save();
+
+[Canvas_saveLayer_3]
+SkCanvas
+int saveLayer(const SaveLayerRec& layerRec);
+
+[Canvas_saveLayer_2]
+SkCanvas
+int saveLayer(const SkRect& bounds, const SkPaint* paint);
+
+[Canvas_saveLayer]
+SkCanvas
+int saveLayer(const SkRect* bounds, const SkPaint* paint);
+
+[Canvas_saveLayerAlpha]
+SkCanvas
+int saveLayerAlpha(const SkRect* bounds, U8CPU alpha);
+
+[Canvas_saveLayerPreserveLCDTextRequests]
+SkCanvas
+int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint);
+
+[Canvas_scale]
+SkCanvas
+void scale(SkScalar sx, SkScalar sy);
+
+[Canvas_setMatrix]
+SkCanvas
+void setMatrix(const SkMatrix& matrix);
+
+[Canvas_skew]
+SkCanvas
+void skew(SkScalar sx, SkScalar sy);
+
+[Canvas_translate]
+SkCanvas
+void translate(SkScalar dx, SkScalar dy);
+
+[Canvas_writePixels_2]
+[State_Stack_a]
+[State_Stack_b]
+SkCanvas
+bool writePixels(const SkBitmap& bitmap, int x, int y);
+
+[Canvas_writePixels]
+SkCanvas
+bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y);
+
+[Canvas_destructor]
+SkCanvas
+virtual ~SkCanvas();
+
+[ColorGetA]
+SkColor
+#define SkColorGetA(color) (((color) >> 24) & 0xFF) color;
+
+[ColorGetB]
+SkColor
+#define SkColorGetB(color) (((color) >> 0) & 0xFF) color;
+
+[ColorGetG]
+SkColor
+#define SkColorGetG(color) (((color) >> 8) & 0xFF) color;
+
+[ColorGetR]
+SkColor
+#define SkColorGetR(color) (((color) >> 16) & 0xFF) color;
+
+[ColorSetA]
+SkColor
+static constexpr inline SkColor SkColorSetA(SkColor c, U8CPU a);
+
+[ColorSetRGB]
+SkColor
+#define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b) r g b;
+
+[ColorSetARGB]
+SkColor
+static constexpr inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+[ColorToHSV]
+SkColor
+static void SkColorToHSV(SkColor color, SkScalar hsv[3]);
+
+[HSVToColor]
+SkColor
+SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]);
+
+[HSVToColor_2]
+SkColor
+static SkColor SkHSVToColor(const SkScalar hsv[3]);
+
+[PreMultiplyARGB]
+SkColor
+SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+[PreMultiplyColor]
+SkColor
+SkPMColor SkPreMultiplyColor(SkColor c);
+
+[RGBToHSV]
+SkColor
+void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]);
+
+[Alpha_Constants_a]
+[Alpha_Constants_b]
+SkColor
+constexpr SkAlpha SK_AlphaTRANSPARENT = 0x00; constexpr SkAlpha SK_AlphaOPAQUE = 0xFF;
+
+[Color_Constants_a]
+[Color_Constants_b]
+[Color_Constants_c]
+[Color_Constants_d]
+SkColor
+constexpr SkColor SK_ColorTRANSPARENT; constexpr SkColor SK_ColorBLACK; constexpr SkColor SK_ColorDKGRAY; constexpr SkColor SK_ColorGRAY; constexpr SkColor SK_ColorLTGRAY; constexpr SkColor SK_ColorWHITE; constexpr SkColor SK_ColorRED; constexpr SkColor SK_ColorGREEN; constexpr SkColor SK_ColorBLUE; constexpr SkColor SK_ColorYELLOW; constexpr SkColor SK_ColorCYAN; constexpr SkColor SK_ColorMAGENTA;
+
+[RGBA4f_FromColor]
+SkColor4f
+static SkRGBA4f FromColor(SkColor color);
+
+[RGBA4f_notequal1_operator]
+SkColor4f
+bool operator!=(const SkRGBA4f& other) const;
+
+[RGBA4f_equal1_operator]
+SkColor4f
+bool operator==(const SkRGBA4f& other) const;
+
+[RGBA4f_toSkColor]
+SkColor4f
+SkColor toSkColor() const;
+
+[RGBA4f_vec]
+SkColor4f
+const float* vec() const;
+
+[RGBA4f_vec_2]
+SkColor4f
+float* vec();
+
+[Font_breakText]
+SkFont
+size_t breakText(const void* text, size_t length, SkTextEncoding encoding, SkScalar maxWidth, SkScalar* measuredWidth = nullptr) const;
+
+[IPoint_Make]
+SkIPoint
+static constexpr SkIPoint Make(int32_t x, int32_t y);
+
+[IPoint_equals]
+SkIPoint
+bool equals(int32_t x, int32_t y) const;
+
+[IPoint_isZero]
+SkIPoint
+bool isZero() const;
+
+[IPoint_notequal_operator]
+SkIPoint
+bool operator!=(const SkIPoint& a, const SkIPoint& b);
+
+[IPoint_add_operator]
+SkIPoint
+SkIPoint operator+(const SkIPoint& a, const SkIVector& b);
+
+[IPoint_addto_operator]
+SkIPoint
+void operator+=(const SkIVector& v);
+
+[IPoint_minus_operator]
+SkIPoint
+SkIPoint operator-() const;
+
+[IPoint_subtract_operator]
+SkIPoint
+SkIVector operator-(const SkIPoint& a, const SkIPoint& b);
+
+[IPoint_subtractfrom_operator]
+SkIPoint
+void operator-=(const SkIVector& v);
+
+[IPoint_equal_operator]
+SkIPoint
+bool operator==(const SkIPoint& a, const SkIPoint& b);
+
+[IPoint_set]
+SkIPoint
+void set(int32_t x, int32_t y);
+
+[IPoint_x]
+SkIPoint
+int32_t x() const;
+
+[IPoint_y]
+SkIPoint
+int32_t y() const;
+
+[IRect_EmptyIRect]
+SkIRect
+static const SkIRect& EmptyIRect();
+
+[IRect_Intersects]
+SkIRect
+static bool Intersects(const SkIRect& a, const SkIRect& b);
+
+[IRect_IntersectsNoEmptyCheck]
+SkIRect
+static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b);
+
+[IRect_MakeEmpty]
+SkIRect
+static constexpr SkIRect MakeEmpty();
+
+[IRect_MakeLTRB]
+SkIRect
+static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b);
+
+[IRect_MakeSize]
+SkIRect
+static constexpr SkIRect MakeSize(const SkISize& size);
+
+[IRect_MakeWH]
+SkIRect
+static constexpr SkIRect MakeWH(int32_t w, int32_t h);
+
+[IRect_MakeXYWH]
+SkIRect
+static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h);
+
+[IRect_adjust]
+SkIRect
+void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB);
+
+[IRect_bottom]
+SkIRect
+int32_t bottom() const;
+
+[IRect_contains_3]
+SkIRect
+bool contains(const SkIRect& r) const;
+
+[IRect_contains_4]
+SkIRect
+bool contains(const SkRect& r) const;
+
+[IRect_contains_2]
+SkIRect
+bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const;
+
+[IRect_contains]
+SkIRect
+bool contains(int32_t x, int32_t y) const;
+
+[IRect_containsNoEmptyCheck_2]
+SkIRect
+bool containsNoEmptyCheck(const SkIRect& r) const;
+
+[IRect_containsNoEmptyCheck]
+SkIRect
+bool containsNoEmptyCheck(int32_t left, int32_t top, int32_t right, int32_t bottom) const;
+
+[IRect_height]
+SkIRect
+int32_t height() const;
+
+[IRect_height64]
+SkIRect
+int64_t height64() const;
+
+[IRect_inset]
+SkIRect
+void inset(int32_t dx, int32_t dy);
+
+[IRect_intersect_2]
+SkIRect
+bool intersect(const SkIRect& a, const SkIRect& b);
+
+[IRect_intersect]
+SkIRect
+bool intersect(const SkIRect& r);
+
+[IRect_intersect_3]
+SkIRect
+bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom);
+
+[IRect_intersectNoEmptyCheck]
+SkIRect
+bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b);
+
+[IRect_isEmpty]
+SkIRect
+bool isEmpty() const;
+
+[IRect_isEmpty64]
+SkIRect
+bool isEmpty64() const;
+
+[IRect_join_2]
+SkIRect
+void join(const SkIRect& r);
+
+[IRect_join]
+SkIRect
+void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
+
+[IRect_left]
+SkIRect
+int32_t left() const;
+
+[IRect_makeInset]
+SkIRect
+SkIRect makeInset(int32_t dx, int32_t dy) const;
+
+[IRect_makeOffset]
+SkIRect
+SkIRect makeOffset(int32_t dx, int32_t dy) const;
+
+[IRect_makeOutset]
+SkIRect
+SkIRect makeOutset(int32_t dx, int32_t dy) const;
+
+[IRect_makeSorted]
+SkIRect
+SkIRect makeSorted() const;
+
+[IRect_offset_2]
+SkIRect
+void offset(const SkIPoint& delta);
+
+[IRect_offset]
+SkIRect
+void offset(int32_t dx, int32_t dy);
+
+[IRect_offsetTo]
+SkIRect
+void offsetTo(int32_t newX, int32_t newY);
+
+[IRect_notequal_operator]
+SkIRect
+bool operator!=(const SkIRect& a, const SkIRect& b);
+
+[IRect_equal_operator]
+SkIRect
+bool operator==(const SkIRect& a, const SkIRect& b);
+
+[IRect_outset]
+SkIRect
+void outset(int32_t dx, int32_t dy);
+
+[IRect_right]
+SkIRect
+int32_t right() const;
+
+[IRect_set]
+SkIRect
+void set(int32_t left, int32_t top, int32_t right, int32_t bottom);
+
+[IRect_setEmpty]
+SkIRect
+void setEmpty();
+
+[IRect_setLTRB]
+SkIRect
+void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom);
+
+[IRect_setXYWH]
+SkIRect
+void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height);
+
+[IRect_size]
+SkIRect
+SkISize size() const;
+
+[IRect_sort]
+SkIRect
+void sort();
+
+[IRect_top]
+SkIRect
+int32_t top() const;
+
+[IRect_width]
+SkIRect
+int32_t width() const;
+
+[IRect_width64]
+SkIRect
+int64_t width64() const;
+
+[IRect_x]
+SkIRect
+int32_t x() const;
+
+[IRect_y]
+SkIRect
+int32_t y() const;
+
+[Image_MakeBackendTextureFromSkImage]
+SkImage
+static bool MakeBackendTextureFromSkImage(GrContext* context, sk_sp<SkImage> image, GrBackendTexture* backendTexture, BackendTextureReleaseProc* backendTextureReleaseProc);
+
+[Image_MakeCrossContextFromPixmap]
+SkImage
+static sk_sp<SkImage> MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap, bool buildMips, bool limitToMaxTextureSize = false);
+
+[Image_MakeFromAdoptedTexture]
+SkImage
+static sk_sp<SkImage> MakeFromAdoptedTexture(GrContext* context, const GrBackendTexture& backendTexture, GrSurfaceOrigin surfaceOrigin, SkColorType colorType, SkAlphaType alphaType = kPremul_SkAlphaType, sk_sp<SkColorSpace> colorSpace = nullptr);
+
+[Image_MakeFromBitmap]
+SkImage
+static sk_sp<SkImage> MakeFromBitmap(const SkBitmap& bitmap);
+
+[Image_MakeFromEncoded]
+SkImage
+static sk_sp<SkImage> MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset = nullptr);
+
+[Image_MakeFromGenerator]
+SkImage
+static sk_sp<SkImage> MakeFromGenerator(std::unique_ptr<SkImageGenerator> imageGenerator, const SkIRect* subset = nullptr);
+
+[Image_MakeFromPicture]
+SkImage
+static sk_sp<SkImage> MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions, const SkMatrix* matrix, const SkPaint* paint, BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace);
+
+[Image_MakeFromRaster]
+SkImage
+static sk_sp<SkImage> MakeFromRaster(const SkPixmap& pixmap, RasterReleaseProc rasterReleaseProc, ReleaseContext releaseContext);
+
+[Image_MakeFromTexture]
+SkImage
+static sk_sp<SkImage> MakeFromTexture(GrContext* context, const GrBackendTexture& backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace);
+
+[Image_MakeFromTexture_2]
+SkImage
+static sk_sp<SkImage> MakeFromTexture(GrContext* context, const GrBackendTexture& backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace, TextureReleaseProc textureReleaseProc, ReleaseContext releaseContext);
+
+[Image_MakeRasterCopy]
+SkImage
+static sk_sp<SkImage> MakeRasterCopy(const SkPixmap& pixmap);
+
+[Image_MakeRasterData]
+SkImage
+static sk_sp<SkImage> MakeRasterData(const SkImageInfo& info, sk_sp<SkData> pixels, size_t rowBytes);
+
+[Image_alphaType]
+SkImage
+SkAlphaType alphaType() const;
+
+[Image_bounds]
+SkImage
+SkIRect bounds() const;
+
+[Image_colorSpace]
+SkImage
+SkColorSpace* colorSpace() const;
+
+[Image_colorType]
+SkImage
+SkColorType colorType() const;
+
+[Image_dimensions]
+SkImage
+SkISize dimensions() const;
+
+[Image_encodeToData_2]
+SkImage
+sk_sp<SkData> encodeToData() const;
+
+[Image_encodeToData]
+SkImage
+sk_sp<SkData> encodeToData(SkEncodedImageFormat encodedImageFormat, int quality) const;
+
+[Image_getBackendTexture]
+SkImage
+GrBackendTexture getBackendTexture(bool flushPendingGrContextIO, GrSurfaceOrigin* origin = nullptr) const;
+
+[Image_height]
+SkImage
+int height() const;
+
+[Image_isAlphaOnly]
+SkImage
+bool isAlphaOnly() const;
+
+[Image_isLazyGenerated_a]
+[Image_isLazyGenerated_b]
+SkImage
+bool isLazyGenerated() const;
+
+[Image_isOpaque]
+SkImage
+bool isOpaque() const;
+
+[Image_isTextureBacked]
+SkImage
+bool isTextureBacked() const;
+
+[Image_isValid]
+SkImage
+bool isValid(GrContext* context) const;
+
+[Image_makeColorSpace]
+SkImage
+sk_sp<SkImage> makeColorSpace(sk_sp<SkColorSpace> target) const;
+
+[Image_makeNonTextureImage]
+SkImage
+sk_sp<SkImage> makeNonTextureImage() const;
+
+[Image_makeRasterImage]
+SkImage
+sk_sp<SkImage> makeRasterImage() const;
+
+[Image_makeShader]
+SkImage
+sk_sp<SkShader> makeShader(SkShader::TileMode tileMode1, SkShader::TileMode tileMode2, const SkMatrix* localMatrix = nullptr) const;
+
+[Image_makeShader_2]
+SkImage
+sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const;
+
+[Image_makeSubset]
+SkImage
+sk_sp<SkImage> makeSubset(const SkIRect& subset) const;
+
+[Image_makeTextureImage]
+SkImage
+sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace, GrMipMapped mipMapped = GrMipMapped::kNo) const;
+
+[Image_makeWithFilter]
+SkImage
+sk_sp<SkImage> makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, const SkIRect& clipBounds, SkIRect* outSubset, SkIPoint* offset) const;
+
+[Image_peekPixels]
+SkImage
+bool peekPixels(SkPixmap* pixmap) const;
+
+[Image_readPixels]
+SkImage
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint = kAllow_CachingHint) const;
+
+[Image_readPixels_2]
+SkImage
+bool readPixels(const SkPixmap& dst, int srcX, int srcY, CachingHint cachingHint = kAllow_CachingHint) const;
+
+[Image_refColorSpace]
+SkImage
+sk_sp<SkColorSpace> refColorSpace() const;
+
+[Image_refEncodedData]
+SkImage
+sk_sp<SkData> refEncodedData() const;
+
+[Image_scalePixels]
+SkImage
+bool scalePixels(const SkPixmap& dst, SkFilterQuality filterQuality, CachingHint cachingHint = kAllow_CachingHint) const;
+
+[Image_uniqueID]
+SkImage
+uint32_t uniqueID() const;
+
+[Image_width]
+SkImage
+int width() const;
+
+[ImageInfo_ByteSizeOverflowed]
+SkImageInfo
+static bool ByteSizeOverflowed(size_t byteSize);
+
+[ImageInfo_Make]
+SkImageInfo
+static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs = nullptr);
+
+[ImageInfo_MakeA8]
+SkImageInfo
+static SkImageInfo MakeA8(int width, int height);
+
+[ImageInfo_MakeN32]
+SkImageInfo
+static SkImageInfo MakeN32(int width, int height, SkAlphaType at, sk_sp<SkColorSpace> cs = nullptr);
+
+[ImageInfo_MakeN32Premul_2]
+SkImageInfo
+static SkImageInfo MakeN32Premul(const SkISize& size);
+
+[ImageInfo_MakeN32Premul]
+SkImageInfo
+static SkImageInfo MakeN32Premul(int width, int height, sk_sp<SkColorSpace> cs = nullptr);
+
+[ImageInfo_MakeS32]
+SkImageInfo
+static SkImageInfo MakeS32(int width, int height, SkAlphaType at);
+
+[ImageInfo_MakeUnknown_2]
+SkImageInfo
+static SkImageInfo MakeUnknown();
+
+[ImageInfo_MakeUnknown]
+SkImageInfo
+static SkImageInfo MakeUnknown(int width, int height);
+
+[ColorTypeBytesPerPixel]
+SkImageInfo
+int SkColorTypeBytesPerPixel(SkColorType ct);
+
+[ColorTypeIsAlwaysOpaque]
+SkImageInfo
+bool SkColorTypeIsAlwaysOpaque(SkColorType ct);
+
+[ColorTypeValidateAlphaType]
+SkImageInfo
+bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, SkAlphaType* canonical = nullptr);
+
+[ImageInfo_empty_constructor]
+SkImageInfo
+SkImageInfo();
+
+[ImageInfo_alphaType]
+SkImageInfo
+SkAlphaType alphaType() const;
+
+[ImageInfo_bounds]
+SkImageInfo
+SkIRect bounds() const;
+
+[ImageInfo_bytesPerPixel]
+SkImageInfo
+int bytesPerPixel() const;
+
+[ImageInfo_colorSpace]
+SkImageInfo
+SkColorSpace* colorSpace() const;
+
+[ImageInfo_colorType]
+SkImageInfo
+SkColorType colorType() const;
+
+[ImageInfo_computeByteSize]
+SkImageInfo
+size_t computeByteSize(size_t rowBytes) const;
+
+[ImageInfo_computeMinByteSize]
+SkImageInfo
+size_t computeMinByteSize() const;
+
+[ImageInfo_computeOffset]
+SkImageInfo
+size_t computeOffset(int x, int y, size_t rowBytes) const;
+
+[ImageInfo_dimensions]
+SkImageInfo
+SkISize dimensions() const;
+
+[Alpha_Type_Opaque]
+SkImageInfo
+enum SkAlphaType { kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType, kLastEnum_SkAlphaType = kUnpremul_SkAlphaType, };
+
+[Color_Type_ARGB_4444]
+[Color_Type_Alpha_8]
+[Color_Type_BGRA_8888]
+[Color_Type_Gray_8]
+[Color_Type_RGBA_1010102]
+[Color_Type_RGBA_8888]
+[Color_Type_RGBA_F16]
+[Color_Type_RGB_101010]
+[Color_Type_RGB_565]
+[Color_Type_RGB_888]
+SkImageInfo
+enum SkColorType { kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType, kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType, kGray_8_SkColorType, kRGBA_F16_SkColorType, kRGBA_F32_SkColorType, kLastEnum_SkColorType = kRGBA_F32_SkColorType, kN32_SkColorType = kBGRA_8888_SkColorType, kN32_SkColorType = kRGBA_8888_SkColorType, };
+
+[ImageInfo_gammaCloseToSRGB]
+SkImageInfo
+bool gammaCloseToSRGB() const;
+
+[ImageInfo_height]
+SkImageInfo
+int height() const;
+
+[ImageInfo_isEmpty]
+SkImageInfo
+bool isEmpty() const;
+
+[ImageInfo_isOpaque]
+SkImageInfo
+bool isOpaque() const;
+
+[ImageInfo_makeAlphaType]
+SkImageInfo
+SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const;
+
+[ImageInfo_makeColorSpace]
+SkImageInfo
+SkImageInfo makeColorSpace(sk_sp<SkColorSpace> cs) const;
+
+[ImageInfo_makeColorType]
+SkImageInfo
+SkImageInfo makeColorType(SkColorType newColorType) const;
+
+[ImageInfo_makeWH]
+SkImageInfo
+SkImageInfo makeWH(int newWidth, int newHeight) const;
+
+[ImageInfo_minRowBytes]
+SkImageInfo
+size_t minRowBytes() const;
+
+[ImageInfo_minRowBytes64]
+SkImageInfo
+uint64_t minRowBytes64() const;
+
+[ImageInfo_notequal1_operator]
+SkImageInfo
+bool operator!=(const SkImageInfo& other) const;
+
+[ImageInfo_equal1_operator]
+SkImageInfo
+bool operator==(const SkImageInfo& other) const;
+
+[ImageInfo_refColorSpace]
+SkImageInfo
+sk_sp<SkColorSpace> refColorSpace() const;
+
+[ImageInfo_reset]
+SkImageInfo
+void reset();
+
+[ImageInfo_shiftPerPixel]
+SkImageInfo
+int shiftPerPixel() const;
+
+[Alpha_Type_Premul]
+SkImageInfo
+stored color = original color * alpha / max alpha;
+
+[Alpha_Type_Unpremul]
+SkImageInfo
+stored color = original color * alpha / max alpha;
+
+[ImageInfo_validRowBytes]
+SkImageInfo
+bool validRowBytes(size_t rowBytes) const;
+
+[ImageInfo_width]
+SkImageInfo
+int width() const;
+
+[Matrix_Concat]
+SkMatrix
+static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b);
+
+[Matrix_I]
+SkMatrix
+static const SkMatrix& I();
+
+[Matrix_063]
+SkMatrix
+| sx 0 0 | | J K L | | sx*J sx*K sx*L | I(divx, divy) * Matrix = | 0 sy 0 | | M N O | = | sy*M sy*N sy*O | | 0 0 1 | | P Q R | | P Q R |;
+
+[Matrix_InvalidMatrix]
+SkMatrix
+static const SkMatrix& InvalidMatrix();
+
+[Matrix_MakeAll]
+SkMatrix
+static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2);
+
+[Matrix_MakeRectToRect]
+SkMatrix
+static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
+
+[Matrix_MakeScale_2]
+SkMatrix
+static SkMatrix MakeScale(SkScalar scale);
+
+[Matrix_MakeScale]
+SkMatrix
+static SkMatrix MakeScale(SkScalar sx, SkScalar sy);
+
+[Matrix_MakeTrans]
+SkMatrix
+static SkMatrix MakeTrans(SkScalar dx, SkScalar dy);
+
+[Matrix_SetAffineIdentity]
+SkMatrix
+static void SetAffineIdentity(SkScalar affine[6]);
+
+[Matrix_asAffine]
+SkMatrix
+bool asAffine(SkScalar affine[6]) const;
+
+[Matrix_cheapEqualTo]
+SkMatrix
+bool cheapEqualTo(const SkMatrix& m) const;
+
+[Matrix_decomposeScale]
+SkMatrix
+bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const;
+
+[Matrix_dirtyMatrixTypeCache]
+SkMatrix
+void dirtyMatrixTypeCache();
+
+[Matrix_dump]
+SkMatrix
+void dump() const;
+
+[Matrix_ScaleToFit]
+SkMatrix
+enum ScaleToFit { kFill_ScaleToFit, kStart_ScaleToFit, kCenter_ScaleToFit, kEnd_ScaleToFit, };
+
+[Matrix_TypeMask]
+SkMatrix
+enum TypeMask { kIdentity_Mask = 0, kTranslate_Mask = 0x01, kScale_Mask = 0x02, kAffine_Mask = 0x04, kPerspective_Mask = 0x08, };
+
+[Matrix_fixedStepInX]
+SkMatrix
+SkVector fixedStepInX(SkScalar y) const;
+
+[Matrix_get]
+SkMatrix
+SkScalar get(int index) const;
+
+[Matrix_get9]
+SkMatrix
+void get9(SkScalar buffer[9]) const;
+
+[Matrix_getMaxScale]
+SkMatrix
+SkScalar getMaxScale() const;
+
+[Matrix_getMinMaxScales]
+SkMatrix
+bool getMinMaxScales(SkScalar scaleFactors[2]) const;
+
+[Matrix_getMinScale]
+SkMatrix
+SkScalar getMinScale() const;
+
+[Matrix_getPerspX]
+SkMatrix
+SkScalar getPerspX() const;
+
+[Matrix_getPerspY]
+SkMatrix
+SkScalar getPerspY() const;
+
+[Matrix_getScaleX]
+SkMatrix
+SkScalar getScaleX() const;
+
+[Matrix_getScaleY]
+SkMatrix
+SkScalar getScaleY() const;
+
+[Matrix_getSkewX]
+SkMatrix
+SkScalar getSkewX() const;
+
+[Matrix_getSkewY]
+SkMatrix
+SkScalar getSkewY() const;
+
+[Matrix_getTranslateX]
+SkMatrix
+SkScalar getTranslateX() const;
+
+[Matrix_getTranslateY]
+SkMatrix
+SkScalar getTranslateY() const;
+
+[Matrix_getType]
+SkMatrix
+TypeMask getType() const;
+
+[Matrix_hasPerspective]
+SkMatrix
+bool hasPerspective() const;
+
+[Matrix_invert]
+SkMatrix
+bool invert(SkMatrix* inverse) const;
+
+[Matrix_isFinite]
+SkMatrix
+bool isFinite() const;
+
+[Matrix_isFixedStepInX]
+SkMatrix
+bool isFixedStepInX() const;
+
+[Matrix_isIdentity]
+SkMatrix
+bool isIdentity() const;
+
+[Matrix_isScaleTranslate]
+SkMatrix
+bool isScaleTranslate() const;
+
+[Matrix_isSimilarity]
+SkMatrix
+bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
+
+[Matrix_isTranslate]
+SkMatrix
+bool isTranslate() const;
+
+[Matrix_mapHomogeneousPoints]
+SkMatrix
+void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const;
+
+[Matrix_mapPoints]
+SkMatrix
+void mapPoints(SkPoint dst[], const SkPoint src[], int count) const;
+
+[Matrix_mapPoints_2]
+SkMatrix
+void mapPoints(SkPoint pts[], int count) const;
+
+[Matrix_mapRadius]
+SkMatrix
+SkScalar mapRadius(SkScalar radius) const;
+
+[Matrix_mapRect_3]
+SkMatrix
+SkRect mapRect(const SkRect& src) const;
+
+[Matrix_mapRect]
+SkMatrix
+bool mapRect(SkRect* dst, const SkRect& src) const;
+
+[Matrix_mapRect_2]
+SkMatrix
+bool mapRect(SkRect* rect) const;
+
+[Matrix_mapRectScaleTranslate]
+SkMatrix
+void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
+
+[Matrix_mapRectToQuad]
+SkMatrix
+void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const;
+
+[Matrix_mapVector_2]
+SkMatrix
+SkVector mapVector(SkScalar dx, SkScalar dy) const;
+
+[Matrix_mapVector]
+SkMatrix
+void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const;
+
+[Matrix_mapVectors]
+SkMatrix
+void mapVectors(SkVector dst[], const SkVector src[], int count) const;
+
+[Matrix_mapVectors_2]
+SkMatrix
+void mapVectors(SkVector vecs[], int count) const;
+
+[Matrix_mapXY_2]
+SkMatrix
+SkPoint mapXY(SkScalar x, SkScalar y) const;
+
+[Matrix_mapXY]
+SkMatrix
+void mapXY(SkScalar x, SkScalar y, SkPoint* result) const;
+
+[Matrix_notequal_operator]
+SkMatrix
+bool operator!=(const SkMatrix& a, const SkMatrix& b);
+
+[Matrix_equal_operator]
+SkMatrix
+bool operator==(const SkMatrix& a, const SkMatrix& b);
+
+[Matrix_array_operator]
+SkMatrix
+SkScalar operator[](int index) const;
+
+[Matrix_dirtyMatrixTypeCache]
+SkMatrix
+SkScalar& operator[](int index);
+
+[Matrix_postConcat]
+SkMatrix
+void postConcat(const SkMatrix& other);
+
+[Matrix_postRotate_2]
+SkMatrix
+void postRotate(SkScalar degrees);
+
+[Matrix_postRotate]
+SkMatrix
+void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+[Matrix_postScale_2]
+SkMatrix
+void postScale(SkScalar sx, SkScalar sy);
+
+[Matrix_postScale]
+SkMatrix
+void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+[Matrix_postSkew_2]
+SkMatrix
+void postSkew(SkScalar kx, SkScalar ky);
+
+[Matrix_postSkew]
+SkMatrix
+void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+[Matrix_postTranslate]
+SkMatrix
+void postTranslate(SkScalar dx, SkScalar dy);
+
+[Matrix_preConcat]
+SkMatrix
+void preConcat(const SkMatrix& other);
+
+[Matrix_preRotate_2]
+SkMatrix
+void preRotate(SkScalar degrees);
+
+[Matrix_preRotate]
+SkMatrix
+void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+[Matrix_preScale_2]
+SkMatrix
+void preScale(SkScalar sx, SkScalar sy);
+
+[Matrix_preScale]
+SkMatrix
+void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+[Matrix_preSkew_2]
+SkMatrix
+void preSkew(SkScalar kx, SkScalar ky);
+
+[Matrix_preSkew]
+SkMatrix
+void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+[Matrix_preTranslate]
+SkMatrix
+void preTranslate(SkScalar dx, SkScalar dy);
+
+[Matrix_preservesAxisAlignment]
+SkMatrix
+bool preservesAxisAlignment() const;
+
+[Matrix_preservesRightAngles]
+SkMatrix
+bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
+
+[Matrix_rectStaysRect]
+SkMatrix
+bool rectStaysRect() const;
+
+[Matrix_reset]
+SkMatrix
+void reset();
+
+[Matrix_set]
+SkMatrix
+void set(int index, SkScalar value);
+
+[Matrix_set9]
+SkMatrix
+void set9(const SkScalar buffer[9]);
+
+[Matrix_setAffine]
+SkMatrix
+void setAffine(const SkScalar affine[6]);
+
+[Matrix_setAll]
+SkMatrix
+void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2);
+
+[Matrix_setConcat]
+SkMatrix
+void setConcat(const SkMatrix& a, const SkMatrix& b);
+
+[Matrix_setIdentity]
+SkMatrix
+void setIdentity();
+
+[Matrix_setPerspX]
+SkMatrix
+void setPerspX(SkScalar v);
+
+[Matrix_setPerspY]
+SkMatrix
+void setPerspY(SkScalar v);
+
+[Matrix_setPolyToPoly]
+SkMatrix
+bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
+
+[Matrix_setRSXform]
+SkMatrix
+SkMatrix& setRSXform(const SkRSXform& rsxForm);
+
+[Matrix_setRectToRect]
+SkMatrix
+bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
+
+[Matrix_setRotate_2]
+SkMatrix
+void setRotate(SkScalar degrees);
+
+[Matrix_setRotate]
+SkMatrix
+void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+[Matrix_setScale_2]
+SkMatrix
+void setScale(SkScalar sx, SkScalar sy);
+
+[Matrix_setScale]
+SkMatrix
+void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+[Matrix_setScaleTranslate]
+SkMatrix
+void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty);
+
+[Matrix_setScaleX]
+SkMatrix
+void setScaleX(SkScalar v);
+
+[Matrix_setScaleY]
+SkMatrix
+void setScaleY(SkScalar v);
+
+[Matrix_setSinCos_2]
+SkMatrix
+void setSinCos(SkScalar sinValue, SkScalar cosValue);
+
+[Matrix_setSinCos]
+SkMatrix
+void setSinCos(SkScalar sinValue, SkScalar cosValue, SkScalar px, SkScalar py);
+
+[Matrix_setSkew_2]
+SkMatrix
+void setSkew(SkScalar kx, SkScalar ky);
+
+[Matrix_setSkew]
+SkMatrix
+void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+[Matrix_setSkewX]
+SkMatrix
+void setSkewX(SkScalar v);
+
+[Matrix_setSkewY]
+SkMatrix
+void setSkewY(SkScalar v);
+
+[Matrix_setTranslate]
+SkMatrix
+void setTranslate(SkScalar dx, SkScalar dy);
+
+[Matrix_setTranslate_2]
+SkMatrix
+void setTranslate(const SkVector& v);
+
+[Matrix_setTranslateX]
+SkMatrix
+void setTranslateX(SkScalar v);
+
+[Matrix_setTranslateY]
+SkMatrix
+void setTranslateY(SkScalar v);
+
+[MemberIndex]
+SkMatrix
+static constexpr int kMScaleX = 0; static constexpr int kMSkewX = 1; static constexpr int kMTransX = 2; static constexpr int kMSkewY = 3; static constexpr int kMScaleY = 4; static constexpr int kMTransY = 5; static constexpr int kMPersp0 = 6; static constexpr int kMPersp1 = 7; static constexpr int kMPersp2 = 8;
+
+[Paint_empty_constructor]
+SkPaint
+SkPaint();
+
+[Paint_move_SkPaint]
+SkPaint
+SkPaint(SkPaint&& paint);
+
+[Paint_copy_const_SkPaint]
+SkPaint
+SkPaint(const SkPaint& paint);
+
+[Paint_containsText]
+SkPaint
+bool containsText(const void* text, size_t byteLength) const;
+
+[Paint_countText]
+SkPaint
+int countText(const void* text, size_t byteLength) const;
+
+[Paint_getAlpha]
+SkPaint
+uint8_t getAlpha() const;
+
+[Paint_getBlendMode]
+SkPaint
+SkBlendMode getBlendMode() const;
+
+[Paint_getColor]
+SkPaint
+SkColor getColor() const;
+
+[Paint_getColor4f]
+SkPaint
+SkColor4f getColor4f() const;
+
+[Paint_getColorFilter]
+SkPaint
+SkColorFilter* getColorFilter() const;
+
+[Paint_getDrawLooper]
+SkPaint
+SkDrawLooper* getDrawLooper() const;
+
+[Paint_getFillPath_2]
+[Shader_Methods_a]
+[Shader_Methods_b]
+SkPaint
+bool getFillPath(const SkPath& src, SkPath* dst) const;
+
+[Paint_getFillPath]
+SkPaint
+bool getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect, SkScalar resScale = 1) const;
+
+[Paint_getFilterQuality]
+SkPaint
+SkFilterQuality getFilterQuality() const;
+
+[Paint_getFlags]
+SkPaint
+uint32_t getFlags() const;
+
+[Paint_getFontMetrics]
+SkPaint
+SkScalar getFontMetrics(SkFontMetrics* metrics) const;
+
+[Paint_getFontSpacing]
+SkPaint
+SkScalar getFontSpacing() const;
+
+[Paint_getHash]
+SkPaint
+uint32_t getHash() const;
+
+[Paint_getHinting]
+SkPaint
+SkFontHinting getHinting() const;
+
+[Paint_getImageFilter]
+SkPaint
+SkImageFilter* getImageFilter() const;
+
+[Paint_getMaskFilter]
+SkPaint
+SkMaskFilter* getMaskFilter() const;
+
+[Paint_getPathEffect]
+SkPaint
+SkPathEffect* getPathEffect() const;
+
+[Paint_getPosTextPath]
+SkPaint
+void getPosTextPath(const void* text, size_t length, const SkPoint pos[], SkPath* path) const;
+
+[Paint_getShader]
+SkPaint
+SkShader* getShader() const;
+
+[Paint_getStrokeCap]
+SkPaint
+Cap getStrokeCap() const;
+
+[Paint_getStrokeJoin]
+SkPaint
+Join getStrokeJoin() const;
+
+[Paint_getStrokeMiter]
+SkPaint
+SkScalar getStrokeMiter() const;
+
+[Paint_getStrokeWidth]
+SkPaint
+SkScalar getStrokeWidth() const;
+
+[Paint_getStyle]
+SkPaint
+Style getStyle() const;
+
+[Paint_getTextEncoding]
+SkPaint
+SkTextEncoding getTextEncoding() const;
+
+[Paint_getTextPath]
+SkPaint
+void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y, SkPath* path) const;
+
+[Paint_getTextScaleX]
+SkPaint
+SkScalar getTextScaleX() const;
+
+[Paint_getTextSize]
+SkPaint
+SkScalar getTextSize() const;
+
+[Paint_getTextSkewX]
+SkPaint
+SkScalar getTextSkewX() const;
+
+[Paint_getTextWidths]
+SkPaint
+int getTextWidths(const void* text, size_t byteLength, SkScalar widths[], SkRect bounds[] = nullptr) const;
+
+[Paint_getTypeface]
+SkPaint
+SkTypeface* getTypeface() const;
+
+[Paint_isAntiAlias]
+SkPaint
+bool isAntiAlias() const;
+
+[Paint_isAutohinted]
+SkPaint
+bool isAutohinted() const;
+
+[Paint_isDither]
+SkPaint
+bool isDither() const;
+
+[Paint_isEmbeddedBitmapText]
+SkPaint
+bool isEmbeddedBitmapText() const;
+
+[Paint_isFakeBoldText]
+SkPaint
+bool isFakeBoldText() const;
+
+[Paint_isLCDRenderText]
+SkPaint
+bool isLCDRenderText() const;
+
+[Paint_isLinearText]
+SkPaint
+bool isLinearText() const;
+
+[Paint_setBlendMode]
+SkPaint
+bool isSrcOver() const;
+
+[Paint_isSubpixelText]
+SkPaint
+bool isSubpixelText() const;
+
+[Paint_measureText_2]
+SkPaint
+SkScalar measureText(const void* text, size_t length) const;
+
+[Paint_measureText]
+SkPaint
+SkScalar measureText(const void* text, size_t length, SkRect* bounds) const;
+
+[Paint_nothingToDraw]
+SkPaint
+bool nothingToDraw() const;
+
+[Paint_notequal_operator]
+SkPaint
+bool operator!=(const SkPaint& a, const SkPaint& b);
+
+[Paint_move_operator]
+SkPaint
+SkPaint& operator=(SkPaint&& paint);
+
+[Paint_copy_operator]
+SkPaint
+SkPaint& operator=(const SkPaint& paint);
+
+[Paint_equal_operator]
+SkPaint
+bool operator==(const SkPaint& a, const SkPaint& b);
+
+[Paint_refColorFilter]
+SkPaint
+sk_sp<SkColorFilter> refColorFilter() const;
+
+[Paint_refDrawLooper]
+SkPaint
+sk_sp<SkDrawLooper> refDrawLooper() const;
+
+[Paint_refImageFilter]
+SkPaint
+sk_sp<SkImageFilter> refImageFilter() const;
+
+[Paint_refMaskFilter]
+SkPaint
+sk_sp<SkMaskFilter> refMaskFilter() const;
+
+[Paint_refPathEffect]
+SkPaint
+sk_sp<SkPathEffect> refPathEffect() const;
+
+[Paint_refShader]
+SkPaint
+sk_sp<SkShader> refShader() const;
+
+[Paint_refTypeface]
+SkPaint
+sk_sp<SkTypeface> refTypeface() const;
+
+[Paint_reset]
+SkPaint
+void reset();
+
+[Paint_setARGB]
+SkPaint
+void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+[Paint_setAlpha]
+SkPaint
+void setAlpha(U8CPU a);
+
+[Dither_a]
+[Dither_b]
+[Paint_setAntiAlias]
+SkPaint
+void setAntiAlias(bool aa);
+
+[Fake_Bold]
+[Paint_setAutohinted]
+SkPaint
+void setAutohinted(bool useAutohinter);
+
+[Paint_setBlendMode]
+[Path_Effect_Methods]
+SkPaint
+void setBlendMode(SkBlendMode mode);
+
+[Paint_setColor]
+SkPaint
+void setColor(SkColor color);
+
+[Paint_setColor4f]
+SkPaint
+void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace);
+
+[Blend_Mode_Methods]
+[Paint_setColorFilter]
+SkPaint
+void setColorFilter(sk_sp<SkColorFilter> colorFilter);
+
+[Device_Text]
+[Paint_setDither]
+SkPaint
+void setDither(bool dither);
+
+[Paint_setDrawLooper]
+[Text_Size]
+SkPaint
+void setDrawLooper(sk_sp<SkDrawLooper> drawLooper);
+
+[Paint_setEmbeddedBitmapText]
+SkPaint
+void setEmbeddedBitmapText(bool useEmbeddedBitmapText);
+
+[Filter_Quality_Methods]
+[Paint_setFakeBoldText]
+SkPaint
+void setFakeBoldText(bool fakeBoldText);
+
+[Color_Methods]
+[Paint_setFilterQuality]
+SkPaint
+void setFilterQuality(SkFilterQuality quality);
+
+[Anti_Alias]
+[Paint_setFlags]
+SkPaint
+void setFlags(uint32_t flags);
+
+[Paint_setHinting]
+SkPaint
+void setHinting(SkFontHinting hintingLevel);
+
+[Draw_Looper_Methods]
+[Paint_setImageFilter]
+SkPaint
+void setImageFilter(sk_sp<SkImageFilter> imageFilter);
+
+[Paint_setLCDRenderText]
+SkPaint
+void setLCDRenderText(bool lcdText);
+
+[Paint_setLinearText]
+SkPaint
+void setLinearText(bool linearText);
+
+[Paint_setMaskFilter]
+[Typeface_Methods]
+SkPaint
+void setMaskFilter(sk_sp<SkMaskFilter> maskFilter);
+
+[Mask_Filter_Methods]
+[Paint_setPathEffect]
+SkPaint
+void setPathEffect(sk_sp<SkPathEffect> pathEffect);
+
+[Color_Filter_Methods]
+[Paint_setShader]
+SkPaint
+void setShader(sk_sp<SkShader> shader);
+
+[Paint_setStrokeCap_a]
+[Paint_setStrokeCap_b]
+SkPaint
+void setStrokeCap(Cap cap);
+
+[Paint_setStrokeJoin]
+SkPaint
+void setStrokeJoin(Join join);
+
+[Paint_setStrokeMiter]
+SkPaint
+void setStrokeMiter(SkScalar miter);
+
+[Miter_Limit]
+[Paint_setStrokeWidth]
+SkPaint
+void setStrokeWidth(SkScalar width);
+
+[Paint_setStyle]
+[Stroke_Width]
+SkPaint
+void setStyle(Style style);
+
+[Paint_setSubpixelText]
+SkPaint
+void setSubpixelText(bool subpixelText);
+
+[Paint_setTextEncoding]
+SkPaint
+void setTextEncoding(SkTextEncoding encoding);
+
+[Paint_setTextScaleX]
+[Text_Skew_X]
+SkPaint
+void setTextScaleX(SkScalar scaleX);
+
+[Paint_setTextSize]
+[Text_Scale_X]
+SkPaint
+void setTextSize(SkScalar textSize);
+
+[Paint_setTextSkewX]
+[Text_Encoding]
+SkPaint
+void setTextSkewX(SkScalar skewX);
+
+[Image_Filter_Methods]
+[Paint_setTypeface]
+SkPaint
+void setTypeface(sk_sp<SkTypeface> typeface);
+
+[Paint_053]
+SkPaint
+static constexpr int kCapCount = kLast_Cap + 1;
+
+[Paint_057]
+SkPaint
+static constexpr int kJoinCount = kLast_Join + 1;
+
+[Paint_textToGlyphs]
+SkPaint
+int textToGlyphs(const void* text, size_t byteLength, SkGlyphID glyphs[]) const;
+
+[Path_ConvertConicToQuads]
+SkPath
+static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, SkScalar w, SkPoint pts[], int pow2);
+
+[Path_ConvertToNonInverseFillType]
+SkPath
+static FillType ConvertToNonInverseFillType(FillType fill);
+
+[Path_IsCubicDegenerate]
+SkPath
+static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, const SkPoint& p4, bool exact);
+
+[Path_IsInverseFillType]
+SkPath
+static bool IsInverseFillType(FillType fill);
+
+[Path_IsLineDegenerate]
+SkPath
+static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact);
+
+[Path_IsQuadDegenerate]
+SkPath
+static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3, bool exact);
+
+[Path_Iter_Iter]
+SkPath
+Iter();
+
+[Path_Iter_const_SkPath]
+SkPath
+Iter(const SkPath& path, bool forceClose);
+
+[Path_empty_constructor]
+SkPath
+SkPath();
+
+[Path_copy_const_SkPath]
+SkPath
+SkPath(const SkPath& path);
+
+[Path_addArc]
+SkPath
+SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
+
+[Path_addCircle]
+SkPath
+SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius, Direction dir = kCW_Direction);
+
+[Path_addOval]
+SkPath
+SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction);
+
+[Path_addOval_2]
+SkPath
+SkPath& addOval(const SkRect& oval, Direction dir, unsigned start);
+
+[Path_addPath_2]
+SkPath
+SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode);
+
+[Path_addPath]
+SkPath
+SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy, AddPathMode mode = kAppend_AddPathMode);
+
+[Path_addPath_3]
+SkPath
+SkPath& addPath(const SkPath& src, const SkMatrix& matrix, AddPathMode mode = kAppend_AddPathMode);
+
+[Path_addPoly]
+SkPath
+SkPath& addPoly(const SkPoint pts[], int count, bool close);
+
+[Path_addPoly_2]
+SkPath
+SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close);
+
+[Path_addRRect]
+SkPath
+SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
+
+[Path_addRRect_2]
+SkPath
+SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start);
+
+[Path_addRect_3]
+SkPath
+SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, Direction dir = kCW_Direction);
+
+[Path_addRect]
+SkPath
+SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction);
+
+[Path_addRect_2]
+SkPath
+SkPath& addRect(const SkRect& rect, Direction dir, unsigned start);
+
+[Path_addRoundRect]
+SkPath
+SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Direction dir = kCW_Direction);
+
+[Path_addRoundRect_2]
+SkPath
+SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[], Direction dir = kCW_Direction);
+
+[Path_arcTo_4]
+SkPath
+SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar x, SkScalar y);
+
+[Path_arcTo_2_a]
+[Path_arcTo_2_b]
+[Path_arcTo_2_c]
+SkPath
+SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
+
+[Path_arcTo_3]
+SkPath
+SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius);
+
+[Path_rArcTo]
+SkPath
+SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, const SkPoint xy);
+
+[Path_arcTo]
+SkPath
+SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo);
+
+[Path_close]
+SkPath
+SkPath& close();
+
+[Path_computeTightBounds]
+SkPath
+SkRect computeTightBounds() const;
+
+[Path_conicTo]
+SkPath
+SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w);
+
+[Path_conicTo_2]
+SkPath
+SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w);
+
+[Path_Iter_conicWeight]
+[Path_RawIter_conicWeight]
+SkPath
+SkScalar conicWeight() const;
+
+[Path_conservativelyContainsRect]
+SkPath
+bool conservativelyContainsRect(const SkRect& rect) const;
+
+[Path_contains]
+SkPath
+bool contains(SkScalar x, SkScalar y) const;
+
+[Path_countPoints]
+SkPath
+int countPoints() const;
+
+[Path_countVerbs]
+SkPath
+int countVerbs() const;
+
+[Path_cubicTo]
+SkPath
+SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3);
+
+[Path_cubicTo_2]
+SkPath
+SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3);
+
+[Path_dump_2]
+SkPath
+void dump() const;
+
+[Path_dump]
+SkPath
+void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const;
+
+[Path_dumpHex]
+SkPath
+void dumpHex() const;
+
+[Path_AddPathMode]
+SkPath
+enum AddPathMode { kAppend_AddPathMode, kExtend_AddPathMode, };
+
+[Path_ArcSize]
+SkPath
+enum ArcSize { kSmall_ArcSize, kLarge_ArcSize, };
+
+[Path_Convexity]
+SkPath
+enum Convexity : uint8_t { kUnknown_Convexity, kConvex_Convexity, kConcave_Convexity, };
+
+[Path_Direction]
+SkPath
+enum Direction : int { kCW_Direction, kCCW_Direction, };
+
+[Path_FillType_a]
+[Path_FillType_b]
+SkPath
+enum FillType { kWinding_FillType, kEvenOdd_FillType, kInverseWinding_FillType, kInverseEvenOdd_FillType, };
+
+[Path_SegmentMask]
+SkPath
+enum SegmentMask { kLine_SegmentMask = 1 << 0, kQuad_SegmentMask = 1 << 1, kConic_SegmentMask = 1 << 2, kCubic_SegmentMask = 1 << 3, };
+
+[Path_Verb]
+SkPath
+enum Verb { kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb, kCubic_Verb, kClose_Verb, kDone_Verb, };
+
+[Path_getBounds]
+SkPath
+const SkRect& getBounds() const;
+
+[Path_getConvexity]
+SkPath
+Convexity getConvexity() const;
+
+[Path_getConvexityOrUnknown]
+SkPath
+Convexity getConvexityOrUnknown() const;
+
+[Path_getFillType]
+SkPath
+FillType getFillType() const;
+
+[Path_getGenerationID]
+SkPath
+uint32_t getGenerationID() const;
+
+[Path_getLastPt]
+SkPath
+bool getLastPt(SkPoint* lastPt) const;
+
+[Path_getPoint]
+SkPath
+SkPoint getPoint(int index) const;
+
+[Path_getPoints]
+SkPath
+int getPoints(SkPoint points[], int max) const;
+
+[Path_getSegmentMasks]
+SkPath
+uint32_t getSegmentMasks() const;
+
+[Path_getVerbs]
+SkPath
+int getVerbs(uint8_t verbs[], int max) const;
+
+[Path_incReserve]
+SkPath
+void incReserve(int extraPtCount);
+
+[Path_interpolate]
+SkPath
+bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const;
+
+[Path_Iter_isCloseLine]
+SkPath
+bool isCloseLine() const;
+
+[Path_Iter_isClosedContour]
+SkPath
+bool isClosedContour() const;
+
+[Path_Iter]
+SkPath
+class Iter { Iter(); Iter(const SkPath& path, bool forceClose); void setPath(const SkPath& path, bool forceClose); Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false); SkScalar conicWeight() const; bool isCloseLine() const; bool isClosedContour() const; };
+
+[Path_isConvex]
+SkPath
+bool isConvex() const;
+
+[Path_isEmpty]
+SkPath
+bool isEmpty() const;
+
+[Path_isFinite]
+SkPath
+bool isFinite() const;
+
+[Path_isInterpolatable]
+SkPath
+bool isInterpolatable(const SkPath& compare) const;
+
+[Path_isInverseFillType_2]
+SkPath
+bool isInverseFillType() const;
+
+[Path_isLastContourClosed]
+SkPath
+bool isLastContourClosed() const;
+
+[Path_isLine]
+SkPath
+bool isLine(SkPoint line[2]) const;
+
+[Path_isNestedFillRects]
+SkPath
+bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const;
+
+[Path_isOval]
+SkPath
+bool isOval(SkRect* bounds) const;
+
+[Path_isRRect]
+SkPath
+bool isRRect(SkRRect* rrect) const;
+
+[Path_isRect]
+SkPath
+bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const;
+
+[Path_isVolatile]
+SkPath
+bool isVolatile() const;
+
+[Path_lineTo]
+SkPath
+SkPath& lineTo(SkScalar x, SkScalar y);
+
+[Path_lineTo_2]
+SkPath
+SkPath& lineTo(const SkPoint& p);
+
+[Path_moveTo]
+SkPath
+SkPath& moveTo(SkScalar x, SkScalar y);
+
+[Path_moveTo_2]
+SkPath
+SkPath& moveTo(const SkPoint& p);
+
+[Path_RawIter_next]
+SkPath
+Verb next(SkPoint pts[4]);
+
+[Path_Iter_next]
+SkPath
+Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false);
+
+[Path_offset_2]
+SkPath
+void offset(SkScalar dx, SkScalar dy);
+
+[Path_offset]
+SkPath
+void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
+
+[Path_notequal_operator]
+SkPath
+bool operator!=(const SkPath& a, const SkPath& b);
+
+[Path_copy_operator]
+SkPath
+SkPath& operator=(const SkPath& path);
+
+[Path_equal_operator]
+SkPath
+bool operator==(const SkPath& a, const SkPath& b);
+
+[Path_RawIter_peek]
+SkPath
+Verb peek() const;
+
+[Path_quadTo]
+SkPath
+SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
+
+[Path_quadTo_2]
+SkPath
+SkPath& quadTo(const SkPoint& p1, const SkPoint& p2);
+
+[Path_rArcTo]
+SkPath
+SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep, SkScalar dx, SkScalar dy);
+
+[Cubic]
+[Path_rConicTo]
+SkPath
+SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, SkScalar w);
+
+[Arc]
+[Path_rCubicTo]
+SkPath
+SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, SkScalar dx3, SkScalar dy3);
+
+[Path_rLineTo]
+[Quad_a]
+[Quad_b]
+SkPath
+SkPath& rLineTo(SkScalar dx, SkScalar dy);
+
+[Path_rMoveTo]
+SkPath
+SkPath& rMoveTo(SkScalar dx, SkScalar dy);
+
+[Conic_Weight_a]
+[Conic_Weight_b]
+[Conic_Weight_c]
+[Path_rQuadTo]
+SkPath
+SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
+
+[Path_readFromMemory]
+SkPath
+size_t readFromMemory(const void* buffer, size_t length);
+
+[Path_reset]
+SkPath
+SkPath& reset();
+
+[Path_reverseAddPath]
+SkPath
+SkPath& reverseAddPath(const SkPath& src);
+
+[Path_rewind]
+SkPath
+SkPath& rewind();
+
+[Path_serialize]
+SkPath
+sk_sp<SkData> serialize() const;
+
+[Path_setConvexity]
+SkPath
+void setConvexity(Convexity convexity);
+
+[Path_setFillType]
+SkPath
+void setFillType(FillType ft);
+
+[Path_setIsVolatile]
+SkPath
+void setIsVolatile(bool isVolatile);
+
+[Path_setLastPt]
+SkPath
+void setLastPt(SkScalar x, SkScalar y);
+
+[Path_setLastPt_2]
+SkPath
+void setLastPt(const SkPoint& p);
+
+[Path_Iter_setPath]
+SkPath
+void setPath(const SkPath& path, bool forceClose);
+
+[Path_swap]
+SkPath
+void swap(SkPath& other);
+
+[Path_toggleInverseFillType]
+SkPath
+void toggleInverseFillType();
+
+[Path_transform_2]
+SkPath
+void transform(const SkMatrix& matrix);
+
+[Path_transform]
+SkPath
+void transform(const SkMatrix& matrix, SkPath* dst) const;
+
+[Path_updateBoundsCache]
+SkPath
+void updateBoundsCache() const;
+
+[Path_writeToMemory]
+SkPath
+size_t writeToMemory(void* buffer) const;
+
+[Path_destructor]
+SkPath
+~SkPath();
+
+[Picture_MakeFromData]
+SkPicture
+static sk_sp<SkPicture> MakeFromData(const SkData* data, const SkDeserialProcs* procs = nullptr);
+
+[Picture_serialize_2]
+SkPicture
+static sk_sp<SkPicture> MakeFromData(const void* data, size_t size, const SkDeserialProcs* procs = nullptr);
+
+[Picture_MakeFromStream]
+SkPicture
+static sk_sp<SkPicture> MakeFromStream(SkStream* stream, const SkDeserialProcs* procs = nullptr);
+
+[Picture_MakePlaceholder]
+SkPicture
+static sk_sp<SkPicture> MakePlaceholder(SkRect cull);
+
+[Picture_AbortCallback_abort]
+SkPicture
+virtual bool abort() = 0;
+
+[Picture_approximateBytesUsed]
+SkPicture
+virtual size_t approximateBytesUsed() const = 0;
+
+[Picture_approximateOpCount]
+SkPicture
+virtual int approximateOpCount() const = 0;
+
+[Picture_cullRect]
+SkPicture
+virtual SkRect cullRect() const = 0;
+
+[Picture_playback]
+SkPicture
+virtual void playback(SkCanvas* canvas, AbortCallback* callback = nullptr) const = 0;
+
+[Picture_serialize]
+SkPicture
+sk_sp<SkData> serialize(const SkSerialProcs* procs = nullptr) const;
+
+[Picture_serialize_2]
+SkPicture
+void serialize(SkWStream* stream, const SkSerialProcs* procs = nullptr) const;
+
+[Picture_uniqueID]
+SkPicture
+uint32_t uniqueID() const;
+
+[Pixmap_empty_constructor]
+SkPixmap
+SkPixmap();
+
+[Pixmap_const_SkImageInfo_const_star]
+SkPixmap
+SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes);
+
+[Pixmap_addr]
+SkPixmap
+const void* addr() const;
+
+[Pixmap_addr_2]
+SkPixmap
+const void* addr(int x, int y) const;
+
+[Pixmap_addr16]
+SkPixmap
+const uint16_t* addr16() const;
+
+[Pixmap_addr16_2]
+SkPixmap
+const uint16_t* addr16(int x, int y) const;
+
+[Pixmap_addr32]
+SkPixmap
+const uint32_t* addr32() const;
+
+[Pixmap_addr32_2]
+SkPixmap
+const uint32_t* addr32(int x, int y) const;
+
+[Pixmap_addr64]
+SkPixmap
+const uint64_t* addr64() const;
+
+[Pixmap_addr64_2]
+SkPixmap
+const uint64_t* addr64(int x, int y) const;
+
+[Pixmap_addr8]
+SkPixmap
+const uint8_t* addr8() const;
+
+[Pixmap_addr8_2]
+SkPixmap
+const uint8_t* addr8(int x, int y) const;
+
+[Pixmap_addrF16]
+SkPixmap
+const uint16_t* addrF16() const;
+
+[Pixmap_addrF16_2]
+SkPixmap
+const uint16_t* addrF16(int x, int y) const;
+
+[Pixmap_alphaType]
+SkPixmap
+SkAlphaType alphaType() const;
+
+[Pixmap_bounds]
+SkPixmap
+SkIRect bounds() const;
+
+[Pixmap_colorSpace]
+SkPixmap
+SkColorSpace* colorSpace() const;
+
+[Pixmap_colorType]
+SkPixmap
+SkColorType colorType() const;
+
+[Pixmap_computeByteSize]
+SkPixmap
+size_t computeByteSize() const;
+
+[Pixmap_computeIsOpaque]
+SkPixmap
+bool computeIsOpaque() const;
+
+[Pixmap_erase_2]
+SkPixmap
+bool erase(SkColor color) const;
+
+[Pixmap_erase]
+SkPixmap
+bool erase(SkColor color, const SkIRect& subset) const;
+
+[Pixmap_erase_3]
+SkPixmap
+bool erase(const SkColor4f& color, const SkIRect* subset = nullptr) const;
+
+[Pixmap_extractSubset]
+SkPixmap
+bool extractSubset(SkPixmap* subset, const SkIRect& area) const;
+
+[Pixmap_getColor]
+SkPixmap
+SkColor getColor(int x, int y) const;
+
+[Pixmap_height]
+SkPixmap
+int height() const;
+
+[Pixmap_info]
+SkPixmap
+const SkImageInfo& info() const;
+
+[Pixmap_isOpaque]
+SkPixmap
+bool isOpaque() const;
+
+[Pixmap_readPixels]
+SkPixmap
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const;
+
+[Pixmap_readPixels_2]
+SkPixmap
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY) const;
+
+[Pixmap_readPixels_4]
+SkPixmap
+bool readPixels(const SkPixmap& dst) const;
+
+[Pixmap_readPixels_3]
+SkPixmap
+bool readPixels(const SkPixmap& dst, int srcX, int srcY) const;
+
+[Pixmap_reset]
+SkPixmap
+void reset();
+
+[Pixmap_reset_2]
+SkPixmap
+void reset(const SkImageInfo& info, const void* addr, size_t rowBytes);
+
+[Pixmap_rowBytes]
+SkPixmap
+size_t rowBytes() const;
+
+[Pixmap_rowBytesAsPixels]
+SkPixmap
+int rowBytesAsPixels() const;
+
+[Pixmap_scalePixels]
+SkPixmap
+bool scalePixels(const SkPixmap& dst, SkFilterQuality filterQuality) const;
+
+[Pixmap_setColorSpace]
+SkPixmap
+void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+[Pixmap_shiftPerPixel]
+SkPixmap
+int shiftPerPixel() const;
+
+[Pixmap_width]
+SkPixmap
+int width() const;
+
+[Pixmap_writable_addr]
+SkPixmap
+void* writable_addr() const;
+
+[Pixmap_writable_addr_2]
+SkPixmap
+void* writable_addr(int x, int y) const;
+
+[Pixmap_writable_addr16]
+SkPixmap
+uint16_t* writable_addr16(int x, int y) const;
+
+[Pixmap_writable_addr32]
+SkPixmap
+uint32_t* writable_addr32(int x, int y) const;
+
+[Pixmap_writable_addr64]
+SkPixmap
+uint64_t* writable_addr64(int x, int y) const;
+
+[Pixmap_writable_addr8]
+SkPixmap
+uint8_t* writable_addr8(int x, int y) const;
+
+[Pixmap_writable_addrF16]
+SkPixmap
+uint16_t* writable_addrF16(int x, int y) const;
+
+[Point_CrossProduct]
+SkPoint
+static SkScalar CrossProduct(const SkVector& a, const SkVector& b);
+
+[Point_Distance]
+SkPoint
+static SkScalar Distance(const SkPoint& a, const SkPoint& b);
+
+[Point_DotProduct]
+SkPoint
+static SkScalar DotProduct(const SkVector& a, const SkVector& b);
+
+[Point_Length]
+SkPoint
+static SkScalar Length(SkScalar x, SkScalar y);
+
+[Point_Make]
+SkPoint
+static constexpr SkPoint Make(SkScalar x, SkScalar y);
+
+[Point_Normalize]
+SkPoint
+static SkScalar Normalize(SkVector* vec);
+
+[Point_Offset_2]
+SkPoint
+static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy);
+
+[Point_Offset]
+SkPoint
+static void Offset(SkPoint points[], int count, const SkVector& offset);
+
+[Point_cross]
+SkPoint
+SkScalar cross(const SkVector& vec) const;
+
+[Point_distanceToOrigin]
+SkPoint
+SkScalar distanceToOrigin() const;
+
+[Point_dot]
+SkPoint
+SkScalar dot(const SkVector& vec) const;
+
+[Point_equals]
+SkPoint
+bool equals(SkScalar x, SkScalar y) const;
+
+[Point_isFinite]
+SkPoint
+bool isFinite() const;
+
+[Point_isZero]
+SkPoint
+bool isZero() const;
+
+[Point_iset_2]
+SkPoint
+void iset(const SkIPoint& p);
+
+[Point_iset]
+SkPoint
+void iset(int32_t x, int32_t y);
+
+[Point_length_2]
+SkPoint
+SkScalar length() const;
+
+[Point_negate]
+SkPoint
+void negate();
+
+[Point_normalize_2]
+SkPoint
+bool normalize();
+
+[Point_offset_3]
+SkPoint
+void offset(SkScalar dx, SkScalar dy);
+
+[Point_notequal_operator]
+SkPoint
+bool operator!=(const SkPoint& a, const SkPoint& b);
+
+[Point_multiply_operator]
+SkPoint
+SkPoint operator*(SkScalar scale) const;
+
+[Point_multiplyby_operator]
+SkPoint
+SkPoint& operator*=(SkScalar scale);
+
+[Point_add_operator]
+SkPoint
+SkPoint operator+(const SkPoint& a, const SkVector& b);
+
+[Point_addto_operator]
+SkPoint
+void operator+=(const SkVector& v);
+
+[Point_minus_operator]
+SkPoint
+SkPoint operator-() const;
+
+[Point_subtract_operator]
+SkPoint
+SkVector operator-(const SkPoint& a, const SkPoint& b);
+
+[Point_subtractfrom_operator]
+SkPoint
+void operator-=(const SkVector& v);
+
+[Point_equal_operator]
+SkPoint
+bool operator==(const SkPoint& a, const SkPoint& b);
+
+[Point_scale]
+SkPoint
+void scale(SkScalar scale, SkPoint* dst) const;
+
+[Point_scale_2]
+SkPoint
+void scale(SkScalar value);
+
+[Point_set]
+SkPoint
+void set(SkScalar x, SkScalar y);
+
+[Point_setAbs]
+SkPoint
+void setAbs(const SkPoint& pt);
+
+[Point_setLength]
+SkPoint
+bool setLength(SkScalar length);
+
+[Point_setLength_2]
+SkPoint
+bool setLength(SkScalar x, SkScalar y, SkScalar length);
+
+[Point_setNormalize]
+SkPoint
+bool setNormalize(SkScalar x, SkScalar y);
+
+[Point_x]
+SkPoint
+SkScalar x() const;
+
+[Point_y]
+SkPoint
+SkScalar y() const;
+
+[RRect_MakeEmpty]
+SkRRect
+static SkRRect MakeEmpty();
+
+[RRect_MakeOval]
+SkRRect
+static SkRRect MakeOval(const SkRect& oval);
+
+[RRect_MakeRect]
+SkRRect
+static SkRRect MakeRect(const SkRect& r);
+
+[RRect_MakeRectXY]
+SkRRect
+static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad);
+
+[RRect_empty_constructor]
+SkRRect
+SkRRect();
+
+[RRect_copy_const_SkRRect]
+SkRRect
+SkRRect(const SkRRect& rrect);
+
+[RRect_contains]
+SkRRect
+bool contains(const SkRect& rect) const;
+
+[RRect_dump_2]
+SkRRect
+void dump() const;
+
+[RRect_dump]
+SkRRect
+void dump(bool asHex) const;
+
+[RRect_dumpHex]
+SkRRect
+void dumpHex() const;
+
+[RRect_Corner]
+SkRRect
+enum Corner { kUpperLeft_Corner, kUpperRight_Corner, kLowerRight_Corner, kLowerLeft_Corner, };
+
+[RRect_Type]
+SkRRect
+enum Type { kEmpty_Type, kRect_Type, kOval_Type, kSimple_Type, kNinePatch_Type, kComplex_Type, kLastType = kComplex_Type, };
+
+[RRect_getBounds]
+SkRRect
+const SkRect& getBounds() const;
+
+[RRect_getSimpleRadii]
+SkRRect
+SkVector getSimpleRadii() const;
+
+[RRect_getType]
+SkRRect
+Type getType() const;
+
+[RRect_height]
+SkRRect
+SkScalar height() const;
+
+[RRect_inset_2]
+SkRRect
+void inset(SkScalar dx, SkScalar dy);
+
+[RRect_inset]
+SkRRect
+void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const;
+
+[RRect_isComplex]
+SkRRect
+bool isComplex() const;
+
+[RRect_isEmpty]
+SkRRect
+bool isEmpty() const;
+
+[RRect_isNinePatch]
+SkRRect
+bool isNinePatch() const;
+
+[RRect_isOval]
+SkRRect
+bool isOval() const;
+
+[RRect_isRect]
+SkRRect
+bool isRect() const;
+
+[RRect_isSimple]
+SkRRect
+bool isSimple() const;
+
+[RRect_isValid]
+SkRRect
+bool isValid() const;
+
+[RRect_makeOffset]
+SkRRect
+SkRRect makeOffset(SkScalar dx, SkScalar dy) const;
+
+[RRect_offset]
+SkRRect
+void offset(SkScalar dx, SkScalar dy);
+
+[RRect_notequal_operator]
+SkRRect
+bool operator!=(const SkRRect& a, const SkRRect& b);
+
+[RRect_copy_operator]
+SkRRect
+SkRRect& operator=(const SkRRect& rrect);
+
+[RRect_equal_operator]
+SkRRect
+bool operator==(const SkRRect& a, const SkRRect& b);
+
+[RRect_outset_2]
+SkRRect
+void outset(SkScalar dx, SkScalar dy);
+
+[RRect_outset]
+SkRRect
+void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const;
+
+[RRect_radii]
+SkRRect
+SkVector radii(Corner corner) const;
+
+[RRect_readFromMemory]
+SkRRect
+size_t readFromMemory(const void* buffer, size_t length);
+
+[RRect_rect]
+SkRRect
+const SkRect& rect() const;
+
+[RRect_setEmpty]
+SkRRect
+void setEmpty();
+
+[RRect_setNinePatch]
+SkRRect
+void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad);
+
+[RRect_setOval]
+SkRRect
+void setOval(const SkRect& oval);
+
+[RRect_setRect]
+SkRRect
+void setRect(const SkRect& rect);
+
+[RRect_setRectRadii]
+SkRRect
+void setRectRadii(const SkRect& rect, const SkVector radii[4]);
+
+[RRect_setRectXY]
+SkRRect
+void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad);
+
+[RRect_transform]
+SkRRect
+bool transform(const SkMatrix& matrix, SkRRect* dst) const;
+
+[RRect_type_2]
+SkRRect
+Type type() const;
+
+[RRect_width]
+SkRRect
+SkScalar width() const;
+
+[RRect_writeToMemory]
+SkRRect
+size_t writeToMemory(void* buffer) const;
+
+[Rect_Intersects]
+SkRect
+static bool Intersects(const SkRect& a, const SkRect& b);
+
+[Rect_Make_2]
+SkRect
+static SkRect Make(const SkIRect& irect);
+
+[Rect_Make]
+SkRect
+static SkRect Make(const SkISize& size);
+
+[Rect_MakeEmpty]
+SkRect
+static constexpr SkRect MakeEmpty();
+
+[Rect_MakeIWH]
+SkRect
+static SkRect MakeIWH(int w, int h);
+
+[Rect_MakeLTRB]
+SkRect
+static constexpr SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b);
+
+[Rect_MakeSize]
+SkRect
+static constexpr SkRect MakeSize(const SkSize& size);
+
+[Rect_MakeWH]
+SkRect
+static constexpr SkRect MakeWH(SkScalar w, SkScalar h);
+
+[Rect_MakeXYWH]
+SkRect
+static constexpr SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h);
+
+[Rect_asScalars]
+SkRect
+const SkScalar* asScalars() const;
+
+[Rect_bottom]
+SkRect
+SkScalar    bottom() const;
+
+[Rect_centerX]
+SkRect
+SkScalar    centerX() const;
+
+[Rect_centerY]
+SkRect
+SkScalar    centerY() const;
+
+[Rect_contains]
+SkRect
+bool contains(SkScalar x, SkScalar y) const;
+
+[Rect_contains_3]
+SkRect
+bool contains(const SkIRect& r) const;
+
+[Rect_contains_2]
+SkRect
+bool contains(const SkRect& r) const;
+
+[Rect_dump_2]
+SkRect
+void dump() const;
+
+[Rect_dump]
+SkRect
+void dump(bool asHex) const;
+
+[Rect_dumpHex]
+SkRect
+void dumpHex() const;
+
+[Rect_height]
+SkRect
+SkScalar    height() const;
+
+[Rect_inset]
+SkRect
+void inset(SkScalar dx, SkScalar dy);
+
+[Rect_intersect_2]
+SkRect
+bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+
+[Rect_intersect_3]
+SkRect
+bool intersect(const SkRect& a, const SkRect& b);
+
+[Rect_intersect]
+SkRect
+bool intersect(const SkRect& r);
+
+[Rect_intersects_3]
+SkRect
+bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const;
+
+[Rect_intersects_2]
+SkRect
+bool intersects(const SkRect& r) const;
+
+[Rect_isEmpty]
+SkRect
+bool isEmpty() const;
+
+[Rect_isFinite]
+SkRect
+bool isFinite() const;
+
+[Rect_isSorted]
+SkRect
+bool isSorted() const;
+
+[Rect_iset]
+SkRect
+void iset(int left, int top, int right, int bottom);
+
+[Rect_isetWH]
+SkRect
+void isetWH(int width, int height);
+
+[Rect_join]
+SkRect
+void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+
+[Rect_join_2]
+SkRect
+void join(const SkRect& r);
+
+[Rect_joinNonEmptyArg]
+SkRect
+void joinNonEmptyArg(const SkRect& r);
+
+[Rect_joinPossiblyEmptyRect]
+SkRect
+void joinPossiblyEmptyRect(const SkRect& r);
+
+[Rect_left]
+SkRect
+SkScalar    left() const;
+
+[Rect_makeInset]
+SkRect
+SkRect makeInset(SkScalar dx, SkScalar dy) const;
+
+[Rect_makeOffset]
+SkRect
+SkRect makeOffset(SkScalar dx, SkScalar dy) const;
+
+[Rect_makeOutset]
+SkRect
+SkRect makeOutset(SkScalar dx, SkScalar dy) const;
+
+[Rect_makeSorted]
+SkRect
+SkRect makeSorted() const;
+
+[Rect_offset]
+SkRect
+void offset(SkScalar dx, SkScalar dy);
+
+[Rect_offset_2]
+SkRect
+void offset(const SkPoint& delta);
+
+[Rect_offsetTo]
+SkRect
+void offsetTo(SkScalar newX, SkScalar newY);
+
+[Rect_notequal_operator]
+SkRect
+bool operator!=(const SkRect& a, const SkRect& b);
+
+[Rect_equal_operator]
+SkRect
+bool operator==(const SkRect& a, const SkRect& b);
+
+[Rect_outset]
+SkRect
+void outset(SkScalar dx, SkScalar dy);
+
+[Rect_right]
+SkRect
+SkScalar    right() const;
+
+[Rect_round_2]
+SkRect
+SkIRect round() const;
+
+[Rect_round]
+SkRect
+void round(SkIRect* dst) const;
+
+[Rect_roundIn]
+SkRect
+void roundIn(SkIRect* dst) const;
+
+[Rect_roundOut_3]
+SkRect
+SkIRect roundOut() const;
+
+[Rect_roundOut]
+SkRect
+void roundOut(SkIRect* dst) const;
+
+[Rect_roundOut_2]
+SkRect
+void roundOut(SkRect* dst) const;
+
+[Rect_set_2]
+SkRect
+void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+
+[Rect_set]
+SkRect
+void set(const SkIRect& src);
+
+[Rect_set_3]
+SkRect
+void set(const SkPoint pts[], int count);
+
+[Rect_set_4]
+SkRect
+void set(const SkPoint& p0, const SkPoint& p1);
+
+[Rect_setBounds]
+SkRect
+void setBounds(const SkPoint pts[], int count);
+
+[Rect_setBoundsCheck]
+SkRect
+bool setBoundsCheck(const SkPoint pts[], int count);
+
+[Rect_setBoundsNoCheck]
+SkRect
+void setBoundsNoCheck(const SkPoint pts[], int count);
+
+[Rect_setEmpty]
+SkRect
+void setEmpty();
+
+[Rect_setLTRB]
+SkRect
+void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+
+[Rect_setWH]
+SkRect
+void setWH(SkScalar width, SkScalar height);
+
+[Rect_setXYWH]
+SkRect
+void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height);
+
+[Rect_sort]
+SkRect
+void sort();
+
+[Rect_toQuad]
+SkRect
+void toQuad(SkPoint quad[4]) const;
+
+[Rect_top]
+SkRect
+SkScalar    top() const;
+
+[Rect_width]
+SkRect
+SkScalar    width() const;
+
+[Rect_x]
+SkRect
+SkScalar    x() const;
+
+[Rect_y]
+SkRect
+SkScalar    y() const;
+
+[Region_Cliperator_const_SkRegion_const_SkIRect]
+SkRegion
+Cliperator(const SkRegion& region, const SkIRect& clip);
+
+[Region_Iterator_Iterator]
+SkRegion
+Iterator();
+
+[Region_Iterator_copy_const_SkRegion]
+SkRegion
+Iterator(const SkRegion& region);
+
+[Region_copy_const_SkIRect]
+SkRegion
+explicit SkRegion(const SkIRect& rect);
+
+[Region_empty_constructor]
+SkRegion
+SkRegion();
+
+[Region_copy_const_SkRegion]
+SkRegion
+SkRegion(const SkRegion& region);
+
+[Region_Spanerator_const_SkRegion_int_int_int]
+SkRegion
+Spanerator(const SkRegion& region, int y, int left, int right);
+
+[Region_computeRegionComplexity]
+SkRegion
+int computeRegionComplexity() const;
+
+[Region_contains_2]
+SkRegion
+bool contains(const SkIRect& other) const;
+
+[Region_contains_3]
+SkRegion
+bool contains(const SkRegion& other) const;
+
+[Region_contains]
+SkRegion
+bool contains(int32_t x, int32_t y) const;
+
+[Region_Iterator_done]
+SkRegion
+bool done() const;
+
+[Region_Cliperator_done]
+SkRegion
+bool done();
+
+[Region_Op]
+SkRegion
+enum Op { kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, kReplace_Op, kLastOp = kReplace_Op, };
+
+[Region_getBoundaryPath]
+SkRegion
+bool getBoundaryPath(SkPath* path) const;
+
+[Region_getBounds]
+SkRegion
+const SkIRect& getBounds() const;
+
+[Region_intersects]
+SkRegion
+bool intersects(const SkIRect& rect) const;
+
+[Region_intersects_2]
+SkRegion
+bool intersects(const SkRegion& other) const;
+
+[Region_isComplex]
+SkRegion
+bool isComplex() const;
+
+[Region_isEmpty]
+SkRegion
+bool isEmpty() const;
+
+[Region_isRect]
+SkRegion
+bool isRect() const;
+
+[Region_Spanerator_next]
+SkRegion
+bool next(int* left, int* right);
+
+[Region_Cliperator_next]
+SkRegion
+void  next();
+
+[Region_Iterator_next]
+SkRegion
+void next();
+
+[Region_op_1]
+SkRegion
+bool op(const SkIRect& rect, Op op);
+
+[Region_op_4]
+SkRegion
+bool op(const SkIRect& rect, const SkRegion& rgn, Op op);
+
+[Region_op_3]
+SkRegion
+bool op(const SkRegion& rgn, Op op);
+
+[Region_op_5]
+SkRegion
+bool op(const SkRegion& rgn, const SkIRect& rect, Op op);
+
+[Region_op_6]
+SkRegion
+bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
+
+[Region_op_2]
+SkRegion
+bool op(int left, int top, int right, int bottom, Op op);
+
+[Region_notequal1_operator]
+SkRegion
+bool operator!=(const SkRegion& other) const;
+
+[Region_copy_operator]
+SkRegion
+SkRegion& operator=(const SkRegion& region);
+
+[Region_equal1_operator]
+SkRegion
+bool operator==(const SkRegion& other) const;
+
+[Region_quickContains]
+SkRegion
+bool quickContains(const SkIRect& r) const;
+
+[Region_quickContains_2]
+SkRegion
+bool quickContains(int32_t left, int32_t top, int32_t right, int32_t bottom) const;
+
+[Region_quickReject]
+SkRegion
+bool quickReject(const SkIRect& rect) const;
+
+[Region_quickReject_2]
+SkRegion
+bool quickReject(const SkRegion& rgn) const;
+
+[Region_readFromMemory]
+SkRegion
+size_t readFromMemory(const void* buffer, size_t length);
+
+[Region_Cliperator_rect]
+[Region_Iterator_rect]
+SkRegion
+const SkIRect& rect() const;
+
+[Region_Iterator_reset]
+SkRegion
+void reset(const SkRegion& region);
+
+[Region_Iterator_rewind]
+SkRegion
+bool rewind();
+
+[Region_Iterator_rgn]
+SkRegion
+const SkRegion* rgn() const;
+
+[Region_set]
+SkRegion
+bool set(const SkRegion& src);
+
+[Region_setEmpty]
+SkRegion
+bool setEmpty();
+
+[Region_setPath]
+SkRegion
+bool setPath(const SkPath& path, const SkRegion& clip);
+
+[Region_setRect]
+SkRegion
+bool setRect(const SkIRect& rect);
+
+[Region_setRect_2]
+SkRegion
+bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
+
+[Region_setRects]
+SkRegion
+bool setRects(const SkIRect rects[], int count);
+
+[Region_setRegion]
+SkRegion
+bool setRegion(const SkRegion& region);
+
+[Region_swap]
+SkRegion
+void swap(SkRegion& other);
+
+[Region_translate]
+SkRegion
+void translate(int dx, int dy);
+
+[Region_translate_2]
+SkRegion
+void translate(int dx, int dy, SkRegion* dst) const;
+
+[Region_writeToMemory]
+SkRegion
+size_t writeToMemory(void* buffer) const;
+
+[Region_destructor]
+SkRegion
+~SkRegion();
+
+[Surface_MakeFromBackendTexture]
+SkSurface
+static sk_sp<SkSurface> MakeFromBackendTexture(GrContext* context, const GrBackendTexture& backendTexture, GrSurfaceOrigin origin, int sampleCnt, SkColorType colorType, sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* surfaceProps);
+
+[Surface_MakeFromBackendTextureAsRenderTarget]
+SkSurface
+static sk_sp<SkSurface> MakeFromBackendTextureAsRenderTarget(GrContext* context, const GrBackendTexture& backendTexture, GrSurfaceOrigin origin, int sampleCnt, SkColorType colorType, sk_sp<SkColorSpace> colorSpace, const SkSurfaceProps* surfaceProps);
+
+[Surface_MakeNull]
+SkSurface
+static sk_sp<SkSurface> MakeNull(int width, int height);
+
+[Surface_MakeRaster_2]
+SkSurface
+static sk_sp<SkSurface> MakeRaster(const SkImageInfo& imageInfo, const SkSurfaceProps* props = nullptr);
+
+[Surface_MakeRaster]
+SkSurface
+static sk_sp<SkSurface> MakeRaster(const SkImageInfo& imageInfo, size_t rowBytes, const SkSurfaceProps* surfaceProps);
+
+[Surface_MakeRasterDirect]
+SkSurface
+static sk_sp<SkSurface> MakeRasterDirect(const SkImageInfo& imageInfo, void* pixels, size_t rowBytes, const SkSurfaceProps* surfaceProps = nullptr);
+
+[Surface_MakeRasterDirectReleaseProc]
+SkSurface
+static sk_sp<SkSurface> MakeRasterDirectReleaseProc(const SkImageInfo& imageInfo, void* pixels, size_t rowBytes, void (*releaseProc) (void* pixels, void* context) , void* context, const SkSurfaceProps* surfaceProps = nullptr);
+
+[Surface_MakeRasterN32Premul]
+SkSurface
+static sk_sp<SkSurface> MakeRasterN32Premul(int width, int height, const SkSurfaceProps* surfaceProps = nullptr);
+
+[Surface_MakeRenderTarget_3]
+SkSurface
+static sk_sp<SkSurface> MakeRenderTarget(GrContext* context, SkBudgeted budgeted, const SkImageInfo& imageInfo);
+
+[Surface_MakeRenderTarget]
+SkSurface
+static sk_sp<SkSurface> MakeRenderTarget(GrContext* context, SkBudgeted budgeted, const SkImageInfo& imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps* surfaceProps, bool shouldCreateWithMips = false);
+
+[Surface_MakeRenderTarget_2]
+SkSurface
+static sk_sp<SkSurface> MakeRenderTarget(GrContext* context, SkBudgeted budgeted, const SkImageInfo& imageInfo, int sampleCount, const SkSurfaceProps* props);
+
+[Surface_characterize]
+SkSurface
+bool characterize(SkSurfaceCharacterization* characterization) const;
+
+[Surface_draw_2]
+SkSurface
+bool draw(SkDeferredDisplayList* deferredDisplayList);
+
+[Surface_draw]
+SkSurface
+void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint);
+
+[Surface_notifyContentWillChange]
+SkSurface
+uint32_t generationID();
+
+[Surface_getCanvas]
+SkSurface
+SkCanvas* getCanvas();
+
+[Surface_height]
+SkSurface
+int height() const;
+
+[Surface_makeImageSnapshot]
+SkSurface
+sk_sp<SkImage> makeImageSnapshot();
+
+[Surface_makeImageSnapshot_2]
+SkSurface
+sk_sp<SkImage> makeImageSnapshot(const SkIRect& bounds);
+
+[Surface_makeSurface]
+SkSurface
+sk_sp<SkSurface> makeSurface(const SkImageInfo& imageInfo);
+
+[Surface_notifyContentWillChange]
+SkSurface
+void notifyContentWillChange(ContentChangeMode mode);
+
+[Surface_peekPixels]
+SkSurface
+bool peekPixels(SkPixmap* pixmap);
+
+[Surface_props]
+SkSurface
+const SkSurfaceProps& props() const;
+
+[Surface_readPixels_3]
+SkSurface
+bool readPixels(const SkBitmap& dst, int srcX, int srcY);
+
+[Surface_readPixels_2]
+SkSurface
+bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX, int srcY);
+
+[Surface_readPixels]
+SkSurface
+bool readPixels(const SkPixmap& dst, int srcX, int srcY);
+
+[Surface_width]
+SkSurface
+int width() const;
+
+[Surface_writePixels_2]
+SkSurface
+void writePixels(const SkBitmap& src, int dstX, int dstY);
+
+[Surface_writePixels]
+SkSurface
+void writePixels(const SkPixmap& src, int dstX, int dstY);
+
+[TextBlob_Deserialize]
+SkTextBlob
+static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkDeserialProcs& procs);
+
+[TextBlob_MakeFromString]
+SkTextBlob
+static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkFont& font, SkTextEncoding encoding = SkTextEncoding::kUTF8);
+
+[TextBlob_MakeFromText]
+SkTextBlob
+static sk_sp<SkTextBlob> MakeFromText(const void* text, size_t byteLength, const SkFont& font, SkTextEncoding encoding = SkTextEncoding::kUTF8);
+
+[TextBlob_bounds]
+SkTextBlob
+const SkRect& bounds() const;
+
+[TextBlob_getIntercepts]
+SkTextBlob
+int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], const SkPaint* paint = nullptr) const;
+
+[TextBlob_serialize]
+SkTextBlob
+size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const;
+
+[TextBlob_serialize_2]
+SkTextBlob
+sk_sp<SkData> serialize(const SkSerialProcs& procs) const;
+
+[TextBlob_uniqueID]
+SkTextBlob
+uint32_t uniqueID() const;
+
+[TextBlobBuilder_empty_constructor]
+SkTextBlobBuilder
+SkTextBlobBuilder();
+
+[TextBlobBuilder_allocRun]
+SkTextBlobBuilder
+const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, const SkRect* bounds = nullptr);
+
+[TextBlobBuilder_allocRunPos]
+SkTextBlobBuilder
+const RunBuffer& allocRunPos(const SkFont& font, int count, const SkRect* bounds = nullptr);
+
+[TextBlobBuilder_allocRunPosH]
+SkTextBlobBuilder
+const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, const SkRect* bounds = nullptr);
+
+[TextBlobBuilder_make]
+SkTextBlobBuilder
+sk_sp<SkTextBlob> make();
+
diff --git a/src/third_party/skia/tools/fiddle/draw.cpp b/src/third_party/skia/tools/fiddle/draw.cpp
index 8e94883..32e52c0 100644
--- a/src/third_party/skia/tools/fiddle/draw.cpp
+++ b/src/third_party/skia/tools/fiddle/draw.cpp
@@ -9,11 +9,12 @@
 // assembled by the fiddler program to compile into a fiddle: an
 // implementation of the GetDrawOptions() and draw() functions.
 
-#include "fiddle_main.h"
+#include "tools/fiddle/fiddle_main.h"
 DrawOptions GetDrawOptions() {
     // path *should* be absolute.
-    static const char path[] = "resources/color_wheel.png";
-    return DrawOptions(256, 256, true, true, true, true, true, false, false, path);
+    static const char path[] = "resources/images/color_wheel.png";
+    return DrawOptions(256, 256, true, true, true, true, true, false, false, path,
+                       GrMipMapped::kYes, 64, 64, 0, GrMipMapped::kYes);
 }
 void draw(SkCanvas* canvas) {
     canvas->clear(SK_ColorWHITE);
@@ -21,9 +22,31 @@
     matrix.setScale(0.75f, 0.75f);
     matrix.preRotate(frame * 30.0f * duration); // If an animation, rotate at 30 deg/s.
     SkPaint paint;
-    paint.setShader(image->makeShader(SkShader::kRepeat_TileMode,
-                                      SkShader::kRepeat_TileMode,
-                                      &matrix));
+    paint.setShader(image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, &matrix));
     canvas->drawPaint(paint);
     SkDebugf("This is text output: %d", 2);
+
+    GrContext* context = canvas->getGrContext();
+    if (context) {
+        sk_sp<SkImage> tmp = SkImage::MakeFromTexture(context,
+                                                      backEndTexture,
+                                                      kTopLeft_GrSurfaceOrigin,
+                                                      kRGBA_8888_SkColorType,
+                                                      kOpaque_SkAlphaType,
+                                                      nullptr);
+
+        // TODO: this sampleCnt parameter here should match that set in the options!
+        sk_sp<SkSurface> tmp2 = SkSurface::MakeFromBackendTexture(context,
+                                                                  backEndTextureRenderTarget,
+                                                                  kTopLeft_GrSurfaceOrigin,
+                                                                  0, kRGBA_8888_SkColorType,
+                                                                  nullptr, nullptr);
+
+        // Note: this surface should only be renderable (i.e., not textureable)
+        sk_sp<SkSurface> tmp3 = SkSurface::MakeFromBackendRenderTarget(context,
+                                                                       backEndRenderTarget,
+                                                                       kTopLeft_GrSurfaceOrigin,
+                                                                       kRGBA_8888_SkColorType,
+                                                                       nullptr, nullptr);
+    }
 }
diff --git a/src/third_party/skia/tools/fiddle/egl_context.cpp b/src/third_party/skia/tools/fiddle/egl_context.cpp
index 107bb4f..d7b6e58 100644
--- a/src/third_party/skia/tools/fiddle/egl_context.cpp
+++ b/src/third_party/skia/tools/fiddle/egl_context.cpp
@@ -5,77 +5,36 @@
  * found in the LICENSE file.
  */
 
-#include "fiddle_main.h"
+#include "include/core/SkRefCnt.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/gl/GrGLFunctions.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 #include <EGL/egl.h>
 #include <GLES2/gl2.h>
 
-static const EGLint configAttribs[] = {
-    EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-    EGL_BLUE_SIZE, 8,
-    EGL_GREEN_SIZE, 8,
-    EGL_RED_SIZE, 8,
-    EGL_DEPTH_SIZE, 8,
-    EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-    EGL_NONE
-};
-
-static const int pbufferWidth = 9;
-static const int pbufferHeight = 9;
-
-static const EGLint pbufferAttribs[] = {
-    EGL_WIDTH, pbufferWidth,
-    EGL_HEIGHT, pbufferHeight,
-    EGL_NONE,
-};
+#include <sstream>
 
 // create_grcontext implementation for EGL.
-sk_sp<GrContext> create_grcontext(std::ostringstream &driverinfo) {
-    EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (EGL_NO_DISPLAY == eglDpy) {
+sk_sp<GrContext> create_grcontext(std::ostringstream& driverinfo,
+                                  std::unique_ptr<sk_gpu_test::GLTestContext>* glContext) {
+    // We are leaking tc, but that's OK because fiddle is a short lived proces.
+    glContext->reset(sk_gpu_test::CreatePlatformGLTestContext(kGLES_GrGLStandard));
+    if (!glContext) {
+        return nullptr;
+    }
+    (*glContext)->makeCurrent();
+    sk_sp<GrContext> result = (*glContext)->makeGrContext(GrContextOptions());
+    if (!result) {
+        glContext->reset();
         return nullptr;
     }
 
-    EGLint major, minor;
-    if (EGL_TRUE != eglInitialize(eglDpy, &major, &minor)) {
-        return nullptr;
-    }
+    driverinfo << "GL Version: " << glGetString(GL_VERSION) << "\n";
+    driverinfo << "GL Vendor: " << glGetString(GL_VENDOR) << "\n";
+    driverinfo << "GL Renderer: " << glGetString(GL_RENDERER) << "\n";
+    driverinfo << "GL Extensions: " << glGetString(GL_EXTENSIONS) << "\n";
 
-    EGLint numConfigs;
-    EGLConfig eglCfg;
-    if (EGL_TRUE != eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs)) {
-        return nullptr;
-    }
-
-    EGLSurface eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, pbufferAttribs);
-    if (EGL_NO_SURFACE == eglSurf) {
-        return nullptr;
-    }
-
-    if (EGL_TRUE != eglBindAPI(EGL_OPENGL_API)) {
-        return nullptr;
-    }
-
-    EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, NULL);
-    if (EGL_NO_CONTEXT == eglCtx) {
-        return nullptr;
-    }
-    if (EGL_FALSE == eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx)) {
-        return nullptr;
-    }
-
-    driverinfo << "EGL " << major << "." << minor << "\n";
-    GrGLGetStringProc getString = (GrGLGetStringProc )eglGetProcAddress("glGetString");
-    driverinfo << "GL Versionr: " << getString(GL_VERSION) << "\n";
-    driverinfo << "GL Vendor: " << getString(GL_VENDOR) << "\n";
-    driverinfo << "GL Renderer: " << getString(GL_RENDERER) << "\n";
-    driverinfo << "GL Extensions: " << getString(GL_EXTENSIONS) << "\n";
-
-    auto interface = GrGLCreateNativeInterface();
-    if (!interface) {
-        return nullptr;
-    }
-    eglTerminate(eglDpy);
-
-    return sk_sp<GrContext>(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)interface));
+    return result;
 }
diff --git a/src/third_party/skia/tools/fiddle/examples.cpp b/src/third_party/skia/tools/fiddle/examples.cpp
new file mode 100644
index 0000000..03d3fd2
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/examples.cpp
@@ -0,0 +1,37 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "tools/fiddle/examples.h"
+
+template sk_tools::Registry<fiddle::Example>* sk_tools::Registry<fiddle::Example>::gHead;
+
+// These globals are needed by fiddles:
+GrBackendTexture backEndTexture;
+GrBackendRenderTarget backEndRenderTarget;
+GrBackendTexture backEndTextureRenderTarget;
+SkBitmap source;
+sk_sp<SkImage> image;
+double duration = 1.0;
+double frame = 1.0;
+
+int main() {
+    constexpr int kImgCount = 7;
+    sk_sp<SkImage> images[kImgCount];
+    SkBitmap bitmaps[kImgCount];
+    for (int i = 1; i < kImgCount; ++i) {
+        SkString path = SkStringPrintf("resources/images/example_%d.png", i);
+        images[i] = SkImage::MakeFromEncoded(SkData::MakeFromFileName(path.c_str()));
+        SkAssertResult(images[i] && images[i]->asLegacyBitmap(&bitmaps[i]));
+    }
+    for (const fiddle::Example& example : sk_tools::Registry<fiddle::Example>::Range()) {
+        SkASSERT((unsigned)example.fImageIndex < (unsigned)kImgCount);
+        image = images[example.fImageIndex];
+        source = bitmaps[example.fImageIndex];
+        SkBitmap bmp;
+        bmp.allocN32Pixels(example.fWidth, example.fHeight);
+        bmp.eraseColor(SK_ColorWHITE);
+        SkCanvas canvas(bmp);
+        SkDebugf("==> %s\n", example.fName);
+        example.fFunc(&canvas);
+    }
+}
diff --git a/src/third_party/skia/tools/fiddle/examples.h b/src/third_party/skia/tools/fiddle/examples.h
new file mode 100644
index 0000000..8ecc328
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/examples.h
@@ -0,0 +1,41 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#ifndef examples_DEFINED
+#define examples_DEFINED
+
+#include "tools/Registry.h"
+#include "skia.h"
+
+#include <cmath>
+#include <string>
+
+namespace fiddle {
+struct Example {
+    void (*fFunc)(SkCanvas*);
+    const char* fName;
+    int fImageIndex;
+    int fWidth;
+    int fHeight;
+    bool fText;
+    bool fSRGB;
+    bool fF16;
+    bool fAnimation;
+    bool fOffscreen;
+};
+}
+
+extern GrBackendTexture backEndTexture;
+extern GrBackendRenderTarget backEndRenderTarget;
+extern GrBackendTexture backEndTextureRenderTarget;
+extern SkBitmap source;
+extern sk_sp<SkImage> image;
+extern double duration; // The total duration of the animation in seconds.
+extern double frame;    // A value in [0, 1] of where we are in the animation.
+
+#define REG_FIDDLE(NAME, W, H, TEXT, I)                                            \
+    namespace example_##NAME { void draw(SkCanvas*);  }                            \
+    sk_tools::Registry<fiddle::Example> reg_##NAME(                                \
+        fiddle::Example{&example_##NAME::draw, #NAME, I, W, H, TEXT, false, false, false, false}); \
+    namespace example_##NAME
+
+#endif  // examples_DEFINED
diff --git a/src/third_party/skia/tools/fiddle/fiddle_main.cpp b/src/third_party/skia/tools/fiddle/fiddle_main.cpp
index 6ceffc9..156f561 100644
--- a/src/third_party/skia/tools/fiddle/fiddle_main.cpp
+++ b/src/third_party/skia/tools/fiddle/fiddle_main.cpp
@@ -10,14 +10,34 @@
 #include <sstream>
 #include <string>
 
-#include "SkCommandLineFlags.h"
+#include "src/core/SkAutoPixmapStorage.h"
+#include "src/core/SkMipMap.h"
+#include "src/core/SkUtils.h"
+#include "tools/flags/CommandLineFlags.h"
 
-#include "fiddle_main.h"
+#include "tools/fiddle/fiddle_main.h"
 
-DEFINE_double(duration, 1.0, "The total duration, in seconds, of the animation we are drawing.");
-DEFINE_double(frame, 1.0, "A double value in [0, 1] that specifies the point in animation to draw.");
+static DEFINE_double(duration, 1.0,
+                     "The total duration, in seconds, of the animation we are drawing.");
+static DEFINE_double(frame, 1.0,
+                     "A double value in [0, 1] that specifies the point in animation to draw.");
+
+#include "include/gpu/GrBackendSurface.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrGpu.h"
+#include "src/gpu/GrRenderTarget.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 // Globals externed in fiddle_main.h
+sk_sp<GrTexture>      backingTexture;  // not externed
+GrBackendTexture      backEndTexture;
+
+sk_sp<GrRenderTarget> backingRenderTarget; // not externed
+GrBackendRenderTarget backEndRenderTarget;
+
+sk_sp<GrTexture>      backingTextureRenderTarget;  // not externed
+GrBackendTexture      backEndTextureRenderTarget;
+
 SkBitmap source;
 sk_sp<SkImage> image;
 double duration; // The total duration of the animation in seconds.
@@ -98,8 +118,130 @@
     return canvas;
 }
 
+static bool setup_backend_objects(GrContext* context,
+                                  const SkBitmap& bm,
+                                  const DrawOptions& options) {
+    if (!context) {
+        return false;
+    }
+
+    auto resourceProvider = context->priv().resourceProvider();
+
+    GrSurfaceDesc backingDesc;
+    backingDesc.fWidth = bm.width();
+    backingDesc.fHeight = bm.height();
+    // This config must match the SkColorType used in draw.cpp in the SkImage and Surface factories
+    backingDesc.fConfig = kRGBA_8888_GrPixelConfig;
+    auto format = resourceProvider->caps()->getDefaultBackendFormat(
+            SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kNo);
+    auto renderableFormat = resourceProvider->caps()->getDefaultBackendFormat(
+            SkColorTypeToGrColorType(kRGBA_8888_SkColorType), GrRenderable::kYes);
+
+    if (!bm.empty()) {
+        SkPixmap originalPixmap;
+        SkPixmap* pixmap = &originalPixmap;
+        if (!bm.peekPixels(&originalPixmap)) {
+            return false;
+        }
+
+        SkAutoPixmapStorage rgbaPixmap;
+        if (kN32_SkColorType != kRGBA_8888_SkColorType) {
+            if (!rgbaPixmap.tryAlloc(bm.info().makeColorType(kRGBA_8888_SkColorType))) {
+                return false;
+            }
+            if (!bm.readPixels(rgbaPixmap)) {
+                return false;
+            }
+            pixmap = &rgbaPixmap;
+        }
+        int mipLevelCount = GrMipMapped::kYes == options.fMipMapping
+                                    ? SkMipMap::ComputeLevelCount(bm.width(), bm.height())
+                                    : 1;
+        std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
+
+        texels[0].fPixels = pixmap->addr();
+        texels[0].fRowBytes = pixmap->rowBytes();
+
+        for (int i = 1; i < mipLevelCount; i++) {
+            texels[i].fPixels = nullptr;
+            texels[i].fRowBytes = 0;
+        }
+
+        backingTexture = resourceProvider->createTexture(
+                backingDesc, format, GrColorType::kRGBA_8888, GrRenderable::kNo, 1, SkBudgeted::kNo,
+                GrProtected::kNo, texels.get(), mipLevelCount);
+        if (!backingTexture) {
+            return false;
+        }
+
+        backEndTexture = backingTexture->getBackendTexture();
+        if (!backEndTexture.isValid()) {
+            return false;
+        }
+    }
+
+    backingDesc.fWidth = options.fOffScreenWidth;
+    backingDesc.fHeight = options.fOffScreenHeight;
+
+    SkAutoTMalloc<uint32_t> data(backingDesc.fWidth * backingDesc.fHeight);
+    sk_memset32(data.get(), 0, backingDesc.fWidth * backingDesc.fHeight);
+
+
+    {
+        // This backend object should be renderable but not textureable. Given the limitations
+        // of how we're creating it though it will wind up being secretly textureable.
+        // We use this fact to initialize it with data but don't allow mipmaps
+        GrMipLevel level0 = { data.get(), backingDesc.fWidth*sizeof(uint32_t) };
+
+        sk_sp<GrTexture> tmp = resourceProvider->createTexture(
+                backingDesc, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
+                options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, &level0, 1);
+        if (!tmp || !tmp->asRenderTarget()) {
+            return false;
+        }
+
+        backingRenderTarget = sk_ref_sp(tmp->asRenderTarget());
+
+        backEndRenderTarget = backingRenderTarget->getBackendRenderTarget();
+        if (!backEndRenderTarget.isValid()) {
+            return false;
+        }
+    }
+
+    {
+        int mipLevelCount = GrMipMapped::kYes == options.fOffScreenMipMapping
+                            ? SkMipMap::ComputeLevelCount(backingDesc.fWidth, backingDesc.fHeight)
+                            : 1;
+        std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
+
+        texels[0].fPixels = data.get();
+        texels[0].fRowBytes = backingDesc.fWidth*sizeof(uint32_t);
+
+        for (int i = 1; i < mipLevelCount; i++) {
+            texels[i].fPixels = nullptr;
+            texels[i].fRowBytes = 0;
+        }
+
+        backingTextureRenderTarget = resourceProvider->createTexture(
+                backingDesc, renderableFormat, GrColorType::kRGBA_8888, GrRenderable::kYes,
+                options.fOffScreenSampleCount, SkBudgeted::kNo, GrProtected::kNo, texels.get(),
+                mipLevelCount);
+        if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
+            return false;
+        }
+
+        backEndTextureRenderTarget = backingTextureRenderTarget->getBackendTexture();
+        if (!backEndTextureRenderTarget.isValid()) {
+            return false;
+        }
+    }
+
+
+    return true;
+}
+
 int main(int argc, char** argv) {
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::Parse(argc, argv);
     duration = FLAGS_duration;
     frame = FLAGS_frame;
     DrawOptions options = GetDrawOptions();
@@ -122,8 +264,7 @@
                 perror("Unable to decode the source image.");
                 return 1;
             }
-            SkAssertResult(image->asLegacyBitmap(
-                                   &source, SkImage::kRO_LegacyBitmapMode));
+            SkAssertResult(image->asLegacyBitmap(&source));
         }
     }
     sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
@@ -145,10 +286,16 @@
         rasterData = encode_snapshot(rasterSurface);
     }
     if (options.gpu) {
-        auto grContext = create_grcontext(gGLDriverInfo);
+        std::unique_ptr<sk_gpu_test::GLTestContext> glContext;
+        sk_sp<GrContext> grContext = create_grcontext(gGLDriverInfo, &glContext);
         if (!grContext) {
             fputs("Unable to get GrContext.\n", stderr);
         } else {
+            if (!setup_backend_objects(grContext.get(), source, options)) {
+                fputs("Unable to create backend objects.\n", stderr);
+                exit(1);
+            }
+
             auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
             if (!surface) {
                 fputs("Unable to get render surface.\n", stderr);
@@ -161,7 +308,7 @@
     }
     if (options.pdf) {
         SkDynamicMemoryWStream pdfStream;
-        sk_sp<SkDocument> document(SkDocument::MakePDF(&pdfStream));
+        auto document = SkPDF::MakeDocument(&pdfStream);
         if (document) {
             srand(0);
             draw(prepare_canvas(document->beginPage(options.size.width(), options.size.height())));
diff --git a/src/third_party/skia/tools/fiddle/fiddle_main.h b/src/third_party/skia/tools/fiddle/fiddle_main.h
index fb9d409..f497fe1 100644
--- a/src/third_party/skia/tools/fiddle/fiddle_main.h
+++ b/src/third_party/skia/tools/fiddle/fiddle_main.h
@@ -8,27 +8,41 @@
 #define fiddle_main_DEFINED
 
 #ifdef FIDDLE_BUILD_TEST
-    #include "GrContext.h"
-    #include "SkCanvas.h"
-    #include "SkDocument.h"
-    #include "SkPictureRecorder.h"
-    #include "SkStream.h"
-    #include "SkSurface.h"
-    #include "gl/GrGLAssembleInterface.h"
-    #include "gl/GrGLInterface.h"
+    #include "include/core/SkCanvas.h"
+    #include "include/core/SkDocument.h"
+    #include "include/core/SkPictureRecorder.h"
+    #include "include/core/SkStream.h"
+    #include "include/core/SkSurface.h"
+    #include "include/gpu/GrContext.h"
+    #include "include/gpu/gl/GrGLAssembleInterface.h"
+    #include "include/gpu/gl/GrGLInterface.h"
 #else
     #include "skia.h"
 #endif
 
+#include <memory>
 #include <sstream>
 
+extern GrBackendTexture backEndTexture;
+extern GrBackendRenderTarget backEndRenderTarget;
+extern GrBackendTexture backEndTextureRenderTarget;
 extern SkBitmap source;
 extern sk_sp<SkImage> image;
 extern double duration; // The total duration of the animation in seconds.
 extern double frame;    // A value in [0, 1] of where we are in the animation.
 
+namespace sk_gpu_test {
+class GLTestContext;
+}
+
 struct DrawOptions {
-    DrawOptions(int w, int h, bool r, bool g, bool p, bool k, bool srgb, bool f16, bool textOnly, const char* s)
+    DrawOptions(int w, int h, bool r, bool g, bool p, bool k, bool srgb, bool f16,
+                bool textOnly, const char* s,
+                GrMipMapped mipMapping,
+                int offScreenWidth,
+                int offScreenHeight,
+                int offScreenSampleCount,
+                GrMipMapped offScreenMipMapping)
         : size(SkISize::Make(w, h))
         , raster(r)
         , gpu(g)
@@ -38,7 +52,11 @@
         , f16(f16)
         , textOnly(textOnly)
         , source(s)
-    {
+        , fMipMapping(mipMapping)
+        , fOffScreenWidth(offScreenWidth)
+        , fOffScreenHeight(offScreenHeight)
+        , fOffScreenSampleCount(offScreenSampleCount)
+        , fOffScreenMipMapping(offScreenMipMapping) {
         // F16 mode is only valid for color correct backends.
         SkASSERT(srgb || !f16);
     }
@@ -51,6 +69,20 @@
     bool f16;
     bool textOnly;
     const char* source;
+
+    // This flag is used when a GPU texture resource is created and exposed as a GrBackendTexture.
+    // In this case the resource is created with extra room to accomodate mipmaps.
+    // TODO: The SkImage::makeTextureImage API would need to be widened to allow this to be true
+    // for the non-backend gpu SkImages.
+    GrMipMapped fMipMapping;
+
+    // Parameters for an GPU offscreen resource exposed as a GrBackendRenderTarget
+    int         fOffScreenWidth;
+    int         fOffScreenHeight;
+    int         fOffScreenSampleCount;
+    // TODO: should we also expose stencilBits here? How about the config?
+
+    GrMipMapped fOffScreenMipMapping; // only applicable if the offscreen is also textureable
 };
 
 extern DrawOptions GetDrawOptions();
@@ -59,6 +91,7 @@
 
 // There are different implementations of create_grcontext() for EGL, Mesa,
 // and a fallback to a null context.
-extern sk_sp<GrContext> create_grcontext(std::ostringstream &driverinfo);
+extern sk_sp<GrContext> create_grcontext(std::ostringstream& driverinfo,
+                                         std::unique_ptr<sk_gpu_test::GLTestContext>* glContext);
 
 #endif  // fiddle_main_DEFINED
diff --git a/src/third_party/skia/tools/fiddle/make_all_examples_cpp.py b/src/third_party/skia/tools/fiddle/make_all_examples_cpp.py
new file mode 100755
index 0000000..4c8dcd2
--- /dev/null
+++ b/src/third_party/skia/tools/fiddle/make_all_examples_cpp.py
@@ -0,0 +1,15 @@
+#! /usr/bin/env python
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+''' Run this script to re-generate the `all_examples.cpp` file after adding or
+    deleting example fiddles. '''
+import glob
+import os
+os.chdir(os.path.dirname(__file__))
+with open('all_examples.cpp', 'w') as o:
+    o.write('// Copyright 2019 Google LLC.\n// Use of this source code is '
+            'governed by a BSD-style license that can be found in the '
+            'LICENSE file.\n')
+    for path in sorted(glob.glob('../../docs/examples/*.cpp')):
+        o.write('#include "%s"\n' % path)
diff --git a/src/third_party/skia/tools/fiddle/mesa_context.cpp b/src/third_party/skia/tools/fiddle/mesa_context.cpp
deleted file mode 100644
index 3b3726b..0000000
--- a/src/third_party/skia/tools/fiddle/mesa_context.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "fiddle_main.h"
-
-#include <GL/osmesa.h>
-
-// create_grcontext implementation for Mesa.
-sk_sp<GrContext> create_grcontext(std::ostringstream &driverinfo) {
-    // We just leak the OSMesaContext... the process will die soon anyway.
-    if (OSMesaContext osMesaContext = OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, nullptr)) {
-        static uint32_t buffer[16 * 16];
-        OSMesaMakeCurrent(osMesaContext, &buffer, GL_UNSIGNED_BYTE, 16, 16);
-    }
-    driverinfo << "Mesa";
-
-    auto osmesa_get = [](void* ctx, const char name[]) {
-        SkASSERT(nullptr == ctx);
-        SkASSERT(OSMesaGetCurrentContext());
-        return OSMesaGetProcAddress(name);
-    };
-    sk_sp<const GrGLInterface> mesa(GrGLAssembleInterface(nullptr, osmesa_get));
-    if (!mesa) {
-        return nullptr;
-    }
-    return sk_sp<GrContext>(GrContext::Create(
-                kOpenGL_GrBackend,
-                reinterpret_cast<intptr_t>(mesa.get())));
-}
diff --git a/src/third_party/skia/tools/fiddle/null_context.cpp b/src/third_party/skia/tools/fiddle/null_context.cpp
index 3fe0054..360ddd9 100644
--- a/src/third_party/skia/tools/fiddle/null_context.cpp
+++ b/src/third_party/skia/tools/fiddle/null_context.cpp
@@ -5,10 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "fiddle_main.h"
+#include "tools/fiddle/fiddle_main.h"
 
 // create_grcontext for when neither Mesa nor EGL are available.
-sk_sp<GrContext> create_grcontext(std::ostringstream &driverinfo) {
+sk_sp<GrContext> create_grcontext(std::ostringstream& driverinfo,
+                                  std::unique_ptr<sk_gpu_test::GLTestContext>* glContext) {
     driverinfo << "(no GL driver available)";
     return nullptr;
 }
diff --git a/src/third_party/skia/tools/flags/SkCommandLineFlags.cpp b/src/third_party/skia/tools/flags/CommandLineFlags.cpp
similarity index 78%
rename from src/third_party/skia/tools/flags/SkCommandLineFlags.cpp
rename to src/third_party/skia/tools/flags/CommandLineFlags.cpp
index bfc9f5e..934ff12 100644
--- a/src/third_party/skia/tools/flags/SkCommandLineFlags.cpp
+++ b/src/third_party/skia/tools/flags/CommandLineFlags.cpp
@@ -5,27 +5,22 @@
  * found in the LICENSE file.
  */
 
-#include "SkCommandLineFlags.h"
-#include "SkTDArray.h"
-#include "SkTSort.h"
+#include "include/private/SkTDArray.h"
+#include "src/core/SkTSort.h"
+#include "tools/flags/CommandLineFlags.h"
 
 #include <stdlib.h>
 
-#if defined(GOOGLE3) && defined(SK_BUILD_FOR_IOS)
-    // This is defined by //base only for iOS (I don't know why).
-    DECLARE_bool(undefok)
-#else
-    DEFINE_bool(undefok, false, "Silently ignore unknown flags instead of crashing.");
-#endif
-
 template <typename T> static void ignore_result(const T&) {}
 
-bool SkFlagInfo::CreateStringFlag(const char* name, const char* shortName,
-                                  SkCommandLineFlags::StringArray* pStrings,
-                                  const char* defaultValue, const char* helpString,
-                                  const char* extendedHelpString) {
-    SkFlagInfo* info = new SkFlagInfo(name, shortName, kString_FlagType, helpString,
-                                      extendedHelpString);
+bool SkFlagInfo::CreateStringFlag(const char*                    name,
+                                  const char*                    shortName,
+                                  CommandLineFlags::StringArray* pStrings,
+                                  const char*                    defaultValue,
+                                  const char*                    helpString,
+                                  const char*                    extendedHelpString) {
+    SkFlagInfo* info =
+            new SkFlagInfo(name, shortName, kString_FlagType, helpString, extendedHelpString);
     info->fDefaultString.set(defaultValue);
 
     info->fStrings = pStrings;
@@ -33,8 +28,8 @@
     return true;
 }
 
-void SkFlagInfo::SetDefaultStrings(SkCommandLineFlags::StringArray* pStrings,
-                                   const char* defaultValue) {
+void SkFlagInfo::SetDefaultStrings(CommandLineFlags::StringArray* pStrings,
+                                   const char*                    defaultValue) {
     pStrings->reset();
     if (nullptr == defaultValue) {
         return;
@@ -43,7 +38,7 @@
     size_t defaultLength = strlen(defaultValue);
     if (defaultLength > 0) {
         const char* const defaultEnd = defaultValue + defaultLength;
-        const char* begin = defaultValue;
+        const char*       begin      = defaultValue;
         while (true) {
             while (begin < defaultEnd && ' ' == *begin) {
                 begin++;
@@ -80,12 +75,12 @@
  *  @param boolean True if the string represents a boolean, false otherwise.
  */
 static bool parse_bool_arg(const char* string, bool* result) {
-    static const char* trueValues[] = { "1", "TRUE", "true" };
+    static const char* trueValues[] = {"1", "TRUE", "true"};
     if (string_is_in(string, trueValues, SK_ARRAY_COUNT(trueValues))) {
         *result = true;
         return true;
     }
-    static const char* falseValues[] = { "0", "FALSE", "false" };
+    static const char* falseValues[] = {"0", "FALSE", "false"};
     if (string_is_in(string, falseValues, SK_ARRAY_COUNT(falseValues))) {
         *result = false;
         return true;
@@ -143,24 +138,20 @@
     return false;
 }
 
-SkFlagInfo* SkCommandLineFlags::gHead;
-SkString SkCommandLineFlags::gUsage;
+SkFlagInfo* CommandLineFlags::gHead;
+SkString    CommandLineFlags::gUsage;
 
-void SkCommandLineFlags::SetUsage(const char* usage) {
-    gUsage.set(usage);
-}
+void CommandLineFlags::SetUsage(const char* usage) { gUsage.set(usage); }
 
-void SkCommandLineFlags::PrintUsage() {
-    SkDebugf("%s", gUsage.c_str());
-}
+void CommandLineFlags::PrintUsage() { SkDebugf("%s", gUsage.c_str()); }
 
 // Maximum line length for the help message.
 #define LINE_LENGTH 72
 
 static void print_indented(const SkString& text) {
-    size_t length = text.size();
+    size_t      length   = text.size();
     const char* currLine = text.c_str();
-    const char* stop = currLine + length;
+    const char* stop     = currLine + length;
     while (currLine < stop) {
         int lineBreak = SkStrFind(currLine, "\n");
         if (lineBreak < 0) {
@@ -177,7 +168,7 @@
             if (0 == spaceIndex) {
                 // No spaces on the entire line. Go ahead and break mid word.
                 spaceIndex = LINE_LENGTH;
-                gap = 0;
+                gap        = 0;
             } else {
                 // Skip the space on the next line
                 gap = 1;
@@ -222,7 +213,7 @@
 };
 }  // namespace
 
-void SkCommandLineFlags::Parse(int argc, char** argv) {
+void CommandLineFlags::Parse(int argc, const char* const* argv) {
     // Only allow calling this function once.
     static bool gOnce;
     if (gOnce) {
@@ -232,7 +223,7 @@
     }
     gOnce = true;
 
-    bool helpPrinted = false;
+    bool helpPrinted  = false;
     bool flagsPrinted = false;
     // Loop over argv, starting with 1, since the first is just the name of the program.
     for (int i = 1; i < argc; i++) {
@@ -256,12 +247,10 @@
             if (0 == helpFlags.count()) {
                 // If no flags followed --help, print them all
                 SkTDArray<SkFlagInfo*> allFlags;
-                for (SkFlagInfo* flag = SkCommandLineFlags::gHead; flag;
-                     flag = flag->next()) {
-                    allFlags.push(flag);
+                for (SkFlagInfo* flag = CommandLineFlags::gHead; flag; flag = flag->next()) {
+                    allFlags.push_back(flag);
                 }
-                SkTQSort(&allFlags[0], &allFlags[allFlags.count() - 1],
-                         CompareFlagsByName());
+                SkTQSort(&allFlags[0], &allFlags[allFlags.count() - 1], CompareFlagsByName());
                 for (int i = 0; i < allFlags.count(); ++i) {
                     print_help_for_flag(allFlags[i]);
                     if (allFlags[i]->extendedHelp().size() > 0) {
@@ -270,8 +259,7 @@
                     }
                 }
             } else {
-                for (SkFlagInfo* flag = SkCommandLineFlags::gHead; flag;
-                     flag = flag->next()) {
+                for (SkFlagInfo* flag = CommandLineFlags::gHead; flag; flag = flag->next()) {
                     for (int k = 0; k < helpFlags.count(); k++) {
                         if (flag->name().equals(helpFlags[k]) ||
                             flag->shortName().equals(helpFlags[k])) {
@@ -292,8 +280,8 @@
         }
         if (!helpPrinted) {
             SkFlagInfo* matchedFlag = nullptr;
-            SkFlagInfo* flag = gHead;
-            int startI = i;
+            SkFlagInfo* flag        = gHead;
+            int         startI      = i;
             while (flag != nullptr) {
                 if (flag->match(argv[startI])) {
                     i = startI;
@@ -307,7 +295,7 @@
                         case SkFlagInfo::kBool_FlagType:
                             // Can be handled by match, above, but can also be set by the next
                             // string.
-                            if (i+1 < argc && !SkStrStartsWith(argv[i+1], '-')) {
+                            if (i + 1 < argc && !SkStrStartsWith(argv[i + 1], '-')) {
                                 i++;
                                 bool value;
                                 if (parse_bool_arg(argv[i], &value)) {
@@ -318,11 +306,11 @@
                         case SkFlagInfo::kString_FlagType:
                             flag->resetStrings();
                             // Add all arguments until another flag is reached.
-                            while (i+1 < argc) {
+                            while (i + 1 < argc) {
                                 char* end = nullptr;
                                 // Negative numbers aren't flags.
-                                ignore_result(strtod(argv[i+1], &end));
-                                if (end == argv[i+1] && SkStrStartsWith(argv[i+1], '-')) {
+                                ignore_result(strtod(argv[i + 1], &end));
+                                if (end == argv[i + 1] && SkStrStartsWith(argv[i + 1], '-')) {
                                     break;
                                 }
                                 i++;
@@ -337,32 +325,27 @@
                             i++;
                             flag->setDouble(atof(argv[i]));
                             break;
-                        default:
-                            SkDEBUGFAIL("Invalid flag type");
+                        default: SkDEBUGFAIL("Invalid flag type");
                     }
                 }
                 flag = flag->next();
             }
             if (!matchedFlag) {
 #if defined(SK_BUILD_FOR_MAC)
-                if (SkStrStartsWith(argv[i], "NSDocumentRevisions")
-                        || SkStrStartsWith(argv[i], "-NSDocumentRevisions")) {
+                if (SkStrStartsWith(argv[i], "NSDocumentRevisions") ||
+                    SkStrStartsWith(argv[i], "-NSDocumentRevisions")) {
                     i++;  // skip YES
                 } else
 #endif
-                if (FLAGS_undefok) {
-                    SkDebugf("FYI: ignoring unknown flag '%s'.\n", argv[i]);
-                } else {
                     SkDebugf("Got unknown flag '%s'. Exiting.\n", argv[i]);
-                    exit(-1);
-                }
+                exit(-1);
             }
         }
     }
     // Since all of the flags have been set, release the memory used by each
     // flag. FLAGS_x can still be used after this.
     SkFlagInfo* flag = gHead;
-    gHead = nullptr;
+    gHead            = nullptr;
     while (flag != nullptr) {
         SkFlagInfo* next = flag->next();
         delete flag;
@@ -375,15 +358,14 @@
 
 namespace {
 
-template <typename Strings>
-bool ShouldSkipImpl(const Strings& strings, const char* name) {
-    int count = strings.count();
-    size_t testLen = strlen(name);
-    bool anyExclude = count == 0;
+template <typename Strings> bool ShouldSkipImpl(const Strings& strings, const char* name) {
+    int    count      = strings.count();
+    size_t testLen    = strlen(name);
+    bool   anyExclude = count == 0;
     for (int i = 0; i < strings.count(); ++i) {
         const char* matchName = strings[i];
-        size_t matchLen = strlen(matchName);
-        bool matchExclude, matchStart, matchEnd;
+        size_t      matchLen  = strlen(matchName);
+        bool        matchExclude, matchStart, matchEnd;
         if ((matchExclude = matchName[0] == '~')) {
             anyExclude = true;
             matchName++;
@@ -396,11 +378,12 @@
         if ((matchEnd = matchName[matchLen - 1] == '$')) {
             matchLen--;
         }
-        if (matchStart ? (!matchEnd || matchLen == testLen)
-                && strncmp(name, matchName, matchLen) == 0
-                : matchEnd ? matchLen <= testLen
-                && strncmp(name + testLen - matchLen, matchName, matchLen) == 0
-                : strstr(name, matchName) != 0) {
+        if (matchStart
+                    ? (!matchEnd || matchLen == testLen) && strncmp(name, matchName, matchLen) == 0
+                    : matchEnd
+                              ? matchLen <= testLen &&
+                                        strncmp(name + testLen - matchLen, matchName, matchLen) == 0
+                              : strstr(name, matchName) != nullptr) {
             return matchExclude;
         }
     }
@@ -409,9 +392,9 @@
 
 }  // namespace
 
-bool SkCommandLineFlags::ShouldSkip(const SkTDArray<const char*>& strings, const char* name) {
+bool CommandLineFlags::ShouldSkip(const SkTDArray<const char*>& strings, const char* name) {
     return ShouldSkipImpl(strings, name);
 }
-bool SkCommandLineFlags::ShouldSkip(const StringArray& strings, const char* name) {
+bool CommandLineFlags::ShouldSkip(const StringArray& strings, const char* name) {
     return ShouldSkipImpl(strings, name);
 }
diff --git a/src/third_party/skia/tools/flags/CommandLineFlags.h b/src/third_party/skia/tools/flags/CommandLineFlags.h
new file mode 100644
index 0000000..7fa3068
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommandLineFlags.h
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SK_COMMAND_LINE_FLAGS_H
+#define SK_COMMAND_LINE_FLAGS_H
+
+#include "include/core/SkString.h"
+#include "include/private/SkTArray.h"
+#include "include/private/SkTDArray.h"
+
+/**
+ *  Including this file (and compiling CommandLineFlags.cpp) provides command line
+ *  parsing. In order to use it, use the following macros in global
+ *  namespace:
+ *
+ *  DEFINE_bool(name, defaultValue, helpString);
+ *  DEFINE_string(name, defaultValue, helpString);
+ *  DEFINE_int(name, defaultValue, helpString);
+ *  DEFINE_double(name, defaultValue, helpString);
+ *
+ *  Then, in main, call CommandLineFlags::SetUsage() to describe usage and call
+ *  CommandLineFlags::Parse() to parse the flags. Henceforth, each flag can
+ *  be referenced using
+ *
+ *  FLAGS_name
+ *
+ *  For example, the line
+ *
+ *  DEFINE_bool(boolean, false, "The variable boolean does such and such");
+ *
+ *  will create the following variable:
+ *
+ *  bool FLAGS_boolean;
+ *
+ *  which will initially be set to false, and can be set to true by using the
+ *  flag "--boolean" on the commandline. "--noboolean" will set FLAGS_boolean
+ *  to false. FLAGS_boolean can also be set using "--boolean=true" or
+ *  "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE",
+ *  "1" or "0").
+ *
+ *  The helpString will be printed if the help flag (-h or -help) is used.
+ *
+ *  Similarly, the line
+ *
+ *  DEFINE_int(integer, .., ..);
+ *
+ *  will create
+ *
+ *  int FLAGS_integer;
+ *
+ *  and
+ *
+ *  DEFINE_double(real, .., ..);
+ *
+ *  will create
+ *
+ *  double FLAGS_real;
+ *
+ *  These flags can be set by specifying, for example, "--integer 7" and
+ *  "--real 3.14" on the command line. Unsigned integers are parsed from the
+ *  command line using strtoul() so will detect the base (0 for octal, and
+ *  0x or 0X for hex, otherwise assumes decimal).
+ *
+ *  Unlike the others, the line
+ *
+ *  DEFINE_string(args, .., ..);
+ *
+ *  creates an array:
+ *
+ *  CommandLineFlags::StringArray FLAGS_args;
+ *
+ *  If the default value is the empty string, FLAGS_args will default to a size
+ *  of zero. Otherwise it will default to a size of 1 with the default string
+ *  as its value. All strings that follow the flag on the command line (until
+ *  a string that begins with '-') will be entries in the array.
+ *
+ *  DEFINE_extended_string(args, .., .., extendedHelpString);
+ *
+ *  creates a similar string array flag as DEFINE_string. The flag will have extended help text
+ *  (extendedHelpString) that can the user can see with '--help <args>' flag.
+ *
+ *  Any flag can be referenced from another file after using the following:
+ *
+ *  DECLARE_x(name);
+ *
+ *  (where 'x' is the type specified in the DEFINE).
+ *
+ *  Inspired by gflags (https://code.google.com/p/gflags/). Is not quite as
+ *  robust as gflags, but suits our purposes. For example, allows creating
+ *  a flag -h or -help which will never be used, since CommandLineFlags handles it.
+ *  CommandLineFlags will also allow creating --flag and --noflag. Uses the same input
+ *  format as gflags and creates similarly named variables (i.e. FLAGS_name).
+ *  Strings are handled differently (resulting variable will be an array of
+ *  strings) so that a flag can be followed by multiple parameters.
+ */
+
+class SkFlagInfo;
+
+class CommandLineFlags {
+public:
+    /**
+     *  Call to set the help message to be displayed. Should be called before
+     *  Parse.
+     */
+    static void SetUsage(const char* usage);
+
+    /**
+     *  Call this to display the help message. Should be called after SetUsage.
+     */
+    static void PrintUsage();
+
+    /**
+     *  Call at the beginning of main to parse flags created by DEFINE_x, above.
+     *  Must only be called once.
+     */
+    static void Parse(int argc, const char* const* argv);
+
+    /**
+     *  Custom class for holding the arguments for a string flag.
+     *  Publicly only has accessors so the strings cannot be modified.
+     */
+    class StringArray {
+    public:
+        StringArray() {}
+        explicit StringArray(const SkTArray<SkString>& strings) : fStrings(strings) {}
+        const char* operator[](int i) const {
+            SkASSERT(i >= 0 && i < fStrings.count());
+            return fStrings[i].c_str();
+        }
+
+        int count() const { return fStrings.count(); }
+
+        bool isEmpty() const { return this->count() == 0; }
+
+        /**
+         * Returns true iff string is equal to one of the strings in this array.
+         */
+        bool contains(const char* string) const {
+            for (int i = 0; i < fStrings.count(); i++) {
+                if (fStrings[i].equals(string)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        void set(int i, const char* str) {
+            if (i >= fStrings.count()) {
+                this->append(str);
+                return;
+            }
+            fStrings[i].set(str);
+        }
+
+        const SkString* begin() const { return fStrings.begin(); }
+        const SkString* end() const { return fStrings.end(); }
+
+    private:
+        void reset() { fStrings.reset(); }
+
+        void append(const char* string) { fStrings.push_back().set(string); }
+
+        void append(const char* string, size_t length) { fStrings.push_back().set(string, length); }
+
+        SkTArray<SkString> fStrings;
+
+        friend class SkFlagInfo;
+    };
+
+    /* Takes a list of the form [~][^]match[$]
+     ~ causes a matching test to always be skipped
+     ^ requires the start of the test to match
+     $ requires the end of the test to match
+     ^ and $ requires an exact match
+     If a test does not match any list entry, it is skipped unless some list entry starts with ~
+    */
+    static bool ShouldSkip(const SkTDArray<const char*>& strings, const char* name);
+    static bool ShouldSkip(const StringArray& strings, const char* name);
+
+private:
+    static SkFlagInfo* gHead;
+    static SkString    gUsage;
+
+    // For access to gHead.
+    friend class SkFlagInfo;
+};
+
+#define TO_STRING2(s) #s
+#define TO_STRING(s) TO_STRING2(s)
+
+#define DEFINE_bool(name, defaultValue, helpString)                   \
+    bool                  FLAGS_##name;                               \
+    SK_UNUSED static bool unused_##name = SkFlagInfo::CreateBoolFlag( \
+            TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString)
+
+// bool 2 allows specifying a short name. No check is done to ensure that shortName
+// is actually shorter than name.
+#define DEFINE_bool2(name, shortName, defaultValue, helpString)       \
+    bool                  FLAGS_##name;                               \
+    SK_UNUSED static bool unused_##name = SkFlagInfo::CreateBoolFlag( \
+            TO_STRING(name), TO_STRING(shortName), &FLAGS_##name, defaultValue, helpString)
+
+#define DECLARE_bool(name) extern bool FLAGS_##name;
+
+#define DEFINE_string(name, defaultValue, helpString)                           \
+    CommandLineFlags::StringArray FLAGS_##name;                                 \
+    SK_UNUSED static bool         unused_##name = SkFlagInfo::CreateStringFlag( \
+            TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString, nullptr)
+#define DEFINE_extended_string(name, defaultValue, helpString, extendedHelpString) \
+    CommandLineFlags::StringArray FLAGS_##name;                                    \
+    SK_UNUSED static bool         unused_##name = SkFlagInfo::CreateStringFlag(    \
+            TO_STRING(name), nullptr, &FLAGS_##name, defaultValue, helpString, extendedHelpString)
+
+// string2 allows specifying a short name. There is an assert that shortName
+// is only 1 character.
+#define DEFINE_string2(name, shortName, defaultValue, helpString)                                    \
+    CommandLineFlags::StringArray FLAGS_##name;                                                      \
+    SK_UNUSED static bool         unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name),      \
+                                                                       TO_STRING(shortName), \
+                                                                       &FLAGS_##name,        \
+                                                                       defaultValue,         \
+                                                                       helpString,           \
+                                                                       nullptr)
+
+#define DECLARE_string(name) extern CommandLineFlags::StringArray FLAGS_##name;
+
+#define DEFINE_int(name, defaultValue, helpString) \
+    int               FLAGS_##name;                \
+    SK_UNUSED static bool unused_##name =          \
+            SkFlagInfo::CreateIntFlag(TO_STRING(name), &FLAGS_##name, defaultValue, helpString)
+
+#define DEFINE_int_2(name, shortName, defaultValue, helpString)      \
+    int               FLAGS_##name;                                  \
+    SK_UNUSED static bool unused_##name = SkFlagInfo::CreateIntFlag( \
+            TO_STRING(name), TO_STRING(shortName), &FLAGS_##name, defaultValue, helpString)
+
+#define DECLARE_int(name) extern int FLAGS_##name;
+
+#define DEFINE_double(name, defaultValue, helpString) \
+    double                FLAGS_##name;               \
+    SK_UNUSED static bool unused_##name =             \
+            SkFlagInfo::CreateDoubleFlag(TO_STRING(name), &FLAGS_##name, defaultValue, helpString)
+
+#define DECLARE_double(name) extern double FLAGS_##name;
+
+class SkFlagInfo {
+public:
+    enum FlagTypes {
+        kBool_FlagType,
+        kString_FlagType,
+        kInt_FlagType,
+        kDouble_FlagType,
+    };
+
+    /**
+     *  Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo
+     *  object is appended to a list, which is deleted when CommandLineFlags::Parse is called.
+     *  Therefore, each call should be made before the call to ::Parse. They are not intended
+     *  to be called directly. Instead, use the macros described above.
+     *  @param name Long version (at least 2 characters) of the name of the flag. This name can
+     *      be referenced on the command line as "--name" to set the value of this flag.
+     *  @param shortName Short version (one character) of the name of the flag. This name can
+     *      be referenced on the command line as "-shortName" to set the value of this flag.
+     *  @param p<Type> Pointer to a global variable which holds the value set by CommandLineFlags.
+     *  @param defaultValue The default value of this flag. The variable pointed to by p<Type> will
+     *      be set to this value initially. This is also displayed as part of the help output.
+     *  @param helpString Explanation of what this flag changes in the program.
+     */
+    static bool CreateBoolFlag(const char* name,
+                               const char* shortName,
+                               bool*       pBool,
+                               bool        defaultValue,
+                               const char* helpString) {
+        SkFlagInfo* info  = new SkFlagInfo(name, shortName, kBool_FlagType, helpString, nullptr);
+        info->fBoolValue  = pBool;
+        *info->fBoolValue = info->fDefaultBool = defaultValue;
+        return true;
+    }
+
+    /**
+     *  See comments for CreateBoolFlag.
+     *  @param pStrings Unlike the others, this is a pointer to an array of values.
+     *  @param defaultValue Thise default will be parsed so that strings separated by spaces
+     *      will be added to pStrings.
+     */
+    static bool CreateStringFlag(const char*                    name,
+                                 const char*                    shortName,
+                                 CommandLineFlags::StringArray* pStrings,
+                                 const char*                    defaultValue,
+                                 const char*                    helpString,
+                                 const char*                    extendedHelpString);
+
+    /**
+     *  See comments for CreateBoolFlag.
+     */
+    static bool CreateIntFlag(const char* name,
+                              int*    pInt,
+                              int     defaultValue,
+                              const char* helpString) {
+        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kInt_FlagType, helpString, nullptr);
+        info->fIntValue  = pInt;
+        *info->fIntValue = info->fDefaultInt = defaultValue;
+        return true;
+    }
+
+    static bool CreateIntFlag(const char* name,
+                              const char* shortName,
+                              int*    pInt,
+                              int     defaultValue,
+                              const char* helpString) {
+        SkFlagInfo* info = new SkFlagInfo(name, shortName, kInt_FlagType, helpString, nullptr);
+        info->fIntValue  = pInt;
+        *info->fIntValue = info->fDefaultInt = defaultValue;
+        return true;
+    }
+
+    /**
+     *  See comments for CreateBoolFlag.
+     */
+    static bool CreateDoubleFlag(const char* name,
+                                 double*     pDouble,
+                                 double      defaultValue,
+                                 const char* helpString) {
+        SkFlagInfo* info    = new SkFlagInfo(name, nullptr, kDouble_FlagType, helpString, nullptr);
+        info->fDoubleValue  = pDouble;
+        *info->fDoubleValue = info->fDefaultDouble = defaultValue;
+        return true;
+    }
+
+    /**
+     *  Returns true if the string matches this flag.
+     *  For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
+     *  without looking at the following string:
+     *      --name
+     *      --noname
+     *      --name=true
+     *      --name=false
+     *      --name=1
+     *      --name=0
+     *      --name=TRUE
+     *      --name=FALSE
+     */
+    bool match(const char* string);
+
+    FlagTypes getFlagType() const { return fFlagType; }
+
+    void resetStrings() {
+        if (kString_FlagType == fFlagType) {
+            fStrings->reset();
+        } else {
+            SkDEBUGFAIL("Can only call resetStrings on kString_FlagType");
+        }
+    }
+
+    void append(const char* string) {
+        if (kString_FlagType == fFlagType) {
+            fStrings->append(string);
+        } else {
+            SkDEBUGFAIL("Can only append to kString_FlagType");
+        }
+    }
+
+    void setInt(int value) {
+        if (kInt_FlagType == fFlagType) {
+            *fIntValue = value;
+        } else {
+            SkDEBUGFAIL("Can only call setInt on kInt_FlagType");
+        }
+    }
+
+    void setDouble(double value) {
+        if (kDouble_FlagType == fFlagType) {
+            *fDoubleValue = value;
+        } else {
+            SkDEBUGFAIL("Can only call setDouble on kDouble_FlagType");
+        }
+    }
+
+    void setBool(bool value) {
+        if (kBool_FlagType == fFlagType) {
+            *fBoolValue = value;
+        } else {
+            SkDEBUGFAIL("Can only call setBool on kBool_FlagType");
+        }
+    }
+
+    SkFlagInfo* next() { return fNext; }
+
+    const SkString& name() const { return fName; }
+
+    const SkString& shortName() const { return fShortName; }
+
+    const SkString& help() const { return fHelpString; }
+    const SkString& extendedHelp() const { return fExtendedHelpString; }
+
+    SkString defaultValue() const {
+        SkString result;
+        switch (fFlagType) {
+            case SkFlagInfo::kBool_FlagType:
+                result.printf("%s", fDefaultBool ? "true" : "false");
+                break;
+            case SkFlagInfo::kString_FlagType: return fDefaultString;
+            case SkFlagInfo::kInt_FlagType: result.printf("%i", fDefaultInt); break;
+            case SkFlagInfo::kDouble_FlagType: result.printf("%2.2f", fDefaultDouble); break;
+            default: SkDEBUGFAIL("Invalid flag type");
+        }
+        return result;
+    }
+
+    SkString typeAsString() const {
+        switch (fFlagType) {
+            case SkFlagInfo::kBool_FlagType: return SkString("bool");
+            case SkFlagInfo::kString_FlagType: return SkString("string");
+            case SkFlagInfo::kInt_FlagType: return SkString("int");
+            case SkFlagInfo::kDouble_FlagType: return SkString("double");
+            default: SkDEBUGFAIL("Invalid flag type"); return SkString();
+        }
+    }
+
+private:
+    SkFlagInfo(const char* name,
+               const char* shortName,
+               FlagTypes   type,
+               const char* helpString,
+               const char* extendedHelpString)
+            : fName(name)
+            , fShortName(shortName)
+            , fFlagType(type)
+            , fHelpString(helpString)
+            , fExtendedHelpString(extendedHelpString)
+            , fBoolValue(nullptr)
+            , fDefaultBool(false)
+            , fIntValue(nullptr)
+            , fDefaultInt(0)
+            , fDoubleValue(nullptr)
+            , fDefaultDouble(0)
+            , fStrings(nullptr) {
+        fNext                   = CommandLineFlags::gHead;
+        CommandLineFlags::gHead = this;
+        SkASSERT(name && strlen(name) > 1);
+        SkASSERT(nullptr == shortName || 1 == strlen(shortName));
+    }
+
+    /**
+     *  Set a StringArray to hold the values stored in defaultStrings.
+     *  @param array The StringArray to modify.
+     *  @param defaultStrings Space separated list of strings that should be inserted into array
+     *      individually.
+     */
+    static void SetDefaultStrings(CommandLineFlags::StringArray* array, const char* defaultStrings);
+
+    // Name of the flag, without initial dashes
+    SkString                       fName;
+    SkString                       fShortName;
+    FlagTypes                      fFlagType;
+    SkString                       fHelpString;
+    SkString                       fExtendedHelpString;
+    bool*                          fBoolValue;
+    bool                           fDefaultBool;
+    int*                           fIntValue;
+    int                            fDefaultInt;
+    double*                        fDoubleValue;
+    double                         fDefaultDouble;
+    CommandLineFlags::StringArray* fStrings;
+    // Both for the help string and in case fStrings is empty.
+    SkString fDefaultString;
+
+    // In order to keep a linked list.
+    SkFlagInfo* fNext;
+};
+#endif  // SK_COMMAND_LINE_FLAGS_H
diff --git a/src/third_party/skia/tools/flags/CommonFlags.h b/src/third_party/skia/tools/flags/CommonFlags.h
new file mode 100644
index 0000000..83ed083
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlags.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#pragma once
+
+#include "include/core/SkString.h"
+#include "include/private/SkTArray.h"
+#include "tools/flags/CommandLineFlags.h"
+
+/**
+ *  Helper to assist in collecting image paths from |dir| specified through a command line
+ * flag.
+ *
+ *  Populates |output|, an array of strings with paths to images to test.
+ *
+ *  Returns true if each argument to the images flag is meaningful:
+ *  - If the file/directory does not exist, return false.
+ *  - If |dir| does not have any supported images (based on file type), return false.
+ *  - If |dir| is a single file, assume the user is deliberately testing this image,
+ *    regardless of file type.
+ */
+bool CollectImages(CommandLineFlags::StringArray dir, SkTArray<SkString>* output);
+
+/**
+ *  Helper to set GrContextOptions from common GPU flags, including
+ *     --gpuThreads
+ *     --cachePathMasks
+ *     --noGS
+ *     --pr
+ *     --disableDriverCorrectnessWorkarounds
+ *     --reduceOpsTaskSplitting
+ *     --dontReduceOpsTaskSplitting
+ */
+void SetCtxOptionsFromCommonFlags(struct GrContextOptions*);
+
+/**
+ *  Enable, disable, or force analytic anti-aliasing using --analyticAA and --forceAnalyticAA.
+ */
+void SetAnalyticAAFromCommonFlags();
diff --git a/src/third_party/skia/tools/flags/CommonFlagsAA.cpp b/src/third_party/skia/tools/flags/CommonFlagsAA.cpp
new file mode 100644
index 0000000..e2df08a
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlagsAA.cpp
@@ -0,0 +1,16 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "src/core/SkScan.h"
+#include "tools/flags/CommonFlags.h"
+
+static DEFINE_bool(analyticAA, true, "If false, disable analytic anti-aliasing");
+static DEFINE_bool(forceAnalyticAA, false,
+            "Force analytic anti-aliasing even if the path is complicated: "
+            "whether it's concave or convex, we consider a path complicated"
+            "if its number of points is comparable to its resolution.");
+
+void SetAnalyticAAFromCommonFlags() {
+    gSkUseAnalyticAA   = FLAGS_analyticAA;
+    gSkForceAnalyticAA = FLAGS_forceAnalyticAA;
+}
diff --git a/src/third_party/skia/tools/flags/CommonFlagsConfig.cpp b/src/third_party/skia/tools/flags/CommonFlagsConfig.cpp
new file mode 100644
index 0000000..dee1d90
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlagsConfig.cpp
@@ -0,0 +1,601 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkImageInfo.h"
+#include "include/private/SkTHash.h"
+#include "src/core/SkColorSpacePriv.h"
+#include "tools/flags/CommonFlagsConfig.h"
+
+#include <stdlib.h>
+
+using sk_gpu_test::GrContextFactory;
+
+#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
+#define DEFAULT_GPU_CONFIG "gles"
+#else
+#define DEFAULT_GPU_CONFIG "gl"
+#endif
+
+static const char defaultConfigs[] = "8888 " DEFAULT_GPU_CONFIG
+                                     " nonrendering "
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+                                     " angle_d3d11_es2"
+#endif
+        ;
+
+#undef DEFAULT_GPU_CONFIG
+
+// clang-format off
+static const struct {
+    const char* predefinedConfig;
+    const char* backend;
+    const char* options;
+} gPredefinedConfigs[] = {
+    { "gl",                    "gpu", "api=gl" },
+    { "gles",                  "gpu", "api=gles" },
+    { "glmsaa4",               "gpu", "api=gl,samples=4" },
+    { "glmsaa8" ,              "gpu", "api=gl,samples=8" },
+    { "glesmsaa4",             "gpu", "api=gles,samples=4" },
+    { "glbetex",               "gpu", "api=gl,surf=betex" },
+    { "glesbetex",             "gpu", "api=gles,surf=betex" },
+    { "glbert",                "gpu", "api=gl,surf=bert" },
+    { "glesbert",              "gpu", "api=gles,surf=bert" },
+    { "gl4444",                "gpu", "api=gl,color=4444" },
+    { "gles4444",              "gpu", "api=gles,color=4444" },
+    { "gl565",                 "gpu", "api=gl,color=565" },
+    { "gl888x",                "gpu", "api=gl,color=888x" },
+    { "gles888x",              "gpu", "api=gles,color=888x" },
+    { "gl1010102",             "gpu", "api=gl,color=1010102" },
+    { "gles1010102",           "gpu", "api=gles,color=1010102" },
+    { "glsrgb",                "gpu", "api=gl,color=srgb" },
+    { "glp3",                  "gpu", "api=gl,color=p3" },
+    { "glesrgb",               "gpu", "api=gl,color=esrgb" },
+    { "glnarrow",              "gpu", "api=gl,color=narrow" },
+    { "glenarrow",             "gpu", "api=gl,color=enarrow" },
+    { "glf16",                 "gpu", "api=gl,color=f16" },
+    { "glf16norm",             "gpu", "api=gl,color=f16norm" },
+    { "glessrgb",              "gpu", "api=gles,color=srgb" },
+    { "glesesrgb",             "gpu", "api=gles,color=esrgb" },
+    { "glesnarrow",            "gpu", "api=gles,color=narrow" },
+    { "glesenarrow",           "gpu", "api=gles,color=enarrow" },
+    { "glesf16",               "gpu", "api=gles,color=f16" },
+    { "glnostencils",          "gpu", "api=gl,stencils=false" },
+    { "gldft",                 "gpu", "api=gl,dit=true" },
+    { "glesdft",               "gpu", "api=gles,dit=true" },
+    { "gltestthreading",       "gpu", "api=gl,testThreading=true" },
+    { "gltestpersistentcache", "gpu", "api=gl,testPersistentCache=1" },
+    { "gltestglslcache",       "gpu", "api=gl,testPersistentCache=2" },
+    { "gltestprecompile",      "gpu", "api=gl,testPrecompile=true" },
+    { "glestestprecompile",    "gpu", "api=gles,testPrecompile=true" },
+    { "angle_d3d11_es2",       "gpu", "api=angle_d3d11_es2" },
+    { "angle_d3d11_es3",       "gpu", "api=angle_d3d11_es3" },
+    { "angle_d3d9_es2",        "gpu", "api=angle_d3d9_es2" },
+    { "angle_d3d11_es2_msaa4", "gpu", "api=angle_d3d11_es2,samples=4" },
+    { "angle_d3d11_es2_msaa8", "gpu", "api=angle_d3d11_es2,samples=8" },
+    { "angle_d3d11_es3_msaa4", "gpu", "api=angle_d3d11_es3,samples=4" },
+    { "angle_d3d11_es3_msaa8", "gpu", "api=angle_d3d11_es3,samples=8" },
+    { "angle_gl_es2",          "gpu", "api=angle_gl_es2" },
+    { "angle_gl_es3",          "gpu", "api=angle_gl_es3" },
+    { "angle_gl_es2_msaa8",    "gpu", "api=angle_gl_es2,samples=8" },
+    { "angle_gl_es3_msaa8",    "gpu", "api=angle_gl_es3,samples=8" },
+    { "commandbuffer",         "gpu", "api=commandbuffer" },
+    { "mock",                  "gpu", "api=mock" },
+#ifdef SK_DAWN
+    { "dawn",                  "gpu", "api=dawn" },
+#endif
+#ifdef SK_VULKAN
+    { "vk",                    "gpu", "api=vulkan" },
+    { "vknostencils",          "gpu", "api=vulkan,stencils=false" },
+    { "vk1010102",             "gpu", "api=vulkan,color=1010102" },
+    { "vksrgb",                "gpu", "api=vulkan,color=srgb" },
+    { "vkesrgb",               "gpu", "api=vulkan,color=esrgb" },
+    { "vknarrow",              "gpu", "api=vulkan,color=narrow" },
+    { "vkenarrow",             "gpu", "api=vulkan,color=enarrow" },
+    { "vkf16",                 "gpu", "api=vulkan,color=f16" },
+    { "vkmsaa4",               "gpu", "api=vulkan,samples=4" },
+    { "vkmsaa8",               "gpu", "api=vulkan,samples=8" },
+    { "vkbetex",               "gpu", "api=vulkan,surf=betex" },
+    { "vkbert",                "gpu", "api=vulkan,surf=bert" },
+    { "vktestpersistentcache", "gpu", "api=vulkan,testPersistentCache=1" },
+#endif
+#ifdef SK_METAL
+    { "mtl",                   "gpu", "api=metal" },
+    { "mtl1010102",            "gpu", "api=metal,color=1010102" },
+    { "mtlmsaa4",              "gpu", "api=metal,samples=4" },
+    { "mtlmsaa8",              "gpu", "api=metal,samples=8" },
+#endif
+};
+// clang-format on
+
+static const char configHelp[] =
+        "Options: 565 8888 srgb f16 nonrendering null pdf pdfa skp pipe svg xps";
+
+static const char* config_help_fn() {
+    static SkString helpString;
+    helpString.set(configHelp);
+    for (const auto& config : gPredefinedConfigs) {
+        helpString.appendf(" %s", config.predefinedConfig);
+    }
+    helpString.append(" or use extended form 'backend[option=value,...]'.\n");
+    return helpString.c_str();
+}
+
+static const char configExtendedHelp[] =
+        "Extended form: 'backend(option=value,...)'\n\n"
+        "Possible backends and options:\n"
+        "\n"
+        "gpu[api=string,color=string,dit=bool,samples=int]\n"
+        "\tapi\ttype: string\trequired\n"
+        "\t    Select graphics API to use with gpu backend.\n"
+        "\t    Options:\n"
+        "\t\tgl    \t\t\tUse OpenGL.\n"
+        "\t\tgles  \t\t\tUse OpenGL ES.\n"
+        "\t\tnullgl \t\t\tUse null OpenGL.\n"
+        "\t\tangle_d3d9_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D9 backend.\n"
+        "\t\tangle_d3d11_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D11 backend.\n"
+        "\t\tangle_d3d11_es3\t\tUse OpenGL ES3 on the ANGLE Direct3D11 backend.\n"
+        "\t\tangle_gl_es2\t\tUse OpenGL ES2 on the ANGLE OpenGL backend.\n"
+        "\t\tangle_gl_es3\t\tUse OpenGL ES3 on the ANGLE OpenGL backend.\n"
+        "\t\tcommandbuffer\t\tUse command buffer.\n"
+        "\t\tmock\t\t\tUse mock context.\n"
+#ifdef SK_VULKAN
+        "\t\tvulkan\t\t\tUse Vulkan.\n"
+#endif
+#ifdef SK_METAL
+        "\t\tmetal\t\t\tUse Metal.\n"
+#endif
+        "\tcolor\ttype: string\tdefault: 8888.\n"
+        "\t    Select framebuffer color format.\n"
+        "\t    Options:\n"
+        "\t\t8888\t\t\tLinear 8888.\n"
+        "\t\t888x\t\t\tLinear 888x.\n"
+        "\t\t4444\t\t\tLinear 4444.\n"
+        "\t\t565\t\t\tLinear 565.\n"
+        "\t\t1010102\t\t\tLinear 1010102.\n"
+        "\t\tsrgb\t\t\tsRGB 8888.\n"
+        "\t\tesrgb\t\t\tsRGB 16-bit floating point.\n"
+        "\t\tnarrow\t\t\tNarrow gamut 8888.\n"
+        "\t\tenarrow\t\t\tNarrow gamut 16-bit floating point.\n"
+        "\t\tf16\t\t\tLinearly blended 16-bit floating point.\n"
+        "\tdit\ttype: bool\tdefault: false.\n"
+        "\t    Use device independent text.\n"
+        "\tsamples\ttype: int\tdefault: 0.\n"
+        "\t    Use multisampling with N samples.\n"
+        "\tstencils\ttype: bool\tdefault: true.\n"
+        "\t    Allow the use of stencil buffers.\n"
+        "\ttestThreading\ttype: bool\tdefault: false.\n"
+        "\t    Run with and without worker threads, check that results match.\n"
+        "\ttestPersistentCache\ttype: int\tdefault: 0.\n"
+        "\t    1: Run using a pre-warmed binary GrContextOptions::fPersistentCache.\n"
+        "\t    2: Run using a pre-warmed GLSL GrContextOptions::fPersistentCache.\n"
+        "\tsurf\ttype: string\tdefault: default.\n"
+        "\t    Controls the type of backing store for SkSurfaces.\n"
+        "\t    Options:\n"
+        "\t\tdefault\t\t\tA renderable texture created in Skia's resource cache.\n"
+        "\t\tbetex\t\t\tA wrapped backend texture.\n"
+        "\t\tbert\t\t\tA wrapped backend render target\n"
+        "\n"
+        "Predefined configs:\n\n"
+        // Help text for pre-defined configs is auto-generated from gPredefinedConfigs
+        ;
+
+static const char* config_extended_help_fn() {
+    static SkString helpString;
+    helpString.set(configExtendedHelp);
+    for (const auto& config : gPredefinedConfigs) {
+        helpString.appendf("\t%-10s\t= gpu(%s)\n", config.predefinedConfig, config.options);
+    }
+    return helpString.c_str();
+}
+
+DEFINE_extended_string(config, defaultConfigs, config_help_fn(), config_extended_help_fn());
+
+SkCommandLineConfig::SkCommandLineConfig(const SkString&           tag,
+                                         const SkString&           backend,
+                                         const SkTArray<SkString>& viaParts)
+        : fTag(tag), fBackend(backend), fViaParts(viaParts) {}
+SkCommandLineConfig::~SkCommandLineConfig() {}
+
+static bool parse_option_int(const SkString& value, int* outInt) {
+    if (value.isEmpty()) {
+        return false;
+    }
+    char* endptr   = nullptr;
+    long  intValue = strtol(value.c_str(), &endptr, 10);
+    if (*endptr != '\0') {
+        return false;
+    }
+    *outInt = static_cast<int>(intValue);
+    return true;
+}
+static bool parse_option_bool(const SkString& value, bool* outBool) {
+    if (value.equals("true")) {
+        *outBool = true;
+        return true;
+    }
+    if (value.equals("false")) {
+        *outBool = false;
+        return true;
+    }
+    return false;
+}
+static bool parse_option_gpu_api(const SkString&                      value,
+                                 SkCommandLineConfigGpu::ContextType* outContextType) {
+    if (value.equals("gl")) {
+        *outContextType = GrContextFactory::kGL_ContextType;
+        return true;
+    }
+    if (value.equals("gles")) {
+        *outContextType = GrContextFactory::kGLES_ContextType;
+        return true;
+    }
+    if (value.equals("angle_d3d9_es2")) {
+        *outContextType = GrContextFactory::kANGLE_D3D9_ES2_ContextType;
+        return true;
+    }
+    if (value.equals("angle_d3d11_es2")) {
+        *outContextType = GrContextFactory::kANGLE_D3D11_ES2_ContextType;
+        return true;
+    }
+    if (value.equals("angle_d3d11_es3")) {
+        *outContextType = GrContextFactory::kANGLE_D3D11_ES3_ContextType;
+        return true;
+    }
+    if (value.equals("angle_gl_es2")) {
+        *outContextType = GrContextFactory::kANGLE_GL_ES2_ContextType;
+        return true;
+    }
+    if (value.equals("angle_gl_es3")) {
+        *outContextType = GrContextFactory::kANGLE_GL_ES3_ContextType;
+        return true;
+    }
+    if (value.equals("commandbuffer")) {
+        *outContextType = GrContextFactory::kCommandBuffer_ContextType;
+        return true;
+    }
+    if (value.equals("mock")) {
+        *outContextType = GrContextFactory::kMock_ContextType;
+        return true;
+    }
+#ifdef SK_VULKAN
+    if (value.equals("vulkan")) {
+        *outContextType = GrContextFactory::kVulkan_ContextType;
+        return true;
+    }
+#endif
+#ifdef SK_METAL
+    if (value.equals("metal")) {
+        *outContextType = GrContextFactory::kMetal_ContextType;
+        return true;
+    }
+#endif
+#ifdef SK_DAWN
+    if (value.equals("dawn")) {
+        *outContextType = GrContextFactory::kDawn_ContextType;
+        return true;
+    }
+#endif
+    return false;
+}
+
+static bool parse_option_gpu_color(const SkString&      value,
+                                   SkColorType*         outColorType,
+                                   SkAlphaType*         alphaType,
+                                   sk_sp<SkColorSpace>* outColorSpace) {
+    // We always use premul unless the color type is 565.
+    *alphaType = kPremul_SkAlphaType;
+
+    if (value.equals("8888")) {
+        *outColorType  = kRGBA_8888_SkColorType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("888x")) {
+        *outColorType  = kRGB_888x_SkColorType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("8888s")) {
+        *outColorType  = kRGBA_8888_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGB();
+    } else if (value.equals("bgra8")) {
+        *outColorType  = kBGRA_8888_SkColorType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("bgra8s")) {
+        *outColorType  = kBGRA_8888_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGB();
+    } else if (value.equals("4444")) {
+        *outColorType  = kARGB_4444_SkColorType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("565")) {
+        *outColorType  = kRGB_565_SkColorType;
+        *alphaType     = kOpaque_SkAlphaType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("1010102")) {
+        *outColorType  = kRGBA_1010102_SkColorType;
+        *outColorSpace = nullptr;
+    } else if (value.equals("srgb")) {
+        *outColorType  = kRGBA_8888_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGB();
+    } else if (value.equals("p3")) {
+        *outColorType  = kRGBA_8888_SkColorType;
+        *outColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
+    } else if (value.equals("esrgb")) {
+        *outColorType  = kRGBA_F16_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGB();
+    } else if (value.equals("narrow") || value.equals("enarrow")) {
+        *outColorType  = value.equals("narrow") ? kRGBA_8888_SkColorType : kRGBA_F16_SkColorType;
+        *outColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50);
+    } else if (value.equals("f16")) {
+        *outColorType  = kRGBA_F16_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGBLinear();
+    } else if (value.equals("f16norm")) {
+        *outColorType  = kRGBA_F16Norm_SkColorType;
+        *outColorSpace = SkColorSpace::MakeSRGB();
+    } else {
+        return false;
+    }
+    return true;
+}
+
+static bool parse_option_gpu_surf_type(const SkString&                   value,
+                                       SkCommandLineConfigGpu::SurfType* surfType) {
+    if (value.equals("default")) {
+        *surfType = SkCommandLineConfigGpu::SurfType::kDefault;
+        return true;
+    }
+    if (value.equals("betex")) {
+        *surfType = SkCommandLineConfigGpu::SurfType::kBackendTexture;
+        return true;
+    }
+    if (value.equals("bert")) {
+        *surfType = SkCommandLineConfigGpu::SurfType::kBackendRenderTarget;
+        return true;
+    }
+    return false;
+}
+
+// Extended options take form --config item[key1=value1,key2=value2,...]
+// Example: --config gpu[api=gl,color=8888]
+class ExtendedOptions {
+public:
+    ExtendedOptions(const SkString& optionsString, bool* outParseSucceeded) {
+        SkTArray<SkString> optionParts;
+        SkStrSplit(optionsString.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
+        for (int i = 0; i < optionParts.count(); ++i) {
+            SkTArray<SkString> keyValueParts;
+            SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
+            if (keyValueParts.count() != 2) {
+                *outParseSucceeded = false;
+                return;
+            }
+            const SkString& key   = keyValueParts[0];
+            const SkString& value = keyValueParts[1];
+            if (fOptionsMap.find(key) == nullptr) {
+                fOptionsMap.set(key, value);
+            } else {
+                // Duplicate values are not allowed.
+                *outParseSucceeded = false;
+                return;
+            }
+        }
+        *outParseSucceeded = true;
+    }
+
+    bool get_option_gpu_color(const char*          optionKey,
+                              SkColorType*         outColorType,
+                              SkAlphaType*         alphaType,
+                              sk_sp<SkColorSpace>* outColorSpace,
+                              bool                 optional = true) const {
+        SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+        if (optionValue == nullptr) {
+            return optional;
+        }
+        return parse_option_gpu_color(*optionValue, outColorType, alphaType, outColorSpace);
+    }
+
+    bool get_option_gpu_api(const char*                          optionKey,
+                            SkCommandLineConfigGpu::ContextType* outContextType,
+                            bool                                 optional = true) const {
+        SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+        if (optionValue == nullptr) {
+            return optional;
+        }
+        return parse_option_gpu_api(*optionValue, outContextType);
+    }
+
+    bool get_option_gpu_surf_type(const char*                       optionKey,
+                                  SkCommandLineConfigGpu::SurfType* outSurfType,
+                                  bool                              optional = true) const {
+        SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+        if (optionValue == nullptr) {
+            return optional;
+        }
+        return parse_option_gpu_surf_type(*optionValue, outSurfType);
+    }
+
+    bool get_option_int(const char* optionKey, int* outInt, bool optional = true) const {
+        SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+        if (optionValue == nullptr) {
+            return optional;
+        }
+        return parse_option_int(*optionValue, outInt);
+    }
+
+    bool get_option_bool(const char* optionKey, bool* outBool, bool optional = true) const {
+        SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+        if (optionValue == nullptr) {
+            return optional;
+        }
+        return parse_option_bool(*optionValue, outBool);
+    }
+
+private:
+    SkTHashMap<SkString, SkString> fOptionsMap;
+};
+
+SkCommandLineConfigGpu::SkCommandLineConfigGpu(const SkString&           tag,
+                                               const SkTArray<SkString>& viaParts,
+                                               ContextType               contextType,
+                                               bool                      useDIText,
+                                               int                       samples,
+                                               SkColorType               colorType,
+                                               SkAlphaType               alphaType,
+                                               sk_sp<SkColorSpace>       colorSpace,
+                                               bool                      useStencilBuffers,
+                                               bool                      testThreading,
+                                               int                       testPersistentCache,
+                                               bool                      testPrecompile,
+                                               SurfType                  surfType)
+        : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
+        , fContextType(contextType)
+        , fContextOverrides(ContextOverrides::kNone)
+        , fUseDIText(useDIText)
+        , fSamples(samples)
+        , fColorType(colorType)
+        , fAlphaType(alphaType)
+        , fColorSpace(std::move(colorSpace))
+        , fTestThreading(testThreading)
+        , fTestPersistentCache(testPersistentCache)
+        , fTestPrecompile(testPrecompile)
+        , fSurfType(surfType) {
+    if (!useStencilBuffers) {
+        fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
+    }
+}
+
+SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString&           tag,
+                                                      const SkTArray<SkString>& vias,
+                                                      const SkString&           options) {
+    // Defaults for GPU backend.
+    SkCommandLineConfigGpu::ContextType contextType         = GrContextFactory::kGL_ContextType;
+    bool                                useDIText           = false;
+    int                                 samples             = 1;
+    SkColorType                         colorType           = kRGBA_8888_SkColorType;
+    SkAlphaType                         alphaType           = kPremul_SkAlphaType;
+    sk_sp<SkColorSpace>                 colorSpace          = nullptr;
+    bool                                useStencils         = true;
+    bool                                testThreading       = false;
+    int                                 testPersistentCache = 0;
+    bool                                testPrecompile      = false;
+    SkCommandLineConfigGpu::SurfType    surfType = SkCommandLineConfigGpu::SurfType::kDefault;
+
+    bool            parseSucceeded = false;
+    ExtendedOptions extendedOptions(options, &parseSucceeded);
+    if (!parseSucceeded) {
+        return nullptr;
+    }
+
+    bool validOptions =
+            extendedOptions.get_option_gpu_api("api", &contextType, false) &&
+            extendedOptions.get_option_bool("dit", &useDIText) &&
+            extendedOptions.get_option_int("samples", &samples) &&
+            extendedOptions.get_option_gpu_color("color", &colorType, &alphaType, &colorSpace) &&
+            extendedOptions.get_option_bool("stencils", &useStencils) &&
+            extendedOptions.get_option_bool("testThreading", &testThreading) &&
+            extendedOptions.get_option_int("testPersistentCache", &testPersistentCache) &&
+            extendedOptions.get_option_bool("testPrecompile", &testPrecompile) &&
+            extendedOptions.get_option_gpu_surf_type("surf", &surfType);
+
+    // testing threading and the persistent cache are mutually exclusive.
+    if (!validOptions || (testThreading && (testPersistentCache != 0))) {
+        return nullptr;
+    }
+
+    return new SkCommandLineConfigGpu(tag,
+                                      vias,
+                                      contextType,
+                                      useDIText,
+                                      samples,
+                                      colorType,
+                                      alphaType,
+                                      colorSpace,
+                                      useStencils,
+                                      testThreading,
+                                      testPersistentCache,
+                                      testPrecompile,
+                                      surfType);
+}
+
+SkCommandLineConfigSvg::SkCommandLineConfigSvg(const SkString&           tag,
+                                               const SkTArray<SkString>& viaParts,
+                                               int                       pageIndex)
+        : SkCommandLineConfig(tag, SkString("svg"), viaParts), fPageIndex(pageIndex) {}
+
+SkCommandLineConfigSvg* parse_command_line_config_svg(const SkString&           tag,
+                                                      const SkTArray<SkString>& vias,
+                                                      const SkString&           options) {
+    // Defaults for SVG backend.
+    int pageIndex = 0;
+
+    bool            parseSucceeded = false;
+    ExtendedOptions extendedOptions(options, &parseSucceeded);
+    if (!parseSucceeded) {
+        return nullptr;
+    }
+
+    bool validOptions = extendedOptions.get_option_int("page", &pageIndex);
+
+    if (!validOptions) {
+        return nullptr;
+    }
+
+    return new SkCommandLineConfigSvg(tag, vias, pageIndex);
+}
+
+void ParseConfigs(const CommandLineFlags::StringArray& configs,
+                  SkCommandLineConfigArray*            outResult) {
+    outResult->reset();
+    for (int i = 0; i < configs.count(); ++i) {
+        SkString           extendedBackend;
+        SkString           extendedOptions;
+        SkString           simpleBackend;
+        SkTArray<SkString> vias;
+
+        SkString           tag(configs[i]);
+        SkTArray<SkString> parts;
+        SkStrSplit(tag.c_str(), "[", kStrict_SkStrSplitMode, &parts);
+        if (parts.count() == 2) {
+            SkTArray<SkString> parts2;
+            SkStrSplit(parts[1].c_str(), "]", kStrict_SkStrSplitMode, &parts2);
+            if (parts2.count() == 2 && parts2[1].isEmpty()) {
+                SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias);
+                if (vias.count()) {
+                    extendedBackend = vias[vias.count() - 1];
+                    vias.pop_back();
+                } else {
+                    extendedBackend = parts[0];
+                }
+                extendedOptions = parts2[0];
+                simpleBackend.printf("%s[%s]", extendedBackend.c_str(), extendedOptions.c_str());
+            }
+        }
+
+        if (extendedBackend.isEmpty()) {
+            simpleBackend = tag;
+            SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias);
+            if (vias.count()) {
+                simpleBackend = vias[vias.count() - 1];
+                vias.pop_back();
+            }
+            for (auto& predefinedConfig : gPredefinedConfigs) {
+                if (simpleBackend.equals(predefinedConfig.predefinedConfig)) {
+                    extendedBackend = predefinedConfig.backend;
+                    extendedOptions = predefinedConfig.options;
+                    break;
+                }
+            }
+        }
+        SkCommandLineConfig* parsedConfig = nullptr;
+        if (extendedBackend.equals("gpu")) {
+            parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions);
+        }
+        if (extendedBackend.equals("svg")) {
+            parsedConfig = parse_command_line_config_svg(tag, vias, extendedOptions);
+        }
+        if (!parsedConfig) {
+            parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias);
+        }
+        outResult->emplace_back(parsedConfig);
+    }
+}
diff --git a/src/third_party/skia/tools/flags/CommonFlagsConfig.h b/src/third_party/skia/tools/flags/CommonFlagsConfig.h
new file mode 100644
index 0000000..6eb5cba
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlagsConfig.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SK_COMMON_FLAGS_CONFIG_H
+#define SK_COMMON_FLAGS_CONFIG_H
+
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/gpu/GrContextFactory.h"
+
+DECLARE_string(config);
+
+class SkCommandLineConfigGpu;
+class SkCommandLineConfigSvg;
+
+// SkCommandLineConfig represents a Skia rendering configuration string.
+// The string has following form:
+// tag:
+//   [via-]*backend
+// where 'backend' consists of chars excluding hyphen
+// and each 'via' consists of chars excluding hyphen.
+class SkCommandLineConfig {
+public:
+    SkCommandLineConfig(const SkString&           tag,
+                        const SkString&           backend,
+                        const SkTArray<SkString>& viaParts);
+    virtual ~SkCommandLineConfig();
+    virtual const SkCommandLineConfigGpu* asConfigGpu() const { return nullptr; }
+    virtual const SkCommandLineConfigSvg* asConfigSvg() const { return nullptr; }
+    const SkString&                       getTag() const { return fTag; }
+    const SkString&                       getBackend() const { return fBackend; }
+    const SkTArray<SkString>&             getViaParts() const { return fViaParts; }
+
+private:
+    SkString           fTag;
+    SkString           fBackend;
+    SkTArray<SkString> fViaParts;
+};
+
+// SkCommandLineConfigGpu is a SkCommandLineConfig that extracts information out of the backend
+// part of the tag. It is constructed tags that have:
+// * backends of form "gpu[option=value,option2=value,...]"
+// * backends that represent a shorthand of above (such as "glmsaa16" representing
+// "gpu(api=gl,samples=16)")
+class SkCommandLineConfigGpu : public SkCommandLineConfig {
+public:
+    enum class SurfType { kDefault, kBackendTexture, kBackendRenderTarget };
+    typedef sk_gpu_test::GrContextFactory::ContextType      ContextType;
+    typedef sk_gpu_test::GrContextFactory::ContextOverrides ContextOverrides;
+
+    SkCommandLineConfigGpu(const SkString&           tag,
+                           const SkTArray<SkString>& viaParts,
+                           ContextType               contextType,
+                           bool                      useDIText,
+                           int                       samples,
+                           SkColorType               colorType,
+                           SkAlphaType               alphaType,
+                           sk_sp<SkColorSpace>       colorSpace,
+                           bool                      useStencilBuffers,
+                           bool                      testThreading,
+                           int                       testPersistentCache,
+                           bool                      testPrecompile,
+                           SurfType);
+
+    const SkCommandLineConfigGpu* asConfigGpu() const override { return this; }
+    ContextType                   getContextType() const { return fContextType; }
+    ContextOverrides              getContextOverrides() const { return fContextOverrides; }
+    bool          getUseDIText() const { return fUseDIText; }
+    int           getSamples() const { return fSamples; }
+    SkColorType   getColorType() const { return fColorType; }
+    SkAlphaType   getAlphaType() const { return fAlphaType; }
+    SkColorSpace* getColorSpace() const { return fColorSpace.get(); }
+    bool          getTestThreading() const { return fTestThreading; }
+    int           getTestPersistentCache() const { return fTestPersistentCache; }
+    bool          getTestPrecompile() const { return fTestPrecompile; }
+    SurfType      getSurfType() const { return fSurfType; }
+
+private:
+    ContextType         fContextType;
+    ContextOverrides    fContextOverrides;
+    bool                fUseDIText;
+    int                 fSamples;
+    SkColorType         fColorType;
+    SkAlphaType         fAlphaType;
+    sk_sp<SkColorSpace> fColorSpace;
+    bool                fTestThreading;
+    int                 fTestPersistentCache;
+    bool                fTestPrecompile;
+    SurfType            fSurfType;
+};
+
+// SkCommandLineConfigSvg is a SkCommandLineConfig that extracts information out of the backend
+// part of the tag. It is constructed tags that have:
+// * backends of form "svg[option=value,option2=value,...]"
+class SkCommandLineConfigSvg : public SkCommandLineConfig {
+public:
+    SkCommandLineConfigSvg(const SkString& tag, const SkTArray<SkString>& viaParts, int pageIndex);
+    const SkCommandLineConfigSvg* asConfigSvg() const override { return this; }
+
+    int getPageIndex() const { return fPageIndex; }
+
+private:
+    int fPageIndex;
+};
+
+typedef SkTArray<std::unique_ptr<SkCommandLineConfig>, true> SkCommandLineConfigArray;
+void ParseConfigs(const CommandLineFlags::StringArray& configList,
+                  SkCommandLineConfigArray*            outResult);
+
+#endif
diff --git a/src/third_party/skia/tools/flags/CommonFlagsGpu.cpp b/src/third_party/skia/tools/flags/CommonFlagsGpu.cpp
new file mode 100644
index 0000000..d341ce5
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlagsGpu.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkExecutor.h"
+#include "include/gpu/GrContextOptions.h"
+#include "tools/flags/CommonFlags.h"
+
+DEFINE_int(gpuThreads,
+             2,
+             "Create this many extra threads to assist with GPU work, "
+             "including software path rendering. Defaults to two.");
+
+static DEFINE_bool(cachePathMasks, true,
+                   "Allows path mask textures to be cached in GPU configs.");
+
+static DEFINE_bool(noGS, false, "Disables support for geometry shaders.");
+
+static DEFINE_bool(cc, false, "Allow coverage counting shortcuts to render paths?");
+
+static DEFINE_string(pr, "",
+              "Set of enabled gpu path renderers. Defined as a list of: "
+              "[~]none [~]dashline [~]nvpr [~]ccpr [~]aahairline [~]aaconvex [~]aalinearizing "
+              "[~]small [~]tess] [~]all");
+
+static DEFINE_bool(disableDriverCorrectnessWorkarounds, false,
+                   "Disables all GPU driver correctness workarounds");
+
+static DEFINE_bool(reduceOpsTaskSplitting, false, "Improve opsTask sorting");
+static DEFINE_bool(dontReduceOpsTaskSplitting, false, "Allow more opsTask splitting");
+
+static GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
+    if (!strcmp(name, "none")) {
+        return GpuPathRenderers::kNone;
+    } else if (!strcmp(name, "dashline")) {
+        return GpuPathRenderers::kDashLine;
+    } else if (!strcmp(name, "nvpr")) {
+        return GpuPathRenderers::kStencilAndCover;
+    } else if (!strcmp(name, "ccpr")) {
+        return GpuPathRenderers::kCoverageCounting;
+    } else if (!strcmp(name, "aahairline")) {
+        return GpuPathRenderers::kAAHairline;
+    } else if (!strcmp(name, "aaconvex")) {
+        return GpuPathRenderers::kAAConvex;
+    } else if (!strcmp(name, "aalinearizing")) {
+        return GpuPathRenderers::kAALinearizing;
+    } else if (!strcmp(name, "small")) {
+        return GpuPathRenderers::kSmall;
+    } else if (!strcmp(name, "tess")) {
+        return GpuPathRenderers::kTessellating;
+    } else if (!strcmp(name, "all")) {
+        return GpuPathRenderers::kAll;
+    }
+    SK_ABORT(SkStringPrintf("error: unknown named path renderer \"%s\"\n", name).c_str());
+}
+
+static GpuPathRenderers collect_gpu_path_renderers_from_flags() {
+    if (FLAGS_pr.isEmpty()) {
+        return GpuPathRenderers::kAll;
+    }
+
+    GpuPathRenderers gpuPathRenderers = ('~' == FLAGS_pr[0][0])
+            ? GpuPathRenderers::kAll
+            : GpuPathRenderers::kNone;
+
+    for (int i = 0; i < FLAGS_pr.count(); ++i) {
+        const char* name = FLAGS_pr[i];
+        if (name[0] == '~') {
+            gpuPathRenderers &= ~get_named_pathrenderers_flags(&name[1]);
+        } else {
+            gpuPathRenderers |= get_named_pathrenderers_flags(name);
+        }
+    }
+    return gpuPathRenderers;
+}
+
+void SetCtxOptionsFromCommonFlags(GrContextOptions* ctxOptions) {
+    static std::unique_ptr<SkExecutor> gGpuExecutor = (0 != FLAGS_gpuThreads)
+        ? SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)
+        : nullptr;
+
+    ctxOptions->fExecutor                            = gGpuExecutor.get();
+    ctxOptions->fDisableCoverageCountingPaths        = !FLAGS_cc;
+    ctxOptions->fAllowPathMaskCaching                = FLAGS_cachePathMasks;
+    ctxOptions->fSuppressGeometryShaders             = FLAGS_noGS;
+    ctxOptions->fGpuPathRenderers                    = collect_gpu_path_renderers_from_flags();
+    ctxOptions->fDisableDriverCorrectnessWorkarounds = FLAGS_disableDriverCorrectnessWorkarounds;
+
+    if (FLAGS_reduceOpsTaskSplitting) {
+        SkASSERT(!FLAGS_dontReduceOpsTaskSplitting);
+        ctxOptions->fReduceOpsTaskSplitting = GrContextOptions::Enable::kYes;
+    } else if (FLAGS_dontReduceOpsTaskSplitting) {
+        ctxOptions->fReduceOpsTaskSplitting = GrContextOptions::Enable::kNo;
+    }
+}
diff --git a/src/third_party/skia/tools/flags/CommonFlagsImages.cpp b/src/third_party/skia/tools/flags/CommonFlagsImages.cpp
new file mode 100644
index 0000000..60b5f12
--- /dev/null
+++ b/src/third_party/skia/tools/flags/CommonFlagsImages.cpp
@@ -0,0 +1,94 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "src/core/SkOSFile.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/flags/CommonFlags.h"
+
+bool CollectImages(CommandLineFlags::StringArray images, SkTArray<SkString>* output) {
+    SkASSERT(output);
+
+    static const char* const exts[] = {
+        "bmp",
+        "gif",
+        "jpg",
+        "jpeg",
+        "png",
+        "webp",
+        "ktx",
+        "astc",
+        "wbmp",
+        "ico",
+#if !defined(SK_BUILD_FOR_WIN)
+        "BMP",
+        "GIF",
+        "JPG",
+        "JPEG",
+        "PNG",
+        "WEBP",
+        "KTX",
+        "ASTC",
+        "WBMP",
+        "ICO",
+#endif
+#ifdef SK_HAS_HEIF_LIBRARY
+        "heic",
+#if !defined(SK_BUILD_FOR_WIN)
+        "HEIC",
+#endif
+#endif
+#ifdef SK_CODEC_DECODES_RAW
+        "arw",
+        "cr2",
+        "dng",
+        "nef",
+        "nrw",
+        "orf",
+        "raf",
+        "rw2",
+        "pef",
+        "srw",
+#if !defined(SK_BUILD_FOR_WIN)
+        "ARW",
+        "CR2",
+        "DNG",
+        "NEF",
+        "NRW",
+        "ORF",
+        "RAF",
+        "RW2",
+        "PEF",
+        "SRW",
+#endif
+#endif
+    };
+
+    for (int i = 0; i < images.count(); ++i) {
+        const char* flag = images[i];
+        if (!sk_exists(flag)) {
+            SkDebugf("%s does not exist!\n", flag);
+            return false;
+        }
+
+        if (sk_isdir(flag)) {
+            // If the value passed in is a directory, add all the images
+            bool foundAnImage = false;
+            for (const char* ext : exts) {
+                SkOSFile::Iter it(flag, ext);
+                SkString       file;
+                while (it.next(&file)) {
+                    foundAnImage        = true;
+                    output->push_back() = SkOSPath::Join(flag, file.c_str());
+                }
+            }
+            if (!foundAnImage) {
+                SkDebugf("No supported images found in %s!\n", flag);
+                return false;
+            }
+        } else {
+            // Also add the value if it is a single image
+            output->push_back() = flag;
+        }
+    }
+    return true;
+}
diff --git a/src/third_party/skia/tools/flags/SkCommandLineFlags.h b/src/third_party/skia/tools/flags/SkCommandLineFlags.h
deleted file mode 100644
index 78919c1..0000000
--- a/src/third_party/skia/tools/flags/SkCommandLineFlags.h
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SK_COMMAND_LINE_FLAGS_H
-#define SK_COMMAND_LINE_FLAGS_H
-
-#include "../private/SkTArray.h"
-#include "../private/SkTDArray.h"
-#include "SkString.h"
-
-/**
- *  Including this file (and compiling SkCommandLineFlags.cpp) provides command line
- *  parsing. In order to use it, use the following macros in global
- *  namespace:
- *
- *  DEFINE_bool(name, defaultValue, helpString);
- *  DEFINE_string(name, defaultValue, helpString);
- *  DEFINE_int32(name, defaultValue, helpString);
- *  DEFINE_double(name, defaultValue, helpString);
- *
- *  Then, in main, call SkCommandLineFlags::SetUsage() to describe usage and call
- *  SkCommandLineFlags::Parse() to parse the flags. Henceforth, each flag can
- *  be referenced using
- *
- *  FLAGS_name
- *
- *  For example, the line
- *
- *  DEFINE_bool(boolean, false, "The variable boolean does such and such");
- *
- *  will create the following variable:
- *
- *  bool FLAGS_boolean;
- *
- *  which will initially be set to false, and can be set to true by using the
- *  flag "--boolean" on the commandline. "--noboolean" will set FLAGS_boolean
- *  to false. FLAGS_boolean can also be set using "--boolean=true" or
- *  "--boolean true" (where "true" can be replaced by "false", "TRUE", "FALSE",
- *  "1" or "0").
- *
- *  The helpString will be printed if the help flag (-h or -help) is used.
- *
- *  Similarly, the line
- *
- *  DEFINE_int32(integer, .., ..);
- *
- *  will create
- *
- *  int32_t FLAGS_integer;
- *
- *  and
- *
- *  DEFINE_double(real, .., ..);
- *
- *  will create
- *
- *  double FLAGS_real;
- *
- *  These flags can be set by specifying, for example, "--integer 7" and
- *  "--real 3.14" on the command line.
- *
- *  Unlike the others, the line
- *
- *  DEFINE_string(args, .., ..);
- *
- *  creates an array:
- *
- *  SkCommandLineFlags::StringArray FLAGS_args;
- *
- *  If the default value is the empty string, FLAGS_args will default to a size
- *  of zero. Otherwise it will default to a size of 1 with the default string
- *  as its value. All strings that follow the flag on the command line (until
- *  a string that begins with '-') will be entries in the array.
- *
- *  DEFINE_extended_string(args, .., .., extendedHelpString);
- *
- *  creates a similar string array flag as DEFINE_string. The flag will have extended help text
- *  (extendedHelpString) that can the user can see with '--help <args>' flag.
- *
- *  Any flag can be referenced from another file after using the following:
- *
- *  DECLARE_x(name);
- *
- *  (where 'x' is the type specified in the DEFINE).
- *
- *  Inspired by gflags (https://code.google.com/p/gflags/). Is not quite as
- *  robust as gflags, but suits our purposes. For example, allows creating
- *  a flag -h or -help which will never be used, since SkCommandLineFlags handles it.
- *  SkCommandLineFlags will also allow creating --flag and --noflag. Uses the same input
- *  format as gflags and creates similarly named variables (i.e. FLAGS_name).
- *  Strings are handled differently (resulting variable will be an array of
- *  strings) so that a flag can be followed by multiple parameters.
- */
-
-class SkFlagInfo;
-
-class SkCommandLineFlags {
-
-public:
-    /**
-     *  Call to set the help message to be displayed. Should be called before
-     *  Parse.
-     */
-    static void SetUsage(const char* usage);
-
-    /**
-     *  Call this to display the help message. Should be called after SetUsage.
-     */
-    static void PrintUsage();
-
-    /**
-     *  Call at the beginning of main to parse flags created by DEFINE_x, above.
-     *  Must only be called once.
-     */
-    static void Parse(int argc, char** argv);
-
-    /**
-     *  Custom class for holding the arguments for a string flag.
-     *  Publicly only has accessors so the strings cannot be modified.
-     */
-    class StringArray {
-    public:
-        StringArray() { }
-        explicit StringArray(const SkTArray<SkString>& strings)
-            : fStrings(strings) {
-        }
-        const char* operator[](int i) const {
-            SkASSERT(i >= 0 && i < fStrings.count());
-            return fStrings[i].c_str();
-        }
-
-        int count() const {
-            return fStrings.count();
-        }
-
-        bool isEmpty() const { return this->count() == 0; }
-
-        /**
-         * Returns true iff string is equal to one of the strings in this array.
-         */
-        bool contains(const char* string) const {
-            for (int i = 0; i < fStrings.count(); i++) {
-                if (fStrings[i].equals(string)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        void set(int i, const char* str) {
-            fStrings[i].set(str);
-        }
-
-    private:
-        void reset() { fStrings.reset(); }
-
-        void append(const char* string) {
-            fStrings.push_back().set(string);
-        }
-
-        void append(const char* string, size_t length) {
-            fStrings.push_back().set(string, length);
-        }
-
-        SkTArray<SkString> fStrings;
-
-        friend class SkFlagInfo;
-    };
-
-    /* Takes a list of the form [~][^]match[$]
-     ~ causes a matching test to always be skipped
-     ^ requires the start of the test to match
-     $ requires the end of the test to match
-     ^ and $ requires an exact match
-     If a test does not match any list entry, it is skipped unless some list entry starts with ~
-    */
-    static bool ShouldSkip(const SkTDArray<const char*>& strings, const char* name);
-    static bool ShouldSkip(const StringArray& strings, const char* name);
-
-private:
-    static SkFlagInfo* gHead;
-    static SkString    gUsage;
-
-    // For access to gHead.
-    friend class SkFlagInfo;
-};
-
-#define TO_STRING2(s) #s
-#define TO_STRING(s) TO_STRING2(s)
-
-#define DEFINE_bool(name, defaultValue, helpString)                         \
-bool FLAGS_##name;                                                          \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name),     \
-                                                                 nullptr,                \
-                                                                 &FLAGS_##name,       \
-                                                                 defaultValue,        \
-                                                                 helpString)
-
-// bool 2 allows specifying a short name. No check is done to ensure that shortName
-// is actually shorter than name.
-#define DEFINE_bool2(name, shortName, defaultValue, helpString)             \
-bool FLAGS_##name;                                                          \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateBoolFlag(TO_STRING(name),     \
-                                                                 TO_STRING(shortName),\
-                                                                 &FLAGS_##name,       \
-                                                                 defaultValue,        \
-                                                                 helpString)
-
-#define DECLARE_bool(name) extern bool FLAGS_##name;
-
-#define DEFINE_string(name, defaultValue, helpString)                       \
-SkCommandLineFlags::StringArray FLAGS_##name;                               \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name),   \
-                                                                   nullptr,              \
-                                                                   &FLAGS_##name,     \
-                                                                   defaultValue,      \
-                                                                   helpString, nullptr)
-#define DEFINE_extended_string(name, defaultValue, helpString, extendedHelpString) \
-SkCommandLineFlags::StringArray FLAGS_##name;                                      \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name),   \
-                                                                   nullptr, \
-                                                                   &FLAGS_##name, \
-                                                                   defaultValue, \
-                                                                   helpString, \
-                                                                   extendedHelpString)
-
-// string2 allows specifying a short name. There is an assert that shortName
-// is only 1 character.
-#define DEFINE_string2(name, shortName, defaultValue, helpString)               \
-SkCommandLineFlags::StringArray FLAGS_##name;                                   \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name),       \
-                                                                   TO_STRING(shortName),  \
-                                                                   &FLAGS_##name,         \
-                                                                   defaultValue,          \
-                                                                   helpString, nullptr)
-
-#define DECLARE_string(name) extern SkCommandLineFlags::StringArray FLAGS_##name;
-
-
-
-
-#define DEFINE_int32(name, defaultValue, helpString)                        \
-int32_t FLAGS_##name;                                                       \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name),      \
-                                                                &FLAGS_##name,        \
-                                                                defaultValue,         \
-                                                                helpString)
-
-#define DEFINE_int32_2(name, shortName, defaultValue, helpString)                     \
-int32_t FLAGS_##name;                                                                 \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateIntFlag(TO_STRING(name),      \
-                                                                TO_STRING(shortName), \
-                                                                &FLAGS_##name,        \
-                                                                defaultValue,         \
-                                                                helpString)
-
-#define DECLARE_int32(name) extern int32_t FLAGS_##name;
-
-#define DEFINE_double(name, defaultValue, helpString)                       \
-double FLAGS_##name;                                                        \
-SK_UNUSED static bool unused_##name = SkFlagInfo::CreateDoubleFlag(TO_STRING(name),   \
-                                                                   &FLAGS_##name,     \
-                                                                   defaultValue,      \
-                                                                   helpString)
-
-#define DECLARE_double(name) extern double FLAGS_##name;
-
-class SkFlagInfo {
-
-public:
-    enum FlagTypes {
-        kBool_FlagType,
-        kString_FlagType,
-        kInt_FlagType,
-        kDouble_FlagType,
-    };
-
-    /**
-     *  Each Create<Type>Flag function creates an SkFlagInfo of the specified type. The SkFlagInfo
-     *  object is appended to a list, which is deleted when SkCommandLineFlags::Parse is called.
-     *  Therefore, each call should be made before the call to ::Parse. They are not intended
-     *  to be called directly. Instead, use the macros described above.
-     *  @param name Long version (at least 2 characters) of the name of the flag. This name can
-     *      be referenced on the command line as "--name" to set the value of this flag.
-     *  @param shortName Short version (one character) of the name of the flag. This name can
-     *      be referenced on the command line as "-shortName" to set the value of this flag.
-     *  @param p<Type> Pointer to a global variable which holds the value set by SkCommandLineFlags.
-     *  @param defaultValue The default value of this flag. The variable pointed to by p<Type> will
-     *      be set to this value initially. This is also displayed as part of the help output.
-     *  @param helpString Explanation of what this flag changes in the program.
-     */
-    static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
-                               bool defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, shortName, kBool_FlagType, helpString, nullptr);
-        info->fBoolValue = pBool;
-        *info->fBoolValue = info->fDefaultBool = defaultValue;
-        return true;
-    }
-
-    /**
-     *  See comments for CreateBoolFlag.
-     *  @param pStrings Unlike the others, this is a pointer to an array of values.
-     *  @param defaultValue Thise default will be parsed so that strings separated by spaces
-     *      will be added to pStrings.
-     */
-    static bool CreateStringFlag(const char* name, const char* shortName,
-                                 SkCommandLineFlags::StringArray* pStrings,
-                                 const char* defaultValue, const char* helpString,
-                                 const char* extendedHelpString);
-
-    /**
-     *  See comments for CreateBoolFlag.
-     */
-    static bool CreateIntFlag(const char* name, int32_t* pInt,
-                              int32_t defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kInt_FlagType, helpString, nullptr);
-        info->fIntValue = pInt;
-        *info->fIntValue = info->fDefaultInt = defaultValue;
-        return true;
-    }
-
-    static bool CreateIntFlag(const char* name, const char* shortName, int32_t* pInt,
-                              int32_t defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, shortName, kInt_FlagType, helpString, nullptr);
-        info->fIntValue = pInt;
-        *info->fIntValue = info->fDefaultInt = defaultValue;
-        return true;
-    }
-
-    /**
-     *  See comments for CreateBoolFlag.
-     */
-    static bool CreateDoubleFlag(const char* name, double* pDouble,
-                                 double defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kDouble_FlagType, helpString, nullptr);
-        info->fDoubleValue = pDouble;
-        *info->fDoubleValue = info->fDefaultDouble = defaultValue;
-        return true;
-    }
-
-    /**
-     *  Returns true if the string matches this flag.
-     *  For a boolean flag, also sets the value, since a boolean flag can be set in a number of ways
-     *  without looking at the following string:
-     *      --name
-     *      --noname
-     *      --name=true
-     *      --name=false
-     *      --name=1
-     *      --name=0
-     *      --name=TRUE
-     *      --name=FALSE
-     */
-    bool match(const char* string);
-
-    FlagTypes getFlagType() const { return fFlagType; }
-
-    void resetStrings() {
-        if (kString_FlagType == fFlagType) {
-            fStrings->reset();
-        } else {
-            SkDEBUGFAIL("Can only call resetStrings on kString_FlagType");
-        }
-    }
-
-    void append(const char* string) {
-        if (kString_FlagType == fFlagType) {
-            fStrings->append(string);
-        } else {
-            SkDEBUGFAIL("Can only append to kString_FlagType");
-        }
-    }
-
-    void setInt(int32_t value) {
-        if (kInt_FlagType == fFlagType) {
-            *fIntValue = value;
-        } else {
-            SkDEBUGFAIL("Can only call setInt on kInt_FlagType");
-        }
-    }
-
-    void setDouble(double value) {
-        if (kDouble_FlagType == fFlagType) {
-            *fDoubleValue = value;
-        } else {
-            SkDEBUGFAIL("Can only call setDouble on kDouble_FlagType");
-        }
-    }
-
-    void setBool(bool value) {
-        if (kBool_FlagType == fFlagType) {
-            *fBoolValue = value;
-        } else {
-            SkDEBUGFAIL("Can only call setBool on kBool_FlagType");
-        }
-    }
-
-    SkFlagInfo* next() { return fNext; }
-
-    const SkString& name() const { return fName; }
-
-    const SkString& shortName() const { return fShortName; }
-
-    const SkString& help() const { return fHelpString; }
-    const SkString& extendedHelp() const { return fExtendedHelpString; }
-
-    SkString defaultValue() const {
-        SkString result;
-        switch (fFlagType) {
-            case SkFlagInfo::kBool_FlagType:
-                result.printf("%s", fDefaultBool ? "true" : "false");
-                break;
-            case SkFlagInfo::kString_FlagType:
-                return fDefaultString;
-            case SkFlagInfo::kInt_FlagType:
-                result.printf("%i", fDefaultInt);
-                break;
-            case SkFlagInfo::kDouble_FlagType:
-                result.printf("%2.2f", fDefaultDouble);
-                break;
-            default:
-                SkDEBUGFAIL("Invalid flag type");
-        }
-        return result;
-    }
-
-    SkString typeAsString() const {
-        switch (fFlagType) {
-            case SkFlagInfo::kBool_FlagType:
-                return SkString("bool");
-            case SkFlagInfo::kString_FlagType:
-                return SkString("string");
-            case SkFlagInfo::kInt_FlagType:
-                return SkString("int");
-            case SkFlagInfo::kDouble_FlagType:
-                return SkString("double");
-            default:
-                SkDEBUGFAIL("Invalid flag type");
-                return SkString();
-        }
-    }
-
-private:
-    SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString,
-               const char* extendedHelpString)
-        : fName(name)
-        , fShortName(shortName)
-        , fFlagType(type)
-        , fHelpString(helpString)
-        , fExtendedHelpString(extendedHelpString)
-        , fBoolValue(nullptr)
-        , fDefaultBool(false)
-        , fIntValue(nullptr)
-        , fDefaultInt(0)
-        , fDoubleValue(nullptr)
-        , fDefaultDouble(0)
-        , fStrings(nullptr) {
-        fNext = SkCommandLineFlags::gHead;
-        SkCommandLineFlags::gHead = this;
-        SkASSERT(name && strlen(name) > 1);
-        SkASSERT(nullptr == shortName || 1 == strlen(shortName));
-    }
-
-    /**
-     *  Set a StringArray to hold the values stored in defaultStrings.
-     *  @param array The StringArray to modify.
-     *  @param defaultStrings Space separated list of strings that should be inserted into array
-     *      individually.
-     */
-    static void SetDefaultStrings(SkCommandLineFlags::StringArray* array,
-                                  const char* defaultStrings);
-
-    // Name of the flag, without initial dashes
-    SkString             fName;
-    SkString             fShortName;
-    FlagTypes            fFlagType;
-    SkString             fHelpString;
-    SkString             fExtendedHelpString;
-    bool*                fBoolValue;
-    bool                 fDefaultBool;
-    int32_t*             fIntValue;
-    int32_t              fDefaultInt;
-    double*              fDoubleValue;
-    double               fDefaultDouble;
-    SkCommandLineFlags::StringArray* fStrings;
-    // Both for the help string and in case fStrings is empty.
-    SkString             fDefaultString;
-
-    // In order to keep a linked list.
-    SkFlagInfo*          fNext;
-};
-#endif // SK_COMMAND_LINE_FLAGS_H
diff --git a/src/third_party/skia/tools/flags/SkCommonFlags.cpp b/src/third_party/skia/tools/flags/SkCommonFlags.cpp
deleted file mode 100644
index 35fc0cf..0000000
--- a/src/third_party/skia/tools/flags/SkCommonFlags.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkCommonFlags.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-
-DEFINE_bool(cpu, true, "master switch for running CPU-bound work.");
-
-DEFINE_bool(dryRun, false,
-            "just print the tests that would be run, without actually running them.");
-
-DEFINE_bool(gpu, true, "master switch for running GPU-bound work.");
-
-DEFINE_string(images, "", "List of images and/or directories to decode. A directory with no images"
-                          " is treated as a fatal error.");
-
-DEFINE_string(colorImages, "", "List of images and/or directories to decode with color correction. "
-                               "A directory with no images is treated as a fatal error.");
-
-DEFINE_bool(simpleCodec, false, "Runs of a subset of the codec tests.  "
-                                "For DM, this means no scaling or subsetting, always using the "
-                                "canvas color type.  "
-                                "For nanobench, this means always N32, Premul or Opaque.");
-
-DEFINE_string2(match, m, nullptr,
-               "[~][^]substring[$] [...] of GM name to run.\n"
-               "Multiple matches may be separated by spaces.\n"
-               "~ causes a matching GM to always be skipped\n"
-               "^ requires the start of the GM to match\n"
-               "$ requires the end of the GM to match\n"
-               "^ and $ requires an exact match\n"
-               "If a GM does not match any list entry,\n"
-               "it is skipped unless some list entry starts with ~");
-
-DEFINE_bool2(quiet, q, false, "if true, don't print status updates.");
-
-DEFINE_bool(preAbandonGpuContext, false, "Test abandoning the GrContext before running the test.");
-
-DEFINE_bool(abandonGpuContext, false, "Test abandoning the GrContext after running each test.");
-
-DEFINE_bool(releaseAndAbandonGpuContext, false,
-            "Test releasing all gpu resources and abandoning the GrContext after running each "
-            "test");
-
-DEFINE_string(skps, "skps", "Directory to read skps from.");
-
-DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
-
-DEFINE_int32_2(threads, j, -1, "Run threadsafe tests on a threadpool with this many extra threads, "
-                               "defaulting to one extra thread per core.");
-
-DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver.");
-
-DEFINE_bool2(veryVerbose, V, false, "tell individual tests to be verbose.");
-
-DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs.");
-
-DEFINE_string(key, "",
-              "Space-separated key/value pairs to add to JSON identifying this builder.");
-DEFINE_string(properties, "",
-              "Space-separated key/value pairs to add to JSON identifying this run.");
-DEFINE_bool2(pre_log, p, false, "Log before running each test. May be incomprehensible when threading");
-
-DEFINE_bool(analyticAA, true, "If false, disable analytic anti-aliasing");
-
-DEFINE_bool(forceAnalyticAA, false, "Force analytic anti-aliasing even if the path is complicated: "
-                                    "whether it's concave or convex, we consider a path complicated"
-                                    "if its number of points is comparable to its resolution.");
-
-DEFINE_bool(trace, false, "Show trace events using SkDebugf.");
-
-bool CollectImages(SkCommandLineFlags::StringArray images, SkTArray<SkString>* output) {
-    SkASSERT(output);
-
-    static const char* const exts[] = {
-        "bmp", "gif", "jpg", "jpeg", "png", "webp", "ktx", "astc", "wbmp", "ico",
-        "BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "KTX", "ASTC", "WBMP", "ICO",
-#ifdef SK_CODEC_DECODES_RAW
-        "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
-        "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
-#endif
-    };
-
-    for (int i = 0; i < images.count(); ++i) {
-        const char* flag = images[i];
-        if (!sk_exists(flag)) {
-            SkDebugf("%s does not exist!\n", flag);
-            return false;
-        }
-
-        if (sk_isdir(flag)) {
-            // If the value passed in is a directory, add all the images
-            bool foundAnImage = false;
-            for (const char* ext : exts) {
-                SkOSFile::Iter it(flag, ext);
-                SkString file;
-                while (it.next(&file)) {
-                    foundAnImage = true;
-                    output->push_back() = SkOSPath::Join(flag, file.c_str());
-                }
-            }
-            if (!foundAnImage) {
-                SkDebugf("No supported images found in %s!\n", flag);
-                return false;
-            }
-        } else {
-            // Also add the value if it is a single image
-            output->push_back() = flag;
-        }
-    }
-    return true;
-}
diff --git a/src/third_party/skia/tools/flags/SkCommonFlags.h b/src/third_party/skia/tools/flags/SkCommonFlags.h
deleted file mode 100644
index 71ff8c3..0000000
--- a/src/third_party/skia/tools/flags/SkCommonFlags.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SK_COMMON_FLAGS_H
-#define SK_COMMON_FLAGS_H
-
-#include "../private/SkTArray.h"
-#include "SkCommandLineFlags.h"
-#include "SkString.h"
-
-DECLARE_bool(cpu);
-DECLARE_bool(dryRun);
-DECLARE_bool(gpu);
-DECLARE_string(images);
-DECLARE_string(colorImages);
-DECLARE_bool(simpleCodec);
-DECLARE_string(match);
-DECLARE_bool(quiet);
-DECLARE_bool(resetGpuContext);
-DECLARE_bool(preAbandonGpuContext);
-DECLARE_bool(abandonGpuContext);
-DECLARE_bool(releaseAndAbandonGpuContext);
-DECLARE_string(skps);
-DECLARE_string(svgs);
-DECLARE_int32(threads);
-DECLARE_string(resourcePath);
-DECLARE_bool(verbose);
-DECLARE_bool(veryVerbose);
-DECLARE_string(writePath);
-DECLARE_bool(pre_log);
-DECLARE_bool(analyticAA);
-DECLARE_bool(forceAnalyticAA);
-DECLARE_bool(trace)
-
-DECLARE_string(key);
-DECLARE_string(properties);
-
-/**
- *  Helper to assist in collecting image paths from |dir| specified through a command line flag.
- *
- *  Populates |output|, an array of strings with paths to images to test.
- *
- *  Returns true if each argument to the images flag is meaningful:
- *  - If the file/directory does not exist, return false.
- *  - If |dir| does not have any supported images (based on file type), return false.
- *  - If |dir| is a single file, assume the user is deliberately testing this image,
- *    regardless of file type.
- */
-bool CollectImages(SkCommandLineFlags::StringArray dir, SkTArray<SkString>* output);
-
-#endif
diff --git a/src/third_party/skia/tools/flags/SkCommonFlagsConfig.cpp b/src/third_party/skia/tools/flags/SkCommonFlagsConfig.cpp
deleted file mode 100644
index 03b3b96..0000000
--- a/src/third_party/skia/tools/flags/SkCommonFlagsConfig.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColorSpace_Base.h"
-#include "SkCommonFlagsConfig.h"
-#include "SkImageInfo.h"
-
-#include <stdlib.h>
-
-#if SK_SUPPORT_GPU
-using sk_gpu_test::GrContextFactory;
-#endif
-
-#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
-#    define DEFAULT_GPU_CONFIG "gles"
-#else
-#    define DEFAULT_GPU_CONFIG "gl"
-#endif
-
-static const char defaultConfigs[] =
-    "8888 " DEFAULT_GPU_CONFIG " nonrendering "
-#if defined(SK_BUILD_FOR_WIN)
-    " angle_d3d11_es2"
-#endif
-    ;
-
-#undef DEFAULT_GPU_CONFIG
-
-static const struct {
-    const char* predefinedConfig;
-    const char* backend;
-    const char* options;
-} gPredefinedConfigs[] ={
-#if SK_SUPPORT_GPU
-    { "gl",                    "gpu", "api=gl" },
-    { "gles",                  "gpu", "api=gles" },
-    { "glmsaa4",               "gpu", "api=gl,samples=4" },
-    { "glmsaa8" ,              "gpu", "api=gl,samples=8" },
-    { "glesmsaa4",             "gpu", "api=gles,samples=4" },
-    { "glnvpr4",               "gpu", "api=gl,nvpr=true,samples=4" },
-    { "glnvpr8" ,              "gpu", "api=gl,nvpr=true,samples=8" },
-    { "glnvprdit4",            "gpu", "api=gl,nvpr=true,samples=4,dit=true" },
-    { "glnvprdit8" ,           "gpu", "api=gl,nvpr=true,samples=8,dit=true" },
-    { "glesnvpr4",             "gpu", "api=gles,nvpr=true,samples=4" },
-    { "glesnvprdit4",          "gpu", "api=gles,nvpr=true,samples=4,dit=true" },
-    { "glinst",                "gpu", "api=gl,inst=true" },
-    { "glinst4",               "gpu", "api=gl,inst=true,samples=4" },
-    { "glinstdit4",            "gpu", "api=gl,inst=true,samples=4,dit=true" },
-    { "glinst8" ,              "gpu", "api=gl,inst=true,samples=8" },
-    { "glinstdit8" ,           "gpu", "api=gl,inst=true,samples=8,dit=true" },
-    { "glesinst",              "gpu", "api=gles,inst=true" },
-    { "glesinst4",             "gpu", "api=gles,inst=true,samples=4" },
-    { "glesinstdit4",          "gpu", "api=gles,inst=true,samples=4,dit=true" },
-    { "gl4444",                "gpu", "api=gl,color=4444" },
-    { "gl565",                 "gpu", "api=gl,color=565" },
-    { "glf16",                 "gpu", "api=gl,color=f16" },
-    { "glsrgb",                "gpu", "api=gl,color=srgb" },
-    { "glsrgbnl",              "gpu", "api=gl,color=srgbnl" },
-    { "glesf16",               "gpu", "api=gles,color=f16" },
-    { "glessrgb",              "gpu", "api=gles,color=srgb" },
-    { "glessrgbnl",            "gpu", "api=gles,color=srgbnl" },
-    { "glsrgb",                "gpu", "api=gl,color=srgb" },
-    { "glwide",                "gpu", "api=gl,color=f16_wide" },
-    { "glnarrow",              "gpu", "api=gl,color=f16_narrow" },
-    { "glnostencils",          "gpu", "api=gl,stencils=false" },
-    { "glessrgb",              "gpu", "api=gles,color=srgb" },
-    { "gleswide",              "gpu", "api=gles,color=f16_wide" },
-    { "glesnarrow",            "gpu", "api=gles,color=f16_narrow" },
-    { "gldft",                 "gpu", "api=gl,dit=true" },
-    { "glesdft",               "gpu", "api=gles,dit=true" },
-    { "debuggl",               "gpu", "api=debuggl" },
-    { "nullgl",                "gpu", "api=nullgl" },
-    { "angle_d3d11_es2",       "gpu", "api=angle_d3d11_es2" },
-    { "angle_d3d11_es3",       "gpu", "api=angle_d3d11_es3" },
-    { "angle_d3d9_es2",        "gpu", "api=angle_d3d9_es2" },
-    { "angle_d3d11_es2_msaa4", "gpu", "api=angle_d3d11_es2,samples=4" },
-    { "angle_d3d11_es2_msaa8", "gpu", "api=angle_d3d11_es2,samples=8" },
-    { "angle_d3d11_es3_msaa4", "gpu", "api=angle_d3d11_es3,samples=4" },
-    { "angle_d3d11_es3_msaa8", "gpu", "api=angle_d3d11_es3,samples=8" },
-    { "angle_gl_es2",          "gpu", "api=angle_gl_es2" },
-    { "angle_gl_es3",          "gpu", "api=angle_gl_es3" },
-    { "commandbuffer",         "gpu", "api=commandbuffer" },
-    { "mock",                  "gpu", "api=mock" }
-#if SK_MESA
-    ,{ "mesa",                 "gpu", "api=mesa" }
-#endif
-#ifdef SK_VULKAN
-    ,{ "vk",                   "gpu", "api=vulkan" }
-    ,{ "vksrgb",               "gpu", "api=vulkan,color=srgb" }
-    ,{ "vkwide",               "gpu", "api=vulkan,color=f16_wide" }
-    ,{ "vkmsaa4",              "gpu", "api=vulkan,samples=4" }
-    ,{ "vkmsaa8",              "gpu", "api=vulkan,samples=8" }
-#endif
-#ifdef SK_METAL
-    ,{ "mtl",                   "gpu", "api=metal" }
-    ,{ "mtlsrgb",               "gpu", "api=metal,color=srgb" }
-    ,{ "mtlwide",               "gpu", "api=metal,color=f16_wide" }
-    ,{ "mtlmsaa4",              "gpu", "api=metal,samples=4" }
-    ,{ "mtlmsaa8",              "gpu", "api=metal,samples=8" }
-#endif
-#else
-     { "", "", "" }
-#endif
-};
-
-static const char configHelp[] =
-    "Options: 565 8888 srgb f16 nonrendering null pdf pdfa skp pipe svg xps";
-
-static const char* config_help_fn() {
-    static SkString helpString;
-    helpString.set(configHelp);
-    for (const auto& config : gPredefinedConfigs) {
-        helpString.appendf(" %s", config.predefinedConfig);
-    }
-    helpString.append(" or use extended form 'backend[option=value,...]'.\n");
-    return helpString.c_str();
-}
-
-static const char configExtendedHelp[] =
-    "Extended form: 'backend(option=value,...)'\n\n"
-    "Possible backends and options:\n"
-#if SK_SUPPORT_GPU
-    "\n"
-    "gpu[api=string,color=string,dit=bool,nvpr=bool,inst=bool,samples=int]\n"
-    "\tapi\ttype: string\trequired\n"
-    "\t    Select graphics API to use with gpu backend.\n"
-    "\t    Options:\n"
-    "\t\tgl    \t\t\tUse OpenGL.\n"
-    "\t\tgles  \t\t\tUse OpenGL ES.\n"
-    "\t\tdebuggl \t\t\tUse debug OpenGL.\n"
-    "\t\tnullgl \t\t\tUse null OpenGL.\n"
-    "\t\tangle_d3d9_es2\t\t\tUse OpenGL ES2 on the ANGLE Direct3D9 backend.\n"
-    "\t\tangle_d3d11_es2\t\t\tUse OpenGL ES2 on the ANGLE Direct3D11 backend.\n"
-    "\t\tangle_d3d11_es3\t\t\tUse OpenGL ES3 on the ANGLE Direct3D11 backend.\n"
-    "\t\tangle_gl_es2\t\t\tUse OpenGL ES2 on the ANGLE OpenGL backend.\n"
-    "\t\tangle_gl_es3\t\t\tUse OpenGL ES3 on the ANGLE OpenGL backend.\n"
-    "\t\tcommandbuffer\t\tUse command buffer.\n"
-    "\t\tmock\t\tUse mock context.\n"
-#if SK_MESA
-    "\t\tmesa\t\t\tUse MESA.\n"
-#endif
-#ifdef SK_VULKAN
-    "\t\tvulkan\t\t\tUse Vulkan.\n"
-#endif
-#ifdef SK_METAL
-    "\t\tmetal\t\t\tUse Metal.\n"
-#endif
-    "\tcolor\ttype: string\tdefault: 8888.\n"
-    "\t    Select framebuffer color format.\n"
-    "\t    Options:\n"
-    "\t\t8888\t\t\tLinear 8888.\n"
-    "\t\t4444\t\t\tLinear 4444.\n"
-    "\t\t565\t\t\tLinear 565.\n"
-    "\t\tf16{_gamut}\t\tLinear 16-bit floating point.\n"
-    "\t\tsrgb{_gamut}\t\tsRGB 8888.\n"
-    "\t  gamut\ttype: string\tdefault: srgb.\n"
-    "\t    Select color gamut for f16 or sRGB format buffers.\n"
-    "\t    Options:\n"
-    "\t\tsrgb\t\t\tsRGB gamut.\n"
-    "\t\twide\t\t\tWide Gamut RGB.\n"
-    "\tdit\ttype: bool\tdefault: false.\n"
-    "\t    Use device independent text.\n"
-    "\tnvpr\ttype: bool\tdefault: false.\n"
-    "\t    Use NV_path_rendering OpenGL and OpenGL ES extension.\n"
-    "\tsamples\ttype: int\tdefault: 0.\n"
-    "\t    Use multisampling with N samples.\n"
-    "\tstencils\ttype: bool\tdefault: true.\n"
-    "\t    Allow the use of stencil buffers.\n"
-    "\n"
-    "Predefined configs:\n\n"
-    // Help text for pre-defined configs is auto-generated from gPredefinedConfigs
-#endif
-    ;
-
-static const char* config_extended_help_fn() {
-    static SkString helpString;
-    helpString.set(configExtendedHelp);
-    for (const auto& config : gPredefinedConfigs) {
-        helpString.appendf("\t%-10s\t= gpu(%s)\n", config.predefinedConfig, config.options);
-    }
-    return helpString.c_str();
-}
-
-DEFINE_extended_string(config, defaultConfigs, config_help_fn(), config_extended_help_fn());
-
-SkCommandLineConfig::SkCommandLineConfig(const SkString& tag, const SkString& backend,
-                                         const SkTArray<SkString>& viaParts)
-        : fTag(tag)
-        , fBackend(backend)
-        , fViaParts(viaParts) {
-}
-SkCommandLineConfig::~SkCommandLineConfig() {
-}
-
-#if SK_SUPPORT_GPU
-SkCommandLineConfigGpu::SkCommandLineConfigGpu(
-    const SkString& tag, const SkTArray<SkString>& viaParts, ContextType contextType, bool useNVPR,
-    bool useInstanced, bool useDIText, int samples, SkColorType colorType, SkAlphaType alphaType,
-    sk_sp<SkColorSpace> colorSpace, bool useStencilBuffers)
-        : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
-        , fContextType(contextType)
-        , fContextOverrides(ContextOverrides::kNone)
-        , fUseDIText(useDIText)
-        , fSamples(samples)
-        , fColorType(colorType)
-        , fAlphaType(alphaType)
-        , fColorSpace(std::move(colorSpace)) {
-    if (useNVPR) {
-        fContextOverrides |= ContextOverrides::kRequireNVPRSupport;
-    } else if (!useInstanced) {
-        // We don't disable NVPR for instanced configs. Otherwise the caps wouldn't use mixed
-        // samples and we couldn't test the mixed samples backend for simple shapes.
-        fContextOverrides |= ContextOverrides::kDisableNVPR;
-    }
-    if (useInstanced) {
-        fContextOverrides |= ContextOverrides::kUseInstanced;
-    }
-    // Subtle logic: If the config has a color space attached, we're going to be rendering to sRGB,
-    // so we need that capability. In addition, to get the widest test coverage, we DO NOT require
-    // that we can disable sRGB decode. (That's for rendering sRGB sources to legacy surfaces).
-    //
-    // If the config doesn't have a color space attached, we're going to be rendering in legacy
-    // mode. In that case, we don't require sRGB capability and we defer to the client to decide on
-    // sRGB decode control.
-    if (fColorSpace) {
-        fContextOverrides |= ContextOverrides::kRequireSRGBSupport;
-        fContextOverrides |= ContextOverrides::kAllowSRGBWithoutDecodeControl;
-    }
-    if (!useStencilBuffers) {
-        fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
-    }
-}
-static bool parse_option_int(const SkString& value, int* outInt) {
-    if (value.isEmpty()) {
-        return false;
-    }
-    char* endptr = nullptr;
-    long intValue = strtol(value.c_str(), &endptr, 10);
-    if (*endptr != '\0') {
-        return false;
-    }
-    *outInt = static_cast<int>(intValue);
-    return true;
-}
-static bool parse_option_bool(const SkString& value, bool* outBool) {
-    if (value.equals("true")) {
-        *outBool = true;
-        return true;
-    }
-    if (value.equals("false")) {
-        *outBool = false;
-        return true;
-    }
-    return false;
-}
-static bool parse_option_gpu_api(const SkString& value,
-                                 SkCommandLineConfigGpu::ContextType* outContextType) {
-    if (value.equals("gl")) {
-        *outContextType = GrContextFactory::kGL_ContextType;
-        return true;
-    }
-    if (value.equals("gles")) {
-        *outContextType = GrContextFactory::kGLES_ContextType;
-        return true;
-    }
-    if (value.equals("debuggl")) {
-        *outContextType = GrContextFactory::kDebugGL_ContextType;
-        return true;
-    }
-    if (value.equals("nullgl")) {
-        *outContextType = GrContextFactory::kNullGL_ContextType;
-        return true;
-    }
-    if (value.equals("angle_d3d9_es2")) {
-        *outContextType = GrContextFactory::kANGLE_D3D9_ES2_ContextType;
-        return true;
-    }
-    if (value.equals("angle_d3d11_es2")) {
-        *outContextType = GrContextFactory::kANGLE_D3D11_ES2_ContextType;
-        return true;
-    }
-    if (value.equals("angle_d3d11_es3")) {
-        *outContextType = GrContextFactory::kANGLE_D3D11_ES3_ContextType;
-        return true;
-    }
-    if (value.equals("angle_gl_es2")) {
-        *outContextType = GrContextFactory::kANGLE_GL_ES2_ContextType;
-        return true;
-    }
-    if (value.equals("angle_gl_es3")) {
-        *outContextType = GrContextFactory::kANGLE_GL_ES3_ContextType;
-        return true;
-    }
-    if (value.equals("commandbuffer")) {
-        *outContextType = GrContextFactory::kCommandBuffer_ContextType;
-        return true;
-    }
-    if (value.equals("mock")) {
-        *outContextType = GrContextFactory::kMock_ContextType;
-        return true;
-    }
-#if SK_MESA
-    if (value.equals("mesa")) {
-        *outContextType = GrContextFactory::kMESA_ContextType;
-        return true;
-    }
-#endif
-#ifdef SK_VULKAN
-    if (value.equals("vulkan")) {
-        *outContextType = GrContextFactory::kVulkan_ContextType;
-        return true;
-    }
-#endif
-#ifdef SK_METAL
-    if (value.equals("metal")) {
-        *outContextType = GrContextFactory::kMetal_ContextType;
-        return true;
-    }
-#endif
-    return false;
-}
-static bool parse_option_gpu_color(const SkString& value,
-                                   SkColorType* outColorType,
-                                   SkAlphaType* alphaType,
-                                   sk_sp<SkColorSpace>* outColorSpace) {
-    // We always use premul unless the color type is 565.
-    *alphaType = kPremul_SkAlphaType;
-
-    if (value.equals("8888")) {
-        *outColorType = kRGBA_8888_SkColorType;
-        *outColorSpace = nullptr;
-        return true;
-    } else if (value.equals("4444")) {
-        *outColorType = kARGB_4444_SkColorType;
-        *outColorSpace = nullptr;
-        return true;
-    } else if (value.equals("565")) {
-        *outColorType = kRGB_565_SkColorType;
-        *alphaType = kOpaque_SkAlphaType;
-        *outColorSpace = nullptr;
-        return true;
-    }
-
-    SkTArray<SkString> commands;
-    SkStrSplit(value.c_str(), "_", &commands);
-    if (commands.count() < 1 || commands.count() > 2) {
-        return false;
-    }
-
-    const bool linearGamma = commands[0].equals("f16");
-    SkColorSpace::Gamut gamut = SkColorSpace::kSRGB_Gamut;
-    SkColorSpace::RenderTargetGamma gamma = linearGamma ? SkColorSpace::kLinear_RenderTargetGamma
-                                                        : SkColorSpace::kSRGB_RenderTargetGamma;
-    *outColorSpace = SkColorSpace::MakeRGB(gamma, gamut);
-
-    if (commands.count() == 2) {
-        if (commands[1].equals("srgb")) {
-            // sRGB gamut (which is our default)
-        } else if (commands[1].equals("wide")) {
-            // WideGamut RGB
-            const float gWideGamutRGB_toXYZD50[]{
-                0.7161046f, 0.1009296f, 0.1471858f,  // -> X
-                0.2581874f, 0.7249378f, 0.0168748f,  // -> Y
-                0.0000000f, 0.0517813f, 0.7734287f,  // -> Z
-            };
-            SkMatrix44 wideGamutRGBMatrix(SkMatrix44::kUninitialized_Constructor);
-            wideGamutRGBMatrix.set3x3RowMajorf(gWideGamutRGB_toXYZD50);
-            *outColorSpace = SkColorSpace::MakeRGB(gamma, wideGamutRGBMatrix);
-        } else if (commands[1].equals("narrow")) {
-            // NarrowGamut RGB (an artifically smaller than sRGB gamut)
-            SkColorSpacePrimaries primaries ={
-                0.54f, 0.33f,     // Rx, Ry
-                0.33f, 0.50f,     // Gx, Gy
-                0.25f, 0.20f,     // Bx, By
-                0.3127f, 0.3290f, // Wx, Wy
-            };
-            SkMatrix44 narrowGamutRGBMatrix(SkMatrix44::kUninitialized_Constructor);
-            primaries.toXYZD50(&narrowGamutRGBMatrix);
-            *outColorSpace = SkColorSpace::MakeRGB(gamma, narrowGamutRGBMatrix);
-        } else {
-            // Unknown color gamut
-            return false;
-        }
-    }
-
-    // Now pick a color type
-    if (commands[0].equals("f16")) {
-        *outColorType = kRGBA_F16_SkColorType;
-        return true;
-    }
-    if (commands[0].equals("srgb") || commands[0].equals("srgbnl")) {
-        *outColorType = kRGBA_8888_SkColorType;
-        return true;
-    }
-    return false;
-}
-
-SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
-                                                      const SkTArray<SkString>& vias,
-                                                      const SkString& options) {
-    // Defaults for GPU backend.
-    bool seenAPI = false;
-    SkCommandLineConfigGpu::ContextType contextType = GrContextFactory::kGL_ContextType;
-    bool seenUseNVPR = false;
-    bool useNVPR = false;
-    bool seenUseInstanced = false;
-    bool useInstanced = false;
-    bool seenUseDIText =false;
-    bool useDIText = false;
-    bool seenSamples = false;
-    int samples = 0;
-    bool seenColor = false;
-    SkColorType colorType = kRGBA_8888_SkColorType;
-    SkAlphaType alphaType = kPremul_SkAlphaType;
-    sk_sp<SkColorSpace> colorSpace = nullptr;
-    bool seenUseStencils = false;
-    bool useStencils = true;
-
-    SkTArray<SkString> optionParts;
-    SkStrSplit(options.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
-    for (int i = 0; i < optionParts.count(); ++i) {
-        SkTArray<SkString> keyValueParts;
-        SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
-        if (keyValueParts.count() != 2) {
-            return nullptr;
-        }
-        const SkString& key = keyValueParts[0];
-        const SkString& value = keyValueParts[1];
-        bool valueOk = false;
-        if (key.equals("api") && !seenAPI) {
-            valueOk = parse_option_gpu_api(value, &contextType);
-            seenAPI = true;
-        } else if (key.equals("nvpr") && !seenUseNVPR) {
-            valueOk = parse_option_bool(value, &useNVPR);
-            seenUseNVPR = true;
-        } else if (key.equals("inst") && !seenUseInstanced) {
-            valueOk = parse_option_bool(value, &useInstanced);
-            seenUseInstanced = true;
-        } else if (key.equals("dit") && !seenUseDIText) {
-            valueOk = parse_option_bool(value, &useDIText);
-            seenUseDIText = true;
-        } else if (key.equals("samples") && !seenSamples) {
-            valueOk = parse_option_int(value, &samples);
-            seenSamples = true;
-        } else if (key.equals("color") && !seenColor) {
-            valueOk = parse_option_gpu_color(value, &colorType, &alphaType, &colorSpace);
-            seenColor = true;
-        } else if (key.equals("stencils") && !seenUseStencils) {
-            valueOk = parse_option_bool(value, &useStencils);
-            seenUseStencils = true;
-        }
-        if (!valueOk) {
-            return nullptr;
-        }
-    }
-    if (!seenAPI) {
-        return nullptr;
-    }
-    return new SkCommandLineConfigGpu(tag, vias, contextType, useNVPR, useInstanced, useDIText,
-                                      samples, colorType, alphaType, colorSpace, useStencils);
-}
-#endif
-
-void ParseConfigs(const SkCommandLineFlags::StringArray& configs,
-                  SkCommandLineConfigArray* outResult) {
-    outResult->reset();
-    for (int i = 0; i < configs.count(); ++i) {
-        SkString extendedBackend;
-        SkString extendedOptions;
-        SkString simpleBackend;
-        SkTArray<SkString> vias;
-
-        SkString tag(configs[i]);
-        SkTArray<SkString> parts;
-        SkStrSplit(tag.c_str(), "[", kStrict_SkStrSplitMode, &parts);
-        if (parts.count() == 2) {
-            SkTArray<SkString> parts2;
-            SkStrSplit(parts[1].c_str(), "]", kStrict_SkStrSplitMode, &parts2);
-            if (parts2.count() == 2 && parts2[1].isEmpty()) {
-                SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias);
-                if (vias.count()) {
-                    extendedBackend = vias[vias.count() - 1];
-                    vias.pop_back();
-                } else {
-                    extendedBackend = parts[0];
-                }
-                extendedOptions = parts2[0];
-                simpleBackend.printf("%s[%s]", extendedBackend.c_str(), extendedOptions.c_str());
-            }
-        }
-
-        if (extendedBackend.isEmpty()) {
-            simpleBackend = tag;
-            SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias);
-            if (vias.count()) {
-                simpleBackend = vias[vias.count() - 1];
-                vias.pop_back();
-            }
-            for (auto& predefinedConfig : gPredefinedConfigs) {
-                if (simpleBackend.equals(predefinedConfig.predefinedConfig)) {
-                    extendedBackend = predefinedConfig.backend;
-                    extendedOptions = predefinedConfig.options;
-                    break;
-                }
-            }
-        }
-        SkCommandLineConfig* parsedConfig = nullptr;
-#if SK_SUPPORT_GPU
-        if (extendedBackend.equals("gpu")) {
-            parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions);
-        }
-#endif
-        if (!parsedConfig) {
-            parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias);
-        }
-        outResult->emplace_back(parsedConfig);
-    }
-}
diff --git a/src/third_party/skia/tools/flags/SkCommonFlagsConfig.h b/src/third_party/skia/tools/flags/SkCommonFlagsConfig.h
deleted file mode 100644
index 77f31c3..0000000
--- a/src/third_party/skia/tools/flags/SkCommonFlagsConfig.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SK_COMMON_FLAGS_CONFIG_H
-#define SK_COMMON_FLAGS_CONFIG_H
-
-#include "SkCommandLineFlags.h"
-
-#if SK_SUPPORT_GPU
-#include "GrContextFactory.h"
-#endif
-
-DECLARE_string(config);
-
-#if SK_SUPPORT_GPU
-class SkCommandLineConfigGpu;
-#endif
-
-// SkCommandLineConfig represents a Skia rendering configuration string.
-// The string has following form:
-// tag:
-//   [via-]*backend
-// where 'backend' consists of chars excluding hyphen
-// and each 'via' consists of chars excluding hyphen.
-class SkCommandLineConfig {
-  public:
-    SkCommandLineConfig(const SkString& tag, const SkString& backend,
-                        const SkTArray<SkString>& viaParts);
-    virtual ~SkCommandLineConfig();
-#if SK_SUPPORT_GPU
-    virtual const SkCommandLineConfigGpu* asConfigGpu() const { return nullptr; }
-#endif
-    const SkString& getTag() const { return fTag; }
-    const SkString& getBackend() const { return fBackend; }
-    const SkTArray<SkString>& getViaParts() const { return fViaParts; }
-  private:
-    SkString fTag;
-    SkString fBackend;
-    SkTArray<SkString> fViaParts;
-};
-
-#if SK_SUPPORT_GPU
-// SkCommandLineConfigGpu is a SkCommandLineConfig that extracts information out of the backend
-// part of the tag. It is constructed tags that have:
-// * backends of form "gpu[option=value,option2=value,...]"
-// * backends that represent a shorthand of above (such as "glmsaa16" representing
-// "gpu(api=gl,samples=16)")
-class SkCommandLineConfigGpu : public SkCommandLineConfig {
-  public:
-    typedef sk_gpu_test::GrContextFactory::ContextType ContextType;
-    typedef sk_gpu_test::GrContextFactory::ContextOverrides ContextOverrides;
-    SkCommandLineConfigGpu(const SkString& tag, const SkTArray<SkString>& viaParts,
-                           ContextType contextType, bool useNVPR, bool useInstanced, bool useDIText,
-                           int samples, SkColorType colorType, SkAlphaType alphaType,
-                           sk_sp<SkColorSpace> colorSpace, bool useStencilBuffers);
-    const SkCommandLineConfigGpu* asConfigGpu() const override { return this; }
-    ContextType getContextType() const { return fContextType; }
-    ContextOverrides getContextOverrides() const { return fContextOverrides; }
-    bool getUseNVPR() const {
-        SkASSERT(!(fContextOverrides & ContextOverrides::kRequireNVPRSupport) ||
-                 !(fContextOverrides & ContextOverrides::kDisableNVPR));
-        return fContextOverrides & ContextOverrides::kRequireNVPRSupport;
-    }
-    bool getUseInstanced() const { return fContextOverrides & ContextOverrides::kUseInstanced; }
-    bool getUseDIText() const { return fUseDIText; }
-    int getSamples() const { return fSamples; }
-    SkColorType getColorType() const { return fColorType; }
-    SkAlphaType getAlphaType() const { return fAlphaType; }
-    SkColorSpace* getColorSpace() const { return fColorSpace.get(); }
-
-  private:
-    ContextType fContextType;
-    ContextOverrides fContextOverrides;
-    bool fUseDIText;
-    int fSamples;
-    SkColorType fColorType;
-    SkAlphaType fAlphaType;
-    sk_sp<SkColorSpace> fColorSpace;
-};
-#endif
-
-typedef SkTArray<std::unique_ptr<SkCommandLineConfig>, true> SkCommandLineConfigArray;
-void ParseConfigs(const SkCommandLineFlags::StringArray& configList,
-                  SkCommandLineConfigArray* outResult);
-
-#endif
diff --git a/src/third_party/skia/tools/flags/SkCommonFlagsPathRenderer.h b/src/third_party/skia/tools/flags/SkCommonFlagsPathRenderer.h
deleted file mode 100644
index ac293a1..0000000
--- a/src/third_party/skia/tools/flags/SkCommonFlagsPathRenderer.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SK_COMMON_FLAGS_PATH_RENDERER_H
-#define SK_COMMON_FLAGS_PATH_RENDERER_H
-
-#if SK_SUPPORT_GPU
-
-#include "GrContextOptions.h"
-#include "SkCommandLineFlags.h"
-#include "SkTypes.h"
-
-DECLARE_string(pr);
-
-#define DEFINE_pathrenderer_flag                                                   \
-    DEFINE_string(pr, "all",                                                       \
-                  "Set of enabled gpu path renderers. Defined as a list of: "      \
-                  "[[~]all [~]dashline [~]nvpr [~]msaa [~]aahairline [~]aaconvex " \
-                  "[~]aalinearizing [~]small [~]tess [~]grdefault]")
-
-inline GrContextOptions::GpuPathRenderers get_named_pathrenderers_flags(const char* name) {
-    using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
-    if (!strcmp(name, "all")) {
-        return GpuPathRenderers::kAll;
-    } else if (!strcmp(name, "dashline")) {
-        return GpuPathRenderers::kDashLine;
-    } else if (!strcmp(name, "nvpr")) {
-        return GpuPathRenderers::kStencilAndCover;
-    } else if (!strcmp(name, "msaa")) {
-        return GpuPathRenderers::kMSAA;
-    } else if (!strcmp(name, "aahairline")) {
-        return GpuPathRenderers::kAAHairline;
-    } else if (!strcmp(name, "aaconvex")) {
-        return GpuPathRenderers::kAAConvex;
-    } else if (!strcmp(name, "aalinearizing")) {
-        return GpuPathRenderers::kAALinearizing;
-    } else if (!strcmp(name, "small")) {
-        return GpuPathRenderers::kSmall;
-    } else if (!strcmp(name, "ccpr")) {
-        return GpuPathRenderers::kCoverageCounting;
-    } else if (!strcmp(name, "tess")) {
-        return GpuPathRenderers::kTessellating;
-    } else if (!strcmp(name, "grdefault")) {
-        return GpuPathRenderers::kDefault;
-    }
-    SK_ABORT(SkStringPrintf("error: unknown named path renderer \"%s\"\n", name).c_str());
-    return GpuPathRenderers::kNone;
-}
-
-inline GrContextOptions::GpuPathRenderers CollectGpuPathRenderersFromFlags() {
-    using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
-    if (FLAGS_pr.isEmpty()) {
-        return GpuPathRenderers::kAll;
-    }
-    GpuPathRenderers gpuPathRenderers = '~' == FLAGS_pr[0][0] ?
-                                        GpuPathRenderers::kAll : GpuPathRenderers::kNone;
-    for (int i = 0; i < FLAGS_pr.count(); ++i) {
-        const char* name = FLAGS_pr[i];
-        if (name[0] == '~') {
-            gpuPathRenderers &= ~get_named_pathrenderers_flags(&name[1]);
-        } else {
-            gpuPathRenderers |= get_named_pathrenderers_flags(name);
-        }
-    }
-    return gpuPathRenderers;
-}
-
-#endif // SK_SUPPORT_GPU
-
-#endif
diff --git a/src/third_party/skia/tools/fm/fm.cpp b/src/third_party/skia/tools/fm/fm.cpp
new file mode 100644
index 0000000..d89bcac
--- /dev/null
+++ b/src/third_party/skia/tools/fm/fm.cpp
@@ -0,0 +1,596 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "experimental/svg/model/SkSVGDOM.h"
+#include "gm/gm.h"
+#include "include/codec/SkCodec.h"
+#include "include/core/SkColorSpace.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkPictureRecorder.h"
+#include "include/docs/SkPDFDocument.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/private/SkTHash.h"
+#include "src/core/SkColorSpacePriv.h"
+#include "src/core/SkMD5.h"
+#include "src/core/SkOSFile.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrGpu.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/AutoreleasePool.h"
+#include "tools/CrashHandler.h"
+#include "tools/HashAndEncode.h"
+#include "tools/ToolUtils.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/flags/CommonFlags.h"
+#include "tools/gpu/GrContextFactory.h"
+#include "tools/gpu/MemoryCache.h"
+#include "tools/trace/EventTracingPriv.h"
+#include <chrono>
+#include <functional>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(SK_ENABLE_SKOTTIE)
+    #include "modules/skottie/include/Skottie.h"
+    #include "modules/skottie/utils/SkottieUtils.h"
+#endif
+
+using sk_gpu_test::GrContextFactory;
+
+static DEFINE_string2(sources, s, "", "Which GMs, .skps, or images to draw.");
+static DEFINE_string2(backend, b, "", "Backend used to create a canvas to draw into.");
+
+static DEFINE_string(ct    ,   "8888", "The color type for any raster backend.");
+static DEFINE_string(at    , "premul", "The alpha type for any raster backend.");
+static DEFINE_string(gamut ,   "srgb", "The color gamut for any raster backend.");
+static DEFINE_string(tf    ,   "srgb", "The transfer function for any raster backend.");
+static DEFINE_bool  (legacy,    false, "Use a null SkColorSpace instead of --gamut and --tf?");
+
+static DEFINE_int   (samples ,         0, "Samples per pixel in GPU backends.");
+static DEFINE_bool  (stencils,      true, "If false, avoid stencil buffers in GPU backends.");
+static DEFINE_bool  (dit     ,     false, "Use device-independent text in GPU backends.");
+static DEFINE_string(surf    , "default", "Backing store for GPU backend surfaces.");
+
+static DEFINE_bool(       preAbandonGpuContext, false, "Abandon the GrContext before drawing.");
+static DEFINE_bool(          abandonGpuContext, false, "Abandon the GrContext after drawing.");
+static DEFINE_bool(releaseAndAbandonGpuContext, false,
+                   "Release all GPU resources and abandon the GrContext after drawing.");
+
+static DEFINE_bool(decodeToDst, false,
+                   "Decode images to destination format rather than suggested natural format.");
+
+static DEFINE_double(rasterDPI, SK_ScalarDefaultRasterDPI,
+                     "DPI for rasterized content in vector backends like --backend pdf.");
+static DEFINE_bool(PDFA, false, "Create PDF/A with --backend pdf?");
+
+static DEFINE_bool   (cpuDetect, true, "Detect CPU features for runtime optimizations?");
+static DEFINE_string2(writePath, w, "", "Write .pngs to this directory if set.");
+
+static DEFINE_string(writeShaders, "", "Write GLSL shaders to this directory if set.");
+
+static DEFINE_string(key,        "", "Metadata passed through to .png encoder and .json output.");
+static DEFINE_string(properties, "", "Metadata passed through to .png encoder and .json output.");
+
+template <typename T>
+struct FlagOption {
+    const char* label;
+    T           value;
+};
+
+template <typename T, int N>
+static bool parse_flag(const CommandLineFlags::StringArray& flag,
+                       const char* flag_name,
+                       const FlagOption<T> (&array)[N],
+                       T* value) {
+    for (auto entry : array) {
+        if (flag.contains(entry.label)) {
+            *value = entry.value;
+            return true;
+        }
+    }
+    fprintf(stderr, "Known values for --%s:\n", flag_name);
+    for (auto entry : array) {
+        fprintf(stderr, "    --%s %s\n", flag_name, entry.label);
+    }
+    return false;
+}
+
+struct Result {
+    enum { Ok, Skip, Fail} status;
+    SkString               failure;
+};
+static const Result ok = {Result::Ok,   {}},
+                  skip = {Result::Skip, {}};
+
+template <typename... Args>
+static Result fail(const char* why, Args... args) {
+    return { Result::Fail, SkStringPrintf(why, args...) };
+}
+
+
+struct Source {
+    SkString                               name;
+    SkISize                                size;
+    std::function<Result(SkCanvas*)>       draw;
+    std::function<void(GrContextOptions*)> tweak = [](GrContextOptions*){};
+};
+
+static void init(Source* source, std::shared_ptr<skiagm::GM> gm) {
+    source->size  = gm->getISize();
+    source->tweak = [gm](GrContextOptions* options) { gm->modifyGrContextOptions(options); };
+    source->draw  = [gm](SkCanvas* canvas) {
+        SkString err;
+        switch (gm->draw(canvas, &err)) {
+            case skiagm::DrawResult::kOk:   break;
+            case skiagm::DrawResult::kSkip: return skip;
+            case skiagm::DrawResult::kFail: return fail(err.c_str());
+        }
+        return ok;
+    };
+}
+
+static void init(Source* source, sk_sp<SkPicture> pic) {
+    source->size = pic->cullRect().roundOut().size();
+    source->draw = [pic](SkCanvas* canvas) {
+        canvas->drawPicture(pic);
+        return ok;
+    };
+}
+
+static void init(Source* source, std::shared_ptr<SkCodec> codec) {
+    source->size = codec->dimensions();
+    source->draw = [codec](SkCanvas* canvas) {
+        SkImageInfo info = codec->getInfo();
+        if (FLAGS_decodeToDst) {
+            info = canvas->imageInfo().makeDimensions(info.dimensions());
+        }
+
+        SkBitmap bm;
+        bm.allocPixels(info);
+        switch (SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes())) {
+            case SkCodec::kSuccess:
+            case SkCodec::kErrorInInput:
+            case SkCodec::kIncompleteInput: canvas->drawBitmap(bm, 0,0);
+                                            break;
+            default: return fail("codec->getPixels() failed: %d\n", result);
+        }
+        return ok;
+    };
+}
+
+static void init(Source* source, sk_sp<SkSVGDOM> svg) {
+    source->size = svg->containerSize().isEmpty() ? SkISize{1000,1000}
+                                                  : svg->containerSize().toCeil();
+    source->draw = [svg](SkCanvas* canvas) {
+        svg->render(canvas);
+        return ok;
+    };
+}
+
+#if defined(SK_ENABLE_SKOTTIE)
+static void init(Source* source, sk_sp<skottie::Animation> animation) {
+    source->size = {1000,1000};
+    source->draw = [animation](SkCanvas* canvas) {
+        canvas->clear(SK_ColorWHITE);
+
+        // Draw frames in a shuffled order to exercise nonlinear frame progression.
+        // The film strip will still be in time order, just drawn out of order.
+        const int order[] = { 4, 0, 3, 1, 2 };
+        const int tiles = SK_ARRAY_COUNT(order);
+        const float dim = 1000.0f / tiles;
+
+        const float dt = 1.0f / (tiles*tiles - 1);
+
+        for (int y : order)
+        for (int x : order) {
+            SkRect dst = {x*dim, y*dim, (x+1)*dim, (y+1)*dim};
+
+            SkAutoCanvasRestore _(canvas, true/*save now*/);
+            canvas->clipRect(dst, /*aa=*/true);
+            canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(animation->size()),
+                                                    dst,
+                                                    SkMatrix::kCenter_ScaleToFit));
+            float t = (y*tiles + x) * dt;
+            animation->seek(t);
+            animation->render(canvas);
+        }
+        return ok;
+    };
+}
+#endif
+
+static sk_sp<SkImage> draw_with_cpu(std::function<bool(SkCanvas*)> draw,
+                                    SkImageInfo info) {
+    if (sk_sp<SkSurface> surface = SkSurface::MakeRaster(info)) {
+        if (draw(surface->getCanvas())) {
+            return surface->makeImageSnapshot();
+        }
+    }
+    return nullptr;
+}
+
+static sk_sp<SkData> draw_as_skp(std::function<bool(SkCanvas*)> draw,
+                                 SkImageInfo info) {
+    SkPictureRecorder recorder;
+    if (draw(recorder.beginRecording(info.width(), info.height()))) {
+        return recorder.finishRecordingAsPicture()->serialize();
+    }
+    return nullptr;
+}
+
+static sk_sp<SkData> draw_as_pdf(std::function<bool(SkCanvas*)> draw,
+                                 SkImageInfo info,
+                                 SkString name) {
+    SkPDF::Metadata metadata;
+    metadata.fTitle     = name;
+    metadata.fCreator   = "Skia/FM";
+    metadata.fRasterDPI = FLAGS_rasterDPI;
+    metadata.fPDFA      = FLAGS_PDFA;
+
+    SkDynamicMemoryWStream stream;
+    if (sk_sp<SkDocument> doc = SkPDF::MakeDocument(&stream, metadata)) {
+        if (draw(doc->beginPage(info.width(), info.height()))) {
+            doc->endPage();
+            doc->close();
+            return stream.detachAsData();
+        }
+    }
+    return nullptr;
+}
+
+static sk_sp<SkImage> draw_with_gpu(std::function<bool(SkCanvas*)> draw,
+                                    SkImageInfo info,
+                                    GrContextFactory::ContextType api,
+                                    GrContextFactory* factory) {
+    enum class SurfaceType { kDefault, kBackendTexture, kBackendRenderTarget };
+    const FlagOption<SurfaceType> kSurfaceTypes[] = {
+        { "default", SurfaceType::kDefault },
+        { "betex"  , SurfaceType::kBackendTexture },
+        { "bert"   , SurfaceType::kBackendRenderTarget },
+    };
+    SurfaceType surfaceType;
+    if (!parse_flag(FLAGS_surf, "surf", kSurfaceTypes, &surfaceType)) {
+        return nullptr;
+    }
+
+    auto overrides = GrContextFactory::ContextOverrides::kNone;
+    if (!FLAGS_stencils) { overrides |= GrContextFactory::ContextOverrides::kAvoidStencilBuffers; }
+
+    GrContext* context = factory->getContextInfo(api, overrides)
+                                 .grContext();
+
+    uint32_t flags = FLAGS_dit ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag
+                               : 0;
+    SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+
+    sk_sp<SkSurface> surface;
+    GrBackendTexture backendTexture;
+    GrBackendRenderTarget backendRT;
+
+    switch (surfaceType) {
+        case SurfaceType::kDefault:
+            surface = SkSurface::MakeRenderTarget(context,
+                                                  SkBudgeted::kNo,
+                                                  info,
+                                                  FLAGS_samples,
+                                                  &props);
+            break;
+
+        case SurfaceType::kBackendTexture:
+            backendTexture = context->createBackendTexture(info.width(),
+                                                           info.height(),
+                                                           info.colorType(),
+                                                           GrMipMapped::kNo,
+                                                           GrRenderable::kYes,
+                                                           GrProtected::kNo);
+            surface = SkSurface::MakeFromBackendTexture(context,
+                                                        backendTexture,
+                                                        kTopLeft_GrSurfaceOrigin,
+                                                        FLAGS_samples,
+                                                        info.colorType(),
+                                                        info.refColorSpace(),
+                                                        &props);
+            break;
+
+        case SurfaceType::kBackendRenderTarget:
+            backendRT = context->priv().getGpu()
+                ->createTestingOnlyBackendRenderTarget(info.width(),
+                                                       info.height(),
+                                                       SkColorTypeToGrColorType(info.colorType()));
+            surface = SkSurface::MakeFromBackendRenderTarget(context,
+                                                             backendRT,
+                                                             kBottomLeft_GrSurfaceOrigin,
+                                                             info.colorType(),
+                                                             info.refColorSpace(),
+                                                             &props);
+            break;
+    }
+
+    if (!surface) {
+        fprintf(stderr, "Could not create GPU surface.\n");
+        return nullptr;
+    }
+
+    if (FLAGS_preAbandonGpuContext) {
+        factory->abandonContexts();
+    }
+
+    sk_sp<SkImage> image;
+    if (draw(surface->getCanvas())) {
+        image = surface->makeImageSnapshot();
+    }
+
+    if (FLAGS_abandonGpuContext) {
+        factory->abandonContexts();
+    } else if (FLAGS_releaseAndAbandonGpuContext) {
+        factory->releaseResourcesAndAbandonContexts();
+    }
+
+    if (!context->abandoned()) {
+        surface.reset();
+        if (backendTexture.isValid()) {
+            context->deleteBackendTexture(backendTexture);
+        }
+        if (backendRT.isValid()) {
+            context->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
+        }
+    }
+
+    return image;
+}
+
+int main(int argc, char** argv) {
+    CommandLineFlags::Parse(argc, argv);
+    SetupCrashHandler();
+
+    if (FLAGS_cpuDetect) {
+        SkGraphics::Init();
+    }
+    initializeEventTracingForTools();
+    ToolUtils::SetDefaultFontMgr();
+    SetAnalyticAAFromCommonFlags();
+
+    GrContextOptions baseOptions;
+    SetCtxOptionsFromCommonFlags(&baseOptions);
+
+    sk_gpu_test::MemoryCache memoryCache;
+    if (!FLAGS_writeShaders.isEmpty()) {
+        baseOptions.fPersistentCache = &memoryCache;
+        baseOptions.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kBackendSource;
+    }
+
+    SkTHashMap<SkString, skiagm::GMFactory> gm_factories;
+    for (skiagm::GMFactory factory : skiagm::GMRegistry::Range()) {
+        std::unique_ptr<skiagm::GM> gm{factory()};
+        if (FLAGS_sources.isEmpty()) {
+            fprintf(stdout, "%s\n", gm->getName());
+        } else {
+            gm_factories.set(SkString{gm->getName()}, factory);
+        }
+    }
+    if (FLAGS_sources.isEmpty()) {
+        return 0;
+    }
+
+    SkTArray<Source> sources;
+    for (const SkString& name : FLAGS_sources) {
+        Source* source = &sources.push_back();
+
+        if (skiagm::GMFactory* factory = gm_factories.find(name)) {
+            std::shared_ptr<skiagm::GM> gm{(*factory)()};
+            source->name = name;
+            init(source, std::move(gm));
+            continue;
+        }
+
+        if (sk_sp<SkData> blob = SkData::MakeFromFileName(name.c_str())) {
+            source->name = SkOSPath::Basename(name.c_str());
+
+            if (name.endsWith(".skp")) {
+                if (sk_sp<SkPicture> pic = SkPicture::MakeFromData(blob.get())) {
+                    init(source, pic);
+                    continue;
+                }
+            } else if (name.endsWith(".svg")) {
+                SkMemoryStream stream{blob};
+                if (sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(stream)) {
+                    init(source, svg);
+                    continue;
+                }
+            }
+#if defined(SK_ENABLE_SKOTTIE)
+            else if (name.endsWith(".json")) {
+                const SkString dir  = SkOSPath::Dirname(name.c_str());
+                if (sk_sp<skottie::Animation> animation = skottie::Animation::Builder()
+                        .setResourceProvider(skottie_utils::FileResourceProvider::Make(dir))
+                        .make((const char*)blob->data(), blob->size())) {
+                    init(source, animation);
+                    continue;
+                }
+            }
+#endif
+            else if (std::shared_ptr<SkCodec> codec = SkCodec::MakeFromData(blob)) {
+                init(source, codec);
+                continue;
+            }
+        }
+
+        fprintf(stderr, "Don't understand source '%s'... bailing out.\n", name.c_str());
+        return 1;
+    }
+
+    enum NonGpuBackends {
+        kCPU_Backend = -1,
+        kSKP_Backend = -2,
+        kPDF_Backend = -3,
+    };
+    const FlagOption<int> kBackends[] = {
+        { "cpu"            , kCPU_Backend },
+        { "skp"            , kSKP_Backend },
+        { "pdf"            , kPDF_Backend },
+        { "gl"             , GrContextFactory::kGL_ContextType },
+        { "gles"           , GrContextFactory::kGLES_ContextType },
+        { "angle_d3d9_es2" , GrContextFactory::kANGLE_D3D9_ES2_ContextType },
+        { "angle_d3d11_es2", GrContextFactory::kANGLE_D3D11_ES2_ContextType },
+        { "angle_d3d11_es3", GrContextFactory::kANGLE_D3D11_ES3_ContextType },
+        { "angle_gl_es2"   , GrContextFactory::kANGLE_GL_ES2_ContextType },
+        { "angle_gl_es3"   , GrContextFactory::kANGLE_GL_ES3_ContextType },
+        { "commandbuffer"  , GrContextFactory::kCommandBuffer_ContextType },
+        { "vk"             , GrContextFactory::kVulkan_ContextType },
+        { "mtl"            , GrContextFactory::kMetal_ContextType },
+        { "mock"           , GrContextFactory::kMock_ContextType },
+    };
+    const FlagOption<SkColorType> kColorTypes[] = {
+        { "a8",           kAlpha_8_SkColorType },
+        { "g8",            kGray_8_SkColorType },
+        { "565",          kRGB_565_SkColorType },
+        { "4444",       kARGB_4444_SkColorType },
+        { "8888",             kN32_SkColorType },
+        { "888x",        kRGB_888x_SkColorType },
+        { "1010102", kRGBA_1010102_SkColorType },
+        { "101010x",  kRGB_101010x_SkColorType },
+        { "f16norm", kRGBA_F16Norm_SkColorType },
+        { "f16",         kRGBA_F16_SkColorType },
+        { "f32",         kRGBA_F32_SkColorType },
+        { "rgba",       kRGBA_8888_SkColorType },
+        { "bgra",       kBGRA_8888_SkColorType },
+    };
+    const FlagOption<SkAlphaType> kAlphaTypes[] = {
+        {   "premul",   kPremul_SkAlphaType },
+        { "unpremul", kUnpremul_SkAlphaType },
+    };
+    const FlagOption<skcms_Matrix3x3> kGamuts[] = {
+        { "srgb",    SkNamedGamut::kSRGB },
+        { "p3",      SkNamedGamut::kDCIP3 },
+        { "rec2020", SkNamedGamut::kRec2020 },
+        { "adobe",   SkNamedGamut::kAdobeRGB },
+        { "narrow",  gNarrow_toXYZD50},
+    };
+    const FlagOption<skcms_TransferFunction> kTransferFunctions[] = {
+        { "srgb"   , SkNamedTransferFn::kSRGB },
+        { "rec2020", SkNamedTransferFn::kRec2020 },
+        { "2.2"    , SkNamedTransferFn::k2Dot2 },
+        { "linear" , SkNamedTransferFn::kLinear },
+    };
+
+
+    int                      backend;
+    SkColorType              ct;
+    SkAlphaType              at;
+    skcms_Matrix3x3          gamut;
+    skcms_TransferFunction   tf;
+
+    if (!parse_flag(FLAGS_backend, "backend", kBackends         , &backend) ||
+        !parse_flag(FLAGS_ct     , "ct"     , kColorTypes       , &ct)      ||
+        !parse_flag(FLAGS_at     , "at"     , kAlphaTypes       , &at)      ||
+        !parse_flag(FLAGS_gamut  , "gamut"  , kGamuts           , &gamut)   ||
+        !parse_flag(FLAGS_tf     , "tf"     , kTransferFunctions, &tf)) {
+        return 1;
+    }
+
+    sk_sp<SkColorSpace> cs = FLAGS_legacy ? nullptr
+                                          : SkColorSpace::MakeRGB(tf,gamut);
+    const SkImageInfo unsized_info = SkImageInfo::Make(0,0, ct,at,cs);
+
+    AutoreleasePool pool;
+    for (auto source : sources) {
+        const auto start = std::chrono::steady_clock::now();
+        fprintf(stdout, "%50s", source.name.c_str());
+        fflush(stdout);
+
+        const SkImageInfo info = unsized_info.makeDimensions(source.size);
+
+        auto draw = [&source](SkCanvas* canvas) {
+            Result result = source.draw(canvas);
+            switch (result.status) {
+                case Result::Ok:   break;
+                case Result::Skip: return false;
+                case Result::Fail:
+                    SK_ABORT(result.failure.c_str());
+            }
+            return true;
+        };
+
+        GrContextOptions options = baseOptions;
+        source.tweak(&options);
+        GrContextFactory factory(options);  // N.B. factory must outlive image
+
+        sk_sp<SkImage> image;
+        sk_sp<SkData>  blob;
+        const char*    ext = ".png";
+        switch (backend) {
+            case kCPU_Backend:
+                image = draw_with_cpu(draw, info);
+                break;
+            case kSKP_Backend:
+                blob = draw_as_skp(draw, info);
+                ext  = ".skp";
+                break;
+            case kPDF_Backend:
+                blob = draw_as_pdf(draw, info, source.name);
+                ext  = ".pdf";
+                break;
+            default:
+                image = draw_with_gpu(draw, info, (GrContextFactory::ContextType)backend, &factory);
+                break;
+        }
+
+        if (!image && !blob) {
+            fprintf(stdout, "\tskipped\n");
+            continue;
+        }
+
+        SkBitmap bitmap;
+        if (image && !image->asLegacyBitmap(&bitmap)) {
+            SK_ABORT("SkImage::asLegacyBitmap() failed.");
+        }
+
+        HashAndEncode hashAndEncode{bitmap};
+        SkString md5;
+        {
+            SkMD5 hash;
+            if (image) {
+                hashAndEncode.write(&hash);
+            } else {
+                hash.write(blob->data(), blob->size());
+            }
+
+            SkMD5::Digest digest = hash.finish();
+            for (int i = 0; i < 16; i++) {
+                md5.appendf("%02x", digest.data[i]);
+            }
+        }
+
+        if (!FLAGS_writePath.isEmpty()) {
+            sk_mkdir(FLAGS_writePath[0]);
+            SkString path = SkStringPrintf("%s/%s%s", FLAGS_writePath[0], source.name.c_str(), ext);
+
+            if (image) {
+                if (!hashAndEncode.writePngTo(path.c_str(), md5.c_str(),
+                                              FLAGS_key, FLAGS_properties)) {
+                    SK_ABORT("Could not write .png.");
+                }
+            } else {
+                SkFILEWStream file(path.c_str());
+                file.write(blob->data(), blob->size());
+            }
+        }
+
+        const auto elapsed = std::chrono::steady_clock::now() - start;
+        fprintf(stdout, "\t%s\t%7dms\n",
+                md5.c_str(),
+                (int)std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
+        pool.drain();
+    }
+
+    if (!FLAGS_writeShaders.isEmpty()) {
+        sk_mkdir(FLAGS_writeShaders[0]);
+        GrBackendApi api =
+                GrContextFactory::ContextTypeBackend((GrContextFactory::ContextType)backend);
+        memoryCache.writeShadersToDisk(FLAGS_writeShaders[0], api);
+
+    }
+
+    return 0;
+}
diff --git a/src/third_party/skia/tools/fm/fm_bot/fm_bot.go b/src/third_party/skia/tools/fm/fm_bot/fm_bot.go
new file mode 100644
index 0000000..ef0efc2
--- /dev/null
+++ b/src/third_party/skia/tools/fm/fm_bot/fm_bot.go
@@ -0,0 +1,281 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"flag"
+	"fmt"
+	"log"
+	"math/rand"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// Too many GPU processes and we'll start to overwhelm your GPU,
+// even hanging your machine in the worst case.  Here's a reasonable default.
+func defaultGpuLimit() int {
+	limit := 8
+	if n := runtime.NumCPU(); n < limit {
+		return n
+	}
+	return limit
+}
+
+var script = flag.String("script", "", "A file with jobs to run, one per line. - for stdin.")
+var random = flag.Bool("random", true, "Assign sources into job batches randomly?")
+var quiet = flag.Bool("quiet", false, "Print only failures?")
+var exact = flag.Bool("exact", false, "Match GM names only exactly.")
+var cpuLimit = flag.Int("cpuLimit", runtime.NumCPU(),
+	"Maximum number of concurrent processes for CPU-bound work.")
+var gpuLimit = flag.Int("gpuLimit", defaultGpuLimit(),
+	"Maximum number of concurrent processes for GPU-bound work.")
+
+func init() {
+	flag.StringVar(script, "s", *script, "Alias for --script.")
+	flag.BoolVar(random, "r", *random, "Alias for --random.")
+	flag.BoolVar(quiet, "q", *quiet, "Alias for --quiet.")
+	flag.BoolVar(exact, "e", *exact, "Alias for --exact.")
+	flag.IntVar(cpuLimit, "c", *cpuLimit, "Alias for --cpuLimit.")
+	flag.IntVar(gpuLimit, "g", *gpuLimit, "Alias for --gpuLimit.")
+}
+
+func listAllGMs(fm string) (gms []string, err error) {
+	// Query fm binary for list of all available GMs by running with no arguments.
+	cmd := exec.Command(fm)
+	stdout, err := cmd.Output()
+	if err != nil {
+		return
+	}
+	// GM names are listed line-by-line.
+	scanner := bufio.NewScanner(bytes.NewReader(stdout))
+	for scanner.Scan() {
+		gms = append(gms, scanner.Text())
+	}
+	err = scanner.Err()
+	return
+}
+
+type work struct {
+	Sources []string
+	Flags   []string
+}
+
+func parseWork(args []string, gms []string) (*work, error) {
+	w := &work{}
+	for _, arg := range args {
+		// I wish we could parse flags here too, but it's too late.
+		if strings.HasPrefix(arg, "-") {
+			msg := "Is '%s' an fm flag? If so please pass it using flag=value syntax."
+			if flag.Lookup(arg[1:]) != nil {
+				msg = "Please pass fm_bot flags like '%s' on the command line before the FM binary."
+			}
+			return nil, fmt.Errorf(msg, arg)
+		}
+
+		// Everything after a # is a comment.
+		if strings.HasPrefix(arg, "#") {
+			break
+		}
+
+		// Treat "gm" or "gms" as a shortcut for all known GMs.
+		if arg == "gm" || arg == "gms" {
+			w.Sources = append(w.Sources, gms...)
+			continue
+		}
+
+		// Is this an option to pass through to fm?
+		if parts := strings.Split(arg, "="); len(parts) == 2 {
+			f := "-"
+			if len(parts[0]) > 1 {
+				f += "-"
+			}
+			f += parts[0]
+
+			w.Flags = append(w.Flags, f, parts[1])
+			continue
+		}
+
+		// Is this argument naming a GM?
+		matchedAnyGM := false
+		for _, gm := range gms {
+			if (*exact && gm == arg) || (!*exact && strings.Contains(gm, arg)) {
+				w.Sources = append(w.Sources, gm)
+				matchedAnyGM = true
+			}
+		}
+		if matchedAnyGM {
+			continue
+		}
+
+		// Anything left ought to be on the file system: a file, a directory, or a glob.
+		// Not all shells expand globs, so we'll do it here just in case.
+		matches, err := filepath.Glob(arg)
+		if err != nil {
+			return nil, err
+		}
+		if len(matches) == 0 {
+			return nil, fmt.Errorf("Don't understand '%s'.", arg)
+		}
+
+		for _, match := range matches {
+			err := filepath.Walk(match, func(path string, info os.FileInfo, err error) error {
+				if !info.IsDir() {
+					w.Sources = append(w.Sources, path)
+				}
+				return err
+			})
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return w, nil
+}
+
+func main() {
+	flag.Parse()
+
+	if flag.NArg() < 1 {
+		log.Fatal("Please pass an fm binary as the first argument.")
+	}
+	fm := flag.Args()[0]
+
+	gms, err := listAllGMs(fm)
+	if err != nil {
+		log.Fatalln("Could not query", fm, "for GMs:", err)
+	}
+
+	// One job can comes right on the command line,
+	// and any number can come one per line from -script.
+	jobs := [][]string{flag.Args()[1:]}
+	if *script != "" {
+		file := os.Stdin
+		if *script != "-" {
+			file, err = os.Open(*script)
+			if err != nil {
+				log.Fatal(err)
+			}
+			defer file.Close()
+		}
+
+		scanner := bufio.NewScanner(file)
+		for scanner.Scan() {
+			jobs = append(jobs, strings.Fields(scanner.Text()))
+		}
+		if err = scanner.Err(); err != nil {
+			log.Fatal(err)
+		}
+	}
+
+	wg := &sync.WaitGroup{}
+	var failures int32 = 0
+
+	worker := func(queue chan work) {
+		for w := range queue {
+			start := time.Now()
+
+			args := w.Flags[:]
+			args = append(args, "-s")
+			args = append(args, w.Sources...)
+
+			cmd := exec.Command(fm, args...)
+			output, err := cmd.CombinedOutput()
+
+			status := "#done"
+			if err != nil {
+				status = fmt.Sprintf("#failed (%v)", err)
+
+				if len(w.Sources) == 1 {
+					// If a source ran alone and failed, that's just a failure.
+					atomic.AddInt32(&failures, 1)
+				} else {
+					// If a batch of sources ran and failed, split them up and try again.
+					for _, source := range w.Sources {
+						wg.Add(1)
+						queue <- work{[]string{source}, w.Flags}
+					}
+				}
+			}
+
+			if !*quiet || (err != nil && len(w.Sources) == 1) {
+				log.Printf("\n%v %v in %v:\n%s",
+					strings.Join(cmd.Args, " "), status, time.Since(start), output)
+			}
+
+			wg.Done()
+		}
+	}
+
+	cpu := make(chan work, 1<<20)
+	for i := 0; i < *cpuLimit; i++ {
+		go worker(cpu)
+	}
+
+	gpu := make(chan work, 1<<20)
+	for i := 0; i < *gpuLimit; i++ {
+		go worker(gpu)
+	}
+
+	for _, job := range jobs {
+		// Skip blank lines, empty command lines.
+		if len(job) == 0 {
+			continue
+		}
+
+		w, err := parseWork(job, gms)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		// Determine if this is CPU-bound or GPU-bound work, conservatively assuming GPU.
+		queue, limit := gpu, *gpuLimit
+		backend := ""
+		for i, flag := range w.Flags {
+			if flag == "-b" || flag == "--backend" {
+				backend = w.Flags[i+1]
+			}
+		}
+		whitelisted := map[string]bool{
+			"cpu": true,
+			"skp": true,
+			"pdf": true,
+		}
+		if whitelisted[backend] {
+			queue, limit = cpu, *cpuLimit
+		}
+
+		if *random {
+			rand.Shuffle(len(w.Sources), func(i, j int) {
+				w.Sources[i], w.Sources[j] = w.Sources[j], w.Sources[i]
+			})
+		}
+
+		// Round up so there's at least one source per batch.
+		sourcesPerBatch := (len(w.Sources) + limit - 1) / limit
+
+		for i := 0; i < len(w.Sources); i += sourcesPerBatch {
+			end := i + sourcesPerBatch
+			if end > len(w.Sources) {
+				end = len(w.Sources)
+			}
+			batch := w.Sources[i:end]
+
+			wg.Add(1)
+			queue <- work{batch, w.Flags}
+		}
+	}
+
+	wg.Wait()
+
+	if failures > 0 {
+		log.Fatalln(failures, "failures after retries")
+	}
+}
diff --git a/src/third_party/skia/tools/fonts/RandomScalerContext.cpp b/src/third_party/skia/tools/fonts/RandomScalerContext.cpp
new file mode 100644
index 0000000..85430f5
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/RandomScalerContext.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkPath.h"
+#include "src/core/SkAdvancedTypefaceMetrics.h"
+#include "src/core/SkGlyph.h"
+#include "src/core/SkMakeUnique.h"
+#include "src/core/SkRectPriv.h"
+#include "tools/fonts/RandomScalerContext.h"
+
+class SkDescriptor;
+
+class RandomScalerContext : public SkScalerContext {
+public:
+    RandomScalerContext(sk_sp<SkRandomTypeface>,
+                        const SkScalerContextEffects&,
+                        const SkDescriptor*,
+                        bool fFakeIt);
+
+protected:
+    unsigned generateGlyphCount() override;
+    bool     generateAdvance(SkGlyph*) override;
+    void     generateMetrics(SkGlyph*) override;
+    void     generateImage(const SkGlyph&) override;
+    bool     generatePath(SkGlyphID, SkPath*) override;
+    void     generateFontMetrics(SkFontMetrics*) override;
+
+private:
+    SkRandomTypeface* getRandomTypeface() const {
+        return static_cast<SkRandomTypeface*>(this->getTypeface());
+    }
+    std::unique_ptr<SkScalerContext> fProxy;
+    bool                             fFakeIt;
+};
+
+RandomScalerContext::RandomScalerContext(sk_sp<SkRandomTypeface>       face,
+                                         const SkScalerContextEffects& effects,
+                                         const SkDescriptor*           desc,
+                                         bool                          fakeIt)
+        : SkScalerContext(std::move(face), effects, desc)
+        , fProxy(getRandomTypeface()->proxy()->createScalerContext(SkScalerContextEffects(), desc))
+        , fFakeIt(fakeIt) {
+    fProxy->forceGenerateImageFromPath();
+}
+
+unsigned RandomScalerContext::generateGlyphCount() { return fProxy->getGlyphCount(); }
+
+bool RandomScalerContext::generateAdvance(SkGlyph* glyph) { return fProxy->generateAdvance(glyph); }
+
+void RandomScalerContext::generateMetrics(SkGlyph* glyph) {
+    // Here we will change the mask format of the glyph
+    // NOTE: this may be overridden by the base class (e.g. if a mask filter is applied).
+    switch (glyph->getGlyphID() % 4) {
+        case 0: glyph->fMaskFormat = SkMask::kLCD16_Format; break;
+        case 1: glyph->fMaskFormat = SkMask::kA8_Format; break;
+        case 2: glyph->fMaskFormat = SkMask::kARGB32_Format; break;
+        case 3: glyph->fMaskFormat = SkMask::kBW_Format; break;
+    }
+
+    fProxy->getMetrics(glyph);
+
+    if (fFakeIt || (glyph->getGlyphID() % 4) != 2) {
+        return;
+    }
+
+    SkPath path;
+    if (!fProxy->getPath(glyph->getPackedID(), &path)) {
+        return;
+    }
+    glyph->fMaskFormat = SkMask::kARGB32_Format;
+
+    SkRect         storage;
+    const SkPaint& paint = this->getRandomTypeface()->paint();
+    const SkRect&  newBounds =
+            paint.doComputeFastBounds(path.getBounds(), &storage, SkPaint::kFill_Style);
+    SkIRect ibounds;
+    newBounds.roundOut(&ibounds);
+    glyph->fLeft   = ibounds.fLeft;
+    glyph->fTop    = ibounds.fTop;
+    glyph->fWidth  = ibounds.width();
+    glyph->fHeight = ibounds.height();
+}
+
+void RandomScalerContext::generateImage(const SkGlyph& glyph) {
+    // TODO: can force down but not up
+    /*
+    SkMask::Format format = (SkMask::Format)glyph.fMaskFormat;
+    switch (glyph.getGlyphID() % 4) {
+        case 0: format = SkMask::kLCD16_Format; break;
+        case 1: format = SkMask::kA8_Format; break;
+        case 2: format = SkMask::kARGB32_Format; break;
+        case 3: format = SkMask::kBW_Format; break;
+    }
+    const_cast<SkGlyph&>(glyph).fMaskFormat = format;
+    */
+
+    if (fFakeIt) {
+        sk_bzero(glyph.fImage, glyph.imageSize());
+        return;
+    }
+
+    if (SkMask::kARGB32_Format != glyph.fMaskFormat) {
+        fProxy->getImage(glyph);
+        return;
+    }
+
+    // If the format is ARGB, just draw the glyph from path.
+    SkPath path;
+    if (!fProxy->getPath(glyph.getPackedID(), &path)) {
+        fProxy->getImage(glyph);
+        return;
+    }
+
+    SkBitmap bm;
+    bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight),
+                     glyph.fImage,
+                     glyph.rowBytes());
+    bm.eraseColor(0);
+
+    SkCanvas canvas(bm);
+    canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop));
+    canvas.drawPath(path, this->getRandomTypeface()->paint());
+}
+
+bool RandomScalerContext::generatePath(SkGlyphID glyph, SkPath* path) {
+    return fProxy->generatePath(glyph, path);
+}
+
+void RandomScalerContext::generateFontMetrics(SkFontMetrics* metrics) {
+    fProxy->getFontMetrics(metrics);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkRandomTypeface::SkRandomTypeface(sk_sp<SkTypeface> proxy, const SkPaint& paint, bool fakeIt)
+        : SkTypeface(proxy->fontStyle(), false)
+        , fProxy(std::move(proxy))
+        , fPaint(paint)
+        , fFakeIt(fakeIt) {}
+
+SkScalerContext* SkRandomTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
+                                                         const SkDescriptor*           desc) const {
+    return new RandomScalerContext(
+            sk_ref_sp(const_cast<SkRandomTypeface*>(this)), effects, desc, fFakeIt);
+}
+
+void SkRandomTypeface::onFilterRec(SkScalerContextRec* rec) const {
+    fProxy->filterRec(rec);
+    rec->setHinting(SkFontHinting::kNone);
+    rec->fMaskFormat = SkMask::kARGB32_Format;
+}
+
+void SkRandomTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
+    fProxy->getGlyphToUnicodeMap(glyphToUnicode);
+}
+
+std::unique_ptr<SkAdvancedTypefaceMetrics> SkRandomTypeface::onGetAdvancedMetrics() const {
+    return fProxy->getAdvancedMetrics();
+}
+
+std::unique_ptr<SkStreamAsset> SkRandomTypeface::onOpenStream(int* ttcIndex) const {
+    return fProxy->openStream(ttcIndex);
+}
+
+sk_sp<SkTypeface> SkRandomTypeface::onMakeClone(const SkFontArguments& args) const {
+    sk_sp<SkTypeface> proxy = fProxy->makeClone(args);
+    if (!proxy) {
+        return nullptr;
+    }
+    return sk_make_sp<SkRandomTypeface>(proxy, fPaint, fFakeIt);
+}
+
+void SkRandomTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
+    // TODO: anything that uses this typeface isn't correctly serializable, since this typeface
+    // cannot be deserialized.
+    fProxy->getFontDescriptor(desc, isLocal);
+}
+
+void SkRandomTypeface::onCharsToGlyphs(const SkUnichar* uni, int count, SkGlyphID glyphs[]) const {
+    fProxy->unicharsToGlyphs(uni, count, glyphs);
+}
+
+int SkRandomTypeface::onCountGlyphs() const { return fProxy->countGlyphs(); }
+
+int SkRandomTypeface::onGetUPEM() const { return fProxy->getUnitsPerEm(); }
+
+void SkRandomTypeface::onGetFamilyName(SkString* familyName) const {
+    fProxy->getFamilyName(familyName);
+}
+
+SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() const {
+    return fProxy->createFamilyNameIterator();
+}
+
+void SkRandomTypeface::getPostScriptGlyphNames(SkString* names) const {
+    return fProxy->getPostScriptGlyphNames(names);
+}
+
+int SkRandomTypeface::onGetVariationDesignPosition(
+        SkFontArguments::VariationPosition::Coordinate coordinates[],
+        int                                            coordinateCount) const {
+    return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount);
+}
+
+int SkRandomTypeface::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                                     int parameterCount) const {
+    return fProxy->onGetVariationDesignParameters(parameters, parameterCount);
+}
+
+int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const {
+    return fProxy->getTableTags(tags);
+}
+
+size_t SkRandomTypeface::onGetTableData(SkFontTableTag tag,
+                                        size_t         offset,
+                                        size_t         length,
+                                        void*          data) const {
+    return fProxy->getTableData(tag, offset, length, data);
+}
diff --git a/src/third_party/skia/tools/fonts/RandomScalerContext.h b/src/third_party/skia/tools/fonts/RandomScalerContext.h
new file mode 100644
index 0000000..2601fd4
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/RandomScalerContext.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef RandomScalerContext_DEFINED
+#define RandomScalerContext_DEFINED
+
+#include "include/core/SkTypeface.h"
+#include "src/core/SkScalerContext.h"
+
+/*
+ * This scaler context is for debug only purposes.  It will 'randomly' but deterministically return
+ * LCD / A8 / BW / RBGA masks based off of the Glyph ID
+ */
+
+class SkRandomTypeface : public SkTypeface {
+public:
+    SkRandomTypeface(sk_sp<SkTypeface> proxy, const SkPaint&, bool fakeit);
+
+    SkTypeface*    proxy() const { return fProxy.get(); }
+    const SkPaint& paint() const { return fPaint; }
+
+protected:
+    SkScalerContext*                           onCreateScalerContext(const SkScalerContextEffects&,
+                                                                     const SkDescriptor*) const override;
+    void                                       onFilterRec(SkScalerContextRec*) const override;
+    void                                       getGlyphToUnicodeMap(SkUnichar*) const override;
+    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
+    std::unique_ptr<SkStreamAsset>             onOpenStream(int* ttcIndex) const override;
+    sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override;
+    void              onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const override;
+
+    void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
+    int onCountGlyphs() const override;
+    int onGetUPEM() const override;
+
+    void                          onGetFamilyName(SkString* familyName) const override;
+    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
+
+    void getPostScriptGlyphNames(SkString*) const override;
+
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override;
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override;
+    int onGetTableTags(SkFontTableTag tags[]) const override;
+    size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
+
+private:
+    sk_sp<SkTypeface> fProxy;
+    SkPaint           fPaint;
+    bool              fFakeIt;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/fonts/TestEmptyTypeface.h b/src/third_party/skia/tools/fonts/TestEmptyTypeface.h
new file mode 100644
index 0000000..3d61762
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestEmptyTypeface.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TestEmptyTypeface_DEFINED
+#define TestEmptyTypeface_DEFINED
+
+#include "include/core/SkStream.h"
+#include "include/core/SkTypeface.h"
+#include "src/core/SkAdvancedTypefaceMetrics.h"
+
+class TestEmptyTypeface : public SkTypeface {
+public:
+    static sk_sp<SkTypeface> Make() { return sk_sp<SkTypeface>(new TestEmptyTypeface); }
+
+protected:
+    TestEmptyTypeface() : SkTypeface(SkFontStyle(), true) {}
+
+    std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override { return nullptr; }
+    sk_sp<SkTypeface>              onMakeClone(const SkFontArguments& args) const override {
+        return sk_ref_sp(this);
+    }
+    SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
+                                           const SkDescriptor*) const override {
+        return nullptr;
+    }
+    void                                       onFilterRec(SkScalerContextRec*) const override {}
+    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override {
+        return nullptr;
+    }
+    void        onGetFontDescriptor(SkFontDescriptor*, bool*) const override {}
+    void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override {
+        sk_bzero(glyphs, count * sizeof(glyphs[0]));
+    }
+    int onCountGlyphs() const override { return 0; }
+    void getPostScriptGlyphNames(SkString*) const override {}
+    void getGlyphToUnicodeMap(SkUnichar*) const override {}
+    int onGetUPEM() const override { return 0; }
+    class EmptyLocalizedStrings : public SkTypeface::LocalizedStrings {
+    public:
+        bool next(SkTypeface::LocalizedString*) override { return false; }
+    };
+    void onGetFamilyName(SkString* familyName) const override { familyName->reset(); }
+    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override {
+        return new EmptyLocalizedStrings;
+    }
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override {
+        return 0;
+    }
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override {
+        return 0;
+    }
+    int    onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
+    size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; }
+};
+
+#endif  // TestEmptyTypeface_DEFINED
diff --git a/src/third_party/skia/tools/fonts/TestFontMgr.cpp b/src/third_party/skia/tools/fonts/TestFontMgr.cpp
new file mode 100644
index 0000000..3b70a0a
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestFontMgr.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/core/SkFontDescriptor.h"
+#include "tools/ToolUtils.h"
+#include "tools/fonts/TestFontMgr.h"
+#include "tools/fonts/TestTypeface.h"
+
+#ifdef SK_XML
+#include "tools/fonts/TestSVGTypeface.h"
+#endif
+
+#include <vector>
+
+namespace {
+
+#include "test_font_monospace.inc"
+#include "test_font_sans_serif.inc"
+#include "test_font_serif.inc"
+
+#include "test_font_index.inc"
+
+class FontStyleSet final : public SkFontStyleSet {
+public:
+    FontStyleSet(const char* familyName) : fFamilyName(familyName) {}
+    struct TypefaceEntry {
+        TypefaceEntry(sk_sp<SkTypeface> typeface, SkFontStyle style, const char* styleName)
+                : fTypeface(std::move(typeface)), fStyle(style), fStyleName(styleName) {}
+        sk_sp<SkTypeface> fTypeface;
+        SkFontStyle       fStyle;
+        const char*       fStyleName;
+    };
+
+    int count() override { return fTypefaces.size(); }
+
+    void getStyle(int index, SkFontStyle* style, SkString* name) override {
+        if (style) {
+            *style = fTypefaces[index].fStyle;
+        }
+        if (name) {
+            *name = fTypefaces[index].fStyleName;
+        }
+    }
+
+    SkTypeface* createTypeface(int index) override {
+        return SkRef(fTypefaces[index].fTypeface.get());
+    }
+
+    SkTypeface* matchStyle(const SkFontStyle& pattern) override {
+        return this->matchStyleCSS3(pattern);
+    }
+
+    SkString getFamilyName() { return fFamilyName; }
+
+    std::vector<TypefaceEntry> fTypefaces;
+    SkString                   fFamilyName;
+};
+
+class FontMgr final : public SkFontMgr {
+public:
+    FontMgr() {
+        for (const auto& sub : gSubFonts) {
+            sk_sp<TestTypeface> typeface =
+                    sk_make_sp<TestTypeface>(sk_make_sp<SkTestFont>(sub.fFont), sub.fStyle);
+            bool defaultFamily = false;
+            if (&sub - gSubFonts == gDefaultFontIndex) {
+                defaultFamily    = true;
+                fDefaultTypeface = typeface;
+            }
+            bool found = false;
+            for (const auto& family : fFamilies) {
+                if (family->getFamilyName().equals(sub.fFamilyName)) {
+                    family->fTypefaces.emplace_back(
+                            std::move(typeface), sub.fStyle, sub.fStyleName);
+                    found = true;
+                    if (defaultFamily) {
+                        fDefaultFamily = family;
+                    }
+                    break;
+                }
+            }
+            if (!found) {
+                fFamilies.emplace_back(sk_make_sp<FontStyleSet>(sub.fFamilyName));
+                fFamilies.back()->fTypefaces.emplace_back(
+                        // NOLINTNEXTLINE(bugprone-use-after-move)
+                        std::move(typeface),
+                        sub.fStyle,
+                        sub.fStyleName);
+                if (defaultFamily) {
+                    fDefaultFamily = fFamilies.back();
+                }
+            }
+        }
+#ifdef SK_XML
+        fFamilies.emplace_back(sk_make_sp<FontStyleSet>("Emoji"));
+        fFamilies.back()->fTypefaces.emplace_back(
+                TestSVGTypeface::Default(), SkFontStyle::Normal(), "Normal");
+
+        fFamilies.emplace_back(sk_make_sp<FontStyleSet>("Planet"));
+        fFamilies.back()->fTypefaces.emplace_back(
+                TestSVGTypeface::Planets(), SkFontStyle::Normal(), "Normal");
+#endif
+    }
+
+    int onCountFamilies() const override { return fFamilies.size(); }
+
+    void onGetFamilyName(int index, SkString* familyName) const override {
+        *familyName = fFamilies[index]->getFamilyName();
+    }
+
+    SkFontStyleSet* onCreateStyleSet(int index) const override {
+        sk_sp<SkFontStyleSet> ref = fFamilies[index];
+        return ref.release();
+    }
+
+    SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
+        if (familyName) {
+            if (strstr(familyName, "ono")) {
+                return this->createStyleSet(0);
+            }
+            if (strstr(familyName, "ans")) {
+                return this->createStyleSet(1);
+            }
+            if (strstr(familyName, "erif")) {
+                return this->createStyleSet(2);
+            }
+#ifdef SK_XML
+            if (strstr(familyName, "oji")) {
+                return this->createStyleSet(6);
+            }
+            if (strstr(familyName, "Planet")) {
+                return this->createStyleSet(7);
+            }
+#endif
+        }
+        return nullptr;
+    }
+
+    SkTypeface* onMatchFamilyStyle(const char         familyName[],
+                                   const SkFontStyle& style) const override {
+        sk_sp<SkFontStyleSet> styleSet(this->matchFamily(familyName));
+        return styleSet->matchStyle(style);
+    }
+
+    SkTypeface* onMatchFamilyStyleCharacter(const char         familyName[],
+                                            const SkFontStyle& style,
+                                            const char*        bcp47[],
+                                            int                bcp47Count,
+                                            SkUnichar          character) const override {
+        (void)bcp47;
+        (void)bcp47Count;
+        (void)character;
+        return this->matchFamilyStyle(familyName, style);
+    }
+
+    SkTypeface* onMatchFaceStyle(const SkTypeface* tf, const SkFontStyle& style) const override {
+        SkString familyName;
+        tf->getFamilyName(&familyName);
+        return this->matchFamilyStyle(familyName.c_str(), style);
+    }
+
+    sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override { return nullptr; }
+    sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
+                                            int ttcIndex) const override {
+        return nullptr;
+    }
+    sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
+                                           const SkFontArguments&) const override {
+        return nullptr;
+    }
+    sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData>) const override {
+        return nullptr;
+    }
+    sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
+        return nullptr;
+    }
+
+    sk_sp<SkTypeface> onLegacyMakeTypeface(const char  familyName[],
+                                           SkFontStyle style) const override {
+        if (familyName == nullptr) {
+            return sk_sp<SkTypeface>(fDefaultFamily->matchStyle(style));
+        }
+        sk_sp<SkTypeface> typeface = sk_sp<SkTypeface>(this->matchFamilyStyle(familyName, style));
+        if (!typeface) {
+            typeface = fDefaultTypeface;
+        }
+        return typeface;
+    }
+
+private:
+    std::vector<sk_sp<FontStyleSet>> fFamilies;
+    sk_sp<FontStyleSet>              fDefaultFamily;
+    sk_sp<SkTypeface>                fDefaultTypeface;
+};
+}  // namespace
+
+namespace ToolUtils {
+sk_sp<SkFontMgr> MakePortableFontMgr() { return sk_make_sp<FontMgr>(); }
+}  // namespace ToolUtils
diff --git a/src/third_party/skia/tools/fonts/TestFontMgr.h b/src/third_party/skia/tools/fonts/TestFontMgr.h
new file mode 100644
index 0000000..b3afd2f
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestFontMgr.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TestFontMgr_DEFINED
+#define TestFontMgr_DEFINED
+
+#include "include/core/SkFontMgr.h"
+
+// An SkFontMgr that always uses ToolUtils::create_portable_typeface().
+
+namespace ToolUtils {
+sk_sp<SkFontMgr> MakePortableFontMgr();
+}  // namespace ToolUtils
+
+#endif  // TestFontMgr_DEFINED
diff --git a/src/third_party/skia/tools/fonts/TestSVGTypeface.cpp b/src/third_party/skia/tools/fonts/TestSVGTypeface.cpp
new file mode 100644
index 0000000..13c4d31
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestSVGTypeface.cpp
@@ -0,0 +1,1442 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/fonts/TestSVGTypeface.h"
+
+#ifdef SK_XML
+
+#include "experimental/svg/model/SkSVGDOM.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkData.h"
+#include "include/core/SkEncodedImageFormat.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkPathEffect.h"
+#include "include/core/SkPixmap.h"
+#include "include/core/SkRRect.h"
+#include "include/core/SkSize.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/pathops/SkPathOps.h"
+#include "include/private/SkTDArray.h"
+#include "include/private/SkTemplates.h"
+#include "include/utils/SkNoDrawCanvas.h"
+#include "src/core/SkAdvancedTypefaceMetrics.h"
+#include "src/core/SkFontDescriptor.h"
+#include "src/core/SkFontPriv.h"
+#include "src/core/SkGeometry.h"
+#include "src/core/SkGlyph.h"
+#include "src/core/SkMask.h"
+#include "src/core/SkPaintPriv.h"
+#include "src/core/SkPathPriv.h"
+#include "src/core/SkPointPriv.h"
+#include "src/core/SkScalerContext.h"
+#include "src/core/SkUtils.h"
+#include "src/sfnt/SkOTUtils.h"
+#include "tools/Resources.h"
+
+#include <utility>
+
+class SkDescriptor;
+
+TestSVGTypeface::TestSVGTypeface(const char*                              name,
+                                 int                                      upem,
+                                 const SkFontMetrics&                     fontMetrics,
+                                 SkSpan<const SkSVGTestTypefaceGlyphData> data,
+                                 const SkFontStyle&                       style)
+        : SkTypeface(style, false)
+        , fName(name)
+        , fUpem(upem)
+        , fFontMetrics(fontMetrics)
+        , fGlyphs(new Glyph[data.size()])
+        , fGlyphCount(data.size()) {
+    for (size_t i = 0; i < data.size(); ++i) {
+        const SkSVGTestTypefaceGlyphData& datum  = data[i];
+        fCMap.set(datum.fUnicode, i);
+        fGlyphs[i].fAdvance      = datum.fAdvance;
+        fGlyphs[i].fOrigin       = datum.fOrigin;
+        fGlyphs[i].fResourcePath = datum.fSvgResourcePath;
+    }
+}
+
+template <typename Fn>
+void TestSVGTypeface::Glyph::withSVG(Fn&& fn) const {
+    SkAutoMutexExclusive lock(fSvgMutex);
+
+    if (!fParsedSvg) {
+        fParsedSvg = true;
+
+        std::unique_ptr<SkStreamAsset> stream = GetResourceAsStream(fResourcePath);
+        if (!stream) {
+            return;
+        }
+
+        sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(*stream.get());
+        if (!svg) {
+            return;
+        }
+
+        if (svg->containerSize().isEmpty()) {
+            return;
+        }
+
+        fSvg = std::move(svg);
+    }
+
+    if (fSvg) {
+        fn(*fSvg);
+    }
+}
+
+SkSize TestSVGTypeface::Glyph::size() const {
+    SkSize size = SkSize::MakeEmpty();
+    this->withSVG([&](const SkSVGDOM& svg){
+        size = svg.containerSize();
+    });
+    return size;
+}
+
+void TestSVGTypeface::Glyph::render(SkCanvas* canvas) const {
+    this->withSVG([&](const SkSVGDOM& svg){
+        svg.render(canvas);
+    });
+}
+
+TestSVGTypeface::~TestSVGTypeface() {}
+
+TestSVGTypeface::Glyph::Glyph() : fOrigin{0, 0}, fAdvance(0) {}
+TestSVGTypeface::Glyph::~Glyph() {}
+
+void TestSVGTypeface::getAdvance(SkGlyph* glyph) const {
+    SkGlyphID glyphID = glyph->getGlyphID();
+    glyphID           = glyphID < fGlyphCount ? glyphID : 0;
+
+    glyph->fAdvanceX = fGlyphs[glyphID].fAdvance;
+    glyph->fAdvanceY = 0;
+}
+
+void TestSVGTypeface::getFontMetrics(SkFontMetrics* metrics) const { *metrics = fFontMetrics; }
+
+void TestSVGTypeface::onFilterRec(SkScalerContextRec* rec) const {
+    rec->setHinting(SkFontHinting::kNone);
+}
+
+void TestSVGTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
+    SkDEBUGCODE(unsigned glyphCount = this->countGlyphs());
+    fCMap.foreach ([=](const SkUnichar& c, const SkGlyphID& g) {
+        SkASSERT(g < glyphCount);
+        glyphToUnicode[g] = c;
+    });
+}
+
+std::unique_ptr<SkAdvancedTypefaceMetrics> TestSVGTypeface::onGetAdvancedMetrics() const {
+    std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
+    info->fFontName = fName;
+    return info;
+}
+
+void TestSVGTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
+    desc->setFamilyName(fName.c_str());
+    desc->setStyle(this->fontStyle());
+    *isLocal = false;
+}
+
+void TestSVGTypeface::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
+    for (int i = 0; i < count; i++) {
+        SkGlyphID* g = fCMap.find(uni[i]);
+        glyphs[i]    = g ? *g : 0;
+    }
+}
+
+void TestSVGTypeface::onGetFamilyName(SkString* familyName) const { *familyName = fName; }
+
+SkTypeface::LocalizedStrings* TestSVGTypeface::onCreateFamilyNameIterator() const {
+    SkString familyName(fName);
+    SkString language("und");  // undetermined
+    return new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
+}
+
+class SkTestSVGScalerContext : public SkScalerContext {
+public:
+    SkTestSVGScalerContext(sk_sp<TestSVGTypeface>        face,
+                           const SkScalerContextEffects& effects,
+                           const SkDescriptor*           desc)
+            : SkScalerContext(std::move(face), effects, desc) {
+        fRec.getSingleMatrix(&fMatrix);
+        SkScalar upem = this->getTestSVGTypeface()->fUpem;
+        fMatrix.preScale(1.f / upem, 1.f / upem);
+    }
+
+protected:
+    TestSVGTypeface* getTestSVGTypeface() const {
+        return static_cast<TestSVGTypeface*>(this->getTypeface());
+    }
+
+    unsigned generateGlyphCount() override { return this->getTestSVGTypeface()->countGlyphs(); }
+
+    bool generateAdvance(SkGlyph* glyph) override {
+        this->getTestSVGTypeface()->getAdvance(glyph);
+
+        const SkVector advance =
+                fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY));
+        glyph->fAdvanceX = SkScalarToFloat(advance.fX);
+        glyph->fAdvanceY = SkScalarToFloat(advance.fY);
+        return true;
+    }
+
+    void generateMetrics(SkGlyph* glyph) override {
+        SkGlyphID glyphID = glyph->getGlyphID();
+        glyphID           = glyphID < this->getTestSVGTypeface()->fGlyphCount ? glyphID : 0;
+
+        glyph->zeroMetrics();
+        glyph->fMaskFormat = SkMask::kARGB32_Format;
+        this->generateAdvance(glyph);
+
+        TestSVGTypeface::Glyph& glyphData = this->getTestSVGTypeface()->fGlyphs[glyphID];
+
+        SkSize containerSize = glyphData.size();
+        SkRect newBounds = SkRect::MakeXYWH(glyphData.fOrigin.fX,
+                                           -glyphData.fOrigin.fY,
+                                            containerSize.fWidth,
+                                            containerSize.fHeight);
+        fMatrix.mapRect(&newBounds);
+        SkScalar dx = SkFixedToScalar(glyph->getSubXFixed());
+        SkScalar dy = SkFixedToScalar(glyph->getSubYFixed());
+        newBounds.offset(dx, dy);
+
+        SkIRect ibounds;
+        newBounds.roundOut(&ibounds);
+        glyph->fLeft   = ibounds.fLeft;
+        glyph->fTop    = ibounds.fTop;
+        glyph->fWidth  = ibounds.width();
+        glyph->fHeight = ibounds.height();
+    }
+
+    void generateImage(const SkGlyph& glyph) override {
+        SkGlyphID glyphID = glyph.getGlyphID();
+        glyphID           = glyphID < this->getTestSVGTypeface()->fGlyphCount ? glyphID : 0;
+
+        SkBitmap bm;
+        // TODO: this should be SkImageInfo::MakeS32 when that passes all the tests.
+        bm.installPixels(SkImageInfo::MakeN32(glyph.fWidth, glyph.fHeight, kPremul_SkAlphaType),
+                         glyph.fImage,
+                         glyph.rowBytes());
+        bm.eraseColor(0);
+
+        TestSVGTypeface::Glyph& glyphData = this->getTestSVGTypeface()->fGlyphs[glyphID];
+
+        SkScalar dx = SkFixedToScalar(glyph.getSubXFixed());
+        SkScalar dy = SkFixedToScalar(glyph.getSubYFixed());
+
+        SkCanvas canvas(bm);
+        canvas.translate(-glyph.fLeft, -glyph.fTop);
+        canvas.translate(dx, dy);
+        canvas.concat(fMatrix);
+        canvas.translate(glyphData.fOrigin.fX, -glyphData.fOrigin.fY);
+
+        glyphData.render(&canvas);
+    }
+
+    bool generatePath(SkGlyphID glyph, SkPath* path) override {
+        path->reset();
+        return false;
+    }
+
+    void generateFontMetrics(SkFontMetrics* metrics) override {
+        this->getTestSVGTypeface()->getFontMetrics(metrics);
+        SkFontPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
+    }
+
+private:
+    SkMatrix fMatrix;
+};
+
+SkScalerContext* TestSVGTypeface::onCreateScalerContext(const SkScalerContextEffects& e,
+                                                        const SkDescriptor*           desc) const {
+    return new SkTestSVGScalerContext(sk_ref_sp(const_cast<TestSVGTypeface*>(this)), e, desc);
+}
+
+sk_sp<TestSVGTypeface> TestSVGTypeface::Default() {
+    // Recommended that the first four be .notdef, .null, CR, space
+    constexpr const static SkSVGTestTypefaceGlyphData glyphs[] = {
+            {"fonts/svg/notdef.svg", {100, 800}, 800, 0x0},      // .notdef
+            {"fonts/svg/empty.svg", {0, 0}, 800, 0x0020},        // space
+            {"fonts/svg/diamond.svg", {100, 800}, 800, 0x2662},  // ♢
+            {"fonts/svg/smile.svg", {0, 800}, 800, 0x1F600},     // 😀
+    };
+    SkFontMetrics metrics;
+    metrics.fFlags = SkFontMetrics::kUnderlineThicknessIsValid_Flag |
+                     SkFontMetrics::kUnderlinePositionIsValid_Flag |
+                     SkFontMetrics::kStrikeoutThicknessIsValid_Flag |
+                     SkFontMetrics::kStrikeoutPositionIsValid_Flag;
+    metrics.fTop                = -800;
+    metrics.fAscent             = -800;
+    metrics.fDescent            = 200;
+    metrics.fBottom             = 200;
+    metrics.fLeading            = 100;
+    metrics.fAvgCharWidth       = 1000;
+    metrics.fMaxCharWidth       = 1000;
+    metrics.fXMin               = 0;
+    metrics.fXMax               = 1000;
+    metrics.fXHeight            = 500;
+    metrics.fCapHeight          = 700;
+    metrics.fUnderlineThickness = 40;
+    metrics.fUnderlinePosition  = 20;
+    metrics.fStrikeoutThickness = 20;
+    metrics.fStrikeoutPosition  = -400;
+
+    class DefaultTypeface : public TestSVGTypeface {
+        using TestSVGTypeface::TestSVGTypeface;
+
+        bool getPathOp(SkColor color, SkPathOp* op) const override {
+            if ((SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color)) / 3 > 0x20) {
+                *op = SkPathOp::kDifference_SkPathOp;
+            } else {
+                *op = SkPathOp::kUnion_SkPathOp;
+            }
+            return true;
+        }
+    };
+    return sk_make_sp<DefaultTypeface>("Emoji",
+                                       1000,
+                                       metrics,
+                                       SkMakeSpan(glyphs),
+                                       SkFontStyle::Normal());
+}
+
+sk_sp<TestSVGTypeface> TestSVGTypeface::Planets() {
+    // Recommended that the first four be .notdef, .null, CR, space
+    constexpr const static SkSVGTestTypefaceGlyphData glyphs[] = {
+            {"fonts/svg/planets/pluto.svg", {0, 20}, 60, 0x0},             // .notdef
+            {"fonts/svg/empty.svg", {0, 0}, 400, 0x0020},                  // space
+            {"fonts/svg/planets/mercury.svg", {0, 45}, 120, 0x263F},       // ☿
+            {"fonts/svg/planets/venus.svg", {0, 100}, 240, 0x2640},        // ♀
+            {"fonts/svg/planets/earth.svg", {0, 100}, 240, 0x2641},        // ♁
+            {"fonts/svg/planets/mars.svg", {0, 50}, 130, 0x2642},          // ♂
+            {"fonts/svg/planets/jupiter.svg", {0, 1000}, 2200, 0x2643},    // ♃
+            {"fonts/svg/planets/saturn.svg", {-300, 1500}, 2600, 0x2644},  // ♄
+            {"fonts/svg/planets/uranus.svg", {0, 375}, 790, 0x2645},       // ♅
+            {"fonts/svg/planets/neptune.svg", {0, 350}, 740, 0x2646},      // ♆
+    };
+    SkFontMetrics metrics;
+    metrics.fFlags = SkFontMetrics::kUnderlineThicknessIsValid_Flag |
+                     SkFontMetrics::kUnderlinePositionIsValid_Flag |
+                     SkFontMetrics::kStrikeoutThicknessIsValid_Flag |
+                     SkFontMetrics::kStrikeoutPositionIsValid_Flag;
+    metrics.fTop                = -1500;
+    metrics.fAscent             = -200;
+    metrics.fDescent            = 50;
+    metrics.fBottom             = 1558;
+    metrics.fLeading            = 10;
+    metrics.fAvgCharWidth       = 200;
+    metrics.fMaxCharWidth       = 200;
+    metrics.fXMin               = -300;
+    metrics.fXMax               = 2566;
+    metrics.fXHeight            = 100;
+    metrics.fCapHeight          = 180;
+    metrics.fUnderlineThickness = 8;
+    metrics.fUnderlinePosition  = 2;
+    metrics.fStrikeoutThickness = 2;
+    metrics.fStrikeoutPosition  = -80;
+
+    class PlanetTypeface : public TestSVGTypeface {
+        using TestSVGTypeface::TestSVGTypeface;
+
+        bool getPathOp(SkColor color, SkPathOp* op) const override {
+            *op = SkPathOp::kUnion_SkPathOp;
+            return true;
+        }
+    };
+    return sk_make_sp<PlanetTypeface>("Planets",
+                                      200,
+                                      metrics,
+                                      SkMakeSpan(glyphs),
+                                      SkFontStyle::Normal());
+}
+
+void TestSVGTypeface::exportTtxCommon(SkWStream*                out,
+                                      const char*               type,
+                                      const SkTArray<GlyfInfo>* glyfInfo) const {
+    int totalGlyphs = fGlyphCount;
+    out->writeText("  <GlyphOrder>\n");
+    for (int i = 0; i < fGlyphCount; ++i) {
+        out->writeText("    <GlyphID name=\"glyf");
+        out->writeHexAsText(i, 4);
+        out->writeText("\"/>\n");
+    }
+    if (glyfInfo) {
+        for (int i = 0; i < fGlyphCount; ++i) {
+            for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) {
+                out->writeText("    <GlyphID name=\"glyf");
+                out->writeHexAsText(i, 4);
+                out->writeText("l");
+                out->writeHexAsText(j, 4);
+                out->writeText("\"/>\n");
+                ++totalGlyphs;
+            }
+        }
+    }
+    out->writeText("  </GlyphOrder>\n");
+
+    out->writeText("  <head>\n");
+    out->writeText("    <tableVersion value=\"1.0\"/>\n");
+    out->writeText("    <fontRevision value=\"1.0\"/>\n");
+    out->writeText("    <checkSumAdjustment value=\"0xa9c3274\"/>\n");
+    out->writeText("    <magicNumber value=\"0x5f0f3cf5\"/>\n");
+    out->writeText("    <flags value=\"00000000 00011011\"/>\n");
+    out->writeText("    <unitsPerEm value=\"");
+    out->writeDecAsText(fUpem);
+    out->writeText("\"/>\n");
+    out->writeText("    <created value=\"Thu Feb 15 12:55:49 2018\"/>\n");
+    out->writeText("    <modified value=\"Thu Feb 15 12:55:49 2018\"/>\n");
+    // TODO: not recalculated for bitmap fonts?
+    out->writeText("    <xMin value=\"");
+    out->writeScalarAsText(fFontMetrics.fXMin);
+    out->writeText("\"/>\n");
+    out->writeText("    <yMin value=\"");
+    out->writeScalarAsText(-fFontMetrics.fBottom);
+    out->writeText("\"/>\n");
+    out->writeText("    <xMax value=\"");
+    out->writeScalarAsText(fFontMetrics.fXMax);
+    out->writeText("\"/>\n");
+    out->writeText("    <yMax value=\"");
+    out->writeScalarAsText(-fFontMetrics.fTop);
+    out->writeText("\"/>\n");
+
+    char macStyle[16] = {
+            '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
+    if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
+        macStyle[0xF - 0x0] = '1';  // Bold
+    }
+    switch (this->fontStyle().slant()) {
+        case SkFontStyle::kUpright_Slant: break;
+        case SkFontStyle::kItalic_Slant:
+            macStyle[0xF - 0x1] = '1';  // Italic
+            break;
+        case SkFontStyle::kOblique_Slant:
+            macStyle[0xF - 0x1] = '1';  // Italic
+            break;
+        default: SK_ABORT("Unknown slant.");
+    }
+    if (this->fontStyle().width() <= SkFontStyle::kCondensed_Width) {
+        macStyle[0xF - 0x5] = '1';  // Condensed
+    } else if (this->fontStyle().width() >= SkFontStyle::kExpanded_Width) {
+        macStyle[0xF - 0x6] = '1';  // Extended
+    }
+    out->writeText("    <macStyle value=\"");
+    out->write(macStyle, 8);
+    out->writeText(" ");
+    out->write(macStyle + 8, 8);
+    out->writeText("\"/>\n");
+    out->writeText("    <lowestRecPPEM value=\"8\"/>\n");
+    out->writeText("    <fontDirectionHint value=\"2\"/>\n");
+    out->writeText("    <indexToLocFormat value=\"0\"/>\n");
+    out->writeText("    <glyphDataFormat value=\"0\"/>\n");
+    out->writeText("  </head>\n");
+
+    out->writeText("  <hhea>\n");
+    out->writeText("    <tableVersion value=\"0x00010000\"/>\n");
+    out->writeText("    <ascent value=\"");
+    out->writeDecAsText(-fFontMetrics.fAscent);
+    out->writeText("\"/>\n");
+    out->writeText("    <descent value=\"");
+    out->writeDecAsText(-fFontMetrics.fDescent);
+    out->writeText("\"/>\n");
+    out->writeText("    <lineGap value=\"");
+    out->writeDecAsText(fFontMetrics.fLeading);
+    out->writeText("\"/>\n");
+    out->writeText("    <advanceWidthMax value=\"0\"/>\n");
+    out->writeText("    <minLeftSideBearing value=\"0\"/>\n");
+    out->writeText("    <minRightSideBearing value=\"0\"/>\n");
+    out->writeText("    <xMaxExtent value=\"");
+    out->writeScalarAsText(fFontMetrics.fXMax - fFontMetrics.fXMin);
+    out->writeText("\"/>\n");
+    out->writeText("    <caretSlopeRise value=\"1\"/>\n");
+    out->writeText("    <caretSlopeRun value=\"0\"/>\n");
+    out->writeText("    <caretOffset value=\"0\"/>\n");
+    out->writeText("    <reserved0 value=\"0\"/>\n");
+    out->writeText("    <reserved1 value=\"0\"/>\n");
+    out->writeText("    <reserved2 value=\"0\"/>\n");
+    out->writeText("    <reserved3 value=\"0\"/>\n");
+    out->writeText("    <metricDataFormat value=\"0\"/>\n");
+    out->writeText("    <numberOfHMetrics value=\"0\"/>\n");
+    out->writeText("  </hhea>\n");
+
+    // Some of this table is going to be re-calculated, but we have to write it out anyway.
+    out->writeText("  <maxp>\n");
+    out->writeText("    <tableVersion value=\"0x10000\"/>\n");
+    out->writeText("    <numGlyphs value=\"");
+    out->writeDecAsText(totalGlyphs);
+    out->writeText("\"/>\n");
+    out->writeText("    <maxPoints value=\"4\"/>\n");
+    out->writeText("    <maxContours value=\"1\"/>\n");
+    out->writeText("    <maxCompositePoints value=\"0\"/>\n");
+    out->writeText("    <maxCompositeContours value=\"0\"/>\n");
+    out->writeText("    <maxZones value=\"1\"/>\n");
+    out->writeText("    <maxTwilightPoints value=\"0\"/>\n");
+    out->writeText("    <maxStorage value=\"0\"/>\n");
+    out->writeText("    <maxFunctionDefs value=\"10\"/>\n");
+    out->writeText("    <maxInstructionDefs value=\"0\"/>\n");
+    out->writeText("    <maxStackElements value=\"512\"/>\n");
+    out->writeText("    <maxSizeOfInstructions value=\"24\"/>\n");
+    out->writeText("    <maxComponentElements value=\"0\"/>\n");
+    out->writeText("    <maxComponentDepth value=\"0\"/>\n");
+    out->writeText("  </maxp>\n");
+
+    out->writeText("  <OS_2>\n");
+    out->writeText("    <version value=\"4\"/>\n");
+    out->writeText("    <xAvgCharWidth value=\"");
+    out->writeScalarAsText(fFontMetrics.fAvgCharWidth);
+    out->writeText("\"/>\n");
+    out->writeText("    <usWeightClass value=\"");
+    out->writeDecAsText(this->fontStyle().weight());
+    out->writeText("\"/>\n");
+    out->writeText("    <usWidthClass value=\"");
+    out->writeDecAsText(this->fontStyle().width());
+    out->writeText("\"/>\n");
+    out->writeText("    <fsType value=\"00000000 00000000\"/>\n");
+    out->writeText("    <ySubscriptXSize value=\"665\"/>\n");
+    out->writeText("    <ySubscriptYSize value=\"716\"/>\n");
+    out->writeText("    <ySubscriptXOffset value=\"0\"/>\n");
+    out->writeText("    <ySubscriptYOffset value=\"143\"/>\n");
+    out->writeText("    <ySuperscriptXSize value=\"665\"/>\n");
+    out->writeText("    <ySuperscriptYSize value=\"716\"/>\n");
+    out->writeText("    <ySuperscriptXOffset value=\"0\"/>\n");
+    out->writeText("    <ySuperscriptYOffset value=\"491\"/>\n");
+    out->writeText("    <yStrikeoutSize value=\"");
+    out->writeScalarAsText(fFontMetrics.fStrikeoutThickness);
+    out->writeText("\"/>\n");
+    out->writeText("    <yStrikeoutPosition value=\"");
+    out->writeScalarAsText(-fFontMetrics.fStrikeoutPosition);
+    out->writeText("\"/>\n");
+    out->writeText("    <sFamilyClass value=\"0\"/>\n");
+    out->writeText("    <panose>\n");
+    out->writeText("      <bFamilyType value=\"0\"/>\n");
+    out->writeText("      <bSerifStyle value=\"0\"/>\n");
+    out->writeText("      <bWeight value=\"0\"/>\n");
+    out->writeText("      <bProportion value=\"0\"/>\n");
+    out->writeText("      <bContrast value=\"0\"/>\n");
+    out->writeText("      <bStrokeVariation value=\"0\"/>\n");
+    out->writeText("      <bArmStyle value=\"0\"/>\n");
+    out->writeText("      <bLetterForm value=\"0\"/>\n");
+    out->writeText("      <bMidline value=\"0\"/>\n");
+    out->writeText("      <bXHeight value=\"0\"/>\n");
+    out->writeText("    </panose>\n");
+    out->writeText("    <ulUnicodeRange1 value=\"00000000 00000000 00000000 00000001\"/>\n");
+    out->writeText("    <ulUnicodeRange2 value=\"00010000 00000000 00000000 00000000\"/>\n");
+    out->writeText("    <ulUnicodeRange3 value=\"00000000 00000000 00000000 00000000\"/>\n");
+    out->writeText("    <ulUnicodeRange4 value=\"00000000 00000000 00000000 00000000\"/>\n");
+    out->writeText("    <achVendID value=\"Skia\"/>\n");
+    char fsSelection[16] = {
+            '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
+    fsSelection[0xF - 0x7] = '1';  // Use typo metrics
+    if (this->fontStyle().weight() >= SkFontStyle::Bold().weight()) {
+        fsSelection[0xF - 0x5] = '1';  // Bold
+    }
+    switch (this->fontStyle().slant()) {
+        case SkFontStyle::kUpright_Slant:
+            if (this->fontStyle().weight() < SkFontStyle::Bold().weight()) {
+                fsSelection[0xF - 0x6] = '1';  // Not bold or italic, is regular
+            }
+            break;
+        case SkFontStyle::kItalic_Slant:
+            fsSelection[0xF - 0x0] = '1';  // Italic
+            break;
+        case SkFontStyle::kOblique_Slant:
+            fsSelection[0xF - 0x0] = '1';  // Italic
+            fsSelection[0xF - 0x9] = '1';  // Oblique
+            break;
+        default: SK_ABORT("Unknown slant.");
+    }
+    out->writeText("    <fsSelection value=\"");
+    out->write(fsSelection, 8);
+    out->writeText(" ");
+    out->write(fsSelection + 8, 8);
+    out->writeText("\"/>\n");
+    out->writeText("    <usFirstCharIndex value=\"0\"/>\n");
+    out->writeText("    <usLastCharIndex value=\"0\"/>\n");
+    out->writeText("    <sTypoAscender value=\"");
+    out->writeScalarAsText(-fFontMetrics.fAscent);
+    out->writeText("\"/>\n");
+    out->writeText("    <sTypoDescender value=\"");
+    out->writeScalarAsText(-fFontMetrics.fDescent);
+    out->writeText("\"/>\n");
+    out->writeText("    <sTypoLineGap value=\"");
+    out->writeScalarAsText(fFontMetrics.fLeading);
+    out->writeText("\"/>\n");
+    out->writeText("    <usWinAscent value=\"");
+    out->writeScalarAsText(-fFontMetrics.fAscent);
+    out->writeText("\"/>\n");
+    out->writeText("    <usWinDescent value=\"");
+    out->writeScalarAsText(fFontMetrics.fDescent);
+    out->writeText("\"/>\n");
+    out->writeText("    <ulCodePageRange1 value=\"00000000 00000000 00000000 00000000\"/>\n");
+    out->writeText("    <ulCodePageRange2 value=\"00000000 00000000 00000000 00000000\"/>\n");
+    out->writeText("    <sxHeight value=\"");
+    out->writeScalarAsText(fFontMetrics.fXHeight);
+    out->writeText("\"/>\n");
+    out->writeText("    <sCapHeight value=\"");
+    out->writeScalarAsText(fFontMetrics.fCapHeight);
+    out->writeText("\"/>\n");
+    out->writeText("    <usDefaultChar value=\"0\"/>\n");
+    out->writeText("    <usBreakChar value=\"32\"/>\n");
+    out->writeText("    <usMaxContext value=\"0\"/>\n");
+    out->writeText("  </OS_2>\n");
+
+    out->writeText("  <hmtx>\n");
+    for (int i = 0; i < fGlyphCount; ++i) {
+        out->writeText("    <mtx name=\"glyf");
+        out->writeHexAsText(i, 4);
+        out->writeText("\" width=\"");
+        out->writeDecAsText(fGlyphs[i].fAdvance);
+        out->writeText("\" lsb=\"");
+        int lsb = fGlyphs[i].fOrigin.fX;
+        if (glyfInfo) {
+            lsb += (*glyfInfo)[i].fBounds.fLeft;
+        }
+        out->writeDecAsText(lsb);
+        out->writeText("\"/>\n");
+    }
+    if (glyfInfo) {
+        for (int i = 0; i < fGlyphCount; ++i) {
+            for (int j = 0; j < (*glyfInfo)[i].fLayers.count(); ++j) {
+                out->writeText("    <mtx name=\"glyf");
+                out->writeHexAsText(i, 4);
+                out->writeText("l");
+                out->writeHexAsText(j, 4);
+                out->writeText("\" width=\"");
+                out->writeDecAsText(fGlyphs[i].fAdvance);
+                out->writeText("\" lsb=\"");
+                int32_t lsb = fGlyphs[i].fOrigin.fX + (*glyfInfo)[i].fLayers[j].fBounds.fLeft;
+                out->writeDecAsText(lsb);
+                out->writeText("\"/>\n");
+            }
+        }
+    }
+    out->writeText("  </hmtx>\n");
+
+    bool hasNonBMP = false;
+    out->writeText("  <cmap>\n");
+    out->writeText("    <tableVersion version=\"0\"/>\n");
+    out->writeText("    <cmap_format_4 platformID=\"3\" platEncID=\"1\" language=\"0\">\n");
+    fCMap.foreach ([&out, &hasNonBMP](const SkUnichar& c, const SkGlyphID& g) {
+        if (0xFFFF < c) {
+            hasNonBMP = true;
+            return;
+        }
+        out->writeText("      <map code=\"0x");
+        out->writeHexAsText(c, 4);
+        out->writeText("\" name=\"glyf");
+        out->writeHexAsText(g, 4);
+        out->writeText("\"/>\n");
+    });
+    out->writeText("    </cmap_format_4>\n");
+    if (hasNonBMP) {
+        out->writeText(
+                "    <cmap_format_12 platformID=\"3\" platEncID=\"10\" format=\"12\" "
+                "reserved=\"0\" length=\"1\" language=\"0\" nGroups=\"0\">\n");
+        fCMap.foreach ([&out](const SkUnichar& c, const SkGlyphID& g) {
+            out->writeText("      <map code=\"0x");
+            out->writeHexAsText(c, 6);
+            out->writeText("\" name=\"glyf");
+            out->writeHexAsText(g, 4);
+            out->writeText("\"/>\n");
+        });
+        out->writeText("    </cmap_format_12>\n");
+    }
+    out->writeText("  </cmap>\n");
+
+    out->writeText("  <name>\n");
+    out->writeText(
+            "    <namerecord nameID=\"1\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
+    out->writeText("      ");
+    out->writeText(fName.c_str());
+    out->writeText(" ");
+    out->writeText(type);
+    out->writeText("\n");
+    out->writeText("    </namerecord>\n");
+    out->writeText(
+            "    <namerecord nameID=\"2\" platformID=\"3\" platEncID=\"1\" langID=\"0x409\">\n");
+    out->writeText("      Regular\n");
+    out->writeText("    </namerecord>\n");
+    out->writeText("  </name>\n");
+
+    out->writeText("  <post>\n");
+    out->writeText("    <formatType value=\"3.0\"/>\n");
+    out->writeText("    <italicAngle value=\"0.0\"/>\n");
+    out->writeText("    <underlinePosition value=\"");
+    out->writeScalarAsText(fFontMetrics.fUnderlinePosition);
+    out->writeText("\"/>\n");
+    out->writeText("    <underlineThickness value=\"");
+    out->writeScalarAsText(fFontMetrics.fUnderlineThickness);
+    out->writeText("\"/>\n");
+    out->writeText("    <isFixedPitch value=\"0\"/>\n");
+    out->writeText("    <minMemType42 value=\"0\"/>\n");
+    out->writeText("    <maxMemType42 value=\"0\"/>\n");
+    out->writeText("    <minMemType1 value=\"0\"/>\n");
+    out->writeText("    <maxMemType1 value=\"0\"/>\n");
+    out->writeText("  </post>\n");
+}
+
+void TestSVGTypeface::exportTtxCbdt(SkWStream* out, SkSpan<unsigned> strikeSizes) const {
+    SkPaint paint;
+    SkFont  font;
+    font.setTypeface(sk_ref_sp(const_cast<TestSVGTypeface*>(this)));
+    SkString name;
+    this->getFamilyName(&name);
+
+    // The CBDT/CBLC format is quite restrictive. Only write strikes which fully fit.
+    SkSTArray<8, int> goodStrikeSizes;
+    for (size_t strikeIndex = 0; strikeIndex < strikeSizes.size(); ++strikeIndex) {
+        font.setSize(strikeSizes[strikeIndex]);
+
+        // CBLC limits
+        SkFontMetrics fm;
+        font.getMetrics(&fm);
+        if (!SkTFitsIn<int8_t>((int)(-fm.fTop)) || !SkTFitsIn<int8_t>((int)(-fm.fBottom)) ||
+            !SkTFitsIn<uint8_t>((int)(fm.fXMax - fm.fXMin))) {
+            SkDebugf("Metrics too big cbdt font size %f for %s.\n", font.getSize(), name.c_str());
+            continue;
+        }
+
+        // CBDT limits
+        auto exceedsCbdtLimits = [&]() {
+            for (int i = 0; i < fGlyphCount; ++i) {
+                SkGlyphID gid = i;
+                SkScalar  advance;
+                SkRect    bounds;
+                font.getWidthsBounds(&gid, 1, &advance, &bounds, nullptr);
+                SkIRect ibounds = bounds.roundOut();
+                if (!SkTFitsIn<int8_t>(ibounds.fLeft) || !SkTFitsIn<int8_t>(ibounds.fTop) ||
+                    !SkTFitsIn<uint8_t>(ibounds.width()) || !SkTFitsIn<uint8_t>(ibounds.height()) ||
+                    !SkTFitsIn<uint8_t>((int)advance)) {
+                    return true;
+                }
+            }
+            return false;
+        };
+        if (exceedsCbdtLimits()) {
+            SkDebugf("Glyphs too big cbdt font size %f for %s.\n", font.getSize(), name.c_str());
+            continue;
+        }
+
+        goodStrikeSizes.emplace_back(strikeSizes[strikeIndex]);
+    }
+
+    if (goodStrikeSizes.empty()) {
+        SkDebugf("No strike size fit for cbdt font for %s.\n", name.c_str());
+        return;
+    }
+
+    out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
+    this->exportTtxCommon(out, "CBDT");
+
+    out->writeText("  <CBDT>\n");
+    out->writeText("    <header version=\"2.0\"/>\n");
+    for (size_t strikeIndex = 0; strikeIndex < goodStrikeSizes.size(); ++strikeIndex) {
+        font.setSize(goodStrikeSizes[strikeIndex]);
+
+        out->writeText("    <strikedata index=\"");
+        out->writeDecAsText(strikeIndex);
+        out->writeText("\">\n");
+        for (int i = 0; i < fGlyphCount; ++i) {
+            SkGlyphID gid = i;
+            SkScalar  advance;
+            SkRect    bounds;
+            font.getWidthsBounds(&gid, 1, &advance, &bounds, nullptr);
+            SkIRect ibounds = bounds.roundOut();
+            if (ibounds.isEmpty()) {
+                continue;
+            }
+            SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height());
+            sk_sp<SkSurface> surface(SkSurface::MakeRaster(image_info));
+            SkASSERT(surface);
+            SkCanvas* canvas = surface->getCanvas();
+            canvas->clear(0);
+            SkPixmap pix;
+            surface->peekPixels(&pix);
+            canvas->drawSimpleText(&gid,
+                                   sizeof(gid),
+                                   SkTextEncoding::kGlyphID,
+                                   -bounds.fLeft,
+                                   -bounds.fTop,
+                                   font,
+                                   paint);
+            surface->flush();
+            sk_sp<SkImage> image = surface->makeImageSnapshot();
+            sk_sp<SkData>  data  = image->encodeToData(SkEncodedImageFormat::kPNG, 100);
+
+            out->writeText("      <cbdt_bitmap_format_17 name=\"glyf");
+            out->writeHexAsText(i, 4);
+            out->writeText("\">\n");
+            out->writeText("        <SmallGlyphMetrics>\n");
+            out->writeText("          <height value=\"");
+            out->writeDecAsText(image->height());
+            out->writeText("\"/>\n");
+            out->writeText("          <width value=\"");
+            out->writeDecAsText(image->width());
+            out->writeText("\"/>\n");
+            out->writeText("          <BearingX value=\"");
+            out->writeDecAsText(ibounds.fLeft);
+            out->writeText("\"/>\n");
+            out->writeText("          <BearingY value=\"");
+            out->writeDecAsText(-ibounds.fTop);
+            out->writeText("\"/>\n");
+            out->writeText("          <Advance value=\"");
+            out->writeDecAsText((int)advance);
+            out->writeText("\"/>\n");
+            out->writeText("        </SmallGlyphMetrics>\n");
+            out->writeText("        <rawimagedata>");
+            uint8_t const* bytes = data->bytes();
+            for (size_t i = 0; i < data->size(); ++i) {
+                if ((i % 0x10) == 0x0) {
+                    out->writeText("\n          ");
+                } else if (((i - 1) % 0x4) == 0x3) {
+                    out->writeText(" ");
+                }
+                out->writeHexAsText(bytes[i], 2);
+            }
+            out->writeText("\n");
+            out->writeText("        </rawimagedata>\n");
+            out->writeText("      </cbdt_bitmap_format_17>\n");
+        }
+        out->writeText("    </strikedata>\n");
+    }
+    out->writeText("  </CBDT>\n");
+
+    SkFontMetrics fm;
+    out->writeText("  <CBLC>\n");
+    out->writeText("    <header version=\"2.0\"/>\n");
+    for (size_t strikeIndex = 0; strikeIndex < goodStrikeSizes.size(); ++strikeIndex) {
+        font.setSize(goodStrikeSizes[strikeIndex]);
+        font.getMetrics(&fm);
+        out->writeText("    <strike index=\"");
+        out->writeDecAsText(strikeIndex);
+        out->writeText("\">\n");
+        out->writeText("      <bitmapSizeTable>\n");
+        out->writeText("        <sbitLineMetrics direction=\"hori\">\n");
+        out->writeText("          <ascender value=\"");
+        out->writeDecAsText((int)(-fm.fTop));
+        out->writeText("\"/>\n");
+        out->writeText("          <descender value=\"");
+        out->writeDecAsText((int)(-fm.fBottom));
+        out->writeText("\"/>\n");
+        out->writeText("          <widthMax value=\"");
+        out->writeDecAsText((int)(fm.fXMax - fm.fXMin));
+        out->writeText("\"/>\n");
+        out->writeText("          <caretSlopeNumerator value=\"0\"/>\n");
+        out->writeText("          <caretSlopeDenominator value=\"0\"/>\n");
+        out->writeText("          <caretOffset value=\"0\"/>\n");
+        out->writeText("          <minOriginSB value=\"0\"/>\n");
+        out->writeText("          <minAdvanceSB value=\"0\"/>\n");
+        out->writeText("          <maxBeforeBL value=\"0\"/>\n");
+        out->writeText("          <minAfterBL value=\"0\"/>\n");
+        out->writeText("          <pad1 value=\"0\"/>\n");
+        out->writeText("          <pad2 value=\"0\"/>\n");
+        out->writeText("        </sbitLineMetrics>\n");
+        out->writeText("        <sbitLineMetrics direction=\"vert\">\n");
+        out->writeText("          <ascender value=\"");
+        out->writeDecAsText((int)(-fm.fTop));
+        out->writeText("\"/>\n");
+        out->writeText("          <descender value=\"");
+        out->writeDecAsText((int)(-fm.fBottom));
+        out->writeText("\"/>\n");
+        out->writeText("          <widthMax value=\"");
+        out->writeDecAsText((int)(fm.fXMax - fm.fXMin));
+        out->writeText("\"/>\n");
+        out->writeText("          <caretSlopeNumerator value=\"0\"/>\n");
+        out->writeText("          <caretSlopeDenominator value=\"0\"/>\n");
+        out->writeText("          <caretOffset value=\"0\"/>\n");
+        out->writeText("          <minOriginSB value=\"0\"/>\n");
+        out->writeText("          <minAdvanceSB value=\"0\"/>\n");
+        out->writeText("          <maxBeforeBL value=\"0\"/>\n");
+        out->writeText("          <minAfterBL value=\"0\"/>\n");
+        out->writeText("          <pad1 value=\"0\"/>\n");
+        out->writeText("          <pad2 value=\"0\"/>\n");
+        out->writeText("        </sbitLineMetrics>\n");
+        out->writeText("        <colorRef value=\"0\"/>\n");
+        out->writeText("        <startGlyphIndex value=\"1\"/>\n");
+        out->writeText("        <endGlyphIndex value=\"1\"/>\n");
+        out->writeText("        <ppemX value=\"");
+        out->writeDecAsText(goodStrikeSizes[strikeIndex]);
+        out->writeText("\"/>\n");
+        out->writeText("        <ppemY value=\"");
+        out->writeDecAsText(goodStrikeSizes[strikeIndex]);
+        out->writeText("\"/>\n");
+        out->writeText("        <bitDepth value=\"32\"/>\n");
+        out->writeText("        <flags value=\"1\"/>\n");
+        out->writeText("      </bitmapSizeTable>\n");
+        out->writeText(
+                "      <eblc_index_sub_table_1 imageFormat=\"17\" firstGlyphIndex=\"1\" "
+                "lastGlyphIndex=\"1\">\n");
+        for (int i = 0; i < fGlyphCount; ++i) {
+            SkGlyphID gid = i;
+            SkRect    bounds;
+            font.getBounds(&gid, 1, &bounds, nullptr);
+            if (bounds.isEmpty()) {
+                continue;
+            }
+            out->writeText("        <glyphLoc name=\"glyf");
+            out->writeHexAsText(i, 4);
+            out->writeText("\"/>\n");
+        }
+        out->writeText("      </eblc_index_sub_table_1>\n");
+        out->writeText("    </strike>\n");
+    }
+    out->writeText("  </CBLC>\n");
+
+    out->writeText("</ttFont>\n");
+}
+
+/**
+ * UnitsPerEm is generally 1000 here. Versions of macOS older than 10.13
+ * have problems in CoreText determining the glyph bounds of bitmap glyphs
+ * with unitsPerEm set to 1024 or numbers not divisible by 100 when the
+ * contour is not closed. The bounds of sbix fonts on macOS appear to be those
+ * of the outline in the 'glyf' table. If this countour is closed it will be
+ * drawn, as the 'glyf' outline is to be drawn on top of any bitmap. (There is
+ * a bit which is supposed to control this, but it cannot be relied on.) So
+ * make the glyph contour a degenerate line with points at the edge of the
+ * bounding box of the glyph.
+ */
+void TestSVGTypeface::exportTtxSbix(SkWStream* out, SkSpan<unsigned> strikeSizes) const {
+    out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
+    this->exportTtxCommon(out, "sbix");
+
+    SkPaint paint;
+    SkFont  font;
+    font.setTypeface(sk_ref_sp(const_cast<TestSVGTypeface*>(this)));
+
+    out->writeText("  <glyf>\n");
+    for (int i = 0; i < fGlyphCount; ++i) {
+        const TestSVGTypeface::Glyph& glyphData = this->fGlyphs[i];
+
+        SkSize containerSize = glyphData.size();
+        SkRect  bounds  = SkRect::MakeXYWH(glyphData.fOrigin.fX,
+                                         -glyphData.fOrigin.fY,
+                                         containerSize.fWidth,
+                                         containerSize.fHeight);
+        SkIRect ibounds = bounds.roundOut();
+        out->writeText("    <TTGlyph name=\"glyf");
+        out->writeHexAsText(i, 4);
+        out->writeText("\" xMin=\"");
+        out->writeDecAsText(ibounds.fLeft);
+        out->writeText("\" yMin=\"");
+        out->writeDecAsText(-ibounds.fBottom);
+        out->writeText("\" xMax=\"");
+        out->writeDecAsText(ibounds.fRight);
+        out->writeText("\" yMax=\"");
+        out->writeDecAsText(-ibounds.fTop);
+        out->writeText("\">\n");
+        out->writeText("      <contour>\n");
+        out->writeText("        <pt x=\"");
+        out->writeDecAsText(ibounds.fLeft);
+        out->writeText("\" y=\"");
+        out->writeDecAsText(-ibounds.fBottom);
+        out->writeText("\" on=\"1\"/>\n");
+        out->writeText("      </contour>\n");
+        out->writeText("      <contour>\n");
+        out->writeText("        <pt x=\"");
+        out->writeDecAsText(ibounds.fRight);
+        out->writeText("\" y=\"");
+        out->writeDecAsText(-ibounds.fTop);
+        out->writeText("\" on=\"1\"/>\n");
+        out->writeText("      </contour>\n");
+        out->writeText("      <instructions/>\n");
+        out->writeText("    </TTGlyph>\n");
+    }
+    out->writeText("  </glyf>\n");
+
+    // The loca table will be re-calculated, but if we don't write one we don't get one.
+    out->writeText("  <loca/>\n");
+
+    out->writeText("  <sbix>\n");
+    out->writeText("    <version value=\"1\"/>\n");
+    out->writeText("    <flags value=\"00000000 00000001\"/>\n");
+    for (size_t strikeIndex = 0; strikeIndex < strikeSizes.size(); ++strikeIndex) {
+        font.setSize(strikeSizes[strikeIndex]);
+        out->writeText("    <strike>\n");
+        out->writeText("      <ppem value=\"");
+        out->writeDecAsText(strikeSizes[strikeIndex]);
+        out->writeText("\"/>\n");
+        out->writeText("      <resolution value=\"72\"/>\n");
+        for (int i = 0; i < fGlyphCount; ++i) {
+            SkGlyphID gid = i;
+            SkScalar  advance;
+            SkRect    bounds;
+            font.getWidthsBounds(&gid, 1, &advance, &bounds, nullptr);
+            SkIRect ibounds = bounds.roundOut();
+            if (ibounds.isEmpty()) {
+                continue;
+            }
+            SkImageInfo image_info = SkImageInfo::MakeN32Premul(ibounds.width(), ibounds.height());
+            sk_sp<SkSurface> surface(SkSurface::MakeRaster(image_info));
+            SkASSERT(surface);
+            SkCanvas* canvas = surface->getCanvas();
+            canvas->clear(0);
+            SkPixmap pix;
+            surface->peekPixels(&pix);
+            canvas->drawSimpleText(&gid,
+                                   sizeof(gid),
+                                   SkTextEncoding::kGlyphID,
+                                   -bounds.fLeft,
+                                   -bounds.fTop,
+                                   font,
+                                   paint);
+            surface->flush();
+            sk_sp<SkImage> image = surface->makeImageSnapshot();
+            sk_sp<SkData>  data  = image->encodeToData(SkEncodedImageFormat::kPNG, 100);
+
+            // The originOffset values are difficult to use as DirectWrite and FreeType interpret
+            // the origin to be the initial glyph position on the baseline, but CoreGraphics
+            // interprets the origin to be the lower left of the cbox of the outline in the 'glyf'
+            // table.
+            //#define SK_SBIX_LIKE_FT
+            //#define SK_SBIX_LIKE_DW
+            out->writeText("      <glyph name=\"glyf");
+            out->writeHexAsText(i, 4);
+            out->writeText("\" graphicType=\"png \" originOffsetX=\"");
+#if defined(SK_SBIX_LIKE_FT) || defined(SK_SBIX_LIKE_DW)
+            out->writeDecAsText(bounds.fLeft);
+#else
+            out->writeDecAsText(0);
+#endif
+            // DirectWrite and CoreGraphics use positive values of originOffsetY to push the
+            // image visually up (but from different origins).
+            // FreeType uses positive values to push the image down.
+            out->writeText("\" originOffsetY=\"");
+#if defined(SK_SBIX_LIKE_FT)
+            out->writeScalarAsText(bounds.fBottom);
+#elif defined(SK_SBIX_LIKE_DW)
+            out->writeScalarAsText(-bounds.fBottom);
+#else
+            out->writeDecAsText(0);
+#endif
+            out->writeText("\">\n");
+
+            out->writeText("        <hexdata>");
+            uint8_t const* bytes = data->bytes();
+            for (size_t i = 0; i < data->size(); ++i) {
+                if ((i % 0x10) == 0x0) {
+                    out->writeText("\n          ");
+                } else if (((i - 1) % 0x4) == 0x3) {
+                    out->writeText(" ");
+                }
+                out->writeHexAsText(bytes[i], 2);
+            }
+            out->writeText("\n");
+            out->writeText("        </hexdata>\n");
+            out->writeText("      </glyph>\n");
+        }
+        out->writeText("    </strike>\n");
+    }
+    out->writeText("  </sbix>\n");
+    out->writeText("</ttFont>\n");
+}
+
+namespace {
+
+void convert_noninflect_cubic_to_quads(const SkPoint            p[4],
+                                       SkScalar                 toleranceSqd,
+                                       SkTArray<SkPoint, true>* quads,
+                                       int                      sublevel = 0) {
+    // Notation: Point a is always p[0]. Point b is p[1] unless p[1] == p[0], in which case it is
+    // p[2]. Point d is always p[3]. Point c is p[2] unless p[2] == p[3], in which case it is p[1].
+
+    SkVector ab = p[1] - p[0];
+    SkVector dc = p[2] - p[3];
+
+    if (SkPointPriv::LengthSqd(ab) < SK_ScalarNearlyZero) {
+        if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) {
+            SkPoint* degQuad = quads->push_back_n(3);
+            degQuad[0]       = p[0];
+            degQuad[1]       = p[0];
+            degQuad[2]       = p[3];
+            return;
+        }
+        ab = p[2] - p[0];
+    }
+    if (SkPointPriv::LengthSqd(dc) < SK_ScalarNearlyZero) {
+        dc = p[1] - p[3];
+    }
+
+    static const SkScalar kLengthScale = 3 * SK_Scalar1 / 2;
+    static const int      kMaxSubdivs  = 10;
+
+    ab.scale(kLengthScale);
+    dc.scale(kLengthScale);
+
+    // e0 and e1 are extrapolations along vectors ab and dc.
+    SkVector c0 = p[0];
+    c0 += ab;
+    SkVector c1 = p[3];
+    c1 += dc;
+
+    SkScalar dSqd = sublevel > kMaxSubdivs ? 0 : SkPointPriv::DistanceToSqd(c0, c1);
+    if (dSqd < toleranceSqd) {
+        SkPoint cAvg = c0;
+        cAvg += c1;
+        cAvg.scale(SK_ScalarHalf);
+
+        SkPoint* pts = quads->push_back_n(3);
+        pts[0]       = p[0];
+        pts[1]       = cAvg;
+        pts[2]       = p[3];
+        return;
+    }
+    SkPoint choppedPts[7];
+    SkChopCubicAtHalf(p, choppedPts);
+    convert_noninflect_cubic_to_quads(choppedPts + 0, toleranceSqd, quads, sublevel + 1);
+    convert_noninflect_cubic_to_quads(choppedPts + 3, toleranceSqd, quads, sublevel + 1);
+}
+
+void convertCubicToQuads(const SkPoint p[4], SkScalar tolScale, SkTArray<SkPoint, true>* quads) {
+    if (!p[0].isFinite() || !p[1].isFinite() || !p[2].isFinite() || !p[3].isFinite()) {
+        return;
+    }
+    SkPoint chopped[10];
+    int     count = SkChopCubicAtInflections(p, chopped);
+
+    const SkScalar tolSqd = SkScalarSquare(tolScale);
+
+    for (int i = 0; i < count; ++i) {
+        SkPoint* cubic = chopped + 3 * i;
+        convert_noninflect_cubic_to_quads(cubic, tolSqd, quads);
+    }
+}
+
+void path_to_quads(const SkPath& path, SkPath* quadPath) {
+    quadPath->reset();
+    SkTArray<SkPoint, true> qPts;
+    SkAutoConicToQuads      converter;
+    const SkPoint*          quadPts;
+    SkPath::RawIter         iter(path);
+    uint8_t                 verb;
+    SkPoint                 pts[4];
+    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+        switch (verb) {
+            case SkPath::kMove_Verb: quadPath->moveTo(pts[0].fX, pts[0].fY); break;
+            case SkPath::kLine_Verb: quadPath->lineTo(pts[1].fX, pts[1].fY); break;
+            case SkPath::kQuad_Verb:
+                quadPath->quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+                break;
+            case SkPath::kCubic_Verb:
+                qPts.reset();
+                convertCubicToQuads(pts, SK_Scalar1, &qPts);
+                for (int i = 0; i < qPts.count(); i += 3) {
+                    quadPath->quadTo(
+                            qPts[i + 1].fX, qPts[i + 1].fY, qPts[i + 2].fX, qPts[i + 2].fY);
+                }
+                break;
+            case SkPath::kConic_Verb:
+                quadPts = converter.computeQuads(pts, iter.conicWeight(), SK_Scalar1);
+                for (int i = 0; i < converter.countQuads(); ++i) {
+                    quadPath->quadTo(quadPts[i * 2 + 1].fX,
+                                     quadPts[i * 2 + 1].fY,
+                                     quadPts[i * 2 + 2].fX,
+                                     quadPts[i * 2 + 2].fY);
+                }
+                break;
+            case SkPath::kClose_Verb: quadPath->close(); break;
+            default: SkDEBUGFAIL("bad verb"); return;
+        }
+    }
+}
+
+class SkCOLRCanvas : public SkNoDrawCanvas {
+public:
+    SkCOLRCanvas(SkRect                     glyphBounds,
+                 const TestSVGTypeface&     typeface,
+                 SkGlyphID                  glyphId,
+                 TestSVGTypeface::GlyfInfo* glyf,
+                 SkTHashMap<SkColor, int>*  colors,
+                 SkWStream*                 out)
+            : SkNoDrawCanvas(glyphBounds.roundOut().width(), glyphBounds.roundOut().height())
+            , fBaselineOffset(glyphBounds.top())
+            , fTypeface(typeface)
+            , fGlyphId(glyphId)
+            , fGlyf(glyf)
+            , fColors(colors)
+            , fOut(out)
+            , fLayerId(0) {}
+
+    void writePoint(SkScalar x, SkScalar y, bool on) {
+        fOut->writeText("        <pt x=\"");
+        fOut->writeDecAsText(SkScalarRoundToInt(x));
+        fOut->writeText("\" y=\"");
+        fOut->writeDecAsText(SkScalarRoundToInt(y));
+        fOut->writeText("\" on=\"");
+        fOut->write8(on ? '1' : '0');
+        fOut->writeText("\"/>\n");
+    }
+    SkIRect writePath(const SkPath& path, bool layer) {
+        // Convert to quads.
+        SkPath quads;
+        path_to_quads(path, &quads);
+
+        SkRect  bounds  = quads.computeTightBounds();
+        SkIRect ibounds = bounds.roundOut();
+        // The bounds will be re-calculated anyway.
+        fOut->writeText("    <TTGlyph name=\"glyf");
+        fOut->writeHexAsText(fGlyphId, 4);
+        if (layer) {
+            fOut->writeText("l");
+            fOut->writeHexAsText(fLayerId, 4);
+        }
+        fOut->writeText("\" xMin=\"");
+        fOut->writeDecAsText(ibounds.fLeft);
+        fOut->writeText("\" yMin=\"");
+        fOut->writeDecAsText(ibounds.fTop);
+        fOut->writeText("\" xMax=\"");
+        fOut->writeDecAsText(ibounds.fRight);
+        fOut->writeText("\" yMax=\"");
+        fOut->writeDecAsText(ibounds.fBottom);
+        fOut->writeText("\">\n");
+
+        SkPath::RawIter iter(quads);
+        uint8_t         verb;
+        SkPoint         pts[4];
+        bool            contourOpen = false;
+        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+            switch (verb) {
+                case SkPath::kMove_Verb:
+                    if (contourOpen) {
+                        fOut->writeText("      </contour>\n");
+                        contourOpen = false;
+                    }
+                    break;
+                case SkPath::kLine_Verb:
+                    if (!contourOpen) {
+                        fOut->writeText("      <contour>\n");
+                        this->writePoint(pts[0].fX, pts[0].fY, true);
+                        contourOpen = true;
+                    }
+                    this->writePoint(pts[1].fX, pts[1].fY, true);
+                    break;
+                case SkPath::kQuad_Verb:
+                    if (!contourOpen) {
+                        fOut->writeText("      <contour>\n");
+                        this->writePoint(pts[0].fX, pts[0].fY, true);
+                        contourOpen = true;
+                    }
+                    this->writePoint(pts[1].fX, pts[1].fY, false);
+                    this->writePoint(pts[2].fX, pts[2].fY, true);
+                    break;
+                case SkPath::kClose_Verb:
+                    if (contourOpen) {
+                        fOut->writeText("      </contour>\n");
+                        contourOpen = false;
+                    }
+                    break;
+                default: SkDEBUGFAIL("bad verb"); return ibounds;
+            }
+        }
+        if (contourOpen) {
+            fOut->writeText("      </contour>\n");
+        }
+
+        // Required to write out an instructions tag.
+        fOut->writeText("      <instructions/>\n");
+        fOut->writeText("    </TTGlyph>\n");
+        return ibounds;
+    }
+
+    void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+        SkPath path;
+        path.addRect(rect);
+        this->drawPath(path, paint);
+    }
+
+    void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
+        SkPath path;
+        path.addOval(oval);
+        this->drawPath(path, paint);
+    }
+
+    void onDrawArc(const SkRect&  oval,
+                   SkScalar       startAngle,
+                   SkScalar       sweepAngle,
+                   bool           useCenter,
+                   const SkPaint& paint) override {
+        SkPath path;
+        bool fillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect();
+        SkPathPriv::CreateDrawArcPath(
+                &path, oval, startAngle, sweepAngle, useCenter, fillNoPathEffect);
+        this->drawPath(path, paint);
+    }
+
+    void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
+        SkPath path;
+        path.addRRect(rrect);
+        this->drawPath(path, paint);
+    }
+
+    void onDrawPath(const SkPath& platonicPath, const SkPaint& originalPaint) override {
+        SkPaint paint = originalPaint;
+        SkPath  path  = platonicPath;
+
+        // Apply the path effect.
+        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
+            bool fill = paint.getFillPath(path, &path);
+
+            paint.setPathEffect(nullptr);
+            if (fill) {
+                paint.setStyle(SkPaint::kFill_Style);
+            } else {
+                paint.setStyle(SkPaint::kStroke_Style);
+                paint.setStrokeWidth(0);
+            }
+        }
+
+        // Apply the matrix.
+        SkMatrix m = this->getTotalMatrix();
+        // If done to the canvas then everything would get clipped out.
+        m.postTranslate(0, fBaselineOffset);  // put the baseline at 0
+        m.postScale(1, -1);                   // and flip it since OpenType is y-up.
+        path.transform(m);
+
+        // While creating the default glyf, union with dark colors and intersect with bright colors.
+        SkColor  color = paint.getColor();
+        SkPathOp op;
+        if (fTypeface.getPathOp(color, &op)) {
+            fBasePath.add(path, op);
+        }
+        SkIRect bounds = this->writePath(path, true);
+
+        // The CPAL table has the concept of a 'current color' which is index 0xFFFF.
+        // Mark any layer drawn in 'currentColor' as having this special index.
+        // The value of 'currentColor' here should a color which causes this layer to union into the
+        // default glyf.
+        constexpr SkColor currentColor = 0xFF2B0000;
+
+        int colorIndex;
+        if (color == currentColor) {
+            colorIndex = 0xFFFF;
+        } else {
+            int* colorIndexPtr = fColors->find(color);
+            if (colorIndexPtr) {
+                colorIndex = *colorIndexPtr;
+            } else {
+                colorIndex = fColors->count();
+                fColors->set(color, colorIndex);
+            }
+        }
+        fGlyf->fLayers.emplace_back(colorIndex, bounds);
+
+        ++fLayerId;
+    }
+
+    void finishGlyph() {
+        SkPath baseGlyph;
+        fBasePath.resolve(&baseGlyph);
+        fGlyf->fBounds = this->writePath(baseGlyph, false);
+    }
+
+private:
+    SkScalar                   fBaselineOffset;
+    const TestSVGTypeface&     fTypeface;
+    SkGlyphID                  fGlyphId;
+    TestSVGTypeface::GlyfInfo* fGlyf;
+    SkTHashMap<SkColor, int>*  fColors;
+    SkWStream* const           fOut;
+    SkOpBuilder                fBasePath;
+    int                        fLayerId;
+};
+
+}  // namespace
+
+void TestSVGTypeface::exportTtxColr(SkWStream* out) const {
+    out->writeText("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    out->writeText("<ttFont sfntVersion=\"\\x00\\x01\\x00\\x00\" ttLibVersion=\"3.19\">\n");
+
+    SkTHashMap<SkColor, int> colors;
+    SkTArray<GlyfInfo>       glyfInfos(fGlyphCount);
+
+    // Need to know all the glyphs up front for the common tables.
+    SkDynamicMemoryWStream glyfOut;
+    glyfOut.writeText("  <glyf>\n");
+    for (int i = 0; i < fGlyphCount; ++i) {
+        const TestSVGTypeface::Glyph& glyphData = this->fGlyphs[i];
+
+        SkSize containerSize = glyphData.size();
+        SkRect       bounds = SkRect::MakeXYWH(glyphData.fOrigin.fX,
+                                         -glyphData.fOrigin.fY,
+                                         containerSize.fWidth,
+                                         containerSize.fHeight);
+        SkCOLRCanvas canvas(bounds, *this, i, &glyfInfos.emplace_back(), &colors, &glyfOut);
+        glyphData.render(&canvas);
+        canvas.finishGlyph();
+    }
+    glyfOut.writeText("  </glyf>\n");
+
+    this->exportTtxCommon(out, "COLR", &glyfInfos);
+
+    // The loca table will be re-calculated, but if we don't write one we don't get one.
+    out->writeText("  <loca/>\n");
+
+    std::unique_ptr<SkStreamAsset> glyfStream = glyfOut.detachAsStream();
+    out->writeStream(glyfStream.get(), glyfStream->getLength());
+
+    out->writeText("  <COLR>\n");
+    out->writeText("    <version value=\"0\"/>\n");
+    for (int i = 0; i < fGlyphCount; ++i) {
+        if (glyfInfos[i].fLayers.empty()) {
+            continue;
+        }
+        if (glyfInfos[i].fBounds.isEmpty()) {
+            SkDebugf("Glyph %d is empty but has layers.\n", i);
+        }
+        out->writeText("    <ColorGlyph name=\"glyf");
+        out->writeHexAsText(i, 4);
+        out->writeText("\">\n");
+        for (int j = 0; j < glyfInfos[i].fLayers.count(); ++j) {
+            const int colorIndex = glyfInfos[i].fLayers[j].fLayerColorIndex;
+            out->writeText("      <layer colorID=\"");
+            out->writeDecAsText(colorIndex);
+            out->writeText("\" name=\"glyf");
+            out->writeHexAsText(i, 4);
+            out->writeText("l");
+            out->writeHexAsText(j, 4);
+            out->writeText("\"/>\n");
+        }
+        out->writeText("    </ColorGlyph>\n");
+    }
+    out->writeText("  </COLR>\n");
+
+    // The colors must be written in order, the 'index' is ignored by ttx.
+    SkAutoTMalloc<SkColor> colorsInOrder(colors.count());
+    colors.foreach ([&colorsInOrder](const SkColor& c, const int* i) { colorsInOrder[*i] = c; });
+    out->writeText("  <CPAL>\n");
+    out->writeText("    <version value=\"0\"/>\n");
+    out->writeText("    <numPaletteEntries value=\"");
+    out->writeDecAsText(colors.count());
+    out->writeText("\"/>\n");
+    out->writeText("    <palette index=\"0\">\n");
+    for (int i = 0; i < colors.count(); ++i) {
+        SkColor c = colorsInOrder[i];
+        out->writeText("      <color index=\"");
+        out->writeDecAsText(i);
+        out->writeText("\" value=\"#");
+        out->writeHexAsText(SkColorGetR(c), 2);
+        out->writeHexAsText(SkColorGetG(c), 2);
+        out->writeHexAsText(SkColorGetB(c), 2);
+        out->writeHexAsText(SkColorGetA(c), 2);
+        out->writeText("\"/>\n");
+    }
+    out->writeText("    </palette>\n");
+    out->writeText("  </CPAL>\n");
+
+    out->writeText("</ttFont>\n");
+}
+#endif  // SK_XML
diff --git a/src/third_party/skia/tools/fonts/TestSVGTypeface.h b/src/third_party/skia/tools/fonts/TestSVGTypeface.h
new file mode 100644
index 0000000..44d3af2
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestSVGTypeface.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TestSVGTypeface_DEFINED
+#define TestSVGTypeface_DEFINED
+
+#include "include/core/SkFontArguments.h"
+#include "include/core/SkFontMetrics.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkScalar.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkString.h"
+#include "include/core/SkTypeface.h"
+#include "include/core/SkTypes.h"
+#include "include/pathops/SkPathOps.h"
+#include "include/private/SkMutex.h"
+#include "include/private/SkTArray.h"
+#include "include/private/SkTHash.h"
+#include "src/core/SkSpan.h"
+
+#include <memory>
+
+class SkCanvas;
+class SkDescriptor;
+class SkFontDescriptor;
+class SkFontStyle;
+class SkGlyph;
+class SkPath;
+class SkScalerContext;
+class SkSVGDOM;
+class SkWStream;
+struct SkAdvancedTypefaceMetrics;
+struct SkScalerContextEffects;
+struct SkScalerContextRec;
+
+struct SkSVGTestTypefaceGlyphData {
+    const char* fSvgResourcePath;
+    SkPoint     fOrigin;  // y-down
+    SkScalar    fAdvance;
+    SkUnichar   fUnicode;  // TODO: this limits to 1:1
+};
+
+class TestSVGTypeface : public SkTypeface {
+public:
+    TestSVGTypeface(const char*                              name,
+                    int                                      upem,
+                    const SkFontMetrics&                     metrics,
+                    SkSpan<const SkSVGTestTypefaceGlyphData> data,
+                    const SkFontStyle&                       style);
+    ~TestSVGTypeface() override;
+    void getAdvance(SkGlyph* glyph) const;
+    void getFontMetrics(SkFontMetrics* metrics) const;
+
+    static sk_sp<TestSVGTypeface> Default();
+    static sk_sp<TestSVGTypeface> Planets();
+    void                          exportTtxCbdt(SkWStream*, SkSpan<unsigned> strikeSizes) const;
+    void                          exportTtxSbix(SkWStream*, SkSpan<unsigned> strikeSizes) const;
+    void                          exportTtxColr(SkWStream*) const;
+    virtual bool                  getPathOp(SkColor, SkPathOp*) const = 0;
+
+    struct GlyfLayerInfo {
+        GlyfLayerInfo(int layerColorIndex, SkIRect bounds)
+                : fLayerColorIndex(layerColorIndex), fBounds(bounds) {}
+        int     fLayerColorIndex;
+        SkIRect fBounds;
+    };
+    struct GlyfInfo {
+        GlyfInfo() : fBounds(SkIRect::MakeEmpty()) {}
+        SkIRect                 fBounds;
+        SkTArray<GlyfLayerInfo> fLayers;
+    };
+
+protected:
+    void exportTtxCommon(SkWStream*, const char* type, const SkTArray<GlyfInfo>* = nullptr) const;
+
+    SkScalerContext*                           onCreateScalerContext(const SkScalerContextEffects&,
+                                                                     const SkDescriptor* desc) const override;
+    void                                       onFilterRec(SkScalerContextRec* rec) const override;
+    void                                       getGlyphToUnicodeMap(SkUnichar*) const override;
+    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
+
+    std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override { return nullptr; }
+
+    sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
+        return sk_ref_sp(this);
+    }
+
+    void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override;
+
+    void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
+
+    void getPostScriptGlyphNames(SkString*) const override {}
+
+    int onCountGlyphs() const override { return fGlyphCount; }
+
+    int onGetUPEM() const override { return fUpem; }
+
+    void                          onGetFamilyName(SkString* familyName) const override;
+    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
+
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override {
+        return 0;
+    }
+
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override {
+        return 0;
+    }
+
+    int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
+
+    size_t onGetTableData(SkFontTableTag tag,
+                          size_t         offset,
+                          size_t         length,
+                          void*          data) const override {
+        return 0;
+    }
+
+private:
+    struct Glyph {
+        Glyph();
+        ~Glyph();
+        SkPoint     fOrigin;
+        SkScalar    fAdvance;
+        const char* fResourcePath;
+
+        SkSize size() const;
+        void render(SkCanvas*) const;
+
+    private:
+        // Lazily parses the SVG from fResourcePath, and manages mutex locking.
+        template <typename Fn> void withSVG(Fn&&) const;
+
+        // The mutex guards lazy parsing of the SVG, but also predates that.
+        // Must be SkSVGDOM::render() is not thread safe?
+        // If not, an SkOnce is enough here.
+        mutable SkMutex         fSvgMutex;
+        mutable bool            fParsedSvg = false;
+        mutable sk_sp<SkSVGDOM> fSvg;
+    };
+
+    SkString                         fName;
+    int                              fUpem;
+    const SkFontMetrics              fFontMetrics;
+    std::unique_ptr<Glyph[]>         fGlyphs;
+    int                              fGlyphCount;
+    SkTHashMap<SkUnichar, SkGlyphID> fCMap;
+    friend class SkTestSVGScalerContext;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/fonts/TestTypeface.cpp b/src/third_party/skia/tools/fonts/TestTypeface.cpp
new file mode 100644
index 0000000..7f30f01
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestTypeface.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFontMetrics.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkString.h"
+#include "include/private/SkTDArray.h"
+#include "include/private/SkTo.h"
+#include "src/core/SkAdvancedTypefaceMetrics.h"
+#include "src/core/SkFontDescriptor.h"
+#include "src/core/SkFontPriv.h"
+#include "src/core/SkGlyph.h"
+#include "src/core/SkPaintPriv.h"
+#include "src/core/SkScalerContext.h"
+#include "src/core/SkUtils.h"
+#include "src/sfnt/SkOTUtils.h"
+#include "tools/fonts/TestTypeface.h"
+
+#include <utility>
+
+class SkDescriptor;
+
+SkTestFont::SkTestFont(const SkTestFontData& fontData)
+        : INHERITED()
+        , fCharCodes(fontData.fCharCodes)
+        , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0)
+        , fWidths(fontData.fWidths)
+        , fMetrics(fontData.fMetrics)
+        , fName(fontData.fName)
+        , fPaths(nullptr) {
+    init(fontData.fPoints, fontData.fVerbs);
+}
+
+SkTestFont::~SkTestFont() {
+    for (unsigned index = 0; index < fCharCodesCount; ++index) {
+        delete fPaths[index];
+    }
+    delete[] fPaths;
+}
+
+SkGlyphID SkTestFont::glyphForUnichar(SkUnichar charCode) const {
+    for (size_t index = 0; index < fCharCodesCount; ++index) {
+        if (fCharCodes[index] == charCode) {
+            return SkTo<SkGlyphID>(index);
+        }
+    }
+    return 0;
+}
+
+void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) {
+    fPaths = new SkPath*[fCharCodesCount];
+    for (unsigned index = 0; index < fCharCodesCount; ++index) {
+        SkPath*      path = new SkPath;
+        SkPath::Verb verb;
+        while ((verb = (SkPath::Verb)*verbs++) != SkPath::kDone_Verb) {
+            switch (verb) {
+                case SkPath::kMove_Verb:
+                    path->moveTo(pts[0], pts[1]);
+                    pts += 2;
+                    break;
+                case SkPath::kLine_Verb:
+                    path->lineTo(pts[0], pts[1]);
+                    pts += 2;
+                    break;
+                case SkPath::kQuad_Verb:
+                    path->quadTo(pts[0], pts[1], pts[2], pts[3]);
+                    pts += 4;
+                    break;
+                case SkPath::kCubic_Verb:
+                    path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+                    pts += 6;
+                    break;
+                case SkPath::kClose_Verb: path->close(); break;
+                default: SkDEBUGFAIL("bad verb"); return;
+            }
+        }
+        // This should make SkPath::getBounds() queries threadsafe.
+        path->updateBoundsCache();
+        fPaths[index] = path;
+    }
+}
+
+TestTypeface::TestTypeface(sk_sp<SkTestFont> testFont, const SkFontStyle& style)
+        : SkTypeface(style, false), fTestFont(std::move(testFont)) {}
+
+void TestTypeface::getAdvance(SkGlyph* glyph) {
+    SkGlyphID glyphID = glyph->getGlyphID();
+    glyphID           = glyphID < fTestFont->fCharCodesCount ? glyphID : 0;
+
+    // TODO(benjaminwagner): Update users to use floats.
+    glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyphID]);
+    glyph->fAdvanceY = 0;
+}
+
+void TestTypeface::getFontMetrics(SkFontMetrics* metrics) { *metrics = fTestFont->fMetrics; }
+
+void TestTypeface::getPath(SkGlyphID glyphID, SkPath* path) {
+    glyphID = glyphID < fTestFont->fCharCodesCount ? glyphID : 0;
+    *path   = *fTestFont->fPaths[glyphID];
+}
+
+void TestTypeface::onFilterRec(SkScalerContextRec* rec) const {
+    rec->setHinting(SkFontHinting::kNone);
+}
+
+void TestTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
+    unsigned glyphCount = fTestFont->fCharCodesCount;
+    for (unsigned gid = 0; gid < glyphCount; ++gid) {
+        glyphToUnicode[gid] = SkTo<SkUnichar>(fTestFont->fCharCodes[gid]);
+    }
+}
+
+std::unique_ptr<SkAdvancedTypefaceMetrics> TestTypeface::onGetAdvancedMetrics() const {  // pdf only
+    std::unique_ptr<SkAdvancedTypefaceMetrics>info(new SkAdvancedTypefaceMetrics);
+    info->fFontName.set(fTestFont->fName);
+    return info;
+}
+
+void TestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
+    desc->setFamilyName(fTestFont->fName);
+    desc->setStyle(this->fontStyle());
+    *isLocal = false;
+}
+
+void TestTypeface::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
+    for (int i = 0; i < count; ++i) {
+        glyphs[i] = fTestFont->glyphForUnichar(uni[i]);
+    }
+}
+
+void TestTypeface::onGetFamilyName(SkString* familyName) const { *familyName = fTestFont->fName; }
+
+SkTypeface::LocalizedStrings* TestTypeface::onCreateFamilyNameIterator() const {
+    SkString familyName(fTestFont->fName);
+    SkString language("und");  // undetermined
+    return new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
+}
+
+class SkTestScalerContext : public SkScalerContext {
+public:
+    SkTestScalerContext(sk_sp<TestTypeface>           face,
+                        const SkScalerContextEffects& effects,
+                        const SkDescriptor*           desc)
+            : SkScalerContext(std::move(face), effects, desc) {
+        fRec.getSingleMatrix(&fMatrix);
+        this->forceGenerateImageFromPath();
+    }
+
+protected:
+    TestTypeface* getTestTypeface() const {
+        return static_cast<TestTypeface*>(this->getTypeface());
+    }
+
+    unsigned generateGlyphCount() override { return this->getTestTypeface()->onCountGlyphs(); }
+
+    bool generateAdvance(SkGlyph* glyph) override {
+        this->getTestTypeface()->getAdvance(glyph);
+
+        const SkVector advance =
+                fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX), SkFloatToScalar(glyph->fAdvanceY));
+        glyph->fAdvanceX = SkScalarToFloat(advance.fX);
+        glyph->fAdvanceY = SkScalarToFloat(advance.fY);
+        return true;
+    }
+
+    void generateMetrics(SkGlyph* glyph) override {
+        glyph->zeroMetrics();
+        this->generateAdvance(glyph);
+        // Always generates from paths, so SkScalerContext::getMetrics will figure the bounds.
+    }
+
+    void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); }
+
+    bool generatePath(SkGlyphID glyph, SkPath* path) override {
+        this->getTestTypeface()->getPath(glyph, path);
+        path->transform(fMatrix);
+        return true;
+    }
+
+    void generateFontMetrics(SkFontMetrics* metrics) override {
+        this->getTestTypeface()->getFontMetrics(metrics);
+        SkFontPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
+    }
+
+private:
+    SkMatrix fMatrix;
+};
+
+SkScalerContext* TestTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
+                                                     const SkDescriptor*           desc) const {
+    return new SkTestScalerContext(sk_ref_sp(const_cast<TestTypeface*>(this)), effects, desc);
+}
diff --git a/src/third_party/skia/tools/fonts/TestTypeface.h b/src/third_party/skia/tools/fonts/TestTypeface.h
new file mode 100644
index 0000000..0d43d09
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/TestTypeface.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TestTypeface_DEFINED
+#define TestTypeface_DEFINED
+
+#include "include/core/SkFontArguments.h"
+#include "include/core/SkFontMetrics.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkPaint.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkScalar.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTypeface.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkFixed.h"
+
+#include <memory>
+
+class SkDescriptor;
+class SkFontDescriptor;
+class SkGlyph;
+class SkPath;
+class SkScalerContext;
+class SkStreamAsset;
+class SkString;
+class SkTestFont;
+struct SkAdvancedTypefaceMetrics;
+struct SkScalerContextEffects;
+struct SkScalerContextRec;
+
+struct SkTestFontData {
+    const SkScalar*      fPoints;
+    const unsigned char* fVerbs;
+    const SkUnichar*     fCharCodes;
+    const size_t         fCharCodesCount;
+    const SkFixed*       fWidths;
+    const SkFontMetrics& fMetrics;
+    const char*          fName;
+    SkFontStyle          fStyle;
+};
+
+class SkTestFont : public SkRefCnt {
+public:
+    SkTestFont(const SkTestFontData&);
+    virtual ~SkTestFont();
+    SkGlyphID glyphForUnichar(SkUnichar charCode) const;
+    void      init(const SkScalar* pts, const unsigned char* verbs);
+
+private:
+    const SkUnichar*     fCharCodes;
+    const size_t         fCharCodesCount;
+    const SkFixed*       fWidths;
+    const SkFontMetrics& fMetrics;
+    const char*          fName;
+    SkPath**             fPaths;
+    friend class TestTypeface;
+    typedef SkRefCnt INHERITED;
+};
+
+class TestTypeface : public SkTypeface {
+public:
+    TestTypeface(sk_sp<SkTestFont>, const SkFontStyle& style);
+    void getAdvance(SkGlyph* glyph);
+    void getFontMetrics(SkFontMetrics* metrics);
+    void getPath(SkGlyphID glyph, SkPath* path);
+
+protected:
+    SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
+                                           const SkDescriptor* desc) const override;
+    void             onFilterRec(SkScalerContextRec* rec) const override;
+    void             getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const override;
+    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
+
+    std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override { return nullptr; }
+
+    sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override {
+        return sk_ref_sp(this);
+    }
+
+    void onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const override;
+
+    void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
+
+    int onCountGlyphs() const override { return (int)fTestFont->fCharCodesCount; }
+
+    void getPostScriptGlyphNames(SkString*) const override {}
+
+    int onGetUPEM() const override { return 2048; }
+
+    void                          onGetFamilyName(SkString* familyName) const override;
+    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
+
+    int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
+                                     int coordinateCount) const override {
+        return 0;
+    }
+
+    int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
+                                       int parameterCount) const override {
+        return 0;
+    }
+
+    int onGetTableTags(SkFontTableTag tags[]) const override { return 0; }
+
+    size_t onGetTableData(SkFontTableTag tag,
+                          size_t         offset,
+                          size_t         length,
+                          void*          data) const override {
+        return 0;
+    }
+
+private:
+    sk_sp<SkTestFont> fTestFont;
+    friend class SkTestScalerContext;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/fonts/ToolUtilsFont.cpp b/src/third_party/skia/tools/fonts/ToolUtilsFont.cpp
new file mode 100644
index 0000000..ad68785
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/ToolUtilsFont.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/ToolUtils.h"
+
+#include "include/core/SkFontMgr.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkTypeface.h"
+#include "include/private/SkMutex.h"
+#include "src/core/SkOSFile.h"
+#include "src/utils/SkUTF.h"
+#include "tools/Resources.h"
+#include "tools/fonts/TestFontMgr.h"
+
+namespace ToolUtils {
+
+sk_sp<SkTypeface> planet_typeface() {
+    static const sk_sp<SkTypeface> planetTypeface = []() {
+        const char* filename;
+#if defined(SK_BUILD_FOR_WIN)
+        filename = "fonts/planetcolr.ttf";
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
+        filename = "fonts/planetsbix.ttf";
+#else
+        filename = "fonts/planetcbdt.ttf";
+#endif
+        sk_sp<SkTypeface> typeface = MakeResourceAsTypeface(filename);
+        if (typeface) {
+            return typeface;
+        }
+        return SkTypeface::MakeFromName("Planet", SkFontStyle());
+    }();
+    return planetTypeface;
+}
+
+sk_sp<SkTypeface> emoji_typeface() {
+    static const sk_sp<SkTypeface> emojiTypeface = []() {
+        const char* filename;
+#if defined(SK_BUILD_FOR_WIN)
+        filename = "fonts/colr.ttf";
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
+        filename = "fonts/sbix.ttf";
+#else
+        filename = "fonts/cbdt.ttf";
+#endif
+        sk_sp<SkTypeface> typeface = MakeResourceAsTypeface(filename);
+        if (typeface) {
+            return typeface;
+        }
+        return SkTypeface::MakeFromName("Emoji", SkFontStyle());
+    }();
+    return emojiTypeface;
+}
+
+const char* emoji_sample_text() {
+    return "\xF0\x9F\x98\x80"
+           " "
+           "\xE2\x99\xA2";  // 😀 ♢
+}
+static sk_sp<SkTypeface> create_font(const char* name, SkFontStyle style) {
+    static sk_sp<SkFontMgr> portableFontMgr = MakePortableFontMgr();
+    return portableFontMgr->legacyMakeTypeface(name, style);
+}
+
+sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style) {
+    return create_font(name, style);
+}
+}  // namespace ToolUtils
diff --git a/src/third_party/skia/tools/fonts/create_test_font.cpp b/src/third_party/skia/tools/fonts/create_test_font.cpp
new file mode 100644
index 0000000..c303024
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/create_test_font.cpp
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Running create_test_font generates ./tools/fonts/test_font_index.inc
+// and ./tools/fonts/test_font_<generic name>.inc which are read by
+// ./tools/fonts/TestFontMgr.cpp
+
+#include "include/core/SkFont.h"
+#include "include/core/SkFontMetrics.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkPath.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTypeface.h"
+#include "include/private/SkTArray.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkSpan.h"
+#include "src/core/SkTSort.h"
+#include "src/utils/SkOSPath.h"
+#include "src/utils/SkUTF.h"
+
+#include <stdio.h>
+
+namespace {
+
+struct NamedFontStyle {
+    char const * const fName;
+    char const * const fIdentifierName;
+    SkFontStyle const fStyle;
+};
+
+struct FontDesc {
+    NamedFontStyle const fNamedStyle;
+    char const * const fFile;
+};
+
+struct FontFamilyDesc {
+    char const * const fGenericName;
+    char const * const fFamilyName;
+    char const * const fIdentifierName;
+    SkSpan<const FontDesc> const fFonts;
+};
+
+} // namespace
+
+static FILE* font_header(const char* family) {
+    SkString outPath(SkOSPath::Join(".", "tools"));
+    outPath = SkOSPath::Join(outPath.c_str(), "fonts");
+    outPath = SkOSPath::Join(outPath.c_str(), "test_font_");
+    SkString fam(family);
+    do {
+        int dashIndex = fam.find("-");
+        if (dashIndex < 0) {
+            break;
+        }
+        fam.writable_str()[dashIndex] = '_';
+    } while (true);
+    outPath.append(fam);
+    outPath.append(".inc");
+    FILE* out = fopen(outPath.c_str(), "w");
+
+    static const char kHeader[] =
+        "/*\n"
+        " * Copyright 2015 Google Inc.\n"
+        " *\n"
+        " * Use of this source code is governed by a BSD-style license that can be\n"
+        " * found in the LICENSE file.\n"
+        " */\n"
+        "\n"
+        "// Auto-generated by ";
+    fprintf(out, "%s%s\n\n", kHeader, SkOSPath::Basename(__FILE__).c_str());
+    return out;
+}
+
+enum {
+    kMaxLineLength = 80,
+};
+
+static ptrdiff_t last_line_length(const SkString& str) {
+    const char* first = str.c_str();
+    const char* last = first + str.size();
+    const char* ptr = last;
+    while (ptr > first && *--ptr != '\n')
+        ;
+    return last - ptr - 1;
+}
+
+static void output_fixed(SkScalar num, int emSize, SkString* out) {
+    int hex = (int) (num * 65536 / emSize);
+    out->appendf("0x%08x,", hex);
+    *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
+}
+
+static void output_scalar(SkScalar num, int emSize, SkString* out) {
+    num /= emSize;
+    if (num == (int) num) {
+       out->appendS32((int) num);
+    } else {
+        SkString str;
+        str.printf("%1.6g", num);
+        int width = (int) str.size();
+        const char* cStr = str.c_str();
+        while (cStr[width - 1] == '0') {
+            --width;
+        }
+        str.remove(width, str.size() - width);
+        out->appendf("%sf", str.c_str());
+    }
+    *out += ',';
+    *out += (int) last_line_length(*out) >= kMaxLineLength ? '\n' : ' ';
+}
+
+static int output_points(const SkPoint* pts, int emSize, int count, SkString* ptsOut) {
+    for (int index = 0; index < count; ++index) {
+        output_scalar(pts[index].fX, emSize, ptsOut);
+        output_scalar(pts[index].fY, emSize, ptsOut);
+    }
+    return count;
+}
+
+static void output_path_data(const SkFont& font,
+        int emSize, SkString* ptsOut, SkTDArray<SkPath::Verb>* verbs,
+        SkTDArray<unsigned>* charCodes, SkTDArray<SkScalar>* widths) {
+    for (SkUnichar index = 0x00; index < 0x7f; ++index) {
+        uint16_t glyphID = font.unicharToGlyph(index);
+        SkPath path;
+        font.getPath(glyphID, &path);
+        SkPath::RawIter iter(path);
+        SkPath::Verb verb;
+        SkPoint pts[4];
+        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+            *verbs->append() = verb;
+            switch (verb) {
+                case SkPath::kMove_Verb:
+                    output_points(&pts[0], emSize, 1, ptsOut);
+                    break;
+                case SkPath::kLine_Verb:
+                    output_points(&pts[1], emSize, 1, ptsOut);
+                    break;
+                case SkPath::kQuad_Verb:
+                    output_points(&pts[1], emSize, 2, ptsOut);
+                    break;
+                case SkPath::kCubic_Verb:
+                    output_points(&pts[1], emSize, 3, ptsOut);
+                    break;
+                case SkPath::kClose_Verb:
+                    break;
+                default:
+                    SkDEBUGFAIL("bad verb");
+                    SkASSERT(0);
+            }
+        }
+        *verbs->append() = SkPath::kDone_Verb;
+        *charCodes->append() = index;
+        SkScalar width;
+        font.getWidths(&glyphID, 1, &width);
+     // SkASSERT(floor(width) == width);  // not true for Hiragino Maru Gothic Pro
+        *widths->append() = width;
+        if (0 == index) {
+            index = 0x1f;  // skip the rest of the control codes
+        }
+    }
+}
+
+static int offset_str_len(unsigned num) {
+    if (num == (unsigned) -1) {
+        return 10;
+    }
+    unsigned result = 1;
+    unsigned ref = 10;
+    while (ref <= num) {
+        ++result;
+        ref *= 10;
+    }
+    return result;
+}
+
+static SkString strip_final(const SkString& str) {
+    SkString result(str);
+    if (result.endsWith("\n")) {
+        result.remove(result.size() - 1, 1);
+    }
+    if (result.endsWith(" ")) {
+        result.remove(result.size() - 1, 1);
+    }
+    if (result.endsWith(",")) {
+        result.remove(result.size() - 1, 1);
+    }
+    return result;
+}
+
+static void output_font(sk_sp<SkTypeface> face, const char* identifier, FILE* out) {
+    const int emSize = face->getUnitsPerEm() * 2;
+    SkFont font;
+    font.setEdging(SkFont::Edging::kAntiAlias);
+    font.setSize(emSize);
+    font.setTypeface(std::move(face));
+
+    SkTDArray<SkPath::Verb> verbs;
+    SkTDArray<unsigned> charCodes;
+    SkTDArray<SkScalar> widths;
+    SkString ptsOut;
+    output_path_data(font, emSize, &ptsOut, &verbs, &charCodes, &widths);
+    fprintf(out, "const SkScalar %sPoints[] = {\n", identifier);
+    ptsOut = strip_final(ptsOut);
+    fprintf(out, "%s", ptsOut.c_str());
+    fprintf(out, "\n};\n\n");
+    fprintf(out, "const unsigned char %sVerbs[] = {\n", identifier);
+    int verbCount = verbs.count();
+    int outChCount = 0;
+    for (int index = 0; index < verbCount;) {
+        SkPath::Verb verb = verbs[index];
+        SkASSERT(verb >= SkPath::kMove_Verb && verb <= SkPath::kDone_Verb);
+        SkASSERT(SkTFitsIn<uint8_t>(verb));
+        fprintf(out, "%u", verb);
+        if (++index < verbCount) {
+            outChCount += 3;
+            fprintf(out, "%c", ',');
+            if (outChCount >= kMaxLineLength) {
+                outChCount = 0;
+                fprintf(out, "%c", '\n');
+            } else {
+                fprintf(out, "%c", ' ');
+            }
+        }
+    }
+    fprintf(out, "\n};\n\n");
+
+    // all fonts are now 0x00, 0x20 - 0xFE
+    // don't need to generate or output character codes?
+    fprintf(out, "const SkUnichar %sCharCodes[] = {\n", identifier);
+    int offsetCount = charCodes.count();
+    for (int index = 0; index < offsetCount;) {
+        unsigned offset = charCodes[index];
+        fprintf(out, "%u", offset);
+        if (++index < offsetCount) {
+            outChCount += offset_str_len(offset) + 2;
+            fprintf(out, "%c", ',');
+            if (outChCount >= kMaxLineLength) {
+                outChCount = 0;
+                fprintf(out, "%c", '\n');
+            } else {
+                fprintf(out, "%c", ' ');
+            }
+        }
+    }
+    fprintf(out, "\n};\n\n");
+
+    SkString widthsStr;
+    fprintf(out, "const SkFixed %sWidths[] = {\n", identifier);
+    for (int index = 0; index < offsetCount; ++index) {
+        output_fixed(widths[index], emSize, &widthsStr);
+    }
+    widthsStr = strip_final(widthsStr);
+    fprintf(out, "%s\n};\n\n", widthsStr.c_str());
+
+    fprintf(out, "const size_t %sCharCodesCount = SK_ARRAY_COUNT(%sCharCodes);\n\n",
+            identifier, identifier);
+
+    SkFontMetrics metrics;
+    font.getMetrics(&metrics);
+    fprintf(out, "const SkFontMetrics %sMetrics = {\n", identifier);
+    SkString metricsStr;
+    metricsStr.printf("0x%08x, ", metrics.fFlags);
+    output_scalar(metrics.fTop, emSize, &metricsStr);
+    output_scalar(metrics.fAscent, emSize, &metricsStr);
+    output_scalar(metrics.fDescent, emSize, &metricsStr);
+    output_scalar(metrics.fBottom, emSize, &metricsStr);
+    output_scalar(metrics.fLeading, emSize, &metricsStr);
+    output_scalar(metrics.fAvgCharWidth, emSize, &metricsStr);
+    output_scalar(metrics.fMaxCharWidth, emSize, &metricsStr);
+    output_scalar(metrics.fXMin, emSize, &metricsStr);
+    output_scalar(metrics.fXMax, emSize, &metricsStr);
+    output_scalar(metrics.fXHeight, emSize, &metricsStr);
+    output_scalar(metrics.fCapHeight, emSize, &metricsStr);
+    output_scalar(metrics.fUnderlineThickness, emSize, &metricsStr);
+    output_scalar(metrics.fUnderlinePosition, emSize, &metricsStr);
+    output_scalar(metrics.fStrikeoutThickness, emSize, &metricsStr);
+    output_scalar(metrics.fStrikeoutPosition, emSize, &metricsStr);
+    metricsStr = strip_final(metricsStr);
+    fprintf(out, "%s\n};\n\n", metricsStr.c_str());
+}
+
+static SkString identifier(const FontFamilyDesc& family, const FontDesc& font) {
+    SkString id(family.fIdentifierName);
+    id.append(font.fNamedStyle.fIdentifierName);
+    return id;
+}
+
+static void generate_fonts(const char* basepath, const SkSpan<const FontFamilyDesc>& families) {
+    FILE* out = nullptr;
+    for (const FontFamilyDesc& family : families) {
+        out = font_header(family.fGenericName);
+        for (const FontDesc& font : family.fFonts) {
+            SkString filepath(SkOSPath::Join(basepath, font.fFile));
+            SkASSERTF(sk_exists(filepath.c_str()), "The file %s does not exist.", filepath.c_str());
+            sk_sp<SkTypeface> resourceTypeface = SkTypeface::MakeFromFile(filepath.c_str());
+            SkASSERTF(resourceTypeface, "The file %s is not a font.", filepath.c_str());
+            output_font(std::move(resourceTypeface), identifier(family, font).c_str(), out);
+        }
+        fclose(out);
+    }
+}
+
+static const char* slant_to_string(SkFontStyle::Slant slant) {
+    switch (slant) {
+        case SkFontStyle::kUpright_Slant: return "SkFontStyle::kUpright_Slant";
+        case SkFontStyle::kItalic_Slant : return "SkFontStyle::kItalic_Slant" ;
+        case SkFontStyle::kOblique_Slant: return "SkFontStyle::kOblique_Slant";
+        default: SK_ABORT("Unknown slant");
+    }
+}
+
+static void generate_index(const SkSpan<const FontFamilyDesc>& families,
+                           const FontDesc* defaultFont)
+{
+    FILE* out = font_header("index");
+    fprintf(out, "static SkTestFontData gTestFonts[] = {\n");
+    for (const FontFamilyDesc& family : families) {
+        for (const FontDesc& font : family.fFonts) {
+            SkString identifierStr = identifier(family, font);
+            const char* identifier = identifierStr.c_str();
+            const SkFontStyle& style = font.fNamedStyle.fStyle;
+            fprintf(out,
+                    "    {    %sPoints, %sVerbs,\n"
+                    "         %sCharCodes, %sCharCodesCount, %sWidths,\n"
+                    "         %sMetrics, \"Toy %s\", SkFontStyle(%d,%d,%s)\n"
+                    "    },\n",
+                    identifier, identifier,
+                    identifier, identifier, identifier,
+                    identifier, family.fFamilyName,
+                    style.weight(), style.width(), slant_to_string(style.slant()));
+        }
+    }
+    fprintf(out, "};\n\n");
+    fprintf(out,
+            "struct SubFont {\n"
+            "    const char* fFamilyName;\n"
+            "    const char* fStyleName;\n"
+            "    SkFontStyle fStyle;\n"
+            "    SkTestFontData& fFont;\n"
+            "    const char* fFile;\n"
+            "};\n\n"
+            "const SubFont gSubFonts[] = {\n");
+    int defaultIndex = -1;
+    int testFontsIndex = 0;
+    for (const FontFamilyDesc& family : families) {
+        for (const FontDesc& font : family.fFonts) {
+            if (&font == defaultFont) {
+                defaultIndex = testFontsIndex;
+            }
+            const SkFontStyle& style = font.fNamedStyle.fStyle;
+            fprintf(out,
+                    "    { \"%s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n",
+                    family.fGenericName, font.fNamedStyle.fName,
+                    style.weight(), style.width(), slant_to_string(style.slant()),
+                    testFontsIndex, font.fFile);
+            testFontsIndex++;
+        }
+    }
+    testFontsIndex = 0;
+    for (const FontFamilyDesc& family : families) {
+        for (const FontDesc& font : family.fFonts) {
+            fprintf(out,
+                    "    { \"Toy %s\", \"%s\", SkFontStyle(%d,%d,%s), gTestFonts[%d], \"%s\" },\n",
+                    family.fFamilyName, font.fNamedStyle.fName,
+                    font.fNamedStyle.fStyle.weight(), font.fNamedStyle.fStyle.width(),
+                    slant_to_string(font.fNamedStyle.fStyle.slant()), testFontsIndex, font.fFile);
+            testFontsIndex++;
+        }
+    }
+    fprintf(out, "};\n\n");
+    SkASSERT(defaultIndex >= 0);
+    fprintf(out, "const size_t gDefaultFontIndex = %d;\n", defaultIndex);
+    fclose(out);
+}
+
+int main(int , char * const []) {
+    constexpr NamedFontStyle normal     = {"Normal",      "Normal",     SkFontStyle::Normal()    };
+    constexpr NamedFontStyle bold       = {"Bold",        "Bold",       SkFontStyle::Bold()      };
+    constexpr NamedFontStyle italic     = {"Italic",      "Italic",     SkFontStyle::Italic()    };
+    constexpr NamedFontStyle bolditalic = {"Bold Italic", "BoldItalic", SkFontStyle::BoldItalic()};
+
+    static constexpr FontDesc kMonoFonts[] = {
+        {normal,     "LiberationMono-Regular.ttf"},
+        {bold,       "LiberationMono-Bold.ttf"},
+        {italic,     "LiberationMono-Italic.ttf"},
+        {bolditalic, "LiberationMono-BoldItalic.ttf"},
+    };
+
+    static constexpr FontDesc kSansFonts[] = {
+        {normal,     "LiberationSans-Regular.ttf"},
+        {bold,       "LiberationSans-Bold.ttf"},
+        {italic,     "LiberationSans-Italic.ttf"},
+        {bolditalic, "LiberationSans-BoldItalic.ttf"},
+    };
+
+    static constexpr FontDesc kSerifFonts[] = {
+        {normal,     "LiberationSerif-Regular.ttf"},
+        {bold,       "LiberationSerif-Bold.ttf"},
+        {italic,     "LiberationSerif-Italic.ttf"},
+        {bolditalic, "LiberationSerif-BoldItalic.ttf"},
+    };
+
+    static constexpr FontFamilyDesc kFamiliesData[] = {
+        {"monospace",  "Liberation Mono",  "LiberationMono",  SkMakeSpan(kMonoFonts)},
+        {"sans-serif", "Liberation Sans",  "LiberationSans",  SkMakeSpan(kSansFonts)},
+        {"serif",      "Liberation Serif", "LiberationSerif", SkMakeSpan(kSerifFonts)},
+    };
+
+    static constexpr SkSpan<const FontFamilyDesc> kFamilies(SkMakeSpan(kFamiliesData));
+
+#ifdef SK_BUILD_FOR_UNIX
+    generate_fonts("/usr/share/fonts/truetype/liberation/", kFamilies);
+#else
+    generate_fonts("/Library/Fonts/", kFamilies);
+#endif
+    generate_index(kFamilies, &kFamilies[1].fFonts[0]);
+    return 0;
+}
diff --git a/src/third_party/skia/tools/fonts/create_test_font_color.cpp b/src/third_party/skia/tools/fonts/create_test_font_color.cpp
new file mode 100644
index 0000000..06d7431
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/create_test_font_color.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// running create_test_font_color generates ./<cbdt|sbix|cpal>.ttx
+// which are read by fonttools ttx to produce native fonts.
+
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkString.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/fonts/TestSVGTypeface.h"
+
+static void export_ttx(sk_sp<TestSVGTypeface> typeface,
+                       SkString               prefix,
+                       SkSpan<unsigned>       cbdtStrikeSizes,
+                       SkSpan<unsigned>       sbixStrikeSizes) {
+    SkFILEWStream cbdt((SkString(prefix) += "cbdt.ttx").c_str());
+    typeface->exportTtxCbdt(&cbdt, cbdtStrikeSizes);
+    cbdt.flush();
+    cbdt.fsync();
+
+    SkFILEWStream sbix((SkString(prefix) += "sbix.ttx").c_str());
+    typeface->exportTtxSbix(&sbix, sbixStrikeSizes);
+    sbix.flush();
+    sbix.fsync();
+
+    SkFILEWStream colr((SkString(prefix) += "colr.ttx").c_str());
+    typeface->exportTtxColr(&colr);
+    colr.flush();
+    colr.fsync();
+}
+
+int main(int argc, char** argv) {
+    CommandLineFlags::Parse(argc, argv);
+
+    // Most of the time use these sizes.
+    unsigned usual[] = { 16, 64, 128 };
+
+    // But the planet font cannot get very big in the size limited cbdt format.
+    unsigned small[] = { 8, 16 };
+
+    export_ttx(TestSVGTypeface::Default(), SkString(), SkMakeSpan(usual), SkMakeSpan(usual));
+    export_ttx(
+            TestSVGTypeface::Planets(), SkString("planet"), SkMakeSpan(small), SkMakeSpan(usual));
+
+    return 0;
+}
diff --git a/src/third_party/skia/tools/generate_fir_coeff.py b/src/third_party/skia/tools/fonts/generate_fir_coeff.py
similarity index 67%
rename from src/third_party/skia/tools/generate_fir_coeff.py
rename to src/third_party/skia/tools/fonts/generate_fir_coeff.py
index 70f521f..f5cc5e5 100644
--- a/src/third_party/skia/tools/generate_fir_coeff.py
+++ b/src/third_party/skia/tools/fonts/generate_fir_coeff.py
@@ -28,18 +28,26 @@
     return (withinStdDev(b) - withinStdDev(a)) / 2;
 
 
-#We have a bunch of smudged samples which represent the average coverage of a range.
-#We have a 'center' which may not line up with those samples.
-#From the 'center' we want to make a normal approximation where '5' sample width out we're at '3' std deviations.
-#The first and last samples may not be fully covered.
+# We have some smudged samples which represent the average coverage of a range.
+# We have a 'center' which may not line up with those samples.
+# From center make a normal where 5 sample widths out is at 3 std deviations.
+# The first and last samples may not be fully covered.
 
-#This is the sub-sample shift for each set of FIR coefficients (the centers of the lcds in the samples)
-#Each subpxl takes up 1/3 of a pixel, so they are centered at x=(i/n+1/2n), or 1/6, 3/6, 5/6 of a pixel.
-#Each sample takes up 1/4 of a pixel, so the results fall at (x*4)%1, or 2/3, 0, 1/3 of a sample.
+# This is the sub-sample shift for each set of FIR coefficients
+#   (the centers of the lcds in the samples)
+# Each subpxl takes up 1/3 of a pixel,
+#   so they are centered at x=(i/n+1/2n), or 1/6, 3/6, 5/6 of a pixel.
+# Each sample takes up 1/4 of a pixel,
+#   so the results fall at (x*4)%1, or 2/3, 0, 1/3 of a sample.
 samples_per_pixel = 4
 subpxls_per_pixel = 3
 #sample_offsets is (frac, int) in sample units.
-sample_offsets = [math.modf((float(subpxl_index)/subpxls_per_pixel + 1.0/(2.0*subpxls_per_pixel))*samples_per_pixel) for subpxl_index in range(subpxls_per_pixel)]
+sample_offsets = [
+  math.modf(
+    (float(subpxl_index)/subpxls_per_pixel + 1.0/(2.0*subpxls_per_pixel))
+    * samples_per_pixel
+  ) for subpxl_index in range(subpxls_per_pixel)
+]
 
 #How many samples to consider to the left and right of the subpxl center.
 sample_units_width = 5
@@ -65,7 +73,9 @@
     if current_sample_right > sample_offset + sample_units_width:
       done = True
       current_sample_right = sample_offset + sample_units_width
-    current_std_dev_right = current_std_dev_left + ((current_sample_right - current_sample_left) / sample_units_width) * std_dev_max
+    current_std_dev_right = current_std_dev_left + (
+      (current_sample_right - current_sample_left) / sample_units_width
+    ) * std_dev_max
 
     coverage = withinStdDevRange(current_std_dev_left, current_std_dev_right)
     coeffs.append(coverage * target_sum)
@@ -74,15 +84,17 @@
     current_sample_left = current_sample_right
     current_std_dev_left = current_std_dev_right
 
-  # Now we have the numbers we want, but our rounding needs to add up to target_sum.
+  # Have the numbers, but rounding needs to add up to target_sum.
   delta = 0
   coeffs_rounded_sum = sum(coeffs_rounded)
   if coeffs_rounded_sum > target_sum:
-    # The coeffs add up to too much. Subtract 1 from the ones which were rounded up the most.
+    # The coeffs add up to too much.
+    # Subtract 1 from the ones which were rounded up the most.
     delta = -1
 
   if coeffs_rounded_sum < target_sum:
-    # The coeffs add up to too little. Add 1 to the ones which were rounded down the most.
+    # The coeffs add up to too little.
+    # Add 1 to the ones which were rounded down the most.
     delta = 1
 
   if delta:
@@ -102,18 +114,20 @@
     coeff_pkg = [IndexTracker(i, diff) for i, diff in enumerate(coeff_diff)]
     coeff_pkg.sort()
 
-    # num_elements_to_force_round had better be < (2 * sample_units_width + 1) or
+    # num_elements_to_force_round better be < (2 * sample_units_width + 1) or
     # * our math was wildy wrong
     # * an awful lot of the curve is out side our sample
     # either is pretty bad, and probably means the results will not be useful.
     num_elements_to_force_round = abs(coeffs_rounded_sum - target_sum)
     for i in xrange(num_elements_to_force_round):
-      print "Adding %d to index %d to force round %f." % (delta, coeff_pkg[i].index, coeffs[coeff_pkg[i].index])
+      print "Adding %d to index %d to force round %f." % (
+          delta, coeff_pkg[i].index, coeffs[coeff_pkg[i].index])
       coeffs_rounded[coeff_pkg[i].index] += delta
 
   print "Prepending %d 0x00 for allignment." % (sample_align,)
   coeffs_rounded_aligned = ([0] * int(sample_align)) + coeffs_rounded
 
-  print ', '.join(["0x%0.2X" % coeff_rounded for coeff_rounded in coeffs_rounded_aligned])
+  print ', '.join(["0x%0.2X" % coeff_rounded
+                   for coeff_rounded in coeffs_rounded_aligned])
   print sum(coeffs), hex(sum(coeffs_rounded))
   print
diff --git a/src/third_party/skia/tools/fonts/test_font_index.inc b/src/third_party/skia/tools/fonts/test_font_index.inc
new file mode 100644
index 0000000..0a3a979
--- /dev/null
+++ b/src/third_party/skia/tools/fonts/test_font_index.inc
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Auto-generated by create_test_font.cpp
+
+static SkTestFontData gTestFonts[] = {
+    {    LiberationMonoNormalPoints, LiberationMonoNormalVerbs,
+         LiberationMonoNormalCharCodes, LiberationMonoNormalCharCodesCount, LiberationMonoNormalWidths,
+         LiberationMonoNormalMetrics, "Toy Liberation Mono", SkFontStyle(400,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationMonoBoldPoints, LiberationMonoBoldVerbs,
+         LiberationMonoBoldCharCodes, LiberationMonoBoldCharCodesCount, LiberationMonoBoldWidths,
+         LiberationMonoBoldMetrics, "Toy Liberation Mono", SkFontStyle(700,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationMonoItalicPoints, LiberationMonoItalicVerbs,
+         LiberationMonoItalicCharCodes, LiberationMonoItalicCharCodesCount, LiberationMonoItalicWidths,
+         LiberationMonoItalicMetrics, "Toy Liberation Mono", SkFontStyle(400,5,SkFontStyle::kItalic_Slant)
+    },
+    {    LiberationMonoBoldItalicPoints, LiberationMonoBoldItalicVerbs,
+         LiberationMonoBoldItalicCharCodes, LiberationMonoBoldItalicCharCodesCount, LiberationMonoBoldItalicWidths,
+         LiberationMonoBoldItalicMetrics, "Toy Liberation Mono", SkFontStyle(700,5,SkFontStyle::kItalic_Slant)
+    },
+    {    LiberationSansNormalPoints, LiberationSansNormalVerbs,
+         LiberationSansNormalCharCodes, LiberationSansNormalCharCodesCount, LiberationSansNormalWidths,
+         LiberationSansNormalMetrics, "Toy Liberation Sans", SkFontStyle(400,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationSansBoldPoints, LiberationSansBoldVerbs,
+         LiberationSansBoldCharCodes, LiberationSansBoldCharCodesCount, LiberationSansBoldWidths,
+         LiberationSansBoldMetrics, "Toy Liberation Sans", SkFontStyle(700,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationSansItalicPoints, LiberationSansItalicVerbs,
+         LiberationSansItalicCharCodes, LiberationSansItalicCharCodesCount, LiberationSansItalicWidths,
+         LiberationSansItalicMetrics, "Toy Liberation Sans", SkFontStyle(400,5,SkFontStyle::kItalic_Slant)
+    },
+    {    LiberationSansBoldItalicPoints, LiberationSansBoldItalicVerbs,
+         LiberationSansBoldItalicCharCodes, LiberationSansBoldItalicCharCodesCount, LiberationSansBoldItalicWidths,
+         LiberationSansBoldItalicMetrics, "Toy Liberation Sans", SkFontStyle(700,5,SkFontStyle::kItalic_Slant)
+    },
+    {    LiberationSerifNormalPoints, LiberationSerifNormalVerbs,
+         LiberationSerifNormalCharCodes, LiberationSerifNormalCharCodesCount, LiberationSerifNormalWidths,
+         LiberationSerifNormalMetrics, "Toy Liberation Serif", SkFontStyle(400,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationSerifBoldPoints, LiberationSerifBoldVerbs,
+         LiberationSerifBoldCharCodes, LiberationSerifBoldCharCodesCount, LiberationSerifBoldWidths,
+         LiberationSerifBoldMetrics, "Toy Liberation Serif", SkFontStyle(700,5,SkFontStyle::kUpright_Slant)
+    },
+    {    LiberationSerifItalicPoints, LiberationSerifItalicVerbs,
+         LiberationSerifItalicCharCodes, LiberationSerifItalicCharCodesCount, LiberationSerifItalicWidths,
+         LiberationSerifItalicMetrics, "Toy Liberation Serif", SkFontStyle(400,5,SkFontStyle::kItalic_Slant)
+    },
+    {    LiberationSerifBoldItalicPoints, LiberationSerifBoldItalicVerbs,
+         LiberationSerifBoldItalicCharCodes, LiberationSerifBoldItalicCharCodesCount, LiberationSerifBoldItalicWidths,
+         LiberationSerifBoldItalicMetrics, "Toy Liberation Serif", SkFontStyle(700,5,SkFontStyle::kItalic_Slant)
+    },
+};
+
+struct SubFont {
+    const char* fFamilyName;
+    const char* fStyleName;
+    SkFontStyle fStyle;
+    SkTestFontData& fFont;
+    const char* fFile;
+};
+
+const SubFont gSubFonts[] = {
+    { "monospace", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[0], "LiberationMono-Regular.ttf" },
+    { "monospace", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[1], "LiberationMono-Bold.ttf" },
+    { "monospace", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[2], "LiberationMono-Italic.ttf" },
+    { "monospace", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[3], "LiberationMono-BoldItalic.ttf" },
+    { "sans-serif", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[4], "LiberationSans-Regular.ttf" },
+    { "sans-serif", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[5], "LiberationSans-Bold.ttf" },
+    { "sans-serif", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[6], "LiberationSans-Italic.ttf" },
+    { "sans-serif", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[7], "LiberationSans-BoldItalic.ttf" },
+    { "serif", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[8], "LiberationSerif-Regular.ttf" },
+    { "serif", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[9], "LiberationSerif-Bold.ttf" },
+    { "serif", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[10], "LiberationSerif-Italic.ttf" },
+    { "serif", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[11], "LiberationSerif-BoldItalic.ttf" },
+    { "Toy Liberation Mono", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[0], "LiberationMono-Regular.ttf" },
+    { "Toy Liberation Mono", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[1], "LiberationMono-Bold.ttf" },
+    { "Toy Liberation Mono", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[2], "LiberationMono-Italic.ttf" },
+    { "Toy Liberation Mono", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[3], "LiberationMono-BoldItalic.ttf" },
+    { "Toy Liberation Sans", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[4], "LiberationSans-Regular.ttf" },
+    { "Toy Liberation Sans", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[5], "LiberationSans-Bold.ttf" },
+    { "Toy Liberation Sans", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[6], "LiberationSans-Italic.ttf" },
+    { "Toy Liberation Sans", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[7], "LiberationSans-BoldItalic.ttf" },
+    { "Toy Liberation Serif", "Normal", SkFontStyle(400,5,SkFontStyle::kUpright_Slant), gTestFonts[8], "LiberationSerif-Regular.ttf" },
+    { "Toy Liberation Serif", "Bold", SkFontStyle(700,5,SkFontStyle::kUpright_Slant), gTestFonts[9], "LiberationSerif-Bold.ttf" },
+    { "Toy Liberation Serif", "Italic", SkFontStyle(400,5,SkFontStyle::kItalic_Slant), gTestFonts[10], "LiberationSerif-Italic.ttf" },
+    { "Toy Liberation Serif", "Bold Italic", SkFontStyle(700,5,SkFontStyle::kItalic_Slant), gTestFonts[11], "LiberationSerif-BoldItalic.ttf" },
+};
+
+const size_t gDefaultFontIndex = 4;
diff --git a/src/third_party/skia/tools/test_font_monospace.inc b/src/third_party/skia/tools/fonts/test_font_monospace.inc
similarity index 99%
rename from src/third_party/skia/tools/test_font_monospace.inc
rename to src/third_party/skia/tools/fonts/test_font_monospace.inc
index 4b14dc6..bb87f93 100644
--- a/src/third_party/skia/tools/test_font_monospace.inc
+++ b/src/third_party/skia/tools/fonts/test_font_monospace.inc
@@ -1164,7 +1164,7 @@
 2, 1, 2, 2, 5, 6
 };
 
-const unsigned LiberationMonoNormalCharCodes[] = {
+const SkUnichar LiberationMonoNormalCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
@@ -1190,11 +1190,11 @@
 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
 };
 
-const int LiberationMonoNormalCharCodesCount = (int) SK_ARRAY_COUNT(LiberationMonoNormalCharCodes);
+const size_t LiberationMonoNormalCharCodesCount = SK_ARRAY_COUNT(LiberationMonoNormalCharCodes);
 
-const SkPaint::FontMetrics LiberationMonoNormalMetrics = {
-0x30307833, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.633301f, 0.00989532f,
--0.0244141f, 0.608887f, 0.538086f, 0.0104446f, 0.0410156f, 0.23291f
+const SkFontMetrics LiberationMonoNormalMetrics = {
+0x0000000f, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.600098f, 0.633301f, -0.0244141f,
+0.608887f, 0.52832f, 0.658691f, 0.0410156f, 0.23291f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationMonoBoldPoints[] = {
@@ -2314,7 +2314,7 @@
 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationMonoBoldCharCodes[] = {
+const SkUnichar LiberationMonoBoldCharCodes[] = {
 0, 32, 33, 34, 35, 36,
 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
@@ -2340,11 +2340,11 @@
 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
 };
 
-const int LiberationMonoBoldCharCodesCount = (int) SK_ARRAY_COUNT(LiberationMonoBoldCharCodes);
+const size_t LiberationMonoBoldCharCodesCount = SK_ARRAY_COUNT(LiberationMonoBoldCharCodes);
 
-const SkPaint::FontMetrics LiberationMonoBoldMetrics = {
-0x30307833, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.641602f, 0.010025f, -0.0268555f,
-0.614746f, 0.538086f, 0.0104446f, 0.100098f, 0.23291f
+const SkFontMetrics LiberationMonoBoldMetrics = {
+0x0000000f, -0.833496f, -0.833496f, 0.300293f, 0.300293f, 0, 0.600098f, 0.641602f, -0.0268555f,
+0.614746f, 0.52832f, 0.658691f, 0.100098f, 0.23291f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationMonoItalicPoints[] = {
@@ -3580,7 +3580,7 @@
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 5, 6
 };
 
-const unsigned LiberationMonoItalicCharCodes[] = {
+const SkUnichar LiberationMonoItalicCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
@@ -3606,11 +3606,11 @@
 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
 };
 
-const int LiberationMonoItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationMonoItalicCharCodes);
+const size_t LiberationMonoItalicCharCodesCount = SK_ARRAY_COUNT(LiberationMonoItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationMonoItalicMetrics = {
-0x30307833, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.798828f, 0.0124817f,
--0.0942383f, 0.70459f, 0.538086f, 0.0104446f, 0.0410156f, 0.23291f
+const SkFontMetrics LiberationMonoItalicMetrics = {
+0x0000000f, -0.833496f, -0.833496f, 0.300293f, 0.300293f, 0, 0.600098f, 0.798828f, -0.0942383f,
+0.70459f, 0.52832f, 0.658691f, 0.0410156f, 0.23291f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationMonoBoldItalicPoints[] = {
@@ -4813,7 +4813,7 @@
 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationMonoBoldItalicCharCodes[] = {
+const SkUnichar LiberationMonoBoldItalicCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
@@ -4839,9 +4839,10 @@
 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
 };
 
-const int LiberationMonoBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationMonoBoldItalicCharCodes);
+const size_t LiberationMonoBoldItalicCharCodesCount = SK_ARRAY_COUNT(LiberationMonoBoldItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationMonoBoldItalicMetrics = {
-0x30307833, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.791992f, 0.0123749f,
--0.0942383f, 0.697754f, 0.538086f, 0.0104446f, 0.100098f, 0.23291f
+const SkFontMetrics LiberationMonoBoldItalicMetrics = {
+0x0000000f, -0.83252f, -0.83252f, 0.300293f, 0.300293f, 0, 0.600098f, 0.791992f, -0.0942383f,
+0.697754f, 0.52832f, 0.658691f, 0.100098f, 0.23291f, 0.0498047f, -0.258789f
 };
+
diff --git a/src/third_party/skia/tools/test_font_sans_serif.inc b/src/third_party/skia/tools/fonts/test_font_sans_serif.inc
similarity index 99%
rename from src/third_party/skia/tools/test_font_sans_serif.inc
rename to src/third_party/skia/tools/fonts/test_font_sans_serif.inc
index b0d433d..b53da19 100644
--- a/src/third_party/skia/tools/test_font_sans_serif.inc
+++ b/src/third_party/skia/tools/fonts/test_font_sans_serif.inc
@@ -1158,7 +1158,7 @@
 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSansNormalCharCodes[] = {
+const SkUnichar LiberationSansNormalCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
@@ -1184,11 +1184,11 @@
 0x00008000, 0x00005580, 0x00004280, 0x00005580, 0x00009580
 };
 
-const int LiberationSansNormalCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSansNormalCharCodes);
+const size_t LiberationSansNormalCharCodesCount = SK_ARRAY_COUNT(LiberationSansNormalCharCodes);
 
-const SkPaint::FontMetrics LiberationSansNormalMetrics = {
-0x30307833, -0.910156f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.25342f, 0.0195847f,
--0.203125f, 1.05029f, 0.538086f, 0.0109024f, 0.0732422f, 0.105957f
+const SkFontMetrics LiberationSansNormalMetrics = {
+0x0000000f, -0.910156f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 0.589355f, 1.25342f,
+-0.203125f, 1.05029f, 0.52832f, 0.687988f, 0.0732422f, 0.105957f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationSansBoldPoints[] = {
@@ -2321,7 +2321,7 @@
 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSansBoldCharCodes[] = {
+const SkUnichar LiberationSansBoldCharCodes[] = {
 0,
 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
@@ -2348,11 +2348,11 @@
 0x00008000, 0x000063a0, 0x000047a0, 0x000063a0, 0x00009580
 };
 
-const int LiberationSansBoldCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSansBoldCharCodes);
+const size_t LiberationSansBoldCharCodesCount = SK_ARRAY_COUNT(LiberationSansBoldCharCodes);
 
-const SkPaint::FontMetrics LiberationSansBoldMetrics = {
-0x30307833, -1.0332f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.24609f, 0.0194702f,
--0.184082f, 1.06201f, 0.538086f, 0.0109024f, 0.10498f, 0.105957f
+const SkFontMetrics LiberationSansBoldMetrics = {
+0x0000000f, -1.0332f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 0.612305f, 1.24609f,
+-0.184082f, 1.06201f, 0.52832f, 0.687988f, 0.10498f, 0.105957f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationSansItalicPoints[] = {
@@ -3563,7 +3563,7 @@
 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSansItalicCharCodes[] = {
+const SkUnichar LiberationSansItalicCharCodes[] = {
 0, 32, 33,
 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
@@ -3589,11 +3589,11 @@
 0x00008000, 0x00005580, 0x00004280, 0x00005580, 0x00009580
 };
 
-const int LiberationSansItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSansItalicCharCodes);
+const size_t LiberationSansItalicCharCodesCount = SK_ARRAY_COUNT(LiberationSansItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationSansItalicMetrics = {
-0x30307833, -1.01416f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.33447f, 0.0208511f,
--0.271973f, 1.0625f, 0.537598f, 0.0109024f, 0.0732422f, 0.105957f
+const SkFontMetrics LiberationSansItalicMetrics = {
+0x0000000f, -1.01416f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 0.590332f, 1.33447f,
+-0.271973f, 1.0625f, 0.52832f, 0.687988f, 0.0732422f, 0.105957f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationSansBoldItalicPoints[] = {
@@ -4823,7 +4823,7 @@
 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSansBoldItalicCharCodes[] = {
+const SkUnichar LiberationSansBoldItalicCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
@@ -4849,9 +4849,10 @@
 0x00008000, 0x000063a0, 0x000047a0, 0x000063a0, 0x00009580
 };
 
-const int LiberationSansBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSansBoldItalicCharCodes);
+const size_t LiberationSansBoldItalicCharCodesCount = SK_ARRAY_COUNT(LiberationSansBoldItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationSansBoldItalicMetrics = {
-0x30307833, -1.02979f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.3374f, 0.0208969f,
--0.208984f, 1.12842f, 0.537598f, 0.0109024f, 0.10498f, 0.105957f
+const SkFontMetrics LiberationSansBoldItalicMetrics = {
+0x0000000f, -1.02979f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 0.61377f, 1.3374f,
+-0.208984f, 1.12842f, 0.52832f, 0.687988f, 0.10498f, 0.105957f, 0.0498047f, -0.258789f
 };
+
diff --git a/src/third_party/skia/tools/test_font_serif.inc b/src/third_party/skia/tools/fonts/test_font_serif.inc
similarity index 99%
rename from src/third_party/skia/tools/test_font_serif.inc
rename to src/third_party/skia/tools/fonts/test_font_serif.inc
index 49279ce..816e094 100644
--- a/src/third_party/skia/tools/test_font_serif.inc
+++ b/src/third_party/skia/tools/fonts/test_font_serif.inc
@@ -1235,7 +1235,7 @@
 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSerifNormalCharCodes[] = {
+const SkUnichar LiberationSerifNormalCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
@@ -1261,11 +1261,11 @@
 0x000071a0, 0x00007ae0, 0x00003340, 0x00007ae0, 0x00008a80
 };
 
-const int LiberationSerifNormalCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSerifNormalCharCodes);
+const size_t LiberationSerifNormalCharCodesCount = SK_ARRAY_COUNT(LiberationSerifNormalCharCodes);
 
-const SkPaint::FontMetrics LiberationSerifNormalMetrics = {
-0x30307833, -0.981445f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 1.18359f, 0.0184937f,
--0.176758f, 1.00684f, 0.469727f, 0.0103607f, 0.0488281f, 0.108887f
+const SkFontMetrics LiberationSerifNormalMetrics = {
+0x0000000f, -0.981445f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 0.567383f, 1.18359f,
+-0.176758f, 1.00684f, 0.458984f, 0.654785f, 0.0488281f, 0.108887f, 0.0488281f, -0.205078f
 };
 
 const SkScalar LiberationSerifBoldPoints[] = {
@@ -2485,7 +2485,7 @@
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSerifBoldCharCodes[] = {
+const SkUnichar LiberationSerifBoldCharCodes[] = {
 0, 32, 33, 34, 35, 36,
 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
@@ -2511,11 +2511,11 @@
 0x000071a0, 0x000064e0, 0x00003860, 0x000064e0, 0x00008520
 };
 
-const int LiberationSerifBoldCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSerifBoldCharCodes);
+const size_t LiberationSerifBoldCharCodesCount = SK_ARRAY_COUNT(LiberationSerifBoldCharCodes);
 
-const SkPaint::FontMetrics LiberationSerifBoldMetrics = {
-0x30307833, -1.00781f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 1.26709f, 0.0197983f,
--0.182129f, 1.08496f, 0.469727f, 0.0103607f, 0.0952148f, 0.108887f
+const SkFontMetrics LiberationSerifBoldMetrics = {
+0x0000000f, -1.00781f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 0.59375f, 1.26709f,
+-0.182129f, 1.08496f, 0.458984f, 0.654785f, 0.0952148f, 0.108887f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationSerifItalicPoints[] = {
@@ -3803,7 +3803,7 @@
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSerifItalicCharCodes[] = {
+const SkUnichar LiberationSerifItalicCharCodes[] = {
 0, 32, 33, 34, 35, 36,
 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
@@ -3829,11 +3829,11 @@
 0x000063a0, 0x00006660, 0x00004660, 0x00006660, 0x00008a80
 };
 
-const int LiberationSerifItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSerifItalicCharCodes);
+const size_t LiberationSerifItalicCharCodesCount = SK_ARRAY_COUNT(LiberationSerifItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationSerifItalicMetrics = {
-0x30307833, -0.980957f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 1.26465f, 0.0197601f,
--0.176758f, 1.08789f, 0.469727f, 0.0103607f, 0.0488281f, 0.108887f
+const SkFontMetrics LiberationSerifItalicMetrics = {
+0x0000000f, -0.980957f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 0.559082f, 1.26465f,
+-0.176758f, 1.08789f, 0.458984f, 0.654785f, 0.0488281f, 0.108887f, 0.0498047f, -0.258789f
 };
 
 const SkScalar LiberationSerifBoldItalicPoints[] = {
@@ -5115,7 +5115,7 @@
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6
 };
 
-const unsigned LiberationSerifBoldItalicCharCodes[] = {
+const SkUnichar LiberationSerifBoldItalicCharCodes[] = {
 0, 32, 33, 34, 35, 36, 37, 38, 39,
 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
@@ -5141,9 +5141,10 @@
 0x000063a0, 0x00005920, 0x00003860, 0x00005920, 0x000091e0
 };
 
-const int LiberationSerifBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSerifBoldItalicCharCodes);
+const size_t LiberationSerifBoldItalicCharCodesCount = SK_ARRAY_COUNT(LiberationSerifBoldItalicCharCodes);
 
-const SkPaint::FontMetrics LiberationSerifBoldItalicMetrics = {
-0x30307833, -0.980957f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 1.32861f, 0.0207596f,
--0.178223f, 1.15039f, 0.469727f, 0.0103607f, 0.0952148f, 0.108887f
+const SkFontMetrics LiberationSerifBoldItalicMetrics = {
+0x0000000f, -0.980957f, -0.891113f, 0.216309f, 0.303223f, 0.0424805f, 0.578125f, 1.32861f,
+-0.178223f, 1.15039f, 0.458984f, 0.654785f, 0.0952148f, 0.108887f, 0.0498047f, -0.258789f
 };
+
diff --git a/src/third_party/skia/tools/force_older_glibc_math.h b/src/third_party/skia/tools/force_older_glibc_math.h
new file mode 100644
index 0000000..bf8b778
--- /dev/null
+++ b/src/third_party/skia/tools/force_older_glibc_math.h
@@ -0,0 +1,10 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#pragma once
+
+// GLIBC_2.27 has new implementations of expf, powf, log2f, exp2f that are pretty nifty,
+// but that's not very helpful if you're using an older glibc that doesn't ship those.
+__asm__(".symver expf,expf@GLIBC_2.4");
+__asm__(".symver powf,powf@GLIBC_2.4");
+__asm__(".symver log2f,log2f@GLIBC_2.4");
+__asm__(".symver exp2f,exp2f@GLIBC_2.4");
diff --git a/src/third_party/skia/tools/gdb/bitmap.py b/src/third_party/skia/tools/gdb/bitmap.py
new file mode 100644
index 0000000..3df079d
--- /dev/null
+++ b/src/third_party/skia/tools/gdb/bitmap.py
@@ -0,0 +1,88 @@
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Visualize bitmaps in gdb.
+
+(gdb) source <path to this file>
+(gdb) sk_bitmap <symbol>
+
+This should pop up a window with the bitmap displayed.
+Right clicking should bring up a menu, allowing the
+bitmap to be saved to a file.
+"""
+
+import gdb
+from enum import Enum
+try:
+  from PIL import Image
+except ImportError:
+  import Image
+
+class ColorType(Enum):
+    unknown = 0
+    alpha_8 = 1
+    rgb_565 = 2
+    argb_4444 = 3
+    rgba_8888 = 4
+    rgbx_8888 = 5
+    bgra_8888 = 6
+    rgba_1010102 = 7
+    rgb_101010x = 8
+    gray_8 = 9
+    rgba_F16 = 10
+
+class AlphaType(Enum):
+    unknown = 0
+    opaque = 1
+    premul = 2
+    unpremul = 3
+
+class sk_bitmap(gdb.Command):
+  """Displays the content of an SkBitmap image."""
+
+  def __init__(self):
+      super(sk_bitmap, self).__init__('sk_bitmap',
+                                      gdb.COMMAND_SUPPORT,
+                                      gdb.COMPLETE_FILENAME)
+
+  def invoke(self, arg, from_tty):
+    frame = gdb.selected_frame()
+    val = frame.read_var(arg)
+    if str(val.type.strip_typedefs()) == 'SkBitmap':
+      pixmap = val['fPixmap']
+      pixels = pixmap['fPixels']
+      row_bytes = pixmap['fRowBytes']
+      info = pixmap['fInfo']
+      dimensions = info['fDimensions']
+      width = dimensions['fWidth']
+      height = dimensions['fHeight']
+      color_type = info['fColorType']
+      alpha_type = info['fAlphaType']
+
+      process = gdb.selected_inferior()
+      memory_data = process.read_memory(pixels, row_bytes * height)
+      size = (width, height)
+      image = None
+      # See Unpack.c for the values understood after the "raw" parameter.
+      if color_type == ColorType.bgra_8888.value:
+        if alpha_type == AlphaType.unpremul.value:
+          image = Image.frombytes("RGBA", size, memory_data,
+                                  "raw", "BGRA", row_bytes, 1)
+        elif alpha_type == AlphaType.premul.value:
+          # RGBA instead of RGBa, because Image.show() doesn't work with RGBa.
+          image = Image.frombytes("RGBA", size, memory_data,
+                                  "raw", "BGRa", row_bytes, 1)
+
+      if image:
+        # Fails on premultiplied alpha, it cannot convert to RGB.
+        image.show()
+      else:
+        print ("Need to add support for %s %s." % (
+               str(ColorType(int(color_type))),
+               str(AlphaType(int(alpha_type)))
+        ))
+
+sk_bitmap()
diff --git a/src/third_party/skia/tools/generate_vk_interface.sh b/src/third_party/skia/tools/generate_vk_interface.sh
deleted file mode 100644
index 84eaee3..0000000
--- a/src/third_party/skia/tools/generate_vk_interface.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2015 Google Inc. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-headerLoc=../third_party/vulkan/vulkan.h
-outFile=tempVkInterface
-
-if [ ! -e "$outFile" ] ; then
-    echo 'I AM HERE'
-    touch "$outFile"
-fi
-
-chmod 700 $outFile
-
-echo '// *******************************************' > $outFile
-echo '// Place these lines into GrVkInterface.cpp::validate' >> $outFile
-echo '// *******************************************' >> $outFile
-sed -n 's/^VKAPI_ATTR \(VkResult\|void\) VKAPI_CALL vk\([a-zA-Z]*\).*/NULL == fFunctions.f\2 ||/p' $headerLoc >> $outFile
-sed -i '1,/NULL/ s/^NULL/if (NULL/' $outFile
-sed -i '5,$ s/^/    /' $outFile
-sed -i '$ s/ ||/) {/' $outFile
-
-echo '' >> $outFile
-echo '// *******************************************' >> $outFile
-echo '// Place these lines into GrVkInterface.h' >> $outFile
-echo '// *******************************************' >> $outFile
-sed -n 's/^VKAPI_ATTR \(VkResult\|void\) VKAPI_CALL vk\([a-zA-Z]*\).*/VkPtr<PFN_vk\2> f\2;/p' $headerLoc >> $outFile
-
-echo '' >> $outFile
-echo '// *******************************************' >> $outFile
-echo '// Place these lines into GrVkInterface.cpp::GrVKCreateInterface' >> $outFile
-echo '// *******************************************' >> $outFile
-sed -n 's/^VKAPI_ATTR \(VkResult\|void\) VKAPI_CALL vk\([a-zA-Z]*\).*/GET_PROC(\2);/p' $headerLoc >> $outFile
-
diff --git a/src/third_party/skia/tools/get_current_monitor_profile.cpp b/src/third_party/skia/tools/get_current_monitor_profile.cpp
index 55a96d5..9f2bd3c 100644
--- a/src/third_party/skia/tools/get_current_monitor_profile.cpp
+++ b/src/third_party/skia/tools/get_current_monitor_profile.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "SkStream.h"
+#include "include/core/SkStream.h"
 
 #if defined(SK_BUILD_FOR_MAC)
 #include <ApplicationServices/ApplicationServices.h>
@@ -19,10 +19,10 @@
     CFDataRef dataRef = CGColorSpaceCopyICCProfile(cs);
     const uint8_t* data = CFDataGetBytePtr(dataRef);
     size_t size = CFDataGetLength(dataRef);
-    
+
     SkFILEWStream file("monitor_0.icc");
     file.write(data, size);
-    
+
     CFRelease(cs);
     CFRelease(dataRef);
     return 0;
diff --git a/src/third_party/skia/tools/get_images_from_skps.cpp b/src/third_party/skia/tools/get_images_from_skps.cpp
index 0debe36..a75d47f 100644
--- a/src/third_party/skia/tools/get_images_from_skps.cpp
+++ b/src/third_party/skia/tools/get_images_from_skps.cpp
@@ -5,32 +5,32 @@
  * found in the LICENSE file.
  */
 
-#include "SkBitmap.h"
-#include "SkCodec.h"
-#include "SkColorSpace.h"
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkJSONCPP.h"
-#include "SkMD5.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkPicture.h"
-#include "SkPixelSerializer.h"
-#include "SkStream.h"
-#include "SkTHash.h"
-
+#include "include/codec/SkCodec.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkColorSpace.h"
+#include "include/core/SkData.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkSerialProcs.h"
+#include "include/core/SkStream.h"
+#include "include/private/SkTHash.h"
+#include "src/core/SkMD5.h"
+#include "src/core/SkOSFile.h"
+#include "src/utils/SkJSONWriter.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/flags/CommandLineFlags.h"
 
 #include <iostream>
 #include <map>
 
-DEFINE_string2(skps, s, "skps", "A path to a directory of skps or a single skp.");
-DEFINE_string2(out, o, "img-out", "A path to an output directory.");
-DEFINE_bool(testDecode, false, "Indicates if we want to test that the images decode successfully.");
-DEFINE_bool(writeImages, true,
-            "Indicates if we want to write out supported/decoded images.");
-DEFINE_bool(writeFailedImages, false,
-            "Indicates if we want to write out unsupported/failed to decode images.");
-DEFINE_string2(failuresJsonPath, j, "",
+static DEFINE_string2(skps, s, "skps", "A path to a directory of skps or a single skp.");
+static DEFINE_string2(out, o, "img-out", "A path to an output directory.");
+static DEFINE_bool(testDecode, false,
+                   "Indicates if we want to test that the images decode successfully.");
+static DEFINE_bool(writeImages, true,
+                   "Indicates if we want to write out supported/decoded images.");
+static DEFINE_bool(writeFailedImages, false,
+                   "Indicates if we want to write out unsupported/failed to decode images.");
+static DEFINE_string2(failuresJsonPath, j, "",
                "Dump SKP and count of unknown images to the specified JSON file. Will not be "
                "written anywhere if empty.");
 
@@ -41,7 +41,7 @@
 
 static SkTHashSet<SkMD5::Digest> gSeen;
 
-struct Sniffer : public SkPixelSerializer {
+struct Sniffer {
 
     std::string skpName;
 
@@ -52,8 +52,7 @@
     void sniff(const void* ptr, size_t len) {
         SkMD5 md5;
         md5.write(ptr, len);
-        SkMD5::Digest digest;
-        md5.finish(digest);
+        SkMD5::Digest digest = md5.finish();
 
         if (gSeen.contains(digest)) {
             return;
@@ -61,7 +60,7 @@
         gSeen.add(digest);
 
         sk_sp<SkData> data(SkData::MakeWithoutCopy(ptr, len));
-        std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
+        std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(data);
         if (!codec) {
             // FIXME: This code is currently unreachable because we create an empty generator when
             //        we fail to create a codec.
@@ -122,38 +121,32 @@
 
         gKnown++;
     }
-
-    bool onUseEncodedData(const void* ptr, size_t len) override {
-        this->sniff(ptr, len);
-        return true;
-    }
-    SkData* onEncode(const SkPixmap&) override { return nullptr; }
 };
 
 static bool get_images_from_file(const SkString& file) {
-    auto stream = SkStream::MakeFromFile(file.c_str());
-    sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream.get()));
-    if (!picture) {
-        return false;
-    }
-
-    SkDynamicMemoryWStream scratch;
     Sniffer sniff(file.c_str());
-    picture->serialize(&scratch, &sniff);
-    return true;
+    auto stream = SkStream::MakeFromFile(file.c_str());
+
+    SkDeserialProcs procs;
+    procs.fImageProc = [](const void* data, size_t size, void* ctx) -> sk_sp<SkImage> {
+        ((Sniffer*)ctx)->sniff(data, size);
+        return nullptr;
+    };
+    procs.fImageCtx = &sniff;
+    return SkPicture::MakeFromStream(stream.get(), &procs) != nullptr;
 }
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage(
+    CommandLineFlags::SetUsage(
             "Usage: get_images_from_skps -s <dir of skps> -o <dir for output images> --testDecode "
             "-j <output JSON path> --writeImages, --writeFailedImages\n");
 
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::Parse(argc, argv);
     const char* inputs = FLAGS_skps[0];
     gOutputDir = FLAGS_out[0];
 
     if (!sk_isdir(gOutputDir)) {
-        SkCommandLineFlags::PrintUsage();
+        CommandLineFlags::PrintUsage();
         return 1;
     }
 
@@ -187,34 +180,53 @@
        "totalSuccesses": 21,
      }
      */
-    Json::Value fRoot;
-    int totalFailures = 0;
-    for(auto it = gSkpToUnknownCount.cbegin(); it != gSkpToUnknownCount.cend(); ++it)
+
+    unsigned int totalFailures = 0,
+              totalUnsupported = 0;
+    SkDynamicMemoryWStream memStream;
+    SkJSONWriter writer(&memStream, SkJSONWriter::Mode::kPretty);
+    writer.beginObject();
     {
-        SkDebugf("%s %d\n", it->first.c_str(), it->second);
-        totalFailures += it->second;
-        fRoot["failures"][it->first.c_str()] = it->second;
-    }
-    fRoot["totalFailures"] = totalFailures;
-    int totalUnsupported = 0;
+        writer.beginObject("failures");
+        {
+            for(const auto& failure : gSkpToUnknownCount) {
+                SkDebugf("%s %d\n", failure.first.c_str(), failure.second);
+                totalFailures += failure.second;
+                writer.appendU32(failure.first.c_str(), failure.second);
+            }
+        }
+        writer.endObject();
+        writer.appendU32("totalFailures", totalFailures);
+
 #ifdef SK_DEBUG
-    for (const auto& unsupported : gSkpToUnsupportedCount) {
-        SkDebugf("%s %d\n", unsupported.first.c_str(), unsupported.second);
-        totalUnsupported += unsupported.second;
-        fRoot["unsupported"][unsupported.first] = unsupported.second;
-    }
-    fRoot["totalUnsupported"] = totalUnsupported;
+        writer.beginObject("unsupported");
+        {
+            for (const auto& unsupported : gSkpToUnsupportedCount) {
+                SkDebugf("%s %d\n", unsupported.first.c_str(), unsupported.second);
+                totalUnsupported += unsupported.second;
+                writer.appendHexU32(unsupported.first.c_str(), unsupported.second);
+            }
+
+        }
+        writer.endObject();
+        writer.appendU32("totalUnsupported", totalUnsupported);
 #endif
-    fRoot["totalSuccesses"] = gKnown;
-    SkDebugf("%d known, %d failures, %d unsupported\n", gKnown, totalFailures, totalUnsupported);
+
+        writer.appendS32("totalSuccesses", gKnown);
+        SkDebugf("%d known, %d failures, %d unsupported\n",
+                 gKnown, totalFailures, totalUnsupported);
+    }
+    writer.endObject();
+    writer.flush();
+
     if (totalFailures > 0 || totalUnsupported > 0) {
         if (!FLAGS_failuresJsonPath.isEmpty()) {
             SkDebugf("Writing failures to %s\n", FLAGS_failuresJsonPath[0]);
             SkFILEWStream stream(FLAGS_failuresJsonPath[0]);
-            stream.writeText(Json::StyledWriter().write(fRoot).c_str());
-            stream.flush();
+            auto jsonStream = memStream.detachAsStream();
+            stream.writeStream(jsonStream.get(), jsonStream->getLength());
         }
-        return -1;
     }
+
     return 0;
 }
diff --git a/src/third_party/skia/tools/git-sync-deps b/src/third_party/skia/tools/git-sync-deps
index 78449d9..c7379c0 100755
--- a/src/third_party/skia/tools/git-sync-deps
+++ b/src/third_party/skia/tools/git-sync-deps
@@ -11,8 +11,8 @@
   An optional list of deps_os values.
 
 Environment Variables:
-  GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of
-  ['git', 'git.exe', 'git.bat'] in your default path.
+  GIT_EXECUTABLE: path to "git" binary; if unset, will look for git in
+  your default path.
 
   GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset,
   will use the file ../DEPS relative to this script's directory.
@@ -43,7 +43,7 @@
       A string suitable for passing to subprocess functions, or None.
   """
   envgit = os.environ.get('GIT_EXECUTABLE')
-  searchlist = ['git', 'git.exe', 'git.bat']
+  searchlist = ['git']
   if envgit:
     searchlist.insert(0, envgit)
   with open(os.devnull, 'w') as devnull:
@@ -204,6 +204,10 @@
         raise Exception('%r is parent of %r' % (other_dir, directory))
   list_of_arg_lists = []
   for directory in sorted(dependencies):
+    if not isinstance(dependencies[directory], basestring):
+      if verbose:
+        print 'Skipping "%s".' % directory
+      continue
     if '@' in dependencies[directory]:
       repo, checkoutable = dependencies[directory].split('@', 1)
     else:
@@ -216,10 +220,6 @@
 
   multithread(git_checkout_to_directory, list_of_arg_lists)
 
-  for directory in deps_file.get('recursedeps', []):
-    recursive_path = os.path.join(deps_file_directory, directory, 'DEPS')
-    git_sync_deps(recursive_path, command_line_os_requests, verbose)
-
 
 def multithread(function, list_of_arg_lists):
   # for args in list_of_arg_lists:
diff --git a/src/third_party/skia/tools/gpu/FenceSync.h b/src/third_party/skia/tools/gpu/FenceSync.h
index b430f5d..146b3a2 100644
--- a/src/third_party/skia/tools/gpu/FenceSync.h
+++ b/src/third_party/skia/tools/gpu/FenceSync.h
@@ -8,7 +8,7 @@
 #ifndef FenceSync_DEFINED
 #define FenceSync_DEFINED
 
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
 
 namespace sk_gpu_test {
 
@@ -26,6 +26,8 @@
     virtual bool waitFence(PlatformFence) const = 0;
     virtual void deleteFence(PlatformFence) const = 0;
 
+    virtual bool validate() const { return true; }
+
     virtual ~FenceSync() {}
 };
 
diff --git a/src/third_party/skia/tools/gpu/GpuTimer.h b/src/third_party/skia/tools/gpu/GpuTimer.h
index 7678421..048dec7 100644
--- a/src/third_party/skia/tools/gpu/GpuTimer.h
+++ b/src/third_party/skia/tools/gpu/GpuTimer.h
@@ -8,8 +8,9 @@
 #ifndef GpuTimer_DEFINED
 #define GpuTimer_DEFINED
 
-#include "SkTypes.h"
-#include "SkExchange.h"
+#include "include/core/SkTypes.h"
+#include "src/core/SkExchange.h"
+
 #include <chrono>
 
 namespace sk_gpu_test {
diff --git a/src/third_party/skia/tools/gpu/GrContextFactory.cpp b/src/third_party/skia/tools/gpu/GrContextFactory.cpp
index 0686b79..d0defdc 100644
--- a/src/third_party/skia/tools/gpu/GrContextFactory.cpp
+++ b/src/third_party/skia/tools/gpu/GrContextFactory.cpp
@@ -6,29 +6,28 @@
  * found in the LICENSE file.
  */
 
-#include "GrContextFactory.h"
-#include "gl/GLTestContext.h"
+#include "src/gpu/GrContextPriv.h"
+#include "tools/gpu/GrContextFactory.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 #if SK_ANGLE
-    #include "gl/angle/GLTestContext_angle.h"
+    #include "tools/gpu/gl/angle/GLTestContext_angle.h"
 #endif
-#include "gl/command_buffer/GLTestContext_command_buffer.h"
-#include "gl/debug/DebugGLTestContext.h"
-#if SK_MESA
-    #include "gl/mesa/GLTestContext_mesa.h"
-#endif
+#include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
 #ifdef SK_VULKAN
-#include "vk/VkTestContext.h"
+#include "tools/gpu/vk/VkTestContext.h"
 #endif
 #ifdef SK_METAL
-#include "mtl/MtlTestContext.h"
+#include "tools/gpu/mtl/MtlTestContext.h"
 #endif
-#include "gl/null/NullGLTestContext.h"
-#include "gl/GrGLGpu.h"
-#include "mock/MockTestContext.h"
-#include "GrCaps.h"
+#ifdef SK_DAWN
+#include "tools/gpu/dawn/DawnTestContext.h"
+#endif
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/gl/GrGLGpu.h"
+#include "tools/gpu/mock/MockTestContext.h"
 
-#if defined(SK_BUILD_FOR_WIN32) && defined(SK_ENABLE_DISCRETE_GPU)
+#if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
 extern "C" {
     // NVIDIA documents that the presence and value of this symbol programmatically enable the high
     // performance GPU in laptops with switchable graphics.
@@ -54,9 +53,15 @@
 }
 
 void GrContextFactory::destroyContexts() {
-    for (Context& context : fContexts) {
+    // We must delete the test contexts in reverse order so that any child context is finished and
+    // deleted before a parent context. This relies on the fact that when we make a new context we
+    // append it to the end of fContexts array.
+    // TODO: Look into keeping a dependency dag for contexts and deletion order
+    for (int i = fContexts.count() - 1; i >= 0; --i) {
+        Context& context = fContexts[i];
+        SkScopeExit restore(nullptr);
         if (context.fTestContext) {
-            context.fTestContext->makeCurrent();
+            restore = context.fTestContext->makeCurrentAndAutoRestore();
         }
         if (!context.fGrContext->unique()) {
             context.fGrContext->releaseResourcesAndAbandonContext();
@@ -69,10 +74,15 @@
 }
 
 void GrContextFactory::abandonContexts() {
-    for (Context& context : fContexts) {
+    // We must abandon the test contexts in reverse order so that any child context is finished and
+    // abandoned before a parent context. This relies on the fact that when we make a new context we
+    // append it to the end of fContexts array.
+    // TODO: Look into keeping a dependency dag for contexts and deletion order
+    for (int i = fContexts.count() - 1; i >= 0; --i) {
+        Context& context = fContexts[i];
         if (!context.fAbandoned) {
             if (context.fTestContext) {
-                context.fTestContext->makeCurrent();
+                auto restore = context.fTestContext->makeCurrentAndAutoRestore();
                 context.fTestContext->testAbandon();
                 delete(context.fTestContext);
                 context.fTestContext = nullptr;
@@ -84,10 +94,16 @@
 }
 
 void GrContextFactory::releaseResourcesAndAbandonContexts() {
-    for (Context& context : fContexts) {
+    // We must abandon the test contexts in reverse order so that any child context is finished and
+    // abandoned before a parent context. This relies on the fact that when we make a new context we
+    // append it to the end of fContexts array.
+    // TODO: Look into keeping a dependency dag for contexts and deletion order
+    for (int i = fContexts.count() - 1; i >= 0; --i) {
+        Context& context = fContexts[i];
+        SkScopeExit restore(nullptr);
         if (!context.fAbandoned) {
             if (context.fTestContext) {
-                context.fTestContext->makeCurrent();
+                restore = context.fTestContext->makeCurrentAndAutoRestore();
             }
             context.fGrContext->releaseResourcesAndAbandonContext();
             context.fAbandoned = true;
@@ -116,7 +132,8 @@
             context.fShareIndex == shareIndex &&
             !context.fAbandoned) {
             context.fTestContext->makeCurrent();
-            return ContextInfo(context.fType, context.fTestContext, context.fGrContext);
+            return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
+                               context.fOptions);
         }
     }
 
@@ -133,11 +150,9 @@
     }
 
     std::unique_ptr<TestContext> testCtx;
-    GrBackendContext backendContext = 0;
-    sk_sp<const GrGLInterface> glInterface;
-    GrBackend backend = ContextTypeBackend(type);
+    GrBackendApi backend = ContextTypeBackend(type);
     switch (backend) {
-        case kOpenGL_GrBackend: {
+        case GrBackendApi::kOpenGL: {
             GLTestContext* glShareContext = masterContext
                     ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
             GLTestContext* glCtx;
@@ -175,18 +190,6 @@
                     glCtx = CommandBufferGLTestContext::Create(glShareContext);
                     break;
 #endif
-#if SK_MESA
-                case kMESA_ContextType:
-                    glCtx = CreateMesaGLTestContext(glShareContext);
-                    break;
-#endif
-                case kNullGL_ContextType:
-                    glCtx = CreateNullGLTestContext(
-                            ContextOverrides::kRequireNVPRSupport & overrides, glShareContext);
-                    break;
-                case kDebugGL_ContextType:
-                    glCtx = CreateDebugGLTestContext(glShareContext);
-                    break;
                 default:
                     return ContextInfo();
             }
@@ -194,18 +197,13 @@
                 return ContextInfo();
             }
             testCtx.reset(glCtx);
-            glInterface.reset(SkRef(glCtx->gl()));
-            backendContext = reinterpret_cast<GrBackendContext>(glInterface.get());
             break;
         }
 #ifdef SK_VULKAN
-        case kVulkan_GrBackend: {
+        case GrBackendApi::kVulkan: {
             VkTestContext* vkSharedContext = masterContext
                     ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
             SkASSERT(kVulkan_ContextType == type);
-            if (ContextOverrides::kRequireNVPRSupport & overrides) {
-                return ContextInfo();
-            }
             testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
             if (!testCtx) {
                 return ContextInfo();
@@ -220,74 +218,61 @@
                     fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
                 }
             }
-            backendContext = testCtx->backendContext();
             break;
         }
 #endif
 #ifdef SK_METAL
-        case kMetal_GrBackend: {
-            SkASSERT(!masterContext);
-            testCtx.reset(CreatePlatformMtlTestContext(nullptr));
+        case GrBackendApi::kMetal: {
+            MtlTestContext* mtlSharedContext = masterContext
+                    ? static_cast<MtlTestContext*>(masterContext->fTestContext) : nullptr;
+            SkASSERT(kMetal_ContextType == type);
+            testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
             if (!testCtx) {
                 return ContextInfo();
             }
             break;
         }
 #endif
-        case kMock_GrBackend: {
-            TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
-            SkASSERT(kMock_ContextType == type);
-            if (ContextOverrides::kRequireNVPRSupport & overrides) {
+#ifdef SK_DAWN
+        case GrBackendApi::kDawn: {
+            DawnTestContext* dawnSharedContext = masterContext
+                    ? static_cast<DawnTestContext*>(masterContext->fTestContext) : nullptr;
+            testCtx.reset(CreatePlatformDawnTestContext(dawnSharedContext));
+            if (!testCtx) {
                 return ContextInfo();
             }
+            break;
+        }
+#endif
+        case GrBackendApi::kMock: {
+            TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
+            SkASSERT(kMock_ContextType == type);
             testCtx.reset(CreateMockTestContext(sharedContext));
             if (!testCtx) {
                 return ContextInfo();
             }
-            backendContext = testCtx->backendContext();
             break;
         }
         default:
             return ContextInfo();
     }
-    testCtx->makeCurrent();
+
     SkASSERT(testCtx && testCtx->backend() == backend);
     GrContextOptions grOptions = fGlobalOptions;
-    if (ContextOverrides::kDisableNVPR & overrides) {
-        grOptions.fSuppressPathRendering = true;
-    }
-    if (ContextOverrides::kUseInstanced & overrides) {
-        grOptions.fEnableInstancedRendering = true;
-    }
-    if (ContextOverrides::kAllowSRGBWithoutDecodeControl & overrides) {
-        grOptions.fRequireDecodeDisableForSRGB = false;
-    }
     if (ContextOverrides::kAvoidStencilBuffers & overrides) {
         grOptions.fAvoidStencilBuffers = true;
     }
-    sk_sp<GrContext> grCtx = testCtx->makeGrContext(grOptions);
-    if (!grCtx.get() && kMetal_GrBackend != backend) {
-        grCtx.reset(GrContext::Create(backend, backendContext, grOptions));
+    sk_sp<GrContext> grCtx;
+    {
+        auto restore = testCtx->makeCurrentAndAutoRestore();
+        grCtx = testCtx->makeGrContext(grOptions);
     }
     if (!grCtx.get()) {
         return ContextInfo();
     }
-    if (ContextOverrides::kRequireNVPRSupport & overrides) {
-        if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) {
-            return ContextInfo();
-        }
-    }
-    if (ContextOverrides::kUseInstanced & overrides) {
-        if (GrCaps::InstancedSupport::kNone == grCtx->caps()->instancedSupport()) {
-            return ContextInfo();
-        }
-    }
-    if (ContextOverrides::kRequireSRGBSupport & overrides) {
-        if (!grCtx->caps()->srgbSupport()) {
-            return ContextInfo();
-        }
-    }
 
+    // We must always add new contexts by pushing to the back so that when we delete them we delete
+    // them in reverse order in which they were made.
     Context& context = fContexts.push_back();
     context.fBackend = backend;
     context.fTestContext = testCtx.release();
@@ -297,7 +282,9 @@
     context.fAbandoned = false;
     context.fShareContext = shareContext;
     context.fShareIndex = shareIndex;
-    return ContextInfo(context.fType, context.fTestContext, context.fGrContext);
+    context.fOptions = grOptions;
+    context.fTestContext->makeCurrent();
+    return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
 }
 
 ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
diff --git a/src/third_party/skia/tools/gpu/GrContextFactory.h b/src/third_party/skia/tools/gpu/GrContextFactory.h
index a13aeb7..d1b7fd5 100644
--- a/src/third_party/skia/tools/gpu/GrContextFactory.h
+++ b/src/third_party/skia/tools/gpu/GrContextFactory.h
@@ -8,11 +8,11 @@
 #ifndef GrContextFactory_DEFINED
 #define GrContextFactory_DEFINED
 
-#include "GrContext.h"
-#include "GrContextOptions.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/GrContextOptions.h"
 
-#include "gl/GLTestContext.h"
-#include "SkTArray.h"
+#include "include/private/SkTArray.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 struct GrVkBackendContext;
 
@@ -39,11 +39,9 @@
         kANGLE_GL_ES2_ContextType,   //! ANGLE on OpenGL OpenGL ES 2 context.
         kANGLE_GL_ES3_ContextType,   //! ANGLE on OpenGL OpenGL ES 3 context.
         kCommandBuffer_ContextType,  //! Chromium command buffer OpenGL ES context.
-        kMESA_ContextType,           //! MESA OpenGL context
-        kNullGL_ContextType,         //! Non-rendering OpenGL mock context.
-        kDebugGL_ContextType,        //! Non-rendering, state verifying OpenGL context.
         kVulkan_ContextType,         //! Vulkan
         kMetal_ContextType,          //! Metal
+        kDawn_ContextType,           //! Dawn
         kMock_ContextType,           //! Mock context that does not draw.
         kLastContextType = kMock_ContextType
     };
@@ -56,19 +54,11 @@
      */
     enum class ContextOverrides {
         kNone                          = 0x0,
-        kDisableNVPR                   = 0x1,
-        kUseInstanced                  = 0x2,
-        kAllowSRGBWithoutDecodeControl = 0x4,
-        kAvoidStencilBuffers           = 0x8,
-
-        kRequireNVPRSupport            = 0x10,
-        kRequireSRGBSupport            = 0x20,
+        kAvoidStencilBuffers           = 0x1,
     };
 
     static bool IsRenderingContext(ContextType type) {
         switch (type) {
-            case kNullGL_ContextType:
-            case kDebugGL_ContextType:
             case kMock_ContextType:
                 return false;
             default:
@@ -76,16 +66,18 @@
         }
     }
 
-    static GrBackend ContextTypeBackend(ContextType type) {
+    static GrBackendApi ContextTypeBackend(ContextType type) {
         switch (type) {
             case kVulkan_ContextType:
-                return kVulkan_GrBackend;
+                return GrBackendApi::kVulkan;
             case kMetal_ContextType:
-                return kMetal_GrBackend;
+                return GrBackendApi::kMetal;
+            case kDawn_ContextType:
+                return GrBackendApi::kDawn;
             case kMock_ContextType:
-                return kMock_GrBackend;
+                return GrBackendApi::kMock;
             default:
-                return kOpenGL_GrBackend;
+                return GrBackendApi::kOpenGL;
         }
     }
 
@@ -107,21 +99,16 @@
                 return "ANGLE GL ES3";
             case kCommandBuffer_ContextType:
                 return "Command Buffer";
-            case kMESA_ContextType:
-                return "Mesa";
-            case kNullGL_ContextType:
-                return "Null GL";
-            case kDebugGL_ContextType:
-                return "Debug GL";
             case kVulkan_ContextType:
                 return "Vulkan";
             case kMetal_ContextType:
                 return "Metal";
+            case kDawn_ContextType:
+                return "Dawn";
             case kMock_ContextType:
                 return "Mock";
         }
-        SkFAIL("Unreachable");
-        return "Unknown";
+        SK_ABORT("Unreachable");
     }
 
     explicit GrContextFactory(const GrContextOptions& opts);
@@ -136,8 +123,7 @@
     /**
      * Get a context initialized with a type of GL context. It also makes the GL context current.
      */
-    ContextInfo getContextInfo(ContextType type,
-                               ContextOverrides overrides = ContextOverrides::kNone);
+    ContextInfo getContextInfo(ContextType type, ContextOverrides = ContextOverrides::kNone);
 
     /**
      * Get a context in the same share group as the passed in GrContext, with the same type and
@@ -159,13 +145,14 @@
     struct Context {
         ContextType       fType;
         ContextOverrides  fOverrides;
-        GrBackend         fBackend;
+        GrContextOptions  fOptions;
+        GrBackendApi      fBackend;
         TestContext*      fTestContext;
         GrContext*        fGrContext;
         GrContext*        fShareContext;
         uint32_t          fShareIndex;
 
-        bool            fAbandoned;
+        bool              fAbandoned;
     };
     SkTArray<Context, true>         fContexts;
     std::unique_ptr<GLTestContext>  fSentinelGLContext;
@@ -178,30 +165,29 @@
     ContextInfo& operator=(const ContextInfo&) = default;
 
     GrContextFactory::ContextType type() const { return fType; }
-    GrBackend backend() const { return GrContextFactory::ContextTypeBackend(fType); }
+    GrBackendApi backend() const { return GrContextFactory::ContextTypeBackend(fType); }
 
     GrContext* grContext() const { return fGrContext; }
 
     TestContext* testContext() const { return fTestContext; }
 
     GLTestContext* glContext() const {
-        SkASSERT(kOpenGL_GrBackend == this->backend());
+        SkASSERT(GrBackendApi::kOpenGL == this->backend());
         return static_cast<GLTestContext*>(fTestContext);
     }
 
+    const GrContextOptions& options() const { return fOptions; }
+
 private:
-    ContextInfo(GrContextFactory::ContextType type,
-                TestContext* testContext,
-                GrContext* grContext)
-        : fType(type)
-        , fTestContext(testContext)
-        , fGrContext(grContext) {
-    }
+    ContextInfo(GrContextFactory::ContextType type, TestContext* testContext, GrContext* grContext,
+                const GrContextOptions& options)
+            : fType(type), fTestContext(testContext), fGrContext(grContext), fOptions(options) {}
 
     GrContextFactory::ContextType fType = GrContextFactory::kGL_ContextType;
     // Valid until the factory destroys it via abandonContexts() or destroyContexts().
-    TestContext*    fTestContext = nullptr;
-    GrContext*      fGrContext = nullptr;
+    TestContext* fTestContext = nullptr;
+    GrContext* fGrContext = nullptr;
+    GrContextOptions fOptions;
 
     friend class GrContextFactory;
 };
diff --git a/src/third_party/skia/tools/gpu/GrTest.cpp b/src/third_party/skia/tools/gpu/GrTest.cpp
index c5af01e..70d8692 100644
--- a/src/third_party/skia/tools/gpu/GrTest.cpp
+++ b/src/third_party/skia/tools/gpu/GrTest.cpp
@@ -5,233 +5,36 @@
  * found in the LICENSE file.
  */
 
-#include "GrTest.h"
+#include "include/core/SkString.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/gpu/GrTexture.h"
+#include "include/private/GrRecordingContext.h"
+#include "include/private/SkTo.h"
+#include "src/core/SkMathPriv.h"
+#include "src/gpu/GrClip.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrDrawOpAtlas.h"
+#include "src/gpu/GrDrawingManager.h"
+#include "src/gpu/GrGpu.h"
+#include "src/gpu/GrGpuResourceCacheAccess.h"
+#include "src/gpu/GrMemoryPool.h"
+#include "src/gpu/GrRecordingContextPriv.h"
+#include "src/gpu/GrRenderTargetContext.h"
+#include "src/gpu/GrRenderTargetContextPriv.h"
+#include "src/gpu/GrRenderTargetProxy.h"
+#include "src/gpu/GrResourceCache.h"
+#include "src/gpu/GrSemaphore.h"
+#include "src/gpu/GrSurfaceContextPriv.h"
+#include "src/gpu/SkGr.h"
+#include "src/gpu/ccpr/GrCCPathCache.h"
+#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
+#include "src/gpu/ops/GrMeshDrawOp.h"
+#include "src/gpu/text/GrStrikeCache.h"
+#include "src/gpu/text/GrTextBlobCache.h"
+#include "src/image/SkImage_Gpu.h"
+
 #include <algorithm>
-#include "GrBackendSurface.h"
-#include "GrContextOptions.h"
-#include "GrContextPriv.h"
-#include "GrDrawOpAtlas.h"
-#include "GrDrawingManager.h"
-#include "GrGpu.h"
-#include "GrGpuResourceCacheAccess.h"
-#include "GrRenderTargetContext.h"
-#include "GrRenderTargetContextPriv.h"
-#include "GrRenderTargetProxy.h"
-#include "GrResourceCache.h"
-#include "GrSemaphore.h"
-#include "GrSurfaceContextPriv.h"
-#include "GrTexture.h"
-#include "SkGr.h"
-#include "SkImage_Gpu.h"
-#include "SkMathPriv.h"
-#include "SkString.h"
-#include "ops/GrMeshDrawOp.h"
-#include "text/GrAtlasGlyphCache.h"
-#include "text/GrTextBlobCache.h"
-
-namespace GrTest {
-
-void SetupAlwaysEvictAtlas(GrContext* context) {
-    // These sizes were selected because they allow each atlas to hold a single plot and will thus
-    // stress the atlas
-    int dim = GrDrawOpAtlas::kGlyphMaxDim;
-    GrDrawOpAtlasConfig configs[3];
-    configs[kA8_GrMaskFormat].fWidth = dim;
-    configs[kA8_GrMaskFormat].fHeight = dim;
-    configs[kA8_GrMaskFormat].fLog2Width = SkNextLog2(dim);
-    configs[kA8_GrMaskFormat].fLog2Height = SkNextLog2(dim);
-    configs[kA8_GrMaskFormat].fPlotWidth = dim;
-    configs[kA8_GrMaskFormat].fPlotHeight = dim;
-
-    configs[kA565_GrMaskFormat].fWidth = dim;
-    configs[kA565_GrMaskFormat].fHeight = dim;
-    configs[kA565_GrMaskFormat].fLog2Width = SkNextLog2(dim);
-    configs[kA565_GrMaskFormat].fLog2Height = SkNextLog2(dim);
-    configs[kA565_GrMaskFormat].fPlotWidth = dim;
-    configs[kA565_GrMaskFormat].fPlotHeight = dim;
-
-    configs[kARGB_GrMaskFormat].fWidth = dim;
-    configs[kARGB_GrMaskFormat].fHeight = dim;
-    configs[kARGB_GrMaskFormat].fLog2Width = SkNextLog2(dim);
-    configs[kARGB_GrMaskFormat].fLog2Height = SkNextLog2(dim);
-    configs[kARGB_GrMaskFormat].fPlotWidth = dim;
-    configs[kARGB_GrMaskFormat].fPlotHeight = dim;
-
-    context->setTextContextAtlasSizes_ForTesting(configs);
-}
-
-GrBackendTexture CreateBackendTexture(GrBackend backend, int width, int height,
-                                      GrPixelConfig config, GrBackendObject handle) {
-    switch (backend) {
-#ifdef SK_VULKAN
-        case kVulkan_GrBackend: {
-            GrVkImageInfo* vkInfo = (GrVkImageInfo*)(handle);
-            return GrBackendTexture(width, height, *vkInfo);
-        }
-#endif
-        case kOpenGL_GrBackend: {
-            GrGLTextureInfo* glInfo = (GrGLTextureInfo*)(handle);
-            return GrBackendTexture(width, height, config, *glInfo);
-        }
-        case kMock_GrBackend: {
-            GrMockTextureInfo* mockInfo = (GrMockTextureInfo*)(handle);
-            return GrBackendTexture(width, height, config, *mockInfo);
-        }
-        default:
-            return GrBackendTexture();
-    }
-}
-
-}  // namespace GrTest
-
-bool GrSurfaceProxy::isWrapped_ForTesting() const {
-    return SkToBool(fTarget);
-}
-
-bool GrRenderTargetContext::isWrapped_ForTesting() const {
-    return fRenderTargetProxy->isWrapped_ForTesting();
-}
-
-void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) {
-    fTextBlobCache->setBudget(bytes);
-}
-
-void GrContext::setTextContextAtlasSizes_ForTesting(const GrDrawOpAtlasConfig* configs) {
-    fAtlasGlyphCache->setAtlasSizes_ForTesting(configs);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrContext::purgeAllUnlockedResources() {
-    fResourceCache->purgeAllUnlocked();
-}
-
-void GrContext::resetGpuStats() const {
-#if GR_GPU_STATS
-    fGpu->stats()->reset();
-#endif
-}
-
-void GrContext::dumpCacheStats(SkString* out) const {
-#if GR_CACHE_STATS
-    fResourceCache->dumpStats(out);
-#endif
-}
-
-void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys,
-                                            SkTArray<double>* values) const {
-#if GR_CACHE_STATS
-    fResourceCache->dumpStatsKeyValuePairs(keys, values);
-#endif
-}
-
-void GrContext::printCacheStats() const {
-    SkString out;
-    this->dumpCacheStats(&out);
-    SkDebugf("%s", out.c_str());
-}
-
-void GrContext::dumpGpuStats(SkString* out) const {
-#if GR_GPU_STATS
-    return fGpu->stats()->dump(out);
-#endif
-}
-
-void GrContext::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys,
-                                          SkTArray<double>* values) const {
-#if GR_GPU_STATS
-    return fGpu->stats()->dumpKeyValuePairs(keys, values);
-#endif
-}
-
-void GrContext::printGpuStats() const {
-    SkString out;
-    this->dumpGpuStats(&out);
-    SkDebugf("%s", out.c_str());
-}
-
-sk_sp<SkImage> GrContext::getFontAtlasImage_ForTesting(GrMaskFormat format) {
-    GrAtlasGlyphCache* cache = this->getAtlasGlyphCache();
-
-    sk_sp<GrTextureProxy> proxy = cache->getProxy(format);
-    if (!proxy) {
-        return nullptr;
-    }
-
-    SkASSERT(proxy->priv().isExact());
-    sk_sp<SkImage> image(new SkImage_Gpu(this, kNeedNewImageUniqueID, kPremul_SkAlphaType,
-                                         std::move(proxy), nullptr, SkBudgeted::kNo));
-    return image;
-}
-
-#if GR_GPU_STATS
-void GrGpu::Stats::dump(SkString* out) {
-    out->appendf("Render Target Binds: %d\n", fRenderTargetBinds);
-    out->appendf("Shader Compilations: %d\n", fShaderCompilations);
-    out->appendf("Textures Created: %d\n", fTextureCreates);
-    out->appendf("Texture Uploads: %d\n", fTextureUploads);
-    out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
-    out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
-    out->appendf("Number of draws: %d\n", fNumDraws);
-}
-
-void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
-    keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
-    keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
-    keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads);
-    keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws);
-    keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumFailedDraws);
-}
-
-#endif
-
-#if GR_CACHE_STATS
-void GrResourceCache::getStats(Stats* stats) const {
-    stats->reset();
-
-    stats->fTotal = this->getResourceCount();
-    stats->fNumNonPurgeable = fNonpurgeableResources.count();
-    stats->fNumPurgeable = fPurgeableQueue.count();
-
-    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
-        stats->update(fNonpurgeableResources[i]);
-    }
-    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
-        stats->update(fPurgeableQueue.at(i));
-    }
-}
-
-void GrResourceCache::dumpStats(SkString* out) const {
-    this->validate();
-
-    Stats stats;
-
-    this->getStats(&stats);
-
-    float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
-    float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
-
-    out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes);
-    out->appendf("\t\tEntry Count: current %d"
-                 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), high %d\n",
-                 stats.fTotal, fBudgetedCount, stats.fWrapped, stats.fNumNonPurgeable,
-                 stats.fScratch, countUtilization, fHighWaterCount);
-    out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
-                 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
-                 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
-}
-
-void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys,
-                                             SkTArray<double>* values) const {
-    this->validate();
-
-    Stats stats;
-    this->getStats(&stats);
-
-    keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable);
-}
-
-#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -256,47 +59,98 @@
 #define ASSERT_SINGLE_OWNER \
     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
 
-uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDrawOp> op) {
+
+uint32_t GrRenderTargetContextPriv::testingOnly_getOpsTaskID() {
+    return fRenderTargetContext->getOpsTask()->uniqueID();
+}
+
+void GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDrawOp> op) {
+    this->testingOnly_addDrawOp(GrNoClip(), std::move(op));
+}
+
+void GrRenderTargetContextPriv::testingOnly_addDrawOp(
+        const GrClip& clip,
+        std::unique_ptr<GrDrawOp> op,
+        const std::function<GrRenderTargetContext::WillAddOpFn>& willAddFn) {
     ASSERT_SINGLE_OWNER
-    if (fRenderTargetContext->drawingManager()->wasAbandoned()) {
-        return SK_InvalidUniqueID;
+    if (fRenderTargetContext->fContext->priv().abandoned()) {
+        fRenderTargetContext->fContext->priv().opMemoryPool()->release(std::move(op));
+        return;
     }
     SkDEBUGCODE(fRenderTargetContext->validate());
-    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
+    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->auditTrail(),
                               "GrRenderTargetContext::testingOnly_addDrawOp");
-    return fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op));
+    fRenderTargetContext->addDrawOp(clip, std::move(op), willAddFn);
 }
 
 #undef ASSERT_SINGLE_OWNER
 
-///////////////////////////////////////////////////////////////////////////////
-
-GrRenderTargetFlags GrRenderTargetProxy::testingOnly_getFlags() const {
-    return fRenderTargetFlags;
-}
-
 //////////////////////////////////////////////////////////////////////////////
 
-void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) {
-    fContext->flush();
-    fContext->fDrawingManager->testingOnly_removeOnFlushCallbackObject(cb);
+void GrCoverageCountingPathRenderer::testingOnly_drawPathDirectly(const DrawPathArgs& args) {
+    // Call onDrawPath() directly: We want to test paths that might fail onCanDrawPath() simply for
+    // performance reasons, and GrPathRenderer::drawPath() assert that this call returns true.
+    // The test is responsible to not draw any paths that CCPR is not actually capable of.
+    this->onDrawPath(args);
 }
 
-void GrDrawingManager::testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject* cb) {
-    int n = std::find(fOnFlushCBObjects.begin(), fOnFlushCBObjects.end(), cb) -
-            fOnFlushCBObjects.begin();
-    SkASSERT(n < fOnFlushCBObjects.count());
-    fOnFlushCBObjects.removeShuffle(n);
+const GrCCPerFlushResources*
+GrCoverageCountingPathRenderer::testingOnly_getCurrentFlushResources() {
+    SkASSERT(fFlushing);
+    if (fFlushingPaths.empty()) {
+        return nullptr;
+    }
+    // All pending paths should share the same resources.
+    const GrCCPerFlushResources* resources = fFlushingPaths.front()->fFlushResources.get();
+#ifdef SK_DEBUG
+    for (const auto& flushingPaths : fFlushingPaths) {
+        SkASSERT(flushingPaths->fFlushResources.get() == resources);
+    }
+#endif
+    return resources;
 }
 
+const GrCCPathCache* GrCoverageCountingPathRenderer::testingOnly_getPathCache() const {
+    return fPathCache.get();
+}
+
+const GrTexture* GrCCPerFlushResources::testingOnly_frontCopyAtlasTexture() const {
+    if (fCopyAtlasStack.empty()) {
+        return nullptr;
+    }
+    const GrTextureProxy* proxy = fCopyAtlasStack.front().textureProxy();
+    return (proxy) ? proxy->peekTexture() : nullptr;
+}
+
+const GrTexture* GrCCPerFlushResources::testingOnly_frontRenderedAtlasTexture() const {
+    if (fRenderedAtlasStack.empty()) {
+        return nullptr;
+    }
+    const GrTextureProxy* proxy = fRenderedAtlasStack.front().textureProxy();
+    return (proxy) ? proxy->peekTexture() : nullptr;
+}
+
+const SkTHashTable<GrCCPathCache::HashNode, const GrCCPathCache::Key&>&
+GrCCPathCache::testingOnly_getHashTable() const {
+    return fHashTable;
+}
+
+const SkTInternalLList<GrCCPathCacheEntry>& GrCCPathCache::testingOnly_getLRU() const {
+    return fLRU;
+}
+
+int GrCCPathCacheEntry::testingOnly_peekOnFlushRefCnt() const { return fOnFlushRefCnt; }
+
+int GrCCCachedAtlas::testingOnly_peekOnFlushRefCnt() const { return fOnFlushRefCnt; }
+
 //////////////////////////////////////////////////////////////////////////////
 
 #define DRAW_OP_TEST_EXTERN(Op) \
-    extern std::unique_ptr<GrDrawOp> Op##__Test(GrPaint&&, SkRandom*, GrContext*, GrFSAAType)
+    extern std::unique_ptr<GrDrawOp> Op##__Test(GrPaint&&, SkRandom*, \
+                                                GrRecordingContext*, int numSamples)
 #define DRAW_OP_TEST_ENTRY(Op) Op##__Test
 
 DRAW_OP_TEST_EXTERN(AAConvexPathOp);
-DRAW_OP_TEST_EXTERN(AAFillRectOp);
 DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp);
 DRAW_OP_TEST_EXTERN(AAHairlineOp);
 DRAW_OP_TEST_EXTERN(AAStrokeRectOp);
@@ -305,10 +159,10 @@
 DRAW_OP_TEST_EXTERN(DefaultPathOp);
 DRAW_OP_TEST_EXTERN(DIEllipseOp);
 DRAW_OP_TEST_EXTERN(EllipseOp);
+DRAW_OP_TEST_EXTERN(FillRectOp);
 DRAW_OP_TEST_EXTERN(GrAtlasTextOp);
-DRAW_OP_TEST_EXTERN(GrDrawAtlasOp);
-DRAW_OP_TEST_EXTERN(GrDrawVerticesOp);
-DRAW_OP_TEST_EXTERN(NonAAFillRectOp);
+DRAW_OP_TEST_EXTERN(DrawAtlasOp);
+DRAW_OP_TEST_EXTERN(DrawVerticesOp);
 DRAW_OP_TEST_EXTERN(NonAALatticeOp);
 DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp);
 DRAW_OP_TEST_EXTERN(ShadowRRectOp);
@@ -316,38 +170,40 @@
 DRAW_OP_TEST_EXTERN(RegionOp);
 DRAW_OP_TEST_EXTERN(RRectOp);
 DRAW_OP_TEST_EXTERN(TesselatingPathOp);
+DRAW_OP_TEST_EXTERN(TextureOp);
 
 void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext, GrPaint&& paint) {
-    GrContext* context = renderTargetContext->surfPriv().getContext();
-    using MakeDrawOpFn = std::unique_ptr<GrDrawOp>(GrPaint&&, SkRandom*, GrContext*, GrFSAAType);
+    auto context = renderTargetContext->surfPriv().getContext();
+    using MakeDrawOpFn = std::unique_ptr<GrDrawOp>(GrPaint&&, SkRandom*,
+                                                   GrRecordingContext*, int numSamples);
     static constexpr MakeDrawOpFn* gFactories[] = {
-        DRAW_OP_TEST_ENTRY(AAConvexPathOp),
-        DRAW_OP_TEST_ENTRY(AAFillRectOp),
-        DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp),
-        DRAW_OP_TEST_ENTRY(AAHairlineOp),
-        DRAW_OP_TEST_ENTRY(AAStrokeRectOp),
-        DRAW_OP_TEST_ENTRY(CircleOp),
-        DRAW_OP_TEST_ENTRY(DashOp),
-        DRAW_OP_TEST_ENTRY(DefaultPathOp),
-        DRAW_OP_TEST_ENTRY(DIEllipseOp),
-        DRAW_OP_TEST_ENTRY(EllipseOp),
-        DRAW_OP_TEST_ENTRY(GrAtlasTextOp),
-        DRAW_OP_TEST_ENTRY(GrDrawAtlasOp),
-        DRAW_OP_TEST_ENTRY(GrDrawVerticesOp),
-        DRAW_OP_TEST_ENTRY(NonAAFillRectOp),
-        DRAW_OP_TEST_ENTRY(NonAALatticeOp),
-        DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp),
-        DRAW_OP_TEST_ENTRY(ShadowRRectOp),
-        DRAW_OP_TEST_ENTRY(SmallPathOp),
-        DRAW_OP_TEST_ENTRY(RegionOp),
-        DRAW_OP_TEST_ENTRY(RRectOp),
-        DRAW_OP_TEST_ENTRY(TesselatingPathOp),
+            DRAW_OP_TEST_ENTRY(AAConvexPathOp),
+            DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp),
+            DRAW_OP_TEST_ENTRY(AAHairlineOp),
+            DRAW_OP_TEST_ENTRY(AAStrokeRectOp),
+            DRAW_OP_TEST_ENTRY(CircleOp),
+            DRAW_OP_TEST_ENTRY(DashOp),
+            DRAW_OP_TEST_ENTRY(DefaultPathOp),
+            DRAW_OP_TEST_ENTRY(DIEllipseOp),
+            DRAW_OP_TEST_ENTRY(EllipseOp),
+            DRAW_OP_TEST_ENTRY(FillRectOp),
+            DRAW_OP_TEST_ENTRY(GrAtlasTextOp),
+            DRAW_OP_TEST_ENTRY(DrawAtlasOp),
+            DRAW_OP_TEST_ENTRY(DrawVerticesOp),
+            DRAW_OP_TEST_ENTRY(NonAALatticeOp),
+            DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp),
+            DRAW_OP_TEST_ENTRY(ShadowRRectOp),
+            DRAW_OP_TEST_ENTRY(SmallPathOp),
+            DRAW_OP_TEST_ENTRY(RegionOp),
+            DRAW_OP_TEST_ENTRY(RRectOp),
+            DRAW_OP_TEST_ENTRY(TesselatingPathOp),
+            DRAW_OP_TEST_ENTRY(TextureOp),
     };
 
     static constexpr size_t kTotal = SK_ARRAY_COUNT(gFactories);
     uint32_t index = random->nextULessThan(static_cast<uint32_t>(kTotal));
     auto op = gFactories[index](
-            std::move(paint), random, context, renderTargetContext->fsaaType());
+            std::move(paint), random, context, renderTargetContext->numSamples());
     SkASSERT(op);
     renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
 }
diff --git a/src/third_party/skia/tools/gpu/GrTest.h b/src/third_party/skia/tools/gpu/GrTest.h
deleted file mode 100644
index d4a4c6d..0000000
--- a/src/third_party/skia/tools/gpu/GrTest.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrTest_DEFINED
-#define GrTest_DEFINED
-
-#include "GrBackendSurface.h"
-#include "GrContext.h"
-
-namespace GrTest {
-    /**
-     * Forces the GrContext to use a small atlas which only has room for one plot and will thus
-     * constantly be evicting entries
-     */
-    void SetupAlwaysEvictAtlas(GrContext*);
-
-    GrBackendTexture CreateBackendTexture(GrBackend, int width, int height,
-                                          GrPixelConfig, GrBackendObject);
-};
-
-#endif
diff --git a/src/third_party/skia/tools/gpu/MemoryCache.cpp b/src/third_party/skia/tools/gpu/MemoryCache.cpp
new file mode 100644
index 0000000..4da7fd7
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/MemoryCache.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "include/utils/SkBase64.h"
+#include "src/core/SkMD5.h"
+#include "src/gpu/GrPersistentCacheUtils.h"
+#include "tools/gpu/MemoryCache.h"
+
+#if defined(SK_VULKAN)
+#include "src/gpu/vk/GrVkGpu.h"
+#endif
+
+// Change this to 1 to log cache hits/misses/stores using SkDebugf.
+#define LOG_MEMORY_CACHE 0
+
+static SkString data_to_str(const SkData& data) {
+    size_t encodeLength = SkBase64::Encode(data.data(), data.size(), nullptr);
+    SkString str;
+    str.resize(encodeLength);
+    SkBase64::Encode(data.data(), data.size(), str.writable_str());
+    static constexpr size_t kMaxLength = 60;
+    static constexpr char kTail[] = "...";
+    static const size_t kTailLen = strlen(kTail);
+    bool overlength = encodeLength > kMaxLength;
+    if (overlength) {
+        str = SkString(str.c_str(), kMaxLength - kTailLen);
+        str.append(kTail);
+    }
+    return str;
+}
+
+namespace sk_gpu_test {
+
+sk_sp<SkData> MemoryCache::load(const SkData& key) {
+    auto result = fMap.find(key);
+    if (result == fMap.end()) {
+        if (LOG_MEMORY_CACHE) {
+            SkDebugf("Load Key: %s\n\tNot Found.\n\n", data_to_str(key).c_str());
+        }
+        ++fCacheMissCnt;
+        return nullptr;
+    }
+    if (LOG_MEMORY_CACHE) {
+        SkDebugf("Load Key: %s\n\tFound Data: %s\n\n", data_to_str(key).c_str(),
+                 data_to_str(*result->second.fData).c_str());
+    }
+    result->second.fHitCount++;
+    return result->second.fData;
+}
+
+void MemoryCache::store(const SkData& key, const SkData& data) {
+    if (LOG_MEMORY_CACHE) {
+        SkDebugf("Store Key: %s\n\tData: %s\n\n", data_to_str(key).c_str(),
+                 data_to_str(data).c_str());
+    }
+    fMap[Key(key)] = Value(data);
+}
+
+void MemoryCache::writeShadersToDisk(const char* path, GrBackendApi api) {
+    if (GrBackendApi::kOpenGL != api && GrBackendApi::kVulkan != api) {
+        return;
+    }
+
+    for (auto it = fMap.begin(); it != fMap.end(); ++it) {
+        SkMD5 hash;
+        size_t bytesToHash = it->first.fKey->size();
+#if defined(SK_VULKAN)
+        if (GrBackendApi::kVulkan == api) {
+            // Vulkan stores two kinds of data in the cache (shaders and pipelines). The last four
+            // bytes of the key identify which one we have. We only want to extract shaders.
+            // Additionally, we don't want to hash the tag bytes, so we get the same keys as GL,
+            // which is good for cross-checking code generation and performance.
+            GrVkGpu::PersistentCacheKeyType vkKeyType;
+            SkASSERT(bytesToHash >= sizeof(vkKeyType));
+            bytesToHash -= sizeof(vkKeyType);
+            memcpy(&vkKeyType, it->first.fKey->bytes() + bytesToHash, sizeof(vkKeyType));
+            if (vkKeyType != GrVkGpu::kShader_PersistentCacheKeyType) {
+                continue;
+            }
+        }
+#endif
+        hash.write(it->first.fKey->bytes(), bytesToHash);
+        SkMD5::Digest digest = hash.finish();
+        SkString md5;
+        for (int i = 0; i < 16; ++i) {
+            md5.appendf("%02x", digest.data[i]);
+        }
+
+        SkSL::Program::Inputs inputsIgnored[kGrShaderTypeCount];
+        SkSL::String shaders[kGrShaderTypeCount];
+        const SkData* data = it->second.fData.get();
+        // Even with the SPIR-V switches, it seems like we must use .spv, or malisc tries to
+        // run glslang on the input.
+        const char* ext = GrBackendApi::kOpenGL == api ? "frag" : "spv";
+        SkReader32 reader(data->data(), data->size());
+        reader.readU32(); // Shader type tag
+        GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders,
+                                                    inputsIgnored, kGrShaderTypeCount);
+
+        SkString filename = SkStringPrintf("%s/%s.%s", path, md5.c_str(), ext);
+        SkFILEWStream file(filename.c_str());
+        file.write(shaders[kFragment_GrShaderType].c_str(), shaders[kFragment_GrShaderType].size());
+    }
+}
+
+}  // namespace sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/MemoryCache.h b/src/third_party/skia/tools/gpu/MemoryCache.h
new file mode 100644
index 0000000..22911a5
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/MemoryCache.h
@@ -0,0 +1,88 @@
+/*
+ * 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 MemoryCache_DEFINED
+#define MemoryCache_DEFINED
+
+#include "include/core/SkData.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/private/SkChecksum.h"
+
+#include <unordered_map>
+
+namespace sk_gpu_test {
+
+/**
+ * This class can be used to maintain an in memory record of all programs cached by GrContext.
+ * It can be shared by multiple GrContexts so long as those GrContexts are created with the same
+ * options and will have the same GrCaps (e.g. same backend, same GL context creation parameters,
+ * ...).
+ */
+class MemoryCache : public GrContextOptions::PersistentCache {
+public:
+    MemoryCache() = default;
+    MemoryCache(const MemoryCache&) = delete;
+    MemoryCache& operator=(const MemoryCache&) = delete;
+    void reset() {
+        fCacheMissCnt = 0;
+        fMap.clear();
+    }
+
+    sk_sp<SkData> load(const SkData& key) override;
+    void store(const SkData& key, const SkData& data) override;
+    int numCacheMisses() const { return fCacheMissCnt; }
+    void resetNumCacheMisses() { fCacheMissCnt = 0; }
+
+    void writeShadersToDisk(const char* path, GrBackendApi backend);
+
+    template <typename Fn>
+    void foreach(Fn&& fn) {
+        for (auto it = fMap.begin(); it != fMap.end(); ++it) {
+            fn(it->first.fKey, it->second.fData, it->second.fHitCount);
+        }
+    }
+
+private:
+    struct Key {
+        Key() = default;
+        Key(const SkData& key) : fKey(SkData::MakeWithCopy(key.data(), key.size())) {}
+        Key(const Key& that) = default;
+        Key& operator=(const Key&) = default;
+        bool operator==(const Key& that) const {
+            return that.fKey->size() == fKey->size() &&
+                   !memcmp(fKey->data(), that.fKey->data(), that.fKey->size());
+        }
+        sk_sp<const SkData> fKey;
+    };
+
+    struct Value {
+        Value() = default;
+        Value(const SkData& data)
+            : fData(SkData::MakeWithCopy(data.data(), data.size()))
+            , fHitCount(1) {}
+        Value(const Value& that) = default;
+        Value& operator=(const Value&) = default;
+
+        sk_sp<SkData> fData;
+        int fHitCount;
+    };
+
+    struct Hash {
+        using argument_type = Key;
+        using result_type = uint32_t;
+        uint32_t operator()(const Key& key) const {
+            return key.fKey ? SkOpts::hash_fn(key.fKey->data(), key.fKey->size(), 0) : 0;
+        }
+    };
+
+    int fCacheMissCnt = 0;
+    std::unordered_map<Key, Value, Hash> fMap;
+};
+
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/ProxyUtils.cpp b/src/third_party/skia/tools/gpu/ProxyUtils.cpp
new file mode 100644
index 0000000..4f6e6fb
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/ProxyUtils.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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 "include/gpu/GrBackendSurface.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrDrawingManager.h"
+#include "src/gpu/GrGpu.h"
+#include "src/gpu/GrImageInfo.h"
+#include "src/gpu/GrProxyProvider.h"
+#include "src/gpu/SkGr.h"
+#include "tools/gpu/ProxyUtils.h"
+
+namespace sk_gpu_test {
+
+sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context,
+                                               GrRenderable renderable,
+                                               int width,
+                                               int height,
+                                               GrColorType colorType, SkAlphaType alphaType,
+                                               GrSurfaceOrigin origin,
+                                               const void* data, size_t rowBytes) {
+    if (context->priv().abandoned()) {
+        return nullptr;
+    }
+
+    const GrCaps* caps = context->priv().caps();
+
+    const GrBackendFormat format = caps->getDefaultBackendFormat(colorType, renderable);
+    if (!format.isValid()) {
+        return nullptr;
+    }
+
+    sk_sp<GrTextureProxy> proxy;
+    if (kBottomLeft_GrSurfaceOrigin == origin) {
+        // We (soon will) only support using kBottomLeft with wrapped textures.
+        auto backendTex = context->createBackendTexture(
+                width, height, format, SkColors::kTransparent, GrMipMapped::kNo, renderable,
+                GrProtected::kNo);
+        if (!backendTex.isValid()) {
+            return nullptr;
+        }
+
+        // Adopt ownership so our caller doesn't have to worry about deleting the backend texture.
+        if (GrRenderable::kYes == renderable) {
+            proxy = context->priv().proxyProvider()->wrapRenderableBackendTexture(
+                    backendTex, origin, 1, colorType, kAdopt_GrWrapOwnership, GrWrapCacheable::kNo,
+                    nullptr, nullptr);
+        } else {
+            proxy = context->priv().proxyProvider()->wrapBackendTexture(
+                    backendTex, colorType, origin, kAdopt_GrWrapOwnership,
+                    GrWrapCacheable::kNo, kRW_GrIOType);
+        }
+
+        if (!proxy) {
+            context->deleteBackendTexture(backendTex);
+            return nullptr;
+        }
+
+    } else {
+        GrSurfaceDesc desc;
+        desc.fConfig = GrColorTypeToPixelConfig(colorType);
+        desc.fWidth = width;
+        desc.fHeight = height;
+        proxy = context->priv().proxyProvider()->createProxy(format, desc, renderable, 1, origin,
+                                                             GrMipMapped::kNo, SkBackingFit::kExact,
+                                                             SkBudgeted::kYes, GrProtected::kNo);
+        if (!proxy) {
+            return nullptr;
+        }
+    }
+
+    auto sContext = context->priv().makeWrappedSurfaceContext(proxy, colorType, alphaType, nullptr);
+    if (!sContext) {
+        return nullptr;
+    }
+    if (!sContext->writePixels({colorType, alphaType, nullptr, width, height}, data, rowBytes,
+                               {0, 0}, context)) {
+        return nullptr;
+    }
+    return proxy;
+}
+
+}  // namespace sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/ProxyUtils.h b/src/third_party/skia/tools/gpu/ProxyUtils.h
new file mode 100644
index 0000000..28eacea
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/ProxyUtils.h
@@ -0,0 +1,37 @@
+/*
+ * 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 ProxyUtils_DEFINED
+#define ProxyUtils_DEFINED
+
+#include "include/private/GrTypesPriv.h"
+#include "src/gpu/GrTextureProxy.h"
+
+namespace sk_gpu_test {
+
+/** Makes a texture proxy containing the passed in color data. */
+sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext*, GrRenderable, int width, int height,
+                                               GrColorType, SkAlphaType, GrSurfaceOrigin,
+                                               const void* data, size_t rowBytes);
+
+/** Version that takes SkColorType rather than GrColorType. */
+inline sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context, GrRenderable renderable,
+                                                      int width, int height, SkColorType ct,
+                                                      SkAlphaType alphaType, GrSurfaceOrigin origin,
+                                                      const void* data, size_t rowBytes) {
+    GrColorType grCT = SkColorTypeToGrColorType(ct);
+    if (GrColorType::kUnknown == grCT) {
+        return nullptr;
+    }
+
+    return MakeTextureProxyFromData(context, renderable, width, height, grCT, alphaType, origin,
+                                    data, rowBytes);
+}
+
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/TestContext.cpp b/src/third_party/skia/tools/gpu/TestContext.cpp
index c80c4ea..bf961fb 100644
--- a/src/third_party/skia/tools/gpu/TestContext.cpp
+++ b/src/third_party/skia/tools/gpu/TestContext.cpp
@@ -6,11 +6,11 @@
  * found in the LICENSE file.
  */
 
-#include "TestContext.h"
+#include "tools/gpu/TestContext.h"
 
-#include "GpuTimer.h"
+#include "tools/gpu/GpuTimer.h"
 
-#include "GrContext.h"
+#include "include/gpu/GrContext.h"
 
 namespace sk_gpu_test {
 TestContext::TestContext()
@@ -37,8 +37,15 @@
 
 void TestContext::makeCurrent() const { this->onPlatformMakeCurrent(); }
 
+SkScopeExit TestContext::makeCurrentAndAutoRestore() const {
+    auto asr = SkScopeExit(this->onPlatformGetAutoContextRestore());
+    this->makeCurrent();
+    return asr;
+}
+
 void TestContext::swapBuffers() { this->onPlatformSwapBuffers(); }
 
+
 void TestContext::waitOnSyncOrSwap() {
     if (!fFenceSync) {
         // Fallback on the platform SwapBuffers method for synchronization. This may have no effect.
diff --git a/src/third_party/skia/tools/gpu/TestContext.h b/src/third_party/skia/tools/gpu/TestContext.h
index 84794f3..e48c598 100644
--- a/src/third_party/skia/tools/gpu/TestContext.h
+++ b/src/third_party/skia/tools/gpu/TestContext.h
@@ -9,10 +9,12 @@
 #ifndef TestContext_DEFINED
 #define TestContext_DEFINED
 
-#include "FenceSync.h"
-#include "GrTypes.h"
-#include "SkRefCnt.h"
-#include "../private/SkTemplates.h"
+#include "include/core/SkRefCnt.h"
+#include "include/gpu/GrTypes.h"
+#include "include/private/SkNoncopyable.h"
+#include "include/private/SkTemplates.h"
+#include "src/core/SkScopeExit.h"
+#include "tools/gpu/FenceSync.h"
 
 class GrContext;
 struct GrContextOptions;
@@ -45,8 +47,19 @@
 
     void makeCurrent() const;
 
-    virtual GrBackend backend() = 0;
-    virtual GrBackendContext backendContext() = 0;
+    /**
+     * Like makeCurrent() but this returns an object that will restore the previous current
+     * context in its destructor. Useful to undo the effect making this current before returning to
+     * a caller that doesn't expect the current context to be changed underneath it.
+     *
+     * The returned object restores the current context of the same type (e.g. egl, glx, ...) in its
+     * destructor. It is undefined behavior if that context is destroyed before the destructor
+     * executes. If the concept of a current context doesn't make sense for this context type then
+     * the returned object's destructor is a no-op.
+     */
+    SkScopeExit SK_WARN_UNUSED_RESULT makeCurrentAndAutoRestore() const;
+
+    virtual GrBackendApi backend() = 0;
 
     virtual sk_sp<GrContext> makeGrContext(const GrContextOptions&);
 
@@ -94,6 +107,14 @@
     virtual void teardown();
 
     virtual void onPlatformMakeCurrent() const = 0;
+    /**
+     * Subclasses should implement such that the returned function will cause the current context
+     * of this type to be made current again when it is called. It should additionally be the
+     * case that if "this" is already current when this is called, then "this" is destroyed (thereby
+     * setting the null context as current), and then the std::function is called the null context
+     * should remain current.
+     */
+    virtual std::function<void()> onPlatformGetAutoContextRestore() const = 0;
     virtual void onPlatformSwapBuffers() const = 0;
 
 private:
diff --git a/src/third_party/skia/tools/gpu/YUVUtils.cpp b/src/third_party/skia/tools/gpu/YUVUtils.cpp
new file mode 100644
index 0000000..eb4ca2c
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/YUVUtils.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/gpu/YUVUtils.h"
+
+#include "include/core/SkData.h"
+#include "include/gpu/GrContext.h"
+#include "src/codec/SkCodecImageGenerator.h"
+#include "src/gpu/GrContextPriv.h"
+
+namespace sk_gpu_test {
+
+std::unique_ptr<LazyYUVImage> LazyYUVImage::Make(sk_sp<SkData> data) {
+    std::unique_ptr<LazyYUVImage> image(new LazyYUVImage());
+    if (image->reset(std::move(data))) {
+        return image;
+    } else {
+        return nullptr;
+    }
+}
+
+sk_sp<SkImage> LazyYUVImage::refImage(GrContext* context) {
+    if (this->ensureYUVImage(context)) {
+        return fYUVImage;
+    } else {
+        return nullptr;
+    }
+}
+
+const SkImage* LazyYUVImage::getImage(GrContext* context) {
+    if (this->ensureYUVImage(context)) {
+        return fYUVImage.get();
+    } else {
+        return nullptr;
+    }
+}
+
+bool LazyYUVImage::reset(sk_sp<SkData> data) {
+    auto codec = SkCodecImageGenerator::MakeFromEncodedCodec(data);
+    if (!codec) {
+        return false;
+    }
+
+    if (!codec->queryYUVA8(&fSizeInfo, fComponents, &fColorSpace)) {
+        return false;
+    }
+
+    fPlaneData.reset(fSizeInfo.computeTotalBytes());
+    void* planes[SkYUVASizeInfo::kMaxCount];
+    fSizeInfo.computePlanes(fPlaneData.get(), planes);
+    if (!codec->getYUVA8Planes(fSizeInfo, fComponents, planes)) {
+        return false;
+    }
+
+    for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
+        if (fSizeInfo.fSizes[i].isEmpty()) {
+            fPlanes[i].reset();
+        } else {
+            SkASSERT(planes[i]);
+            auto planeInfo = SkImageInfo::Make(fSizeInfo.fSizes[i].fWidth,
+                                               fSizeInfo.fSizes[i].fHeight,
+                                               kGray_8_SkColorType, kOpaque_SkAlphaType, nullptr);
+            fPlanes[i].reset(planeInfo, planes[i], fSizeInfo.fWidthBytes[i]);
+        }
+    }
+    // The SkPixmap data is fully configured now for MakeFromYUVAPixmaps once we get a GrContext
+    return true;
+}
+
+bool LazyYUVImage::ensureYUVImage(GrContext* context) {
+    if (!context) {
+        return false; // Cannot make a YUV image from planes
+    }
+    if (context->priv().contextID() == fOwningContextID) {
+        return fYUVImage != nullptr; // Have already made a YUV image (or tried and failed)
+    }
+    // Must make a new YUV image
+    fYUVImage = SkImage::MakeFromYUVAPixmaps(context, fColorSpace, fPlanes, fComponents,
+            fSizeInfo.fSizes[0], kTopLeft_GrSurfaceOrigin, false, false);
+    fOwningContextID = context->priv().contextID();
+    return fYUVImage != nullptr;
+}
+
+} // namespace sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/YUVUtils.h b/src/third_party/skia/tools/gpu/YUVUtils.h
new file mode 100644
index 0000000..f6097b9
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/YUVUtils.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef YUVUtils_DEFINED
+#define YUVUtils_DEFINED
+
+#include "include/core/SkImage.h"
+#include "include/core/SkYUVAIndex.h"
+#include "include/core/SkYUVASizeInfo.h"
+#include "src/core/SkAutoMalloc.h"
+
+class SkData;
+
+namespace sk_gpu_test {
+
+// Utility that decodes a JPEG but preserves the YUVA8 planes in the image, and uses
+// MakeFromYUVAPixmaps to create a GPU multiplane YUVA image for a context. It extracts the planar
+// data once, and lazily creates the actual SkImage when the GrContext is provided (and refreshes
+// the image if the context has changed, as in Viewer)
+class LazyYUVImage {
+public:
+    // Returns null if the data could not be extracted into YUVA8 planes
+    static std::unique_ptr<LazyYUVImage> Make(sk_sp<SkData> data);
+
+    sk_sp<SkImage> refImage(GrContext* context);
+
+    const SkImage* getImage(GrContext* context);
+
+private:
+    // Decoded YUV data
+    SkYUVASizeInfo fSizeInfo;
+    SkYUVColorSpace fColorSpace;
+    SkYUVAIndex fComponents[SkYUVAIndex::kIndexCount];
+    SkAutoMalloc fPlaneData;
+    SkPixmap fPlanes[SkYUVASizeInfo::kMaxCount];
+
+    // Memoized SkImage formed with planes
+    sk_sp<SkImage> fYUVImage;
+    uint32_t fOwningContextID;
+
+    LazyYUVImage() : fOwningContextID(SK_InvalidGenID) {}
+
+    bool reset(sk_sp<SkData> data);
+
+    bool ensureYUVImage(GrContext* context);
+};
+
+} // namespace sk_gpu_test
+
+#endif // YUVUtils_DEFINED
diff --git a/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp b/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp
new file mode 100644
index 0000000..c8dc054
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp
@@ -0,0 +1,483 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkBitmap.h"
+#include "src/gpu/gl/GrGLDefines.h"
+#include "src/gpu/gl/GrGLUtil.h"
+#include "tools/gpu/atlastext/GLTestAtlasTextRenderer.h"
+#include "tools/gpu/atlastext/TestAtlasTextRenderer.h"
+#include "tools/gpu/gl/GLTestContext.h"
+
+using sk_gpu_test::GLTestContext;
+
+namespace {
+
+class GLTestAtlasTextRenderer : public sk_gpu_test::TestAtlasTextRenderer {
+public:
+    GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext>);
+
+    void* createTexture(AtlasFormat, int width, int height) override;
+
+    void deleteTexture(void* textureHandle) override;
+
+    void setTextureData(void* textureHandle, const void* data, int x, int y, int width, int height,
+                        size_t rowBytes) override;
+
+    void drawSDFGlyphs(void* targetHandle, void* textureHandle, const SDFVertex vertices[],
+                       int quadCnt) override;
+
+    void* makeTargetHandle(int width, int height) override;
+
+    void targetDeleted(void* targetHandle) override;
+
+    SkBitmap readTargetHandle(void* targetHandle) override;
+
+    void clearTarget(void* targetHandle, uint32_t color) override;
+
+    bool initialized() const { return 0 != fProgram; }
+
+private:
+    struct AtlasTexture {
+        GrGLuint fID;
+        AtlasFormat fFormat;
+        int fWidth;
+        int fHeight;
+    };
+
+    struct Target {
+        GrGLuint fFBOID;
+        GrGLuint fRBID;
+        int fWidth;
+        int fHeight;
+    };
+
+    std::unique_ptr<GLTestContext> fContext;
+    GrGLuint fProgram = 0;
+    GrGLint fDstScaleAndTranslateLocation = 0;
+    GrGLint fAtlasInvSizeLocation = 0;
+    GrGLint fSamplerLocation = 0;
+};
+
+#define callgl(NAME, ...) fContext->gl()->fFunctions.f##NAME(__VA_ARGS__)
+#define checkgl()                                               \
+    do {                                                        \
+        static constexpr auto line = __LINE__;                  \
+        auto error = fContext->gl()->fFunctions.fGetError();    \
+        if (error != GR_GL_NO_ERROR) {                          \
+            SkDebugf("GL ERROR: 0x%x, line %d\n", error, line); \
+        }                                                       \
+    } while (false)
+
+GLTestAtlasTextRenderer::GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext> context)
+        : fContext(std::move(context)) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    // First check whether the GL is supported so we can avoid spammy failures on systems
+    // where the GL simply doesn't work with this class.
+    const char* versionStr = reinterpret_cast<const char*>(callgl(GetString, GR_GL_VERSION));
+    auto version = GrGLGetVersionFromString(versionStr);
+    auto standard = GrGLGetStandardInUseFromString(versionStr);
+    switch (standard) {
+        case kWebGL_GrGLStandard:
+        case kNone_GrGLStandard:
+            return;
+        case kGLES_GrGLStandard:
+            if (version < GR_GL_VER(3, 0)) {
+                return;
+            }
+            break;
+        case kGL_GrGLStandard: {
+            if (version < GR_GL_VER(4, 3)) {
+                return;
+            }
+            GrGLint profileMask;
+            callgl(GetIntegerv, GR_GL_CONTEXT_PROFILE_MASK, &profileMask);
+            if (profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT) {
+                return;
+            }
+        }
+    }
+
+    auto vs = callgl(CreateShader, GR_GL_VERTEX_SHADER);
+    static constexpr char kGLVersionString[] = "#version 430 compatibility";
+    static constexpr char kGLESVersionString[] = "#version 300 es";
+    GrGLint lengths[2];
+    const GrGLchar* strings[2];
+    switch (fContext->gl()->fStandard) {
+        case kGL_GrGLStandard:
+            strings[0] = kGLVersionString;
+            lengths[0] = static_cast<GrGLint>(SK_ARRAY_COUNT(kGLVersionString)) - 1;
+            break;
+        case kGLES_GrGLStandard:
+            strings[0] = kGLESVersionString;
+            lengths[0] = static_cast<GrGLint>(SK_ARRAY_COUNT(kGLESVersionString)) - 1;
+            break;
+        default:
+            strings[0] = nullptr;
+            lengths[0] = 0;
+            break;
+    }
+
+    static constexpr const char kVS[] = R"(
+        uniform vec4 uDstScaleAndTranslate;
+        uniform vec2 uAtlasInvSize;
+
+        layout (location = 0) in vec3 inPosition;
+        layout (location = 1) in vec4 inColor;
+        layout (location = 2) in uvec2 inTextureCoords;
+
+        out vec2 vTexCoord;
+        out vec4 vColor;
+        out vec2 vIntTexCoord;
+
+        void main() {
+            vec2 intCoords;
+            // floor(vec2) doesn't seem to work on some ES devices.
+            intCoords.x = floor(float(inTextureCoords.x));
+            intCoords.y = floor(float(inTextureCoords.y));
+            vTexCoord = intCoords * uAtlasInvSize;
+            vIntTexCoord = intCoords;
+            vColor = inColor;
+            gl_Position = vec4(inPosition.x * uDstScaleAndTranslate.x + uDstScaleAndTranslate.y,
+                               inPosition.y * uDstScaleAndTranslate.z + uDstScaleAndTranslate.w,
+                               0.0, inPosition.z);
+        }
+    )";
+    strings[1] = kVS;
+    lengths[1] = SK_ARRAY_COUNT(kVS) - 1;
+    callgl(ShaderSource, vs, 2, strings, lengths);
+    callgl(CompileShader, vs);
+    GrGLint compileStatus;
+    callgl(GetShaderiv, vs, GR_GL_COMPILE_STATUS, &compileStatus);
+    if (compileStatus == GR_GL_FALSE) {
+        GrGLint logLength;
+        callgl(GetShaderiv, vs, GR_GL_INFO_LOG_LENGTH, &logLength);
+        std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
+        log[logLength] = '\0';
+        callgl(GetShaderInfoLog, vs, logLength, &logLength, log.get());
+        SkDebugf("Vertex Shader failed to compile\n%s", log.get());
+        callgl(DeleteShader, vs);
+        return;
+    }
+
+    auto fs = callgl(CreateShader, GR_GL_FRAGMENT_SHADER);
+    static constexpr const char kFS[] = R"(
+        uniform sampler2D uSampler;
+
+        in vec2 vTexCoord;
+        in vec4 vColor;
+        in vec2 vIntTexCoord;
+
+        layout (location = 0) out vec4 outColor;
+
+        void main() {
+            float sdfValue = texture(uSampler, vTexCoord).r;
+            float distance = 7.96875 * (sdfValue - 0.50196078431000002);
+            vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));
+            vec2 Jdx = dFdx(vIntTexCoord);
+            vec2 Jdy = dFdy(vIntTexCoord);
+            float dg_len2 = dot(dist_grad, dist_grad);
+            if (dg_len2 < 0.0001) {
+                dist_grad = vec2(0.7071, 0.7071);
+            } else {
+                dist_grad = dist_grad * inversesqrt(dg_len2);
+            }
+            vec2 grad = vec2(dist_grad.x * Jdx.x + dist_grad.y * Jdy.x,
+                             dist_grad.x * Jdx.y + dist_grad.y * Jdy.y);
+            float afwidth = abs(0.65000000000000002 * length(grad));
+            float value = smoothstep(-afwidth, afwidth, distance);
+            outColor = value * vec4(vColor.rgb * vColor.a, vColor.a);
+        }
+    )";
+    strings[1] = kFS;
+    lengths[1] = SK_ARRAY_COUNT(kFS) - 1;
+    callgl(ShaderSource, fs, 2, strings, lengths);
+    callgl(CompileShader, fs);
+    callgl(GetShaderiv, fs, GR_GL_COMPILE_STATUS, &compileStatus);
+    if (compileStatus == GR_GL_FALSE) {
+        GrGLint logLength;
+        callgl(GetShaderiv, fs, GR_GL_INFO_LOG_LENGTH, &logLength);
+        std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
+        log[logLength] = '\0';
+        callgl(GetShaderInfoLog, fs, logLength, &logLength, log.get());
+        SkDebugf("Fragment Shader failed to compile\n%s", log.get());
+        callgl(DeleteShader, vs);
+        callgl(DeleteShader, fs);
+        return;
+    }
+
+    fProgram = callgl(CreateProgram);
+    if (!fProgram) {
+        callgl(DeleteShader, vs);
+        callgl(DeleteShader, fs);
+        return;
+    }
+
+    callgl(AttachShader, fProgram, vs);
+    callgl(AttachShader, fProgram, fs);
+    callgl(LinkProgram, fProgram);
+    GrGLint linkStatus;
+    callgl(GetProgramiv, fProgram, GR_GL_LINK_STATUS, &linkStatus);
+    if (linkStatus == GR_GL_FALSE) {
+        GrGLint logLength = 0;
+        callgl(GetProgramiv, vs, GR_GL_INFO_LOG_LENGTH, &logLength);
+        std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
+        log[logLength] = '\0';
+        callgl(GetProgramInfoLog, vs, logLength, &logLength, log.get());
+        SkDebugf("Program failed to link\n%s", log.get());
+        callgl(DeleteShader, vs);
+        callgl(DeleteShader, fs);
+        callgl(DeleteProgram, fProgram);
+        fProgram = 0;
+        return;
+    }
+    fDstScaleAndTranslateLocation = callgl(GetUniformLocation, fProgram, "uDstScaleAndTranslate");
+    fAtlasInvSizeLocation = callgl(GetUniformLocation, fProgram, "uAtlasInvSize");
+    fSamplerLocation = callgl(GetUniformLocation, fProgram, "uSampler");
+    if (fDstScaleAndTranslateLocation < 0 || fAtlasInvSizeLocation < 0 || fSamplerLocation < 0) {
+        callgl(DeleteShader, vs);
+        callgl(DeleteShader, fs);
+        callgl(DeleteProgram, fProgram);
+        fProgram = 0;
+    }
+
+    checkgl();
+}
+
+inline bool atlas_format_to_gl_types(SkAtlasTextRenderer::AtlasFormat format,
+                                     GrGLenum* internalFormat, GrGLenum* externalFormat,
+                                     GrGLenum* type) {
+    switch (format) {
+        case SkAtlasTextRenderer::AtlasFormat::kA8:
+            *internalFormat = GR_GL_R8;
+            *externalFormat = GR_GL_RED;
+            *type = GR_GL_UNSIGNED_BYTE;
+            return true;
+    }
+    return false;
+}
+
+inline int atlas_format_bytes_per_pixel(SkAtlasTextRenderer::AtlasFormat format) {
+    switch (format) {
+        case SkAtlasTextRenderer::AtlasFormat::kA8:
+            return 1;
+    }
+    return 0;
+}
+
+void* GLTestAtlasTextRenderer::createTexture(AtlasFormat format, int width, int height) {
+    GrGLenum internalFormat;
+    GrGLenum externalFormat;
+    GrGLenum type;
+    if (!atlas_format_to_gl_types(format, &internalFormat, &externalFormat, &type)) {
+        return nullptr;
+    }
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    GrGLuint id;
+    callgl(GenTextures, 1, &id);
+    if (!id) {
+        return nullptr;
+    }
+
+    callgl(BindTexture, GR_GL_TEXTURE_2D, id);
+    callgl(TexImage2D, GR_GL_TEXTURE_2D, 0, internalFormat, width, height, 0, externalFormat, type,
+           nullptr);
+    checkgl();
+
+    AtlasTexture* atlas = new AtlasTexture;
+    atlas->fID = id;
+    atlas->fFormat = format;
+    atlas->fWidth = width;
+    atlas->fHeight = height;
+    return atlas;
+}
+
+void GLTestAtlasTextRenderer::deleteTexture(void* textureHandle) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    auto* atlasTexture = reinterpret_cast<const AtlasTexture*>(textureHandle);
+
+    callgl(DeleteTextures, 1, &atlasTexture->fID);
+    checkgl();
+
+    delete atlasTexture;
+}
+
+void GLTestAtlasTextRenderer::setTextureData(void* textureHandle, const void* data, int x, int y,
+                                             int width, int height, size_t rowBytes) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    auto atlasTexture = reinterpret_cast<const AtlasTexture*>(textureHandle);
+
+    GrGLenum internalFormat;
+    GrGLenum externalFormat;
+    GrGLenum type;
+    if (!atlas_format_to_gl_types(atlasTexture->fFormat, &internalFormat, &externalFormat, &type)) {
+        return;
+    }
+    int bpp = atlas_format_bytes_per_pixel(atlasTexture->fFormat);
+    GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
+    if (static_cast<size_t>(rowLength * bpp) != rowBytes) {
+        return;
+    }
+    callgl(PixelStorei, GR_GL_UNPACK_ALIGNMENT, 1);
+    callgl(PixelStorei, GR_GL_UNPACK_ROW_LENGTH, rowLength);
+    callgl(BindTexture, GR_GL_TEXTURE_2D, atlasTexture->fID);
+    callgl(TexSubImage2D, GR_GL_TEXTURE_2D, 0, x, y, width, height, externalFormat, type, data);
+    checkgl();
+}
+
+void GLTestAtlasTextRenderer::drawSDFGlyphs(void* targetHandle, void* textureHandle,
+                                            const SDFVertex vertices[], int quadCnt) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    auto target = reinterpret_cast<const Target*>(targetHandle);
+    auto atlas = reinterpret_cast<const AtlasTexture*>(textureHandle);
+
+    callgl(UseProgram, fProgram);
+
+    callgl(ActiveTexture, GR_GL_TEXTURE0);
+    callgl(BindTexture, GR_GL_TEXTURE_2D, atlas->fID);
+    callgl(TexParameteri, GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_LINEAR);
+    callgl(TexParameteri, GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_LINEAR);
+
+    float uniformScaleAndTranslate[4] = {2.f / target->fWidth, -1.f, 2.f / target->fHeight, -1.f};
+    callgl(Uniform4fv, fDstScaleAndTranslateLocation, 1, uniformScaleAndTranslate);
+    callgl(Uniform2f, fAtlasInvSizeLocation, 1.f / atlas->fWidth, 1.f / atlas->fHeight);
+    callgl(Uniform1i, fSamplerLocation, 0);
+
+    callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, target->fFBOID);
+    callgl(Viewport, 0, 0, target->fWidth, target->fHeight);
+
+    callgl(Enable, GR_GL_BLEND);
+    callgl(BlendFunc, GR_GL_ONE, GR_GL_ONE_MINUS_SRC_ALPHA);
+    callgl(Disable, GR_GL_DEPTH_TEST);
+
+    callgl(BindVertexArray, 0);
+    callgl(BindBuffer, GR_GL_ARRAY_BUFFER, 0);
+    callgl(BindBuffer, GR_GL_ELEMENT_ARRAY_BUFFER, 0);
+    callgl(VertexAttribPointer, 0, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(SDFVertex), vertices);
+    size_t colorOffset = 3 * sizeof(float);
+    callgl(VertexAttribPointer, 1, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE, sizeof(SDFVertex),
+           reinterpret_cast<const char*>(vertices) + colorOffset);
+    size_t texOffset = colorOffset + sizeof(uint32_t);
+    callgl(VertexAttribIPointer, 2, 2, GR_GL_UNSIGNED_SHORT, sizeof(SDFVertex),
+           reinterpret_cast<const char*>(vertices) + texOffset);
+    callgl(EnableVertexAttribArray, 0);
+    callgl(EnableVertexAttribArray, 1);
+    callgl(EnableVertexAttribArray, 2);
+
+    std::unique_ptr<uint16_t[]> indices(new uint16_t[quadCnt * 6]);
+    for (int q = 0; q < quadCnt; ++q) {
+        indices[q * 6 + 0] = 0 + 4 * q;
+        indices[q * 6 + 1] = 1 + 4 * q;
+        indices[q * 6 + 2] = 2 + 4 * q;
+        indices[q * 6 + 3] = 2 + 4 * q;
+        indices[q * 6 + 4] = 1 + 4 * q;
+        indices[q * 6 + 5] = 3 + 4 * q;
+    }
+    callgl(DrawElements, GR_GL_TRIANGLES, 6 * quadCnt, GR_GL_UNSIGNED_SHORT, indices.get());
+    checkgl();
+}
+
+void* GLTestAtlasTextRenderer::makeTargetHandle(int width, int height) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    GrGLuint fbo;
+    callgl(GenFramebuffers, 1, &fbo);
+    if (!fbo) {
+        return nullptr;
+    }
+    GrGLuint rb;
+    callgl(GenRenderbuffers, 1, &rb);
+    if (!rb) {
+        callgl(DeleteFramebuffers, 1, &fbo);
+        return nullptr;
+    }
+    callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, fbo);
+    callgl(BindRenderbuffer, GR_GL_RENDERBUFFER, rb);
+    callgl(RenderbufferStorage, GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height);
+    callgl(FramebufferRenderbuffer, GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_RENDERBUFFER,
+           rb);
+    GrGLenum status = callgl(CheckFramebufferStatus, GR_GL_FRAMEBUFFER);
+    if (GR_GL_FRAMEBUFFER_COMPLETE != status) {
+        callgl(DeleteFramebuffers, 1, &fbo);
+        callgl(DeleteRenderbuffers, 1, &rb);
+        return nullptr;
+    }
+    callgl(Disable, GR_GL_SCISSOR_TEST);
+    callgl(ClearColor, 0, 0, 0, 0.0);
+    callgl(Clear, GR_GL_COLOR_BUFFER_BIT);
+    checkgl();
+    Target* target = new Target;
+    target->fFBOID = fbo;
+    target->fRBID = rb;
+    target->fWidth = width;
+    target->fHeight = height;
+    return target;
+}
+
+void GLTestAtlasTextRenderer::targetDeleted(void* targetHandle) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    Target* target = reinterpret_cast<Target*>(targetHandle);
+    callgl(DeleteFramebuffers, 1, &target->fFBOID);
+    callgl(DeleteRenderbuffers, 1, &target->fRBID);
+    delete target;
+}
+
+SkBitmap GLTestAtlasTextRenderer::readTargetHandle(void* targetHandle) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    Target* target = reinterpret_cast<Target*>(targetHandle);
+
+    auto info =
+            SkImageInfo::Make(target->fWidth, target->fHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+    SkBitmap bmp;
+    bmp.setInfo(info, sizeof(uint32_t) * target->fWidth);
+    bmp.allocPixels();
+
+    callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, target->fFBOID);
+    callgl(ReadPixels, 0, 0, target->fWidth, target->fHeight, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
+           bmp.getPixels());
+    checkgl();
+    return bmp;
+}
+
+void GLTestAtlasTextRenderer::clearTarget(void* targetHandle, uint32_t color) {
+    auto restore = fContext->makeCurrentAndAutoRestore();
+
+    Target* target = reinterpret_cast<Target*>(targetHandle);
+    callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, target->fFBOID);
+    callgl(Disable, GR_GL_SCISSOR_TEST);
+    float r = ((color >>  0) & 0xff) / 255.f;
+    float g = ((color >>  8) & 0xff) / 255.f;
+    float b = ((color >> 16) & 0xff) / 255.f;
+    float a = ((color >> 24) & 0xff) / 255.f;
+    callgl(ClearColor, r, g, b, a);
+    callgl(Clear, GR_GL_COLOR_BUFFER_BIT);
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+
+sk_sp<TestAtlasTextRenderer> MakeGLTestAtlasTextRenderer() {
+    std::unique_ptr<GLTestContext> context(CreatePlatformGLTestContext(kGL_GrGLStandard));
+    if (!context) {
+        context.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
+    }
+    if (!context) {
+        return nullptr;
+    }
+    auto restorer = context->makeCurrentAndAutoRestore();
+    auto renderer = sk_make_sp<GLTestAtlasTextRenderer>(std::move(context));
+    return renderer->initialized() ? std::move(renderer) : nullptr;
+}
+
+}  // namespace sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.h b/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.h
new file mode 100644
index 0000000..d1536d3
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/atlastext/GLTestAtlasTextRenderer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GLTestAtlasTextRenderer_DEFINED
+#define GLTestAtlasTextRenderer_DEFINED
+
+#include "include/core/SkRefCnt.h"
+
+namespace sk_gpu_test {
+
+class TestAtlasTextRenderer;
+
+/**
+ * Creates a TestAtlasTextRenderer that uses its own OpenGL context to implement
+ * SkAtlasTextRenderer.
+ */
+sk_sp<TestAtlasTextRenderer> MakeGLTestAtlasTextRenderer();
+
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/atlastext/TestAtlasTextRenderer.h b/src/third_party/skia/tools/gpu/atlastext/TestAtlasTextRenderer.h
new file mode 100644
index 0000000..e928e76
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/atlastext/TestAtlasTextRenderer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef TestAtlasTextRenderer_DEFINED
+#define TestAtlasTextRenderer_DEFINED
+
+#include "include/atlastext/SkAtlasTextRenderer.h"
+#include "include/core/SkBitmap.h"
+
+namespace sk_gpu_test {
+
+class TestContext;
+
+/**
+ * Base class for implementations of SkAtlasTextRenderer in order to test the SkAtlasText APIs.
+ * Adds a helper for creating SkAtlasTextTargets and to read back the contents of a target as a
+ * bitmap.
+ */
+class TestAtlasTextRenderer : public SkAtlasTextRenderer {
+public:
+    /** Returns a handle that can be used to construct a SkAtlasTextTarget instance. */
+    virtual void* makeTargetHandle(int width, int height) = 0;
+
+    /** Makes a SkBitmap of the target handle's contents. */
+    virtual SkBitmap readTargetHandle(void* targetHandle) = 0;
+
+    /** Clears the target to the specified color, encoded as RGBA (low to high byte order) */
+    virtual void clearTarget(void* targetHandle, uint32_t color) = 0;
+};
+
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/dawn/DawnTestContext.cpp b/src/third_party/skia/tools/gpu/dawn/DawnTestContext.cpp
new file mode 100644
index 0000000..666ea6c
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/dawn/DawnTestContext.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "dawn/dawncpp.h"
+#include "dawn_native/DawnNative.h"
+#include "tools/gpu/dawn/DawnTestContext.h"
+
+#ifdef SK_BUILD_FOR_UNIX
+#include "GL/glx.h"
+#endif
+
+#ifdef SK_BUILD_FOR_WIN
+#include <windows.h>
+#endif
+
+#define USE_OPENGL_BACKEND 0
+
+#ifdef SK_DAWN
+#include "dawn/dawn.h"
+#include "dawn/dawn_proc.h"
+#include "include/gpu/GrContext.h"
+#include "tools/AutoreleasePool.h"
+#if USE_OPENGL_BACKEND
+#include "dawn_native/OpenGLBackend.h"
+#endif
+
+#if defined(SK_BUILD_FOR_MAC) && USE_OPENGL_BACKEND
+#include <dlfcn.h>
+static void* getProcAddressMacOS(const char* procName) {
+    return dlsym(RTLD_DEFAULT, procName);
+}
+#endif
+
+namespace {
+
+#ifdef SK_BUILD_FOR_WIN
+class ProcGetter {
+public:
+    typedef void(*Proc)();
+
+    ProcGetter()
+      : fModule(LoadLibraryA("opengl32.dll")) {
+        SkASSERT(!fInstance);
+        fInstance = this;
+    }
+
+    ~ProcGetter() {
+        if (fModule) {
+            FreeLibrary(fModule);
+        }
+        fInstance = nullptr;
+    }
+
+    static void* getProcAddress(const char* name) {
+        return fInstance->getProc(name);
+    }
+
+private:
+    Proc getProc(const char* name) {
+        PROC proc;
+        if (proc = GetProcAddress(fModule, name)) {
+            return (Proc) proc;
+        }
+        if (proc = wglGetProcAddress(name)) {
+            return (Proc) proc;
+        }
+        return nullptr;
+    }
+
+    HMODULE fModule;
+    static ProcGetter* fInstance;
+};
+
+ProcGetter* ProcGetter::fInstance;
+#endif
+
+class DawnFence {
+public:
+    DawnFence(const dawn::Device& device, const dawn::Buffer& buffer)
+      : fDevice(device), fBuffer(buffer), fCalled(false) {
+        fBuffer.MapReadAsync(callback, this);
+    }
+
+    bool wait() {
+        while (!fCalled) {
+            fDevice.Tick();
+        }
+        return true;
+    }
+
+    ~DawnFence() {
+    }
+
+    static void callback(DawnBufferMapAsyncStatus status, const void* data, uint64_t dataLength,
+                         void* userData) {
+        DawnFence* fence = static_cast<DawnFence*>(userData);
+        fence->fCalled = true;
+    }
+    dawn::Buffer buffer() { return fBuffer; }
+
+private:
+    dawn::Device                   fDevice;
+    dawn::Buffer                   fBuffer;
+    bool                           fCalled;
+};
+
+/**
+ * Implements sk_gpu_test::FenceSync for Dawn.
+ */
+class DawnFenceSync : public sk_gpu_test::FenceSync {
+public:
+    DawnFenceSync(dawn::Device device) : fDevice(device) {
+    }
+
+    ~DawnFenceSync() override {
+    }
+
+    sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
+        dawn::Buffer buffer;
+        if (fBuffers.empty()) {
+            dawn::BufferDescriptor desc;
+            desc.usage = dawn::BufferUsage::MapRead | dawn::BufferUsage::CopyDst;
+            desc.size = 1;
+            buffer = fDevice.CreateBuffer(&desc);
+        } else {
+            buffer = fBuffers.back();
+            fBuffers.pop_back();
+        }
+        DawnFence* fence = new DawnFence(fDevice, buffer);
+        return reinterpret_cast<sk_gpu_test::PlatformFence>(fence);
+    }
+
+    bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
+        fAutoreleasePool.drain();
+        DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
+        return fence->wait();
+    }
+
+    void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
+        DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
+        fBuffers.push_back(fence->buffer());
+        delete fence;
+    }
+
+private:
+    dawn::Device                      fDevice;
+    mutable std::vector<dawn::Buffer> fBuffers;
+    mutable AutoreleasePool           fAutoreleasePool;
+    typedef sk_gpu_test::FenceSync INHERITED;
+};
+
+class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
+public:
+    static dawn::Device createDevice(const dawn_native::Instance& instance,
+                                     dawn_native::BackendType type) {
+        DawnProcTable backendProcs = dawn_native::GetProcs();
+        dawnProcSetProcs(&backendProcs);
+
+        std::vector<dawn_native::Adapter> adapters = instance.GetAdapters();
+        for (dawn_native::Adapter adapter : adapters) {
+            if (adapter.GetBackendType() == type) {
+                return adapter.CreateDevice();
+            }
+        }
+        return nullptr;
+    }
+
+    static DawnTestContext* Create(DawnTestContext* sharedContext) {
+        std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
+        dawn::Device device;
+        if (sharedContext) {
+            device = sharedContext->getDevice();
+        } else {
+            dawn_native::BackendType type;
+#if USE_OPENGL_BACKEND
+            dawn_native::opengl::AdapterDiscoveryOptions adapterOptions;
+            adapterOptions.getProc = reinterpret_cast<void*(*)(const char*)>(
+#if defined(SK_BUILD_FOR_UNIX)
+                glXGetProcAddress
+#elif defined(SK_BUILD_FOR_MAC)
+                getProcAddressMacOS
+#elif defined(SK_BUILD_FOR_WIN)
+                ProcGetter::getProcAddress
+#endif
+            );
+            instance->DiscoverAdapters(&adapterOptions);
+            type = dawn_native::BackendType::OpenGL;
+#else
+            instance->DiscoverDefaultAdapters();
+#if defined(SK_BUILD_FOR_MAC)
+            type = dawn_native::BackendType::Metal;
+#elif defined(SK_BUILD_FOR_WIN)
+            type = dawn_native::BackendType::D3D12;
+#elif defined(SK_BUILD_FOR_UNIX)
+            type = dawn_native::BackendType::Vulkan;
+#endif
+#endif
+            device = createDevice(*instance, type);
+        }
+        if (!device) {
+            return nullptr;
+        }
+        return new DawnTestContextImpl(std::move(instance), device);
+    }
+
+    ~DawnTestContextImpl() override { this->teardown(); }
+
+    void testAbandon() override {}
+
+    // There is really nothing to here since we don't own any unqueued command buffers here.
+    void submit() override {}
+
+    void finish() override {}
+
+    sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
+        return GrContext::MakeDawn(fDevice, options);
+    }
+
+protected:
+    void teardown() override {
+        INHERITED::teardown();
+    }
+
+private:
+    DawnTestContextImpl(std::unique_ptr<dawn_native::Instance> instance,
+                        const dawn::Device& device)
+            : DawnTestContext(device)
+            , fInstance(std::move(instance)) {
+        fFenceSync.reset(new DawnFenceSync(fDevice));
+    }
+
+    void onPlatformMakeCurrent() const override {}
+    std::function<void()> onPlatformGetAutoContextRestore() const override  { return nullptr; }
+    void onPlatformSwapBuffers() const override {}
+    std::unique_ptr<dawn_native::Instance> fInstance;
+
+    typedef sk_gpu_test::DawnTestContext INHERITED;
+};
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext* sharedContext) {
+    return DawnTestContextImpl::Create(sharedContext);
+}
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/dawn/DawnTestContext.h b/src/third_party/skia/tools/gpu/dawn/DawnTestContext.h
new file mode 100644
index 0000000..4afd018
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/dawn/DawnTestContext.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef DawnTestContext_DEFINED
+#define DawnTestContext_DEFINED
+
+#include "tools/gpu/TestContext.h"
+
+#ifdef SK_DAWN
+
+namespace sk_gpu_test {
+class DawnTestContext : public TestContext {
+public:
+    virtual GrBackend backend() override { return GrBackendApi::kDawn; }
+
+    const dawn::Device& getDevice() {
+        return fDevice;
+    }
+
+protected:
+    DawnTestContext(const dawn::Device& device) : fDevice(device) {}
+
+    dawn::Device fDevice;
+
+private:
+    typedef TestContext INHERITED;
+};
+
+/**
+ * Creates Dawn context object bound to the Dawn library.
+ */
+DawnTestContext* CreatePlatformDawnTestContext(DawnTestContext*);
+
+}  // namespace sk_gpu_test
+
+#endif
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/gl/GLTestContext.cpp b/src/third_party/skia/tools/gpu/gl/GLTestContext.cpp
index abbb8a6..d4aa605 100644
--- a/src/third_party/skia/tools/gpu/gl/GLTestContext.cpp
+++ b/src/third_party/skia/tools/gpu/gl/GLTestContext.cpp
@@ -5,16 +5,17 @@
  * found in the LICENSE file.
  */
 
-#include "GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
-#include "GpuTimer.h"
-#include "gl/GrGLUtil.h"
+#include "include/gpu/GrContext.h"
+#include "src/gpu/gl/GrGLUtil.h"
+#include "tools/gpu/GpuTimer.h"
 
 namespace {
 
 class GLFenceSync : public sk_gpu_test::FenceSync {
 public:
-    static std::unique_ptr<GLFenceSync> MakeIfSupported(const sk_gpu_test::GLTestContext*);
+    static std::unique_ptr<FenceSync> MakeIfSupported(const sk_gpu_test::GLTestContext*);
 
     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
     bool waitFence(sk_gpu_test::PlatformFence fence) const override;
@@ -23,7 +24,7 @@
 private:
     GLFenceSync(const sk_gpu_test::GLTestContext*, const char* ext = "");
 
-    bool validate() { return fGLFenceSync && fGLClientWaitSync && fGLDeleteSync; }
+    bool validate() const override { return fGLFenceSync && fGLClientWaitSync && fGLDeleteSync; }
 
     static constexpr GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE  = 0x9117;
     static constexpr GrGLenum GL_WAIT_FAILED                 = 0x911d;
@@ -43,8 +44,37 @@
     typedef FenceSync INHERITED;
 };
 
-std::unique_ptr<GLFenceSync> GLFenceSync::MakeIfSupported(const sk_gpu_test::GLTestContext* ctx) {
-    std::unique_ptr<GLFenceSync> ret;
+class GLNVFenceSync : public sk_gpu_test::FenceSync {
+public:
+    GLNVFenceSync(const sk_gpu_test::GLTestContext*);
+
+    sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
+    bool waitFence(sk_gpu_test::PlatformFence fence) const override;
+    void deleteFence(sk_gpu_test::PlatformFence fence) const override;
+
+private:
+    bool validate() const override {
+        return fGLGenFencesNV && fGLDeleteFencesNV && fGLSetFenceNV && fGLFinishFenceNV;
+    }
+
+    static constexpr GrGLenum GL_ALL_COMPLETED_NV = 0x84F2;
+
+    typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLGenFencesNVProc) (GrGLsizei, GrGLuint*);
+    typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLDeleteFencesNVProc) (GrGLsizei, const GrGLuint*);
+    typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLSetFenceNVProc) (GrGLuint, GrGLenum);
+    typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLFinishFenceNVProc) (GrGLuint);
+
+    GLGenFencesNVProc    fGLGenFencesNV;
+    GLDeleteFencesNVProc fGLDeleteFencesNV;
+    GLSetFenceNVProc     fGLSetFenceNV;
+    GLFinishFenceNVProc  fGLFinishFenceNV;
+
+    typedef FenceSync INHERITED;
+};
+
+std::unique_ptr<sk_gpu_test::FenceSync> GLFenceSync::MakeIfSupported(
+        const sk_gpu_test::GLTestContext* ctx) {
+    std::unique_ptr<FenceSync> ret;
     if (kGL_GrGLStandard == ctx->gl()->fStandard) {
         if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
             return nullptr;
@@ -53,6 +83,8 @@
     } else {
         if (ctx->gl()->hasExtension("GL_APPLE_sync")) {
             ret.reset(new GLFenceSync(ctx, "APPLE"));
+        } else if (ctx->gl()->hasExtension("GL_NV_fence")) {
+            ret.reset(new GLNVFenceSync(ctx));
         } else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) {
             ret.reset(new GLFenceSync(ctx));
         } else {
@@ -66,9 +98,9 @@
 }
 
 GLFenceSync::GLFenceSync(const sk_gpu_test::GLTestContext* ctx, const char* ext) {
-    ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync");
-    ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync");
-    ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync");
+    ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync", ext);
+    ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync", ext);
+    ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync", ext);
 }
 
 sk_gpu_test::PlatformFence GLFenceSync::insertFence() const {
@@ -86,6 +118,30 @@
     fGLDeleteSync(glsync);
 }
 
+GLNVFenceSync::GLNVFenceSync(const sk_gpu_test::GLTestContext* ctx) {
+    ctx->getGLProcAddress(&fGLGenFencesNV, "glGenFencesNV");
+    ctx->getGLProcAddress(&fGLDeleteFencesNV, "glDeleteFencesNV");
+    ctx->getGLProcAddress(&fGLSetFenceNV, "glSetFenceNV");
+    ctx->getGLProcAddress(&fGLFinishFenceNV, "glFinishFenceNV");
+}
+
+sk_gpu_test::PlatformFence GLNVFenceSync::insertFence() const {
+    GrGLuint fence;
+    fGLGenFencesNV(1, &fence);
+    fGLSetFenceNV(fence, GL_ALL_COMPLETED_NV);
+    return fence;
+}
+
+bool GLNVFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const {
+    fGLFinishFenceNV(fence);
+    return true;
+}
+
+void GLNVFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const {
+    GrGLuint glFence = static_cast<GrGLuint>(fence);
+    fGLDeleteFencesNV(1, &glFence);
+}
+
 class GLGpuTimer : public sk_gpu_test::GpuTimer {
 public:
     static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*);
@@ -228,9 +284,8 @@
     SkASSERT(nullptr == fGL.get());
 }
 
-void GLTestContext::init(const GrGLInterface* gl, std::unique_ptr<FenceSync> fenceSync) {
-    SkASSERT(!fGL.get());
-    fGL.reset(gl);
+void GLTestContext::init(sk_sp<const GrGLInterface> gl, std::unique_ptr<FenceSync> fenceSync) {
+    fGL = std::move(gl);
     fFenceSync = fenceSync ? std::move(fenceSync) : GLFenceSync::MakeIfSupported(this);
     fGpuTimer = GLGpuTimer::MakeIfSupported(this);
 }
@@ -259,11 +314,14 @@
     }
 }
 
-GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
-                                          GrGLenum externalFormat, GrGLenum externalType,
-                                          GrGLvoid* data) {
-    if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL.get()) >= GR_GL_VER(3, 1)) &&
-        !fGL->fExtensions.has("GL_ARB_texture_rectangle")) {
+GrGLuint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
+                                               GrGLenum externalFormat, GrGLenum externalType,
+                                               GrGLvoid* data) {
+    // Should match GrGLCaps check for fRectangleTextureSupport.
+    if (kGL_GrGLStandard != fGL->fStandard ||
+        (GrGLGetVersion(fGL.get()) < GR_GL_VER(3, 1) &&
+         !fGL->fExtensions.has("GL_ARB_texture_rectangle") &&
+         !fGL->fExtensions.has("GL_ANGLE_texture_rectangle"))) {
         return 0;
     }
 
@@ -286,4 +344,9 @@
                                      externalFormat, externalType, data));
     return id;
 }
+
+sk_sp<GrContext> GLTestContext::makeGrContext(const GrContextOptions& options) {
+    return GrContext::MakeGL(fGL, options);
+}
+
 }  // namespace sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/gl/GLTestContext.h b/src/third_party/skia/tools/gpu/gl/GLTestContext.h
index f5afa31..197148c 100644
--- a/src/third_party/skia/tools/gpu/gl/GLTestContext.h
+++ b/src/third_party/skia/tools/gpu/gl/GLTestContext.h
@@ -8,8 +8,8 @@
 #ifndef GLTestContext_DEFINED
 #define GLTestContext_DEFINED
 
-#include "TestContext.h"
-#include "gl/GrGLInterface.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/gpu/TestContext.h"
 
 namespace sk_gpu_test {
 /**
@@ -20,24 +20,20 @@
 public:
     ~GLTestContext() override;
 
-    virtual GrBackend backend() override { return kOpenGL_GrBackend; }
-    virtual GrBackendContext backendContext() override {
-        return reinterpret_cast<GrBackendContext>(fGL.get());
-    }
+    virtual GrBackendApi backend() override { return GrBackendApi::kOpenGL; }
 
     bool isValid() const { return SkToBool(this->gl()); }
 
-    const GrGLInterface *gl() const { return fGL.get(); }
+    const GrGLInterface* gl() const { return fGL.get(); }
 
     /** Used for testing EGLImage integration. Take a GL_TEXTURE_2D and wraps it in an EGL Image */
-    virtual GrEGLImage texture2DToEGLImage(GrGLuint /*texID*/) const { return 0; }
+    virtual GrEGLImage texture2DToEGLImage(GrGLuint /*texID*/) const { return nullptr; }
 
     virtual void destroyEGLImage(GrEGLImage) const { }
 
     /** Used for testing GL_TEXTURE_RECTANGLE integration. */
-    GrGLint createTextureRectangle(int width, int height, GrGLenum internalFormat,
-                                   GrGLenum externalFormat, GrGLenum externalType,
-                                   GrGLvoid *data);
+    GrGLuint createTextureRectangle(int width, int height, GrGLenum internalFormat,
+                                    GrGLenum externalFormat, GrGLenum externalType, GrGLvoid* data);
 
     /**
      * Used for testing EGLImage integration. Takes a EGLImage and wraps it in a
@@ -64,7 +60,7 @@
                           const char* name, const char* ext = nullptr) const {
         using Proc = Ret(GR_GL_FUNCTION_TYPE*)(Args...);
         if (!SkStrStartsWith(name, "gl")) {
-            SkFAIL("getGLProcAddress: proc name must have 'gl' prefix");
+            SK_ABORT("getGLProcAddress: proc name must have 'gl' prefix");
             *out = nullptr;
         } else if (ext) {
             SkString fullname(name);
@@ -75,13 +71,15 @@
         }
     }
 
+    sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override;
+
 protected:
     GLTestContext();
 
     /*
      * Methods that sublcasses must call from their constructors and destructors.
      */
-    void init(const GrGLInterface *, std::unique_ptr<FenceSync> = nullptr);
+    void init(sk_sp<const GrGLInterface>, std::unique_ptr<FenceSync> = nullptr);
 
     void teardown() override;
 
diff --git a/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.cpp b/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.cpp
index 52cc512..c7c9149 100644
--- a/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.cpp
+++ b/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.cpp
@@ -5,17 +5,22 @@
  * found in the LICENSE file.
  */
 
-#include "GLTestContext_angle.h"
+#include "tools/gpu/gl/angle/GLTestContext_angle.h"
+
+#define EGL_EGL_PROTOTYPES 1
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include "gl/GrGLDefines.h"
-#include "gl/GrGLUtil.h"
+#include "src/gpu/gl/GrGLDefines.h"
+#include "src/gpu/gl/GrGLUtil.h"
 
-#include "gl/GrGLInterface.h"
-#include "gl/GrGLAssembleInterface.h"
-#include "../ports/SkOSLibrary.h"
+#include "include/core/SkTime.h"
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "src/core/SkTraceEvent.h"
+#include "src/ports/SkOSLibrary.h"
+#include "third_party/externals/angle2/include/platform/Platform.h"
 
 #include <EGL/egl.h>
 
@@ -34,6 +39,16 @@
     void* fEGLLib;
 };
 
+std::function<void()> context_restorer() {
+    auto display = eglGetCurrentDisplay();
+    auto dsurface = eglGetCurrentSurface(EGL_DRAW);
+    auto rsurface = eglGetCurrentSurface(EGL_READ);
+    auto context = eglGetCurrentContext();
+    return [display, dsurface, rsurface, context] {
+        eglMakeCurrent(display, dsurface, rsurface, context);
+    };
+}
+
 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
     const Libs* libs = reinterpret_cast<const Libs*>(ctx);
     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
@@ -87,6 +102,7 @@
     void destroyGLContext();
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
 
@@ -96,6 +112,11 @@
     ANGLEBackend                fType;
     ANGLEContextVersion         fVersion;
 
+    angle::ResetDisplayPlatformFunc fResetPlatform = nullptr;
+
+    PFNEGLCREATEIMAGEKHRPROC    fCreateImage = nullptr;
+    PFNEGLDESTROYIMAGEKHRPROC   fDestroyImage = nullptr;
+
 #ifdef SK_BUILD_FOR_WIN
     HWND                        fWindow;
     HDC                         fDeviceContext;
@@ -105,8 +126,53 @@
 
 #ifdef SK_BUILD_FOR_WIN
 ATOM ANGLEGLContext::gWC = 0;
+
+enum class IsWine { kUnknown, kNo, kYes };
+
+static IsWine is_wine() {
+    HMODULE ntdll = GetModuleHandle("ntdll.dll");
+    if (!ntdll) {
+        SkDebugf("No ntdll.dll on Windows?!\n");
+        return IsWine::kUnknown;
+    }
+    return GetProcAddress(ntdll, "wine_get_version") == nullptr ? IsWine::kNo : IsWine::kYes;
+}
+
 #endif
 
+static const unsigned char* ANGLE_getTraceCategoryEnabledFlag(angle::PlatformMethods* platform,
+                                                              const char* category_group) {
+    return SkEventTracer::GetInstance()->getCategoryGroupEnabled(category_group);
+}
+
+static angle::TraceEventHandle ANGLE_addTraceEvent(angle::PlatformMethods* platform,
+                                                   char phase,
+                                                   const unsigned char* category_group_enabled,
+                                                   const char* name,
+                                                   unsigned long long id,
+                                                   double timestamp,
+                                                   int num_args,
+                                                   const char** arg_names,
+                                                   const unsigned char* arg_types,
+                                                   const unsigned long long* arg_values,
+                                                   unsigned char flags) {
+    static_assert(sizeof(unsigned long long) == sizeof(uint64_t), "Non-64-bit trace event args!");
+    return SkEventTracer::GetInstance()->addTraceEvent(
+            phase, category_group_enabled, name, id, num_args, arg_names, arg_types,
+            reinterpret_cast<const uint64_t*>(arg_values), flags);
+}
+
+static void ANGLE_updateTraceEventDuration(angle::PlatformMethods* platform,
+                                           const unsigned char* category_group_enabled,
+                                           const char* name,
+                                           angle::TraceEventHandle handle) {
+    SkEventTracer::GetInstance()->updateTraceEventDuration(category_group_enabled, name, handle);
+}
+
+static double ANGLE_monotonicallyIncreasingTime(angle::PlatformMethods* platform) {
+    return SkTime::GetSecs();
+}
+
 ANGLEGLContext::ANGLEGLContext(ANGLEBackend type, ANGLEContextVersion version,
                                ANGLEGLContext* shareContext, void* display)
     : fContext(EGL_NO_CONTEXT)
@@ -118,6 +184,14 @@
     fWindow = nullptr;
     fDeviceContext = nullptr;
 
+    static IsWine gIsWine = is_wine();
+    if (gIsWine == IsWine::kYes && type != ANGLEBackend::kOpenGL) {
+        // D3D backends of ANGLE don't really work well under Wine with our tests and are likely to
+        // crash. This makes it easier to test using the GL ANGLE backend under Wine on Linux
+        // without lots of spurious Wine debug spew and crashes.
+        return;
+    }
+
     if (EGL_NO_DISPLAY == fDisplay) {
         HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
 
@@ -167,6 +241,24 @@
         return;
     }
 
+    // Add ANGLE platform hooks to connect to Skia's tracing implementation
+    angle::GetDisplayPlatformFunc getPlatform = reinterpret_cast<angle::GetDisplayPlatformFunc>(
+            eglGetProcAddress("ANGLEGetDisplayPlatform"));
+    if (getPlatform) {
+        fResetPlatform = reinterpret_cast<angle::ResetDisplayPlatformFunc>(
+                eglGetProcAddress("ANGLEResetDisplayPlatform"));
+        SkASSERT(fResetPlatform);
+
+        angle::PlatformMethods* platformMethods = nullptr;
+        if (getPlatform(fDisplay, angle::g_PlatformMethodNames, angle::g_NumPlatformMethods,
+                        nullptr, &platformMethods)) {
+            platformMethods->addTraceEvent               = ANGLE_addTraceEvent;
+            platformMethods->getTraceCategoryEnabledFlag = ANGLE_getTraceCategoryEnabledFlag;
+            platformMethods->updateTraceEventDuration    = ANGLE_updateTraceEventDuration;
+            platformMethods->monotonicallyIncreasingTime = ANGLE_monotonicallyIncreasingTime;
+        }
+    }
+
     EGLint majorVersion;
     EGLint minorVersion;
     if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) {
@@ -214,13 +306,14 @@
 
     fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
 
+    SkScopeExit restorer(context_restorer());
     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
         SkDebugf("Could not set the context.");
         this->destroyGLContext();
         return;
     }
 
-    sk_sp<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface());
+    sk_sp<const GrGLInterface> gl = sk_gpu_test::CreateANGLEGLInterface();
     if (nullptr == gl.get()) {
         SkDebugf("Could not create ANGLE GL interface!\n");
         this->destroyGLContext();
@@ -249,8 +342,13 @@
         break;
     }
 #endif
+    const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
+    if (strstr(extensions, "EGL_KHR_image")) {
+        fCreateImage = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
+        fDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
+    }
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 ANGLEGLContext::~ANGLEGLContext() {
@@ -262,21 +360,15 @@
     if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
         return GR_EGL_NO_IMAGE;
     }
-    GrEGLImage img;
-    GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
-                           GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
-                           GR_EGL_NONE };
+    EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
+                         GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
+                         GR_EGL_NONE };
     // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
-    GR_GL_CALL_RET(this->gl(), img,
-                   EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
-                                  attribs));
-    return img;
+    return fCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
 }
 
-void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
-    GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
-}
+void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const { fDestroyImage(fDisplay, image); }
 
 GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
     GrGLClearErr(this->gl());
@@ -320,7 +412,10 @@
 
 void ANGLEGLContext::destroyGLContext() {
     if (EGL_NO_DISPLAY != fDisplay) {
-        eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        if (eglGetCurrentContext() == fContext) {
+            // This will ensure that the context is immediately deleted.
+            eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        }
 
         if (EGL_NO_CONTEXT != fContext) {
             eglDestroyContext(fDisplay, fContext);
@@ -332,6 +427,10 @@
             fSurface = EGL_NO_SURFACE;
         }
 
+        if (fResetPlatform) {
+            fResetPlatform(fDisplay);
+        }
+
         eglTerminate(fDisplay);
         fDisplay = EGL_NO_DISPLAY;
     }
@@ -355,6 +454,13 @@
     }
 }
 
+std::function<void()> ANGLEGLContext::onPlatformGetAutoContextRestore() const {
+    if (eglGetCurrentContext() == fContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void ANGLEGLContext::onPlatformSwapBuffers() const {
     if (!eglSwapBuffers(fDisplay, fSurface)) {
         SkDebugf("Could not complete eglSwapBuffers.\n");
@@ -367,7 +473,7 @@
 }  // anonymous namespace
 
 namespace sk_gpu_test {
-const GrGLInterface* CreateANGLEGLInterface() {
+sk_sp<const GrGLInterface> CreateANGLEGLInterface() {
     static Libs gLibs = { nullptr, nullptr };
 
     if (nullptr == gLibs.fGLLib) {
@@ -389,11 +495,19 @@
         return nullptr;
     }
 
-    return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
+    return GrGLMakeAssembledGLESInterface(&gLibs, angle_get_gl_proc);
 }
 
 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
-                                                    GLTestContext* shareContext, void* display){
+                                                    GLTestContext* shareContext, void* display) {
+#if defined(SK_BUILD_FOR_WIN) && defined(_M_ARM64)
+    // Windows-on-ARM only has D3D11. This will fail correctly, but it produces huge amounts of
+    // debug output for every unit test from both ANGLE and our context factory.
+    if (ANGLEBackend::kD3D11 != type) {
+        return nullptr;
+    }
+#endif
+
     ANGLEGLContext* angleShareContext = reinterpret_cast<ANGLEGLContext*>(shareContext);
     std::unique_ptr<GLTestContext> ctx(new ANGLEGLContext(type, version,
                                                           angleShareContext, display));
diff --git a/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.h b/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.h
index 5a72b93..1dc563a 100644
--- a/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.h
+++ b/src/third_party/skia/tools/gpu/gl/angle/GLTestContext_angle.h
@@ -8,7 +8,7 @@
 #ifndef GLTestContext_angle_DEFINED
 #define GLTestContext_angle_DEFINED
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 namespace sk_gpu_test {
 
@@ -16,7 +16,7 @@
  * Creates a GrGLInterface for the current ANGLE GLES Context. Here current means bound in ANGLE's
  * implementation of EGL.
  */
-const GrGLInterface* CreateANGLEGLInterface();
+sk_sp<const GrGLInterface> CreateANGLEGLInterface();
 
 enum class ANGLEBackend {
     kD3D9,
diff --git a/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp b/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
index 54845fc..cf82e35 100644
--- a/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
+++ b/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.cpp
@@ -8,12 +8,15 @@
 
 #ifndef SK_NO_COMMAND_BUFFER
 
-#include "SkMutex.h"
-#include "SkOnce.h"
-#include "gl/GrGLInterface.h"
-#include "gl/GrGLAssembleInterface.h"
-#include "gl/command_buffer/GLTestContext_command_buffer.h"
-#include "../ports/SkOSLibrary.h"
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "include/private/SkMutex.h"
+#include "include/private/SkOnce.h"
+#include "src/core/SkTLS.h"
+#include "src/ports/SkOSLibrary.h"
+#include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
+
+namespace {
 
 typedef void *EGLDisplay;
 typedef unsigned int EGLBoolean;
@@ -25,6 +28,7 @@
 typedef void* EGLNativeWindowType;
 typedef void (*__eglMustCastToProperFunctionPointerType)(void);
 #define EGL_FALSE 0
+#define EGL_TRUE 1
 #define EGL_OPENGL_ES2_BIT 0x0004
 #define EGL_CONTEXT_CLIENT_VERSION 0x3098
 #define EGL_NO_SURFACE ((EGLSurface)0)
@@ -45,6 +49,8 @@
 #define EGL_NONE 0x3038
 #define EGL_WIDTH 0x3057
 #define EGL_HEIGHT 0x3056
+#define EGL_DRAW 0x3059
+#define EGL_READ 0x305A
 
 typedef EGLDisplay (*GetDisplayProc)(EGLNativeDisplayType display_id);
 typedef EGLBoolean (*InitializeProc)(EGLDisplay dpy, EGLint *major, EGLint *minor);
@@ -77,7 +83,6 @@
 static void* gLibrary = nullptr;
 static bool gfFunctionsLoadedSuccessfully = false;
 
-namespace {
 static void load_command_buffer_functions() {
     if (!gLibrary) {
         static constexpr const char* libName =
@@ -104,12 +109,11 @@
             gfSwapBuffers = (SwapBuffersProc)GetProcedureAddress(gLibrary, "eglSwapBuffers");
             gfGetProcAddress = (GetProcAddressProc)GetProcedureAddress(gLibrary, "eglGetProcAddress");
 
-            gfFunctionsLoadedSuccessfully = gfGetDisplay && gfInitialize && gfTerminate &&
-                                            gfChooseConfig && gfCreateWindowSurface &&
-                                            gfCreatePbufferSurface && gfDestroySurface &&
-                                            gfCreateContext && gfDestroyContext && gfMakeCurrent &&
-                                            gfSwapBuffers && gfGetProcAddress;
-
+            gfFunctionsLoadedSuccessfully =
+                    gfGetDisplay && gfInitialize && gfTerminate && gfChooseConfig &&
+                    gfCreateWindowSurface && gfCreatePbufferSurface && gfDestroySurface &&
+                    gfCreateContext && gfDestroyContext && gfMakeCurrent && gfSwapBuffers &&
+                    gfGetProcAddress;
         }
     }
 }
@@ -126,12 +130,86 @@
     once(load_command_buffer_functions);
 }
 
-static const GrGLInterface* create_command_buffer_interface() {
+static sk_sp<const GrGLInterface> create_command_buffer_interface() {
     load_command_buffer_once();
     if (!gfFunctionsLoadedSuccessfully) {
         return nullptr;
     }
-    return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc);
+    return GrGLMakeAssembledGLESInterface(gLibrary, command_buffer_get_gl_proc);
+}
+
+
+// The command buffer does not correctly implement eglGetCurrent. It always returns EGL_NO_<foo>.
+// So we implement them ourselves and hook eglMakeCurrent to store the current values in TLS.
+class TLSCurrentObjects {
+public:
+    static EGLDisplay CurrentDisplay() {
+        if (auto objects = Get()) {
+            return objects->fDisplay;
+        }
+        return EGL_NO_DISPLAY;
+    }
+
+    static EGLSurface CurrentSurface(EGLint readdraw) {
+        if (auto objects = Get()) {
+            switch (readdraw) {
+                case EGL_DRAW:
+                    return objects->fDrawSurface;
+                case EGL_READ:
+                    return objects->fReadSurface;
+                default:
+                    return EGL_NO_SURFACE;
+            }
+        }
+        return EGL_NO_SURFACE;
+    }
+
+    static EGLContext CurrentContext() {
+        if (auto objects = Get()) {
+            return objects->fContext;
+        }
+        return EGL_NO_CONTEXT;
+    }
+
+    static EGLBoolean MakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read,
+                                  EGLContext ctx) {
+        if (gfFunctionsLoadedSuccessfully && EGL_TRUE == gfMakeCurrent(display, draw, read, ctx)) {
+            if (auto objects = Get()) {
+                objects->fDisplay = display;
+                objects->fDrawSurface = draw;
+                objects->fReadSurface = read;
+                objects->fContext = ctx;
+            }
+            return EGL_TRUE;
+        }
+        return EGL_FALSE;
+
+    }
+
+private:
+    EGLDisplay fDisplay = EGL_NO_DISPLAY;
+    EGLSurface fReadSurface = EGL_NO_SURFACE;
+    EGLSurface fDrawSurface = EGL_NO_SURFACE;
+    EGLContext fContext = EGL_NO_CONTEXT;
+
+    static TLSCurrentObjects* Get() {
+        return (TLSCurrentObjects*) SkTLS::Get(TLSCreate, TLSDelete);
+    }
+    static void* TLSCreate() { return new TLSCurrentObjects(); }
+    static void TLSDelete(void* objs) { delete (TLSCurrentObjects*)objs; }
+};
+
+std::function<void()> context_restorer() {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return nullptr;
+    }
+    auto display = TLSCurrentObjects::CurrentDisplay();
+    auto dsurface = TLSCurrentObjects::CurrentSurface(EGL_DRAW);
+    auto rsurface = TLSCurrentObjects::CurrentSurface(EGL_READ);
+    auto context = TLSCurrentObjects::CurrentContext();
+    return [display, dsurface, rsurface, context] {
+        TLSCurrentObjects::MakeCurrent(display, dsurface, rsurface, context);
+    };
 }
 
 }  // anonymous namespace
@@ -204,14 +282,15 @@
         return;
     }
 
-    if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+    SkScopeExit restorer(context_restorer());
+    if (!TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
         SkDebugf("Command Buffer: Could not make EGL context current.\n");
         this->destroyGLContext();
         return;
     }
 
-    sk_sp<const GrGLInterface> gl(create_command_buffer_interface());
-    if (nullptr == gl.get()) {
+    auto gl = create_command_buffer_interface();
+    if (!gl) {
         SkDebugf("Command Buffer: Could not create CommandBuffer GL interface.\n");
         this->destroyGLContext();
         return;
@@ -222,7 +301,7 @@
         return;
     }
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 CommandBufferGLTestContext::~CommandBufferGLTestContext() {
@@ -237,15 +316,19 @@
     if (EGL_NO_DISPLAY == fDisplay) {
         return;
     }
+    bool wasCurrent = false;
     if (EGL_NO_CONTEXT != fContext) {
+        wasCurrent = (TLSCurrentObjects::CurrentContext() == fContext);
         gfDestroyContext(fDisplay, fContext);
         fContext = EGL_NO_CONTEXT;
     }
-    // Call MakeCurrent after destroying the context, so that the EGL implementation knows that
-    // the context is not used anymore after it is released from being current.  This way
-    // command buffer does not need to abandon the context before destruction, and no
-    // client-side errors are printed.
-    gfMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    if (wasCurrent) {
+        // Call MakeCurrent after destroying the context, so that the EGL implementation knows that
+        // the context is not used anymore after it is released from being current.This way the
+        // command buffer does not need to abandon the context before destruction, and no
+        // client-side errors are printed.
+        TLSCurrentObjects::MakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    }
 
     if (EGL_NO_SURFACE != fSurface) {
         gfDestroySurface(fDisplay, fSurface);
@@ -258,11 +341,18 @@
     if (!gfFunctionsLoadedSuccessfully) {
         return;
     }
-    if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+    if (!TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
         SkDebugf("Command Buffer: Could not make EGL context current.\n");
     }
 }
 
+std::function<void()> CommandBufferGLTestContext::onPlatformGetAutoContextRestore() const {
+    if (!gfFunctionsLoadedSuccessfully || TLSCurrentObjects::CurrentContext() == fContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void CommandBufferGLTestContext::onPlatformSwapBuffers() const {
     if (!gfFunctionsLoadedSuccessfully) {
         return;
@@ -288,7 +378,7 @@
 }
 
 bool CommandBufferGLTestContext::makeCurrent() {
-    return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
+    return TLSCurrentObjects::MakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
 }
 
 int CommandBufferGLTestContext::getStencilBits() {
diff --git a/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h b/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h
index 7582f16..089c06e 100644
--- a/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h
+++ b/src/third_party/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h
@@ -9,7 +9,7 @@
 #ifndef GLTestContext_command_buffer_DEFINED
 #define GLTestContext_command_buffer_DEFINED
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 namespace sk_gpu_test {
 class CommandBufferGLTestContext : public GLTestContext {
@@ -42,6 +42,8 @@
 
     void onPlatformMakeCurrent() const override;
 
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
+
     void onPlatformSwapBuffers() const override;
 
     GrGLFuncPtr onPlatformGetProcAddress(const char *name) const override;
diff --git a/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.cpp b/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.cpp
deleted file mode 100644
index e8eea8f..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.cpp
+++ /dev/null
@@ -1,1222 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "DebugGLTestContext.h"
-
-#include "GrBufferObj.h"
-#include "GrFrameBufferObj.h"
-#include "GrProgramObj.h"
-#include "GrRenderBufferObj.h"
-#include "GrShaderObj.h"
-#include "GrTextureObj.h"
-#include "GrTextureUnitObj.h"
-#include "GrVertexArrayObj.h"
-#include "gl/GrGLTestInterface.h"
-
-#include "SkMutex.h"
-
-namespace {
-
-// Helper macro to make creating an object (where you need to get back a derived type) easier
-#define CREATE(className, classEnum)                     \
-    reinterpret_cast<className *>(this->createObj(classEnum))
-
-// Helper macro to make creating an object (where you need to get back a derived type) easier
-#define FIND(id, className, classEnum)                   \
-    reinterpret_cast<className *>(this->findObject(id, classEnum))
-
-class DebugInterface : public GrGLTestInterface {
-public:
-    DebugInterface()
-        : fCurrGenericID(0)
-        , fCurrTextureUnit(0)
-        , fVertexArray(nullptr)
-        , fPackRowLength(0)
-        , fUnpackRowLength(0)
-        , fPackAlignment(4)
-        , fFrameBuffer(nullptr)
-        , fRenderBuffer(nullptr)
-        , fProgram(nullptr)
-        , fAbandoned(false) {
-        for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
-            fTextureUnits[i] =
-                reinterpret_cast<GrTextureUnitObj*>(this->createObj(kTextureUnit_ObjTypes));
-            fTextureUnits[i]->ref();
-            fTextureUnits[i]->setNumber(i);
-        }
-        memset(fBoundBuffers, 0, sizeof(fBoundBuffers));
-        this->init(kGL_GrGLStandard);
-    }
-
-    ~DebugInterface() override {
-        // unref & delete the texture units first so they don't show up on the leak report
-        for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
-            fTextureUnits[i]->unref();
-            fTextureUnits[i]->deleteAction();
-        }
-        for (int i = 0; i < fObjects.count(); ++i) {
-            delete fObjects[i];
-        }
-        fObjects.reset();
-
-        memset(fBoundBuffers, 0, sizeof(fBoundBuffers));
-        fVertexArray = nullptr;
-
-        this->report();
-    }
-
-    void abandon() const override { fAbandoned = true; }
-
-    GrGLvoid activeTexture(GrGLenum texture) override {
-        // Ganesh offsets the texture unit indices
-        texture -= GR_GL_TEXTURE0;
-        GrAlwaysAssert(texture < kDefaultMaxTextureUnits);
-        fCurrTextureUnit = texture;
-    }
-
-    GrGLvoid attachShader(GrGLuint programID, GrGLuint shaderID) override {
-
-        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
-        GrAlwaysAssert(program);
-
-        GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
-        GrAlwaysAssert(shader);
-
-        program->AttachShader(shader);
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////
-    GrGLvoid bindTexture(GrGLenum target, GrGLuint textureID) override {
-        GrAlwaysAssert(target == GR_GL_TEXTURE_2D ||
-                       target == GR_GL_TEXTURE_RECTANGLE ||
-                       target == GR_GL_TEXTURE_EXTERNAL);
-
-        // a textureID of 0 is acceptable - it binds to the default texture target
-        GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
-
-        this->setTexture(texture);
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////
-    GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data,
-                        GrGLenum usage) override {
-        GrAlwaysAssert(size >= 0);
-        GrAlwaysAssert(GR_GL_STREAM_DRAW == usage ||
-                       GR_GL_STATIC_DRAW == usage ||
-                       GR_GL_DYNAMIC_DRAW == usage);
-
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        GrAlwaysAssert(buffer);
-        GrAlwaysAssert(buffer->getBound());
-
-        buffer->allocate(size, reinterpret_cast<const GrGLchar *>(data));
-        buffer->setUsage(usage);
-    }
-
-
-    GrGLvoid pixelStorei(GrGLenum pname, GrGLint param) override {
-
-        switch (pname) {
-            case GR_GL_UNPACK_ROW_LENGTH:
-                fUnpackRowLength = param;
-                break;
-            case GR_GL_PACK_ROW_LENGTH:
-                fPackRowLength = param;
-                break;
-            case GR_GL_UNPACK_ALIGNMENT:
-                break;
-            case GR_GL_PACK_ALIGNMENT:
-                fPackAlignment = param;
-                break;
-            default:
-                GrAlwaysAssert(false);
-                break;
-        }
-    }
-
-    GrGLvoid readPixels(GrGLint x,
-                        GrGLint y,
-                        GrGLsizei width,
-                        GrGLsizei height,
-                        GrGLenum format,
-                        GrGLenum type,
-                        GrGLvoid* pixels) override {
-
-        GrGLint pixelsInRow = width;
-        if (fPackRowLength > 0) {
-            pixelsInRow = fPackRowLength;
-        }
-
-        GrGLint componentsPerPixel = 0;
-
-        switch (format) {
-            case GR_GL_RGBA:
-                // fallthrough
-            case GR_GL_BGRA:
-                componentsPerPixel = 4;
-                break;
-            case GR_GL_RGB:
-                componentsPerPixel = 3;
-                break;
-            case GR_GL_RED:
-                componentsPerPixel = 1;
-                break;
-            default:
-                GrAlwaysAssert(false);
-                break;
-        }
-
-        GrGLint alignment = fPackAlignment;
-
-        GrGLint componentSize = 0;  // size (in bytes) of a single component
-
-        switch (type) {
-            case GR_GL_UNSIGNED_BYTE:
-                componentSize = 1;
-                break;
-            default:
-                GrAlwaysAssert(false);
-                break;
-        }
-
-        GrGLint rowStride = 0;  // number of components (not bytes) to skip
-        if (componentSize >= alignment) {
-            rowStride = componentsPerPixel * pixelsInRow;
-        } else {
-            float fTemp =
-                sk_float_ceil(componentSize * componentsPerPixel * pixelsInRow /
-                              static_cast<float>(alignment));
-            rowStride = static_cast<GrGLint>(alignment * fTemp / componentSize);
-        }
-
-        GrGLchar *scanline = static_cast<GrGLchar *>(pixels);
-        for (int y = 0; y < height; ++y) {
-            memset(scanline, 0, componentsPerPixel * componentSize * width);
-            scanline += rowStride;
-        }
-    }
-
-    GrGLvoid useProgram(GrGLuint programID) override {
-
-        // A programID of 0 is legal
-        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
-
-        this->useProgram(program);
-    }
-
-    GrGLvoid bindFramebuffer(GrGLenum target, GrGLuint frameBufferID) override {
-
-        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target ||
-                       GR_GL_READ_FRAMEBUFFER == target ||
-                       GR_GL_DRAW_FRAMEBUFFER);
-
-        // a frameBufferID of 0 is acceptable - it binds to the default
-        // frame buffer
-        GrFrameBufferObj *frameBuffer = FIND(frameBufferID, GrFrameBufferObj,
-                                             kFrameBuffer_ObjTypes);
-
-        this->setFrameBuffer(frameBuffer);
-    }
-
-    GrGLvoid bindRenderbuffer(GrGLenum target, GrGLuint renderBufferID) override {
-
-        GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
-
-        // a renderBufferID of 0 is acceptable - it unbinds the bound render buffer
-        GrRenderBufferObj *renderBuffer = FIND(renderBufferID, GrRenderBufferObj,
-                                               kRenderBuffer_ObjTypes);
-
-        this->setRenderBuffer(renderBuffer);
-    }
-
-    GrGLvoid deleteTextures(GrGLsizei n, const GrGLuint* textures) override {
-        // first potentially unbind the texture
-        for (unsigned int i = 0; i < kDefaultMaxTextureUnits; ++i) {
-            GrTextureUnitObj *pTU = this->getTextureUnit(i);
-
-            if (pTU->getTexture()) {
-                for (int j = 0; j < n; ++j) {
-
-                    if (textures[j] == pTU->getTexture()->getID()) {
-                        // this ID is the current texture - revert the binding to 0
-                        pTU->setTexture(nullptr);
-                    }
-                }
-            }
-        }
-
-        // TODO: fuse the following block with DeleteRenderBuffers?
-        // Open GL will remove a deleted render buffer from the active
-        // frame buffer but not from any other frame buffer
-        if (this->getFrameBuffer()) {
-
-            GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
-
-            for (int i = 0; i < n; ++i) {
-
-                if (frameBuffer->getColor() &&
-                    textures[i] == frameBuffer->getColor()->getID()) {
-                    frameBuffer->setColor(nullptr);
-                }
-                if (frameBuffer->getDepth() &&
-                    textures[i] == frameBuffer->getDepth()->getID()) {
-                    frameBuffer->setDepth(nullptr);
-                }
-                if (frameBuffer->getStencil() &&
-                    textures[i] == frameBuffer->getStencil()->getID()) {
-                    frameBuffer->setStencil(nullptr);
-                }
-            }
-        }
-
-        // then actually "delete" the buffers
-        for (int i = 0; i < n; ++i) {
-            GrTextureObj *buffer = FIND(textures[i], GrTextureObj, kTexture_ObjTypes);
-            GrAlwaysAssert(buffer);
-
-            // OpenGL gives no guarantees if a texture is deleted while attached to
-            // something other than the currently bound frame buffer
-            GrAlwaysAssert(!buffer->getBound());
-
-            GrAlwaysAssert(!buffer->getDeleted());
-            buffer->deleteAction();
-        }
-
-    }
-
-    GrGLvoid deleteFramebuffers(GrGLsizei n, const GrGLuint *frameBuffers) override {
-
-        // first potentially unbind the buffers
-        if (this->getFrameBuffer()) {
-            for (int i = 0; i < n; ++i) {
-
-                if (frameBuffers[i] ==
-                    this->getFrameBuffer()->getID()) {
-                    // this ID is the current frame buffer - rebind to the default
-                    this->setFrameBuffer(nullptr);
-                }
-            }
-        }
-
-        // then actually "delete" the buffers
-        for (int i = 0; i < n; ++i) {
-            GrFrameBufferObj *buffer = FIND(frameBuffers[i], GrFrameBufferObj,
-                                            kFrameBuffer_ObjTypes);
-            GrAlwaysAssert(buffer);
-
-            GrAlwaysAssert(!buffer->getDeleted());
-            buffer->deleteAction();
-        }
-    }
-
-    GrGLvoid deleteRenderbuffers(GrGLsizei n,const GrGLuint *renderBuffers) override {
-
-        // first potentially unbind the buffers
-        if (this->getRenderBuffer()) {
-            for (int i = 0; i < n; ++i) {
-
-                if (renderBuffers[i] ==
-                    this->getRenderBuffer()->getID()) {
-                    // this ID is the current render buffer - make no
-                    // render buffer be bound
-                    this->setRenderBuffer(nullptr);
-                }
-            }
-        }
-
-        // TODO: fuse the following block with DeleteTextures?
-        // Open GL will remove a deleted render buffer from the active frame
-        // buffer but not from any other frame buffer
-        if (this->getFrameBuffer()) {
-
-            GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
-
-            for (int i = 0; i < n; ++i) {
-
-                if (frameBuffer->getColor() &&
-                    renderBuffers[i] == frameBuffer->getColor()->getID()) {
-                    frameBuffer->setColor(nullptr);
-                }
-                if (frameBuffer->getDepth() &&
-                    renderBuffers[i] == frameBuffer->getDepth()->getID()) {
-                    frameBuffer->setDepth(nullptr);
-                }
-                if (frameBuffer->getStencil() &&
-                    renderBuffers[i] == frameBuffer->getStencil()->getID()) {
-                    frameBuffer->setStencil(nullptr);
-                }
-            }
-        }
-
-        // then actually "delete" the buffers
-        for (int i = 0; i < n; ++i) {
-            GrRenderBufferObj *buffer = FIND(renderBuffers[i], GrRenderBufferObj,
-                                             kRenderBuffer_ObjTypes);
-            GrAlwaysAssert(buffer);
-
-            // OpenGL gives no guarantees if a render buffer is deleted
-            // while attached to something other than the currently
-            // bound frame buffer
-            GrAlwaysAssert(!buffer->getColorBound());
-            GrAlwaysAssert(!buffer->getDepthBound());
-            // However, at GrContext destroy time we release all GrRsources and so stencil buffers
-            // may get deleted before FBOs that refer to them.
-            //GrAlwaysAssert(!buffer->getStencilBound());
-
-            GrAlwaysAssert(!buffer->getDeleted());
-            buffer->deleteAction();
-        }
-    }
-
-    GrGLvoid renderbufferStorage(GrGLenum target, GrGLenum internalformat, GrGLsizei width,
-                                 GrGLsizei height) override {
-        GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
-        GrRenderBufferObj* renderBuffer = this->getRenderBuffer();
-        GrAlwaysAssert(renderBuffer);
-        renderBuffer->setNumSamples(1);
-    }
-
-    GrGLvoid renderbufferStorageMultisample(GrGLenum target, GrGLsizei samples,
-                                            GrGLenum internalformat, GrGLsizei width,
-                                            GrGLsizei height) override {
-        GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
-        GrRenderBufferObj* renderBuffer = this->getRenderBuffer();
-        GrAlwaysAssert(renderBuffer);
-        renderBuffer->setNumSamples(samples);
-    }
-
-    GrGLvoid namedRenderbufferStorage(GrGLuint renderbuffer, GrGLenum GrGLinternalformat,
-                                      GrGLsizei width, GrGLsizei height) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLvoid namedRenderbufferStorageMultisample(GrGLuint renderbuffer, GrGLsizei samples,
-                                                 GrGLenum GrGLinternalformat, GrGLsizei width,
-                                                 GrGLsizei height) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLvoid framebufferRenderbuffer(GrGLenum target,
-                                     GrGLenum attachment,
-                                     GrGLenum renderbuffertarget,
-                                     GrGLuint renderBufferID) override {
-
-        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
-        GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
-                       GR_GL_DEPTH_ATTACHMENT == attachment ||
-                       GR_GL_STENCIL_ATTACHMENT == attachment);
-        GrAlwaysAssert(GR_GL_RENDERBUFFER == renderbuffertarget);
-
-        GrFrameBufferObj *framebuffer = this->getFrameBuffer();
-        // A render buffer cannot be attached to the default framebuffer
-        GrAlwaysAssert(framebuffer);
-
-        // a renderBufferID of 0 is acceptable - it unbinds the current
-        // render buffer
-        GrRenderBufferObj *renderbuffer = FIND(renderBufferID, GrRenderBufferObj,
-                                               kRenderBuffer_ObjTypes);
-
-        switch (attachment) {
-            case GR_GL_COLOR_ATTACHMENT0:
-                framebuffer->setColor(renderbuffer);
-                break;
-            case GR_GL_DEPTH_ATTACHMENT:
-                framebuffer->setDepth(renderbuffer);
-                break;
-            case GR_GL_STENCIL_ATTACHMENT:
-                framebuffer->setStencil(renderbuffer);
-                break;
-            default:
-                GrAlwaysAssert(false);
-                break;
-        };
-
-    }
-
-    GrGLvoid namedFramebufferRenderbuffer(GrGLuint framebuffer, GrGLenum attachment,
-                                          GrGLenum renderbuffertarget,
-                                          GrGLuint renderbuffer) override {
-        SK_ABORT("Not implemented");
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////
-    GrGLvoid framebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget,
-                                  GrGLuint textureID, GrGLint level) override {
-
-        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
-        GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
-                       GR_GL_DEPTH_ATTACHMENT == attachment ||
-                       GR_GL_STENCIL_ATTACHMENT == attachment);
-        GrAlwaysAssert(GR_GL_TEXTURE_2D == textarget);
-
-        GrFrameBufferObj *framebuffer = this->getFrameBuffer();
-        // A texture cannot be attached to the default framebuffer
-        GrAlwaysAssert(framebuffer);
-
-        // A textureID of 0 is allowed - it unbinds the currently bound texture
-        GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
-        if (texture) {
-            // The texture shouldn't be bound to a texture unit - this
-            // could lead to a feedback loop
-            GrAlwaysAssert(!texture->getBound());
-        }
-
-        GrAlwaysAssert(0 == level);
-
-        switch (attachment) {
-            case GR_GL_COLOR_ATTACHMENT0:
-                framebuffer->setColor(texture);
-                break;
-            case GR_GL_DEPTH_ATTACHMENT:
-                framebuffer->setDepth(texture);
-                break;
-            case GR_GL_STENCIL_ATTACHMENT:
-                framebuffer->setStencil(texture);
-                break;
-            default:
-                GrAlwaysAssert(false);
-                break;
-        };
-    }
-
-    GrGLvoid framebufferTexture2DMultisample(GrGLenum target, GrGLenum attachment,
-                                             GrGLenum textarget, GrGLuint texture, GrGLint level,
-                                             GrGLsizei samples) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLvoid namedFramebufferTexture1D(GrGLuint framebuffer, GrGLenum attachment,
-                                       GrGLenum textarget, GrGLuint texture,
-                                       GrGLint level) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLvoid namedFramebufferTexture2D(GrGLuint framebuffer, GrGLenum attachment,
-                                       GrGLenum textarget, GrGLuint texture,
-                                       GrGLint level) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLvoid namedFramebufferTexture3D(GrGLuint framebuffer, GrGLenum attachment,
-                                       GrGLenum textarget, GrGLuint texture, GrGLint level,
-                                       GrGLint zoffset) override {
-        SK_ABORT("Not implemented");
-    }
-
-    GrGLuint createProgram() override {
-
-        GrProgramObj *program = CREATE(GrProgramObj, kProgram_ObjTypes);
-
-        return program->getID();
-    }
-
-    GrGLuint createShader(GrGLenum type) override {
-
-        GrAlwaysAssert(GR_GL_VERTEX_SHADER == type ||
-                       GR_GL_FRAGMENT_SHADER == type);
-
-        GrShaderObj *shader = CREATE(GrShaderObj, kShader_ObjTypes);
-        shader->setType(type);
-
-        return shader->getID();
-    }
-
-    GrGLenum checkFramebufferStatus(GrGLenum target) override { return GR_GL_FRAMEBUFFER_COMPLETE; }
-
-    GrGLvoid deleteProgram(GrGLuint programID) override {
-
-        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
-        GrAlwaysAssert(program);
-
-        if (program->getRefCount()) {
-            // someone is still using this program so we can't delete it here
-            program->setMarkedForDeletion();
-        } else {
-            program->deleteAction();
-        }
-    }
-
-    GrGLvoid deleteShader(GrGLuint shaderID) override {
-
-        GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
-        GrAlwaysAssert(shader);
-
-        if (shader->getRefCount()) {
-            // someone is still using this shader so we can't delete it here
-            shader->setMarkedForDeletion();
-        } else {
-            shader->deleteAction();
-        }
-    }
-
-    GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override {
-        this->genObjs(kBuffer_ObjTypes, n, ids);
-    }
-
-    GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint* ids) override {
-        this->genObjs(kFrameBuffer_ObjTypes, n, ids);
-    }
-
-    GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint* ids) override {
-        this->genObjs(kRenderBuffer_ObjTypes, n, ids);
-    }
-
-    GrGLvoid genTextures(GrGLsizei n, GrGLuint* ids) override {
-        this->genObjs(kTexture_ObjTypes, n, ids);
-    }
-
-    GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint* ids) override {
-        this->genObjs(kVertexArray_ObjTypes, n, ids);
-    }
-
-    GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); }
-
-    GrGLenum getError() override { return GR_GL_NO_ERROR; }
-
-    GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override {
-        // TODO: remove from Ganesh the #defines for gets we don't use.
-        // We would like to minimize gets overall due to performance issues
-        switch (pname) {
-            case GR_GL_CONTEXT_PROFILE_MASK:
-                *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
-                break;
-            case GR_GL_STENCIL_BITS:
-                *params = 8;
-                break;
-            case GR_GL_SAMPLES: {
-                GrFrameBufferObj* framebuffer = this->getFrameBuffer();
-                GrAlwaysAssert(framebuffer);
-                int numSamples = 0;
-
-                if (GrFBBindableObj* stencil = framebuffer->getStencil()) {
-                    numSamples = stencil->numSamples();
-                }
-                if (GrFBBindableObj* depth = framebuffer->getDepth()) {
-                    GrAlwaysAssert(!numSamples || numSamples == depth->numSamples());
-                    numSamples = depth->numSamples();
-                }
-                if (GrFBBindableObj* color = framebuffer->getColor()) {
-                    GrAlwaysAssert(!numSamples || numSamples == color->numSamples());
-                    numSamples = color->numSamples();
-                }
-                GrAlwaysAssert(numSamples);
-                *params = numSamples;
-                break;
-            }
-            case GR_GL_FRAMEBUFFER_BINDING:
-                *params = 0;
-                break;
-            case GR_GL_VIEWPORT:
-                params[0] = 0;
-                params[1] = 0;
-                params[2] = 800;
-                params[3] = 600;
-                break;
-            case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
-            case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
-            case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
-            case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
-                *params = 8;
-                break;
-            case GR_GL_MAX_TEXTURE_COORDS:
-                *params = 8;
-                break;
-            case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
-                *params = kDefaultMaxVertexUniformVectors;
-                break;
-            case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
-                *params = kDefaultMaxFragmentUniformVectors;
-                break;
-            case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
-                *params = 16 * 4;
-                break;
-            case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
-                *params = 0;
-                break;
-            case GR_GL_COMPRESSED_TEXTURE_FORMATS:
-                break;
-            case GR_GL_MAX_TEXTURE_SIZE:
-                *params = 8192;
-                break;
-            case GR_GL_MAX_RENDERBUFFER_SIZE:
-                *params = 8192;
-                break;
-            case GR_GL_MAX_SAMPLES:
-                *params = 32;
-                break;
-            case GR_GL_MAX_VERTEX_ATTRIBS:
-                *params = kDefaultMaxVertexAttribs;
-                break;
-            case GR_GL_MAX_VARYING_VECTORS:
-                *params = kDefaultMaxVaryingVectors;
-                break;
-            case GR_GL_NUM_EXTENSIONS: {
-                GrGLint i = 0;
-                while (kExtensions[i++]);
-                *params = i;
-                break;
-            }
-            default:
-                SkFAIL("Unexpected pname to GetIntegerv");
-        }
-    }
-
-    GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override {
-        val[0] = val[1] = 0.5f;
-    }
-
-    GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override {
-        this->getShaderOrProgramiv(program, pname, params);
-    }
-
-    GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length,
-                               char* infolog) override {
-        this->getInfoLog(program, bufsize, length, infolog);
-    }
-
-    GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override {
-        switch (pname) {
-            case GR_GL_CURRENT_QUERY:
-                *params = 0;
-                break;
-            case GR_GL_QUERY_COUNTER_BITS:
-                *params = 32;
-                break;
-            default:
-                SkFAIL("Unexpected pname passed GetQueryiv.");
-        }
-    }
-
-    GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override {
-        this->queryResult(id, pname, params);
-    }
-
-    GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override {
-        this->queryResult(id, pname, params);
-    }
-
-    GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override {
-        this->queryResult(id, pname, params);
-    }
-
-    GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override {
-        this->queryResult(id, pname, params);
-    }
-
-    GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override {
-        this->getShaderOrProgramiv(shader, pname, params);
-    }
-
-    GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length,
-                              char* infolog) override {
-        this->getInfoLog(shader, bufsize, length, infolog);
-    }
-
-    const GrGLubyte* getString(GrGLenum name) override {
-        switch (name) {
-            case GR_GL_EXTENSIONS:
-                return CombinedExtensionString();
-            case GR_GL_VERSION:
-                return (const GrGLubyte*)"4.0 Debug GL";
-            case GR_GL_SHADING_LANGUAGE_VERSION:
-                return (const GrGLubyte*)"4.20.8 Debug GLSL";
-            case GR_GL_VENDOR:
-                return (const GrGLubyte*)"Debug Vendor";
-            case GR_GL_RENDERER:
-                return (const GrGLubyte*)"The Debug (Non-)Renderer";
-            default:
-                SkFAIL("Unexpected name passed to GetString");
-                return nullptr;
-        }
-    }
-
-    const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override {
-        switch (name) {
-            case GR_GL_EXTENSIONS: {
-                GrGLint count;
-                this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count);
-                if ((GrGLint)i <= count) {
-                    return (const GrGLubyte*) kExtensions[i];
-                } else {
-                    return nullptr;
-                }
-            }
-            default:
-                SkFAIL("Unexpected name passed to GetStringi");
-                return nullptr;
-        }
-    }
-
-    GrGLvoid getTexLevelParameteriv(GrGLenum target, GrGLint level, GrGLenum pname,
-                                    GrGLint* params) override {
-        // we used to use this to query stuff about externally created textures,
-        // now we just require clients to tell us everything about the texture.
-        SkFAIL("Should never query texture parameters.");
-    }
-
-    GrGLvoid deleteVertexArrays(GrGLsizei n, const GrGLuint* ids) override {
-        for (GrGLsizei i = 0; i < n; ++i) {
-            GrVertexArrayObj* array = FIND(ids[i], GrVertexArrayObj, kVertexArray_ObjTypes);
-            GrAlwaysAssert(array);
-
-            // Deleting the current vertex array binds object 0
-            if (this->getVertexArray() == array) {
-                this->setVertexArray(nullptr);
-            }
-
-            if (array->getRefCount()) {
-                // someone is still using this vertex array so we can't delete it here
-                array->setMarkedForDeletion();
-            } else {
-                array->deleteAction();
-            }
-        }
-    }
-
-    GrGLvoid bindVertexArray(GrGLuint id) override {
-        GrVertexArrayObj* array = FIND(id, GrVertexArrayObj, kVertexArray_ObjTypes);
-        GrAlwaysAssert((0 == id) || array);
-        this->setVertexArray(array);
-    }
-
-    GrGLvoid bindBuffer(GrGLenum target, GrGLuint bufferID) override {
-        GrBufferObj *buffer = FIND(bufferID, GrBufferObj, kBuffer_ObjTypes);
-        // 0 is a permissible bufferID - it unbinds the current buffer
-
-        this->setBuffer(GetBufferIndex(target), buffer);
-    }
-
-    // deleting a bound buffer has the side effect of binding 0
-    GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override {
-        // first potentially unbind the buffers
-        for (int buffIdx = 0; buffIdx < kNumBufferTargets; ++buffIdx) {
-            GrBufferObj* buffer = fBoundBuffers[buffIdx];
-            if (!buffer) {
-                continue;
-            }
-            for (int i = 0; i < n; ++i) {
-                if (ids[i] == buffer->getID()) {
-                    this->setBuffer(buffIdx, nullptr);
-                    break;
-                }
-            }
-        }
-
-        // then actually "delete" the buffers
-        for (int i = 0; i < n; ++i) {
-            GrBufferObj *buffer = FIND(ids[i], GrBufferObj, kBuffer_ObjTypes);
-            GrAlwaysAssert(buffer);
-
-            GrAlwaysAssert(!buffer->getDeleted());
-            buffer->deleteAction();
-        }
-    }
-
-    // map a buffer to the caller's address space
-    GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length,
-                             GrGLbitfield access) override {
-        // We only expect read access and we expect that the buffer or range is always invalidated.
-        GrAlwaysAssert(!SkToBool(GR_GL_MAP_READ_BIT & access));
-        GrAlwaysAssert((GR_GL_MAP_INVALIDATE_BUFFER_BIT | GR_GL_MAP_INVALIDATE_RANGE_BIT) & access);
-
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        if (buffer) {
-            GrAlwaysAssert(offset >= 0 && offset + length <= buffer->getSize());
-            GrAlwaysAssert(!buffer->getMapped());
-            buffer->setMapped(offset, length);
-            return buffer->getDataPtr() + offset;
-        }
-
-        GrAlwaysAssert(false);
-        return nullptr;        // no buffer bound to the target
-    }
-
-    GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override {
-        GrAlwaysAssert(GR_GL_WRITE_ONLY == access);
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        return this->mapBufferRange(target, 0, buffer->getSize(),
-                                    GR_GL_MAP_WRITE_BIT | GR_GL_MAP_INVALIDATE_BUFFER_BIT);
-    }
-
-    // remove a buffer from the caller's address space
-    // TODO: check if the "access" method from "glMapBuffer" was honored
-    GrGLboolean unmapBuffer(GrGLenum target) override {
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        if (buffer) {
-            GrAlwaysAssert(buffer->getMapped());
-            buffer->resetMapped();
-            return GR_GL_TRUE;
-        }
-
-        GrAlwaysAssert(false);
-        return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
-    }
-
-    GrGLvoid flushMappedBufferRange(GrGLenum target, GrGLintptr offset,
-                                    GrGLsizeiptr length) override {
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        if (buffer) {
-            GrAlwaysAssert(buffer->getMapped());
-            GrAlwaysAssert(offset >= 0 && (offset + length) <= buffer->getMappedLength());
-        } else {
-            GrAlwaysAssert(false);
-        }
-    }
-
-    GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum value, GrGLint* params) override {
-
-        GrAlwaysAssert(GR_GL_BUFFER_SIZE == value ||
-                       GR_GL_BUFFER_USAGE == value);
-
-        GrBufferObj *buffer = fBoundBuffers[GetBufferIndex(target)];
-        GrAlwaysAssert(buffer);
-
-        switch (value) {
-            case GR_GL_BUFFER_MAPPED:
-                *params = GR_GL_FALSE;
-                if (buffer)
-                    *params = buffer->getMapped() ? GR_GL_TRUE : GR_GL_FALSE;
-                break;
-            case GR_GL_BUFFER_SIZE:
-                *params = 0;
-                if (buffer)
-                    *params = SkToInt(buffer->getSize());
-                break;
-            case GR_GL_BUFFER_USAGE:
-                *params = GR_GL_STATIC_DRAW;
-                if (buffer)
-                    *params = buffer->getUsage();
-                break;
-            default:
-                SkFAIL("Unexpected value to glGetBufferParamateriv");
-                break;
-        }
-    }
-
-private:
-    inline int static GetBufferIndex(GrGLenum glTarget) {
-        switch (glTarget) {
-            default:                           SkFAIL("Unexpected GL target to GetBufferIndex");
-            case GR_GL_ARRAY_BUFFER:           return 0;
-            case GR_GL_ELEMENT_ARRAY_BUFFER:   return 1;
-            case GR_GL_TEXTURE_BUFFER:         return 2;
-            case GR_GL_DRAW_INDIRECT_BUFFER:   return 3;
-        }
-    }
-    constexpr int static kNumBufferTargets = 4;
-
-    // the OpenGLES 2.0 spec says this must be >= 128
-    static const GrGLint kDefaultMaxVertexUniformVectors = 128;
-
-    // the OpenGLES 2.0 spec says this must be >=16
-    static const GrGLint kDefaultMaxFragmentUniformVectors = 16;
-
-    // the OpenGLES 2.0 spec says this must be >= 8
-    static const GrGLint kDefaultMaxVertexAttribs = 8;
-
-    // the OpenGLES 2.0 spec says this must be >= 8
-    static const GrGLint kDefaultMaxVaryingVectors = 8;
-
-    // the OpenGLES 2.0 spec says this must be >= 2
-    static const GrGLint kDefaultMaxTextureUnits = 8;
-
-    static const char* kExtensions[];
-
-    GrGLuint                    fCurrGenericID;
-    GrGLuint                    fCurrTextureUnit;
-    GrTextureUnitObj*           fTextureUnits[kDefaultMaxTextureUnits];
-    GrBufferObj*                fBoundBuffers[kNumBufferTargets];
-    GrVertexArrayObj*           fVertexArray;
-    GrGLint                     fPackRowLength;
-    GrGLint                     fUnpackRowLength;
-    GrGLint                     fPackAlignment;
-    GrFrameBufferObj*           fFrameBuffer;
-    GrRenderBufferObj*          fRenderBuffer;
-    GrProgramObj*               fProgram;
-    mutable bool                fAbandoned;
-    // global store of all objects
-    SkTArray<GrFakeRefObj *>    fObjects;
-
-    static const GrGLubyte* CombinedExtensionString() {
-        static SkString gExtString;
-        static SkMutex gMutex;
-        gMutex.acquire();
-        if (0 == gExtString.size()) {
-            int i = 0;
-            while (kExtensions[i]) {
-                if (i > 0) {
-                    gExtString.append(" ");
-                }
-                gExtString.append(kExtensions[i]);
-                ++i;
-            }
-        }
-        gMutex.release();
-        return (const GrGLubyte*) gExtString.c_str();
-    }
-
-    GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) {
-        for (int i = 0; i < n; ++i) {
-            ids[i] = ++fCurrGenericID;
-        }
-    }
-
-    GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length,
-                        char* infolog) {
-        if (length) {
-            *length = 0;
-        }
-        if (bufsize > 0) {
-            *infolog = 0;
-        }
-    }
-
-    GrGLvoid getShaderOrProgramiv(GrGLuint object,  GrGLenum pname, GrGLint* params) {
-        switch (pname) {
-            case GR_GL_LINK_STATUS:  // fallthru
-            case GR_GL_COMPILE_STATUS:
-                *params = GR_GL_TRUE;
-                break;
-            case GR_GL_INFO_LOG_LENGTH:
-                *params = 0;
-                break;
-                // we don't expect any other pnames
-            default:
-                SkFAIL("Unexpected pname to GetProgramiv");
-                break;
-        }
-    }
-
-    template <typename T>
-    void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) {
-        switch (pname) {
-            case GR_GL_QUERY_RESULT_AVAILABLE:
-                *params = GR_GL_TRUE;
-                break;
-            case GR_GL_QUERY_RESULT:
-                *params = 0;
-                break;
-            default:
-                SkFAIL("Unexpected pname passed to GetQueryObject.");
-                break;
-        }
-    }
-
-    enum ObjTypes {
-        kTexture_ObjTypes = 0,
-        kBuffer_ObjTypes,
-        kRenderBuffer_ObjTypes,
-        kFrameBuffer_ObjTypes,
-        kShader_ObjTypes,
-        kProgram_ObjTypes,
-        kTextureUnit_ObjTypes,
-        kVertexArray_ObjTypes,
-        kObjTypeCount
-    };
-
-    typedef GrFakeRefObj *(*Create)();
-
-    static Create gFactoryFunc[kObjTypeCount];
-
-    GrGLvoid genObjs(ObjTypes type, GrGLsizei n, GrGLuint* ids) {
-        for (int i = 0; i < n; ++i) {
-            GrAlwaysAssert(ids[i] == 0);
-            GrFakeRefObj *obj = this->createObj(type);
-            GrAlwaysAssert(obj);
-            ids[i] = obj->getID();
-        }
-    }
-
-    GrFakeRefObj* createObj(ObjTypes type) {
-        GrFakeRefObj *temp = (*gFactoryFunc[type])();
-
-        fObjects.push_back(temp);
-
-        return temp;
-    }
-
-    GrFakeRefObj* findObject(GrGLuint ID, ObjTypes type) {
-        for (int i = 0; i < fObjects.count(); ++i) {
-            if (fObjects[i]->getID() == ID) { // && fObjects[i]->getType() == type) {
-                // The application shouldn't be accessing objects
-                // that (as far as OpenGL knows) were already deleted
-                GrAlwaysAssert(!fObjects[i]->getDeleted());
-                GrAlwaysAssert(!fObjects[i]->getMarkedForDeletion());
-                return fObjects[i];
-            }
-        }
-        return nullptr;
-    }
-
-    GrTextureUnitObj* getTextureUnit(int unit) {
-        GrAlwaysAssert(0 <= unit && kDefaultMaxTextureUnits > unit);
-
-        return fTextureUnits[unit];
-    }
-
-    GrGLvoid setBuffer(int buffIdx, GrBufferObj* buffer) {
-        if (fBoundBuffers[buffIdx]) {
-            // automatically break the binding of the old buffer
-            GrAlwaysAssert(fBoundBuffers[buffIdx]->getBound());
-            fBoundBuffers[buffIdx]->resetBound();
-
-            GrAlwaysAssert(!fBoundBuffers[buffIdx]->getDeleted());
-            fBoundBuffers[buffIdx]->unref();
-        }
-
-        if (buffer) {
-            GrAlwaysAssert(!buffer->getDeleted());
-            buffer->ref();
-
-            GrAlwaysAssert(!buffer->getBound());
-            buffer->setBound();
-        }
-
-        fBoundBuffers[buffIdx] = buffer;
-    }
-
-    void setVertexArray(GrVertexArrayObj* vertexArray) {
-        if (vertexArray) {
-            SkASSERT(!vertexArray->getDeleted());
-        }
-        SkRefCnt_SafeAssign(fVertexArray, vertexArray);
-    }
-
-    GrVertexArrayObj* getVertexArray() { return fVertexArray; }
-
-    void setTexture(GrTextureObj *texture) {
-        fTextureUnits[fCurrTextureUnit]->setTexture(texture);
-    }
-
-    void setFrameBuffer(GrFrameBufferObj *frameBuffer) {
-        if (fFrameBuffer) {
-            GrAlwaysAssert(fFrameBuffer->getBound());
-            fFrameBuffer->resetBound();
-
-            GrAlwaysAssert(!fFrameBuffer->getDeleted());
-            fFrameBuffer->unref();
-        }
-
-        fFrameBuffer = frameBuffer;
-
-        if (fFrameBuffer) {
-            GrAlwaysAssert(!fFrameBuffer->getDeleted());
-            fFrameBuffer->ref();
-
-            GrAlwaysAssert(!fFrameBuffer->getBound());
-            fFrameBuffer->setBound();
-        }
-    }
-
-    GrFrameBufferObj *getFrameBuffer() { return fFrameBuffer; }
-
-    void setRenderBuffer(GrRenderBufferObj *renderBuffer) {
-        if (fRenderBuffer) {
-            GrAlwaysAssert(fRenderBuffer->getBound());
-            fRenderBuffer->resetBound();
-
-            GrAlwaysAssert(!fRenderBuffer->getDeleted());
-            fRenderBuffer->unref();
-        }
-
-        fRenderBuffer = renderBuffer;
-
-        if (fRenderBuffer) {
-            GrAlwaysAssert(!fRenderBuffer->getDeleted());
-            fRenderBuffer->ref();
-
-            GrAlwaysAssert(!fRenderBuffer->getBound());
-            fRenderBuffer->setBound();
-        }
-    }
-    GrRenderBufferObj *getRenderBuffer() { return fRenderBuffer; }
-
-    void useProgram(GrProgramObj *program) {
-        if (fProgram) {
-            GrAlwaysAssert(fProgram->getInUse());
-            fProgram->resetInUse();
-
-            GrAlwaysAssert(!fProgram->getDeleted());
-            fProgram->unref();
-        }
-
-        fProgram = program;
-
-        if (fProgram) {
-            GrAlwaysAssert(!fProgram->getDeleted());
-            fProgram->ref();
-
-            GrAlwaysAssert(!fProgram->getInUse());
-            fProgram->setInUse();
-        }
-    }
-
-    void report() const {
-        for (int i = 0; i < fObjects.count(); ++i) {
-            if (!fAbandoned) {
-                GrAlwaysAssert(0 == fObjects[i]->getRefCount());
-                GrAlwaysAssert(fObjects[i]->getDeleted());
-            }
-        }
-    }
-
-    typedef GrGLTestInterface INHERITED;
-};
-
-#undef CREATE
-#undef FIND
-
-DebugInterface::Create DebugInterface::gFactoryFunc[kObjTypeCount] = {
-    GrTextureObj::createGrTextureObj,
-    GrBufferObj::createGrBufferObj,
-    GrRenderBufferObj::createGrRenderBufferObj,
-    GrFrameBufferObj::createGrFrameBufferObj,
-    GrShaderObj::createGrShaderObj,
-    GrProgramObj::createGrProgramObj,
-    GrTextureUnitObj::createGrTextureUnitObj,
-    GrVertexArrayObj::createGrVertexArrayObj,
-};
-
-const char* DebugInterface::kExtensions[] = {
-    "GL_ARB_framebuffer_object",
-    "GL_ARB_blend_func_extended",
-    "GL_ARB_timer_query",
-    "GL_ARB_draw_buffers",
-    "GL_ARB_occlusion_query",
-    "GL_EXT_stencil_wrap",
-    nullptr, // signifies the end of the array.
-};
-
-class DebugGLContext : public sk_gpu_test::GLTestContext {
-public:
-   DebugGLContext() {
-       this->init(new DebugInterface());
-   }
-
-   ~DebugGLContext() override { this->teardown(); }
-
-private:
-    void onPlatformMakeCurrent() const override {}
-    void onPlatformSwapBuffers() const override {}
-    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; }
-};
-}  // anonymous namespace
-
-namespace sk_gpu_test {
-GLTestContext* CreateDebugGLTestContext(GLTestContext* shareContext) {
-    if (shareContext) {
-        return nullptr;
-    }
-    GLTestContext* ctx = new DebugGLContext();
-    if (ctx->isValid()) {
-        return ctx;
-    }
-    delete ctx;
-    return nullptr;
-}
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.h b/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.h
deleted file mode 100644
index 9b9abe5..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/DebugGLTestContext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef DebugGLContext_DEFINED
-#define DebugGLContext_DEFINED
-
-#include "gl/GLTestContext.h"
-
-namespace sk_gpu_test {
-GLTestContext* CreateDebugGLTestContext(GLTestContext* shareContext = nullptr);
-}  // namespace sk_gpu_test
-
-#endif
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.cpp
deleted file mode 100644
index 37d4438..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBufferObj.h"
-
-void GrBufferObj::allocate(GrGLsizeiptr size, const GrGLchar *dataPtr) {
-    GrAlwaysAssert(size >= 0);
-
-    // delete pre-existing data
-    delete[] fDataPtr;
-
-    fSize = size;
-    fDataPtr = new GrGLchar[size];
-    if (dataPtr) {
-        memcpy(fDataPtr, dataPtr, fSize);
-    }
-    // TODO: w/ no dataPtr the data is unitialized - this could be tracked
-}
-
-void GrBufferObj::deleteAction() {
-
-    // buffers are automatically unmapped when deleted
-    this->resetMapped();
-
-    this->INHERITED::deleteAction();
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.h
deleted file mode 100644
index d0217b2..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrBufferObj.h
+++ /dev/null
@@ -1,76 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrBufferObj_DEFINED
-#define GrBufferObj_DEFINED
-
-#include "GrFakeRefObj.h"
-#include "gl/GrGLDefines.h"
-
-////////////////////////////////////////////////////////////////////////////////
-class GrBufferObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrBufferObj)
-
-public:
-    GrBufferObj()
-        : GrFakeRefObj()
-        , fDataPtr(nullptr)
-        , fMapped(false)
-        , fBound(false)
-        , fSize(0)
-        , fUsage(GR_GL_STATIC_DRAW) {
-    }
-    ~GrBufferObj() override {
-        delete[] fDataPtr;
-    }
-
-    void access() {
-        // cannot access the buffer if it is currently mapped
-        GrAlwaysAssert(!fMapped);
-    }
-
-    void setMapped(GrGLintptr offset, GrGLsizeiptr length) {
-        fMapped = true;
-        fMappedOffset = offset;
-        fMappedLength = length;
-    }
-    void resetMapped()           { fMapped = false; }
-    bool getMapped() const       { return fMapped; }
-    GrGLintptr getMappedOffset() const { return fMappedOffset; }
-    GrGLsizeiptr getMappedLength() const { return fMappedLength; }
-
-    void setBound()              { fBound = true; }
-    void resetBound()            { fBound = false; }
-    bool getBound() const        { return fBound; }
-
-    void allocate(GrGLsizeiptr size, const GrGLchar *dataPtr);
-    GrGLsizeiptr getSize() const { return fSize; }
-    GrGLchar *getDataPtr()       { return fDataPtr; }
-
-    void setUsage(GrGLint usage) { fUsage = usage; }
-    GrGLint getUsage() const     { return fUsage; }
-
-    void deleteAction() override;
-
-protected:
-private:
-
-    GrGLchar*    fDataPtr;
-    bool         fMapped;       // is the buffer object mapped via "glMapBuffer[Range]"?
-    GrGLintptr   fMappedOffset; // the offset of the buffer range that is mapped
-    GrGLsizeiptr fMappedLength; // the size of the buffer range that is mapped
-    bool         fBound;        // is the buffer object bound via "glBindBuffer"?
-    GrGLsizeiptr fSize;         // size in bytes
-    GrGLint      fUsage;        // one of: GL_STREAM_DRAW,
-                                //         GL_STATIC_DRAW,
-                                //         GL_DYNAMIC_DRAW
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrBufferObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrFBBindableObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrFBBindableObj.h
deleted file mode 100644
index f5b46ab..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrFBBindableObj.h
+++ /dev/null
@@ -1,92 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrFBBindableObj_DEFINED
-#define GrFBBindableObj_DEFINED
-
-#include "SkTDArray.h"
-#include "GrFakeRefObj.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// A common base class for render buffers and textures
-class GrFBBindableObj : public GrFakeRefObj {
-
-public:
-    GrFBBindableObj()
-        : GrFakeRefObj()
-        , fNumSamples(1) {
-    }
-
-    virtual ~GrFBBindableObj() {
-        GrAlwaysAssert(0 == fColorReferees.count());
-        GrAlwaysAssert(0 == fDepthReferees.count());
-        GrAlwaysAssert(0 == fStencilReferees.count());
-    }
-
-    void setColorBound(GrFakeRefObj *referee) {
-        fColorReferees.append(1, &referee);
-    }
-    void resetColorBound(GrFakeRefObj *referee) {
-        int index = fColorReferees.find(referee);
-        GrAlwaysAssert(0 <= index);
-        fColorReferees.removeShuffle(index);
-    }
-    bool getColorBound(GrFakeRefObj *referee) const {
-        int index = fColorReferees.find(referee);
-        return 0 <= index;
-    }
-    bool getColorBound() const {
-        return 0 != fColorReferees.count();
-    }
-
-    void setDepthBound(GrFakeRefObj *referee) {
-        fDepthReferees.append(1, &referee);
-    }
-    void resetDepthBound(GrFakeRefObj *referee) {
-        int index = fDepthReferees.find(referee);
-        GrAlwaysAssert(0 <= index);
-        fDepthReferees.removeShuffle(index);
-    }
-    bool getDepthBound(GrFakeRefObj *referee) const {
-        int index = fDepthReferees.find(referee);
-        return 0 <= index;
-    }
-    bool getDepthBound() const {
-        return 0 != fDepthReferees.count();
-    }
-
-    void setStencilBound(GrFakeRefObj *referee) {
-        fStencilReferees.append(1, &referee);
-    }
-    void resetStencilBound(GrFakeRefObj *referee) {
-        int index = fStencilReferees.find(referee);
-        GrAlwaysAssert(0 <= index);
-        fStencilReferees.removeShuffle(index);
-    }
-    bool getStencilBound(GrFakeRefObj *referee) const {
-        int index = fStencilReferees.find(referee);
-        return 0 <= index;
-    }
-    bool getStencilBound() const {
-        return 0 != fStencilReferees.count();
-    }
-
-    int numSamples() { return fNumSamples; }
-
-protected:
-    int fNumSamples;
-
-private:
-    SkTDArray<GrFakeRefObj *> fColorReferees;   // frame buffers that use this as a color buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
-    SkTDArray<GrFakeRefObj *> fDepthReferees;   // frame buffers that use this as a depth buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
-    SkTDArray<GrFakeRefObj *> fStencilReferees; // frame buffers that use this as a stencil buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrFBBindableObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrFakeRefObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrFakeRefObj.h
deleted file mode 100644
index e59aeb3..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrFakeRefObj.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrFakeRefObj_DEFINED
-#define GrFakeRefObj_DEFINED
-
-#include "SkTypes.h"
-#include "gl/GrGLInterface.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// This object is used to track the OpenGL objects. We don't use real
-// reference counting (i.e., we don't free the objects when their ref count
-// goes to 0) so that we can detect invalid memory accesses. The refs we
-// are tracking in this class are actually OpenGL's references to the objects
-// not "ours"
-// Each object also gets a unique globally identifying ID
-class GrFakeRefObj : SkNoncopyable {
-public:
-    GrFakeRefObj()
-        : fRef(0)
-        , fMarkedForDeletion(false)
-        , fDeleted(false) {
-
-        // source for globally unique IDs - 0 is reserved!
-        static int fNextID = 0;
-
-        fID = ++fNextID;
-    }
-    virtual ~GrFakeRefObj() {}
-
-    void ref() {
-        fRef++;
-    }
-    void unref() {
-        fRef--;
-        GrAlwaysAssert(fRef >= 0);
-
-        // often in OpenGL a given object may still be in use when the
-        // delete call is made. In these cases the object is marked
-        // for deletion and then freed when it is no longer in use
-        if (0 == fRef && fMarkedForDeletion) {
-            this->deleteAction();
-        }
-    }
-    int getRefCount() const             { return fRef; }
-
-    GrGLuint getID() const              { return fID; }
-
-    void setMarkedForDeletion()         { fMarkedForDeletion = true; }
-    bool getMarkedForDeletion() const   { return fMarkedForDeletion; }
-
-    bool getDeleted() const             { return fDeleted; }
-
-    // The deleteAction fires if the object has been marked for deletion but
-    // couldn't be deleted earlier due to refs
-    virtual void deleteAction() {
-        this->setDeleted();
-    }
-
-protected:
-private:
-    int         fRef;               // ref count
-    GrGLuint    fID;                // globally unique ID
-    bool        fMarkedForDeletion;
-    // The deleted flag is only set when OpenGL thinks the object is deleted
-    // It is obviously still allocated w/in this framework
-    bool        fDeleted;
-
-    // setDeleted should only ever appear in the deleteAction method!
-    void setDeleted()                   { fDeleted = true; }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Each class derived from GrFakeRefObj should use this macro to add a
-// factory creation entry point. This entry point is used by the GrGLDebug
-// object to instantiate the various objects
-// all globally unique IDs
-#define GR_DEFINE_CREATOR(className) \
-public:                              \
-    static GrFakeRefObj *create##className() { return new className; }
-
-#endif // GrFakeRefObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.cpp
deleted file mode 100644
index 7dc12ac..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrFrameBufferObj.h"
-#include "GrFBBindableObj.h"
-
-void GrFrameBufferObj::setColor(GrFBBindableObj *buffer) {
-    if (fColorBuffer) {
-        // automatically break the binding of the old buffer
-        GrAlwaysAssert(fColorBuffer->getColorBound(this));
-        fColorBuffer->resetColorBound(this);
-
-        GrAlwaysAssert(!fColorBuffer->getDeleted());
-        fColorBuffer->unref();
-    }
-    fColorBuffer = buffer;
-    if (fColorBuffer) {
-        GrAlwaysAssert(!fColorBuffer->getDeleted());
-        fColorBuffer->ref();
-
-        GrAlwaysAssert(!fColorBuffer->getColorBound(this));
-        fColorBuffer->setColorBound(this);
-    }
-}
-
-void GrFrameBufferObj::setDepth(GrFBBindableObj *buffer) {
-    if (fDepthBuffer) {
-        // automatically break the binding of the old buffer
-        GrAlwaysAssert(fDepthBuffer->getDepthBound(this));
-        fDepthBuffer->resetDepthBound(this);
-
-        GrAlwaysAssert(!fDepthBuffer->getDeleted());
-        fDepthBuffer->unref();
-    }
-    fDepthBuffer = buffer;
-    if (fDepthBuffer) {
-        GrAlwaysAssert(!fDepthBuffer->getDeleted());
-        fDepthBuffer->ref();
-
-        GrAlwaysAssert(!fDepthBuffer->getDepthBound(this));
-        fDepthBuffer->setDepthBound(this);
-    }
-}
-
-void GrFrameBufferObj::setStencil(GrFBBindableObj *buffer) {
-    if (fStencilBuffer) {
-        // automatically break the binding of the old buffer
-        GrAlwaysAssert(fStencilBuffer->getStencilBound(this));
-        fStencilBuffer->resetStencilBound(this);
-
-        //GrAlwaysAssert(!fStencilBuffer->getDeleted());
-        fStencilBuffer->unref();
-    }
-    fStencilBuffer = buffer;
-    if (fStencilBuffer) {
-        GrAlwaysAssert(!fStencilBuffer->getDeleted());
-        fStencilBuffer->ref();
-
-        GrAlwaysAssert(!fStencilBuffer->getStencilBound(this));
-        fStencilBuffer->setStencilBound(this);
-    }
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.h
deleted file mode 100644
index 9003127..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrFrameBufferObj.h
+++ /dev/null
@@ -1,68 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrFrameBufferObj_DEFINED
-#define GrFrameBufferObj_DEFINED
-
-#include "GrFakeRefObj.h"
-class GrFBBindableObj;
-
-////////////////////////////////////////////////////////////////////////////////
-// TODO: when a framebuffer obj is bound the GL_SAMPLES query must return 0
-// TODO: GL_STENCIL_BITS must also be redirected to the framebuffer
-class GrFrameBufferObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrFrameBufferObj)
-
-public:
-    GrFrameBufferObj()
-        : GrFakeRefObj()
-        , fBound(false)
-        , fColorBuffer(nullptr)
-        , fDepthBuffer(nullptr)
-        , fStencilBuffer(nullptr) {
-    }
-
-    ~GrFrameBufferObj() override {
-        fColorBuffer = nullptr;
-        fDepthBuffer = nullptr;
-        fStencilBuffer = nullptr;
-    }
-
-    void setBound()         { fBound = true; }
-    void resetBound()       { fBound = false; }
-    bool getBound() const   { return fBound; }
-
-    void setColor(GrFBBindableObj *buffer);
-    GrFBBindableObj *getColor()       { return fColorBuffer; }
-
-    void setDepth(GrFBBindableObj *buffer);
-    GrFBBindableObj *getDepth()       { return fDepthBuffer; }
-
-    void setStencil(GrFBBindableObj *buffer);
-    GrFBBindableObj *getStencil()     { return fStencilBuffer; }
-
-    void deleteAction() override {
-
-        setColor(nullptr);
-        setDepth(nullptr);
-        setStencil(nullptr);
-
-        this->INHERITED::deleteAction();
-    }
-
-protected:
-private:
-    bool fBound;        // is this frame buffer currently bound via "glBindFramebuffer"?
-    GrFBBindableObj * fColorBuffer;
-    GrFBBindableObj * fDepthBuffer;
-    GrFBBindableObj * fStencilBuffer;
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrFrameBufferObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.cpp
deleted file mode 100644
index d6cc36b..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrProgramObj.h"
-#include "GrShaderObj.h"
-
-void GrProgramObj::AttachShader(GrShaderObj *shader) {
-    shader->ref();
-    fShaders.push_back(shader);
-}
-
-void GrProgramObj::deleteAction() {
-
-    // shaders are automatically detached from a deleted program. They will only be
-    // deleted if they were marked for deletion by a prior call to glDeleteShader
-    for (int i = 0; i < fShaders.count(); ++i) {
-        fShaders[i]->unref();
-    }
-    fShaders.reset();
-
-    this->INHERITED::deleteAction();
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.h
deleted file mode 100644
index f4ff9d1..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrProgramObj.h
+++ /dev/null
@@ -1,43 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrProgramObj_DEFINED
-#define GrProgramObj_DEFINED
-
-#include "SkTArray.h"
-#include "GrFakeRefObj.h"
-class GrShaderObj;
-
-////////////////////////////////////////////////////////////////////////////////
-class GrProgramObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrProgramObj)
-
-public:
-    GrProgramObj()
-        : GrFakeRefObj()
-        , fInUse(false) {}
-
-    void AttachShader(GrShaderObj *shader);
-
-    void deleteAction() override;
-
-    // TODO: this flag system won't work w/ multiple contexts!
-    void setInUse()         { fInUse = true; }
-    void resetInUse()       { fInUse = false; }
-    bool getInUse() const   { return fInUse; }
-
-protected:
-
-private:
-    SkTArray<GrShaderObj *> fShaders;
-    bool fInUse;            // has this program been activated by a glUseProgram call?
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrProgramObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrRenderBufferObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrRenderBufferObj.h
deleted file mode 100644
index 1802eb5..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrRenderBufferObj.h
+++ /dev/null
@@ -1,45 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrRenderBufferObj_DEFINED
-#define GrRenderBufferObj_DEFINED
-
-#include "GrFBBindableObj.h"
-
-////////////////////////////////////////////////////////////////////////////////
-class GrRenderBufferObj : public GrFBBindableObj {
-    GR_DEFINE_CREATOR(GrRenderBufferObj)
-
-public:
-    GrRenderBufferObj()
-        : GrFBBindableObj()
-        , fBound(false) {
-    }
-
-    void setBound()         { fBound = true; }
-    void resetBound()       { fBound = false; }
-    bool getBound() const   { return fBound; }
-
-    void deleteAction() override {
-
-        this->INHERITED::deleteAction();
-    }
-
-    void setNumSamples(int numSamples) {
-        GrAlwaysAssert(numSamples > 0);
-        fNumSamples = numSamples;
-    }
-
-protected:
-private:
-    bool fBound;           // is this render buffer currently bound via "glBindRenderbuffer"?
-
-    typedef GrFBBindableObj INHERITED;
-};
-
-#endif // GrRenderBufferObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.cpp
deleted file mode 100644
index 8d3caa1..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrShaderObj.h"
-
-void GrShaderObj::deleteAction() {
-
-    this->INHERITED::deleteAction();
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.h
deleted file mode 100644
index 8ecb990..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrShaderObj.h
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrShaderObj_DEFINED
-#define GrShaderObj_DEFINED
-
-#include "GrFakeRefObj.h"
-#include "gl/GrGLDefines.h"
-
-////////////////////////////////////////////////////////////////////////////////
-class GrShaderObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrShaderObj)
-
-public:
-    GrShaderObj()
-        : GrFakeRefObj()
-        , fType(GR_GL_VERTEX_SHADER)    {}
-
-    void setType(GrGLenum type)         { fType = type; }
-    GrGLenum getType()                  { return fType; }
-
-    void deleteAction() override;
-
-protected:
-private:
-    GrGLenum fType;  // either GR_GL_VERTEX_SHADER or GR_GL_FRAGMENT_SHADER
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrShaderObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.cpp
deleted file mode 100644
index 86063fb..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrTextureObj.h"
-
-void GrTextureObj::deleteAction() {
-
-    this->INHERITED::deleteAction();
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.h
deleted file mode 100644
index 5532723..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrTextureObj.h
+++ /dev/null
@@ -1,57 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrTextureObj_DEFINED
-#define GrTextureObj_DEFINED
-
-#include "GrFBBindableObj.h"
-
-class GrTextureUnitObj;
-
-////////////////////////////////////////////////////////////////////////////////
-class GrTextureObj : public GrFBBindableObj {
-    GR_DEFINE_CREATOR(GrTextureObj)
-
-public:
-    GrTextureObj()
-        : GrFBBindableObj() {
-    }
-
-    ~GrTextureObj() override {
-        GrAlwaysAssert(0 == fTextureUnitReferees.count());
-    }
-
-    void setBound(GrTextureUnitObj *referee) {
-        fTextureUnitReferees.append(1, &referee);
-    }
-
-    void resetBound(GrTextureUnitObj *referee) {
-        int index = fTextureUnitReferees.find(referee);
-        GrAlwaysAssert(0 <= index);
-        fTextureUnitReferees.removeShuffle(index);
-    }
-    bool getBound(GrTextureUnitObj *referee) const {
-        int index = fTextureUnitReferees.find(referee);
-        return 0 <= index;
-    }
-    bool getBound() const {
-        return 0 != fTextureUnitReferees.count();
-    }
-
-    void deleteAction() override;
-
-protected:
-
-private:
-    // texture units that bind this texture (via "glBindTexture")
-    SkTDArray<GrTextureUnitObj *> fTextureUnitReferees;
-
-    typedef GrFBBindableObj INHERITED;
-};
-
-#endif // GrTextureObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.cpp b/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.cpp
deleted file mode 100644
index 316dcec..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrTextureUnitObj.h"
-#include "GrTextureObj.h"
-
-void GrTextureUnitObj::setTexture(GrTextureObj *texture)  {
-
-    if (fTexture) {
-        GrAlwaysAssert(fTexture->getBound(this));
-        fTexture->resetBound(this);
-
-        GrAlwaysAssert(!fTexture->getDeleted());
-        fTexture->unref();
-    }
-
-    fTexture = texture;
-
-    if (fTexture) {
-        GrAlwaysAssert(!fTexture->getDeleted());
-        fTexture->ref();
-
-        GrAlwaysAssert(!fTexture->getBound(this));
-        fTexture->setBound(this);
-    }
-}
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.h
deleted file mode 100644
index b06d117..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrTextureUnitObj.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrTextureUnitObj_DEFINED
-#define GrTextureUnitObj_DEFINED
-
-#include "GrFakeRefObj.h"
-class GrTextureObj;
-
-////////////////////////////////////////////////////////////////////////////////
-// Although texture unit objects are allocated & deallocated like the other
-// GL emulation objects they are derived from GrFakeRefObj to provide some
-// uniformity in how the debug interface class manages resources
-class GrTextureUnitObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrTextureUnitObj)
-
-public:
-    GrTextureUnitObj()
-        : GrFakeRefObj()
-        , fNumber(0)
-        , fTexture(nullptr) {
-    }
-
-    void setNumber(GrGLenum number) {
-        fNumber = number;
-    }
-    GrGLenum getNumber() const { return fNumber; }
-
-    void setTexture(GrTextureObj *texture);
-    GrTextureObj *getTexture()                  { return fTexture; }
-
-protected:
-private:
-    GrGLenum fNumber;
-    GrTextureObj *fTexture;
-
-    typedef GrFakeRefObj INHERITED;
-};
-
-#endif // GrTextureUnitObj_DEFINED
diff --git a/src/third_party/skia/tools/gpu/gl/debug/GrVertexArrayObj.h b/src/third_party/skia/tools/gpu/gl/debug/GrVertexArrayObj.h
deleted file mode 100644
index 3aeb0b2..0000000
--- a/src/third_party/skia/tools/gpu/gl/debug/GrVertexArrayObj.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrVertexArrayObj_DEFINED
-#define GrVertexArrayObj_DEFINED
-
-#include "GrFakeRefObj.h"
-
-class GrVertexArrayObj : public GrFakeRefObj {
-    GR_DEFINE_CREATOR(GrVertexArrayObj)
-
-public:
-    GrVertexArrayObj() : GrFakeRefObj() {}
-
-    typedef GrFakeRefObj INHERITED;
-};
-#endif
diff --git a/src/third_party/skia/tools/gpu/gl/egl/CreatePlatformGLTestContext_egl.cpp b/src/third_party/skia/tools/gpu/gl/egl/CreatePlatformGLTestContext_egl.cpp
index c006098..96900fd 100644
--- a/src/third_party/skia/tools/gpu/gl/egl/CreatePlatformGLTestContext_egl.cpp
+++ b/src/third_party/skia/tools/gpu/gl/egl/CreatePlatformGLTestContext_egl.cpp
@@ -5,16 +5,17 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 #define GL_GLEXT_PROTOTYPES
+
 #include <GLES2/gl2.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include "gl/GrGLDefines.h"
-#include "gl/GrGLUtil.h"
+#include "src/gpu/gl/GrGLDefines.h"
+#include "src/gpu/gl/GrGLUtil.h"
 
 namespace {
 
@@ -39,6 +40,16 @@
     typedef sk_gpu_test::FenceSync INHERITED;
 };
 
+std::function<void()> context_restorer() {
+    auto display = eglGetCurrentDisplay();
+    auto dsurface = eglGetCurrentSurface(EGL_DRAW);
+    auto rsurface = eglGetCurrentSurface(EGL_READ);
+    auto context = eglGetCurrentContext();
+    return [display, dsurface, rsurface, context] {
+        eglMakeCurrent(display, dsurface, rsurface, context);
+    };
+}
+
 class EGLGLTestContext : public sk_gpu_test::GLTestContext {
 public:
     EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext);
@@ -53,14 +64,38 @@
     void destroyGLContext();
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
 
+    PFNEGLCREATEIMAGEKHRPROC fEglCreateImageProc = nullptr;
+    PFNEGLDESTROYIMAGEKHRPROC fEglDestroyImageProc = nullptr;
+
     EGLContext fContext;
     EGLDisplay fDisplay;
     EGLSurface fSurface;
 };
 
+static EGLContext create_gles_egl_context(EGLDisplay display,
+                                          EGLConfig surfaceConfig,
+                                          EGLContext eglShareContext,
+                                          EGLint eglContextClientVersion) {
+    const EGLint contextAttribsForOpenGLES[] = {
+        EGL_CONTEXT_CLIENT_VERSION,
+        eglContextClientVersion,
+        EGL_NONE
+    };
+    return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGLES);
+}
+static EGLContext create_gl_egl_context(EGLDisplay display,
+                                        EGLConfig surfaceConfig,
+                                        EGLContext eglShareContext) {
+    const EGLint contextAttribsForOpenGL[] = {
+        EGL_NONE
+    };
+    return eglCreateContext(display, surfaceConfig, eglShareContext, contextAttribsForOpenGL);
+}
+
 EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext* shareContext)
     : fContext(EGL_NO_CONTEXT)
     , fDisplay(EGL_NO_DISPLAY)
@@ -68,43 +103,19 @@
 
     EGLContext eglShareContext = shareContext ? shareContext->fContext : nullptr;
 
-    static const EGLint kEGLContextAttribsForOpenGL[] = {
-        EGL_NONE
+    static const GrGLStandard kStandards[] = {
+        kGL_GrGLStandard,
+        kGLES_GrGLStandard,
     };
 
-    static const EGLint kEGLContextAttribsForOpenGLES[] = {
-        EGL_CONTEXT_CLIENT_VERSION, 2,
-        EGL_NONE
-    };
-
-    static const struct {
-        const EGLint* fContextAttribs;
-        EGLenum fAPI;
-        EGLint  fRenderableTypeBit;
-        GrGLStandard fStandard;
-    } kAPIs[] = {
-        {   // OpenGL
-            kEGLContextAttribsForOpenGL,
-            EGL_OPENGL_API,
-            EGL_OPENGL_BIT,
-            kGL_GrGLStandard
-        },
-        {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
-            kEGLContextAttribsForOpenGLES,
-            EGL_OPENGL_ES_API,
-            EGL_OPENGL_ES2_BIT,
-            kGLES_GrGLStandard
-        },
-    };
-
-    size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
+    size_t apiLimit = SK_ARRAY_COUNT(kStandards);
     size_t api = 0;
     if (forcedGpuAPI == kGL_GrGLStandard) {
         apiLimit = 1;
     } else if (forcedGpuAPI == kGLES_GrGLStandard) {
         api = 1;
     }
-    SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
+    SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kStandards[api] == forcedGpuAPI);
 
     sk_sp<const GrGLInterface> gl;
 
@@ -121,15 +132,16 @@
         SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
         SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
 #endif
+        bool gles = kGLES_GrGLStandard == kStandards[api];
 
-        if (!eglBindAPI(kAPIs[api].fAPI)) {
+        if (!eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
             continue;
         }
 
         EGLint numConfigs = 0;
         const EGLint configAttribs[] = {
             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-            EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
+            EGL_RENDERABLE_TYPE, gles ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT,
             EGL_RED_SIZE, 8,
             EGL_GREEN_SIZE, 8,
             EGL_BLUE_SIZE, 8,
@@ -148,8 +160,20 @@
             continue;
         }
 
-        fContext = eglCreateContext(fDisplay, surfaceConfig, eglShareContext,
-                                    kAPIs[api].fContextAttribs);
+        if (gles) {
+#ifdef GR_EGL_TRY_GLES3_THEN_GLES2
+            // Some older devices (Nexus7/Tegra3) crash when you try this.  So it is (for now)
+            // hidden behind this flag.
+            fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 3);
+            if (EGL_NO_CONTEXT == fContext) {
+                fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
+            }
+#else
+            fContext = create_gles_egl_context(fDisplay, surfaceConfig, eglShareContext, 2);
+#endif
+        } else {
+            fContext = create_gl_egl_context(fDisplay, surfaceConfig, eglShareContext);
+        }
         if (EGL_NO_CONTEXT == fContext) {
             SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
             continue;
@@ -168,14 +192,15 @@
             continue;
         }
 
+        SkScopeExit restorer(context_restorer());
         if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
             SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
             this->destroyGLContext();
             continue;
         }
 
-        gl.reset(GrGLCreateNativeInterface());
-        if (nullptr == gl.get()) {
+        gl = GrGLMakeNativeInterface();
+        if (!gl) {
             SkDebugf("Failed to create gl interface.\n");
             this->destroyGLContext();
             continue;
@@ -186,8 +211,14 @@
             this->destroyGLContext();
             continue;
         }
+        const char* extensions = eglQueryString(fDisplay, EGL_EXTENSIONS);
+        if (strstr(extensions, "EGL_KHR_image")) {
+            fEglCreateImageProc = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
+            fEglDestroyImageProc =
+                    (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
+        }
 
-        this->init(gl.release(), EGLFenceSync::MakeIfSupported(fDisplay));
+        this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
         break;
     }
 }
@@ -199,9 +230,11 @@
 
 void EGLGLTestContext::destroyGLContext() {
     if (fDisplay) {
-        eglMakeCurrent(fDisplay, 0, 0, 0);
-
         if (fContext) {
+            if (eglGetCurrentContext() == fContext) {
+                // This will ensure that the context is immediately deleted.
+                eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            }
             eglDestroyContext(fDisplay, fContext);
             fContext = EGL_NO_CONTEXT;
         }
@@ -217,19 +250,16 @@
 }
 
 GrEGLImage EGLGLTestContext::texture2DToEGLImage(GrGLuint texID) const {
-    if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
+    if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image") || !fEglCreateImageProc) {
         return GR_EGL_NO_IMAGE;
     }
-    GrEGLImage img;
-    GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
+    EGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
     GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
-    GR_GL_CALL_RET(this->gl(), img,
-                   EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
-    return img;
+    return fEglCreateImageProc(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs);
 }
 
 void EGLGLTestContext::destroyEGLImage(GrEGLImage image) const {
-    GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
+    fEglDestroyImageProc(fDisplay, image);
 }
 
 GrGLuint EGLGLTestContext::eglImageToExternalTexture(GrEGLImage image) const {
@@ -237,7 +267,6 @@
     if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
         return 0;
     }
-#ifndef EGL_NO_IMAGE_EXTERNAL
     typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
 
     EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
@@ -246,24 +275,21 @@
         return 0;
     }
     GrGLuint texID;
-    glGenTextures(1, &texID);
+    GR_GL_CALL(this->gl(), GenTextures(1, &texID));
     if (!texID) {
         return 0;
     }
-    glBindTexture(GR_GL_TEXTURE_EXTERNAL, texID);
-    if (glGetError() != GR_GL_NO_ERROR) {
-        glDeleteTextures(1, &texID);
+    GR_GL_CALL_NOERRCHECK(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
+    if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
+        GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
         return 0;
     }
     glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
-    if (glGetError() != GR_GL_NO_ERROR) {
-        glDeleteTextures(1, &texID);
+    if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
+        GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
         return 0;
     }
     return texID;
-#else
-    return 0;
-#endif //EGL_NO_IMAGE_EXTERNAL
 }
 
 std::unique_ptr<sk_gpu_test::GLTestContext> EGLGLTestContext::makeNew() const {
@@ -281,6 +307,13 @@
     }
 }
 
+std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const {
+    if (eglGetCurrentContext() == fContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void EGLGLTestContext::onPlatformSwapBuffers() const {
     if (!eglSwapBuffers(fDisplay, fSurface)) {
         SkDebugf("Could not complete eglSwapBuffers.\n");
diff --git a/src/third_party/skia/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp b/src/third_party/skia/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
index 76b6d21..5e643e2 100644
--- a/src/third_party/skia/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
+++ b/src/third_party/skia/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx.cpp
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#include "gl/GLTestContext.h"
-#include "SkOnce.h"
+#include "include/private/SkOnce.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 #include <X11/Xlib.h>
 #include <GL/glx.h>
@@ -62,6 +62,7 @@
                                         GLXContext glxSharedContext);
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
 
@@ -90,11 +91,27 @@
     return ad->display();
 }
 
+std::function<void()> context_restorer() {
+    auto display = glXGetCurrentDisplay();
+    auto drawable = glXGetCurrentDrawable();
+    auto context = glXGetCurrentContext();
+    // On some systems calling glXMakeCurrent with a null display crashes.
+    if (!display) {
+        display = get_display();
+    }
+    return [display, drawable, context] { glXMakeCurrent(display, drawable, context); };
+}
+
 GLXGLTestContext::GLXGLTestContext(GrGLStandard forcedGpuAPI, GLXGLTestContext* shareContext)
     : fContext(nullptr)
     , fDisplay(nullptr)
     , fPixmap(0)
     , fGlxPixmap(0) {
+    // We cross our fingers that this is the first X call in the program and that if the application
+    // is actually threaded that this succeeds.
+    static SkOnce gOnce;
+    gOnce([] { XInitThreads(); });
+
     fDisplay = get_display();
 
     GLXContext glxShareContext = shareContext ? shareContext->fContext : nullptr;
@@ -214,6 +231,7 @@
         //SkDebugf("Direct GLX rendering context obtained.\n");
     }
 
+    SkScopeExit restorer(context_restorer());
     //SkDebugf("Making context current.\n");
     if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
       SkDebugf("Could not set the context.\n");
@@ -221,8 +239,8 @@
         return;
     }
 
-    sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
-    if (nullptr == gl.get()) {
+    auto gl = GrGLMakeNativeInterface();
+    if (!gl) {
         SkDebugf("Failed to create gl interface");
         this->destroyGLContext();
         return;
@@ -234,7 +252,7 @@
         return;
     }
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 
@@ -245,9 +263,11 @@
 
 void GLXGLTestContext::destroyGLContext() {
     if (fDisplay) {
-        glXMakeCurrent(fDisplay, 0, 0);
-
         if (fContext) {
+            if (glXGetCurrentContext() == fContext) {
+                // This will ensure that the context is immediately deleted.
+                glXMakeContextCurrent(fDisplay, None, None, nullptr);
+            }
             glXDestroyContext(fDisplay, fContext);
             fContext = nullptr;
         }
@@ -334,6 +354,13 @@
     }
 }
 
+std::function<void()> GLXGLTestContext::onPlatformGetAutoContextRestore() const {
+    if (glXGetCurrentContext() == fContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void GLXGLTestContext::onPlatformSwapBuffers() const {
     glXSwapBuffers(fDisplay, fGlxPixmap);
 }
diff --git a/src/third_party/skia/tools/gpu/gl/iOS/CreatePlatformGLTestContext_iOS.mm b/src/third_party/skia/tools/gpu/gl/iOS/CreatePlatformGLTestContext_iOS.mm
index 1fd50d1..0605fdf 100644
--- a/src/third_party/skia/tools/gpu/gl/iOS/CreatePlatformGLTestContext_iOS.mm
+++ b/src/third_party/skia/tools/gpu/gl/iOS/CreatePlatformGLTestContext_iOS.mm
@@ -6,7 +6,7 @@
  * found in the LICENSE file.
  */
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 #import <OpenGLES/EAGL.h>
 #include <dlfcn.h>
 
@@ -14,6 +14,11 @@
 
 namespace {
 
+std::function<void()> context_restorer() {
+    EAGLContext* context = [EAGLContext currentContext];
+    return [context] { [EAGLContext setCurrentContext:context]; };
+}
+
 class IOSGLTestContext : public sk_gpu_test::GLTestContext {
 public:
     IOSGLTestContext(IOSGLTestContext* shareContext);
@@ -23,6 +28,7 @@
     void destroyGLContext();
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
 
@@ -36,11 +42,19 @@
 
     if (shareContext) {
         EAGLContext* iosShareContext = shareContext->fEAGLContext;
-        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2
-                                            sharegroup: [iosShareContext sharegroup]];
+        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3
+                                            sharegroup:[iosShareContext sharegroup]];
+        if (fEAGLContext == nil) {
+            fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2
+                                                sharegroup:[iosShareContext sharegroup]];
+        }
     } else {
-        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+        fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
+        if (fEAGLContext == nil) {
+            fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+        }
     }
+    SkScopeExit restorer(context_restorer());
     [EAGLContext setCurrentContext:fEAGLContext];
 
     sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
@@ -59,7 +73,7 @@
         "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
         RTLD_LAZY);
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 IOSGLTestContext::~IOSGLTestContext() {
@@ -70,11 +84,12 @@
 void IOSGLTestContext::destroyGLContext() {
     if (fEAGLContext) {
         if ([EAGLContext currentContext] == fEAGLContext) {
+            // This will ensure that the context is immediately deleted.
             [EAGLContext setCurrentContext:nil];
         }
         fEAGLContext = nil;
     }
-    if (RTLD_DEFAULT != fGLLibrary) {
+    if (nullptr != fGLLibrary) {
         dlclose(fGLLibrary);
     }
 }
@@ -86,10 +101,18 @@
     }
 }
 
+std::function<void()> IOSGLTestContext::onPlatformGetAutoContextRestore() const {
+    if ([EAGLContext currentContext] == fEAGLContext) {
+		return nullptr;
+	}
+    return context_restorer();
+}
+
 void IOSGLTestContext::onPlatformSwapBuffers() const { }
 
 GrGLFuncPtr IOSGLTestContext::onPlatformGetProcAddress(const char* procName) const {
-    return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
+    void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
+    return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
 }
 
 }  // anonymous namespace
diff --git a/src/third_party/skia/tools/gpu/gl/interface/Makefile b/src/third_party/skia/tools/gpu/gl/interface/Makefile
new file mode 100644
index 0000000..b7f5ced
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/gl/interface/Makefile
@@ -0,0 +1,5 @@
+generate:
+	go run *.go --in_table "./interface.json5" --out_dir "../../../../src/gpu/gl"
+
+dryrun:
+	go run *.go --in_table "./interface.json5" --out_dir "../../../../src/gpu/gl" --dryrun
\ No newline at end of file
diff --git a/src/third_party/skia/tools/gpu/gl/interface/README.md b/src/third_party/skia/tools/gpu/gl/interface/README.md
new file mode 100644
index 0000000..f4e1788
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/gl/interface/README.md
@@ -0,0 +1,22 @@
+GrGlInterface Autogeneration
+============================
+
+Background
+----------
+
+At a high level, the first three steps of making a GrGLInterface (a generic way to
+interact with a GL-like GPU) are:
+
+  - Assemble: Copy a set of function pointers into the struct
+  - Validate: Make sure the function pointers advertised actually exist.
+  - Capabilities: Compute what fast/slow paths are enabled based on the functions
+        in the struct (GrGLCaps, for short)
+
+Autogeneration
+--------------
+
+The first two steps have been automated with a table-based generation script located
+in this folder. The table is in JSON5 format (like JSON, but with comments). O
+
+Once edited, the Assemble/Validate code can be re-generated by running
+`make generate` in this folder.
\ No newline at end of file
diff --git a/src/third_party/skia/tools/gpu/gl/interface/gen_interface.go b/src/third_party/skia/tools/gpu/gl/interface/gen_interface.go
new file mode 100644
index 0000000..6eb94a5
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/gl/interface/gen_interface.go
@@ -0,0 +1,460 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package main
+
+// gen_interface creates the assemble/validate cpp files given the
+// interface.json5 file.
+// See README for more details.
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"github.com/flynn/json5"
+)
+
+var (
+	outDir  = flag.String("out_dir", "../../src/gpu/gl", "Where to output the GrGlAssembleInterface_* and GrGlInterface.cpp files")
+	inTable = flag.String("in_table", "./interface.json5", "The JSON5 table to read in")
+	dryRun  = flag.Bool("dryrun", false, "Print the outputs, don't write to file")
+)
+
+const (
+	CORE_FEATURE        = "<core>"
+	SPACER              = "    "
+	GLES_FILE_NAME      = "GrGLAssembleGLESInterfaceAutogen.cpp"
+	GL_FILE_NAME        = "GrGLAssembleGLInterfaceAutogen.cpp"
+	WEBGL_FILE_NAME     = "GrGLAssembleWebGLInterfaceAutogen.cpp"
+	INTERFACE_FILE_NAME = "GrGLInterfaceAutogen.cpp"
+)
+
+// FeatureSet represents one set of requirements for each of the GL "standards" that
+// Skia supports.  This is currently OpenGL, OpenGL ES and WebGL.
+// OpenGL is typically abbreviated as just "GL".
+// https://www.khronos.org/registry/OpenGL/index_gl.php
+// https://www.khronos.org/opengles/
+// https://www.khronos.org/registry/webgl/specs/1.0/
+type FeatureSet struct {
+	GLReqs    []Requirement `json:"GL"`
+	GLESReqs  []Requirement `json:"GLES"`
+	WebGLReqs []Requirement `json:"WebGL"`
+
+	Functions         []string           `json:"functions"`
+	HardCodeFunctions []HardCodeFunction `json:"hardcode_functions"`
+	OptionalFunctions []string           `json:"optional"` // not checked in validate
+
+	// only assembled/validated when testing
+	TestOnlyFunctions []string `json:"test_functions"`
+
+	Required bool `json:"required"`
+}
+
+// Requirement lists how we know if a function exists. Extension is the
+// GL extension (or the string CORE_FEATURE if it's part of the core functionality).
+// MinVersion optionally indicates the minimum version of a standard
+// that has the function.
+// SuffixOverride allows the extension suffix to be manually specified instead
+// of automatically derived from the extension name.
+// (for example, if an NV extension specifies some EXT extensions)
+type Requirement struct {
+	Extension      string     `json:"ext"` // required
+	MinVersion     *GLVersion `json:"min_version"`
+	SuffixOverride *string    `json:"suffix"`
+}
+
+// HardCodeFunction indicates to not use the C++ macro and just directly
+// adds a given function ptr to the struct.
+type HardCodeFunction struct {
+	PtrName  string `json:"ptr_name"`
+	CastName string `json:"cast_name"`
+	GetName  string `json:"get_name"`
+}
+
+var CORE_REQUIREMENT = Requirement{Extension: CORE_FEATURE, MinVersion: nil}
+
+type GLVersion [2]int
+
+// RequirementGetter functions allows us to "iterate" over the requirements
+// of the different standards which are stored as keys in FeatureSet and
+// normally not easily iterable.
+type RequirementGetter func(FeatureSet) []Requirement
+
+func glRequirements(fs FeatureSet) []Requirement {
+	return fs.GLReqs
+}
+
+func glesRequirements(fs FeatureSet) []Requirement {
+	return fs.GLESReqs
+}
+
+func webglRequirements(fs FeatureSet) []Requirement {
+	return fs.WebGLReqs
+}
+
+// generateAssembleInterface creates one GrGLAssembleInterface_[type]_gen.cpp
+// for each of the standards
+func generateAssembleInterface(features []FeatureSet) {
+	gl := fillAssembleTemplate(ASSEMBLE_INTERFACE_GL, features, glRequirements)
+	writeToFile(*outDir, GL_FILE_NAME, gl)
+	gles := fillAssembleTemplate(ASSEMBLE_INTERFACE_GL_ES, features, glesRequirements)
+	writeToFile(*outDir, GLES_FILE_NAME, gles)
+	webgl := fillAssembleTemplate(ASSEMBLE_INTERFACE_WEBGL, features, webglRequirements)
+	writeToFile(*outDir, WEBGL_FILE_NAME, webgl)
+}
+
+// fillAssembleTemplate returns a generated file given a template (for a single standard)
+// to fill out and a slice of features with which to fill it.  getReqs is used to select
+// the requirements for the standard we are working on.
+func fillAssembleTemplate(template string, features []FeatureSet, getReqs RequirementGetter) string {
+	content := ""
+	for _, feature := range features {
+		// For each feature set, we are going to create a series of
+		// if statements, which check for the requirements (e.g. extensions, version)
+		// and inside those if branches, write the code to load the
+		// correct function pointer to the interface. GET_PROC and
+		// GET_PROC_SUFFIX are macros defined in C++ part of the template
+		// to accomplish this (for a core feature and extensions, respectively).
+		reqs := getReqs(feature)
+		if len(reqs) == 0 {
+			continue
+		}
+		// blocks holds all the if blocks generated - it will be joined with else
+		// after and appended to content
+		blocks := []string{}
+		for i, req := range reqs {
+			block := ""
+			ifExpr := requirementIfExpression(req, true)
+
+			if ifExpr != "" {
+				if strings.HasPrefix(ifExpr, "(") {
+					ifExpr = "if " + ifExpr + " {"
+				} else {
+					ifExpr = "if (" + ifExpr + ") {"
+				}
+				// Indent the first if statement
+				if i == 0 {
+					block = addLine(block, ifExpr)
+				} else {
+					block += ifExpr + "\n"
+				}
+			}
+			// sort for determinism
+			sort.Strings(feature.Functions)
+			for _, function := range feature.Functions {
+				block = assembleFunction(block, ifExpr, function, req)
+			}
+			sort.Strings(feature.TestOnlyFunctions)
+			if len(feature.TestOnlyFunctions) > 0 {
+				block += "#if GR_TEST_UTILS\n"
+				for _, function := range feature.TestOnlyFunctions {
+					block = assembleFunction(block, ifExpr, function, req)
+				}
+				block += "#endif\n"
+			}
+
+			// a hard code function does not use the C++ macro
+			for _, hcf := range feature.HardCodeFunctions {
+				if ifExpr != "" {
+					// extra tab for being in an if statement
+					block += SPACER
+				}
+				line := fmt.Sprintf(`functions->%s =(%s*)get(ctx, "%s");`, hcf.PtrName, hcf.CastName, hcf.GetName)
+				block = addLine(block, line)
+			}
+			if ifExpr != "" {
+				block += SPACER + "}"
+			}
+			blocks = append(blocks, block)
+		}
+		content += strings.Join(blocks, " else ")
+
+		if feature.Required && reqs[0] != CORE_REQUIREMENT {
+			content += ` else {
+        SkASSERT(false); // Required feature
+        return nullptr;
+    }`
+		}
+
+		if !strings.HasSuffix(content, "\n") {
+			content += "\n"
+		}
+		// Add an extra space between blocks for easier readability
+		content += "\n"
+
+	}
+
+	return strings.Replace(template, "[[content]]", content, 1)
+}
+
+// assembleFunction is a little helper that will add a function to the interface
+// using an appropriate macro (e.g. if the function is added)
+// with an extension.
+func assembleFunction(block, ifExpr, function string, req Requirement) string {
+	if ifExpr != "" {
+		// extra tab for being in an if statement
+		block += SPACER
+	}
+	suffix := deriveSuffix(req.Extension)
+	// Some ARB extensions don't have ARB suffixes because they were written
+	// for backwards compatibility simultaneous to adding them as required
+	// in a new GL version.
+	if suffix == "ARB" {
+		suffix = ""
+	}
+	if req.SuffixOverride != nil {
+		suffix = *req.SuffixOverride
+	}
+	if req.Extension == CORE_FEATURE || suffix == "" {
+		block = addLine(block, fmt.Sprintf("GET_PROC(%s);", function))
+	} else if req.Extension != "" {
+		block = addLine(block, fmt.Sprintf("GET_PROC_SUFFIX(%s, %s);", function, suffix))
+	}
+	return block
+}
+
+// requirementIfExpression returns a string that is an if expression
+// Notably, there is no if expression if the function is a "core" function
+// on all supported versions.
+// The expressions are wrapped in parentheses so they can be safely
+// joined together with && or ||.
+func requirementIfExpression(req Requirement, isLocal bool) string {
+	mv := req.MinVersion
+	if req == CORE_REQUIREMENT {
+		return ""
+	}
+	if req.Extension == CORE_FEATURE && mv != nil {
+		return fmt.Sprintf("(glVer >= GR_GL_VER(%d,%d))", mv[0], mv[1])
+	}
+	extVar := "fExtensions"
+	if isLocal {
+		extVar = "extensions"
+	}
+	// We know it has an extension
+	if req.Extension != "" {
+		if mv == nil {
+			return fmt.Sprintf("%s.has(%q)", extVar, req.Extension)
+		} else {
+			return fmt.Sprintf("(glVer >= GR_GL_VER(%d,%d) && %s.has(%q))", mv[0], mv[1], extVar, req.Extension)
+		}
+	}
+	abort("ERROR: requirement must have ext")
+	return "ERROR"
+}
+
+// driveSuffix returns the suffix of the function associated with the given
+// extension.
+func deriveSuffix(ext string) string {
+	// Some extensions begin with GL_ and then have the actual
+	// extension like KHR, EXT etc.
+	ext = strings.TrimPrefix(ext, "GL_")
+	return strings.Split(ext, "_")[0]
+}
+
+// addLine is a little helper function which handles the newline and tab
+func addLine(str, line string) string {
+	return str + SPACER + line + "\n"
+}
+
+func writeToFile(parent, file, content string) {
+	p := filepath.Join(parent, file)
+	if *dryRun {
+		fmt.Printf("Writing to %s\n", p)
+		fmt.Println(content)
+	} else {
+		if err := ioutil.WriteFile(p, []byte(content), 0644); err != nil {
+			abort("Error while writing to file %s: %s", p, err)
+		}
+	}
+}
+
+// validationEntry is a helper struct that contains anything
+// necessary to make validation code for a given standard.
+type validationEntry struct {
+	StandardCheck string
+	GetReqs       RequirementGetter
+}
+
+func generateValidateInterface(features []FeatureSet) {
+	standards := []validationEntry{
+		{
+			StandardCheck: "GR_IS_GR_GL(fStandard)",
+			GetReqs:       glRequirements,
+		}, {
+			StandardCheck: "GR_IS_GR_GL_ES(fStandard)",
+			GetReqs:       glesRequirements,
+		}, {
+			StandardCheck: "GR_IS_GR_WEBGL(fStandard)",
+			GetReqs:       webglRequirements,
+		},
+	}
+	content := ""
+	// For each feature, we are going to generate a series of
+	// boolean expressions which check that the functions we thought
+	// were gathered during the assemble phase actually were applied to
+	// the interface (functionCheck). This check will be guarded
+	// another set of if statements (one per standard) based
+	// on the same requirements (standardChecks) that were used when
+	// assembling the interface.
+	for _, feature := range features {
+		if allReqsAreCore(feature) {
+			content += functionCheck(feature, 1)
+		} else {
+			content += SPACER
+			standardChecks := []string{}
+			for _, std := range standards {
+				reqs := std.GetReqs(feature)
+				if reqs == nil || len(reqs) == 0 {
+					continue
+				}
+				expr := []string{}
+				for _, r := range reqs {
+					e := requirementIfExpression(r, false)
+					if e != "" {
+						expr = append(expr, e)
+					}
+				}
+				check := ""
+				if len(expr) == 0 {
+					check = fmt.Sprintf("%s", std.StandardCheck)
+				} else {
+					lineBreak := "\n" + SPACER + "      "
+					check = fmt.Sprintf("(%s && (%s%s))", std.StandardCheck, lineBreak, strings.Join(expr, " ||"+lineBreak))
+				}
+				standardChecks = append(standardChecks, check)
+			}
+			content += fmt.Sprintf("if (%s) {\n", strings.Join(standardChecks, " ||\n"+SPACER+"   "))
+			content += functionCheck(feature, 2)
+
+			content += SPACER + "}\n"
+		}
+		// add additional line between each block
+		content += "\n"
+	}
+	content = strings.Replace(VALIDATE_INTERFACE, "[[content]]", content, 1)
+	writeToFile(*outDir, INTERFACE_FILE_NAME, content)
+}
+
+// functionCheck returns an if statement that checks that all functions
+// in the passed in slice are on the interface (that is, they are truthy
+// on the fFunctions struct)
+func functionCheck(feature FeatureSet, indentLevel int) string {
+	// sort for determinism
+	sort.Strings(feature.Functions)
+	indent := strings.Repeat(SPACER, indentLevel)
+
+	checks := []string{}
+	for _, function := range feature.Functions {
+		if in(function, feature.OptionalFunctions) {
+			continue
+		}
+		checks = append(checks, "!fFunctions.f"+function)
+	}
+	testOnly := []string{}
+	for _, function := range feature.TestOnlyFunctions {
+		if in(function, feature.OptionalFunctions) {
+			continue
+		}
+		testOnly = append(testOnly, "!fFunctions.f"+function)
+	}
+	for _, hcf := range feature.HardCodeFunctions {
+		checks = append(checks, "!fFunctions."+hcf.PtrName)
+	}
+	preCheck := ""
+	if len(testOnly) != 0 {
+		preCheck = fmt.Sprintf(`#if GR_TEST_UTILS
+%sif (%s) {
+%s%sRETURN_FALSE_INTERFACE;
+%s}
+#endif
+`, indent, strings.Join(testOnly, " ||\n"+indent+"    "), indent, SPACER, indent)
+	}
+
+	if len(checks) == 0 {
+		return preCheck + strings.Repeat(SPACER, indentLevel) + "// all functions were marked optional or test_only\n"
+	}
+
+	return preCheck + fmt.Sprintf(`%sif (%s) {
+%s%sRETURN_FALSE_INTERFACE;
+%s}
+`, indent, strings.Join(checks, " ||\n"+indent+"    "), indent, SPACER, indent)
+}
+
+// allReqsAreCore returns true iff the FeatureSet is part of "core" for
+// all standards
+func allReqsAreCore(feature FeatureSet) bool {
+	if feature.GLReqs == nil || feature.GLESReqs == nil {
+		return false
+	}
+	return feature.GLReqs[0] == CORE_REQUIREMENT && feature.GLESReqs[0] == CORE_REQUIREMENT && feature.WebGLReqs[0] == CORE_REQUIREMENT
+}
+
+func validateFeatures(features []FeatureSet) {
+	seen := map[string]bool{}
+	for _, feature := range features {
+		for _, fn := range feature.Functions {
+			if seen[fn] {
+				abort("ERROR: Duplicate function %s", fn)
+			}
+			seen[fn] = true
+		}
+		for _, fn := range feature.TestOnlyFunctions {
+			if seen[fn] {
+				abort("ERROR: Duplicate function %s\n", fn)
+			}
+			seen[fn] = true
+		}
+	}
+}
+
+// in returns true if |s| is *in* |a| slice.
+func in(s string, a []string) bool {
+	for _, x := range a {
+		if x == s {
+			return true
+		}
+	}
+	return false
+}
+
+func abort(fmtStr string, inputs ...interface{}) {
+	fmt.Printf(fmtStr+"\n", inputs...)
+	os.Exit(1)
+}
+
+func main() {
+	flag.Parse()
+	b, err := ioutil.ReadFile(*inTable)
+	if err != nil {
+		abort("Could not read file %s", err)
+	}
+
+	dir, err := os.Open(*outDir)
+	if err != nil {
+		abort("Could not write to output dir %s", err)
+	}
+	defer dir.Close()
+	if fi, err := dir.Stat(); err != nil {
+		abort("Error getting info about %s: %s", *outDir, err)
+	} else if !fi.IsDir() {
+		abort("%s must be a directory", *outDir)
+	}
+
+	features := []FeatureSet{}
+
+	err = json5.Unmarshal(b, &features)
+	if err != nil {
+		abort("Invalid JSON: %s", err)
+	}
+
+	validateFeatures(features)
+
+	generateAssembleInterface(features)
+	generateValidateInterface(features)
+}
diff --git a/src/third_party/skia/tools/gpu/gl/interface/interface.json5 b/src/third_party/skia/tools/gpu/gl/interface/interface.json5
new file mode 100644
index 0000000..ceb3f44
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/gl/interface/interface.json5
@@ -0,0 +1,692 @@
+// This file specifies which functions should be attached to GrGLInterface
+// for a given standard (OpenGL, OpenGL ES, etc). It allows specifing
+// how and when to attach them (e.g. only if an extension is present).
+// It is used for both the assemble and validate step.
+//
+// To regenerate the Assemble/Validate code after editing this file, execute:
+//
+//   make -C tools/gpu/gl/interface generate
+//
+// Currently it assumes the minimum versions:
+//   - GL: 2.0
+//   - GLES: 2.0
+//   - WebGL: [WIP] 1.0
+//
+// http://web.eecs.umich.edu/~sugih/courses/eecs487/common/notes/APITables.xml
+// is a handy reference comparing GL and GLES API
+[
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"ext": "<core>"}],
+    "WebGL": [{"ext": "<core>"}],
+
+    "functions": [
+      "ActiveTexture", "AttachShader", "BindAttribLocation", "BindBuffer",
+      "BindTexture", "BlendColor", "BlendEquation", "BlendFunc",
+      "BufferData", "BufferSubData", "Clear", "ClearColor",
+      "ClearStencil", "ColorMask", "CompileShader", "CompressedTexImage2D",
+      "CompressedTexSubImage2D", "CopyTexSubImage2D", "CreateProgram", "CreateShader",
+      "CullFace", "DeleteBuffers", "DeleteProgram",
+      "DeleteShader", "DeleteTextures", "DepthMask", "Disable",
+      "DisableVertexAttribArray", "DrawArrays", "DrawElements", "Enable",
+      "EnableVertexAttribArray", "Finish", "Flush",
+      "FrontFace", "GenBuffers",
+      "GenTextures", "GetBufferParameteriv", "GetError",
+      "GetIntegerv", "GetProgramInfoLog",
+      "GetProgramiv", "GetShaderInfoLog",
+      "GetShaderiv", "GetString",
+      "GetUniformLocation", "IsTexture", "LineWidth", "LinkProgram", "PixelStorei",
+      "ReadPixels", "Scissor", "ShaderSource", "StencilFunc",
+      "StencilFuncSeparate", "StencilMask", "StencilMaskSeparate", "StencilOp",
+      "StencilOpSeparate", "TexImage2D", "TexParameterf", "TexParameterfv", "TexParameteri",
+      "TexParameteriv", "TexSubImage2D", "Uniform1f", "Uniform1fv", "Uniform1i", "Uniform1iv",
+      "Uniform2f", "Uniform2fv", "Uniform2i", "Uniform2iv", "Uniform3f", "Uniform3fv", "Uniform3i",
+      "Uniform3iv", "Uniform4f", "Uniform4fv", "Uniform4i", "Uniform4iv", "UniformMatrix2fv",
+      "UniformMatrix3fv", "UniformMatrix4fv", "UseProgram", "VertexAttrib1f",
+      "VertexAttrib2fv", "VertexAttrib3fv", "VertexAttrib4fv", "VertexAttribPointer",
+      "Viewport",
+    ],
+  },
+  { // GL exclusive core functions
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  null,
+
+    "functions": [
+      "DrawBuffer", "PolygonMode",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "GetStringi",
+    ]
+  },
+
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_vertex_array_object"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_vertex_array_object"},
+              {/*    else if      */  "ext": "OES_vertex_array_object"}],
+
+    // WebGL uses createVertexArray instead of genVertexArrays, but Emscripten
+    // creates an alias called genVertexArray which papers over this difference.
+    "functions": [
+      "BindVertexArray", "DeleteVertexArrays", "GenVertexArrays",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "GL_EXT_blend_func_extended"}],
+    "WebGL": null,
+
+    "functions": [
+      "BindFragDataLocation",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_blend_func_extended"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "GL_EXT_blend_func_extended"}],
+    "WebGL": null,
+
+    "functions": [
+      "BindFragDataLocationIndexed",
+    ],
+  },
+
+  {
+    "GL":    [{"ext": "GL_KHR_blend_equation_advanced"},
+              {"ext": "GL_NV_blend_equation_advanced"}],
+    "GLES":  [{"ext": "GL_KHR_blend_equation_advanced"},
+              {"ext": "GL_NV_blend_equation_advanced"}],
+    "WebGL": null,
+
+    "functions": [
+      "BlendBarrier",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [4, 4], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_clear_texture"}],
+    "GLES":  [{"ext": "GL_EXT_clear_texture", "suffix": "EXT"}],
+    "WebGL": null,
+
+    "functions": [
+      "ClearTexImage", "ClearTexSubImage",
+    ],
+    // https://bugs.chromium.org/p/skia/issues/detail?id=8913
+    "optional": [
+      "ClearTexImage", "ClearTexSubImage",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [3, 1], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_draw_instanced"},
+              {/*    else if      */  "ext": "GL_EXT_draw_instanced"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_EXT_draw_instanced"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "DrawArraysInstanced", "DrawElementsInstanced",
+    ]
+  },
+  { // ES 3.0 has glDrawBuffers but not glDrawBuffer
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "DrawBuffers", "ReadBuffer",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [4, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_draw_indirect"}],
+    "GLES":  [{"min_version": [3, 1], "ext": "<core>"}],
+    "WebGL": null,
+
+    "functions": [
+      "DrawArraysIndirect", "DrawElementsIndirect",
+    ]
+  },
+
+  { // glDrawRangeElements was added to ES in 3.0.
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "DrawRangeElements",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_texture_multisample"}],
+    "GLES":  [{"min_version": [3, 1], "ext": "<core>"}],
+    "WebGL": null,
+
+    "functions": [
+      "GetMultisamplefv",
+    ]
+  },
+
+  // glGetTexLevelParameteriv was added to ES in 3.1.
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 1], "ext": "<core>"}],
+    "WebGL": null,
+
+    "functions": [
+      "GetTexLevelParameteriv",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_multi_draw_indirect"}],
+    "GLES":  [{"ext": "GL_EXT_multi_draw_indirect"}],
+    "WebGL": null,
+
+    "functions": [
+      "MultiDrawArraysIndirect", "MultiDrawElementsIndirect",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [3, 1], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_texture_buffer"},
+              {/*    else if      */  "ext": "GL_EXT_texture_buffer"}],
+    "WebGL": null,
+
+    "functions": [
+      "TexBuffer",
+    ]
+  },
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_texture_buffer"},
+              {/*    else if      */  "ext": "GL_EXT_texture_buffer"}],
+    "WebGL": null,
+
+    "functions": [
+      "TexBufferRange",
+    ]
+  },
+
+    // GL_EXT_texture_storage is part of desktop 4.2
+    // There is a desktop ARB extension and an ES+desktop EXT extension
+  {
+    "GL":    [{"min_version": [4, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_texture_storage"},
+              {/*    else if      */  "ext": "GL_EXT_texture_storage"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_EXT_texture_storage"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "TexStorage2D",
+    ]
+  },
+
+  // glTextureBarrier is part of desktop 4.5. There are also ARB and NV extensions.
+  {
+    "GL":    [{"min_version": [4, 5], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_texture_barrier"},
+              {/*    else if      */  "ext": "GL_NV_texture_barrier"}],
+    "GLES":  [{"ext": "GL_NV_texture_barrier"}],
+    "WebGL": null,
+
+    "functions": [
+      "TextureBarrier",
+    ]
+  },
+
+  {
+    "GL":    null, // Not supported
+    "GLES":  [{"ext": "GL_EXT_discard_framebuffer"}],
+    "WebGL": null,
+
+    "functions": [
+      "DiscardFramebuffer",
+    ]
+  },
+
+  {
+    "GL":    null, // Not supported
+    "GLES":  [{"ext": "GL_QCOM_tiled_rendering"}],
+    "WebGL": null,
+
+    "functions": [
+      "StartTiling", "EndTiling",
+    ]
+  },
+
+  {
+    "GL":    [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_instanced_arrays"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_EXT_instanced_arrays"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "VertexAttribDivisor",
+    ]
+  },
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "VertexAttribIPointer",
+    ]
+  },
+
+  // FrameBuffer Object (FBO) related calls
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_framebuffer_object"},
+              {/*    else if      */  "ext": "GL_EXT_framebuffer_object"}],
+    "GLES":  [{"ext": "<core>"}], // These are all in ES 2.0 and above
+    "WebGL": [{"ext": "<core>"}],
+
+    "functions": [
+      "BindFramebuffer", "BindRenderbuffer", "CheckFramebufferStatus",
+      "DeleteFramebuffers", "DeleteRenderbuffers", "FramebufferRenderbuffer",
+      "FramebufferTexture2D", "GenFramebuffers", "GenRenderbuffers", "GenerateMipmap",
+      "GetFramebufferAttachmentParameteriv", "GetRenderbufferParameteriv",
+      "RenderbufferStorage",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_framebuffer_object"},
+              {/*    else if      */  "ext": "GL_EXT_framebuffer_blit"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_CHROMIUM_framebuffer_multisample"},
+              {/*    else if      */  "ext": "GL_ANGLE_framebuffer_blit"}],
+    // WebGL 2.0 might have support for blitFramebuffer and related functions.
+
+    "functions": [
+      "BlitFramebuffer",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_framebuffer_object"},
+              {/*    else if      */  "ext": "GL_EXT_framebuffer_multisample"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_CHROMIUM_framebuffer_multisample"},
+              {/*    else if      */  "ext": "GL_ANGLE_framebuffer_multisample"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "RenderbufferStorageMultisample",
+    ],
+  },
+
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_CHROMIUM_map_sub"}],
+    "WebGL": null,
+
+    "functions": [
+      "MapBufferSubData", "MapTexSubImage2D", "UnmapBufferSubData",
+      "UnmapTexSubImage2D"
+    ],
+  },
+
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_EXT_multisampled_render_to_texture"},
+              {"ext": "GL_IMG_multisampled_render_to_texture"}],
+    "WebGL": null,
+
+    "functions": [
+      "FramebufferTexture2DMultisample",
+    ],
+  },
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_EXT_multisampled_render_to_texture"}],
+    "WebGL": null,
+
+    "hardcode_functions" : [
+      {
+        "ptr_name": "fRenderbufferStorageMultisampleES2EXT",
+        "cast_name": "GrGLRenderbufferStorageMultisampleFn",
+        "get_name": "glRenderbufferStorageMultisampleEXT",
+      }
+    ]
+  },
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_IMG_multisampled_render_to_texture"}],
+    "WebGL": null,
+
+    "hardcode_functions" : [
+      {
+        "ptr_name": "fRenderbufferStorageMultisampleES2EXT",
+        "cast_name": "GrGLRenderbufferStorageMultisampleFn",
+        "get_name": "glRenderbufferStorageMultisampleIMG",
+      }
+    ]
+  },
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_APPLE_framebuffer_multisample"}],
+    "WebGL": null,
+
+    "functions" : ["ResolveMultisampleFramebuffer"],
+    "hardcode_functions" : [
+      {
+        "ptr_name": "fRenderbufferStorageMultisampleES2APPLE",
+        "cast_name": "GrGLRenderbufferStorageMultisampleFn",
+        "get_name": "glRenderbufferStorageMultisampleAPPLE",
+      }
+    ]
+  },
+
+    // There are several APIs for buffer mapping:
+    // ES2 + GL_OES_mapbuffer: MapBufferOES and UnmapBufferOES
+    // ES2 + GL_EXT_map_buffer_range: Adds MapBufferRangeEXT and FlushMappedBufferRangeEXT
+    // ES3: MapBufferRange, FlushMappedBufferRange, and UnmapBuffer are core (so no suffix).
+    //
+    // MapBuffer is not part of ES3, but implementations may still report the OES versions of
+    // MapBuffer and UnmapBuffer, per the older GL_OES_mapbuffer extension. Some implementations
+    // let us mix the newer MapBufferRange with the older UnmapBufferOES, but we've hit others that
+    // don't permit it. Note that in GrGLBuffer, we choose which API to use based on version and
+    // extensions. This code is written so that we never mix OES and non-OES functions.
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"ext": "GL_OES_mapbuffer"}],
+    "WebGL": null,
+
+    "functions": [
+      "MapBuffer",
+    ],
+  },
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_mapbuffer"}],
+    "WebGL": null, // explicitly removed https://www.khronos.org/registry/webgl/specs/2.0/#5.14
+
+    "functions": [
+      "UnmapBuffer",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_map_buffer_range"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_EXT_map_buffer_range"}],
+    "WebGL": null, // explicitly removed https://www.khronos.org/registry/webgl/specs/2.0/#5.14
+
+    "functions": [
+      // These functions are added to the 3.0 version of both GLES and GL.
+      "MapBufferRange", "FlushMappedBufferRange",
+    ],
+  },
+
+  {
+    "GL":    [{"ext": "GL_EXT_debug_marker"}],
+    "GLES":  [{"ext": "GL_EXT_debug_marker"}],
+    "WebGL": null,
+
+    "functions": [
+      "InsertEventMarker", "PushGroupMarker", "PopGroupMarker"
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_program_interface_query"}],
+    "GLES":  [{"min_version": [3, 1], "ext": "<core>"}],
+    "WebGL": null,
+
+    "functions": [
+      "GetProgramResourceLocation",
+    ],
+  },
+
+  {  // It appears that the GL_NV_path_rendering sometimes provides these
+     // functions under the "EXT" extension instead of "NV".
+    "GL":    [{"ext": "GL_NV_path_rendering", "suffix": "EXT"}],
+
+    "GLES":  [{"ext": "GL_CHROMIUM_path_rendering"},
+              {"ext": "GL_NV_path_rendering", "suffix": "EXT"}],
+    "WebGL": null,
+
+    "functions": [
+      "MatrixLoadIdentity", "MatrixLoadf"
+    ],
+  },
+  {
+    "GL":    [{"ext": "GL_NV_path_rendering"}],
+    "GLES":  [{"ext": "GL_CHROMIUM_path_rendering"},
+              {"ext": "GL_NV_path_rendering"}],
+    "WebGL": null,
+
+    "functions": [
+      "CoverFillPath", "CoverFillPathInstanced", "CoverStrokePath",
+      "CoverStrokePathInstanced", "DeletePaths", "GenPaths",
+      "IsPath", "PathCommands", "PathParameterf", "PathParameteri",
+      "PathStencilFunc", "ProgramPathFragmentInputGen", "StencilFillPath",
+      "StencilFillPathInstanced", "StencilStrokePath", "StencilStrokePathInstanced",
+      "StencilThenCoverFillPath", "StencilThenCoverFillPathInstanced",
+      "StencilThenCoverStrokePath", "StencilThenCoverStrokePathInstanced",
+    ],
+    // List of functions that Skia uses, but which have been added since the initial release
+    // of NV_path_rendering driver. We do not want to fail interface validation due to
+    // missing features, we will just not use the extension.
+    // If one updates this list, then update GrGLCaps::hasPathRenderingSupport too.
+    "optional": [
+      "ProgramPathFragmentInputGen", "StencilThenCoverFillPath",
+      "StencilThenCoverFillPathInstanced", "StencilThenCoverStrokePath",
+      "StencilThenCoverStrokePathInstanced",
+    ],
+  },
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_CHROMIUM_path_rendering"}],
+    "WebGL": null,
+
+    "functions": [
+      "BindFragmentInputLocation",
+    ],
+  },
+  {
+    "GL":    [{"ext": "GL_NV_framebuffer_mixed_samples"}],
+    "GLES":  [{"ext": "GL_CHROMIUM_framebuffer_mixed_samples"},
+              {"ext": "GL_NV_framebuffer_mixed_samples"}],
+    "WebGL": null,
+
+    "functions": [
+      "CoverageModulation",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_KHR_debug", "suffix": ""}],
+    "GLES":  [{"ext": "GL_KHR_debug"}],
+    "WebGL": null,
+
+    // In OpenGL (but not ES), KHR_debug defines these methods to have no suffix.
+    "functions": [
+      "DebugMessageControl", "DebugMessageInsert", "DebugMessageCallback",
+      "GetDebugMessageLog", "PushDebugGroup", "PopDebugGroup", "ObjectLabel",
+    ],
+  },
+
+  {
+    "GL":    null,
+    "GLES":  [{"ext": "GL_CHROMIUM_bind_uniform_location"}],
+    "WebGL": null,
+
+    "functions": [
+      "BindUniformLocation",
+    ],
+  },
+
+  {
+    "GL":    [{"ext": "GL_EXT_window_rectangles"}],
+    "GLES":  [{"ext": "GL_EXT_window_rectangles"}],
+    "WebGL": null,
+
+    "functions": [
+      "WindowRectangles",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_sync"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_APPLE_sync"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "ClientWaitSync", "DeleteSync", "FenceSync",
+      "IsSync", "WaitSync"
+    ],
+  },
+
+  {  // getInternalformativ was added in GL 4.2, ES 3.0, and with
+     // extension ARB_internalformat_query
+    "GL":    [{"min_version": [4, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_internalformat_query"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": null,
+
+    "functions": [
+      "GetInternalformativ"
+    ],
+  },
+
+  // GetProgramBinary and ProgramBinary are available with an ES2 extension...
+  {
+    "GL":    [{"min_version": [4, 1], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_OES_get_program_binary"}],
+    "WebGL": null, // explicitly not supported in WebGL 2.0
+
+    "functions": [
+      "GetProgramBinary", "ProgramBinary",
+    ],
+  },
+
+  // ... but the related ProgramParameteri is only in ES3
+  {
+    "GL":    [{"min_version": [4, 1], "ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": null, // explicitly not supported in WebGL 2.0
+
+    "functions": [
+      "ProgramParameteri",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [3, 2], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_sampler_objects"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL":  [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "BindSampler", "DeleteSamplers", "GenSamplers",
+      "SamplerParameteri", "SamplerParameteriv",
+    ],
+  },
+
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  null, // not in ES
+    "WebGL": null,
+
+    "functions": [
+      "GetQueryObjectiv",
+    ],
+  },
+  {
+    "GL":    [{"ext": "<core>"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_EXT_occlusion_query_boolean"}],
+    "WebGL": null,
+
+    // We only use these in our test tools
+    "test_functions": [
+      "GenQueries", "DeleteQueries", "BeginQuery", "EndQuery",
+      "GetQueryObjectuiv", "GetQueryiv",
+    ]
+  },
+  {
+    "GL":    [{"min_version": [3, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_timer_query"},
+              {/*    else if      */  "ext": "GL_EXT_timer_query"}],
+    "GLES":  null,
+    "WebGL": null,
+
+    "functions": [
+      "GetQueryObjecti64v", "GetQueryObjectui64v",
+    ],
+  },
+  {
+    "GL":    [{"min_version": [3, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_timer_query"}],
+    "GLES":  null,
+    "WebGL": null,
+
+    "functions": [
+      "QueryCounter",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_invalidate_subdata"}],
+    "GLES":  null,
+    "WebGL": null,
+
+    "functions": [
+      "InvalidateBufferData", "InvalidateBufferSubData", "InvalidateTexImage",
+      "InvalidateTexSubImage",
+    ],
+  },
+  {  // ES 3.0 adds the framebuffer functions but not the others.
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_invalidate_subdata"}],
+    "GLES":  [{"min_version": [3, 0], "ext": "<core>"}],
+    "WebGL": [{"min_version": [2, 0], "ext": "<core>"}],
+
+    "functions": [
+      "InvalidateFramebuffer", "InvalidateSubFramebuffer",
+    ],
+  },
+
+  {
+    "GL":    [{"min_version": [4, 3], "ext": "<core>"},
+              {/*    else if      */  "ext": "GL_ARB_ES2_compatibility"}],
+    "GLES":  [{"ext": "<core>"}],
+    "WebGL": [{"ext": "<core>"}],
+
+    "functions": [
+      "GetShaderPrecisionFormat",
+    ],
+  },
+
+]
diff --git a/src/third_party/skia/tools/gpu/gl/interface/templates.go b/src/third_party/skia/tools/gpu/gl/interface/templates.go
new file mode 100644
index 0000000..650e855
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/gl/interface/templates.go
@@ -0,0 +1,268 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package main
+
+const ASSEMBLE_INTERFACE_GL_ES = `/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * THIS FILE IS AUTOGENERATED
+ * Make edits to tools/gpu/gl/interface/templates.go or they will
+ * be overwritten.
+ */
+
+#include "include/gpu/gl/GrGLAssembleHelpers.h"
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "src/gpu/gl/GrGLUtil.h"
+
+#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+
+#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)
+
+#if SK_DISABLE_GL_ES_INTERFACE
+sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
+    return nullptr;
+}
+#else
+sk_sp<const GrGLInterface> GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get) {
+    GET_PROC_LOCAL(GetString);
+    if (nullptr == GetString) {
+        return nullptr;
+    }
+
+    const char* verStr = reinterpret_cast<const char*>(GetString(GR_GL_VERSION));
+    GrGLVersion glVer = GrGLGetVersionFromString(verStr);
+
+    if (glVer < GR_GL_VER(2,0)) {
+        return nullptr;
+    }
+
+    GET_PROC_LOCAL(GetIntegerv);
+    GET_PROC_LOCAL(GetStringi);
+    GrEGLQueryStringFn* queryString;
+    GrEGLDisplay display;
+    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
+    GrGLExtensions extensions;
+    if (!extensions.init(kGLES_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
+                         display)) {
+        return nullptr;
+    }
+
+    sk_sp<GrGLInterface> interface(new GrGLInterface);
+    GrGLInterface::Functions* functions = &interface->fFunctions;
+
+    // Autogenerated content follows
+[[content]]
+    // End autogenerated content
+    // TODO(kjlubick): Do we want a feature that removes the extension if it doesn't have
+    // the function? This is common on some low-end GPUs.
+
+    if (extensions.has("GL_KHR_debug")) {
+        // In general we have a policy against removing extension strings when the driver does
+        // not provide function pointers for an advertised extension. However, because there is a
+        // known device that advertises GL_KHR_debug but fails to provide the functions and this is
+        // a debugging- only extension we've made an exception. This also can happen when using
+        // APITRACE.
+        if (!interface->fFunctions.fDebugMessageControl) {
+            extensions.remove("GL_KHR_debug");
+        }
+    }
+    interface->fStandard = kGLES_GrGLStandard;
+    interface->fExtensions.swap(&extensions);
+
+    return interface;
+}
+#endif
+`
+
+const ASSEMBLE_INTERFACE_GL = `/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * THIS FILE IS AUTOGENERATED
+ * Make edits to tools/gpu/gl/interface/templates.go or they will
+ * be overwritten.
+ */
+
+#include "include/gpu/gl/GrGLAssembleHelpers.h"
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "src/gpu/gl/GrGLUtil.h"
+
+#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+
+#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)
+
+#if SK_DISABLE_GL_INTERFACE
+sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
+    return nullptr;
+}
+#else
+sk_sp<const GrGLInterface> GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get) {
+    GET_PROC_LOCAL(GetString);
+    GET_PROC_LOCAL(GetStringi);
+    GET_PROC_LOCAL(GetIntegerv);
+
+    // GetStringi may be nullptr depending on the GL version.
+    if (nullptr == GetString || nullptr == GetIntegerv) {
+        return nullptr;
+    }
+
+    const char* versionString = (const char*) GetString(GR_GL_VERSION);
+    GrGLVersion glVer = GrGLGetVersionFromString(versionString);
+
+    if (glVer < GR_GL_VER(2,0) || GR_GL_INVALID_VER == glVer) {
+        // This is our minimum for non-ES GL.
+        return nullptr;
+    }
+
+    GrEGLQueryStringFn* queryString;
+    GrEGLDisplay display;
+    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
+    GrGLExtensions extensions;
+    if (!extensions.init(kGL_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
+                         display)) {
+        return nullptr;
+    }
+
+    sk_sp<GrGLInterface> interface(new GrGLInterface());
+    GrGLInterface::Functions* functions = &interface->fFunctions;
+
+    // Autogenerated content follows
+[[content]]
+    // End autogenerated content
+    interface->fStandard = kGL_GrGLStandard;
+    interface->fExtensions.swap(&extensions);
+
+    return interface;
+}
+#endif
+`
+
+const ASSEMBLE_INTERFACE_WEBGL = `/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * THIS FILE IS AUTOGENERATED
+ * Make edits to tools/gpu/gl/interface/templates.go or they will
+ * be overwritten.
+ */
+
+#include "include/gpu/gl/GrGLAssembleHelpers.h"
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "src/gpu/gl/GrGLUtil.h"
+
+#define GET_PROC(F) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f##F = (GrGL##F##Fn*)get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL##F##Fn* F = (GrGL##F##Fn*)get(ctx, "gl" #F)
+
+#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL##F = (GrEGL##F##Fn*)get(ctx, "egl" #F #S)
+
+#if SK_DISABLE_WEBGL_INTERFACE
+sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
+    return nullptr;
+}
+#else
+sk_sp<const GrGLInterface> GrGLMakeAssembledWebGLInterface(void *ctx, GrGLGetProc get) {
+    GET_PROC_LOCAL(GetString);
+    if (nullptr == GetString) {
+        return nullptr;
+    }
+
+    const char* verStr = reinterpret_cast<const char*>(GetString(GR_GL_VERSION));
+    GrGLVersion glVer = GrGLGetVersionFromString(verStr);
+
+    if (glVer < GR_GL_VER(1,0)) {
+        return nullptr;
+    }
+
+    GET_PROC_LOCAL(GetIntegerv);
+    GET_PROC_LOCAL(GetStringi);
+    GrEGLQueryStringFn* queryString;
+    GrEGLDisplay display;
+    GrGetEGLQueryAndDisplay(&queryString, &display, ctx, get);
+    GrGLExtensions extensions;
+    if (!extensions.init(kWebGL_GrGLStandard, GetString, GetStringi, GetIntegerv, queryString,
+                         display)) {
+        return nullptr;
+    }
+
+    sk_sp<GrGLInterface> interface(new GrGLInterface);
+    GrGLInterface::Functions* functions = &interface->fFunctions;
+
+    // Autogenerated content follows
+[[content]]
+    // End autogenerated content
+
+    interface->fStandard = kWebGL_GrGLStandard;
+    interface->fExtensions.swap(&extensions);
+
+    return interface;
+}
+#endif
+`
+
+const VALIDATE_INTERFACE = `/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * THIS FILE IS AUTOGENERATED
+ * Make edits to tools/gpu/gl/interface/templates.go or they will
+ * be overwritten.
+ */
+
+#include "include/gpu/gl/GrGLExtensions.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "src/gpu/gl/GrGLUtil.h"
+
+#include <stdio.h>
+
+GrGLInterface::GrGLInterface() {
+    fStandard = kNone_GrGLStandard;
+}
+
+#define RETURN_FALSE_INTERFACE                                                 \
+    SkDEBUGF("%s:%d GrGLInterface::validate() failed.\n", __FILE__, __LINE__); \
+    return false
+
+bool GrGLInterface::validate() const {
+
+    if (kNone_GrGLStandard == fStandard) {
+        RETURN_FALSE_INTERFACE;
+    }
+
+    if (!fExtensions.isInitialized()) {
+        RETURN_FALSE_INTERFACE;
+    }
+
+    GrGLVersion glVer = GrGLGetVersion(this);
+    if (GR_GL_INVALID_VER == glVer) {
+        RETURN_FALSE_INTERFACE;
+    }
+    // Autogenerated content follows
+[[content]]
+    // End autogenerated content
+    return true;
+}
+
+#if GR_TEST_UTILS
+
+void GrGLInterface::abandon() const {
+    const_cast<GrGLInterface*>(this)->fFunctions = GrGLInterface::Functions();
+}
+
+#endif // GR_TEST_UTILS
+`
diff --git a/src/third_party/skia/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp b/src/third_party/skia/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp
index 8ce687d..c27fe24 100644
--- a/src/third_party/skia/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp
+++ b/src/third_party/skia/tools/gpu/gl/mac/CreatePlatformGLTestContext_mac.cpp
@@ -5,15 +5,21 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 #include "AvailabilityMacros.h"
 
 #include <OpenGL/OpenGL.h>
 #include <dlfcn.h>
 
 namespace {
+
+std::function<void()> context_restorer() {
+    auto context = CGLGetCurrentContext();
+    return [context] { CGLSetCurrentContext(context); };
+}
+
 class MacGLTestContext : public sk_gpu_test::GLTestContext {
 public:
     MacGLTestContext(MacGLTestContext* shareContext);
@@ -23,6 +29,7 @@
     void destroyGLContext();
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
 
@@ -58,10 +65,11 @@
         return;
     }
 
+    SkScopeExit restorer(context_restorer());
     CGLSetCurrentContext(fContext);
 
-    sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
-    if (nullptr == gl.get()) {
+    auto gl = GrGLMakeNativeInterface();
+    if (!gl) {
         SkDebugf("Context could not create GL interface.\n");
         this->destroyGLContext();
         return;
@@ -76,7 +84,7 @@
         "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
         RTLD_LAZY);
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 MacGLTestContext::~MacGLTestContext() {
@@ -86,10 +94,14 @@
 
 void MacGLTestContext::destroyGLContext() {
     if (fContext) {
+        if (CGLGetCurrentContext() == fContext) {
+            // This will ensure that the context is immediately deleted.
+            CGLSetCurrentContext(nullptr);
+        }
         CGLReleaseContext(fContext);
         fContext = nullptr;
     }
-    if (RTLD_DEFAULT != fGLLibrary) {
+    if (nullptr != fGLLibrary) {
         dlclose(fGLLibrary);
     }
 }
@@ -98,12 +110,20 @@
     CGLSetCurrentContext(fContext);
 }
 
+std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const {
+    if (CGLGetCurrentContext() == fContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void MacGLTestContext::onPlatformSwapBuffers() const {
     CGLFlushDrawable(fContext);
 }
 
 GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const {
-    return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
+    void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
+    return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
 }
 
 }  // anonymous namespace
diff --git a/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.cpp b/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.cpp
deleted file mode 100644
index 5d0014b..0000000
--- a/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <GL/osmesa.h>
-
-#include "gl/mesa/GLTestContext_mesa.h"
-#include "gl/GrGLDefines.h"
-
-#include "gl/GrGLAssembleInterface.h"
-#include "gl/GrGLUtil.h"
-#include "osmesa_wrapper.h"
-
-namespace {
-
-static GrGLFuncPtr osmesa_get(void* ctx, const char name[]) {
-    SkASSERT(nullptr == ctx);
-    SkASSERT(OSMesaGetCurrentContext());
-    return OSMesaGetProcAddress(name);
-}
-
-static const GrGLInterface* create_mesa_interface() {
-    if (nullptr == OSMesaGetCurrentContext()) {
-        return nullptr;
-    }
-    return GrGLAssembleInterface(nullptr, osmesa_get);
-}
-
-static const GrGLint gBOGUS_SIZE = 16;
-
-class MesaGLContext : public sk_gpu_test::GLTestContext {
-private:
-    typedef intptr_t Context;
-
-public:
-    MesaGLContext(MesaGLContext* shareContext);
-    ~MesaGLContext() override;
-
-private:
-    void destroyGLContext();
-
-    void onPlatformMakeCurrent() const override;
-
-    void onPlatformSwapBuffers() const override;
-
-    GrGLFuncPtr onPlatformGetProcAddress(const char *) const override;
-
-    Context fContext;
-    GrGLubyte *fImage;
-};
-
-MesaGLContext::MesaGLContext(MesaGLContext* shareContext)
-        : fContext(static_cast<Context>(0))
-        , fImage(nullptr) {
-    GR_STATIC_ASSERT(sizeof(Context) == sizeof(OSMesaContext));
-    OSMesaContext mesaShareContext = shareContext ? (OSMesaContext)(shareContext->fContext)
-                                                  : nullptr;
-
-    /* Create an RGBA-mode context */
-#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
-    /* specify Z, stencil, accum sizes */
-    fContext = (Context)OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, mesaShareContext);
-#else
-    fContext = (Context) OSMesaCreateContext(OSMESA_BGRA, mesaShareContext);
-#endif
-    if (!fContext) {
-        SkDebugf("OSMesaCreateContext failed!\n");
-        this->destroyGLContext();
-        return;
-    }
-    // Allocate the image buffer
-    fImage = (GrGLubyte *) sk_malloc_throw(gBOGUS_SIZE * gBOGUS_SIZE *
-                                           4 * sizeof(GrGLubyte));
-    if (!fImage) {
-        SkDebugf("Alloc image buffer failed!\n");
-        this->destroyGLContext();
-        return;
-    }
-
-    // Bind the buffer to the context and make it current
-    if (!OSMesaMakeCurrent((OSMesaContext) fContext,
-                           fImage,
-                           GR_GL_UNSIGNED_BYTE,
-                           gBOGUS_SIZE,
-                           gBOGUS_SIZE)) {
-        SkDebugf("OSMesaMakeCurrent failed!\n");
-        this->destroyGLContext();
-        return;
-    }
-
-    sk_sp<const GrGLInterface> gl(create_mesa_interface());
-    if (nullptr == gl.get()) {
-        SkDebugf("Could not create GL interface!\n");
-        this->destroyGLContext();
-        return;
-    }
-
-    if (!gl->validate()) {
-        SkDebugf("Could not validate GL interface!\n");
-        this->destroyGLContext();
-        return;
-    }
-
-    this->init(gl.release());
-}
-
-MesaGLContext::~MesaGLContext() {
-    this->teardown();
-    this->destroyGLContext();
-}
-
-void MesaGLContext::destroyGLContext() {
-    if (fImage) {
-        sk_free(fImage);
-        fImage = nullptr;
-    }
-
-    if (fContext) {
-        OSMesaDestroyContext((OSMesaContext) fContext);
-        fContext = static_cast<Context>(0);
-    }
-}
-
-
-void MesaGLContext::onPlatformMakeCurrent() const {
-    if (fContext) {
-        if (!OSMesaMakeCurrent((OSMesaContext) fContext, fImage,
-                               GR_GL_UNSIGNED_BYTE, gBOGUS_SIZE, gBOGUS_SIZE)) {
-            SkDebugf("Could not make MESA context current.");
-        }
-    }
-}
-
-void MesaGLContext::onPlatformSwapBuffers() const { }
-
-GrGLFuncPtr MesaGLContext::onPlatformGetProcAddress(const char *procName) const {
-    return OSMesaGetProcAddress(procName);
-}
-}  // anonymous namespace
-
-
-namespace sk_gpu_test {
-GLTestContext *CreateMesaGLTestContext(GLTestContext* shareContext) {
-    MesaGLContext* mesaShareContext = reinterpret_cast<MesaGLContext*>(shareContext);
-    MesaGLContext *ctx = new MesaGLContext(mesaShareContext);
-    if (!ctx->isValid()) {
-        delete ctx;
-        return nullptr;
-    }
-    return ctx;
-}
-}  // sk_gpu_test
diff --git a/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.h b/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.h
deleted file mode 100644
index 40184aa..0000000
--- a/src/third_party/skia/tools/gpu/gl/mesa/GLTestContext_mesa.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef GLTestContext_mesa_DEFINED
-#define GLTestContext_mesa_DEFINED
-
-#include "gl/GLTestContext.h"
-
-namespace sk_gpu_test {
-GLTestContext* CreateMesaGLTestContext(GLTestContext* shareContext);
-}  // namespace sk_gpu_test
-
-#endif
diff --git a/src/third_party/skia/tools/gpu/gl/mesa/osmesa_wrapper.h b/src/third_party/skia/tools/gpu/gl/mesa/osmesa_wrapper.h
deleted file mode 100644
index 70de993..0000000
--- a/src/third_party/skia/tools/gpu/gl/mesa/osmesa_wrapper.h
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Older versions of XQuartz have a bug where a header included by osmesa.h
-// defines GL_GLEXT_PROTOTYPES. This will cause a redefinition warning if
-// the file that includes osmesa.h already defined it. XCode 3 uses a version
-// of gcc (4.2.1) that does not support the diagnostic pragma to disable a
-// warning (added in 4.2.4). So we use the system_header pragma to shut GCC
-// up about warnings in osmesa.h
-#pragma GCC system_header
-#include <GL/osmesa.h>
diff --git a/src/third_party/skia/tools/gpu/gl/none/CreatePlatformGLTestContext_none.cpp b/src/third_party/skia/tools/gpu/gl/none/CreatePlatformGLTestContext_none.cpp
index 25343b0..de2f935 100644
--- a/src/third_party/skia/tools/gpu/gl/none/CreatePlatformGLTestContext_none.cpp
+++ b/src/third_party/skia/tools/gpu/gl/none/CreatePlatformGLTestContext_none.cpp
@@ -6,7 +6,7 @@
  * found in the LICENSE file.
  */
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
 
 namespace sk_gpu_test {
 GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
diff --git a/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.cpp b/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.cpp
deleted file mode 100644
index 894de07..0000000
--- a/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "NullGLTestContext.h"
-#include "gl/GrGLTestInterface.h"
-#include "gl/GrGLDefines.h"
-#include "gl/GrGLInterface.h"
-#include "gl/GrGLTypes.h"
-#include "SkMutex.h"
-#include "SkTDArray.h"
-
-namespace {
-class NullGLContext : public sk_gpu_test::GLTestContext {
-public:
-    NullGLContext(bool enableNVPR) { this->init(GrGLCreateNullInterface(enableNVPR)); }
-   ~NullGLContext() override { this->teardown(); }
-
-private:
-    void onPlatformMakeCurrent() const override {}
-    void onPlatformSwapBuffers() const override {}
-    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; }
-};
-
-}  // anonymous namespace
-
-namespace sk_gpu_test {
-GLTestContext* CreateNullGLTestContext(bool enableNVPR, GLTestContext* shareContext) {
-    if (shareContext) {
-        return nullptr;
-    }
-    GLTestContext* ctx = new NullGLContext(enableNVPR);
-    if (ctx->isValid()) {
-        return ctx;
-    }
-    delete ctx;
-    return nullptr;
-}
-}  // namespace sk_gpu_test
-
diff --git a/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.h b/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.h
deleted file mode 100644
index 9062e88..0000000
--- a/src/third_party/skia/tools/gpu/gl/null/NullGLTestContext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef NullGLContext_DEFINED
-#define NullGLContext_DEFINED
-
-#include "gl/GLTestContext.h"
-
-namespace sk_gpu_test {
-GLTestContext* CreateNullGLTestContext(bool enableNVPR, GLTestContext* shareContext);
-}  // namespace sk_gpu_test
-
-#endif
diff --git a/src/third_party/skia/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp b/src/third_party/skia/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
index 49d7743..7159c13 100644
--- a/src/third_party/skia/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
+++ b/src/third_party/skia/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
@@ -6,16 +6,32 @@
  * found in the LICENSE file.
  */
 
-#include "gl/GLTestContext.h"
+#include "tools/gpu/gl/GLTestContext.h"
+
+#if defined(_M_ARM64)
+
+namespace sk_gpu_test {
+
+GLTestContext* CreatePlatformGLTestContext(GrGLStandard, GLTestContext*) { return nullptr; }
+
+}  // namespace sk_gpu_test
+
+#else
 
 #include <windows.h>
 #include <GL/GL.h>
-#include "win/SkWGL.h"
+#include "src/utils/win/SkWGL.h"
 
 #include <windows.h>
 
 namespace {
 
+std::function<void()> context_restorer() {
+    auto glrc = wglGetCurrentContext();
+    auto dc = wglGetCurrentDC();
+    return [glrc, dc] { wglMakeCurrent(dc, glrc); };
+}
+
 class WinGLTestContext : public sk_gpu_test::GLTestContext {
 public:
     WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext);
@@ -25,6 +41,7 @@
     void destroyGLContext();
 
     void onPlatformMakeCurrent() const override;
+    std::function<void()> onPlatformGetAutoContextRestore() const override;
     void onPlatformSwapBuffers() const override;
     GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
 
@@ -32,7 +49,7 @@
     HDC fDeviceContext;
     HGLRC fGlRenderContext;
     static ATOM gWC;
-    SkWGLPbufferContext* fPbufferContext;
+    sk_sp<SkWGLPbufferContext> fPbufferContext;
 };
 
 ATOM WinGLTestContext::gWC = 0;
@@ -90,7 +107,7 @@
         winShareContext = shareContext->fPbufferContext ? shareContext->fPbufferContext->getGLRC()
                                                         : shareContext->fGlRenderContext;
     }
-    fPbufferContext = SkWGLPbufferContext::Create(fDeviceContext, 0, contextType, winShareContext);
+    fPbufferContext = SkWGLPbufferContext::Create(fDeviceContext, contextType, winShareContext);
 
     HDC dc;
     HGLRC glrc;
@@ -113,14 +130,15 @@
         glrc = fPbufferContext->getGLRC();
     }
 
+    SkScopeExit restorer(context_restorer());
     if (!(wglMakeCurrent(dc, glrc))) {
         SkDebugf("Could not set the context.\n");
         this->destroyGLContext();
         return;
     }
 
-    sk_sp<const GrGLInterface> gl(GrGLCreateNativeInterface());
-    if (nullptr == gl.get()) {
+    auto gl = GrGLMakeNativeInterface();
+    if (!gl) {
         SkDebugf("Could not create GL interface.\n");
         this->destroyGLContext();
         return;
@@ -131,7 +149,7 @@
         return;
     }
 
-    this->init(gl.release());
+    this->init(std::move(gl));
 }
 
 WinGLTestContext::~WinGLTestContext() {
@@ -140,8 +158,9 @@
 }
 
 void WinGLTestContext::destroyGLContext() {
-    SkSafeSetNull(fPbufferContext);
+    fPbufferContext = nullptr;
     if (fGlRenderContext) {
+        // This deletes the context immediately even if it is current.
         wglDeleteContext(fGlRenderContext);
         fGlRenderContext = 0;
     }
@@ -172,6 +191,13 @@
     }
 }
 
+std::function<void()> WinGLTestContext::onPlatformGetAutoContextRestore() const {
+    if (wglGetCurrentContext() == fGlRenderContext) {
+        return nullptr;
+    }
+    return context_restorer();
+}
+
 void WinGLTestContext::onPlatformSwapBuffers() const {
     HDC dc;
 
@@ -204,3 +230,4 @@
 }
 }  // namespace sk_gpu_test
 
+#endif
diff --git a/src/third_party/skia/tools/gpu/mock/MockTestContext.cpp b/src/third_party/skia/tools/gpu/mock/MockTestContext.cpp
index 56cd68c..f892714 100644
--- a/src/third_party/skia/tools/gpu/mock/MockTestContext.cpp
+++ b/src/third_party/skia/tools/gpu/mock/MockTestContext.cpp
@@ -8,7 +8,9 @@
 #ifndef GLTestContext_DEFINED
 #define GLTestContext_DEFINED
 
-#include "MockTestContext.h"
+#include "tools/gpu/mock/MockTestContext.h"
+
+#include "include/gpu/GrContext.h"
 
 namespace {
 
@@ -17,17 +19,20 @@
     MockTestContext() {}
     ~MockTestContext() override {}
 
-    virtual GrBackend backend() override { return kMock_GrBackend; }
-    virtual GrBackendContext backendContext() override {
-        return reinterpret_cast<GrBackendContext>(nullptr);
-    }
+    virtual GrBackendApi backend() override { return GrBackendApi::kMock; }
+
     void testAbandon() override {}
     void submit() override {}
     void finish() override {}
 
+    sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
+        return GrContext::MakeMock(nullptr, options);
+    }
+
 protected:
     void teardown() override {}
     void onPlatformMakeCurrent() const override {}
+    std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
     void onPlatformSwapBuffers() const override {}
 
 private:
diff --git a/src/third_party/skia/tools/gpu/mock/MockTestContext.h b/src/third_party/skia/tools/gpu/mock/MockTestContext.h
index 4aac248..aae7fad 100644
--- a/src/third_party/skia/tools/gpu/mock/MockTestContext.h
+++ b/src/third_party/skia/tools/gpu/mock/MockTestContext.h
@@ -8,12 +8,12 @@
 #ifndef MockTestContext_DEFINED
 #define MockTestContext_DEFINED
 
-#include "TestContext.h"
+#include "tools/gpu/TestContext.h"
 
 namespace sk_gpu_test {
 
 /**
- * Creates mock context object for use with GrContexts created with kMock_GrBackend. It will
+ * Creates mock context object for use with GrContexts created with GrBackendApi::kMock. It will
  * trivially succeed at everything.
  */
 TestContext* CreateMockTestContext(TestContext* shareContext = nullptr);
diff --git a/src/third_party/skia/tools/gpu/mtl/MtlTestContext.h b/src/third_party/skia/tools/gpu/mtl/MtlTestContext.h
index f703238..dbda09d 100644
--- a/src/third_party/skia/tools/gpu/mtl/MtlTestContext.h
+++ b/src/third_party/skia/tools/gpu/mtl/MtlTestContext.h
@@ -8,15 +8,29 @@
 #ifndef MtlTestContext_h
 #define MtlTestContext_h
 
-#include "TestContext.h"
+#include "tools/gpu/TestContext.h"
 
 #ifdef SK_METAL
 
 namespace sk_gpu_test {
-TestContext* CreatePlatformMtlTestContext(TestContext*);
+class MtlTestContext : public TestContext {
+public:
+    GrBackendApi backend() override { return GrBackendApi::kMetal; }
+
+protected:
+    MtlTestContext() {}
+
+private:
+    typedef TestContext INHERITED;
+};
+
+/**
+ * Creates Metal context object bound to the native Metal library.
+ */
+MtlTestContext* CreatePlatformMtlTestContext(MtlTestContext*);
+
 }  // namespace sk_gpu_test
 
 #endif
 
-
 #endif /* MtlTestContext_h */
diff --git a/src/third_party/skia/tools/gpu/mtl/MtlTestContext.mm b/src/third_party/skia/tools/gpu/mtl/MtlTestContext.mm
index 4014e2b..367051f 100644
--- a/src/third_party/skia/tools/gpu/mtl/MtlTestContext.mm
+++ b/src/third_party/skia/tools/gpu/mtl/MtlTestContext.mm
@@ -5,160 +5,127 @@
  * found in the LICENSE file.
  */
 
-#include "MtlTestContext.h"
+#include "tools/gpu/mtl/MtlTestContext.h"
 
-#include "GrContext.h"
-#include "GrContextOptions.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/GrContextOptions.h"
 
-#import <Metal/Metal.h>
+#include "src/gpu/mtl/GrMtlUtil.h"
 
 #ifdef SK_METAL
 
+#import <Metal/Metal.h>
+
 namespace {
 /**
  * Implements sk_gpu_test::FenceSync for Metal.
+ *
+ * Fences as MTLSharedEvents are not supported across all Metal platforms, so we do
+ * the next best thing and submit an empty MTLCommandBuffer and track when it's complete.
  */
-
-// TODO
-#if 0
 class MtlFenceSync : public sk_gpu_test::FenceSync {
 public:
-    MtlFenceSync(sk_sp<const GrVkInterface> vk, VkDevice device, VkQueue queue,
-                uint32_t queueFamilyIndex)
-            : fVk(std::move(vk))
-            , fDevice(device)
-            , fQueue(queue) {
+    MtlFenceSync(id<MTLCommandQueue> queue)
+            : fQueue(queue) {
         SkDEBUGCODE(fUnfinishedSyncs = 0;)
-        VkCommandPoolCreateInfo createInfo;
-        createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
-        createInfo.pNext = nullptr;
-        createInfo.flags = 0;
-        createInfo.queueFamilyIndex = queueFamilyIndex;
-        GR_VK_CALL_ERRCHECK(fVk, CreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool));
-
-        VkCommandBufferAllocateInfo allocateInfo;
-        allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-        allocateInfo.pNext = nullptr;
-        allocateInfo.commandBufferCount = 1;
-        allocateInfo.commandPool = fCommandPool;
-        allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-        GR_VK_CALL_ERRCHECK(fVk, AllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer));
-
-        VkCommandBufferBeginInfo beginInfo;
-        beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-        beginInfo.pNext = nullptr;
-        beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
-        beginInfo.pInheritanceInfo = nullptr;
-        GR_VK_CALL_ERRCHECK(fVk, BeginCommandBuffer(fCommandBuffer, &beginInfo));
-        GR_VK_CALL_ERRCHECK(fVk, EndCommandBuffer(fCommandBuffer));
     }
 
-    ~VkFenceSync() override {
+    ~MtlFenceSync() override {
         SkASSERT(!fUnfinishedSyncs);
-        // If the above assertion is true then the command buffer should not be in flight.
-        GR_VK_CALL(fVk, FreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer));
-        GR_VK_CALL(fVk, DestroyCommandPool(fDevice, fCommandPool, nullptr));
     }
 
     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
-        VkFence fence;
-        VkFenceCreateInfo info;
-        info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-        info.pNext = nullptr;
-        info.flags = 0;
-        GR_VK_CALL_ERRCHECK(fVk, CreateFence(fDevice, &info, nullptr, &fence));
-        VkSubmitInfo submitInfo;
-        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-        submitInfo.pNext = nullptr;
-        submitInfo.waitSemaphoreCount = 0;
-        submitInfo.pWaitSemaphores = nullptr;
-        submitInfo.pWaitDstStageMask = nullptr;
-        submitInfo.commandBufferCount = 1;
-        submitInfo.pCommandBuffers = &fCommandBuffer;
-        submitInfo.signalSemaphoreCount = 0;
-        submitInfo.pSignalSemaphores = nullptr;
-        GR_VK_CALL_ERRCHECK(fVk, QueueSubmit(fQueue, 1, &submitInfo, fence));
+        id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer];
+        cmdBuffer.label = @"Fence";
+        [cmdBuffer commit];
+
         SkDEBUGCODE(++fUnfinishedSyncs;)
-        return (sk_gpu_test::PlatformFence)fence;
+
+        void* cfCmdBuffer = (__bridge_retained void*)cmdBuffer;
+        return (sk_gpu_test::PlatformFence)cfCmdBuffer;
     }
 
     bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
-        VkFence fence = (VkFence)opaqueFence;
-        static constexpr uint64_t kForever = ~((uint64_t)0);
-        auto result = GR_VK_CALL(fVk, WaitForFences(fDevice, 1, &fence, true, kForever));
-        return result != VK_TIMEOUT;
+        void* cfCmdBuffer = (void*) opaqueFence;
+        id<MTLCommandBuffer> cmdBuffer = (__bridge id<MTLCommandBuffer>) cfCmdBuffer;
+
+        [cmdBuffer waitUntilCompleted];
+
+        return (MTLCommandBufferStatusError != cmdBuffer.status);
     }
 
     void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
-        VkFence fence = (VkFence)opaqueFence;
-        GR_VK_CALL(fVk, DestroyFence(fDevice, fence, nullptr));
+        CFRelease((void*) opaqueFence);
         SkDEBUGCODE(--fUnfinishedSyncs;)
     }
 
 private:
-    sk_sp<const GrVkInterface>  fVk;
-    VkDevice                    fDevice;
-    VkQueue                     fQueue;
-    VkCommandPool               fCommandPool;
-    VkCommandBuffer             fCommandBuffer;
+    id<MTLCommandQueue>         fQueue;
     SkDEBUGCODE(mutable int     fUnfinishedSyncs;)
     typedef sk_gpu_test::FenceSync INHERITED;
 };
 
-GR_STATIC_ASSERT(sizeof(VkFence) <= sizeof(sk_gpu_test::PlatformFence));
-#endif
+GR_STATIC_ASSERT(sizeof(uint64_t) <= sizeof(sk_gpu_test::PlatformFence));
 
-class MtlTestContext : public sk_gpu_test::TestContext {
+class MtlTestContextImpl : public sk_gpu_test::MtlTestContext {
 public:
-    static MtlTestContext* Create(TestContext* sharedContext) {
-        SkASSERT(!sharedContext);
-        id<MTLDevice> device = MTLCreateSystemDefaultDevice();
-        id<MTLCommandQueue> queue = [device newCommandQueue];
+    static MtlTestContext* Create(MtlTestContext* sharedContext) {
+        id<MTLDevice> device;
+        id<MTLCommandQueue> queue;
+        if (sharedContext) {
+            MtlTestContextImpl* sharedContextImpl = (MtlTestContextImpl*) sharedContext;
+            device = sharedContextImpl->device();
+            queue = sharedContextImpl->queue();
+        } else {
+            device = MTLCreateSystemDefaultDevice();
+            queue = [device newCommandQueue];
+        }
 
-        return new MtlTestContext(device, queue);
+        return new MtlTestContextImpl(device, queue);
     }
 
-    ~MtlTestContext() override { this->teardown(); }
-
-    GrBackend backend() override { return kMetal_GrBackend; }
-
-    GrBackendContext backendContext() override { return 0; }
+    ~MtlTestContextImpl() override { this->teardown(); }
 
     void testAbandon() override {}
 
-    // There is really nothing to here since we don't own any unqueued command buffers here.
+    // There is really nothing to do here since we don't own any unqueued command buffers here.
     void submit() override {}
 
     void finish() override {}
 
     sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
-        return GrContext::MakeMetal((__bridge_retained void*)fDevice,
-                                    (__bridge_retained void*)fQueue,
+        return GrContext::MakeMetal((__bridge void*)fDevice,
+                                    (__bridge void*)fQueue,
                                     options);
     }
 
+    id<MTLDevice> device() { return fDevice; }
+    id<MTLCommandQueue> queue() { return fQueue; }
+
 private:
-    MtlTestContext(id<MTLDevice> device, id<MTLCommandQueue> queue)
-            : fDevice(device), fQueue(queue) {
-        fFenceSync.reset(nullptr);
+    MtlTestContextImpl(id<MTLDevice> device, id<MTLCommandQueue> queue)
+            : INHERITED(), fDevice(device), fQueue(queue) {
+        fFenceSync.reset(new MtlFenceSync(queue));
     }
 
     void onPlatformMakeCurrent() const override {}
+    std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
     void onPlatformSwapBuffers() const override {}
 
-    id<MTLDevice> fDevice;
+    id<MTLDevice>        fDevice;
     id<MTLCommandQueue>  fQueue;
 
-    typedef sk_gpu_test::TestContext INHERITED;
+    typedef sk_gpu_test::MtlTestContext INHERITED;
 };
 
 }  // anonymous namespace
 
 namespace sk_gpu_test {
 
-TestContext* CreatePlatformMtlTestContext(TestContext* sharedContext) {
-    return MtlTestContext::Create(sharedContext);
+MtlTestContext* CreatePlatformMtlTestContext(MtlTestContext* sharedContext) {
+    return MtlTestContextImpl::Create(sharedContext);
 }
+
 }  // namespace sk_gpu_test
 
 
diff --git a/src/third_party/skia/tools/gpu/vk/GrVulkanDefines.h b/src/third_party/skia/tools/gpu/vk/GrVulkanDefines.h
new file mode 100644
index 0000000..ad65a84
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/vk/GrVulkanDefines.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVulkanDefines_DEFINED
+#define GrVulkanDefines_DEFINED
+
+#include "include/core/SkTypes.h"
+
+#if defined(SK_BUILD_FOR_WIN)
+#   if !defined(VK_USE_PLATFORM_WIN32_KHR)
+#      define VK_USE_PLATFORM_WIN32_KHR
+#   endif
+#elif defined(SK_BUILD_FOR_ANDROID)
+#   if !defined(VK_USE_PLATFORM_ANDROID_KHR)
+#      define VK_USE_PLATFORM_ANDROID_KHR
+#   endif
+#elif defined(SK_BUILD_FOR_UNIX)
+#   if !defined(VK_USE_PLATFORM_XCB_KHR)
+#      define VK_USE_PLATFORM_XCB_KHR
+#   endif
+#elif defined(SK_BUILD_FOR_MAC)
+#   if !defined(VK_USE_PLATFORM_MACOS_MVK)
+#      define VK_USE_PLATFORM_MACOS_MVK
+#   endif
+#elif defined(SK_BUILD_FOR_IOS)
+#   if !defined(VK_USE_PLATFORM_IOS_MVK)
+#      define VK_USE_PLATFORM_IOS_MVK
+#   endif
+#endif
+
+// We create our own function table and never directly call any functions via vk*(). So no
+// need to include the prototype functions. We do them for molten vk however.
+#if !defined(SK_MOLTENVK) && !defined(VK_NO_PROTOTYPES)
+    #define VK_NO_PROTOTYPES
+#endif
+
+#include <vulkan/vulkan.h> // IWYU pragma: export
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/vk/VkTestContext.cpp b/src/third_party/skia/tools/gpu/vk/VkTestContext.cpp
index 125ead2..6215efe 100644
--- a/src/third_party/skia/tools/gpu/vk/VkTestContext.cpp
+++ b/src/third_party/skia/tools/gpu/vk/VkTestContext.cpp
@@ -5,15 +5,20 @@
  * found in the LICENSE file.
  */
 
-#include "VkTestContext.h"
+#include "tools/gpu/vk/VkTestContext.h"
 
 #ifdef SK_VULKAN
 
-#include "vk/GrVkInterface.h"
-#include "vk/GrVkUtil.h"
-#include <vulkan/vulkan.h>
+#include "include/gpu/GrContext.h"
+#include "include/gpu/vk/GrVkExtensions.h"
+#include "tools/gpu/vk/VkTestUtils.h"
 
 namespace {
+
+#define ACQUIRE_VK_PROC(name, device)                                               \
+    f##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, nullptr, device)); \
+    SkASSERT(f##name)
+
 /**
  * Implements sk_gpu_test::FenceSync for Vulkan. It creates a single command
  * buffer with USAGE_SIMULTANEOUS with no content . On every insertFence request
@@ -21,18 +26,30 @@
  */
 class VkFenceSync : public sk_gpu_test::FenceSync {
 public:
-    VkFenceSync(sk_sp<const GrVkInterface> vk, VkDevice device, VkQueue queue,
+    VkFenceSync(GrVkGetProc getProc, VkDevice device, VkQueue queue,
                 uint32_t queueFamilyIndex)
-            : fVk(std::move(vk))
-            , fDevice(device)
+            : fDevice(device)
             , fQueue(queue) {
+        ACQUIRE_VK_PROC(CreateCommandPool, device);
+        ACQUIRE_VK_PROC(DestroyCommandPool, device);
+        ACQUIRE_VK_PROC(AllocateCommandBuffers, device);
+        ACQUIRE_VK_PROC(FreeCommandBuffers, device);
+        ACQUIRE_VK_PROC(BeginCommandBuffer, device);
+        ACQUIRE_VK_PROC(EndCommandBuffer, device);
+        ACQUIRE_VK_PROC(CreateFence, device);
+        ACQUIRE_VK_PROC(DestroyFence, device);
+        ACQUIRE_VK_PROC(WaitForFences, device);
+        ACQUIRE_VK_PROC(QueueSubmit, device);
+
+        VkResult result;
         SkDEBUGCODE(fUnfinishedSyncs = 0;)
         VkCommandPoolCreateInfo createInfo;
         createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
         createInfo.pNext = nullptr;
         createInfo.flags = 0;
         createInfo.queueFamilyIndex = queueFamilyIndex;
-        GR_VK_CALL_ERRCHECK(fVk, CreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool));
+        result = fCreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool);
+        SkASSERT(VK_SUCCESS == result);
 
         VkCommandBufferAllocateInfo allocateInfo;
         allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -40,31 +57,39 @@
         allocateInfo.commandBufferCount = 1;
         allocateInfo.commandPool = fCommandPool;
         allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-        GR_VK_CALL_ERRCHECK(fVk, AllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer));
+        result = fAllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer);
+        SkASSERT(VK_SUCCESS == result);
 
         VkCommandBufferBeginInfo beginInfo;
         beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
         beginInfo.pNext = nullptr;
         beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
         beginInfo.pInheritanceInfo = nullptr;
-        GR_VK_CALL_ERRCHECK(fVk, BeginCommandBuffer(fCommandBuffer, &beginInfo));
-        GR_VK_CALL_ERRCHECK(fVk, EndCommandBuffer(fCommandBuffer));
+        result = fBeginCommandBuffer(fCommandBuffer, &beginInfo);
+        SkASSERT(VK_SUCCESS == result);
+        result = fEndCommandBuffer(fCommandBuffer);
+        SkASSERT(VK_SUCCESS == result);
+
     }
 
     ~VkFenceSync() override {
         SkASSERT(!fUnfinishedSyncs);
         // If the above assertion is true then the command buffer should not be in flight.
-        GR_VK_CALL(fVk, FreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer));
-        GR_VK_CALL(fVk, DestroyCommandPool(fDevice, fCommandPool, nullptr));
+        fFreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer);
+        fDestroyCommandPool(fDevice, fCommandPool, nullptr);
     }
 
     sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
+        VkResult result;
+
         VkFence fence;
         VkFenceCreateInfo info;
         info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
         info.pNext = nullptr;
         info.flags = 0;
-        GR_VK_CALL_ERRCHECK(fVk, CreateFence(fDevice, &info, nullptr, &fence));
+        result = fCreateFence(fDevice, &info, nullptr, &fence);
+        SkASSERT(VK_SUCCESS == result);
+
         VkSubmitInfo submitInfo;
         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
         submitInfo.pNext = nullptr;
@@ -75,7 +100,9 @@
         submitInfo.pCommandBuffers = &fCommandBuffer;
         submitInfo.signalSemaphoreCount = 0;
         submitInfo.pSignalSemaphores = nullptr;
-        GR_VK_CALL_ERRCHECK(fVk, QueueSubmit(fQueue, 1, &submitInfo, fence));
+        result = fQueueSubmit(fQueue, 1, &submitInfo, fence);
+        SkASSERT(VK_SUCCESS == result);
+
         SkDEBUGCODE(++fUnfinishedSyncs;)
         return (sk_gpu_test::PlatformFence)fence;
     }
@@ -83,22 +110,33 @@
     bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
         VkFence fence = (VkFence)opaqueFence;
         static constexpr uint64_t kForever = ~((uint64_t)0);
-        auto result = GR_VK_CALL(fVk, WaitForFences(fDevice, 1, &fence, true, kForever));
+        auto result = fWaitForFences(fDevice, 1, &fence, true, kForever);
         return result != VK_TIMEOUT;
     }
 
     void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
         VkFence fence = (VkFence)opaqueFence;
-        GR_VK_CALL(fVk, DestroyFence(fDevice, fence, nullptr));
+        fDestroyFence(fDevice, fence, nullptr);
         SkDEBUGCODE(--fUnfinishedSyncs;)
     }
 
 private:
-    sk_sp<const GrVkInterface>  fVk;
     VkDevice                    fDevice;
     VkQueue                     fQueue;
     VkCommandPool               fCommandPool;
     VkCommandBuffer             fCommandBuffer;
+
+    PFN_vkCreateCommandPool fCreateCommandPool = nullptr;
+    PFN_vkDestroyCommandPool fDestroyCommandPool = nullptr;
+    PFN_vkAllocateCommandBuffers fAllocateCommandBuffers = nullptr;
+    PFN_vkFreeCommandBuffers fFreeCommandBuffers = nullptr;
+    PFN_vkBeginCommandBuffer fBeginCommandBuffer = nullptr;
+    PFN_vkEndCommandBuffer fEndCommandBuffer = nullptr;
+    PFN_vkCreateFence fCreateFence = nullptr;
+    PFN_vkDestroyFence fDestroyFence = nullptr;
+    PFN_vkWaitForFences fWaitForFences = nullptr;
+    PFN_vkQueueSubmit fQueueSubmit = nullptr;
+
     SkDEBUGCODE(mutable int     fUnfinishedSyncs;)
     typedef sk_gpu_test::FenceSync INHERITED;
 };
@@ -109,17 +147,49 @@
 class VkTestContextImpl : public sk_gpu_test::VkTestContext {
 public:
     static VkTestContext* Create(VkTestContext* sharedContext) {
-        sk_sp<const GrVkBackendContext> backendContext;
+        GrVkBackendContext backendContext;
+        GrVkExtensions* extensions;
+        VkPhysicalDeviceFeatures2* features;
+        bool ownsContext = true;
+        VkDebugReportCallbackEXT debugCallback = VK_NULL_HANDLE;
+        PFN_vkDestroyDebugReportCallbackEXT destroyCallback = nullptr;
         if (sharedContext) {
             backendContext = sharedContext->getVkBackendContext();
+            extensions = const_cast<GrVkExtensions*>(sharedContext->getVkExtensions());
+            features = const_cast<VkPhysicalDeviceFeatures2*>(sharedContext->getVkFeatures());
+            // We always delete the parent context last so make sure the child does not think they
+            // own the vulkan context.
+            ownsContext = false;
         } else {
-            backendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr,
-                                                            vkGetDeviceProcAddr));
+            PFN_vkGetInstanceProcAddr instProc;
+            PFN_vkGetDeviceProcAddr devProc;
+            if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
+                return nullptr;
+            }
+            auto getProc = [instProc, devProc](const char* proc_name,
+                                               VkInstance instance, VkDevice device) {
+                if (device != VK_NULL_HANDLE) {
+                    return devProc(device, proc_name);
+                }
+                return instProc(instance, proc_name);
+            };
+            extensions = new GrVkExtensions();
+            features = new VkPhysicalDeviceFeatures2;
+            memset(features, 0, sizeof(VkPhysicalDeviceFeatures2));
+            if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, extensions,
+                                                     features, &debugCallback)) {
+                sk_gpu_test::FreeVulkanFeaturesStructs(features);
+                delete features;
+                delete extensions;
+                return nullptr;
+            }
+            if (debugCallback != VK_NULL_HANDLE) {
+                destroyCallback = (PFN_vkDestroyDebugReportCallbackEXT) instProc(
+                        backendContext.fInstance, "vkDestroyDebugReportCallbackEXT");
+            }
         }
-        if (!backendContext) {
-            return nullptr;
-        }
-        return new VkTestContextImpl(std::move(backendContext));
+        return new VkTestContextImpl(backendContext, extensions, features, ownsContext,
+                                     debugCallback, destroyCallback);
     }
 
     ~VkTestContextImpl() override { this->teardown(); }
@@ -131,20 +201,56 @@
 
     void finish() override {}
 
+    sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
+        return GrContext::MakeVulkan(fVk, options);
+    }
+
 protected:
+#define ACQUIRE_VK_PROC_LOCAL(name, inst)                                            \
+    PFN_vk##name grVk##name =                                                        \
+            reinterpret_cast<PFN_vk##name>(fVk.fGetProc("vk" #name, inst, nullptr)); \
+    do {                                                                             \
+        if (grVk##name == nullptr) {                                                 \
+            SkDebugf("Function ptr for vk%s could not be acquired\n", #name);        \
+            return;                                                                  \
+        }                                                                            \
+    } while (0)
+
     void teardown() override {
         INHERITED::teardown();
-        fVk.reset(nullptr);
+        fVk.fMemoryAllocator.reset();
+        if (fOwnsContext) {
+            ACQUIRE_VK_PROC_LOCAL(DeviceWaitIdle, fVk.fInstance);
+            ACQUIRE_VK_PROC_LOCAL(DestroyDevice, fVk.fInstance);
+            ACQUIRE_VK_PROC_LOCAL(DestroyInstance, fVk.fInstance);
+            grVkDeviceWaitIdle(fVk.fDevice);
+            grVkDestroyDevice(fVk.fDevice, nullptr);
+#ifdef SK_ENABLE_VK_LAYERS
+            if (fDebugCallback != VK_NULL_HANDLE) {
+                fDestroyDebugReportCallbackEXT(fVk.fInstance, fDebugCallback, nullptr);
+            }
+#endif
+            grVkDestroyInstance(fVk.fInstance, nullptr);
+            delete fExtensions;
+
+            sk_gpu_test::FreeVulkanFeaturesStructs(fFeatures);
+            delete fFeatures;
+        }
     }
 
 private:
-    VkTestContextImpl(sk_sp<const GrVkBackendContext> backendContext)
-            : VkTestContext(std::move(backendContext)) {
-        fFenceSync.reset(new VkFenceSync(fVk->fInterface, fVk->fDevice, fVk->fQueue,
-                                         fVk->fGraphicsQueueIndex));
+    VkTestContextImpl(const GrVkBackendContext& backendContext, const GrVkExtensions* extensions,
+                      VkPhysicalDeviceFeatures2* features, bool ownsContext,
+                      VkDebugReportCallbackEXT debugCallback,
+                      PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
+            : VkTestContext(backendContext, extensions, features, ownsContext, debugCallback,
+                            destroyCallback) {
+        fFenceSync.reset(new VkFenceSync(fVk.fGetProc, fVk.fDevice, fVk.fQueue,
+                                         fVk.fGraphicsQueueIndex));
     }
 
     void onPlatformMakeCurrent() const override {}
+    std::function<void()> onPlatformGetAutoContextRestore() const override  { return nullptr; }
     void onPlatformSwapBuffers() const override {}
 
     typedef sk_gpu_test::VkTestContext INHERITED;
diff --git a/src/third_party/skia/tools/gpu/vk/VkTestContext.h b/src/third_party/skia/tools/gpu/vk/VkTestContext.h
index 5090f55..fd4d8d2 100644
--- a/src/third_party/skia/tools/gpu/vk/VkTestContext.h
+++ b/src/third_party/skia/tools/gpu/vk/VkTestContext.h
@@ -8,30 +8,50 @@
 #ifndef VkTestContext_DEFINED
 #define VkTestContext_DEFINED
 
-#include "TestContext.h"
+#include "tools/gpu/TestContext.h"
 
 #ifdef SK_VULKAN
 
-#include "vk/GrVkBackendContext.h"
+#include "include/gpu/vk/GrVkBackendContext.h"
+#include "tools/gpu/vk/GrVulkanDefines.h"
+
+class GrVkExtensions;
 
 namespace sk_gpu_test {
 class VkTestContext : public TestContext {
 public:
-    virtual GrBackend backend() override { return kVulkan_GrBackend; }
-    virtual GrBackendContext backendContext() override {
-        return reinterpret_cast<GrBackendContext>(fVk.get());
-    }
+    virtual GrBackendApi backend() override { return GrBackendApi::kVulkan; }
 
-    sk_sp<const GrVkBackendContext> getVkBackendContext() {
+    const GrVkBackendContext& getVkBackendContext() const {
         return fVk;
     }
 
-    const GrVkInterface* vk() const { return fVk->fInterface.get(); }
+    const GrVkExtensions* getVkExtensions() const {
+        return fExtensions;
+    }
+
+    const VkPhysicalDeviceFeatures2* getVkFeatures() const {
+        return fFeatures;
+    }
 
 protected:
-    VkTestContext(sk_sp<const GrVkBackendContext> vk) : fVk(std::move(vk)) {}
+    VkTestContext(const GrVkBackendContext& vk, const GrVkExtensions* extensions,
+                  const VkPhysicalDeviceFeatures2* features, bool ownsContext,
+                  VkDebugReportCallbackEXT debugCallback,
+                  PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
+            : fVk(vk)
+            , fExtensions(extensions)
+            , fFeatures(features)
+            , fOwnsContext(ownsContext)
+            , fDebugCallback(debugCallback)
+            , fDestroyDebugReportCallbackEXT(destroyCallback) {}
 
-    sk_sp<const GrVkBackendContext> fVk;
+    GrVkBackendContext                  fVk;
+    const GrVkExtensions*               fExtensions;
+    const VkPhysicalDeviceFeatures2*    fFeatures;
+    bool                                fOwnsContext;
+    VkDebugReportCallbackEXT            fDebugCallback = VK_NULL_HANDLE;
+    PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr;
 
 private:
     typedef TestContext INHERITED;
diff --git a/src/third_party/skia/tools/gpu/vk/VkTestUtils.cpp b/src/third_party/skia/tools/gpu/vk/VkTestUtils.cpp
new file mode 100644
index 0000000..5b7e8c2
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/vk/VkTestUtils.cpp
@@ -0,0 +1,775 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/gpu/vk/VkTestUtils.h"
+
+#ifdef SK_VULKAN
+
+#ifndef SK_GPU_TOOLS_VK_LIBRARY_NAME
+    #if defined _WIN32
+        #define SK_GPU_TOOLS_VK_LIBRARY_NAME "vulkan-1.dll"
+    #else
+        #define SK_GPU_TOOLS_VK_LIBRARY_NAME "libvulkan.so"
+    #endif
+#endif
+
+#include "include/gpu/vk/GrVkBackendContext.h"
+#include "include/gpu/vk/GrVkExtensions.h"
+#include "src/core/SkAutoMalloc.h"
+#include "src/ports/SkOSLibrary.h"
+
+#if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS)
+#include <sanitizer/lsan_interface.h>
+#endif
+
+namespace sk_gpu_test {
+
+bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr* instProc,
+                                      PFN_vkGetDeviceProcAddr* devProc) {
+#ifdef SK_MOLTENVK
+    // MoltenVK is a statically linked framework, so there is no Vulkan library to load.
+    *instProc = &vkGetInstanceProcAddr;
+    *devProc = &vkGetDeviceProcAddr;
+    return true;
+#else
+    static void* vkLib = nullptr;
+    static PFN_vkGetInstanceProcAddr localInstProc = nullptr;
+    static PFN_vkGetDeviceProcAddr localDevProc = nullptr;
+    if (!vkLib) {
+        vkLib = DynamicLoadLibrary(SK_GPU_TOOLS_VK_LIBRARY_NAME);
+        if (!vkLib) {
+            return false;
+        }
+        localInstProc = (PFN_vkGetInstanceProcAddr) GetProcedureAddress(vkLib,
+                                                                        "vkGetInstanceProcAddr");
+        localDevProc = (PFN_vkGetDeviceProcAddr) GetProcedureAddress(vkLib,
+                                                                     "vkGetDeviceProcAddr");
+    }
+    if (!localInstProc || !localDevProc) {
+        return false;
+    }
+    *instProc = localInstProc;
+    *devProc = localDevProc;
+    return true;
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Helper code to set up Vulkan context objects
+
+#ifdef SK_ENABLE_VK_LAYERS
+const char* kDebugLayerNames[] = {
+    // elements of VK_LAYER_LUNARG_standard_validation
+    "VK_LAYER_GOOGLE_threading",
+    "VK_LAYER_LUNARG_parameter_validation",
+    "VK_LAYER_LUNARG_object_tracker",
+    "VK_LAYER_LUNARG_core_validation",
+    "VK_LAYER_GOOGLE_unique_objects",
+    // not included in standard_validation
+    //"VK_LAYER_LUNARG_api_dump",
+    //"VK_LAYER_LUNARG_vktrace",
+    //"VK_LAYER_LUNARG_screenshot",
+};
+
+static uint32_t remove_patch_version(uint32_t specVersion) {
+    return (specVersion >> 12) << 12;
+}
+
+// Returns the index into layers array for the layer we want. Returns -1 if not supported.
+static int should_include_debug_layer(const char* layerName,
+                                       uint32_t layerCount, VkLayerProperties* layers,
+                                       uint32_t version) {
+    for (uint32_t i = 0; i < layerCount; ++i) {
+        if (!strcmp(layerName, layers[i].layerName)) {
+            // Since the layers intercept the vulkan calls and forward them on, we need to make sure
+            // layer was written against a version that isn't older than the version of Vulkan we're
+            // using so that it has all the api entry points.
+            if (version <= remove_patch_version(layers[i].specVersion)) {
+                return i;
+            }
+            return -1;
+        }
+
+    }
+    return -1;
+}
+
+VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(
+    VkDebugReportFlagsEXT       flags,
+    VkDebugReportObjectTypeEXT  objectType,
+    uint64_t                    object,
+    size_t                      location,
+    int32_t                     messageCode,
+    const char*                 pLayerPrefix,
+    const char*                 pMessage,
+    void*                       pUserData) {
+    if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
+        SkDebugf("Vulkan error [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+        return VK_TRUE; // skip further layers
+    } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
+        // There is currently a bug in the spec which doesn't have
+        // VK_STRUCTURE_TYPE_BLEND_OPERATION_ADVANCED_FEATURES_EXT as an allowable pNext struct in
+        // VkDeviceCreateInfo. So we ignore that warning since it is wrong.
+        if (!strstr(pMessage,
+                    "pCreateInfo->pNext chain includes a structure with unexpected VkStructureType "
+                    "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT")) {
+            SkDebugf("Vulkan warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+        }
+    } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
+        SkDebugf("Vulkan perf warning [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+    } else {
+        SkDebugf("Vulkan info/debug [%s]: code: %d: %s\n", pLayerPrefix, messageCode, pMessage);
+    }
+    return VK_FALSE;
+}
+#endif
+
+#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device)
+
+static bool init_instance_extensions_and_layers(GrVkGetProc getProc,
+                                                uint32_t specVersion,
+                                                SkTArray<VkExtensionProperties>* instanceExtensions,
+                                                SkTArray<VkLayerProperties>* instanceLayers) {
+    if (getProc == nullptr) {
+        return false;
+    }
+
+    GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
+
+    if (!EnumerateInstanceExtensionProperties ||
+        !EnumerateInstanceLayerProperties) {
+        return false;
+    }
+
+    VkResult res;
+    uint32_t layerCount = 0;
+#ifdef SK_ENABLE_VK_LAYERS
+    // instance layers
+    res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkLayerProperties* layers = new VkLayerProperties[layerCount];
+    res = EnumerateInstanceLayerProperties(&layerCount, layers);
+    if (VK_SUCCESS != res) {
+        delete[] layers;
+        return false;
+    }
+
+    uint32_t nonPatchVersion = remove_patch_version(specVersion);
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
+        int idx = should_include_debug_layer(kDebugLayerNames[i], layerCount, layers,
+                                             nonPatchVersion);
+        if (idx != -1) {
+            instanceLayers->push_back() = layers[idx];
+        }
+    }
+    delete[] layers;
+#endif
+
+    // instance extensions
+    // via Vulkan implementation and implicitly enabled layers
+    uint32_t extensionCount = 0;
+    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return false;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        instanceExtensions->push_back() = extensions[i];
+    }
+    delete [] extensions;
+
+    // via explicitly enabled layers
+    layerCount = instanceLayers->count();
+    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
+        uint32_t extensionCount = 0;
+        res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
+                                                   &extensionCount, nullptr);
+        if (VK_SUCCESS != res) {
+            return false;
+        }
+        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+        res = EnumerateInstanceExtensionProperties((*instanceLayers)[layerIndex].layerName,
+                                                   &extensionCount, extensions);
+        if (VK_SUCCESS != res) {
+            delete[] extensions;
+            return false;
+        }
+        for (uint32_t i = 0; i < extensionCount; ++i) {
+            instanceExtensions->push_back() = extensions[i];
+        }
+        delete[] extensions;
+    }
+
+    return true;
+}
+
+static bool init_device_extensions_and_layers(GrVkGetProc getProc, uint32_t specVersion,
+                                              VkInstance inst, VkPhysicalDevice physDev,
+                                              SkTArray<VkExtensionProperties>* deviceExtensions,
+                                              SkTArray<VkLayerProperties>* deviceLayers) {
+    if (getProc == nullptr) {
+        return false;
+    }
+
+    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
+    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
+
+    if (!EnumerateDeviceExtensionProperties ||
+        !EnumerateDeviceLayerProperties) {
+        return false;
+    }
+
+    VkResult res;
+    // device layers
+    uint32_t layerCount = 0;
+#ifdef SK_ENABLE_VK_LAYERS
+    res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkLayerProperties* layers = new VkLayerProperties[layerCount];
+    res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
+    if (VK_SUCCESS != res) {
+        delete[] layers;
+        return false;
+    }
+
+    uint32_t nonPatchVersion = remove_patch_version(specVersion);
+    for (size_t i = 0; i < SK_ARRAY_COUNT(kDebugLayerNames); ++i) {
+        int idx = should_include_debug_layer(kDebugLayerNames[i], layerCount, layers,
+                                             nonPatchVersion);
+        if (idx != -1) {
+            deviceLayers->push_back() = layers[idx];
+        }
+    }
+    delete[] layers;
+#endif
+
+    // device extensions
+    // via Vulkan implementation and implicitly enabled layers
+    uint32_t extensionCount = 0;
+    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
+    if (VK_SUCCESS != res) {
+        delete[] extensions;
+        return false;
+    }
+    for (uint32_t i = 0; i < extensionCount; ++i) {
+        deviceExtensions->push_back() = extensions[i];
+    }
+    delete[] extensions;
+
+    // via explicitly enabled layers
+    layerCount = deviceLayers->count();
+    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
+        uint32_t extensionCount = 0;
+        res = EnumerateDeviceExtensionProperties(physDev,
+            (*deviceLayers)[layerIndex].layerName,
+            &extensionCount, nullptr);
+        if (VK_SUCCESS != res) {
+            return false;
+        }
+        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
+        res = EnumerateDeviceExtensionProperties(physDev,
+            (*deviceLayers)[layerIndex].layerName,
+            &extensionCount, extensions);
+        if (VK_SUCCESS != res) {
+            delete[] extensions;
+            return false;
+        }
+        for (uint32_t i = 0; i < extensionCount; ++i) {
+            deviceExtensions->push_back() = extensions[i];
+        }
+        delete[] extensions;
+    }
+
+    return true;
+}
+
+#define ACQUIRE_VK_PROC_NOCHECK(name, instance, device) \
+    PFN_vk##name grVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device))
+
+#define ACQUIRE_VK_PROC(name, instance, device)                                    \
+    PFN_vk##name grVk##name =                                                      \
+            reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
+    do {                                                                           \
+        if (grVk##name == nullptr) {                                               \
+            SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
+            if (device != VK_NULL_HANDLE) {                                        \
+                destroy_instance(getProc, inst, debugCallback, hasDebugExtension); \
+            }                                                                      \
+            return false;                                                          \
+        }                                                                          \
+    } while (0)
+
+#define ACQUIRE_VK_PROC_LOCAL(name, instance, device)                              \
+    PFN_vk##name grVk##name =                                                      \
+            reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
+    do {                                                                           \
+        if (grVk##name == nullptr) {                                               \
+            SkDebugf("Function ptr for vk%s could not be acquired\n", #name);      \
+            return false;                                                                \
+        }                                                                          \
+    } while (0)
+
+static bool destroy_instance(GrVkGetProc getProc, VkInstance inst,
+                             VkDebugReportCallbackEXT* debugCallback,
+                             bool hasDebugExtension) {
+    if (hasDebugExtension && *debugCallback != VK_NULL_HANDLE) {
+        ACQUIRE_VK_PROC_LOCAL(DestroyDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
+        grVkDestroyDebugReportCallbackEXT(inst, *debugCallback, nullptr);
+        *debugCallback = VK_NULL_HANDLE;
+    }
+    ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE);
+    grVkDestroyInstance(inst, nullptr);
+    return true;
+}
+
+static bool setup_features(GrVkGetProc getProc, VkInstance inst, VkPhysicalDevice physDev,
+                           uint32_t physDeviceVersion, GrVkExtensions* extensions,
+                           VkPhysicalDeviceFeatures2* features, bool isProtected) {
+    SkASSERT(physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
+             extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1));
+
+    // Setup all extension feature structs we may want to use.
+    void** tailPNext = &features->pNext;
+
+    // If |isProtected| is given, attach that first
+    VkPhysicalDeviceProtectedMemoryFeatures* protectedMemoryFeatures = nullptr;
+    if (isProtected) {
+        SkASSERT(physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0));
+        protectedMemoryFeatures =
+          (VkPhysicalDeviceProtectedMemoryFeatures*)sk_malloc_throw(
+              sizeof(VkPhysicalDeviceProtectedMemoryFeatures));
+        protectedMemoryFeatures->sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+        protectedMemoryFeatures->pNext = nullptr;
+        *tailPNext = protectedMemoryFeatures;
+        tailPNext = &protectedMemoryFeatures->pNext;
+    }
+
+    VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT* blend = nullptr;
+    if (extensions->hasExtension(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, 2)) {
+        blend = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*) sk_malloc_throw(
+                sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT));
+        blend->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT;
+        blend->pNext = nullptr;
+        *tailPNext = blend;
+        tailPNext = &blend->pNext;
+    }
+
+    VkPhysicalDeviceSamplerYcbcrConversionFeatures* ycbcrFeature = nullptr;
+    if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
+        extensions->hasExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1)) {
+        ycbcrFeature = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*) sk_malloc_throw(
+                sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
+        ycbcrFeature->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+        ycbcrFeature->pNext = nullptr;
+        ycbcrFeature->samplerYcbcrConversion = VK_TRUE;
+        *tailPNext = ycbcrFeature;
+        tailPNext = &ycbcrFeature->pNext;
+    }
+
+    if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+        ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2, inst, VK_NULL_HANDLE);
+        grVkGetPhysicalDeviceFeatures2(physDev, features);
+    } else {
+        SkASSERT(extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+                                          1));
+        ACQUIRE_VK_PROC_LOCAL(GetPhysicalDeviceFeatures2KHR, inst, VK_NULL_HANDLE);
+        grVkGetPhysicalDeviceFeatures2KHR(physDev, features);
+    }
+
+    if (isProtected) {
+        if (!protectedMemoryFeatures->protectedMemory) {
+            return false;
+        }
+    }
+    return true;
+    // If we want to disable any extension features do so here.
+}
+
+bool CreateVkBackendContext(GrVkGetProc getProc,
+                            GrVkBackendContext* ctx,
+                            GrVkExtensions* extensions,
+                            VkPhysicalDeviceFeatures2* features,
+                            VkDebugReportCallbackEXT* debugCallback,
+                            uint32_t* presentQueueIndexPtr,
+                            CanPresentFn canPresent,
+                            bool isProtected) {
+    VkResult err;
+
+    ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    uint32_t instanceVersion = 0;
+    if (!grVkEnumerateInstanceVersion) {
+        instanceVersion = VK_MAKE_VERSION(1, 0, 0);
+    } else {
+        err = grVkEnumerateInstanceVersion(&instanceVersion);
+        if (err) {
+            SkDebugf("failed to enumerate instance version. Err: %d\n", err);
+            return false;
+        }
+    }
+    SkASSERT(instanceVersion >= VK_MAKE_VERSION(1, 0, 0));
+    if (isProtected && instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
+        SkDebugf("protected requires vk instance version 1.1\n");
+        return false;
+    }
+
+    uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0);
+    if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+        // If the instance version is 1.0 we must have the apiVersion also be 1.0. However, if the
+        // instance version is 1.1 or higher, we can set the apiVersion to be whatever the highest
+        // api we may use in skia (technically it can be arbitrary). So for now we set it to 1.1
+        // since that is the highest vulkan version.
+        apiVersion = VK_MAKE_VERSION(1, 1, 0);
+    }
+
+    instanceVersion = SkTMin(instanceVersion, apiVersion);
+
+    VkPhysicalDevice physDev;
+    VkDevice device;
+    VkInstance inst;
+
+    const VkApplicationInfo app_info = {
+        VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
+        nullptr,                            // pNext
+        "vktest",                           // pApplicationName
+        0,                                  // applicationVersion
+        "vktest",                           // pEngineName
+        0,                                  // engineVerison
+        apiVersion,                         // apiVersion
+    };
+
+    SkTArray<VkLayerProperties> instanceLayers;
+    SkTArray<VkExtensionProperties> instanceExtensions;
+
+    if (!init_instance_extensions_and_layers(getProc, instanceVersion,
+                                             &instanceExtensions,
+                                             &instanceLayers)) {
+        return false;
+    }
+
+    SkTArray<const char*> instanceLayerNames;
+    SkTArray<const char*> instanceExtensionNames;
+    for (int i = 0; i < instanceLayers.count(); ++i) {
+        instanceLayerNames.push_back(instanceLayers[i].layerName);
+    }
+    for (int i = 0; i < instanceExtensions.count(); ++i) {
+        if (strncmp(instanceExtensions[i].extensionName, "VK_KHX", 6)) {
+            instanceExtensionNames.push_back(instanceExtensions[i].extensionName);
+        }
+    }
+
+    const VkInstanceCreateInfo instance_create = {
+        VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,    // sType
+        nullptr,                                   // pNext
+        0,                                         // flags
+        &app_info,                                 // pApplicationInfo
+        (uint32_t) instanceLayerNames.count(),     // enabledLayerNameCount
+        instanceLayerNames.begin(),                // ppEnabledLayerNames
+        (uint32_t) instanceExtensionNames.count(), // enabledExtensionNameCount
+        instanceExtensionNames.begin(),            // ppEnabledExtensionNames
+    };
+
+    bool hasDebugExtension = false;
+
+    ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE, VK_NULL_HANDLE);
+    err = grVkCreateInstance(&instance_create, nullptr, &inst);
+    if (err < 0) {
+        SkDebugf("vkCreateInstance failed: %d\n", err);
+        return false;
+    }
+
+#ifdef SK_ENABLE_VK_LAYERS
+    *debugCallback = VK_NULL_HANDLE;
+    for (int i = 0; i < instanceExtensionNames.count() && !hasDebugExtension; ++i) {
+        if (!strcmp(instanceExtensionNames[i], VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
+            hasDebugExtension = true;
+        }
+    }
+    if (hasDebugExtension) {
+        // Setup callback creation information
+        VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
+        callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
+        callbackCreateInfo.pNext = nullptr;
+        callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
+                                   VK_DEBUG_REPORT_WARNING_BIT_EXT |
+                                   // VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
+                                   // VK_DEBUG_REPORT_DEBUG_BIT_EXT |
+                                   VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+        callbackCreateInfo.pfnCallback = &DebugReportCallback;
+        callbackCreateInfo.pUserData = nullptr;
+
+        ACQUIRE_VK_PROC(CreateDebugReportCallbackEXT, inst, VK_NULL_HANDLE);
+        // Register the callback
+        grVkCreateDebugReportCallbackEXT(inst, &callbackCreateInfo, nullptr, debugCallback);
+    }
+#endif
+
+    ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
+    ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
+
+    uint32_t gpuCount;
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
+    if (err) {
+        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+    if (!gpuCount) {
+        SkDebugf("vkEnumeratePhysicalDevices returned no supported devices.\n");
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+    // Just returning the first physical device instead of getting the whole array.
+    // TODO: find best match for our needs
+    gpuCount = 1;
+    err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
+    // VK_INCOMPLETE is returned when the count we provide is less than the total device count.
+    if (err && VK_INCOMPLETE != err) {
+        SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    VkPhysicalDeviceProperties physDeviceProperties;
+    grVkGetPhysicalDeviceProperties(physDev, &physDeviceProperties);
+    int physDeviceVersion = SkTMin(physDeviceProperties.apiVersion, apiVersion);
+
+    if (isProtected && physDeviceVersion < VK_MAKE_VERSION(1, 1, 0)) {
+        SkDebugf("protected requires vk physical device version 1.1\n");
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    // query to get the initial queue props size
+    uint32_t queueCount;
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
+    if (!queueCount) {
+        SkDebugf("vkGetPhysicalDeviceQueueFamilyProperties returned no queues.\n");
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
+    // now get the actual queue props
+    VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
+
+    grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
+
+    // iterate to find the graphics queue
+    uint32_t graphicsQueueIndex = queueCount;
+    for (uint32_t i = 0; i < queueCount; i++) {
+        if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            graphicsQueueIndex = i;
+            break;
+        }
+    }
+    if (graphicsQueueIndex == queueCount) {
+        SkDebugf("Could not find any supported graphics queues.\n");
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    // iterate to find the present queue, if needed
+    uint32_t presentQueueIndex = queueCount;
+    if (presentQueueIndexPtr && canPresent) {
+        for (uint32_t i = 0; i < queueCount; i++) {
+            if (canPresent(inst, physDev, i)) {
+                presentQueueIndex = i;
+                break;
+            }
+        }
+        if (presentQueueIndex == queueCount) {
+            SkDebugf("Could not find any supported present queues.\n");
+            destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+            return false;
+        }
+        *presentQueueIndexPtr = presentQueueIndex;
+    } else {
+        // Just setting this so we end up make a single queue for graphics since there was no
+        // request for a present queue.
+        presentQueueIndex = graphicsQueueIndex;
+    }
+
+    SkTArray<VkLayerProperties> deviceLayers;
+    SkTArray<VkExtensionProperties> deviceExtensions;
+    if (!init_device_extensions_and_layers(getProc, physDeviceVersion,
+                                           inst, physDev,
+                                           &deviceExtensions,
+                                           &deviceLayers)) {
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    SkTArray<const char*> deviceLayerNames;
+    SkTArray<const char*> deviceExtensionNames;
+    for (int i = 0; i < deviceLayers.count(); ++i) {
+        deviceLayerNames.push_back(deviceLayers[i].layerName);
+    }
+    for (int i = 0; i < deviceExtensions.count(); ++i) {
+        // Don't use experimental extensions since they typically don't work with debug layers and
+        // often are missing dependecy requirements for other extensions. Additionally, these are
+        // often left behind in the driver even after they've been promoted to real extensions.
+        if (strncmp(deviceExtensions[i].extensionName, "VK_KHX", 6) &&
+            strncmp(deviceExtensions[i].extensionName, "VK_NVX", 6)) {
+            deviceExtensionNames.push_back(deviceExtensions[i].extensionName);
+        }
+    }
+
+    extensions->init(getProc, inst, physDev,
+                     (uint32_t) instanceExtensionNames.count(),
+                     instanceExtensionNames.begin(),
+                     (uint32_t) deviceExtensionNames.count(),
+                     deviceExtensionNames.begin());
+
+    memset(features, 0, sizeof(VkPhysicalDeviceFeatures2));
+    features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+    features->pNext = nullptr;
+
+    VkPhysicalDeviceFeatures* deviceFeatures = &features->features;
+    void* pointerToFeatures = nullptr;
+    if (physDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
+        extensions->hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1)) {
+        if (!setup_features(getProc, inst, physDev, physDeviceVersion, extensions, features,
+                          isProtected)) {
+            destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+            return false;
+        }
+
+        // If we set the pNext of the VkDeviceCreateInfo to our VkPhysicalDeviceFeatures2 struct,
+        // the device creation will use that instead of the ppEnabledFeatures.
+        pointerToFeatures = features;
+    } else {
+        grVkGetPhysicalDeviceFeatures(physDev, deviceFeatures);
+    }
+
+    // this looks like it would slow things down,
+    // and we can't depend on it on all platforms
+    deviceFeatures->robustBufferAccess = VK_FALSE;
+
+    VkDeviceQueueCreateFlags flags = isProtected ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0;
+    float queuePriorities[1] = { 0.0 };
+    // Here we assume no need for swapchain queue
+    // If one is needed, the client will need its own setup code
+    const VkDeviceQueueCreateInfo queueInfo[2] = {
+        {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+            nullptr,                                    // pNext
+            flags,                                      // VkDeviceQueueCreateFlags
+            graphicsQueueIndex,                         // queueFamilyIndex
+            1,                                          // queueCount
+            queuePriorities,                            // pQueuePriorities
+
+        },
+        {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+            nullptr,                                    // pNext
+            0,                                          // VkDeviceQueueCreateFlags
+            presentQueueIndex,                          // queueFamilyIndex
+            1,                                          // queueCount
+            queuePriorities,                            // pQueuePriorities
+        }
+    };
+    uint32_t queueInfoCount = (presentQueueIndex != graphicsQueueIndex) ? 2 : 1;
+
+    const VkDeviceCreateInfo deviceInfo = {
+        VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,        // sType
+        pointerToFeatures,                           // pNext
+        0,                                           // VkDeviceCreateFlags
+        queueInfoCount,                              // queueCreateInfoCount
+        queueInfo,                                   // pQueueCreateInfos
+        (uint32_t) deviceLayerNames.count(),         // layerCount
+        deviceLayerNames.begin(),                    // ppEnabledLayerNames
+        (uint32_t) deviceExtensionNames.count(),     // extensionCount
+        deviceExtensionNames.begin(),                // ppEnabledExtensionNames
+        pointerToFeatures ? nullptr : deviceFeatures // ppEnabledFeatures
+    };
+
+    {
+#if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS)
+        // skia:8712
+        __lsan::ScopedDisabler lsanDisabler;
+#endif
+        err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
+    }
+    if (err) {
+        SkDebugf("CreateDevice failed: %d\n", err);
+        destroy_instance(getProc, inst, debugCallback, hasDebugExtension);
+        return false;
+    }
+
+    VkQueue queue;
+    if (isProtected) {
+        ACQUIRE_VK_PROC(GetDeviceQueue2, inst, device);
+        SkASSERT(grVkGetDeviceQueue2 != nullptr);
+        VkDeviceQueueInfo2 queue_info2 = {
+            VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2,          // sType
+            nullptr,                                        // pNext
+            VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT,           // flags
+            graphicsQueueIndex,                             // queueFamilyIndex
+            0                                               // queueIndex
+        };
+        grVkGetDeviceQueue2(device, &queue_info2, &queue);
+    } else {
+        grVkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
+    }
+
+    ctx->fInstance = inst;
+    ctx->fPhysicalDevice = physDev;
+    ctx->fDevice = device;
+    ctx->fQueue = queue;
+    ctx->fGraphicsQueueIndex = graphicsQueueIndex;
+    ctx->fMaxAPIVersion = apiVersion;
+    ctx->fVkExtensions = extensions;
+    ctx->fDeviceFeatures2 = features;
+    ctx->fGetProc = getProc;
+    ctx->fOwnsInstanceAndDevice = false;
+    ctx->fProtectedContext = isProtected ? GrProtected::kYes : GrProtected::kNo;
+
+    return true;
+}
+
+void FreeVulkanFeaturesStructs(const VkPhysicalDeviceFeatures2* features) {
+    // All Vulkan structs that could be part of the features chain will start with the
+    // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+    // so we can get access to the pNext for the next struct.
+    struct CommonVulkanHeader {
+        VkStructureType sType;
+        void*           pNext;
+    };
+
+    void* pNext = features->pNext;
+    while (pNext) {
+        void* current = pNext;
+        pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+        sk_free(current);
+    }
+}
+
+}
+
+#endif
diff --git a/src/third_party/skia/tools/gpu/vk/VkTestUtils.h b/src/third_party/skia/tools/gpu/vk/VkTestUtils.h
new file mode 100644
index 0000000..ab7281d
--- /dev/null
+++ b/src/third_party/skia/tools/gpu/vk/VkTestUtils.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef VkTestUtils_DEFINED
+#define VkTestUtils_DEFINED
+
+#include "include/core/SkTypes.h"
+
+#ifdef SK_VULKAN
+
+#include "include/gpu/vk/GrVkBackendContext.h"
+#include "include/gpu/vk/GrVkTypes.h"
+#include "tools/gpu/vk/GrVulkanDefines.h"
+#include <functional>
+
+class GrVkExtensions;
+struct GrVkBackendContext;
+
+namespace sk_gpu_test {
+    bool LoadVkLibraryAndGetProcAddrFuncs(PFN_vkGetInstanceProcAddr*, PFN_vkGetDeviceProcAddr*);
+
+    using CanPresentFn = std::function<bool(VkInstance, VkPhysicalDevice,
+                                            uint32_t queueFamilyIndex)>;
+
+    bool CreateVkBackendContext(GrVkGetProc getProc,
+                                GrVkBackendContext* ctx,
+                                GrVkExtensions*,
+                                VkPhysicalDeviceFeatures2*,
+                                VkDebugReportCallbackEXT* debugCallback,
+                                uint32_t* presentQueueIndexPtr = nullptr,
+                                CanPresentFn canPresent = CanPresentFn(),
+                                bool isProtected = false);
+
+    void FreeVulkanFeaturesStructs(const VkPhysicalDeviceFeatures2*);
+}
+
+#endif
+#endif
+
diff --git a/src/third_party/skia/tools/gpuveto.cpp b/src/third_party/skia/tools/gpuveto.cpp
deleted file mode 100644
index cc33721..0000000
--- a/src/third_party/skia/tools/gpuveto.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkCommandLineFlags.h"
-#include "SkPicture.h"
-#include "SkPictureAnalyzer.h"
-#include "SkPictureRecorder.h"
-#include "SkStream.h"
-
-DEFINE_string2(readFile, r, "", "skp file to process.");
-DEFINE_bool2(quiet, q, false, "quiet");
-
-// This tool just loads a single skp, replays into a new SkPicture (to
-// regenerate the GPU-specific tracking information) and reports
-// the value of the suitableForGpuRasterization method.
-// Return codes:
-static const int kSuccess = 0;
-static const int kError = 1;
-
-int main(int argc, char** argv) {
-#if SK_SUPPORT_GPU
-    SkCommandLineFlags::SetUsage("Reports on an skp file's suitability for GPU rasterization");
-    SkCommandLineFlags::Parse(argc, argv);
-
-    if (FLAGS_readFile.count() != 1) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Missing input file\n");
-        }
-        return kError;
-    }
-
-    SkFILEStream inputStream(FLAGS_readFile[0]);
-    if (!inputStream.isValid()) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't open file\n");
-        }
-        return kError;
-    }
-
-    sk_sp<SkPicture> picture(SkPicture::MakeFromStream(&inputStream));
-    if (nullptr == picture) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Could not read the SkPicture\n");
-        }
-        return kError;
-    }
-
-    // The SkPicture tracking information is only generated during recording
-    // an isn't serialized. Replay the picture to regenerated the tracking data.
-    SkPictureRecorder recorder;
-    picture->playback(recorder.beginRecording(picture->cullRect().width(),
-                                              picture->cullRect().height(),
-                                              nullptr, 0));
-    sk_sp<SkPicture> recorded(recorder.finishRecordingAsPicture());
-
-    if (SkPictureGpuAnalyzer(recorded).suitableForGpuRasterization(nullptr)) {
-        SkDebugf("suitable\n");
-    } else {
-        SkDebugf("unsuitable\n");
-    }
-
-    return kSuccess;
-#else
-    SkDebugf("gpuveto is only useful when GPU rendering is enabled\n");
-    return kError;
-#endif
-}
diff --git a/src/third_party/skia/tools/gyp b/src/third_party/skia/tools/gyp
deleted file mode 120000
index d871f5b..0000000
--- a/src/third_party/skia/tools/gyp
+++ /dev/null
@@ -1 +0,0 @@
-../third_party/externals/gyp/
\ No newline at end of file
diff --git a/src/third_party/skia/tools/hello-opencl.cpp b/src/third_party/skia/tools/hello-opencl.cpp
new file mode 100644
index 0000000..12b51f5
--- /dev/null
+++ b/src/third_party/skia/tools/hello-opencl.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a simple OpenCL Hello World that tests you have a functioning OpenCL setup.
+
+#include "cl.hpp"
+#include <initializer_list>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+static inline void assert_cl(cl_int rc, const char* file, int line) {
+    if (rc != CL_SUCCESS) {
+        fprintf(stderr, "%s:%d, got OpenCL error code %d\n", file,line,rc);
+        exit(1);
+    }
+}
+#define cl_ok(err) assert_cl(err, __FILE__, __LINE__)
+
+int main(int, char**) {
+    std::vector<cl::Platform> platforms;
+    cl_ok(cl::Platform::get(&platforms));
+
+    std::vector<cl::Device> devices;
+    for (cl::Platform platform : platforms) {
+        std::vector<cl::Device> platform_devices;
+        cl_ok(platform.getDevices(CL_DEVICE_TYPE_ALL, &platform_devices));
+        devices.insert(devices.end(), platform_devices.begin(), platform_devices.end());
+    }
+
+    if (devices.empty()) {
+        fprintf(stderr, "No OpenCL devices available. :(\n");
+        return 1;
+    }
+
+    // To keep things simple we'll only create single-device cl::Contexts.
+    for (cl::Device device : devices) {
+        std::string name,
+                    version,
+                    driver,
+                    vendor,
+                    extensions;
+        cl_ok(device.getInfo(CL_DEVICE_NAME,       &name));
+        cl_ok(device.getInfo(CL_DEVICE_VERSION,    &version));
+        cl_ok(device.getInfo(CL_DEVICE_VENDOR,     &vendor));
+        cl_ok(device.getInfo(CL_DEVICE_EXTENSIONS, &extensions));
+        cl_ok(device.getInfo(CL_DRIVER_VERSION,    &driver));
+
+        fprintf(stdout, "Using %s%s, vendor %s, version %s, extensions:\n%s\n",
+                version.c_str(), name.c_str(), vendor.c_str(), driver.c_str(), extensions.c_str());
+
+        std::vector<cl::Device> devices = { device };
+
+        // Some APIs can't return their cl_int error but might still fail,
+        // so they take a pointer.  cl_ok() is really handy here too.
+        cl_int ok;
+        cl::Context ctx(devices,
+                        nullptr/*optional cl_context_properties*/,
+                        nullptr/*optional error reporting callback*/,
+                        nullptr/*context argument for error reporting callback*/,
+                        &ok);
+        cl_ok(ok);
+
+        cl::Program program(ctx,
+                            "__kernel void mul(__global const float* a,    "
+                            "                  __global const float* b,    "
+                            "                  __global       float* dst) {"
+                            "    int i = get_global_id(0);                 "
+                            "    dst[i] = a[i] * b[i];                     "
+                            "}                                             ",
+                            /*and build now*/true,
+                            &ok);
+        cl_ok(ok);
+
+        std::vector<float> a,b,p;
+        for (int i = 0; i < 1000; i++) {
+            a.push_back(+i);
+            b.push_back(-i);
+            p.push_back( 0);
+        }
+
+        cl::Buffer
+            A(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*a.size(), a.data()),
+            B(ctx, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , sizeof(float)*b.size(), b.data()),
+            P(ctx, CL_MEM_WRITE_ONLY| CL_MEM_HOST_READ_ONLY, sizeof(float)*p.size());
+
+        cl::Kernel mul(program, "mul", &ok);
+        cl_ok(ok);
+        cl_ok(mul.setArg(0, A));
+        cl_ok(mul.setArg(1, B));
+        cl_ok(mul.setArg(2, P));
+
+        cl::CommandQueue queue(ctx, device);
+
+        cl_ok(queue.enqueueNDRangeKernel(mul, cl::NDRange(0)  /*offset*/
+                                            , cl::NDRange(1000) /*size*/));
+
+        cl_ok(queue.enqueueReadBuffer(P, true/*block until read is done*/
+                                       , 0                     /*offset in bytes*/
+                                       , sizeof(float)*p.size() /*size in bytes*/
+                                       , p.data()));
+
+        fprintf(stdout, "OpenCL sez: %g x %g = %g\n", a[42], b[42], p[42]);
+        for (int i = 0; i < 1000; i++) {
+            if (p[i] != a[i]*b[i]) {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
diff --git a/src/third_party/skia/tools/iOSShell.cpp b/src/third_party/skia/tools/iOSShell.cpp
deleted file mode 100644
index 02884c8..0000000
--- a/src/third_party/skia/tools/iOSShell.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "iOSShell.h"
-
-#include "Resources.h"
-#include "SkApplication.h"
-#include "SkCanvas.h"
-#include "SkCommonFlags.h"
-#include "SkGraphics.h"
-#include "SkWindow.h"
-#include "sk_tool_utils.h"
-
-//////////////////////////////////////////////////////////////////////////////
-
-static SkView* curr_view(SkWindow* wind) {
-    SkView::F2BIter iter(wind);
-    return iter.next();
-}
-
-ShellWindow::ShellWindow(void* hwnd, int argc, char** argv)
-    : INHERITED(hwnd) {
-    SkCommandLineFlags::Parse(argc, argv);
-}
-
-ShellWindow::~ShellWindow() {
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool ShellWindow::onDispatchClick(int x, int y, Click::State state,
-        void* owner, unsigned modi) {
-    int w = SkScalarRoundToInt(this->width());
-    int h = SkScalarRoundToInt(this->height());
-
-    // check for the resize-box
-    if (w - x < 16 && h - y < 16) {
-        return false;   // let the OS handle the click
-    } else {
-        return this->INHERITED::onDispatchClick(x, y, state, owner, modi);
-    }
-}
-
-void ShellWindow::onSizeChange() {
-    this->INHERITED::onSizeChange();
-
-    SkView::F2BIter iter(this);
-    SkView* view = iter.next();
-    view->setSize(this->width(), this->height());
-}
-
-DEFINE_bool(dm, false, "run dm");
-DEFINE_bool(nanobench, false, "run nanobench");
-
-int nanobench_main();
-int dm_main();
-
-IOS_launch_type set_cmd_line_args(int argc, char *argv[], const char* resourceDir) {
-    SkCommandLineFlags::Parse(argc, argv);
-    if (FLAGS_nanobench) {
-        return nanobench_main() ? kError_iOSLaunchType : kTool_iOSLaunchType;
-    }
-    if (FLAGS_dm) {
-        return dm_main() ? kError_iOSLaunchType : kTool_iOSLaunchType;
-    }
-    return kError_iOSLaunchType;
-}
-
-// FIXME: this should be in a header
-SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv);
-SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
-    return new ShellWindow(hwnd, argc, argv);
-}
-
-// FIXME: this should be in a header
-void get_preferred_size(int* x, int* y, int* width, int* height);
-void get_preferred_size(int* x, int* y, int* width, int* height) {
-    *x = 10;
-    *y = 50;
-    *width = 640;
-    *height = 480;
-}
-
-// FIXME: this should be in a header
-void application_init();
-void application_init() {
-    SkGraphics::Init();
-    SkEvent::Init();
-}
-
-// FIXME: this should be in a header
-void application_term();
-void application_term() {
-    SkEvent::Term();
-}
diff --git a/src/third_party/skia/tools/iOSShell.h b/src/third_party/skia/tools/iOSShell.h
deleted file mode 100644
index eaecba5..0000000
--- a/src/third_party/skia/tools/iOSShell.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2014 Skia
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef iOSShell_DEFINED
-#define iOSShell_DEFINED
-
-#include "SkWindow.h"
-
-class SkCanvas;
-class SkEvent;
-class SkViewFactory;
-
-class ShellWindow : public SkOSWindow {
-public:
-    ShellWindow(void* hwnd, int argc, char** argv);
-    virtual ~ShellWindow();
-
-protected:
-    void onSizeChange() override;
-
-    virtual bool onDispatchClick(int x, int y, Click::State, void* owner,
-                                 unsigned modi) override;
-
-private:
-    typedef SkOSWindow INHERITED;
-};
-
-#endif
diff --git a/src/third_party/skia/tools/image_diff_metric.cpp b/src/third_party/skia/tools/image_diff_metric.cpp
new file mode 100644
index 0000000..b690c72
--- /dev/null
+++ b/src/third_party/skia/tools/image_diff_metric.cpp
@@ -0,0 +1,54 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+// Image Diff:   Provides a metric for measuring the difference between two encoded images.   Prints
+// out a single floating-point number between 0.0 and 1.0; 0 means that the images are identical; 1
+// means that each pixel is maximally different in each channel.  A non-zero return value indicates
+// that something went wrong.
+
+#include "include/codec/SkCodec.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkData.h"
+#include "include/core/SkPixmap.h"
+#include "include/core/SkSize.h"
+
+#include <cmath>
+#include <cstdio>
+
+int main(int argc, char** argv) {
+    if (argc != 3) {
+        const char usage[] = "\nUsage:\n  %s {FILE1}.png {FILE2}.png\n\n";
+        fprintf(stderr, usage, argv[0]);
+        return 1;
+    }
+    SkBitmap bm[2];
+    for (int i = 0; i < 2; ++i) {
+        const char* path = argv[i + 1];
+        if (std::unique_ptr<SkCodec> codec =
+                SkCodec::MakeFromData(SkData::MakeFromFileName(path))) {
+            bm[i].allocN32Pixels(codec->dimensions().fWidth, codec->dimensions().fHeight);
+            if (SkCodec::kSuccess == codec->getPixels(bm[i].pixmap())) {
+                continue;
+            }
+        }
+        fprintf(stderr, "\nBad file: '%s'.\n\n", path);
+        return 2;
+    }
+    SkISize dim = bm[0].dimensions();
+    if (dim != bm[1].dimensions()) {
+        fprintf(stderr, "\nImages must be same size: (%d,%d) != (%d,%d)\n\n",
+                dim.fWidth, dim.fHeight, bm[1].dimensions().fWidth, bm[1].dimensions().fHeight);
+        return 3;
+    }
+    int64_t totalDiffs = 0; // Manhattan distance in ARGB color-space.
+    for (int y = 0; y < dim.fHeight; ++y) {
+        const uint8_t* row1 = reinterpret_cast<const uint8_t*>(bm[0].pixmap().addr32(0, y));
+        const uint8_t* row2 = reinterpret_cast<const uint8_t*>(bm[1].pixmap().addr32(0, y));
+        for (size_t i = 0; i < (size_t)dim.fWidth * (size_t)4; ++i) {
+            totalDiffs += std::abs((int)row1[i] - (int)row2[i]);
+        }
+    }
+    printf("%g\n", (double)totalDiffs /
+                   ((uint64_t)255 * 4 * (uint64_t)dim.fWidth * (uint64_t)dim.fHeight));
+    return 0;
+}
diff --git a/src/third_party/skia/tools/imgblur.cpp b/src/third_party/skia/tools/imgblur.cpp
deleted file mode 100644
index 20d3684..0000000
--- a/src/third_party/skia/tools/imgblur.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBitmap.h"
-#include "SkCommandLineFlags.h"
-#include "SkCommonFlags.h"
-#include "SkData.h"
-#include "SkImage.h"
-#include "SkStream.h"
-#include "SkTypes.h"
-
-#include "sk_tool_utils.h"
-
-DEFINE_string(in, "input.png", "Input image");
-DEFINE_string(out, "blurred.png", "Output image");
-DEFINE_double(sigma, 1, "Sigma to be used for blur (> 0.0f)");
-
-
-// This tool just performs a blur on an input image
-// Return codes:
-static const int kSuccess = 0;
-static const int kError = 1;
-
-int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("Brute force blur of an image.");
-    SkCommandLineFlags::Parse(argc, argv);
-
-    if (FLAGS_sigma <= 0) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Sigma must be greater than zero (it is %f).\n", FLAGS_sigma);
-        }
-        return kError;
-    }
-
-    sk_sp<SkData> data(SkData::MakeFromFileName(FLAGS_in[0]));
-    if (nullptr == data) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't open file: %s\n", FLAGS_in[0]);
-        }
-        return kError;
-    }
-
-    sk_sp<SkImage> image(SkImage::MakeFromEncoded(data));
-    if (!image) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't create image for: %s.\n", FLAGS_in[0]);
-        }
-        return kError;
-    }
-
-    SkBitmap src;
-    if (!image->asLegacyBitmap(&src, SkImage::kRW_LegacyBitmapMode)) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't create bitmap for: %s.\n", FLAGS_in[0]);
-        }
-        return kError;
-    }
-
-    SkBitmap dst = sk_tool_utils::slow_blur(src, (float) FLAGS_sigma);
-
-    if (!sk_tool_utils::EncodeImageToFile(FLAGS_out[0], dst, SkEncodedImageFormat::kPNG, 100)) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't write to file: %s\n", FLAGS_out[0]);
-        }
-        return kError;
-    }
-
-    return kSuccess;
-}
diff --git a/src/third_party/skia/tools/imgcvt.cpp b/src/third_party/skia/tools/imgcvt.cpp
new file mode 100644
index 0000000..5c024f0
--- /dev/null
+++ b/src/third_party/skia/tools/imgcvt.cpp
@@ -0,0 +1,166 @@
+/*
+* 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 "include/core/SkCanvas.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/third_party/skcms/skcms.h"
+#include "src/core/SkColorSpacePriv.h"
+
+static void write_png(const char* path, sk_sp<SkImage> img) {
+    sk_sp<SkData>  png = img->encodeToData();
+    SkFILEWStream(path).write(png->data(), png->size());
+}
+
+int main(int argc, char** argv) {
+    const char* source_path = argc > 1 ? argv[1] : nullptr;
+    if (!source_path) {
+        SkDebugf("Please pass an image or profile to convert"
+                 " as the first argument to this program.\n");
+        return 1;
+    }
+
+    const char* dst_profile_path = argc > 2 ? argv[2] : nullptr;
+    skcms_ICCProfile dst_profile = *skcms_sRGB_profile();
+    sk_sp<SkData> dst_blob;
+    if (dst_profile_path) {
+        dst_blob = SkData::MakeFromFileName(dst_profile_path);
+        if (!skcms_Parse(dst_blob->data(), dst_blob->size(), &dst_profile)) {
+            SkDebugf("Can't parse %s as an ICC profile.\n", dst_profile_path);
+            return 1;
+        }
+    }
+
+    auto blob = SkData::MakeFromFileName(source_path);
+
+    skcms_ICCProfile src_profile;
+    if (skcms_Parse(blob->data(), blob->size(), &src_profile)) {
+        // Transform white, black, primaries, and primary complements.
+        float src[] = {
+           0,0,0,
+           1,1,1,
+
+           1,0,0,
+           0,1,0,
+           0,0,1,
+
+           0,1,1,
+           1,0,1,
+           1,1,0,
+        };
+        float dst[24] = {0};
+
+        if (!skcms_Transform(
+                    src, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &src_profile,
+                    dst, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &dst_profile,
+                    8)) {
+            SkDebugf("Cannot transform.\n");
+            return 1;
+        }
+        for (int i = 0; i < 8; i++) {
+            SkDebugf("(%g, %g, %g) --> (%+.4f, %+.4f, %+.4f)\n",
+                     src[3*i+0], src[3*i+1], src[3*i+2],
+                     dst[3*i+0], dst[3*i+1], dst[3*i+2]);
+        }
+        return 0;
+    }
+
+    sk_sp<SkImage> image = SkImage::MakeFromEncoded(blob);
+    if (!image) {
+        SkDebugf("Couldn't decode %s as an SkImage or an ICC profile.\n", source_path);
+        return 1;
+    }
+
+    image = image->makeRasterImage();
+    if (!image) {
+        SkDebugf("Converting to raster image failed.\n");
+        return 1;
+    }
+
+    SkPixmap pixmap;
+    if (!image->peekPixels(&pixmap)) {
+        SkDebugf("We really should be able to peek raster pixels.\n");
+        return 1;
+    }
+
+    sk_sp<SkColorSpace> dst_cs = SkColorSpace::Make(dst_profile);
+    if (!dst_cs) {
+        SkDebugf("We can't convert to this destination profile as-is. Coercing it.\n");
+        if (skcms_MakeUsableAsDestinationWithSingleCurve(&dst_profile)) {
+            dst_cs = SkColorSpace::Make(dst_profile);
+        }
+        if (!dst_cs) {
+            SkDebugf("We can't convert to this destination profile at all.\n");
+            return 1;
+        }
+    }
+
+    { // transform with skcms
+        SkColorSpace* src_cs = image->colorSpace() ? image->colorSpace()
+                                                   : sk_srgb_singleton();
+        src_cs->toProfile(&src_profile);
+
+        skcms_PixelFormat fmt;
+        switch (pixmap.colorType()) {
+            case kRGBA_8888_SkColorType: fmt = skcms_PixelFormat_RGBA_8888; break;
+            case kBGRA_8888_SkColorType: fmt = skcms_PixelFormat_BGRA_8888; break;
+            default:
+                SkDebugf("color type %d not yet supported, imgcvt.cpp needs an update.\n",
+                         pixmap.colorType());
+                return 1;
+        }
+
+        if (pixmap.alphaType() == kUnpremul_SkAlphaType) {
+            SkDebugf("not premul, that's weird.\n");
+            return 1;
+        }
+        auto alpha = skcms_AlphaFormat_PremulAsEncoded;
+
+        if (pixmap.rowBytes() != (size_t)pixmap.width() * pixmap.info().bytesPerPixel()) {
+            SkDebugf("not a tight pixmap, need a loop here\n");
+            return 1;
+        }
+
+        if (!skcms_Transform(pixmap.addr(),          fmt,alpha, &src_profile,
+                             pixmap.writable_addr(), fmt,alpha, &dst_profile,
+                             pixmap.width() * pixmap.height())) {
+            SkDebugf("skcms_Transform() failed\n");
+            return 1;
+        }
+        pixmap.setColorSpace(dst_cs);
+
+        write_png("transformed-skcms.png", SkImage::MakeRasterCopy(pixmap));
+    }
+
+    { // transform with writePixels()
+        sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
+        if (!surface) {
+            SkDebugf("couldn't create a surface\n");
+            return 1;
+        }
+
+        surface->writePixels(pixmap, 0,0);
+
+        write_png("transformed-writepixels.png", surface->makeImageSnapshot());
+    }
+
+    { // transform by drawing
+        sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
+        if (!surface) {
+            SkDebugf("couldn't create a surface\n");
+            return 1;
+        }
+
+        surface->getCanvas()->drawImage(image, 0,0);
+
+        write_png("transformed-draw.png", surface->makeImageSnapshot());
+    }
+
+    return 0;
+}
diff --git a/src/third_party/skia/tools/imgslice.cpp b/src/third_party/skia/tools/imgslice.cpp
deleted file mode 100644
index 51aeef7..0000000
--- a/src/third_party/skia/tools/imgslice.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBitmap.h"
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkImage.h"
-#include "SkStream.h"
-
-DEFINE_bool(header, false, "Print an extra row of the min-max values");
-DEFINE_string2(label, l, "label", "Label printed as the first value");
-
-DEFINE_string2(image, i, "", "Input image");
-DEFINE_int32_2(row, r, -1, "Row to extract");
-DEFINE_int32_2(column, c, -1, "Column to extract");
-
-DEFINE_int32_2(min, n, 0, "Minimum row/column to extract - inclusive");
-DEFINE_int32_2(max, m, 100, "Maximum row/column to extract - inclusive");
-
-DEFINE_int32(rgb, 0, "Color channel to print (0->b, 1->g, 2->r, 3->a)");
-
-DEFINE_bool2(quiet, q, false, "Quiet");
-DEFINE_bool2(reverse, v, false, "Iterate from max to min");
-
-
-// This tool just loads a single image and prints out a comma-separated row or column
-// Return codes:
-static const int kSuccess = 0;
-static const int kError = 1;
-
-int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("Print out a row or column of an image.");
-    SkCommandLineFlags::Parse(argc, argv);
-
-    if (FLAGS_rgb > 3 || FLAGS_rgb < 0) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Channel (--rgb) must be between 0 and 3 (inclusive) - value is %d.\n",
-                     FLAGS_rgb);
-        }
-        return kError;
-    }
-
-    if (FLAGS_row >= 0 && FLAGS_column >= 0) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Only one of '-c' or '-r' can be specified at at time.\n");
-        }
-        return kError;
-    }
-
-    if (FLAGS_row < 0 && FLAGS_column < 0) {
-        if (!FLAGS_quiet) {
-            SkDebugf("At least one of '-c' or '-r' need to be specified.\n");
-        }
-        return kError;
-    }
-
-    sk_sp<SkData> data(SkData::MakeFromFileName(FLAGS_image[0]));
-    if (nullptr == data) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't open file: %s\n", FLAGS_image[0]);
-        }
-        return kError;
-    }
-
-    sk_sp<SkImage> image(SkImage::MakeFromEncoded(data));
-    if (!image) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't create image for: %s.\n", FLAGS_image[0]);
-        }
-        return kError;
-    }
-
-    SkBitmap bitmap;
-    if (!image->asLegacyBitmap(&bitmap, SkImage::kRW_LegacyBitmapMode)) {
-        if (!FLAGS_quiet) {
-            SkDebugf("Couldn't create bitmap for: %s.\n", FLAGS_image[0]);
-        }
-        return kError;
-    }
-
-    int top, bottom, left, right;
-
-    if (-1 != FLAGS_row) {
-        SkASSERT(-1 == FLAGS_column);
-
-        top = bottom = SkTPin(FLAGS_row, 0, bitmap.height()-1);
-        FLAGS_min = left = SkTPin(FLAGS_min, 0, bitmap.width()-1);
-        FLAGS_max = right = SkTPin(FLAGS_max, left, bitmap.width()-1);
-    } else {
-        SkASSERT(-1 != FLAGS_column);
-        left = right = SkTPin(FLAGS_column, 0, bitmap.width()-1);
-        FLAGS_min = top = SkTPin(FLAGS_min, 0, bitmap.height()-1);
-        FLAGS_max = bottom = SkTPin(FLAGS_max, top, bitmap.height()-1);
-    }
-
-    if (FLAGS_header) {
-        SkDebugf("header");
-        if (FLAGS_reverse) {
-            for (int i = FLAGS_max; i >= FLAGS_min; --i) {
-                SkDebugf(", %d", i);
-            }
-        } else {
-            for (int i = FLAGS_min; i <= FLAGS_max; ++i) {
-                SkDebugf(", %d", i);
-            }
-        }
-        SkDebugf("\n");
-    }
-
-    SkDebugf("%s", FLAGS_label[0]);
-    if (FLAGS_reverse) {
-        for (int y = bottom; y >= top; --y) {
-            for (int x = right; x >= left; --x) {
-                SkColor c = bitmap.getColor(x, y);
-
-                SkDebugf(", %d", ((c) >> (FLAGS_rgb*8)) & 0xFF);
-            }
-        }
-    } else {
-        for (int y = top; y <= bottom; ++y) {
-            for (int x = left; x <= right; ++x) {
-                SkColor c = bitmap.getColor(x, y);
-
-                SkDebugf(", %d", ((c) >> (FLAGS_rgb*8)) & 0xFF);
-            }
-        }
-    }
-
-    SkDebugf("\n");
-
-    return kSuccess;
-}
diff --git a/src/third_party/skia/tools/infra/__init__.py b/src/third_party/skia/tools/infra/__init__.py
new file mode 100644
index 0000000..d5cf199
--- /dev/null
+++ b/src/third_party/skia/tools/infra/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/src/third_party/skia/tools/infra/git.py b/src/third_party/skia/tools/infra/git.py
new file mode 100644
index 0000000..cc51d42
--- /dev/null
+++ b/src/third_party/skia/tools/infra/git.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import subprocess
+import sys
+
+
+GIT = 'git.bat' if sys.platform == 'win32' else 'git'
+
+
+def git(*args):
+  '''Run the given Git command, return the output.'''
+  return subprocess.check_output([GIT]+list(args))
diff --git a/src/third_party/skia/tools/infra/go.py b/src/third_party/skia/tools/infra/go.py
new file mode 100644
index 0000000..213fc75
--- /dev/null
+++ b/src/third_party/skia/tools/infra/go.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import os
+import subprocess
+import sys
+
+
+INFRA_GO = 'go.skia.org/infra'
+WHICH = 'where' if sys.platform == 'win32' else 'which'
+
+
+def check():
+  '''Verify that golang is properly installed. If not, exit with an error.'''
+  def _fail(msg):
+    print >> sys.stderr, msg
+    sys.exit(1)
+
+  try:
+    go_exe = subprocess.check_output([WHICH, 'go'])
+  except (subprocess.CalledProcessError, OSError):
+    go_exe = None
+  if not go_exe:
+    _fail('Unable to find Golang installation; see '
+          'https://golang.org/doc/install')
+  if not os.environ.get('GOPATH'):
+    _fail('GOPATH environment variable is not set; is Golang properly '
+          'installed?')
+  go_bin = os.path.join(os.environ['GOPATH'], 'bin')
+  for entry in os.environ.get('PATH', '').split(os.pathsep):
+    if entry == go_bin:
+      break
+  else:
+    _fail('%s not in PATH; is Golang properly installed?' % go_bin)
+
+
+def get(url):
+  '''Clone or update the given repo URL via "go get".'''
+  check()
+  subprocess.check_call(['go', 'get', '-u', url])
+
+
+def update_infra():
+  '''Update the local checkout of the Skia infra codebase.'''
+  get(INFRA_GO + '/...')
diff --git a/src/third_party/skia/tools/install_dependencies.sh b/src/third_party/skia/tools/install_dependencies.sh
index fd5c366..b011545 100755
--- a/src/third_party/skia/tools/install_dependencies.sh
+++ b/src/third_party/skia/tools/install_dependencies.sh
@@ -23,17 +23,20 @@
 
 if command -v lsb_release > /dev/null ; then
     case $(lsb_release -i -s) in
-        Ubuntu)
+        Ubuntu|Debian)
             PACKAGES=$(cat<<-EOF
 		build-essential
 		freeglut3-dev
 		libfontconfig-dev
 		libfreetype6-dev
 		libgif-dev
+		libgl1-mesa-dev
 		libglu1-mesa-dev
-		libosmesa6-dev
-		libpng12-dev
-		libqt4-dev
+		libharfbuzz-dev
+		libicu-dev
+		libjpeg-dev
+		libpng-dev
+		libwebp-dev
 		EOF
             )
            if [ $(lsb_release -r -s) = '14.04' ] ; then
diff --git a/src/third_party/skia/tools/ios_utils.h b/src/third_party/skia/tools/ios_utils.h
index 0287dc1..579da07 100644
--- a/src/third_party/skia/tools/ios_utils.h
+++ b/src/third_party/skia/tools/ios_utils.h
@@ -14,7 +14,7 @@
 
     // cd into the current app's Documents/ directory.
     // (This is the only directory we can easily read and write.)
-    void cd_Documents();
+    void cd_Documents(void);
 
 #if defined(__cplusplus)
 }
diff --git a/src/third_party/skia/tools/ios_utils.m b/src/third_party/skia/tools/ios_utils.m
index b88ab5b..faef5c5 100644
--- a/src/third_party/skia/tools/ios_utils.m
+++ b/src/third_party/skia/tools/ios_utils.m
@@ -6,7 +6,7 @@
  */
 
 #import <Foundation/Foundation.h>
-#include "ios_utils.h"
+#include "tools/ios_utils.h"
 #include <unistd.h>
 
 void cd_Documents() {
diff --git a/src/third_party/skia/tools/jsondiff.py b/src/third_party/skia/tools/jsondiff.py
index 91e3e4b..ed4731a 100755
--- a/src/third_party/skia/tools/jsondiff.py
+++ b/src/third_party/skia/tools/jsondiff.py
@@ -130,7 +130,8 @@
             if results_of_this_type:
                 for test_name in results_of_this_type.keys():
                     digest_pair = results_of_this_type[test_name]
-                    if digest_pair[0] != gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5:
+                    if (digest_pair[0] !=
+                            gm_json.JSONKEY_HASHTYPE_BITMAP_64BITMD5):
                         raise ValueError(
                             'test %s has unsupported hashtype %s' % (
                                 test_name, digest_pair[0]))
@@ -138,7 +139,7 @@
         return result_dict
 
     def _DictionaryDiff(self, old_dict, new_dict):
-        """Generate a dictionary showing the diffs between old_dict and new_dict.
+        """Generate a dictionary showing diffs between old_dict and new_dict.
         Any entries which are identical across them will be left out."""
         diff_dict = {}
         all_keys = set(old_dict.keys() + new_dict.keys())
@@ -158,8 +159,9 @@
         If newfile is not specified, then 'new' is the actual results within
         oldfile.
         """
-        return self.GenerateDiffDictFromStrings(self._GetFileContentsAsString(oldfile),
-                                                self._GetFileContentsAsString(newfile))
+        return self.GenerateDiffDictFromStrings(
+            self._GetFileContentsAsString(oldfile),
+            self._GetFileContentsAsString(newfile))
 
     def GenerateDiffDictFromStrings(self, oldjson, newjson=None):
         """Generate a dictionary showing the diffs:
diff --git a/src/third_party/skia/tools/list_gms.cpp b/src/third_party/skia/tools/list_gms.cpp
new file mode 100644
index 0000000..6c3ebc5
--- /dev/null
+++ b/src/third_party/skia/tools/list_gms.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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 <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "gm/gm.h"
+
+int main() {
+    std::vector<std::string> gms;
+    for (skiagm::GMFactory factory : skiagm::GMRegistry::Range()) {
+        std::unique_ptr<skiagm::GM> gm(factory());
+        gms.push_back(std::string(gm->getName()));
+    }
+    std::sort(gms.begin(), gms.end());
+    for (const std::string& gm : gms) {
+        std::cout << gm << '\n';
+    }
+}
diff --git a/src/third_party/skia/tools/list_gpu_unit_tests.cpp b/src/third_party/skia/tools/list_gpu_unit_tests.cpp
new file mode 100644
index 0000000..a39a5f4
--- /dev/null
+++ b/src/third_party/skia/tools/list_gpu_unit_tests.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "tests/Test.h"
+
+int main() {
+    std::vector<std::string> tests;
+    for (const skiatest::Test& test : skiatest::TestRegistry::Range()) {
+        if (test.needsGpu) {
+            tests.push_back(std::string(test.name));
+        }
+    }
+    std::sort(tests.begin(), tests.end());
+    for (const std::string& test : tests) {
+        std::cout << test << '\n';
+    }
+}
diff --git a/src/third_party/skia/tools/lottie-web-perf/lottie-web-canvas-perf.html b/src/third_party/skia/tools/lottie-web-perf/lottie-web-canvas-perf.html
new file mode 100644
index 0000000..746c0bc
--- /dev/null
+++ b/src/third_party/skia/tools/lottie-web-perf/lottie-web-canvas-perf.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Lottie-Web Perf</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=egde,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="/res/lottie.js" type="text/javascript" charset="utf-8"></script>
+    <style type="text/css" media="screen">
+      body {
+        margin: 0;
+        padding: 0;
+      }
+    </style>
+</head>
+<body>
+  <main>
+    <canvas id=canvas width=1000 height=1000 style="height: 1000px; width: 1000px;"></canvas>
+  </main>
+  <script type="text/javascript" charset="utf-8">
+    (function () {
+      const PATH = '/res/lottie.json';
+      const RENDERER = 'canvas';
+      const MAX_FRAMES = 25;
+      const MAX_LOOPS = 3;
+
+      const cvs = document.getElementById("canvas");
+      const canvasContext = cvs.getContext('2d');
+
+      // Get total number of frames of the animation from the hash.
+      const hash = window.location.hash;
+      const totalFrames = hash.slice(1);
+      console.log("Lottie has " + totalFrames + "total frames");
+
+      // Load the animation with autoplay false. We will control which
+      // frame to seek to and then will measure performance.
+      let anim = lottie.loadAnimation({
+        container: document.querySelector('.anim'),
+        renderer: RENDERER,
+        loop: false,
+        autoplay: false,
+        path: PATH,
+        rendererSettings: {
+          context: canvasContext,
+          scaleMode: 'noScale',
+          clearCanvas: true,
+          preserveAspectRatio:'xMidYMid meet',
+        },
+      });
+
+      const t_rate = 1.0 / (MAX_FRAMES - 1);
+      let frame = 0;
+      let loop = 0;
+      const drawFrame = () => {
+        if (frame >= MAX_FRAMES) {
+          // Reached the end of one loop.
+          loop++;
+          if (loop == MAX_LOOPS) {
+            // These are global variables to talk with puppeteer.
+            window._lottieWebDone = true;
+            return;
+          }
+          // Reset frame to restart the loop.
+          frame = 0;
+        }
+
+        let t1 = Math.max(Math.min(t_rate * frame, 1.0), 0.0);
+        let seekToFrame = totalFrames * t1;
+        if (seekToFrame >= totalFrames-1) {
+          // bodymovin player sometimes draws blank when requesting
+          // to draw the very last frame.  Subtracting a small value
+          // seems to fix this and make it draw the last frame.
+          seekToFrame -= .001;
+        }
+
+        anim.goToAndStop(seekToFrame, true /* isFrame */);
+        console.log("Used seek: " + (seekToFrame/totalFrames));
+        frame++;
+        window.requestAnimationFrame(drawFrame);
+      };
+      window.requestAnimationFrame(drawFrame);
+    })();
+  </script>
+</body>
+</html>
diff --git a/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.html b/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.html
new file mode 100644
index 0000000..88cc992
--- /dev/null
+++ b/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Lottie-Web Perf</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=egde,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="/res/lottie.js" type="text/javascript" charset="utf-8"></script>
+    <style type="text/css" media="screen">
+      body {
+        margin: 0;
+        padding: 0;
+      }
+    </style>
+</head>
+<body>
+  <main>
+    <div style="width:1000px;height:1000px" class=anim></div>
+  </main>
+  <script type="text/javascript" charset="utf-8">
+    (function () {
+      const PATH = '/res/lottie.json';
+      const RENDERER = 'svg';
+      const MAX_FRAMES = 25;
+      const MAX_LOOPS = 5;
+
+      // Get total number of frames of the animation from the hash.
+      const hash = window.location.hash;
+      const totalFrames = hash.slice(1);
+      console.log("Lottie has " + totalFrames + "total frames");
+
+      // Load the animation with autoplay false. We will control which
+      // frame to seek to and then will measure performance.
+      let anim = lottie.loadAnimation({
+        container: document.querySelector('.anim'),
+        renderer: RENDERER,
+        loop: false,
+        autoplay: false,
+        path: PATH,
+        rendererSettings: {
+          preserveAspectRatio:'xMidYMid meet'
+        },
+      });
+
+      const t_rate = 1.0 / (MAX_FRAMES - 1);
+      let frame = 0;
+      let loop = 0;
+      const drawFrame = () => {
+        if (frame >= MAX_FRAMES) {
+          // Reached the end of one loop.
+          loop++;
+          if (loop == MAX_LOOPS) {
+            // These are global variables to talk with puppeteer.
+            window._lottieWebDone = true;
+            return;
+          }
+          // Reset frame to restart the loop.
+          frame = 0;
+        }
+
+        let t1 = Math.max(Math.min(t_rate * frame, 1.0), 0.0);
+        let seekToFrame = totalFrames * t1;
+        if (seekToFrame >= totalFrames-1) {
+          // bodymovin player sometimes draws blank when requesting
+          // to draw the very last frame.  Subtracting a small value
+          // seems to fix this and make it draw the last frame.
+          seekToFrame -= .001;
+        }
+
+        anim.goToAndStop(seekToFrame, true /* isFrame */);
+        console.log("Used seek: " + (seekToFrame/totalFrames));
+        frame++;
+        window.requestAnimationFrame(drawFrame);
+      };
+      window.requestAnimationFrame(drawFrame);
+    })();
+  </script>
+</body>
+</html>
diff --git a/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.js b/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.js
new file mode 100644
index 0000000..3321cf6
--- /dev/null
+++ b/src/third_party/skia/tools/lottie-web-perf/lottie-web-perf.js
@@ -0,0 +1,184 @@
+/**
+ * Command line application to run Lottie-Web perf on a Lottie file in the
+ * browser and then exporting that result.
+ *
+ */
+const puppeteer = require('puppeteer');
+const express = require('express');
+const fs = require('fs');
+const commandLineArgs = require('command-line-args');
+const commandLineUsage= require('command-line-usage');
+const fetch = require('node-fetch');
+
+const opts = [
+  {
+    name: 'input',
+    typeLabel: '{underline file}',
+    description: 'The Lottie JSON file to process.'
+  },
+  {
+    name: 'output',
+    typeLabel: '{underline file}',
+    description: 'The perf file to write. Defaults to perf.json',
+  },
+  {
+    name: 'use_gpu',
+    description: 'Whether we should run in non-headless mode with GPU.',
+    type: Boolean,
+  },
+  {
+    name: 'port',
+    description: 'The port number to use, defaults to 8081.',
+    type: Number,
+  },
+  {
+    name: 'lottie_player',
+    description: 'The path to lottie.min.js, defaults to a local npm install location.',
+    type: String,
+  },
+  {
+    name: 'backend',
+    description: 'Which lottie-web backend to use. Options: canvas or svg.',
+    type: String,
+  },
+  {
+    name: 'help',
+    alias: 'h',
+    type: Boolean,
+    description: 'Print this usage guide.'
+  },
+];
+
+const usage = [
+  {
+    header: 'Lottie-Web Perf',
+    content: 'Command line application to run Lottie-Web perf.',
+  },
+  {
+    header: 'Options',
+    optionList: opts,
+  },
+];
+
+// Parse and validate flags.
+const options = commandLineArgs(opts);
+
+if (options.backend != 'canvas' && options.backend != 'svg') {
+  console.error('You must supply a lottie-web backend (canvas, svg).');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+if (!options.output) {
+  options.output = 'perf.json';
+}
+if (!options.port) {
+  options.port = 8081;
+}
+if (!options.lottie_player) {
+  options.lottie_player = 'node_modules/lottie-web/build/player/lottie.min.js';
+}
+
+if (options.help) {
+  console.log(commandLineUsage(usage));
+  process.exit(0);
+}
+
+if (!options.input) {
+  console.error('You must supply a Lottie JSON filename.');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+// Start up a web server to serve the three files we need.
+let lottieJS = fs.readFileSync(options.lottie_player, 'utf8');
+let lottieJSON = fs.readFileSync(options.input, 'utf8');
+let driverHTML;
+if (options.backend == 'svg') {
+  console.log('Using lottie-web-perf.html');
+  driverHTML = fs.readFileSync('lottie-web-perf.html', 'utf8');
+} else {
+  console.log('Using lottie-web-canvas-perf.html');
+  driverHTML = fs.readFileSync('lottie-web-canvas-perf.html', 'utf8');
+}
+
+// Find number of frames from the lottie JSON.
+let lottieJSONContent = JSON.parse(lottieJSON);
+const totalFrames = lottieJSONContent.op - lottieJSONContent.ip;
+console.log('Total frames: ' + totalFrames);
+
+const app = express();
+app.get('/', (req, res) => res.send(driverHTML));
+app.get('/res/lottie.js', (req, res) => res.send(lottieJS));
+app.get('/res/lottie.json', (req, res) => res.send(lottieJSON));
+app.listen(options.port, () => console.log('- Local web server started.'))
+
+// Utility function.
+async function wait(ms) {
+    await new Promise(resolve => setTimeout(() => resolve(), ms));
+    return ms;
+}
+
+const targetURL = "http://localhost:" + options.port + "/#" + totalFrames;
+const viewPort = {width: 1000, height: 1000};
+
+// Drive chrome to load the web page from the server we have running.
+async function driveBrowser() {
+  console.log('- Launching chrome for ' + options.input);
+  let browser;
+  let page;
+  const headless = !options.use_gpu;
+  let browser_args = [
+      '--no-sandbox',
+      '--disable-setuid-sandbox',
+      '--window-size=' + viewPort.width + ',' + viewPort.height,
+  ];
+  if (options.use_gpu) {
+    browser_args.push('--ignore-gpu-blacklist');
+    browser_args.push('--ignore-gpu-blocklist');
+    browser_args.push('--enable-gpu-rasterization');
+  }
+  console.log("Running with headless: " + headless + " args: " + browser_args);
+  try {
+    browser = await puppeteer.launch({headless: headless, args: browser_args});
+    page = await browser.newPage();
+    await page.setViewport(viewPort);
+  } catch (e) {
+    console.log('Could not open the browser.', e);
+    process.exit(1);
+  }
+
+  console.log("Loading " + targetURL);
+  try {
+    // Start trace.
+    await page.tracing.start({
+      path: options.output,
+      screenshots: false,
+      categories: ["blink", "cc", "gpu"]
+    });
+
+    await page.goto(targetURL, {
+      timeout: 60000,
+      waitUntil: 'networkidle0'
+    });
+
+    console.log('- Waiting 60s for run to be done.');
+    await page.waitForFunction('window._lottieWebDone === true', {
+      timeout: 60000,
+    });
+
+    // Stop trace.
+    await page.tracing.stop();
+  } catch(e) {
+    console.log('Timed out while loading or drawing. Either the JSON file was ' +
+                'too big or hit a bug in the player.', e);
+    await browser.close();
+    process.exit(1);
+  }
+
+  await browser.close();
+  // Need to call exit() because the web server is still running.
+  process.exit(0);
+}
+
+driveBrowser();
diff --git a/src/third_party/skia/tools/lottie-web-perf/package.json b/src/third_party/skia/tools/lottie-web-perf/package.json
new file mode 100644
index 0000000..5a4aaaf
--- /dev/null
+++ b/src/third_party/skia/tools/lottie-web-perf/package.json
@@ -0,0 +1,10 @@
+{
+  "dependencies": {
+    "command-line-args": "^5.0.2",
+    "command-line-usage": "^5.0.3",
+    "express": "^4.16.3",
+    "lottie-web": "5.5.5",
+    "node-fetch": "^2.2.0",
+    "puppeteer": "~1.17.0"
+  }
+}
diff --git a/src/third_party/skia/tools/lottiecap/README.md b/src/third_party/skia/tools/lottiecap/README.md
new file mode 100644
index 0000000..79ed953
--- /dev/null
+++ b/src/third_party/skia/tools/lottiecap/README.md
@@ -0,0 +1,29 @@
+Capture Lottie Filmstrip in the Browser
+=======================================
+
+Command line application to build a 5x5 filmstrip
+from a Lottie file in the browser and then export
+that filmstrip in a 1000x1000 PNG.
+
+First run
+
+    $ npm install
+
+Then run
+
+    $ node ./lottiecap.js --input some_lottie_file.js
+
+To get more help:
+
+    $ node ./lottiecap.js -h
+
+Requirements
+------------
+
+You need to have a recent version of 'node' installed, i.e.  version v8.9 or
+later. Get recent versions of Node from:
+
+    https://nodejs.org/en/download/
+
+It is doubtful that your workstation's distribution has a recent version of
+Node available.
diff --git a/src/third_party/skia/tools/lottiecap/driver.html b/src/third_party/skia/tools/lottiecap/driver.html
new file mode 100644
index 0000000..2b6dc94
--- /dev/null
+++ b/src/third_party/skia/tools/lottiecap/driver.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Lottie Filmstrip Capture</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=egde,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="/lottie.js" type="text/javascript" charset="utf-8"></script>
+    <style type="text/css" media="screen">
+      body,
+      main,
+      .anim {
+        margin: 0;
+        padding: 0;
+      }
+
+      main {
+        display: flex;
+        width: 1000px;
+        height: 1000px;
+        flex-flow: row wrap;
+      }
+    </style>
+</head>
+<body>
+  <main>
+    <div class=anim></div>
+  </main>
+  <script type="text/javascript" charset="utf-8">
+    (function () {
+      const TILE_COUNT = 5; // Number of tiles in x or y direction.
+      const TARGET_SIZE = 1000; // Image size in pixels both x and y direction.
+      const PATH = '/lottie.json';
+
+      let renderer = 'svg';
+      let hash = window.location.hash;
+      if (hash) {
+        renderer = hash.slice(1);
+      }
+
+      // This global is used by puppeteer to determine if all tiles have finished drawing.
+      window._tileCount = 0;
+
+      // First load the animation for just a single tile
+      // so we can read out some values and calculate what
+      // the filmstrip should look like.
+      let anim = lottie.loadAnimation({
+        container: document.querySelector('.anim'),
+        renderer: renderer,
+        loop: false,
+        autoplay: true,
+        path: PATH,
+        rendererSettings: {
+          preserveAspectRatio:'xMidYMid meet'
+        },
+      });
+
+      anim.addEventListener('data_ready', (e) => {
+        // Once the first tile is loaded, calculate what
+        // the filmstrip should look like.
+        let animationData = anim.animationData;
+        let totalFrames = anim.totalFrames;
+        // t_rate mimics DMSrcSink.cpp::SkottieSrc::draw
+        let t_rate = 1.0 / (TILE_COUNT * TILE_COUNT - 1);
+
+        let main = document.querySelector('main');
+
+        // Clear out the first div now that our measurements are done.
+        main.firstElementChild.remove();
+
+        // Add in all the tiles.
+        for (let i = 0; i < TILE_COUNT*TILE_COUNT; i++) {
+          let div = document.createElement('div');
+          div.classList.add('anim');
+          div.style.width = (TARGET_SIZE / TILE_COUNT) + 'px';
+          div.style.height = (TARGET_SIZE / TILE_COUNT) + 'px';
+          main.appendChild(div);
+
+          // create a new animation for each tile. It is tempting to try having
+          // one animation and "clone" each frame, but that doesn't work
+          // because of how bodymovin cleans up the URLObjects that are the path
+          // data for the svgs.
+          // We can re-use the animationData to avoid having to hit the
+          // (local) network a bunch of times.
+          let anim = lottie.loadAnimation({
+            container: div,
+            renderer: renderer,
+            loop: false,
+            autoplay: false,
+            animationData: animationData,
+            rendererSettings: {
+              preserveAspectRatio:'xMidYMid meet'
+            },
+          });
+
+          let t = Math.max(Math.min(t_rate * i, 1.0), 0.0);
+          let seekToFrame = totalFrames * t;
+          if (seekToFrame >= totalFrames) {
+            // bodymovin player sometimes draws blank when requesting
+            // to draw the very last frame.  Subtracting a small value
+            // seems to fix this and make it draw the last frame.
+            seekToFrame -= .001;
+          }
+
+          // don't need to wait for data_ready because it's instantly ready.
+          console.log(`t = ${t}, go to frame ${seekToFrame}`);
+          anim.goToAndStop(seekToFrame, true);
+          window._tileCount += 1;
+        }
+      });
+    })();
+  </script>
+</body>
+</html>
diff --git a/src/third_party/skia/tools/lottiecap/lottiecap.js b/src/third_party/skia/tools/lottiecap/lottiecap.js
new file mode 100644
index 0000000..ba8123a
--- /dev/null
+++ b/src/third_party/skia/tools/lottiecap/lottiecap.js
@@ -0,0 +1,218 @@
+/**
+ * Command line application to build a 5x5 filmstrip from a Lottie file in the
+ * browser and then exporting that filmstrip in a 1000x1000 PNG.
+ *
+ */
+const puppeteer = require('puppeteer');
+const express = require('express');
+const fs = require('fs');
+const commandLineArgs = require('command-line-args');
+const commandLineUsage= require('command-line-usage');
+const fetch = require('node-fetch');
+
+// Valid values for the --renderer flag.
+const RENDERERS = ['svg', 'canvas'];
+
+const opts = [
+  {
+    name: 'input',
+    typeLabel: '{underline file}',
+    description: 'The Lottie JSON file to process.'
+  },
+  {
+    name: 'output',
+    typeLabel: '{underline file}',
+    description: 'The captured filmstrip PNG file to write. Defaults to filmstrip.png',
+  },
+  {
+    name: 'renderer',
+    typeLabel: '{underline mode}',
+    description: 'Which renderer to use, "svg" or "canvas". Defaults to "svg".',
+  },
+  {
+    name: 'port',
+    description: 'The port number to use, defaults to 8081.',
+    type: Number,
+  },
+  {
+    name: 'lottie_player',
+    description: 'The path to lottie.min.js, defaults to a local npm install location.',
+    type: String,
+  },
+  {
+    name: 'post_to',
+    description: 'If set, the url to post results to for Gold Ingestion.',
+    type: String,
+  },
+  {
+    name: 'in_docker',
+    description: 'Is this being run in docker, defaults to false',
+    type: Boolean,
+  },
+  {
+    name: 'skip_automation',
+    description: 'If the automation of the screenshot taking should be skipped ' +
+                 '(e.g. debugging). Defaults to false.',
+    type: Boolean,
+  },
+  {
+    name: 'help',
+    alias: 'h',
+    type: Boolean,
+    description: 'Print this usage guide.'
+  },
+];
+
+const usage = [
+  {
+    header: 'Lottie Filmstrip Capture',
+    content: `Command line application to build a 5x5 filmstrip
+from a Lottie file in the browser and then export
+that filmstrip in a 1000x1000 PNG.`
+  },
+  {
+    header: 'Options',
+    optionList: opts,
+  },
+];
+
+// Parse and validate flags.
+const options = commandLineArgs(opts);
+
+if (!options.output) {
+  options.output = 'filmstrip.png';
+}
+if (!options.port) {
+  options.port = 8081;
+}
+if (!options.lottie_player) {
+  options.lottie_player = 'node_modules/lottie-web/build/player/lottie.min.js';
+}
+
+if (options.help) {
+  console.log(commandLineUsage(usage));
+  process.exit(0);
+}
+
+if (!options.input) {
+  console.error('You must supply a Lottie JSON filename.');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+if (!options.renderer) {
+  options.renderer = 'svg';
+}
+
+if (!RENDERERS.includes(options.renderer)) {
+  console.error('The --renderer flag must have as a value one of: ', RENDERERS);
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+// Start up a web server to serve the three files we need.
+let lottieJS = fs.readFileSync(options.lottie_player, 'utf8');
+let driverHTML = fs.readFileSync('driver.html', 'utf8');
+let lottieJSON = fs.readFileSync(options.input, 'utf8');
+
+const app = express();
+app.get('/', (req, res) => res.send(driverHTML));
+app.get('/lottie.js', (req, res) => res.send(lottieJS));
+app.get('/lottie.json', (req, res) => res.send(lottieJSON));
+app.listen(options.port, () => console.log('- Local web server started.'))
+
+// Utiltity function.
+async function wait(ms) {
+    await new Promise(resolve => setTimeout(() => resolve(), ms));
+    return ms;
+}
+
+const targetURL = `http://localhost:${options.port}/#${options.renderer}`;
+
+// Drive chrome to load the web page from the server we have running.
+async function driveBrowser() {
+  console.log('- Launching chrome in headless mode.');
+  let browser = null;
+  if (options.in_docker) {
+    browser = await puppeteer.launch({
+      'executablePath': '/usr/bin/google-chrome-stable',
+      'args': ['--no-sandbox'],
+    });
+  } else {
+    browser = await puppeteer.launch();
+  }
+
+  const page = await browser.newPage();
+  console.log(`- Loading our Lottie exercising page for ${options.input}.`);
+  try {
+     // 20 seconds is plenty of time to wait for the json to be loaded once
+     // This usually times out for super large json.
+    await page.goto(targetURL, {
+      timeout: 20000,
+      waitUntil: 'networkidle0'
+    });
+    // 20 seconds is plenty of time to wait for the frames to be drawn.
+    // This usually times out for json that causes errors in the player.
+    console.log('- Waiting 15s for all the tiles to be drawn.');
+    await page.waitForFunction('window._tileCount === 25', {
+      timeout: 20000,
+    });
+  } catch(e) {
+    console.log('Timed out while loading or drawing. Either the JSON file was ' +
+                'too big or hit a bug in the player.', e);
+    await browser.close();
+    process.exit(0);
+  }
+
+  console.log('- Taking screenshot.');
+  let encoding = 'binary';
+  if (options.post_to) {
+    encoding = 'base64';
+    // prevent writing the image to disk
+    options.output = '';
+  }
+
+  // See https://github.com/GoogleChrome/puppeteer/blob/v1.6.0/docs/api.md#pagescreenshotoptions
+  let result = await page.screenshot({
+    path: options.output,
+    type: 'png',
+    clip: {
+      x: 0,
+      y: 0,
+      width: 1000,
+      height: 1000,
+    },
+    encoding: encoding,
+  });
+
+  if (options.post_to) {
+    console.log(`- Reporting ${options.input} to Gold server ${options.post_to}`);
+    let shortenedName = options.input;
+    let lastSlash = shortenedName.lastIndexOf('/');
+    if (lastSlash !== -1) {
+      shortenedName = shortenedName.slice(lastSlash+1);
+    }
+    await fetch(options.post_to, {
+        method: 'POST',
+        mode: 'no-cors',
+        headers: {
+            'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+            'data': result,
+            'test_name': shortenedName,
+        })
+    });
+  }
+
+  await browser.close();
+  // Need to call exit() because the web server is still running.
+  process.exit(0);
+}
+
+if (!options.skip_automation) {
+  driveBrowser();
+} else {
+  console.log(`open ${targetURL} to see the animation.`)
+}
+
diff --git a/src/third_party/skia/tools/lottiecap/package.json b/src/third_party/skia/tools/lottiecap/package.json
new file mode 100644
index 0000000..6bce532
--- /dev/null
+++ b/src/third_party/skia/tools/lottiecap/package.json
@@ -0,0 +1,10 @@
+{
+  "dependencies": {
+    "command-line-args": "^5.0.2",
+    "command-line-usage": "^5.0.3",
+    "express": "^4.16.3",
+    "lottie-web": "5.2.1",
+    "node-fetch": "^2.2.0",
+    "puppeteer": "~1.6.2"
+  }
+}
diff --git a/src/third_party/skia/tools/lua/lua_app.cpp b/src/third_party/skia/tools/lua/lua_app.cpp
index 68e1a8d..0c1723e 100644
--- a/src/third_party/skia/tools/lua/lua_app.cpp
+++ b/src/third_party/skia/tools/lua/lua_app.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "SkLua.h"
-#include "SkGraphics.h"
-#include "SkStream.h"
-#include "SkData.h"
-#include "SkOSFile.h"
+#include "include/core/SkData.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkStream.h"
+#include "include/utils/SkLua.h"
+#include "src/core/SkOSFile.h"
 
 #include <stdlib.h>
 
diff --git a/src/third_party/skia/tools/lua/lua_pictures.cpp b/src/third_party/skia/tools/lua/lua_pictures.cpp
index 85fbd98..faf9be4 100644
--- a/src/third_party/skia/tools/lua/lua_pictures.cpp
+++ b/src/third_party/skia/tools/lua/lua_pictures.cpp
@@ -5,16 +5,15 @@
  * found in the LICENSE file.
  */
 
-#include "SkLua.h"
-#include "SkLuaCanvas.h"
-#include "SkPicture.h"
-#include "SkCommandLineFlags.h"
-#include "SkGraphics.h"
-#include "SkStream.h"
-#include "SkData.h"
-#include "picture_utils.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
+#include "include/core/SkData.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "include/utils/SkLua.h"
+#include "include/utils/SkLuaCanvas.h"
+#include "src/core/SkOSFile.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/flags/CommandLineFlags.h"
 
 #include <stdlib.h>
 
@@ -64,8 +63,8 @@
 }
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("apply lua script to .skp files.");
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::SetUsage("apply lua script to .skp files.");
+    CommandLineFlags::Parse(argc, argv);
 
     if (FLAGS_skpPath.isEmpty()) {
         SkDebugf(".skp files or directories are required.\n");
diff --git a/src/third_party/skia/tools/malisc/malisc.py b/src/third_party/skia/tools/malisc/malisc.py
new file mode 100644
index 0000000..d437e61
--- /dev/null
+++ b/src/third_party/skia/tools/malisc/malisc.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import subprocess
+import sys
+
+if len(sys.argv) != 3:
+    print sys.argv[0], ' <compiler> <folder>'
+    sys.exit(1)
+
+compiler = sys.argv[1]
+folder = sys.argv[2]
+
+stats = {}
+
+for filename in os.listdir(folder):
+    basename, ext = os.path.splitext(filename)
+    if ext not in ['.frag', '.spv']:
+        continue
+    cmdline = [compiler]
+    if ext == '.spv':
+        cmdline.extend(['-f', '-p'])
+    cmdline.append(os.path.join(folder, filename))
+    try:
+        output = subprocess.check_output(cmdline)
+    except subprocess.CalledProcessError:
+        continue
+    stats.setdefault(basename, {})
+    for line in output.splitlines():
+        if line.startswith('Instructions Emitted'):
+            inst = line.split(':')[1].split()
+            stats[basename][ext] = inst
+
+for k, v in stats.iteritems():
+    gl = v.get('.frag', ['', '', ''])
+    vk = v.get('.spv', ['', '', ''])
+    print '{0},{1},{2},{3},{4},{5},{6}'.format(k, gl[0], gl[1], gl[2], vk[0], vk[1], vk[2])
diff --git a/src/third_party/skia/tools/mdbviz/Model.cpp b/src/third_party/skia/tools/mdbviz/Model.cpp
new file mode 100644
index 0000000..0243d00
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/Model.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <memory>
+
+#include "tools/mdbviz/Model.h"
+
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "tools/debugger/DebugCanvas.h"
+
+Model::Model() : fCurOp(0) {
+    SkImageInfo ii = SkImageInfo::MakeN32Premul(1024, 1024);
+    fBM.allocPixels(ii, 0);
+}
+
+Model::~Model() {
+    this->resetOpsTask();
+}
+
+Model::ErrorCode Model::load(const char* filename) {
+    std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(filename);
+    if (!stream) {
+        return ErrorCode::kCouldntOpenFile;
+    }
+    sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
+    if (!pic) {
+        return ErrorCode::kCouldntDecodeSKP;
+    }
+
+    {
+        std::unique_ptr<DebugCanvas> temp(
+                new DebugCanvas(SkScalarCeilToInt(pic->cullRect().width()),
+                                SkScalarCeilToInt(pic->cullRect().height())));
+
+        temp->setPicture(pic.get());
+        pic->playback(temp.get());
+        temp->setPicture(nullptr);
+        this->resetOpsTask();
+        temp->detachCommands(&fOps);
+    }
+
+    this->setCurOp(fOps.count()-1);
+
+    return ErrorCode::kOK;
+}
+
+const char* Model::ErrorString(ErrorCode err) {
+    static const char* kStrings[] = {
+        "OK",
+        "Couldn't read file",
+        "Couldn't decode picture"
+    };
+
+    return kStrings[(int)err];
+}
+
+const char* Model::getOpName(int index) const {
+    return DrawCommand::GetCommandString(fOps[index]->getType());
+}
+
+bool Model::isHierarchyPush(int index) const {
+    DrawCommand::OpType type = fOps[index]->getType();
+
+    return DrawCommand::kSave_OpType == type || DrawCommand::kSaveLayer_OpType == type ||
+           DrawCommand::kBeginDrawPicture_OpType == type;
+}
+
+bool Model::isHierarchyPop(int index) const {
+    DrawCommand::OpType type = fOps[index]->getType();
+
+    return DrawCommand::kRestore_OpType == type || DrawCommand::kEndDrawPicture_OpType == type;
+}
+
+void Model::setCurOp(int curOp) {
+    SkASSERT(curOp < fOps.count());
+
+    if (curOp == fCurOp) {
+        return; // the render state is already up to date
+    }
+
+    fCurOp = curOp;
+    this->drawTo(fCurOp);
+}
+
+void Model::drawTo(int index) {
+    SkASSERT(index < fOps.count());
+
+    SkCanvas canvas(fBM);
+
+    int saveCount = canvas.save();
+
+    for (int i = 0; i <= index; ++i) {
+        if (fOps[i]->isVisible()) {
+            fOps[i]->execute(&canvas);
+        }
+    }
+
+    canvas.restoreToCount(saveCount);
+}
+
+void Model::resetOpsTask() {
+    for (int i = 0; i < fOps.count(); ++i) {
+        delete fOps[i];
+    }
+    fOps.reset();
+    fCurOp = 0;
+}
diff --git a/src/third_party/skia/tools/mdbviz/Model.h b/src/third_party/skia/tools/mdbviz/Model.h
new file mode 100644
index 0000000..f3bc99d
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/Model.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkBitmap.h"
+#include "include/private/SkTDArray.h"
+
+class DrawCommand;
+
+// This class encapsulates the both the in-memory representation of the draw ops
+// and the state of Skia/Ganesh's rendering. It should never have any Qt intrusions.
+class Model {
+public:
+    enum class ErrorCode {
+        kOK,
+        kCouldntOpenFile,
+        kCouldntDecodeSKP
+    };
+
+    Model();
+    ~Model();
+
+    static const char* ErrorString(ErrorCode);
+
+    // Replace the list of draw ops by reading the provided skp filename and
+    // reset the Skia draw state. It is up to the view portion to update itself
+    // after this call (i.e., rebuild the opsTask view).
+    ErrorCode load(const char* filename);
+
+    // Update the rendering state to the provided op
+    void setCurOp(int curOp);
+    int curOp() const { return fCurOp; }
+
+    int numOps() const { return fOps.count(); }
+    const char* getOpName(int index) const;
+
+    bool isHierarchyPush(int index) const;
+    bool isHierarchyPop(int index) const;
+
+    // Get the bits visually representing the current rendering state
+    void* getPixels() const { return fBM.getPixels(); }
+    int width() const { return fBM.width(); }
+    int height() const { return fBM.height(); }
+
+protected:
+    // draw the ops up to (and including) the index-th op
+    void drawTo(int index);
+    void resetOpsTask();
+
+private:
+    SkTDArray<DrawCommand*>   fOps;
+    int                       fCurOp;  // The current op the rendering state is at
+    SkBitmap                  fBM;
+};
diff --git a/src/third_party/skia/tools/mdbviz/images/open.png b/src/third_party/skia/tools/mdbviz/images/open.png
new file mode 100644
index 0000000..6043f4b
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/images/open.png
Binary files differ
diff --git a/src/third_party/skia/tools/mdbviz/main.cpp b/src/third_party/skia/tools/mdbviz/main.cpp
new file mode 100644
index 0000000..6679871
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/main.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <QtWidgets>
+
+#include "tools/mdbviz/mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+    QApplication app(argc, argv);
+    QCoreApplication::setOrganizationName("Google");
+    QCoreApplication::setApplicationName("MDB Viz");
+    QCoreApplication::setApplicationVersion("0.0");
+
+    QCommandLineParser parser;
+    parser.setApplicationDescription(QCoreApplication::applicationName());
+    parser.addVersionOption();
+    parser.process(app);
+
+    MainWindow mainWin;
+    mainWin.show();
+
+    return app.exec();
+}
+
+
diff --git a/src/third_party/skia/tools/mdbviz/mainwindow.cpp b/src/third_party/skia/tools/mdbviz/mainwindow.cpp
new file mode 100644
index 0000000..e36f81a
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/mainwindow.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <QtWidgets>
+
+#include "MainWindow.h"
+
+MainWindow::MainWindow() {
+    this->createActions();
+    this->createStatusBar();
+    this->createDockWindows();
+
+    this->setWindowTitle("MDB Viz");
+
+    this->readSettings();
+    this->setUnifiedTitleAndToolBarOnMac(true);
+}
+
+void MainWindow::openFile() {
+    QString fileName = QFileDialog::getOpenFileName(this);
+    if (!fileName.isEmpty()) {
+        this->loadFile(fileName);
+    }
+}
+
+void MainWindow::setupOpsTaskWidget() {
+    fOpsTaskWidget->clear();
+
+    QTreeWidgetItem* item = nullptr;
+    SkTDArray<QTreeWidgetItem*> parents;
+
+    for (int i = 0; i < fModel.numOps(); i++) {
+        item = new QTreeWidgetItem();
+
+        item->setText(0, QString::number(i));
+        item->setData(0, Qt::UserRole, i);
+        item->setText(1, fModel.getOpName(i));
+
+        if (fModel.isHierarchyPop(i)) {
+            parents.pop();
+        }
+
+        if (parents.isEmpty()) {
+            fOpsTaskWidget->addTopLevelItem(item);
+        } else {
+            parents.top()->addChild(item);
+        }
+
+        if (fModel.isHierarchyPush(i)) {
+            *parents.push() = item;
+        }
+    }
+
+    fOpsTaskWidget->setCurrentItem(item);
+    fOpsTaskWidget->expandToDepth(100);
+}
+
+void MainWindow::presentCurrentRenderState() {
+    fImage = QImage((uchar*)fModel.getPixels(), fModel.width(), fModel.height(),
+                    QImage::Format_RGBA8888);
+    fImageLabel->setPixmap(QPixmap::fromImage(fImage));
+}
+
+void MainWindow::loadFile(const QString &fileName) {
+    QFile file(fileName);
+    if (!file.open(QFile::ReadOnly | QFile::Text)) {
+        QMessageBox::warning(this, tr("MDB Viz"),
+                             tr("Cannot read file %1:\n%2.")
+                             .arg(QDir::toNativeSeparators(fileName), file.errorString()));
+        return;
+    }
+
+    QTextStream in(&file);
+#ifndef QT_NO_CURSOR
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+#endif
+
+    std::string str = file.fileName().toLocal8Bit().constData();
+
+    Model::ErrorCode err = fModel.load(str.c_str());
+    if (Model::ErrorCode::kOK != err) {
+        this->statusBar()->showMessage(Model::ErrorString(err));
+        return;
+    }
+
+    this->setupOpsTaskWidget();
+    this->presentCurrentRenderState();
+
+#ifndef QT_NO_CURSOR
+    QApplication::restoreOverrideCursor();
+#endif
+}
+
+
+void MainWindow::about() {
+   QMessageBox::about(this, "About MDB Viz", "Visualize MDB");
+}
+
+void MainWindow::createActions() {
+
+    // File menu
+    QMenu* fileMenu = this->menuBar()->addMenu(tr("&File"));
+    QToolBar* fileToolBar = this->addToolBar(tr("File"));
+
+    const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/images/open.png"));
+    QAction* openAct = new QAction(openIcon, tr("&Open..."), this);
+    openAct->setShortcuts(QKeySequence::Open);
+    openAct->setStatusTip(tr("Open an existing file"));
+    connect(openAct, &QAction::triggered, this, &MainWindow::openFile);
+    fileMenu->addAction(openAct);
+    fileToolBar->addAction(openAct);
+
+    fileMenu->addSeparator();
+
+    const QIcon exitIcon = QIcon::fromTheme("application-exit");
+    QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close);
+    exitAct->setShortcuts(QKeySequence::Quit);
+    exitAct->setStatusTip(tr("Exit the application"));
+
+    // View menu
+    fViewMenu = this->menuBar()->addMenu(tr("&View"));
+
+    // Help menu
+    this->menuBar()->addSeparator();
+
+    QMenu* helpMenu = this->menuBar()->addMenu(tr("&Help"));
+
+    QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+    aboutAct->setStatusTip(tr("Show the application's About box"));
+}
+
+void MainWindow::onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* /* prev */) {
+    int currentRow = cur->data(0, Qt::UserRole).toInt();
+    fModel.setCurOp(currentRow);
+    this->presentCurrentRenderState();
+}
+
+void MainWindow::createStatusBar() {
+    this->statusBar()->showMessage(tr("Ready"));
+}
+
+void MainWindow::createDockWindows() {
+
+    // Op List Window
+    {
+        QDockWidget* opsTaskDock = new QDockWidget("Ops", this);
+        opsTaskDock->setAllowedAreas(Qt::LeftDockWidgetArea);
+
+        fOpsTaskWidget = new QTreeWidget(opsTaskDock);
+
+        QTreeWidgetItem* headerItem = new QTreeWidgetItem;
+        headerItem->setText(0, "Index");
+        headerItem->setText(1, "Op Name");
+        fOpsTaskWidget->setHeaderItem(headerItem);
+
+        fOpsTaskWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+        fOpsTaskWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+
+        opsTaskDock->setWidget(fOpsTaskWidget);
+        this->addDockWidget(Qt::LeftDockWidgetArea, opsTaskDock);
+
+        fViewMenu->addAction(opsTaskDock->toggleViewAction());
+
+        connect(fOpsTaskWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
+                this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
+    }
+
+    // Main canvas Window
+    {
+        QDockWidget* mainCanvasDock = new QDockWidget("Main Canvas", this);
+        mainCanvasDock->setAllowedAreas(Qt::RightDockWidgetArea);
+
+        fImageLabel = new QLabel(mainCanvasDock);
+
+        fImage = QImage(1024, 1024, QImage::Format_RGBA8888);
+        fImage.fill(0);
+        fImageLabel->setPixmap(QPixmap::fromImage(fImage));
+
+        mainCanvasDock->setWidget(fImageLabel);
+        this->addDockWidget(Qt::RightDockWidgetArea, mainCanvasDock);
+
+        fViewMenu->addAction(mainCanvasDock->toggleViewAction());
+    }
+}
+
+void MainWindow::readSettings() {
+    QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+    const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
+    if (geometry.isEmpty()) {
+        const QRect availableGeometry = QApplication::desktop()->availableGeometry(this);
+        resize(availableGeometry.width() / 3, availableGeometry.height() / 2);
+        move((availableGeometry.width() - width()) / 2,
+             (availableGeometry.height() - height()) / 2);
+    } else {
+        this->restoreGeometry(geometry);
+    }
+}
+
+void MainWindow::writeSettings() {
+    QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
+    settings.setValue("geometry", this->saveGeometry());
+}
diff --git a/src/third_party/skia/tools/mdbviz/mainwindow.h b/src/third_party/skia/tools/mdbviz/mainwindow.h
new file mode 100644
index 0000000..f80b157
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/mainwindow.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef MainWindow_DEFINED
+#define MainWindow_DEFINED
+
+#include <memory>
+#include <QMainWindow>
+
+#include "tools/mdbviz/Model.h"
+
+class QLabel;
+class QMenu;
+class QTreeWidget;
+class QTreeWidgetItem;
+
+
+class MainWindow : public QMainWindow {
+    Q_OBJECT
+
+public:
+    MainWindow();
+
+private slots:
+    void openFile();
+    void about();
+    void onCurrentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* prev);
+
+private:
+    void loadFile(const QString &fileName);
+    void setupOpsTaskWidget();
+    void presentCurrentRenderState();
+
+
+    void createActions();
+    void createStatusBar();
+    void createDockWindows();
+
+    void readSettings();
+    void writeSettings();
+
+    QImage  fImage;
+    QLabel* fImageLabel;
+
+    QTreeWidget* fOpsTaskWidget;
+
+    QMenu* fViewMenu;
+
+    Model fModel;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/mdbviz/resources.qrc b/src/third_party/skia/tools/mdbviz/resources.qrc
new file mode 100644
index 0000000..e3e2dc0
--- /dev/null
+++ b/src/third_party/skia/tools/mdbviz/resources.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+  <file>images/open.png</file>
+</qresource>
+</RCC>
\ No newline at end of file
diff --git a/src/third_party/skia/tools/merge_static_libs.py b/src/third_party/skia/tools/merge_static_libs.py
index 842be18..a32c3a5 100755
--- a/src/third_party/skia/tools/merge_static_libs.py
+++ b/src/third_party/skia/tools/merge_static_libs.py
@@ -15,7 +15,7 @@
 
 def MergeLibs(in_libs, out_lib):
   """ Merges multiple static libraries into one.
-  
+
   in_libs: list of paths to static libraries to be merged
   out_lib: path to the static library which will be created from in_libs
   """
@@ -38,12 +38,12 @@
       proc.wait()
       if proc.poll() == 0:
         # The static library is non-thin, and we extracted objects
-        for object in current_objects:
-          objects.append(os.path.abspath(object))
+        for obj in current_objects:
+          objects.append(os.path.abspath(obj))
       elif 'thin archive' in proc.communicate()[0]:
         # The static library is thin, so it contains the paths to its objects
-        for object in current_objects:
-          objects.append(object)
+        for obj in current_objects:
+          objects.append(obj)
       else:
         raise Exception('Failed to extract objects from %s.' % in_lib)
     os.chdir(curdir)
diff --git a/src/third_party/skia/tools/mirror-dev.sh b/src/third_party/skia/tools/mirror-dev.sh
index 0512a78..47786de 100755
--- a/src/third_party/skia/tools/mirror-dev.sh
+++ b/src/third_party/skia/tools/mirror-dev.sh
@@ -1,5 +1,9 @@
+# Copyright 2013 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
  # For each installed *-dev package DEV
- for DEV in $(dpkg --list | grep '^ii  [^ ]' | cut -d ' ' -f 3 | grep '\-dev$')
+ for DEV in $(dpkg --list | grep '^ii  [^ ]' | cut -d ' ' -f 3 | grep -P '\-dev($|\:amd64$)')
  do
      # For each multi-arch *.so SO installed by DEV
      for DEV_64_SO in $(dpkg -L $DEV | grep '/lib/x86_64-linux-gnu/.*\.so$')
@@ -10,14 +14,14 @@
             echo "$DEV installed $DEV_64_SO which is real."
             continue
         fi
- 
+
         DEV_64_TARGET=$(readlink $DEV_64_SO)
-        DEV_64_TARGET_FULL=$(readlink -f $DEV_64_SO) 
- 
+        DEV_64_TARGET_FULL=$(readlink -f $DEV_64_SO)
+
         DEV_32_SO=$(echo $DEV_64_SO | sed -e 's@/lib/x86_64-linux-gnu/@/lib/i386-linux-gnu/@')
         DEV_32_TARGET=$(echo $DEV_64_TARGET | sed -e 's@/lib/x86_64-linux-gnu/@/lib/i386-linux-gnu/@')
         DEV_32_TARGET_FULL=$(echo $DEV_64_TARGET_FULL | sed -e 's@/lib/x86_64-linux-gnu/@/lib/i386-linux-gnu/@')
- 
+
         # Error if DEV_32_TARGET does not exist.
         if ! test -e $DEV_32_TARGET_FULL
         then
@@ -27,7 +31,7 @@
             #echo "   $DEV_32_SO -> $DEV_32_TARGET ($DEV_32_TARGET_FULL)"
             continue
         fi
- 
+
         # Create DEV_32_SO
         sudo ln -s $DEV_32_TARGET $DEV_32_SO
      done
diff --git a/src/third_party/skia/tools/monobench.cpp b/src/third_party/skia/tools/monobench.cpp
deleted file mode 100644
index ff0abc2..0000000
--- a/src/third_party/skia/tools/monobench.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Benchmark.h"
-#include "OverwriteLine.h"
-#include "SkGraphics.h"
-#include "SkSurface.h"
-#include "SkTaskGroup.h"
-#include <algorithm>
-#include <chrono>
-#include <limits>
-#include <regex>
-#include <stdlib.h>
-#include <string>
-#include <vector>
-
-
-#if defined(SK_BUILD_FOR_WIN32)
-static const char* kEllipsis = "...";
-#else
-static const char* kEllipsis = "…";
-#endif
-
-int main(int argc, char** argv) {
-    SkGraphics::Init();
-    SkTaskGroup::Enabler enabled;
-
-    using clock = std::chrono::high_resolution_clock;
-    using ns = std::chrono::duration<double, std::nano>;
-
-    std::regex pattern;
-    int limit = 2147483647;
-    if (argc > 1) { pattern = argv[1]; }
-    if (argc > 2) { limit = atoi(argv[2]); }
-
-    struct Bench {
-        std::unique_ptr<Benchmark> b;
-        std::string                name;
-        ns                         best;
-    };
-    std::vector<Bench> benches;
-
-    for (auto r = BenchRegistry::Head(); r; r = r->next()) {
-        std::unique_ptr<Benchmark> bench{ r->factory()(nullptr) };
-
-        std::string name = bench->getName();
-        if (std::regex_search(name, pattern) &&
-                (bench->isSuitableFor(Benchmark::kNonRendering_Backend) ||
-                 bench->isSuitableFor(Benchmark::      kRaster_Backend))) {
-            bench->delayedSetup();
-            benches.emplace_back(Bench{std::move(bench), name,
-                                       ns{std::numeric_limits<double>::infinity()}});
-        }
-    }
-
-    if (benches.size() == 0) {
-        SkDebugf("No bench matched.\n");
-        return 1;
-    }
-
-    if (benches.size() > 1) {
-        int common_prefix = benches[0].name.size();
-        for (size_t i = 1; i < benches.size(); i++) {
-            int len = std::mismatch(benches[i-1].name.begin(), benches[i-1].name.end(),
-                                    benches[i-0].name.begin())
-                .first - benches[i-1].name.begin();
-            common_prefix = std::min(common_prefix, len);
-        }
-        std::string prefix = benches[0].name.substr(0, common_prefix);
-        if (common_prefix) {
-            for (auto& bench : benches) {
-                bench.name.replace(0, common_prefix, kEllipsis);
-            }
-        }
-
-        int common_suffix = benches[0].name.size();
-        for (size_t i = 1; i < benches.size(); i++) {
-            int len = std::mismatch(benches[i-1].name.rbegin(), benches[i-1].name.rend(),
-                                    benches[i-0].name.rbegin())
-                .first - benches[i-1].name.rbegin();
-            common_suffix = std::min(common_suffix, len);
-        }
-        std::string suffix = benches[0].name.substr(benches[0].name.size() - common_suffix);
-        if (common_suffix) {
-            for (auto& bench : benches) {
-                bench.name.replace(bench.name.size() - common_suffix, common_suffix, kEllipsis);
-            }
-        }
-
-        SkDebugf("%s%s%s\n", prefix.c_str(), kEllipsis, suffix.c_str());
-    }
-
-    int samples = 0;
-    while (samples < limit) {
-        std::random_shuffle(benches.begin(), benches.end());
-        for (auto& bench : benches) {
-            sk_sp<SkSurface> dst;
-            SkCanvas* canvas = nullptr;
-            if (!bench.b->isSuitableFor(Benchmark::kNonRendering_Backend)) {
-                dst = SkSurface::MakeRaster(SkImageInfo::MakeS32(bench.b->getSize().x(),
-                                                                 bench.b->getSize().y(),
-                                                                 kPremul_SkAlphaType));
-                canvas = dst->getCanvas();
-                bench.b->perCanvasPreDraw(canvas);
-            }
-            for (int loops = 1; loops < 1000000000;) {
-
-                bench.b->preDraw(canvas);
-                auto start = clock::now();
-                    bench.b->draw(loops, canvas);
-                ns elapsed = clock::now() - start;
-                bench.b->postDraw(canvas);
-
-                if (elapsed < std::chrono::milliseconds{10}) {
-                    loops *= 2;
-                    continue;
-                }
-
-                bench.best = std::min(bench.best, elapsed / loops);
-                samples++;
-
-                struct Result { const char* name; ns best; };
-                std::vector<Result> sorted(benches.size());
-                for (size_t i = 0; i < benches.size(); i++) {
-                    sorted[i].name = benches[i].name.c_str();
-                    sorted[i].best = benches[i].best;
-                }
-                std::sort(sorted.begin(), sorted.end(), [](const Result& a, const Result& b) {
-                    return a.best < b.best;
-                });
-
-                SkDebugf("%s%d", kSkOverwriteLine, samples);
-                for (auto& result : sorted) {
-                    if (sorted.size() == 1) {
-                        SkDebugf("  %s %gns" , result.name, result.best.count());
-                    } else {
-                        SkDebugf("  %s %.3gx", result.name, result.best / sorted[0].best);
-                    }
-                }
-                break;
-            }
-            if (canvas) {
-                bench.b->perCanvasPostDraw(canvas);
-            }
-        }
-    }
-
-    return 0;
-}
diff --git a/src/third_party/skia/tools/ok.cpp b/src/third_party/skia/tools/ok.cpp
deleted file mode 100644
index edda9be..0000000
--- a/src/third_party/skia/tools/ok.cpp
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// ok is an experimental test harness, maybe to replace DM.  Key features:
-//   * work is balanced across separate processes for stability and isolation;
-//   * ok is entirely opt-in.  No more maintaining huge --blacklists.
-
-#include "SkGraphics.h"
-#include "SkImage.h"
-#include "ok.h"
-#include <chrono>
-#include <future>
-#include <list>
-#include <stdio.h>
-#include <stdlib.h>
-#include <thread>
-#include <vector>
-
-#if !defined(__has_include)
-    #define  __has_include(x) 0
-#endif
-
-static thread_local const char* tls_currently_running = "";
-
-#if __has_include(<execinfo.h>) && __has_include(<fcntl.h>) && __has_include(<signal.h>)
-    #include <execinfo.h>
-    #include <fcntl.h>
-    #include <signal.h>
-
-    static int log_fd = 2/*stderr*/;
-
-    static void log(const char* msg) {
-        write(log_fd, msg, strlen(msg));
-    }
-
-    static void setup_crash_handler() {
-        static void (*original_handlers[32])(int);
-        for (int sig : std::vector<int>{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }) {
-            original_handlers[sig] = signal(sig, [](int sig) {
-                lockf(log_fd, F_LOCK, 0);
-                    log("\ncaught signal ");
-                    switch (sig) {
-                    #define CASE(s) case s: log(#s); break
-                        CASE(SIGABRT);
-                        CASE(SIGBUS);
-                        CASE(SIGFPE);
-                        CASE(SIGILL);
-                        CASE(SIGSEGV);
-                    #undef CASE
-                    }
-                    log(" while running '");
-                    log(tls_currently_running);
-                    log("'\n");
-
-                    void* stack[128];
-                    int frames = backtrace(stack, sizeof(stack)/sizeof(*stack));
-                    backtrace_symbols_fd(stack, frames, log_fd);
-                lockf(log_fd, F_ULOCK, 0);
-
-                signal(sig, original_handlers[sig]);
-                raise(sig);
-            });
-        }
-    }
-
-    static void defer_logging() {
-        log_fd = fileno(tmpfile());
-        atexit([] {
-            lseek(log_fd, 0, SEEK_SET);
-            char buf[1024];
-            while (size_t bytes = read(log_fd, buf, sizeof(buf))) {
-                write(2, buf, bytes);
-            }
-        });
-    }
-
-    void ok_log(const char* msg) {
-        lockf(log_fd, F_LOCK, 0);
-            log("[");
-            log(tls_currently_running);
-            log("]\t");
-            log(msg);
-            log("\n");
-        lockf(log_fd, F_ULOCK, 0);
-    }
-
-#else
-    static void setup_crash_handler() {}
-    static void defer_logging() {}
-
-    void ok_log(const char* msg) {
-        fprintf(stderr, "%s\n", msg);
-    }
-#endif
-
-struct Engine {
-    virtual ~Engine() {}
-    virtual bool spawn(std::function<Status(void)>) = 0;
-    virtual Status wait_one() = 0;
-};
-
-struct SerialEngine : Engine {
-    Status last = Status::None;
-
-    bool spawn(std::function<Status(void)> fn) override {
-        last = fn();
-        return true;
-    }
-
-    Status wait_one() override {
-        Status s = last;
-        last = Status::None;
-        return s;
-    }
-};
-
-struct ThreadEngine : Engine {
-    std::list<std::future<Status>> live;
-    const std::chrono::steady_clock::time_point the_past = std::chrono::steady_clock::now();
-
-    bool spawn(std::function<Status(void)> fn) override {
-        live.push_back(std::async(std::launch::async, fn));
-        return true;
-    }
-
-    Status wait_one() override {
-        if (live.empty()) {
-            return Status::None;
-        }
-
-        for (;;) {
-            for (auto it = live.begin(); it != live.end(); it++) {
-                if (it->wait_until(the_past) == std::future_status::ready) {
-                    Status s = it->get();
-                    live.erase(it);
-                    return s;
-                }
-            }
-        }
-    }
-};
-
-#if defined(_MSC_VER)
-    using ForkEngine = ThreadEngine;
-#else
-    #include <sys/wait.h>
-    #include <unistd.h>
-
-    struct ForkEngine : Engine {
-        bool spawn(std::function<Status(void)> fn) override {
-            switch (fork()) {
-                case  0: _exit((int)fn());
-                case -1: return false;
-                default: return true;
-            }
-        }
-
-        Status wait_one() override {
-            do {
-                int status;
-                if (wait(&status) > 0) {
-                    return WIFEXITED(status) ? (Status)WEXITSTATUS(status)
-                                             : Status::Crashed;
-                }
-            } while (errno == EINTR);
-            return Status::None;
-        }
-    };
-#endif
-
-struct StreamType {
-    const char *name, *help;
-    std::unique_ptr<Stream> (*factory)(Options);
-};
-static std::vector<StreamType> stream_types;
-
-struct DstType {
-    const char *name, *help;
-    std::unique_ptr<Dst> (*factory)(Options);
-};
-static std::vector<DstType> dst_types;
-
-struct ViaType {
-    const char *name, *help;
-    std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>);
-};
-static std::vector<ViaType> via_types;
-
-template <typename T>
-static std::string help_for(std::vector<T> registered) {
-    std::string help;
-    for (auto r : registered) {
-        help += "\n    ";
-        help += r.name;
-        help += ": ";
-        help += r.help;
-    }
-    return help;
-}
-
-int main(int argc, char** argv) {
-    SkGraphics::Init();
-    setup_crash_handler();
-
-    int                                       jobs{1};
-    std::unique_ptr<Stream>                   stream;
-    std::function<std::unique_ptr<Dst>(void)> dst_factory = []{
-        // A default Dst that's enough for unit tests and not much else.
-        struct : Dst {
-            Status draw(Src* src)  override { return src->draw(nullptr); }
-            sk_sp<SkImage> image() override { return nullptr; }
-        } dst;
-        return move_unique(dst);
-    };
-
-    auto help = [&] {
-        std::string stream_help = help_for(stream_types),
-                       dst_help = help_for(   dst_types),
-                       via_help = help_for(   via_types);
-
-        printf("%s [-j N] src[:k=v,...] dst[:k=v,...] [via[:k=v,...] ...]            \n"
-                "  -j: Run at most N processes at any time.                          \n"
-                "      If <0, use -N threads instead.                                \n"
-                "      If 0, use one thread in one process.                          \n"
-                "      If 1 (default) or -1, auto-detect N.                          \n"
-                " src: content to draw%s                                             \n"
-                " dst: how to draw that content%s                                    \n"
-                " via: wrappers around dst%s                                         \n"
-                " Most srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n",
-                argv[0], stream_help.c_str(), dst_help.c_str(), via_help.c_str());
-        return 1;
-    };
-
-    for (int i = 1; i < argc; i++) {
-        if (0 == strcmp("-j",     argv[i])) { jobs = atoi(argv[++i]); }
-        if (0 == strcmp("-h",     argv[i])) { return help(); }
-        if (0 == strcmp("--help", argv[i])) { return help(); }
-
-        for (auto s : stream_types) {
-            size_t len = strlen(s.name);
-            if (0 == strncmp(s.name, argv[i], len)) {
-                switch (argv[i][len]) {
-                    case  ':': len++;
-                    case '\0': stream = s.factory(Options{argv[i]+len});
-                }
-            }
-        }
-        for (auto d : dst_types) {
-            size_t len = strlen(d.name);
-            if (0 == strncmp(d.name, argv[i], len)) {
-                switch (argv[i][len]) {
-                    case  ':': len++;
-                    case '\0': dst_factory = [=]{
-                                   return d.factory(Options{argv[i]+len});
-                               };
-                }
-            }
-        }
-        for (auto v : via_types) {
-            size_t len = strlen(v.name);
-            if (0 == strncmp(v.name, argv[i], len)) {
-                if (!dst_factory) { return help(); }
-                switch (argv[i][len]) {
-                    case  ':': len++;
-                    case '\0': dst_factory = [=]{
-                                   return v.factory(Options{argv[i]+len}, dst_factory());
-                               };
-                }
-            }
-        }
-    }
-    if (!stream) { return help(); }
-
-    std::unique_ptr<Engine> engine;
-    if (jobs == 0) { engine.reset(new SerialEngine);                  }
-    if (jobs  > 0) { engine.reset(new   ForkEngine); defer_logging(); }
-    if (jobs  < 0) { engine.reset(new ThreadEngine); jobs = -jobs;    }
-
-    if (jobs == 1) { jobs = std::thread::hardware_concurrency(); }
-
-    int ok = 0, failed = 0, crashed = 0, skipped = 0;
-
-    auto update_stats = [&](Status s) {
-        switch (s) {
-            case Status::OK:      ok++;      break;
-            case Status::Failed:  failed++;  break;
-            case Status::Crashed: crashed++; break;
-            case Status::Skipped: skipped++; break;
-            case Status::None:              return;
-        }
-        const char* leader = "\r";
-        auto print = [&](int count, const char* label) {
-            if (count) {
-                printf("%s%d %s", leader, count, label);
-                leader = ", ";
-            }
-        };
-        print(ok,      "ok");
-        print(failed,  "failed");
-        print(crashed, "crashed");
-        print(skipped, "skipped");
-        fflush(stdout);
-    };
-
-    auto spawn = [&](std::function<Status(void)> fn) {
-        if (--jobs < 0) {
-            update_stats(engine->wait_one());
-        }
-        while (!engine->spawn(fn)) {
-            update_stats(engine->wait_one());
-        }
-    };
-
-    for (std::unique_ptr<Src> owned = stream->next(); owned; owned = stream->next()) {
-        Src* raw = owned.release();  // Can't move std::unique_ptr into a lambda in C++11. :(
-        spawn([=] {
-            std::unique_ptr<Src> src{raw};
-
-            std::string name = src->name();
-            tls_currently_running = name.c_str();
-
-            return dst_factory()->draw(src.get());
-        });
-    }
-
-    for (Status s = Status::OK; s != Status::None; ) {
-        s = engine->wait_one();
-        update_stats(s);
-    }
-    printf("\n");
-    return (failed || crashed) ? 1 : 0;
-}
-
-
-Register::Register(const char* name, const char* help,
-                   std::unique_ptr<Stream> (*factory)(Options)) {
-    stream_types.push_back(StreamType{name, help, factory});
-}
-Register::Register(const char* name, const char* help,
-                   std::unique_ptr<Dst> (*factory)(Options)) {
-    dst_types.push_back(DstType{name, help, factory});
-}
-Register::Register(const char* name, const char* help,
-                   std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>)) {
-    via_types.push_back(ViaType{name, help, factory});
-}
-
-Options::Options(std::string str) {
-    std::string k,v, *curr = &k;
-    for (auto c : str) {
-        switch(c) {
-            case ',': (*this)[k] = v;
-                      curr = &(k = "");
-                      break;
-            case '=': curr = &(v = "");
-                      break;
-            default: *curr += c;
-        }
-    }
-    (*this)[k] = v;
-}
-
-std::string& Options::operator[](std::string k) { return this->kv[k]; }
-
-std::string Options::operator()(std::string k, std::string fallback) const {
-    for (auto it = kv.find(k); it != kv.end(); ) {
-        return it->second;
-    }
-    return fallback;
-}
diff --git a/src/third_party/skia/tools/ok.h b/src/third_party/skia/tools/ok.h
deleted file mode 100644
index f55842b..0000000
--- a/src/third_party/skia/tools/ok.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef ok_DEFINED
-#define ok_DEFINED
-
-#include "SkCanvas.h"
-#include <functional>
-#include <map>
-#include <memory>
-#include <string>
-
-// Not really ok-specific, but just kind of generally handy.
-template <typename T>
-static std::unique_ptr<T> move_unique(T& v) {
-    return std::unique_ptr<T>{new T{std::move(v)}};
-}
-
-void ok_log(const char*);
-
-enum class Status { OK, Failed, Crashed, Skipped, None };
-
-struct Src {
-    virtual ~Src() {}
-    virtual std::string name()     = 0;
-    virtual SkISize     size()     = 0;
-    virtual Status draw(SkCanvas*) = 0;
-};
-
-struct Stream {
-    virtual ~Stream() {}
-    virtual std::unique_ptr<Src> next() = 0;
-};
-
-struct Dst {
-    virtual ~Dst() {}
-    virtual Status draw(Src*)      = 0;
-    virtual sk_sp<SkImage> image() = 0;
-};
-
-class Options {
-    std::map<std::string, std::string> kv;
-public:
-    explicit Options(std::string = "");
-    std::string& operator[](std::string k);
-    std::string  operator()(std::string k, std::string fallback = "") const;
-};
-
-// Create globals to register your new type of Stream or Dst.
-struct Register {
-    Register(const char* name, const char* help, std::unique_ptr<Stream> (*factory)(Options));
-    Register(const char* name, const char* help, std::unique_ptr<Dst>    (*factory)(Options));
-    Register(const char* name, const char* help,
-             std::unique_ptr<Dst>(*factory)(Options, std::unique_ptr<Dst>));
-};
-
-#endif//ok_DEFINED
diff --git a/src/third_party/skia/tools/ok_dsts.cpp b/src/third_party/skia/tools/ok_dsts.cpp
deleted file mode 100644
index c25a8d5f..0000000
--- a/src/third_party/skia/tools/ok_dsts.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "ok.h"
-#include "SkSurface.h"
-
-struct SWDst : Dst {
-    SkImageInfo      info;
-    sk_sp<SkSurface> surface;
-
-    static std::unique_ptr<Dst> Create(Options options) {
-        SkImageInfo info = SkImageInfo::MakeN32Premul(0,0);
-        if (options("ct") == "565") { info = info.makeColorType(kRGB_565_SkColorType); }
-        if (options("ct") == "f16") { info = info.makeColorType(kRGBA_F16_SkColorType); }
-
-        if (options("cs") == "srgb") {
-            auto cs = info.colorType() == kRGBA_F16_SkColorType ? SkColorSpace::MakeSRGBLinear()
-                                                                : SkColorSpace::MakeSRGB();
-            info = info.makeColorSpace(std::move(cs));
-        }
-
-        SWDst dst;
-        dst.info = info;
-        return move_unique(dst);
-    }
-
-    Status draw(Src* src) override {
-        auto size = src->size();
-        surface = SkSurface::MakeRaster(info.makeWH(size.width(), size.height()));
-        return src->draw(surface->getCanvas());
-    }
-
-    sk_sp<SkImage> image() override {
-        return surface->makeImageSnapshot();
-    }
-};
-static Register sw{"sw", "draw with the software backend", SWDst::Create};
-static Register _8888{"8888", "alias for sw", SWDst::Create};
-
-static Register _565{"565", "alias for sw:ct=565", [](Options options) {
-    options["ct"] = "565";
-    return SWDst::Create(options);
-}};
-
-static Register srgb{"srgb", "alias for sw:cs=srgb", [](Options options) {
-    options["cs"] = "srgb";
-    return SWDst::Create(options);
-}};
-
-static Register f16{"f16", "alias for sw:ct=f16,cs=srgb", [](Options options) {
-    options["ct"] = "f16";
-    options["cs"] = "srgb";
-    return SWDst::Create(options);
-}};
-
-extern bool gSkForceRasterPipelineBlitter;
-static Register rp{"rp", "draw forcing SkRasterPipelineBlitter", [](Options options) {
-    gSkForceRasterPipelineBlitter = true;
-    return SWDst::Create(options);
-}};
diff --git a/src/third_party/skia/tools/ok_srcs.cpp b/src/third_party/skia/tools/ok_srcs.cpp
deleted file mode 100644
index 5630a34..0000000
--- a/src/third_party/skia/tools/ok_srcs.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "ok.h"
-#include "gm.h"
-#include "SkData.h"
-#include "SkOSFile.h"
-#include "SkPicture.h"
-#include <vector>
-
-struct GMStream : Stream {
-    const skiagm::GMRegistry* registry = skiagm::GMRegistry::Head();
-
-    static std::unique_ptr<Stream> Create(Options) {
-        GMStream stream;
-        return move_unique(stream);
-    }
-
-    struct GMSrc : Src {
-        skiagm::GM* (*factory)(void*);
-        std::unique_ptr<skiagm::GM> gm;
-
-        void init() {
-            if (gm) { return; }
-            gm.reset(factory(nullptr));
-        }
-
-        std::string name() override {
-            this->init();
-            return gm->getName();
-        }
-
-        SkISize size() override {
-            this->init();
-            return gm->getISize();
-        }
-
-        Status draw(SkCanvas* canvas) override {
-            this->init();
-            canvas->clear(0xffffffff);
-            canvas->concat(gm->getInitialTransform());
-            gm->draw(canvas);
-            return Status::OK;
-        }
-    };
-
-    std::unique_ptr<Src> next() override {
-        if (!registry) {
-            return nullptr;
-        }
-        GMSrc src;
-        src.factory = registry->factory();
-        registry = registry->next();
-        return move_unique(src);
-    }
-};
-static Register gm{"gm", "draw GMs linked into this binary", GMStream::Create};
-
-struct SKPStream : Stream {
-    std::string dir;
-    std::vector<std::string> skps;
-
-    static std::unique_ptr<Stream> Create(Options options) {
-        SKPStream stream;
-        stream.dir = options("dir", "skps");
-        SkOSFile::Iter it{stream.dir.c_str(), ".skp"};
-        for (SkString path; it.next(&path); ) {
-            stream.skps.push_back(path.c_str());
-        }
-        return move_unique(stream);
-    }
-
-    struct SKPSrc : Src {
-        std::string dir, path;
-        sk_sp<SkPicture> pic;
-
-        void init() {
-            if (pic) { return; }
-            auto skp = SkData::MakeFromFileName((dir+"/"+path).c_str());
-            pic = SkPicture::MakeFromData(skp.get());
-        }
-
-        std::string name() override {
-            return path;
-        }
-
-        SkISize size() override {
-            this->init();
-            return pic->cullRect().roundOut().size();
-        }
-
-        Status draw(SkCanvas* canvas) override {
-            this->init();
-            canvas->clear(0xffffffff);
-            pic->playback(canvas);
-            return Status::OK;
-        }
-    };
-
-    std::unique_ptr<Src> next() override {
-        if (skps.empty()) {
-            return nullptr;
-        }
-        SKPSrc src;
-        src.dir  = dir;
-        src.path = skps.back();
-        skps.pop_back();
-        return move_unique(src);
-    }
-};
-static Register skp{"skp", "draw SKPs from dir=skps", SKPStream::Create};
diff --git a/src/third_party/skia/tools/ok_test.cpp b/src/third_party/skia/tools/ok_test.cpp
deleted file mode 100644
index f5c4f22..0000000
--- a/src/third_party/skia/tools/ok_test.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "ok.h"
-#include "Test.h"
-
-#if SK_SUPPORT_GPU
-    #include "GrContextFactory.h"
-#endif
-
-struct TestStream : Stream {
-    const skiatest::TestRegistry* registry = skiatest::TestRegistry::Head();
-    bool extended = false, verbose = false;
-
-    static std::unique_ptr<Stream> Create(Options options) {
-        TestStream stream;
-        if (options("extended") != "") { stream.extended = true; }
-        if (options("verbose" ) != "") { stream.verbose  = true; }
-
-        return move_unique(stream);
-    }
-
-    struct TestSrc : Src {
-        skiatest::Test test {"", false, nullptr};
-        bool extended, verbose;
-
-        std::string name() override { return test.name; }
-        SkISize     size() override { return {0,0}; }
-
-        Status draw(SkCanvas*) override {
-
-            struct : public skiatest::Reporter {
-                Status status = Status::OK;
-                bool extended, verbose_;
-
-                void reportFailed(const skiatest::Failure& failure) override {
-                    ok_log(failure.toString().c_str());
-                    status = Status::Failed;
-                }
-                bool allowExtendedTest() const override { return extended; }
-                bool           verbose() const override { return verbose_; }
-            } reporter;
-            reporter.extended = extended;
-            reporter.verbose_ = verbose;
-
-            sk_gpu_test::GrContextFactory* factory = nullptr;
-        #if SK_SUPPORT_GPU
-            GrContextOptions options;
-            sk_gpu_test::GrContextFactory a_real_factory(options);
-            factory = &a_real_factory;
-        #endif
-
-            test.proc(&reporter, factory);
-            return reporter.status;
-        }
-    };
-
-    std::unique_ptr<Src> next() override {
-        if (!registry) {
-            return nullptr;
-        }
-        TestSrc src;
-        src.test = registry->factory();
-        src.extended = extended;
-        src.verbose  = verbose;
-        registry = registry->next();
-        return move_unique(src);
-    }
-};
-static Register test{"test", "run unit tests linked into this binary", TestStream::Create};
-
-// Hey, now why were these defined in DM.cpp?  That's kind of weird.
-namespace skiatest {
-#if SK_SUPPORT_GPU
-    bool IsGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
-        return kOpenGL_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type);
-    }
-    bool IsVulkanContextType(sk_gpu_test::GrContextFactory::ContextType type) {
-        return kVulkan_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type);
-    }
-    bool IsRenderingGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
-        return IsGLContextType(type) && sk_gpu_test::GrContextFactory::IsRenderingContext(type);
-    }
-    bool IsNullGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
-        return type == sk_gpu_test::GrContextFactory::kNullGL_ContextType;
-    }
-#else
-    bool IsGLContextType         (int) { return false; }
-    bool IsVulkanContextType     (int) { return false; }
-    bool IsRenderingGLContextType(int) { return false; }
-    bool IsNullGLContextType     (int) { return false; }
-#endif
-
-    void RunWithGPUTestContexts(GrContextTestFn* test, GrContextTypeFilterFn* contextTypeFilter,
-                                Reporter* reporter, sk_gpu_test::GrContextFactory* factory) {
-        // TODO(bsalomon)
-    }
-}
diff --git a/src/third_party/skia/tools/ok_vias.cpp b/src/third_party/skia/tools/ok_vias.cpp
deleted file mode 100644
index 37d371f..0000000
--- a/src/third_party/skia/tools/ok_vias.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkImage.h"
-#include "SkOSFile.h"
-#include "SkPictureRecorder.h"
-#include "SkPngEncoder.h"
-#include "ProcStats.h"
-#include "Timer.h"
-#include "ok.h"
-#include <chrono>
-#include <regex>
-
-static std::unique_ptr<Src> proxy(Src* original, std::function<Status(SkCanvas*)> fn) {
-    struct : Src {
-        Src*                             original;
-        std::function<Status(SkCanvas*)> fn;
-
-        std::string name() override { return original->name(); }
-        SkISize     size() override { return original->size(); }
-        Status draw(SkCanvas* canvas) override { return fn(canvas); }
-    } src;
-    src.original = original;
-    src.fn       = fn;
-    return move_unique(src);
-}
-
-struct ViaPic : Dst {
-    std::unique_ptr<Dst> target;
-    bool                 rtree = false;
-
-    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
-        ViaPic via;
-        via.target = std::move(dst);
-        if (options("bbh") == "rtree") { via.rtree = true; }
-        return move_unique(via);
-    }
-
-    Status draw(Src* src) override {
-        SkRTreeFactory factory;
-        SkPictureRecorder rec;
-        rec.beginRecording(SkRect::MakeSize(SkSize::Make(src->size())),
-                           rtree ? &factory : nullptr);
-
-        for (auto status = src->draw(rec.getRecordingCanvas()); status != Status::OK; ) {
-            return status;
-        }
-        auto pic = rec.finishRecordingAsPicture();
-
-        return target->draw(proxy(src, [=](SkCanvas* canvas) {
-            pic->playback(canvas);
-            return Status::OK;
-        }).get());
-    }
-
-    sk_sp<SkImage> image() override {
-        return target->image();
-    }
-};
-static Register via_pic{"via_pic", "record then play back an SkPicture", ViaPic::Create};
-
-struct Png : Dst {
-    std::unique_ptr<Dst> target;
-    std::string          dir;
-
-    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
-        Png via;
-        via.target = std::move(dst);
-        via.dir    = options("dir", "ok");
-        return move_unique(via);
-    }
-
-    Status draw(Src* src) override {
-        for (auto status = target->draw(src); status != Status::OK; ) {
-            return status;
-        }
-
-        SkBitmap bm;
-        SkPixmap pm;
-        if (!target->image()->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode) ||
-            !bm.peekPixels(&pm)) {
-            return Status::Failed;
-        }
-
-        sk_mkdir(dir.c_str());
-        SkFILEWStream dst{(dir + "/" + src->name() + ".png").c_str()};
-
-        SkPngEncoder::Options options;
-        options.fFilterFlags      = SkPngEncoder::FilterFlag::kNone;
-        options.fZLibLevel        = 1;
-        options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect
-                                                    : SkTransferFunctionBehavior::kIgnore;
-        return SkPngEncoder::Encode(&dst, pm, options) ? Status::OK
-                                                       : Status::Failed;
-    }
-
-    sk_sp<SkImage> image() override {
-        return target->image();
-    }
-};
-static Register png{"png", "dump PNGs to dir=ok" , Png::Create};
-
-struct Filter : Dst {
-    std::unique_ptr<Dst> target;
-    std::regex match, search;
-
-    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
-        Filter via;
-        via.target = std::move(dst);
-        via.match  = options("match",  ".*");
-        via.search = options("search", ".*");
-        return move_unique(via);
-    }
-
-    Status draw(Src* src) override {
-        auto name = src->name();
-        if (!std::regex_match (name, match) ||
-            !std::regex_search(name, search)) {
-            return Status::Skipped;
-        }
-        return target->draw(src);
-    }
-
-    sk_sp<SkImage> image() override {
-        return target->image();
-    }
-};
-static Register filter{"filter",
-                       "run only srcs matching match=.* exactly and search=.* somewhere",
-                       Filter::Create};
-
-struct Time : Dst {
-    std::unique_ptr<Dst> target;
-
-    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
-        Time via;
-        via.target = std::move(dst);
-        return move_unique(via);
-    }
-
-    Status draw(Src* src) override {
-        auto start = std::chrono::steady_clock::now();
-            Status status = target->draw(src);
-        std::chrono::duration<double, std::milli> elapsed = std::chrono::steady_clock::now()
-                                                          - start;
-
-        auto msg = HumanizeMs(elapsed.count());
-        ok_log(msg.c_str());
-        return status;
-    }
-
-    sk_sp<SkImage> image() override {
-        return target->image();
-    }
-};
-static Register _time{"time", "print wall run time", Time::Create};
-
-struct Memory : Dst {
-    std::unique_ptr<Dst> target;
-
-    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
-        Memory via;
-        via.target = std::move(dst);
-        return move_unique(via);
-    }
-
-    Status draw(Src* src) override {
-        Status status = target->draw(src);
-
-        auto msg = SkStringPrintf("%dMB", sk_tools::getMaxResidentSetSizeMB());
-        ok_log(msg.c_str());
-
-        return status;
-    }
-
-    sk_sp<SkImage> image() override {
-        return target->image();
-    }
-};
-static Register memory{"memory", "print process maximum memory usage", Memory::Create};
diff --git a/src/third_party/skia/tools/pathops_sorter.htm b/src/third_party/skia/tools/pathops_sorter.htm
index d8371ad..c2c5103 100644
--- a/src/third_party/skia/tools/pathops_sorter.htm
+++ b/src/third_party/skia/tools/pathops_sorter.htm
@@ -6,16 +6,11 @@
     <title></title>
 <div style="height:0">
 
-<div id="cubics">
-{{{152, 16}, {152, 16.0685501}, {91.06044, 16.1242027}, {16, 16.1242027}}}, id=0

-{{{16, 16.1242027}, {-59.06044, 16.1242027}, {-120, 16.0685501}, {-120, 16}}}, id=1

-{{{-120, 16}, {-120, 15.9314508}, {-59.06044, 15.8757973}, {16, 15.8757973}}}, id=2

-{{{16, 15.8757973}, {91.06044, 15.8757973}, {152, 15.9314508}, {152, 16}}}, id=3

-{{{16, 16}, {152, 16}}}, id=4

-{{{16, 17}, {152, 17}}}, id=5

-{{{16, 16}, {16, 17}}}, id=6

-{{{152, 16}, {152, 17}}}, id=7

-</div>
+    <div id="cubics">

+{{{fX=124.70011901855469 fY=9.3718261718750000 } {fX=124.66775026544929 fY=9.3744316215161234 } {fX=124.63530969619751 fY=9.3770743012428284 }{fX=124.60282897949219 fY=9.3797206878662109 } id=10      

+{{{fX=124.70011901855469 fY=9.3718004226684570 } {fX=124.66775026544929 fY=9.3744058723095804 } {fX=124.63530969619751 fY=9.3770485520362854 } {fX=124.60282897949219 fY=9.3796949386596680 } id=1

+{{{fX=124.70011901855469 fY=9.3718004226684570 } {fX=124.66786243087600 fY=9.3743968522034287 } {fX=124.63553249625420 fY=9.3770303056986286 } {fX=124.60316467285156 fY=9.3796672821044922 } id=2

+    </div>
 
     </div>
 
@@ -145,7 +140,7 @@
         mouseX = (screenWidth / 2) / hscale + srcLeft;
         mouseY = (screenHeight / 2) / vscale + srcTop;
         hinitScale = hscale;
-        vinitScale = vscale;

+        vinitScale = vscale;
     }
 
     function setScale(x0, x1, y0, y1) {
@@ -160,7 +155,7 @@
         vscale = screenHeight / srcHeight;
         if (uniformScale) {
             hscale = Math.min(hscale, vscale);
-            vscale = hscale;

+            vscale = hscale;
         }
         var hinvScale = 1 / hscale;
         var vinvScale = 1 / vscale;
@@ -897,10 +892,10 @@
                 var scaleTextOffset = hscale != vscale ? -25 : -5;
                 ctx.fillText(hscale.toFixed(decimal_places) + 'x',
                         screenWidth - 10, screenHeight - scaleTextOffset);
-                if (hscale != vscale) {

+                if (hscale != vscale) {
                     ctx.fillText(vscale.toFixed(decimal_places) + 'y',
-                            screenWidth - 10, screenHeight - 5);

-                }

+                            screenWidth - 10, screenHeight - 5);
+                }
             }
             if (draw_t) {
                 drawPointAtT(curve);
@@ -1105,10 +1100,10 @@
                 if (focusWasOn) {
                     focus_on_selection = false;
                     hscale /= 1.2;
-                    vscale /= 1.2;

+                    vscale /= 1.2;
                 } else {
-                    hscale /= 2;

-                    vscale /= 2;

+                    hscale /= 2;
+                    vscale /= 2;
                 }
                 calcLeftTop();
                 redraw();
@@ -1119,11 +1114,11 @@
                 focusWasOn = focus_on_selection;
                 if (focusWasOn) {
                     focus_on_selection = false;
-                    hscale *= 1.2;

-                    vscale *= 1.2;

+                    hscale *= 1.2;
+                    vscale *= 1.2;
                 } else {
-                    hscale *= 2;

-                    vscale *= 2;

+                    hscale *= 2;
+                    vscale *= 2;
                 }
                 calcLeftTop();
                 redraw();
diff --git a/src/third_party/skia/tools/pathops_visualizer.htm b/src/third_party/skia/tools/pathops_visualizer.htm
index 99acb76..c8afb44 100644
--- a/src/third_party/skia/tools/pathops_visualizer.htm
+++ b/src/third_party/skia/tools/pathops_visualizer.htm
@@ -1,223 +1,547 @@
 <html>
 <head>
-<div height="0" hidden="true">
-

-Skia UnitTests: --match PathOpsOp$ --resourcePath resources\ SK_DEBUG

-<div id="android1">

-seg=1 {{{-5, 0}, {1075, 0}}}

-seg=2 {{{1075, 0}, {1075, 242}}}

-seg=3 {{{1075, 242}, {-5, 242}}}

-seg=4 {{{-5, 242}, {-5, 0}}}

+<div height="0" hidden="true">

+<div id="bug8380">

+SkDCubic::ComplexBreak

+{{{126, 9.396100044250488281}, {125.6320571899414063, 9.295844078063964844}, {125.1227340698242188, 9.337338447570800781}, {124.6031646728515625, 9.379667282104492188}}},

+inflectionsTs[0]=0.999997776 {{{126.1618761931709827, 9.252680507258252973}, {123.04446008475567, 9.506653492188940291}}},

+SkDCubic::ComplexBreak

+{{{124.6031646728515625, 9.379667282104492188}, {124.1427383422851563, 9.417178153991699219}, {123.6742630004882813, 9.45534515380859375}, {123.28900146484375, 9.396100044250488281}}},

+inflectionsTs[0]=4.14921088e-06 {{{125.984438133710114, 9.267135117035042668}, {123.2218797495565639, 9.492200381017113386}}},

+maxCurvature[0]=0.0817322831 {{{125.8735553329735666, 9.277935394706121386}, {123.1067608854740314, 9.499713475347833835}}},

+SkDCubic::ComplexBreak

+{{{126, 9.396200180053710938}, {125.305999755859375, 9.206999778747558594}, {124.1090011596679688, 9.522199630737304688}, {123.28900146484375, 9.396200180053710938}}},

+inflectionsTs[0]=0.530286644 {{{127.5428560571536707, 9.140180090182106198}, {121.6628069847287179, 9.619260454379688241}}},

+maxCurvature[0]=0.568563182 {{{127.4346914043237859, 9.15278490094694952}, {121.5456828946143446, 9.624913158409162506}}},

+seg=1 {{{0, 353.891998f}, {126, 9.39610004f}}}

+seg=2 {{{126, 9.39610004f}, {125.632057f, 9.29584408f}, {125.122734f, 9.33733845f}, {124.603165f, 9.37966728f}}}

+seg=3 {{{124.603165f, 9.37966728f}, {124.142731f, 9.41717815f}, {123.674263f, 9.45534515f}, {123.289001f, 9.39610004f}}}

+seg=4 {{{123.289001f, 9.39610004f}, {118.119003f, 8.07219982f}}}

+seg=5 {{{118.119003f, 8.07219982f}, {8.17210007f, 104.212997f}}}

+seg=6 {{{8.17210007f, 104.212997f}, {0, 259.298737f}}}

+seg=7 {{{0, 259.298737f}, {0, 353.891998f}}}

 op sect

-seg=5 {{{0, 0}, {1080, 0}}}

-seg=6 {{{1080, 0}, {1080, 242}}}

-seg=7 {{{1080, 242}, {0, 242}}}

-seg=8 {{{0, 242}, {0, 0}}}

-debugShowLineIntersection wtTs[0]=0 {{{1075,0}, {1075,242}}} {{1075,0}} wnTs[0]=1 {{{-5,0}, {1075,0}}}

-debugShowLineIntersection wtTs[0]=1 {{{-5,242}, {-5,0}}} {{-5,0}} wnTs[0]=0 {{{-5,0}, {1075,0}}}

-debugShowLineIntersection wtTs[0]=0 {{{1075,242}, {-5,242}}} {{1075,242}} wnTs[0]=1 {{{1075,0}, {1075,242}}}

-debugShowLineIntersection wtTs[0]=0 {{{-5,242}, {-5,0}}} {{-5,242}} wnTs[0]=1 {{{1075,242}, {-5,242}}}

-debugShowLineIntersection wtTs[0]=0 {{{0,0}, {1080,0}}} {{0,0}} wtTs[1]=0.99537037 {{1075,0}} wnTs[0]=0.00462963 {{{-5,0}, {1075,0}}} wnTs[1]=1

-SkOpSegment::addT insert t=0.00462962963 segID=1 spanID=17

-SkOpSegment::addT insert t=0.99537037 segID=5 spanID=18

-debugShowLineIntersection wtTs[0]=1 {{{0,242}, {0,0}}} {{0,0}} wnTs[0]=0.00462963 {{{-5,0}, {1075,0}}}

-debugShowLineIntersection wtTs[0]=0.99537037 {{{0,0}, {1080,0}}} {{1075,0}} wnTs[0]=0 {{{1075,0}, {1075,242}}}

-debugShowLineIntersection wtTs[0]=0.00462962963 {{{1080,242}, {0,242}}} {{1075,242}} wnTs[0]=1 {{{1075,0}, {1075,242}}}

-SkOpSegment::addT insert t=0.00462962963 segID=7 spanID=19

-debugShowLineIntersection wtTs[0]=0.00462962963 {{{1080,242}, {0,242}}} {{1075,242}} wtTs[1]=1 {{0,242}} wnTs[0]=0 {{{1075,242}, {-5,242}}} wnTs[1]=0.99537037

-SkOpSegment::addT insert t=0.99537037 segID=3 spanID=20

-debugShowLineIntersection wtTs[0]=0 {{{0,242}, {0,0}}} {{0,242}} wnTs[0]=0.99537 {{{1075,242}, {-5,242}}}

-debugShowLineIntersection wtTs[0]=0 {{{1080,0}, {1080,242}}} {{1080,0}} wnTs[0]=1 {{{0,0}, {1080,0}}}

-debugShowLineIntersection wtTs[0]=1 {{{0,242}, {0,0}}} {{0,0}} wnTs[0]=0 {{{0,0}, {1080,0}}}

-debugShowLineIntersection wtTs[0]=0 {{{1080,242}, {0,242}}} {{1080,242}} wnTs[0]=1 {{{1080,0}, {1080,242}}}

-debugShowLineIntersection wtTs[0]=0 {{{0,242}, {0,0}}} {{0,242}} wnTs[0]=1 {{{1080,242}, {0,242}}}

-------------------x--x---------------- addExpanded

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-SkOpSegment::debugShowActiveSpans id=1 (-5,0 -8.8817842e-16,0) t=0 tEnd=0.00462962963 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=3 (2.22044605e-14,242 -5,242) t=0.99537037 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=4 (-5,242 -5,0) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=5 (0,0 1075,0) t=0 tEnd=0.99537037 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=7 (1075,242 0,242) t=0.00462962963 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=? windValue=1

-------------------x--x---------------- move_multiples

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- move_nearby

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- correctEnds

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- addEndMovedSpans

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- expand

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- addExpanded

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

-------------------x--x---------------- mark

-00:  seg/base=3/5 seg/base=7/19 MarkCoinStart

-01:  seg/base=3/20 seg/base=7/14 MarkCoinEnd

-02:  seg/base=1/17 seg/base=5/9 MarkCoinStart

-03:  seg/base=1/2 seg/base=5/18 MarkCoinEnd

+seg=8 {{{8.17210007f, 104.212997f}, {-5.82350016f, 369.813995f}}}

+seg=9 {{{-5.82350016f, 369.813995f}, {126, 9.39620018f}}}

+seg=10 {{{126, 9.39620018f}, {125.631981f, 9.29586983f}, {125.12252f, 9.3373785f}, {124.602829f, 9.37972069f}}}

+seg=11 {{{124.602829f, 9.37972069f}, {124.142509f, 9.41722488f}, {123.674164f, 9.45538425f}, {123.289001f, 9.39620018f}}}

+seg=12 {{{123.289001f, 9.39620018f}, {118.119003f, 8.07219982f}}}

+seg=13 {{{118.119003f, 8.07219982f}, {8.17210007f, 104.212997f}}}

+debugShowLineIntersection wtTs[0]=1 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{-5.82350016,369.813995}} wnTs[0]=0 {{{-5.82350016,369.813995}, {126,9.39620018}}}

+debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wnTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{126,9.39620018}} wnTs[0]=1 {{{-5.82350016,369.813995}, {126,9.39620018}}}

+debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{-5.82350016,369.813995}, {126,9.39620018}}}

+debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{123.289001,9.39620018}, {118.119003,8.07219982}}}

+debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowCubicIntersection wtTs[0]=1 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{124.602829,9.37972069}} wnTs[0]=0 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}}

+debugShowCubicLineIntersection wtTs[0]=1 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{123.289001,9.39620018}} wnTs[0]=0 {{{123.289001,9.39620018}, {118.119003,8.07219982}}}

+debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection no intersect {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{{0,353.891998}, {126,9.39610004}}}

+debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wnTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection wtTs[0]=0 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{8.17210007,104.212997}} wtTs[1]=0.583904956 {{0,259.298737}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}} wnTs[1]=1

+SkOpSegment::addT insert t=0.583904956 segID=8 spanID=27

+debugShowLineIntersection wtTs[0]=0.583904956 {{{8.17210007,104.212997}, {-5.82350016,369.813995}}} {{0,259.298737}} wnTs[0]=0 {{{0,259.298737}, {0,353.891998}}}

+debugShowLineIntersection wtTs[0]=0.0441765002 {{{-5.82350016,369.813995}, {126,9.39620018}}} {{0,353.891998}} wtTs[1]=1 {{126,9.39620018}} wnTs[0]=0 {{{0,353.891998}, {126,9.39610004}}} wnTs[1]=0.999999744

+SkOpSegment::addT insert t=0.0441765002 segID=9 spanID=28

+debugShowCubicLineIntersection no intersect {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{{-5.82350016,369.813995}, {126,9.39620018}}}

+debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection no intersect {{{-5.82350016,369.813995}, {126,9.39620018}}} {{{8.17210007,104.212997}, {0,259.298737}}}

+debugShowLineIntersection wtTs[0]=0.0441765002 {{{-5.82350016,369.813995}, {126,9.39620018}}} {{0,353.891998}} wnTs[0]=1 {{{0,259.298737}, {0,353.891998}}}

+debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{126,9.39620018}} wnTs[0]=1 {{{0,353.891998}, {126,9.39610004}}}

+-1=(0.375,0.5) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.5,0.625) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.625,0.75) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.75,0.8125) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.8125,0.875) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.875,0.9375) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+SkTSect::addForPerp priorSpan=-1 t=0.937702598 opp=-1

+-1=(0.9375,1) []

+SkTSect::addForPerp addBounded span=-1 opp=-1

+debugShowCubicIntersection wtTs[0]=0.307128906 {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{125.624687,9.33981037}} wtTs[1]=0.9375 {{124.700119,9.37182617}} wnTs[0]=0.307191 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} wnTs[1]=0.937702598

+SkOpSegment::addT insert t=0.307128906 segID=10 spanID=29

+SkOpSegment::addT insert t=0.307190555 segID=2 spanID=30

+SkOpSegment::addT insert t=0.9375 segID=10 spanID=31

+SkOpSegment::addT insert t=0.937702598 segID=2 spanID=32

+debugShowCubicIntersection no intersect {{{126,9.39620018}, {125.631981,9.29586983}, {125.12252,9.3373785}, {124.602829,9.37972069}}} {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}}

+debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{0,353.891998}, {126,9.39610004}}}

+-1=(0.125,0.1875) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.1875,0.25) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.25,0.375) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.375,0.5) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.5,0.625) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+-1=(0.625,0.75) [-1]

+SkTSect::addForPerp addBounded span=-1 opp=-1

+debugShowCubicIntersection wtTs[0]=0.0625 {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{124.516449,9.38673687}} wtTs[1]=0.625 {{123.752594,9.4268837}} wnTs[0]=0.0627287 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} wnTs[1]=0.625091708

+SkOpSegment::addT insert t=0.0625 segID=11 spanID=33

+SkOpSegment::addT insert t=0.0627286673 segID=3 spanID=34

+SkOpSegment::addT insert t=0.625 segID=11 spanID=35

+SkOpSegment::addT insert t=0.625091708 segID=3 spanID=36

+debugShowCubicLineIntersection no intersect {{{124.602829,9.37972069}, {124.142509,9.41722488}, {123.674164,9.45538425}, {123.289001,9.39620018}}} {{{123.289001,9.39610004}, {118.119003,8.07219982}}}

+debugShowLineIntersection no intersect {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{{0,353.891998}, {126,9.39610004}}}

+debugShowCubicLineIntersection wtTs[0]=0.999978653 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{123.289001,9.39620018}} wnTs[0]=0 {{{123.289001,9.39620018}, {118.119003,8.07219982}}}

+debugShowLineIntersection wtTs[0]=4.65488731e-06 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{123.289001,9.39610004}} wtTs[1]=1 {{118.119003,8.07219982}} wnTs[0]=0 {{{123.289001,9.39610004}, {118.119003,8.07219982}}} wnTs[1]=1

+debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39620018}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection no intersect {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{{0,353.891998}, {126,9.39610004}}}

+debugShowLineIntersection wtTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{118.119003,8.07219982}} wnTs[0]=1 {{{123.289001,9.39610004}, {118.119003,8.07219982}}}

+debugShowLineIntersection wtTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{118.119003,8.07219982}} wtTs[1]=1 {{8.17210007,104.212997}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} wnTs[1]=1

+debugShowLineIntersection wtTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{8.17210007,104.212997}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}}

+debugShowCubicLineIntersection wtTs[0]=0 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} {{126,9.39610004}} wnTs[0]=1 {{{0,353.891998}, {126,9.39610004}}}

+debugShowCubicLineIntersection no intersect {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{{0,353.891998}, {126,9.39610004}}}

+debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{123.289001,9.39610004}, {118.119003,8.07219982}}}

+debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection no intersect {{{0,353.891998}, {126,9.39610004}}} {{{8.17210007,104.212997}, {0,259.298737}}}

+debugShowLineIntersection wtTs[0]=0 {{{0,353.891998}, {126,9.39610004}}} {{0,353.891998}} wnTs[0]=1 {{{0,259.298737}, {0,353.891998}}}

+debugShowCubicIntersection wtTs[0]=1 {{{126,9.39610004}, {125.632057,9.29584408}, {125.122734,9.33733845}, {124.603165,9.37966728}}} {{124.603165,9.37966728}} wnTs[0]=0 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}}

+debugShowCubicLineIntersection wtTs[0]=1 {{{124.603165,9.37966728}, {124.142731,9.41717815}, {123.674263,9.45534515}, {123.289001,9.39610004}}} {{123.289001,9.39610004}} wnTs[0]=0 {{{123.289001,9.39610004}, {118.119003,8.07219982}}}

+debugShowLineIntersection wtTs[0]=1 {{{123.289001,9.39610004}, {118.119003,8.07219982}}} {{118.119003,8.07219982}} wnTs[0]=0 {{{118.119003,8.07219982}, {8.17210007,104.212997}}}

+debugShowLineIntersection wtTs[0]=1 {{{118.119003,8.07219982}, {8.17210007,104.212997}}} {{8.17210007,104.212997}} wnTs[0]=0 {{{8.17210007,104.212997}, {0,259.298737}}}

+debugShowLineIntersection wtTs[0]=1 {{{8.17210007,104.212997}, {0,259.298737}}} {{0,259.298737}} wnTs[0]=0 {{{0,259.298737}, {0,353.891998}}}

+----------------x-x--x-x-------------- addExpanded

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+SkOpSegment::debugShowActiveSpans id=8 (8.17210007,104.212997 -2.71619996e-07,259.298737) t=0 tEnd=0.583904956 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=9 (7.26031715e-07,353.891998 126,9.39620018) t=0.0441765002 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=10 (126,9.39620018 125.886971,9.36538583 125.760599,9.34795095 125.624687,9.33981037) t=0 tEnd=0.307128906 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=10 (125.624687,9.33981037 125.345733,9.32310212 125.026588,9.34554777 124.700119,9.37182617) t=0.307128906 tEnd=0.9375 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=10 (124.700119,9.37182617 124.66775,9.37443162 124.63531,9.3770743 124.602829,9.37972069) t=0.9375 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=11 (124.602829,9.37972069 124.574059,9.3820647 124.545259,9.38441166 124.516449,9.38673687) t=0 tEnd=0.0625 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=11 (124.516449,9.38673687 124.257155,9.40766372 123.997126,9.42685982 123.752594,9.4268837) t=0.0625 tEnd=0.625 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=11 (123.752594,9.4268837 123.589573,9.42689962 123.433437,9.41839421 123.289001,9.39620018) t=0.625 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=12 (123.289001,9.39620018 118.119003,8.07219982) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=1 (0,353.891998 126,9.39610004) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=2 (126,9.39610004 125.886971,9.36530236 125.760605,9.34788101 125.624695,9.33975124) t=0 tEnd=0.307190555 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=2 (125.624695,9.33975124 125.345738,9.3230648 125.026588,9.34552196 124.700119,9.37180042) t=0.307190555 tEnd=0.937702598 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=2 (124.700119,9.37180042 124.667862,9.37439685 124.635532,9.37703031 124.603165,9.37966728) t=0.937702598 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=3 (124.603165,9.37966728 124.574282,9.38202029 124.545364,9.3843762 124.516441,9.38671017) t=0 tEnd=0.0627286673 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=3 (124.516441,9.38671017 124.257145,9.40763418 123.997124,9.42681973 123.752594,9.42682648) t=0.0627286673 tEnd=0.625091708 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=3 (123.752594,9.42682648 123.589574,9.42683098 123.433439,9.41831153 123.289001,9.39610004) t=0.625091708 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=5 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=6 (8.17210007,104.212997 0,259.298737) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=? windValue=1

+----------------x-x--x-x-------------- move_multiples

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+----------------x-x--x-x-------------- move_nearby

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+----------------x-x--x-x-------------- correctEnds

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+----------------x-x--x-x-------------- addEndMovedSpans

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+----------------x-x--x-x-------------- expand

+00:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+01:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+02:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+03:  coinSeg/Span/PtT=2/3/3 endSpan=30 oppSeg/Span/PtT=10/19/19 oppEndSpan=29 MissingCoin

+04:  coinSeg/Span/PtT=3/36/36 endSpan=6 oppSeg/Span/PtT=11/35/35 oppEndSpan=22 MissingCoin

+05:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+06:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+07:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+08:  coinSeg/Span/PtT=10/19/19 endSpan=29 oppSeg/Span/PtT=2/3/3 oppEndSpan=30 MissingCoin

+09:  coinSeg/Span/PtT=11/35/35 endSpan=22 oppSeg/Span/PtT=3/36/36 oppEndSpan=6 MissingCoin

+10:  coinSeg/Span/PtT=11/33/33 endSpan=6 oppSeg/Span/PtT=11/22/22 oppEndSpan=6 ExpandCoin

+11:  coinSeg/Span/PtT=2/30/30 endSpan=19 oppSeg/Span/PtT=2/3/3 oppEndSpan=19 ExpandCoin

+12:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+13:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+14:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+15:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+16:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+17:  seg/base=11/35 seg/base=3/36 MarkCoinEnd

+18:  seg/base=2/30 seg/base=10/29 MarkCoinStart

+19:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+20:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+21:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+22:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+23:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+------------------xx-x-x-------------- addExpanded

+00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+02:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+04:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+06:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd

+08:  seg/base=3/36 MarkCoinInsert

+09:  seg/base=11/35 MarkCoinInsert

+10:  seg/base=2/3 seg/base=10/19 MarkCoinStart

+11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+12:  seg/base=10/29 MarkCoinInsert

+13:  seg/base=2/30 MarkCoinInsert

+14:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+16:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+------------------xx-x-x-------------- move_multiples

+00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+02:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+04:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+06:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd

+08:  seg/base=3/36 MarkCoinInsert

+09:  seg/base=11/35 MarkCoinInsert

+10:  seg/base=2/3 seg/base=10/19 MarkCoinStart

+11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+12:  seg/base=10/29 MarkCoinInsert

+13:  seg/base=2/30 MarkCoinInsert

+14:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+16:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+------------------xx-x-x-------------- move_nearby

+00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+02:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+04:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+06:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd

+08:  seg/base=3/36 MarkCoinInsert

+09:  seg/base=11/35 MarkCoinInsert

+10:  seg/base=2/3 seg/base=10/19 MarkCoinStart

+11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+12:  seg/base=10/29 MarkCoinInsert

+13:  seg/base=2/30 MarkCoinInsert

+14:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+16:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+------------------xx-x-x-------------- addExpanded

+00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+02:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+04:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+06:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd

+08:  seg/base=3/36 MarkCoinInsert

+09:  seg/base=11/35 MarkCoinInsert

+10:  seg/base=2/3 seg/base=10/19 MarkCoinStart

+11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+12:  seg/base=10/29 MarkCoinInsert

+13:  seg/base=2/30 MarkCoinInsert

+14:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+16:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

+------------------xx-x-x-------------- mark

+00:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+01:  coinSeg/Span/PtT=5/9/9 endSpan=10 oppSeg/Span/PtT=13/25/25 oppEndSpan=26 MissingCoin

+02:  seg/base=13/25 seg/base=5/9 MarkCoinStart

+03:  seg/base=13/26 seg/base=5/10 MarkCoinEnd

+04:  seg/base=4/7 seg/base=12/23 MarkCoinStart

+05:  seg/base=4/8 seg/base=12/24 MarkCoinEnd

+06:  seg/base=11/33 seg/base=3/34 MarkCoinStart

+07:  seg/base=11/22 seg/base=3/6 MarkCoinEnd

+08:  seg/base=3/36 MarkCoinInsert

+09:  seg/base=11/35 MarkCoinInsert

+10:  seg/base=2/3 seg/base=10/19 MarkCoinStart

+11:  seg/base=2/32 seg/base=10/31 MarkCoinEnd

+12:  seg/base=10/29 MarkCoinInsert

+13:  seg/base=2/30 MarkCoinInsert

+14:  seg/base=9/28 seg/base=1/1 MarkCoinStart

+15:  seg/base=9/18 seg/base=1/2 MarkCoinEnd

+16:  seg/base=8/15 seg/base=6/11 MarkCoinStart

+17:  seg/base=8/27 seg/base=6/12 MarkCoinEnd

 -------------------------------------- missing_coincidence

 -------------------------------------- expand

 -------------------------------------- expand

 -------------------------------------- apply

-SkOpSegment::markDone id=7 (1080,242 0,242) t=0.00462962963 [19] (1075,242) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

-SkOpSegment::markDone id=5 (0,0 1080,0) t=0 [9] (0,0) tEnd=0.99537037 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=5 (118.119003,8.07219982 8.17210007,104.212997) t=0 [9] (118.119003,8.07219982) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=12 (123.289001,9.39620018 118.119003,8.07219982) t=0 [23] (123.289001,9.39620018) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0.0627286673 [34] (124.516441,9.38671017) tEnd=0.625091708 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0.625091708 [36] (123.752594,9.42682648) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0 [19] (126,9.39620018) tEnd=0.307128906 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.307128906 [29] (125.624687,9.33981037) tEnd=0.9375 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=1 (0,353.891998 126,9.39610004) t=0 [1] (0,353.891998) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

+SkOpSegment::markDone id=6 (8.17210007,104.212997 0,259.298737) t=0 [11] (8.17210007,104.212997) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0

 -------------------------------------- findOverlaps

-SkOpSegment::debugShowActiveSpans id=1 (-5,0 -8.8817842e-16,0) t=0 tEnd=0.00462962963 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

-SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=? oppSum=? windValue=1 oppValue=1

-SkOpSegment::debugShowActiveSpans id=3 (2.22044605e-14,242 -5,242) t=0.99537037 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=4 (-5,242 -5,0) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=8 (8.17210007,104.212997 -2.71619996e-07,259.298737) t=0 tEnd=0.583904956 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=9 (7.26031715e-07,353.891998 126,9.39620018) t=0.0441765002 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=10 (124.700119,9.37182617 124.66775,9.37443162 124.63531,9.3770743 124.602829,9.37972069) t=0.9375 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=11 (124.602829,9.37972069 124.574059,9.3820647 124.545259,9.38441166 124.516449,9.38673687) t=0 tEnd=0.0625 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=11 (124.516449,9.38673687 124.257155,9.40766372 123.997126,9.42685982 123.752594,9.4268837) t=0.0625 tEnd=0.625 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=11 (123.752594,9.4268837 123.589573,9.42689962 123.433437,9.41839421 123.289001,9.39620018) t=0.625 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=2 (126,9.39610004 125.886971,9.36530236 125.760605,9.34788101 125.624695,9.33975124) t=0 tEnd=0.307190555 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=2 (125.624695,9.33975124 125.345738,9.3230648 125.026588,9.34552196 124.700119,9.37180042) t=0.307190555 tEnd=0.937702598 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=2 (124.700119,9.37180042 124.667862,9.37439685 124.635532,9.37703031 124.603165,9.37966728) t=0.937702598 tEnd=1 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=3 (124.603165,9.37966728 124.574282,9.38202029 124.545364,9.3843762 124.516441,9.38671017) t=0 tEnd=0.0627286673 windSum=? windValue=1

+SkOpSegment::debugShowActiveSpans id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

+SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=? windValue=1

 -------------------------------------- calc_angles

-SkOpSegment::sortAngles [1] tStart=0.00462962963 [17]

-SkOpAngle::after [1/1] 15/15 tStart=0.00462962963 tEnd=0 < [8/12] 23/23 tStart=1 tEnd=0 < [1/2] 31/31 tStart=0.00462962963 tEnd=1  T 4

-SkOpAngle::afterPart {{{0,0}, {-5,0}}} id=1

-SkOpAngle::afterPart {{{0,0}, {0,242}}} id=8

-SkOpAngle::afterPart {{{0,0}, {1075,0}}} id=1

-SkOpSegment::sortAngles [1] tStart=1 [2]

-SkOpAngle::after [1/3] 15/15 tStart=1 tEnd=0.00462962963 < [2/4] 23/23 tStart=0 tEnd=1 < [5/9] 31/31 tStart=0.99537037 tEnd=1  T 4

-SkOpAngle::afterPart {{{1075,0}, {-8.8817842e-16,0}}} id=1

-SkOpAngle::afterPart {{{1075,0}, {1075,242}}} id=2

-SkOpAngle::afterPart {{{1075,0}, {1080,0}}} id=5

-SkOpSegment::sortAngles [2] tStart=0 [3]

-SkOpSegment::sortAngles [2] tStart=1 [4]

-SkOpAngle::after [2/5] 7/7 tStart=1 tEnd=0 < [3/6] 15/15 tStart=0 tEnd=0.99537037 < [7/10] 31/31 tStart=0.00462962963 tEnd=0  T 4

-SkOpAngle::afterPart {{{1075,242}, {1075,0}}} id=2

-SkOpAngle::afterPart {{{1075,242}, {2.22044605e-14,242}}} id=3

-SkOpAngle::afterPart {{{1075,242}, {1080,242}}} id=7

-SkOpSegment::sortAngles [3] tStart=0 [5]

-SkOpSegment::sortAngles [3] tStart=0.99537037 [20]

-SkOpAngle::after [3/7] 31/31 tStart=0.99537037 tEnd=0 < [8/11] 7/7 tStart=0 tEnd=1 < [3/8] 15/15 tStart=0.99537037 tEnd=1  T 4

-SkOpAngle::afterPart {{{0,242}, {1075,242}}} id=3

-SkOpAngle::afterPart {{{0,242}, {0,0}}} id=8

-SkOpAngle::afterPart {{{0,242}, {-5,242}}} id=3

-SkOpSegment::sortAngles [5] tStart=0.99537037 [18]

-SkOpSegment::sortAngles [7] tStart=0.00462962963 [19]

 SkOpSegment::sortAngles [8] tStart=0 [15]

-SkOpSegment::sortAngles [8] tStart=1 [16]

-coinSpan - id=3 t=0 tEnd=0.99537037

-coinSpan + id=7 t=0.00462962963 tEnd=1

-coinSpan - id=1 t=0.00462962963 tEnd=1

-coinSpan + id=5 t=0 tEnd=0.99537037

-SkOpSpan::sortableTop dir=kTop seg=1 t=0.00231481481 pt=(-2.5,0)

-SkOpSpan::sortableTop [0] valid=1 operand=0 span=1 ccw=1 seg=1 {{{-5, 0}, {1075, 0}}} t=0.00231481481 pt=(-2.5,0) slope=(1080,0)

-SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markWinding id=4 (-5,242 -5,0) t=0 [7] (-5,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markWinding id=3 (1075,242 -5,242) t=0.99537037 [20] (2.22044605e-14,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::activeOp id=1 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0

-SkOpSegment::markDone id=1 (-5,0 1075,0) t=0 [1] (-5,0) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markDone id=4 (-5,242 -5,0) t=0 [7] (-5,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markDone id=3 (1075,242 -5,242) t=0.99537037 [20] (2.22044605e-14,242) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-bridgeOp chase.append id=3 windSum=-1

-SkOpSegment::markWinding id=3 (1075,242 -5,242) t=0 [5] (1075,242) tEnd=0.99537037 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1

-SkOpSegment::markAngle last segment=3 span=5 windSum=-1 

-SkOpSegment::markWinding id=8 (0,242 0,0) t=0 [15] (0,242) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markAngle last segment=8 span=16 

-SkOpSegment::debugShowActiveSpans id=1 (-8.8817842e-16,0 1075,0) t=0.00462962963 tEnd=1 windSum=? oppSum=? windValue=1 oppValue=1

-SkOpSegment::debugShowActiveSpans id=2 (1075,0 1075,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=3 (1075,242 2.22044605e-14,242) t=0 tEnd=0.99537037 windSum=-1 oppSum=-1 windValue=1 oppValue=1

-SkOpSegment::debugShowActiveSpans id=5 (1075,0 1080,0) t=0.99537037 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=6 (1080,0 1080,242) t=0 tEnd=1 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=7 (1080,242 1075,242) t=0 tEnd=0.00462962963 windSum=? windValue=1

-SkOpSegment::debugShowActiveSpans id=8 (0,242 0,0) t=0 tEnd=1 windSum=-1 oppSum=-1 windValue=1 oppValue=0

-SkOpSegment::activeOp id=3 t=0.99537037 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1

-SkOpSegment::markWinding id=7 (1080,242 0,242) t=0 [13] (1080,242) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markWinding id=6 (1080,0 1080,242) t=0 [11] (1080,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markWinding id=5 (0,0 1080,0) t=0.99537037 [18] (1075,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markAngle last segment=5 span=18 windSum=-1 

-SkOpSegment::markWinding id=2 (1075,0 1075,242) t=0 [3] (1075,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=0

-SkOpSegment::markAngle last segment=2 span=3 windSum=-1 

+SkOpSegment::sortAngles [8] tStart=0.583904956 [27]

+SkOpAngle::after [8/2] 5/5 tStart=0.583904956 tEnd=0 < [7/23] 23/23 tStart=0 tEnd=1 < [8/3] 21/21 tStart=0.583904956 tEnd=1  F 4

+SkOpAngle::afterPart {{{0,259.298737}, {8.17210034,104.212997}}} id=8

+SkOpAngle::afterPart {{{0,259.298737}, {0,353.891998}}} id=7

+SkOpAngle::afterPart {{{0,259.298737}, {-5.82349988,369.813995}}} id=8

+SkOpSegment::sortAngles [9] tStart=0.0441765002 [28]

+SkOpAngle::after [9/4] 21/21 tStart=0.0441765002 tEnd=0 < [7/24] 7/7 tStart=1 tEnd=0 < [9/5] 5/5 tStart=0.0441765002 tEnd=1  F 4

+SkOpAngle::afterPart {{{0,353.891998}, {-5.82350088,369.813995}}} id=9

+SkOpAngle::afterPart {{{0,353.891998}, {0,259.298737}}} id=7

+SkOpAngle::afterPart {{{0,353.891998}, {125.999999,9.39620018}}} id=9

+SkOpSegment::sortAngles [9] tStart=1 [18]

+SkOpSegment::sortAngles [10] tStart=0.9375 [31]

+SkOpAngle::after [10/7] 17/17 tStart=0.9375 tEnd=1 < [2/19] 17/17 tStart=0.937702598 tEnd=1 < [2/18] 1/1 tStart=0.937702598 tEnd=0.307190555  T 12

+SkOpAngle::afterPart {{{124.700119,9.37180042}, {124.66775,9.37440587}, {124.63531,9.37704855}, {124.602829,9.37969494}}} id=10

+SkOpAngle::afterPart {{{124.700119,9.37180042}, {124.667862,9.37439685}, {124.635532,9.37703031}, {124.603165,9.37966728}}} id=2

+SkOpAngle::afterPart {{{124.700119,9.37180042}, {125.026588,9.34552196}, {125.345738,9.3230648}, {125.624695,9.33975124}}} id=2

+SkOpSegment::sortAngles [11] tStart=0.0625 [33]

+SkOpAngle::after [11/8] 1/1 tStart=0.0625 tEnd=0 < [3/20] 1/1 tStart=0.0627286673 tEnd=0 < [11/9] 17/17 tStart=0.0625 tEnd=0.625  T 12

+SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.545252,9.38438496}, {124.574051,9.382038}, {124.602821,9.37969398}}} id=11

+SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.545364,9.3843762}, {124.574282,9.38202029}, {124.603165,9.37966728}}} id=3

+SkOpAngle::afterPart {{{124.516441,9.38671017}, {124.257148,9.40763702}, {123.997118,9.42683311}, {123.752586,9.42685699}}} id=11

+SkOpSegment::sortAngles [11] tStart=0.625 [35]

+SkOpSegment::sortAngles [11] tStart=1 [22]

+SkOpSegment::sortAngles [13] tStart=0 [25]

+SkOpSegment::sortAngles [13] tStart=1 [26]

+SkOpSegment::sortAngles [2] tStart=0 [3]

+SkOpSegment::sortAngles [2] tStart=0.307190555 [30]

+SkOpSegment::sortAngles [2] tStart=0.937702598 [32]

+SkOpSegment::sortAngles [3] tStart=0.0627286673 [34]

+SkOpSegment::sortAngles [4] tStart=0 [7]

+SkOpSegment::sortAngles [4] tStart=1 [8]

+SkOpSegment::sortAngles [7] tStart=0 [13]

+SkOpSegment::sortAngles [7] tStart=1 [14]

+coinSpan - id=13 t=0 tEnd=1

+coinSpan + id=5 t=0 tEnd=1

+coinSpan - id=4 t=0 tEnd=1

+coinSpan + id=12 t=0 tEnd=1

+coinSpan - id=11 t=0.0625 tEnd=1

+coinSpan + id=3 t=0.0627286673 tEnd=1

+coinSpan - id=2 t=0 tEnd=0.937702598

+coinSpan + id=10 t=0 tEnd=0.9375

+coinSpan - id=9 t=0.0441765002 tEnd=1

+coinSpan + id=1 t=0 tEnd=1

+coinSpan - id=8 t=0 tEnd=0.583904956

+coinSpan + id=6 t=0 tEnd=1

+SkOpSpan::sortableTop dir=kLeft seg=8 t=0.291952478 pt=(4.08605003,181.755859)

+SkOpSpan::sortableTop [0] valid=1 operand=1 span=15 ccw=0 seg=8 {{{8.17210007f, 104.212997f}, {-5.82350016f, 369.813995f}}} t=0.291952478 pt=(4.08605003,181.755859) slope=(-13.9956002,265.600998)

+SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+SkOpSegment::markWinding id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 [25] (118.119003,8.07219982) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markWinding id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 [7] (123.289001,9.39610004) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.625 [35] (123.752594,9.4268837) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.0625 [33] (124.516449,9.38673687) tEnd=0.625 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::activeOp id=8 t=0.583904956 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=1 suTo=0 result=1

+SkOpSegment::findNextOp simple

+SkOpSegment::markDone id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0 [15] (8.17210007,104.212997) tEnd=0.583904956 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+bridgeOp current id=8 from=(-2.71619996e-07,259.298737) to=(8.17210007,104.212997)

+SkOpSegment::findNextOp simple

+SkOpSegment::markDone id=13 (118.119003,8.07219982 8.17210007,104.212997) t=0 [25] (118.119003,8.07219982) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+bridgeOp current id=13 from=(8.17210007,104.212997) to=(118.119003,8.07219982)

+path.moveTo(-2.71619996e-07,259.298737);

+path.lineTo(8.17210007,104.212997);

+SkOpSegment::findNextOp simple

+SkOpSegment::markDone id=4 (123.289001,9.39610004 118.119003,8.07219982) t=0 [7] (123.289001,9.39610004) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+bridgeOp current id=4 from=(118.119003,8.07219982) to=(123.289001,9.39610004)

+path.lineTo(118.119003,8.07219982);

+SkOpSegment::findNextOp simple

+SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.625 [35] (123.752594,9.4268837) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+bridgeOp current id=11 from=(123.289001,9.39620018) to=(123.752594,9.4268837)

+path.lineTo(123.289001,9.39610004);

+path.cubicTo(123.433441,9.41839409, 123.589569,9.42689991, 123.752594,9.4268837);

+SkOpSegment::markWinding id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0 [21] (124.602829,9.37972069) tEnd=0.0625 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markWinding id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.9375 [31] (124.700119,9.37182617) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markAngle last segment=10 span=31 windSum=1

+SkOpSegment::markWinding id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0 [5] (124.603165,9.37966728) tEnd=0.0627286673 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.937702598 [32] (124.700119,9.37180042) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markAngle last segment=2 span=32 windSum=1

 SkOpSegment::findNextOp

-SkOpAngle::dumpOne [3/6] next=7/10 sect=15/15  s=0 [5] e=0.99537037 [20] sgn=-1 windVal=1 windSum=-1 oppVal=1 oppSum=-1

-SkOpAngle::dumpOne [7/10] next=2/5 sect=31/31  s=0.00462962963 [19] e=0 [13] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand

-SkOpAngle::dumpOne [2/5] next=3/6 sect=7/7  s=1 [4] e=0 [3] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1

-SkOpSegment::activeOp id=7 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0

-SkOpSegment::markDone id=7 (1080,242 0,242) t=0 [13] (1080,242) tEnd=0.00462962963 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markDone id=6 (1080,0 1080,242) t=0 [11] (1080,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::markDone id=5 (0,0 1080,0) t=0.99537037 [18] (1075,0) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::findNextOp chase.append segment=5 span=18 windSum=-1

-SkOpSegment::activeOp id=2 t=1 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1

-SkOpSegment::findNextOp chase.append segment=2 span=3 windSum=-1

-SkOpSegment::markDone id=3 (1075,242 -5,242) t=0 [5] (1075,242) tEnd=0.99537037 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1

-SkOpSegment::findNextOp from:[3] to:[2] start=90366152 end=90366008

-bridgeOp current id=3 from=(2.22044605e-14,242) to=(1075,242)

-SkOpSegment::markWinding id=1 (-5,0 1075,0) t=0.00462962963 [17] (-8.8817842e-16,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1

-SkOpSegment::markAngle last segment=1 span=17 windSum=-1 

+SkOpAngle::dumpOne [11/9] next=11/8 sect=17/17  s=0.0625 [33] e=0.625 [35] sgn=-1 windVal=1 windSum=1 oppVal=1 oppSum=1 operand

+SkOpAngle::dumpOne [11/8] next=3/20 sect=1/1  s=0.0625 [33] e=0 [21] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand

+SkOpAngle::dumpOne [3/20] next=11/9 sect=1/1  s=0.0627286673 [34] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0

+SkOpSegment::activeOp id=11 t=0.0625 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=0 result=1

+SkOpSegment::findNextOp chase.append segment=10 span=31 windSum=1

+SkOpSegment::activeOp id=3 t=0.0627286673 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0

+SkOpSegment::markDone id=3 (124.603165,9.37966728 124.142731,9.41717815 123.674263,9.45534515 123.289001,9.39610004) t=0 [5] (124.603165,9.37966728) tEnd=0.0627286673 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0

+SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.937702598 [32] (124.700119,9.37180042) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0

+SkOpSegment::findNextOp chase.append segment=2 span=32 windSum=1

+SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0.0625 [33] (124.516449,9.38673687) tEnd=0.625 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=1

+SkOpSegment::findNextOp from:[11] to:[11] start=-1132576784 end=-1353716568

+bridgeOp current id=11 from=(123.752594,9.4268837) to=(124.516449,9.38673687)

+path.cubicTo(123.997124,9.42685986, 124.257156,9.40766335, 124.516449,9.38673687);

+SkOpSegment::findNextOp simple

+SkOpSegment::markDone id=11 (124.602829,9.37972069 124.142509,9.41722488 123.674164,9.45538425 123.289001,9.39620018) t=0 [21] (124.602829,9.37972069) tEnd=0.0625 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0

+bridgeOp current id=11 from=(124.516449,9.38673687) to=(124.602829,9.37972069)

+path.cubicTo(124.545258,9.38441181, 124.574059,9.38206482, 124.602829,9.37972069);

+SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.307190555 [30] (125.624695,9.33975124) tEnd=0.937702598 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markWinding id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0 [3] (126,9.39610004) tEnd=0.307190555 newWindSum=1 newOppSum=-1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markWinding id=9 (-5.82350016,369.813995 126,9.39620018) t=0.0441765002 [28] (7.26031715e-07,353.891998) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=1

+SkOpSegment::markAngle last segment=9 span=28 windSum=-1

 SkOpSegment::findNextOp

-SkOpAngle::dumpOne [2/4] next=5/9 sect=23/23  s=0 [3] e=1 [4] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1

-SkOpAngle::dumpOne [5/9] next=1/3 sect=31/31  s=0.99537037 [18] e=1 [10] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done operand

-SkOpAngle::dumpOne [1/3] next=2/4 sect=15/15  s=1 [2] e=0.00462962963 [17] sgn=1 windVal=1 windSum=-1 oppVal=1 oppSum=-1

-SkOpSegment::activeOp id=5 t=0.99537037 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0

-SkOpSegment::activeOp id=1 t=1 tEnd=0.00462962963 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1

-SkOpSegment::findNextOp chase.append segment=1 span=17 windSum=-1

-SkOpSegment::markDone id=2 (1075,0 1075,242) t=0 [3] (1075,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::findNextOp from:[2] to:[1] start=90365736 end=90368360

-bridgeOp current id=2 from=(1075,242) to=(1075,0)

-path.moveTo(2.22044605e-14,242);

-path.lineTo(1075,242);

-SkOpSegment::findNextOp

-SkOpAngle::dumpOne [1/2] next=1/1 sect=31/31  s=0.00462962963 [17] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=1 oppSum=-1

-SkOpAngle::dumpOne [1/1] next=8/12 sect=15/15  s=0.00462962963 [17] e=0 [1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done

-SkOpAngle::dumpOne [8/12] next=1/2 sect=23/23  s=1 [16] e=0 [15] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand

-SkOpSegment::activeOp id=1 t=0.00462962963 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0

-SkOpSegment::activeOp id=8 t=1 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1

-SkOpSegment::markDone id=1 (-5,0 1075,0) t=0.00462962963 [17] (-8.8817842e-16,0) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=1

-SkOpSegment::findNextOp from:[1] to:[8] start=90368192 end=90368048

-bridgeOp current id=1 from=(1075,0) to=(-8.8817842e-16,0)

-path.lineTo(1075,0);

-SkOpSegment::findNextOp

-SkOpAngle::dumpOne [8/11] next=3/8 sect=7/7  s=0 [15] e=1 [16] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=-1 operand

-SkOpAngle::dumpOne [3/8] next=3/7 sect=15/15  s=0.99537037 [20] e=1 [6] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 done

-SkOpAngle::dumpOne [3/7] next=8/11 sect=31/31  s=0.99537037 [20] e=0 [5] sgn=1 windVal=1 windSum=-1 oppVal=1 oppSum=-1 done

-SkOpSegment::activeOp id=3 t=0.99537037 tEnd=1 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0

-SkOpSegment::activeOp id=3 t=0.99537037 tEnd=0 op=sect miFrom=0 miTo=1 suFrom=0 suTo=1 result=1

-SkOpSegment::markDone id=8 (0,242 0,0) t=0 [15] (0,242) tEnd=1 newWindSum=-1 newOppSum=-1 oppSum=-1 windSum=-1 windValue=1 oppValue=0

-SkOpSegment::findNextOp from:[8] to:[3] start=90368840 end=90366336

-bridgeOp current id=8 from=(0,0) to=(0,242)

-path.lineTo(-8.8817842e-16,0);

-path.lineTo(0,242);

-path.close();

+SkOpAngle::dumpOne [10/7] next=2/19 sect=17/17  s=0.9375 [31] e=1 [20] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand

+SkOpAngle::dumpOne [2/19] next=2/18 sect=17/17  s=0.937702598 [32] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done

+SkOpAngle::dumpOne [2/18] next=10/7 sect=1/1  s=0.937702598 [32] e=0.307190555 [30] sgn=1 windVal=1 windSum=1 oppVal=1 oppSum=-1

+SkOpSegment::activeOp id=2 t=0.937702598 tEnd=1 op=sect = result=1

+SkOpSegment::activeOp id=2 t=0.937702598 tEnd=0.307190555 op=sect miFrom=0 miTo=1 suFrom=1 suTo=0 result=0

+SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0.307190555 [30] (125.624695,9.33975124) tEnd=0.937702598 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=1

+SkOpSegment::markDone id=2 (126,9.39610004 125.632057,9.29584408 125.122734,9.33733845 124.603165,9.37966728) t=0 [3] (126,9.39610004) tEnd=0.307190555 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=1

+SkOpSegment::markDone id=9 (-5.82350016,369.813995 126,9.39620018) t=0.0441765002 [28] (7.26031715e-07,353.891998) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=1

+SkOpSegment::findNextOp chase.append segment=9 span=28 windSum=-1

+SkOpSegment::markDone id=10 (126,9.39620018 125.631981,9.29586983 125.12252,9.3373785 124.602829,9.37972069) t=0.9375 [31] (124.700119,9.37182617) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0

+SkOpSegment::findNextOp from:[10] to:[2] start=-1132576976 end=-1353719496

+bridgeOp current id=10 from=(124.602829,9.37972069) to=(124.700119,9.37182617)

+path.cubicTo(124.635307,9.37707424, 124.667747,9.37443161, 124.700119,9.37182617);

+SkOpSegment::markWinding id=7 (0,259.298737 0,353.891998) t=0 [13] (0,259.298737) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markWinding id=9 (-5.82350016,369.813995 126,9.39620018) t=0 [17] (-5.82350016,369.813995) tEnd=0.0441765002 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::markWinding id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0.583904956 [27] (-2.71619996e-07,259.298737) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0

+SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0

+SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=-1 oppSum=0 windValue=1 oppValue=0

+SkOpSegment::debugShowActiveSpans id=7 (0,259.298737 0,353.891998) t=0 tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0

+SkOpSegment::activeOp id=7 t=1 tEnd=0 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0

+SkOpSegment::markDone id=7 (0,259.298737 0,353.891998) t=0 [13] (0,259.298737) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0

+bridgeOp chase.append id=7 windSum=1

+SkOpSegment::debugShowActiveSpans id=8 (-2.71619996e-07,259.298737 -5.82350016,369.813995) t=0.583904956 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0

+SkOpSegment::debugShowActiveSpans id=9 (-5.82350016,369.813995 7.26031715e-07,353.891998) t=0 tEnd=0.0441765002 windSum=-1 oppSum=0 windValue=1 oppValue=0

+SkOpSegment::activeOp id=8 t=0.583904956 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0

+SkOpSegment::markDone id=8 (8.17210007,104.212997 -5.82350016,369.813995) t=0.583904956 [27] (-2.71619996e-07,259.298737) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

+SkOpSegment::markDone id=9 (-5.82350016,369.813995 126,9.39620018) t=0 [17] (-5.82350016,369.813995) tEnd=0.0441765002 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0

 </div>

 

-</div>
+

+

+    </div>
 
 <script type="text/javascript">
 
     var testDivs = [
-        android1,
+        bug8380,
     ];
 
 var decimal_places = 3; // make this 3 to show more precision
@@ -504,9 +828,9 @@
     escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
     escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
     escape = escape.replace(/PT_VAL/g, "\\(P_VAL\\)");
-    escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
-    escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
-    escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
+    escape = escape.replace(/P_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?, ?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
+    escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)");
+    escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
     escape = escape.replace(/PATH/g, "pathB?");
     escape = escape.replace(/IDX/g, "(-?\\d+)");
     escape = escape.replace(/NUM/g, "(-?\\d+)");
@@ -524,9 +848,9 @@
     escape = escape.replace(/FILL_TYPE/g, "SkPath::k[a-zA-Z]+_FillType");
     escape = escape.replace(/PTR_VAL/g, "0x[0-9A-F]+");
     escape = escape.replace(/PT_VAL/g, "\\{\\{P_VAL\\}\\}");
-    escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
-    escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)");
-    escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e-?\\d+)?)[Ff]?");
+    escape = escape.replace(/P_VAL/g, "(?:f?[xX] = )?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?, *(?: f?[yY] = )?(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
+    escape = escape.replace(/T_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)");
+    escape = escape.replace(/W_VAL/g, "(-?\\d+\\.?\\d*(?:e[+-]?\\d+)?)[Ff]?");
     escape = escape.replace(/OPER/g, "[a-z]+");
     escape = escape.replace(/PATH/g, "pathB?");
     escape = escape.replace(/T_F/g, "([TF])");
@@ -2226,9 +2550,9 @@
     return dxy;
 }
 
-function dpt_at_t(curve, t) {

+function dpt_at_t(curve, t) {
     var type = PATH_LINE + (curve.length / 2 - 2);
-    return dxy_at_t(curve, type, t);

+    return dxy_at_t(curve, type, t);
 }
 
 function drawLabel(num, px, py) {
@@ -2346,11 +2670,11 @@
     return a * curve[1] + b * curve[3] + c * curve[5] + d * curve[7];
 }
 
-function pt_at_t(curve, t) {

-    var pt = {};

-    pt.x = x_at_t(curve, t);

-    pt.y = y_at_t(curve, t);

-    return pt;

+function pt_at_t(curve, t) {
+    var pt = {};
+    pt.x = x_at_t(curve, t);
+    pt.y = y_at_t(curve, t);
+    return pt;
 }
 
 function drawOrder(curve, t, label) {
@@ -2377,59 +2701,59 @@
     ctx.font = "normal 10px Arial";
 }
 
-function drawVisibleOrder(curve, label) {

-    var s = pt_at_t(curve, 0);

-    var e = pt_at_t(curve, 1);

-    var sOn = ptOnScreen(s);

-    var eOn = ptOnScreen(e);

-    var defaultT = 0.85;

-    if (sOn && eOn)

-        return drawOrder(curve, defaultT, label);

-    if (sOn || eOn) {

-        if (eOn) {

-            defaultT = 1 - defaultT;

-        }

-        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;

-        var t = defaultT;

-        var tries = 16;

-        do {

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawOrder(curve, t, label);

-            t += step;

-            step /= 2;

-        } while (--tries > 0);

-        drawOrder(curve, defaultT, label);

-    }

-    // scattershot until we find a visible point

-    var denom = 2;  // visit odd number num / denom to hit unique pts

-    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...

-    do {

-        for (var numer = 1; numer < denom; numer += 2) {

-            var t = numer / denom + 0.1;

-            if (t >= 1) {

-                break;

-            }

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawOrder(curve, t, label);

-        }

-        denom *= 2;

-    } while (--tries > 0);

-    drawOrder(curve, defaultT, label);

+function drawVisibleOrder(curve, label) {
+    var s = pt_at_t(curve, 0);
+    var e = pt_at_t(curve, 1);
+    var sOn = ptOnScreen(s);
+    var eOn = ptOnScreen(e);
+    var defaultT = 0.85;
+    if (sOn && eOn)
+        return drawOrder(curve, defaultT, label);
+    if (sOn || eOn) {
+        if (eOn) {
+            defaultT = 1 - defaultT;
+        }
+        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
+        var t = defaultT;
+        var tries = 16;
+        do {
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawOrder(curve, t, label);
+            t += step;
+            step /= 2;
+        } while (--tries > 0);
+        drawOrder(curve, defaultT, label);
+    }
+    // scattershot until we find a visible point
+    var denom = 2;  // visit odd number num / denom to hit unique pts
+    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
+    do {
+        for (var numer = 1; numer < denom; numer += 2) {
+            var t = numer / denom + 0.1;
+            if (t >= 1) {
+                break;
+            }
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawOrder(curve, t, label);
+        }
+        denom *= 2;
+    } while (--tries > 0);
+    drawOrder(curve, defaultT, label);
 }
 
-function set_length(pt, newLen) {

-    var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);

-    var scale = newLen / len;

-    var newPt = { x: pt.x * scale, y: pt.y * scale };

-    return newPt;

+function set_length(pt, newLen) {
+    var len = Math.sqrt(pt.x * pt.x + pt.y * pt.y);
+    var scale = newLen / len;
+    var newPt = { x: pt.x * scale, y: pt.y * scale };
+    return newPt;
 }
 
-function drawDirection(curve, t) {

+function drawDirection(curve, t) {
     var d = dpt_at_t(curve, t);
     d = set_length(d, 16);
-    var pt = localToGlobal(pt_at_t(curve, t));

+    var pt = localToGlobal(pt_at_t(curve, t));
     ctx.beginPath();
     ctx.moveTo(pt.x - d.y, pt.y + d.x);
     ctx.lineTo(pt.x + d.x, pt.y + d.y);
@@ -2438,47 +2762,47 @@
     ctx.stroke();
 }
 
-function drawVisibleDirection(curve) {

-    var s = pt_at_t(curve, 0);

-    var e = pt_at_t(curve, 1);

-    var sOn = ptOnScreen(s);

-    var eOn = ptOnScreen(e);

-    var defaultT = 0.65;

-    if (sOn && eOn) {

-        return drawDirection(curve, defaultT);

-    }

-    if (sOn || eOn) {

-        if (eOn) {

-            defaultT = 1 - defaultT;

-        }

-        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;

-        var t = defaultT;

-        var tries = 16;

-        do {

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawDirection(curve, t);

-            t += step;

-            step /= 2;

-        } while (--tries > 0);

-        drawDirection(curve, defaultT);

-    }

-    // scattershot until we find a visible point

-    var denom = 2;  // visit odd number num / denom to hit unique pts

-    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...

-    do {

-        for (var numer = 1; numer < denom; numer += 2) {

-            var t = numer / denom + 0.1;

-            if (t >= 1) {

-                break;

-            }

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawDirection(curve, t);

-        }

-        denom *= 2;

-    } while (--tries > 0);

-    drawDirection(curve, defaultT);

+function drawVisibleDirection(curve) {
+    var s = pt_at_t(curve, 0);
+    var e = pt_at_t(curve, 1);
+    var sOn = ptOnScreen(s);
+    var eOn = ptOnScreen(e);
+    var defaultT = 0.65;
+    if (sOn && eOn) {
+        return drawDirection(curve, defaultT);
+    }
+    if (sOn || eOn) {
+        if (eOn) {
+            defaultT = 1 - defaultT;
+        }
+        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
+        var t = defaultT;
+        var tries = 16;
+        do {
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawDirection(curve, t);
+            t += step;
+            step /= 2;
+        } while (--tries > 0);
+        drawDirection(curve, defaultT);
+    }
+    // scattershot until we find a visible point
+    var denom = 2;  // visit odd number num / denom to hit unique pts
+    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
+    do {
+        for (var numer = 1; numer < denom; numer += 2) {
+            var t = numer / denom + 0.1;
+            if (t >= 1) {
+                break;
+            }
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawDirection(curve, t);
+        }
+        denom *= 2;
+    } while (--tries > 0);
+    drawDirection(curve, defaultT);
 }
 
 function drawID(curve, t, id) {
@@ -2489,53 +2813,53 @@
     draw_id_at(id, _px, _py);
 }
 
-function localToGlobal(local) {

-    var global = {};

-    global.x = (local.x - srcLeft) * scale;

-    global.y = (local.y - srcTop) * scale;

-    return global;

+function localToGlobal(local) {
+    var global = {};
+    global.x = (local.x - srcLeft) * scale;
+    global.y = (local.y - srcTop) * scale;
+    return global;
 }
 
-function ptOnScreen(local) {

-    var pt = localToGlobal(local);

-    return 10 <= pt.x && pt.x <= screenWidth - 10

-        && 10 <= pt.y && pt.y <= screenHeight - 10;

+function ptOnScreen(local) {
+    var pt = localToGlobal(local);
+    return 10 <= pt.x && pt.x <= screenWidth - 10
+        && 10 <= pt.y && pt.y <= screenHeight - 10;
 }
 
-function drawVisibleID(curve, defaultT, id) {

-    // determine if either or both ends are visible

-    var s = pt_at_t(curve, 0);

-    var e = pt_at_t(curve, 1);

-    var sOn = ptOnScreen(s);

-    var eOn = ptOnScreen(e);

-    if (sOn && eOn)

-        return drawID(curve, defaultT, id);

-    if (sOn || eOn) {

-        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;

-        var t = defaultT;

-        var tries = 16;

-        do {

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawID(curve, t, id);

-            t += step;

-            step /= 2;

-        } while (--tries > 0);

-        drawID(curve, defaultT, id);

-    }

-    // scattershot until we find a visible point

-    var denom = 2;  // visit odd number num / denom to hit unique pts

-    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...

-    do {

-        for (var numer = 1; numer < denom; numer += 2) {

-            var t = numer / denom;

-            var mid = pt_at_t(curve, t);

-            if (ptOnScreen(mid))

-                return drawID(curve, t, id);

-        }

-        denom *= 2;

-    } while (--tries > 0);

-    drawID(curve, defaultT, id);

+function drawVisibleID(curve, defaultT, id) {
+    // determine if either or both ends are visible
+    var s = pt_at_t(curve, 0);
+    var e = pt_at_t(curve, 1);
+    var sOn = ptOnScreen(s);
+    var eOn = ptOnScreen(e);
+    if (sOn && eOn)
+        return drawID(curve, defaultT, id);
+    if (sOn || eOn) {
+        var step = sOn ? -defaultT / 2 : (1 - defaultT) / 2;
+        var t = defaultT;
+        var tries = 16;
+        do {
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawID(curve, t, id);
+            t += step;
+            step /= 2;
+        } while (--tries > 0);
+        drawID(curve, defaultT, id);
+    }
+    // scattershot until we find a visible point
+    var denom = 2;  // visit odd number num / denom to hit unique pts
+    var tries = 6; // tries 1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16 ...
+    do {
+        for (var numer = 1; numer < denom; numer += 2) {
+            var t = numer / denom;
+            var mid = pt_at_t(curve, t);
+            if (ptOnScreen(mid))
+                return drawID(curve, t, id);
+        }
+        denom *= 2;
+    } while (--tries > 0);
+    drawID(curve, defaultT, id);
 }
 
 function draw_id_at(id, _px, _py) {
@@ -2613,8 +2937,8 @@
             drawVisibleID(curve, 0.5, id);
         }
     }
-    if (draw_direction) {

-        drawVisibleDirection(curve);

+    if (draw_direction) {
+        drawVisibleDirection(curve);
     }
     if (type == PATH_LINE) {
         return;
@@ -3205,10 +3529,10 @@
                         drawVisibleOrder(leftCurve, 'L');
                         drawVisibleOrder(rightCurve, 'R');
                     }
-                    if (draw_id) {

-                        drawVisibleID(leftCurve, 0.5, frags[0]);

-                        drawVisibleID(midCurve, 0.5, frags[6]);

-                        drawVisibleID(rightCurve, 0.5, frags[12]);

+                    if (draw_id) {
+                        drawVisibleID(leftCurve, 0.5, frags[0]);
+                        drawVisibleID(midCurve, 0.5, frags[6]);
+                        drawVisibleID(rightCurve, 0.5, frags[12]);
                     }
                     break;
                 case REC_TYPE_AFTERPART:
@@ -3245,8 +3569,8 @@
                             throw "stop execution";
                     }
                     drawCurve(curve);
-                    if (draw_id) {

-                        drawVisibleID(curve, 0.5, id);

+                    if (draw_id) {
+                        drawVisibleID(curve, 0.5, id);
                     }
                     ++afterIndex;
                     break;
diff --git a/src/third_party/skia/tools/picture_utils.cpp b/src/third_party/skia/tools/picture_utils.cpp
deleted file mode 100644
index 93d598d..0000000
--- a/src/third_party/skia/tools/picture_utils.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "picture_utils.h"
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-#include "SkHalf.h"
-#include "SkImageEncoder.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkPM4fPriv.h"
-#include "SkPicture.h"
-#include "SkStream.h"
-#include "SkString.h"
-#include "SkRasterPipeline.h"
-
-#include "sk_tool_utils.h"
-
-namespace sk_tools {
-    void force_all_opaque(const SkBitmap& bitmap) {
-        SkASSERT(kN32_SkColorType == bitmap.colorType());
-        if (kN32_SkColorType == bitmap.colorType()) {
-            return;
-        }
-
-        for (int y = 0; y < bitmap.height(); y++) {
-            for (int x = 0; x < bitmap.width(); x++) {
-                *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT);
-            }
-        }
-    }
-
-    void replace_char(SkString* str, const char oldChar, const char newChar) {
-        if (nullptr == str) {
-            return;
-        }
-        for (size_t i = 0; i < str->size(); ++i) {
-            if (oldChar == str->operator[](i)) {
-                str->operator[](i) = newChar;
-            }
-        }
-    }
-
-    bool is_percentage(const char* const string) {
-        SkString skString(string);
-        return skString.endsWith("%");
-    }
-
-    void setup_bitmap(SkBitmap* bitmap, int width, int height) {
-        bitmap->allocN32Pixels(width, height);
-        bitmap->eraseColor(SK_ColorTRANSPARENT);
-    }
-
-    bool write_bitmap_to_disk(const SkBitmap& bm, const SkString& dirPath,
-                              const char *subdirOrNull, const SkString& baseName) {
-        SkString partialPath;
-        if (subdirOrNull) {
-            partialPath = SkOSPath::Join(dirPath.c_str(), subdirOrNull);
-            sk_mkdir(partialPath.c_str());
-        } else {
-            partialPath.set(dirPath);
-        }
-        SkString fullPath = SkOSPath::Join(partialPath.c_str(), baseName.c_str());
-        if (sk_tool_utils::EncodeImageToFile(fullPath.c_str(), bm, SkEncodedImageFormat::kPNG, 100)) {
-            return true;
-        } else {
-            SkDebugf("Failed to write the bitmap to %s.\n", fullPath.c_str());
-            return false;
-        }
-    }
-
-    sk_sp<SkData> encode_bitmap_for_png(SkBitmap bitmap) {
-        const int w = bitmap.width(),
-                  h = bitmap.height();
-
-        // PNG wants unpremultiplied 8-bit RGBA pixels (16-bit could work fine too).
-        // We leave the gamma of these bytes unspecified, to continue the status quo,
-        // which we think generally is to interpret them as sRGB.
-
-        SkAutoTMalloc<uint32_t> rgba(w*h);
-
-        const void* src = bitmap.getPixels();
-        uint32_t*   dst = rgba.get();
-
-        SkRasterPipeline_<256> p;
-        switch (bitmap.colorType()) {
-            case  kRGBA_F16_SkColorType: p.append(SkRasterPipeline::load_f16,  &src); break;
-            case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &src); break;
-            case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &src); break;
-            case   kRGB_565_SkColorType: p.append(SkRasterPipeline::load_565,  &src); break;
-            default: SkASSERT(false);  // DM doesn't support any other formats, does it?
-        }
-        if (bitmap.info().gammaCloseToSRGB()) {
-            p.append_from_srgb(kUnpremul_SkAlphaType);
-        }
-        p.append(SkRasterPipeline::unpremul);
-        p.append(SkRasterPipeline::clamp_0);
-        p.append(SkRasterPipeline::clamp_1);
-        if (bitmap.info().colorSpace()) {
-            // We leave legacy modes as-is.  They're already sRGB encoded (kind of).
-            p.append(SkRasterPipeline::to_srgb);
-        }
-        p.append(SkRasterPipeline::store_8888, &dst);
-
-        auto run = p.compile();
-        for (int y = 0; y < h; y++) {
-            run(0,y, w);
-            src = SkTAddOffset<const void>(src, bitmap.rowBytes());
-            dst += w;
-        }
-
-        return SkData::MakeFromMalloc(rgba.release(), w*h*sizeof(uint32_t));
-    }
-
-} // namespace sk_tools
diff --git a/src/third_party/skia/tools/picture_utils.h b/src/third_party/skia/tools/picture_utils.h
deleted file mode 100644
index 49a2c82..0000000
--- a/src/third_party/skia/tools/picture_utils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef picture_utils_DEFINED
-#define picture_utils_DEFINED
-
-#include "SkBitmap.h"
-
-class SkData;
-class SkString;
-
-namespace sk_tools {
-    // since PNG insists on unpremultiplying our alpha, we take no precision
-    // chances and force all pixels to be 100% opaque, otherwise on compare we
-    // may not get a perfect match.
-    //
-    // This expects a bitmap with a config type of 8888 and for the pixels to
-    // not be on the GPU.
-    void force_all_opaque(const SkBitmap& bitmap);
-
-    /**
-     * Replaces all instances of oldChar with newChar in str.
-     */
-    void replace_char(SkString* str, const char oldChar, const char newChar);
-
-    // Returns true if the string ends with %
-    bool is_percentage(const char* const string);
-
-    // Prepares the bitmap so that it can be written.
-    //
-    // Specifically, it configures the bitmap, allocates pixels and then
-    // erases the pixels to transparent black.
-    void setup_bitmap(SkBitmap* bitmap, int width, int height);
-
-    /**
-     * Write a bitmap file to disk.
-     *
-     * @param bm the bitmap to record
-     * @param dirPath directory within which to write the image file
-     * @param subdirOrNull subdirectory within dirPath, or nullptr to just write into dirPath
-     * @param baseName last part of the filename
-     *
-     * @return true if written out successfully
-     */
-    bool write_bitmap_to_disk(const SkBitmap& bm, const SkString& dirPath,
-                              const char *subdirOrNull, const SkString& baseName);
-
-    // Return raw unpremultiplied RGBA bytes, suitable for storing in a PNG. The output
-    // colors are assumed to be sRGB values. This is only guaranteed to work for the
-    // cases that are currently emitted by tools:
-    // Linear premul 8888, sRGB premul 8888, Linear premul F16
-    sk_sp<SkData> encode_bitmap_for_png(SkBitmap bitmap);
-
-} // namespace sk_tools
-
-#endif  // picture_utils_DEFINED
diff --git a/src/third_party/skia/tools/pinspect.cpp b/src/third_party/skia/tools/pinspect.cpp
deleted file mode 100644
index 29a4222..0000000
--- a/src/third_party/skia/tools/pinspect.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkGraphics.h"
-#include "SkOSFile.h"
-#include "SkPicture.h"
-#include "SkStream.h"
-#include "SkString.h"
-#include "SkDumpCanvas.h"
-
-static sk_sp<SkPicture> inspect(const char path[]) {
-    SkFILEStream stream(path);
-    if (!stream.isValid()) {
-        printf("-- Can't open '%s'\n", path);
-        return nullptr;
-    }
-
-    printf("Opening '%s'...\n", path);
-
-    {
-        int32_t header[3];
-        if (stream.read(header, sizeof(header)) != sizeof(header)) {
-            printf("-- Failed to read header (12 bytes)\n");
-            return nullptr;
-        }
-        printf("version:%d width:%d height:%d\n", header[0], header[1], header[2]);
-    }
-
-    stream.rewind();
-    auto pic = SkPicture::MakeFromStream(&stream);
-    if (nullptr == pic) {
-        SkDebugf("Could not create SkPicture: %s\n", path);
-        return nullptr;
-    }
-    printf("picture cullRect: [%f %f %f %f]\n",
-           pic->cullRect().fLeft, pic->cullRect().fTop,
-           pic->cullRect().fRight, pic->cullRect().fBottom);
-    return pic;
-}
-
-static void dumpOps(SkPicture* pic) {
-#ifdef SK_DEBUG
-    SkDebugfDumper dumper;
-    SkDumpCanvas canvas(&dumper);
-    canvas.drawPicture(pic);
-#else
-    printf("SK_DEBUG mode not enabled\n");
-#endif
-}
-
-int main(int argc, char** argv) {
-    SkAutoGraphics ag;
-    if (argc < 2) {
-        printf("Usage: pinspect [--dump-ops] filename [filename ...]\n");
-        return 1;
-    }
-
-    bool doDumpOps = false;
-
-    int index = 1;
-    if (!strcmp(argv[index], "--dump-ops")) {
-        index += 1;
-        doDumpOps = true;
-    }
-
-    for (; index < argc; ++index) {
-        auto pic(inspect(argv[index]));
-        if (doDumpOps) {
-            dumpOps(pic.get());
-        }
-        if (index < argc - 1) {
-            printf("\n");
-        }
-    }
-    return 0;
-}
diff --git a/src/third_party/skia/tools/random_parse_path.cpp b/src/third_party/skia/tools/random_parse_path.cpp
index ffc4b58..4d13f65 100644
--- a/src/third_party/skia/tools/random_parse_path.cpp
+++ b/src/third_party/skia/tools/random_parse_path.cpp
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#include "SkRandom.h"
-#include "random_parse_path.h"
+#include "include/utils/SkRandom.h"
+#include "tools/random_parse_path.h"
 
 const struct Legal {
     char fSymbol;
diff --git a/src/third_party/skia/tools/random_parse_path.h b/src/third_party/skia/tools/random_parse_path.h
index 4dfa501..7071c8a 100644
--- a/src/third_party/skia/tools/random_parse_path.h
+++ b/src/third_party/skia/tools/random_parse_path.h
@@ -8,7 +8,7 @@
 #ifndef random_parse_path_DEFINED
 #define random_parse_path_DEFINED
 
-#include "SkString.h"
+#include "include/core/SkString.h"
 
 class SkRandom;
 
diff --git a/src/third_party/skia/tools/rebaseline/toggle_legacy_flag.py b/src/third_party/skia/tools/rebaseline/toggle_legacy_flag.py
new file mode 100644
index 0000000..80edeb2
--- /dev/null
+++ b/src/third_party/skia/tools/rebaseline/toggle_legacy_flag.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# Copyright (c) 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+README = """
+Automatically add or remove a specific legacy flag to multiple Skia client repos.
+
+This would only work on Google desktop.
+
+Example usage:
+  $ python toggle_legacy_flag.py SK_SUPPORT_LEGACY_SOMETHING \\
+      -a /data/android -c ~/chromium/src -g legacyflag
+
+If you only need to add the flag to one repo, for example, Android, please give
+only -a (--android-dir) argument:
+  $ python toggle_legacy_flag.py SK_SUPPORT_LEGACY_SOMETHING -a /data/android
+
+"""
+
+import os, sys
+import argparse
+import subprocess
+import getpass
+from random import randint
+
+
+ANDROID_TOOLS_DIR = os.path.join(
+    os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
+    'android')
+
+
+def toggle_android(args):
+  sys.path.append(ANDROID_TOOLS_DIR)
+  import upload_to_android
+
+  modifier = upload_to_android.AndroidLegacyFlagModifier(args.flag)
+  upload_to_android.upload_to_android(args.android_dir, modifier)
+
+
+def toggle_chromium(args):
+  os.chdir(args.chromium_dir)
+
+  branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
+  branch = branch.strip()
+
+  EXPECTED_STASH_OUT = "No local changes to save"
+  stash_output = subprocess.check_output(['git', 'stash']).strip()
+
+  if branch != "master" or stash_output != EXPECTED_STASH_OUT:
+    print ("Please checkout a clean master branch at your chromium repo (%s) "
+        "before running this script") % args.chromium_dir
+    if stash_output != EXPECTED_STASH_OUT:
+      subprocess.check_call(['git', 'stash', 'pop'])
+    exit(1)
+
+  # Update the repository to avoid conflicts
+  subprocess.check_call(['git', 'pull'])
+  subprocess.check_call(['gclient', 'sync']);
+
+  # Use random number to avoid branch name collision.
+  # We'll delete the branch in the end.
+  random = randint(1, 10000)
+  subprocess.check_call(['git', 'checkout', '-b', 'legacyflag_%d' % random])
+
+  try:
+    config_file = os.path.join('skia', 'config', 'SkUserConfig.h')
+    with open(config_file) as f:
+      lines = f.readlines()
+
+    flag_line = "#define %s\n" % args.flag
+    if flag_line in lines:
+      index = lines.index(flag_line)
+      del lines[index-1 : index +2]
+      verb = "Remove"
+    else:
+      separator = (
+        "/////////////////////////"
+        " Imported from BUILD.gn and skia_common.gypi\n")
+      content = ("#ifndef {0}\n"
+                 "#define {0}\n"
+                 "#endif\n\n").format(args.flag)
+      lines.insert(lines.index(separator), content)
+      verb = "Add"
+
+    with open(config_file, 'w') as f:
+      for line in lines:
+        f.write(line)
+
+    message = "%s %s" % (verb, args.flag)
+
+    subprocess.check_call('git commit -a -m "%s"' % message, shell=True)
+    subprocess.check_call('git cl upload -m "%s" -f' % message,
+                          shell=True)
+  finally:
+    subprocess.check_call(['git', 'checkout', 'master'])
+    subprocess.check_call(['git', 'branch', '-D', 'legacyflag_%d' % random])
+
+
+def toggle_google3(args):
+  G3_SCRIPT_DIR = os.path.expanduser("~/skia-g3/scripts")
+  if not os.path.isdir(G3_SCRIPT_DIR):
+    print ("Google3 directory unavailable.\n"
+           "Please see "
+           "https://sites.google.com/a/google.com/skia/rebaseline#g3_flag "
+           "for Google3 setup.")
+    exit(1)
+  sys.path.append(G3_SCRIPT_DIR)
+  import citc_flag
+
+  citc_flag.toggle_google3(args.google3, args.flag)
+
+
+def main():
+  if len(sys.argv) <= 1 or sys.argv[1] == '-h' or sys.argv[1] == '--help':
+    print README
+
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--android-dir', '-a', required=False,
+      help='Directory where an Android checkout will be created (if it does '
+           'not already exist). Note: ~1GB space will be used.')
+  parser.add_argument(
+      '--chromium-dir', '-c', required=False,
+      help='Directory of an EXISTING Chromium checkout (e.g., ~/chromium/src)')
+  parser.add_argument(
+      '--google3', '-g', required=False,
+      help='Google3 workspace to be created (if it does not already exist).')
+  parser.add_argument('flag', type=str, help='legacy flag name')
+
+  args = parser.parse_args()
+
+  if not args.android_dir and not args.chromium_dir and not args.google3:
+    print """
+Nothing to do. Please give me at least one of these three arguments:
+  -a (--android-dir)
+  -c (--chromium-dir)
+  -g (--google3)
+"""
+    exit(1)
+
+  end_message = "CLs generated. Now go review and land them:\n"
+  if args.chromium_dir:
+    args.chromium_dir = os.path.expanduser(args.chromium_dir)
+    toggle_chromium(args)
+    end_message += " * https://chromium-review.googlesource.com\n"
+  if args.google3:
+    toggle_google3(args)
+    end_message += " * http://goto.google.com/cl\n"
+  if args.android_dir:
+    args.android_dir = os.path.expanduser(args.android_dir)
+    toggle_android(args)
+    end_message += " * http://goto.google.com/androidcl\n"
+
+  print end_message
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/third_party/skia/tools/remote_demo.cpp b/src/third_party/skia/tools/remote_demo.cpp
new file mode 100644
index 0000000..91fd124
--- /dev/null
+++ b/src/third_party/skia/tools/remote_demo.cpp
@@ -0,0 +1,327 @@
+/*
+ * 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 <chrono>
+#include <err.h>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <thread>
+#include <unistd.h>
+
+#include "include/core/SkGraphics.h"
+#include "include/core/SkSurface.h"
+#include "src/core/SkRemoteGlyphCache.h"
+#include "src/core/SkScalerContext.h"
+
+static std::string gSkpName;
+static bool gUseGpu = true;
+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));
+    if (bytesWritten < 0) {
+        err(1,"Failed write %zu", size);
+        return false;
+    }
+
+    bytesWritten = ::write(fd, data.data(), data.size());
+    if (bytesWritten < 0) {
+        err(1,"Failed write %zu", size);
+        return false;
+    }
+
+    return true;
+}
+
+static sk_sp<SkData> read_SkData(int fd) {
+    size_t size;
+    ssize_t readSize = ::read(fd, &size, sizeof(size));
+    if (readSize <= 0) {
+        if (readSize < 0) {
+            err(1, "Failed read %zu", size);
+        }
+        return nullptr;
+    }
+
+    auto out = SkData::MakeUninitialized(size);
+    auto data = (uint8_t*)out->data();
+
+    size_t totalRead = 0;
+    while (totalRead < size) {
+        ssize_t sizeRead;
+        sizeRead = ::read(fd, &data[totalRead], size - totalRead);
+        if (sizeRead <= 0) {
+            if (readSize < 0) {
+                err(1, "Failed read %zu", size);
+            }
+            return nullptr;
+        }
+        totalRead += sizeRead;
+    }
+
+    return out;
+}
+
+class Timer {
+public:
+    void start() {
+        fStart = std::chrono::high_resolution_clock::now();
+    }
+
+    void stop() {
+        auto end = std::chrono::high_resolution_clock::now();
+        fElapsedSeconds += end - fStart;
+    }
+
+    double elapsedSeconds() {
+        return fElapsedSeconds.count();
+    }
+
+private:
+    decltype(std::chrono::high_resolution_clock::now()) fStart;
+    std::chrono::duration<double>                       fElapsedSeconds{0.0};
+};
+
+static bool push_font_data(const SkPicture& pic, SkStrikeServer* strikeServer,
+                           sk_sp<SkColorSpace> colorSpace, int writeFd) {
+    const SkIRect bounds = pic.cullRect().round();
+    const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
+    SkTextBlobCacheDiffCanvas filter(bounds.width(), bounds.height(), props,
+                                     strikeServer, std::move(colorSpace), true);
+    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, 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 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);
+
+    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) {
+            // 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();
+    }
+
+    std::cout << "useProcess: " << gUseProcess
+              << " useGPU: " << gUseGpu
+              << " purgeCache: " << gPurgeFontCaches << std::endl;
+    fprintf(stderr, "%s use GPU %s elapsed time %8.6f s\n", gSkpName.c_str(),
+            gUseGpu ? "true" : "false", drawTime.elapsedSeconds());
+
+    auto i = s->makeImageSnapshot();
+    auto data = i->encodeToData();
+    SkFILEWStream f(outFilename.c_str());
+    f.write(data->data(), data->size());
+}
+
+static void gpu(int readFd, int writeFd) {
+
+    if (gUseGpu) {
+        auto picData = read_SkData(readFd);
+        if (picData == nullptr) {
+            return;
+        }
+
+        sk_sp<ClientDiscardableManager> discardableManager = sk_make_sp<ClientDiscardableManager>();
+        SkStrikeClient strikeClient(discardableManager);
+
+        final_draw("test.png", picData.get(), &strikeClient, discardableManager.get(), readFd,
+                   writeFd);
+    }
+
+    ::close(writeFd);
+    ::close(readFd);
+
+    printf("GPU is exiting\n");
+}
+
+static int renderer(
+    const std::string& skpName, int readFd, int writeFd)
+{
+    ServerDiscardableManager discardableManager;
+    SkStrikeServer server(&discardableManager);
+    auto closeAll = [readFd, writeFd]() {
+        ::close(writeFd);
+        ::close(readFd);
+    };
+
+    auto skpData = SkData::MakeFromFileName(skpName.c_str());
+    std::cout << "skp stream is " << skpData->size() << " bytes long " << std::endl;
+
+    sk_sp<SkData> stream;
+    if (gUseGpu) {
+        auto pic = SkPicture::MakeFromData(skpData.get());
+        auto colorSpace = SkColorSpace::MakeSRGB();
+        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)) {
+            closeAll();
+            return 1;
+        }
+
+        while (true) {
+            auto inBuffer = read_SkData(readFd);
+            if (inBuffer == nullptr) {
+                closeAll();
+                return 0;
+            }
+            if (gPurgeFontCaches) discardableManager.purgeAll();
+            push_font_data(*pic.get(), &server, colorSpace, writeFd);
+        }
+    } else {
+        stream = skpData;
+        final_draw("test-correct.png", stream.get(), nullptr, nullptr, -1, -1);
+        closeAll();
+        return 0;
+    }
+}
+
+int main(int argc, char** argv) {
+    std::string skpName = argc > 1 ? std::string{argv[1]} : std::string{"skps/desk_nytimes.skp"};
+    int mode = argc > 2 ? atoi(argv[2]) : -1;
+    printf("skp: %s\n", skpName.c_str());
+
+    gSkpName = skpName;
+
+    enum direction : int {kRead = 0, kWrite = 1};
+
+
+    int render_to_gpu[2],
+        gpu_to_render[2];
+
+    for (int m = 0; m < 8; m++) {
+        int r = pipe(render_to_gpu);
+        if (r < 0) {
+            perror("Can't write picture from render to GPU ");
+            return 1;
+        }
+        r = pipe(gpu_to_render);
+        if (r < 0) {
+            perror("Can't write picture from render to GPU ");
+            return 1;
+        }
+
+        gPurgeFontCaches = (m & 4) == 4;
+        gUseGpu = (m & 2) == 2;
+        gUseProcess = (m & 1) == 1;
+
+        if (mode >= 0 && mode < 8 && mode != m) {
+            continue;
+        }
+
+        if (gUseProcess) {
+            pid_t child = fork();
+            SkGraphics::Init();
+
+            if (child == 0) {
+                close(gpu_to_render[kRead]);
+                close(render_to_gpu[kWrite]);
+                gpu(render_to_gpu[kRead], gpu_to_render[kWrite]);
+            } else {
+                close(render_to_gpu[kRead]);
+                close(gpu_to_render[kWrite]);
+                renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
+                waitpid(child, nullptr, 0);
+            }
+        } else {
+            SkGraphics::Init();
+            std::thread(gpu, render_to_gpu[kRead], gpu_to_render[kWrite]).detach();
+            renderer(skpName, gpu_to_render[kRead], render_to_gpu[kWrite]);
+        }
+    }
+
+    return 0;
+}
+
diff --git a/src/third_party/skia/tools/rewrite_includes.py b/src/third_party/skia/tools/rewrite_includes.py
new file mode 100644
index 0000000..d0ee8f8
--- /dev/null
+++ b/src/third_party/skia/tools/rewrite_includes.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python2
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import StringIO
+import argparse
+import os
+import sys
+
+parser = argparse.ArgumentParser()
+parser.add_argument('-n', '--dry-run', action='store_true',
+                    help='Just check there is nothing to rewrite.')
+parser.add_argument('sources', nargs='*',
+                    help='Source files to rewrite, or all if empty.')
+args = parser.parse_args()
+
+roots = [
+    'bench',
+    'dm',
+    'docs',
+    'example',
+    'experimental',
+    'fuzz',
+    'gm',
+    'include',
+    'modules',
+    'platform_tools/android/apps',
+    'samplecode',
+    'src',
+    'tests',
+    'third_party/etc1',
+    'third_party/gif',
+    'tools'
+  ]
+
+# Don't count our local Vulkan headers as Skia headers;
+# we don't want #include <vulkan/vulkan_foo.h> rewritten to point to them.
+blacklist = ['include/third_party/vulkan']
+
+assert '/' in [os.sep, os.altsep]
+def fix_path(p):
+  return p.replace(os.sep, os.altsep) if os.altsep else p
+
+# Map short name -> absolute path for all Skia headers.
+headers = {}
+for root in roots:
+  for path, _, files in os.walk(root):
+    if not any(snippet in fix_path(path) for snippet in blacklist):
+      for file_name in files:
+        if file_name.endswith('.h'):
+          if file_name in headers:
+            print path, file_name, headers[file_name]
+          assert file_name not in headers
+          headers[file_name] = os.path.abspath(os.path.join(path, file_name))
+
+def to_rewrite():
+  if args.sources:
+    for path in args.sources:
+      yield path
+  else:
+    for root in roots:
+      for path, _, files in os.walk(root):
+        for file_name in files:
+          yield os.path.join(path, file_name)
+
+# Rewrite any #includes relative to Skia's top-level directory.
+need_rewriting = []
+for file_path in to_rewrite():
+  if 'generated' in file_path or 'third_party/skcms' in file_path:
+    continue
+  if (file_path.endswith('.h') or
+      file_path.endswith('.c') or
+      file_path.endswith('.m') or
+      file_path.endswith('.mm') or
+      file_path.endswith('.inc') or
+      file_path.endswith('.fp') or
+      file_path.endswith('.cc') or
+      file_path.endswith('.cpp')):
+    # Read the whole file into memory.
+    lines = open(file_path).readlines()
+
+    # Write it back out again line by line with substitutions for #includes.
+    output = StringIO.StringIO() if args.dry_run else open(file_path, 'wb')
+
+    includes = []
+    for line in lines:
+      parts = line.replace('<', '"').replace('>', '"').split('"')
+      if (len(parts) == 3
+          and '#' in parts[0]
+          and 'include' in parts[0]
+          and os.path.basename(parts[1]) in headers):
+        header = fix_path(os.path.relpath(headers[os.path.basename(parts[1])], '.'))
+        includes.append(parts[0] + '"%s"' % header + parts[2])
+      else:
+        for inc in sorted(includes):
+          output.write(inc.strip('\n') + '\n')
+        includes = []
+        output.write(line.strip('\n') + '\n')
+
+    if args.dry_run and output.getvalue() != open(file_path).read():
+      need_rewriting.append(file_path)
+      rc = 1
+    output.close()
+
+if need_rewriting:
+  print 'Some files need rewritten #includes:'
+  for path in need_rewriting:
+    print '\t' + path
+  print 'To do this automatically, run'
+  print 'python tools/rewrite_includes.py ' + ' '.join(need_rewriting)
+  sys.exit(1)
diff --git a/src/third_party/skia/tools/viewer/sk_app/Application.h b/src/third_party/skia/tools/sk_app/Application.h
similarity index 100%
rename from src/third_party/skia/tools/viewer/sk_app/Application.h
rename to src/third_party/skia/tools/sk_app/Application.h
diff --git a/src/third_party/skia/tools/viewer/sk_app/CommandSet.cpp b/src/third_party/skia/tools/sk_app/CommandSet.cpp
similarity index 75%
rename from src/third_party/skia/tools/viewer/sk_app/CommandSet.cpp
rename to src/third_party/skia/tools/sk_app/CommandSet.cpp
index d0154d6..ea0eb13 100644
--- a/src/third_party/skia/tools/viewer/sk_app/CommandSet.cpp
+++ b/src/third_party/skia/tools/sk_app/CommandSet.cpp
@@ -5,10 +5,11 @@
 * found in the LICENSE file.
 */
 
-#include "CommandSet.h"
+#include "tools/sk_app/CommandSet.h"
 
-#include "SkCanvas.h"
-#include "SkTSort.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFont.h"
+#include "src/core/SkTSort.h"
 
 namespace sk_app {
 
@@ -34,8 +35,8 @@
     fWindow = window;
 }
 
-bool CommandSet::onKey(Window::Key key, Window::InputState state, uint32_t modifiers) {
-    if (Window::kDown_InputState == state) {
+bool CommandSet::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) {
+    if (skui::InputState::kDown == state) {
         for (Command& cmd : fCommands) {
             if (Command::kKey_CommandType == cmd.fType && key == cmd.fKey) {
                 cmd.fFunction();
@@ -47,7 +48,7 @@
     return false;
 }
 
-bool CommandSet::onChar(SkUnichar c, uint32_t modifiers) {
+bool CommandSet::onChar(SkUnichar c, skui::ModifierKey modifiers) {
     for (Command& cmd : fCommands) {
         if (Command::kChar_CommandType == cmd.fType && c == cmd.fChar) {
             cmd.fFunction();
@@ -73,12 +74,12 @@
     fCommands.push_back(Command(c, group, description, function));
 }
 
-void CommandSet::addCommand(Window::Key k, const char* keyName, const char* group,
+void CommandSet::addCommand(skui::Key k, const char* keyName, const char* group,
                             const char* description, std::function<void(void)> function) {
     fCommands.push_back(Command(k, keyName, group, description, function));
 }
 
-#if defined(SK_BUILD_FOR_WIN32)
+#if defined(SK_BUILD_FOR_WIN)
     #define SK_strcasecmp   _stricmp
 #else
     #define SK_strcasecmp   strcasecmp
@@ -101,17 +102,21 @@
     SkTQSort(fCommands.begin(), fCommands.end() - 1,
              kAlphabetical_HelpMode == fHelpMode ? compareCommandKey : compareCommandGroup);
 
+    SkFont font;
+    font.setSize(16);
+
+    SkFont groupFont;
+    groupFont.setSize(18);
+
     SkPaint bgPaint;
     bgPaint.setColor(0xC0000000);
     canvas->drawPaint(bgPaint);
 
     SkPaint paint;
-    paint.setTextSize(16);
     paint.setAntiAlias(true);
     paint.setColor(0xFFFFFFFF);
 
     SkPaint groupPaint;
-    groupPaint.setTextSize(18);
     groupPaint.setAntiAlias(true);
     groupPaint.setColor(0xFFFFFFFF);
 
@@ -122,14 +127,15 @@
     SkScalar keyWidth = 0;
     for (Command& cmd : fCommands) {
         keyWidth = SkMaxScalar(keyWidth,
-                               paint.measureText(cmd.fKeyName.c_str(), cmd.fKeyName.size()));
+                               font.measureText(cmd.fKeyName.c_str(), cmd.fKeyName.size(),
+                                                SkTextEncoding::kUTF8));
     }
-    keyWidth += paint.measureText(" ", 1);
+    keyWidth += font.measureText(" ", 1, SkTextEncoding::kUTF8);
 
     // If we're grouping by category, we'll be adding text height on every new group (including the
     // first), so no need to do that here. Otherwise, skip down so the first line is where we want.
     if (kGrouped_HelpMode != fHelpMode) {
-        y += paint.getTextSize();
+        y += font.getSize();
     }
 
     // Print everything:
@@ -137,16 +143,18 @@
     for (Command& cmd : fCommands) {
         if (kGrouped_HelpMode == fHelpMode && lastGroup != cmd.fGroup) {
             // Group change. Advance and print header:
-            y += paint.getTextSize();
-            canvas->drawString(cmd.fGroup, x, y, groupPaint);
-            y += groupPaint.getTextSize() + 2;
+            y += font.getSize();
+            canvas->drawSimpleText(cmd.fGroup.c_str(), cmd.fGroup.size(), SkTextEncoding::kUTF8,
+                                   x, y, groupFont, groupPaint);
+            y += groupFont.getSize() + 2;
             lastGroup = cmd.fGroup;
         }
 
-        canvas->drawString(cmd.fKeyName, x, y, paint);
+        canvas->drawSimpleText(cmd.fKeyName.c_str(), cmd.fKeyName.size(), SkTextEncoding::kUTF8,
+                               x, y, font, paint);
         SkString text = SkStringPrintf(": %s", cmd.fDescription.c_str());
-        canvas->drawString(text, x + keyWidth, y, paint);
-        y += paint.getTextSize() + 2;
+        canvas->drawString(text, x + keyWidth, y, font, paint);
+        y += font.getSize() + 2;
     }
 }
 
diff --git a/src/third_party/skia/tools/viewer/sk_app/CommandSet.h b/src/third_party/skia/tools/sk_app/CommandSet.h
similarity index 88%
rename from src/third_party/skia/tools/viewer/sk_app/CommandSet.h
rename to src/third_party/skia/tools/sk_app/CommandSet.h
index 0784a38..07a7def 100644
--- a/src/third_party/skia/tools/viewer/sk_app/CommandSet.h
+++ b/src/third_party/skia/tools/sk_app/CommandSet.h
@@ -8,8 +8,8 @@
 #ifndef CommandSet_DEFINED
 #define CommandSet_DEFINED
 
-#include "SkString.h"
-#include "Window.h"
+#include "include/core/SkString.h"
+#include "tools/sk_app/Window.h"
 
 #include <functional>
 #include <vector>
@@ -41,13 +41,13 @@
     CommandSet();
 
     void attach(Window* window);
-    bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers);
-    bool onChar(SkUnichar, uint32_t modifiers);
+    bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers);
+    bool onChar(SkUnichar, skui::ModifierKey modifiers);
     bool onSoftkey(const SkString& softkey);
 
     void addCommand(SkUnichar c, const char* group, const char* description,
                     std::function<void(void)> function);
-    void addCommand(Window::Key k, const char* keyName, const char* group, const char* description,
+    void addCommand(skui::Key k, const char* keyName, const char* group, const char* description,
                     std::function<void(void)> function);
 
     void drawHelp(SkCanvas* canvas);
@@ -70,7 +70,7 @@
             , fDescription(description)
             , fFunction(function) {}
 
-        Command(Window::Key k, const char* keyName, const char* group, const char* description,
+        Command(skui::Key k, const char* keyName, const char* group, const char* description,
                 std::function<void(void)> function)
             : fType(kKey_CommandType)
             , fKey(k)
@@ -85,7 +85,7 @@
         SkUnichar fChar;
 
         // For kKey_CommandType
-        Window::Key fKey;
+        skui::Key fKey;
 
         // Common to all command types
         SkString fKeyName;
diff --git a/src/third_party/skia/tools/sk_app/DawnWindowContext.cpp b/src/third_party/skia/tools/sk_app/DawnWindowContext.cpp
new file mode 100644
index 0000000..1d9b58e
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/DawnWindowContext.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkSurface.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContext.h"
+#include "src/core/SkAutoMalloc.h"
+#include "tools/sk_app/DawnWindowContext.h"
+
+#include "dawn/dawn_proc.h"
+
+static void PrintDeviceError(DawnErrorType, const char* message, void*) {
+    printf("Device error: %s\n", message);
+    SkASSERT(false);
+}
+
+namespace sk_app {
+
+DawnWindowContext::DawnWindowContext(const DisplayParams& params,
+                                     dawn::TextureFormat swapChainFormat)
+    : WindowContext(params)
+    , fSwapChainFormat(swapChainFormat)
+    , fInstance(std::make_unique<dawn_native::Instance>()) {
+}
+
+void DawnWindowContext::initializeContext(int width, int height) {
+    fWidth = width;
+    fHeight = height;
+    fDevice = onInitializeContext();
+    fContext = GrContext::MakeDawn(fDevice, fDisplayParams.fGrContextOptions);
+
+    if (!fContext) {
+        return;
+    }
+    fSwapChainImplementation = this->createSwapChainImplementation(-1, -1, fDisplayParams);
+    dawn::SwapChainDescriptor swapChainDesc;
+    swapChainDesc.implementation = reinterpret_cast<int64_t>(&fSwapChainImplementation);
+    fSwapChain = fDevice.CreateSwapChain(&swapChainDesc);
+    if (!fSwapChain) {
+        fContext.reset();
+        return;
+    }
+    fSwapChain.Configure(fSwapChainFormat, dawn::TextureUsage::OutputAttachment, width, height);
+    fDevice.SetUncapturedErrorCallback(PrintDeviceError, 0);
+}
+
+DawnWindowContext::~DawnWindowContext() {
+}
+
+void DawnWindowContext::destroyContext() {
+    if (!fDevice.Get()) {
+        return;
+    }
+
+    this->onDestroyContext();
+
+    fContext.reset();
+    fDevice = nullptr;
+}
+
+sk_sp<SkSurface> DawnWindowContext::getBackbufferSurface() {
+    GrDawnImageInfo imageInfo;
+    imageInfo.fTexture = fSwapChain.GetNextTexture();
+    imageInfo.fFormat = fSwapChainFormat;
+    imageInfo.fLevelCount = 1; // FIXME
+    GrBackendTexture backendTexture(fWidth, fHeight, imageInfo);
+    fSurface = SkSurface::MakeFromBackendTextureAsRenderTarget(fContext.get(),
+                                                               backendTexture,
+                                                               this->getRTOrigin(),
+                                                               fDisplayParams.fMSAASampleCount,
+                                                               fDisplayParams.fColorType,
+                                                               fDisplayParams.fColorSpace,
+                                                               &fDisplayParams.fSurfaceProps);
+    return fSurface;
+}
+
+void DawnWindowContext::swapBuffers() {
+    GrBackendRenderTarget backendRT = fSurface->getBackendRenderTarget(
+        SkSurface::kFlushRead_BackendHandleAccess);
+    GrDawnImageInfo imageInfo;
+    SkAssertResult(backendRT.getDawnImageInfo(&imageInfo));
+
+    fSwapChain.Present(imageInfo.fTexture);
+    this->onSwapBuffers();
+}
+
+void DawnWindowContext::resize(int w, int h) {
+    fWidth = w;
+    fHeight = h;
+    fSwapChainImplementation = this->createSwapChainImplementation(w, h, fDisplayParams);
+    dawn::SwapChainDescriptor swapChainDesc;
+    swapChainDesc.implementation = reinterpret_cast<int64_t>(&fSwapChainImplementation);
+    fSwapChain = fDevice.CreateSwapChain(&swapChainDesc);
+    if (!fSwapChain) {
+        fContext.reset();
+        return;
+    }
+    fSwapChain.Configure(fSwapChainFormat, dawn::TextureUsage::OutputAttachment, fWidth,
+                         fHeight);
+}
+
+void DawnWindowContext::setDisplayParams(const DisplayParams& params) {
+    fDisplayParams = params;
+}
+
+dawn::Device DawnWindowContext::createDevice(dawn_native::BackendType type) {
+    fInstance->DiscoverDefaultAdapters();
+    DawnProcTable backendProcs = dawn_native::GetProcs();
+    dawnProcSetProcs(&backendProcs);
+
+    std::vector<dawn_native::Adapter> adapters = fInstance->GetAdapters();
+    for (dawn_native::Adapter adapter : adapters) {
+        if (adapter.GetBackendType() == type) {
+            return adapter.CreateDevice();
+        }
+    }
+    return nullptr;
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/DawnWindowContext.h b/src/third_party/skia/tools/sk_app/DawnWindowContext.h
new file mode 100644
index 0000000..6c2e1c9
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/DawnWindowContext.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DawnWindowContext_DEFINED
+#define DawnWindowContext_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSurface.h"
+
+#include "tools/sk_app/WindowContext.h"
+#include "dawn/dawncpp.h"
+#include "dawn_native/DawnNative.h"
+#include "dawn/dawn_wsi.h"
+
+class GrContext;
+
+namespace sk_app {
+
+class DawnWindowContext : public WindowContext {
+public:
+    DawnWindowContext(const DisplayParams&, dawn::TextureFormat swapChainFormat);
+    ~DawnWindowContext() override;
+    sk_sp<SkSurface> getBackbufferSurface() override;
+    void swapBuffers() override;
+    bool isValid() override { return SkToBool(fDevice.Get()); }
+
+    void resize(int w, int h) override;
+
+    void setDisplayParams(const DisplayParams& params) override;
+
+protected:
+    bool isGpuContext() override { return true; }
+    void initializeContext(int width, int height);
+    dawn::Device createDevice(dawn_native::BackendType type);
+    virtual dawn::Device onInitializeContext() = 0;
+    virtual void onDestroyContext() = 0;
+    virtual void onSwapBuffers() = 0;
+    virtual GrSurfaceOrigin getRTOrigin() const { return kTopLeft_GrSurfaceOrigin; }
+    void destroyContext();
+    virtual DawnSwapChainImplementation createSwapChainImplementation( int width, int height,
+        const DisplayParams& params) = 0;
+
+    sk_sp<SkSurface>              fSurface;
+    DawnSwapChainImplementation   fSwapChainImplementation;
+    dawn::TextureFormat           fSwapChainFormat;
+    dawn::SwapChain               fSwapChain;
+    dawn::Device                  fDevice;
+    std::unique_ptr<dawn_native::Instance> fInstance;
+};
+
+}   // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/DisplayParams.h b/src/third_party/skia/tools/sk_app/DisplayParams.h
similarity index 61%
rename from src/third_party/skia/tools/viewer/sk_app/DisplayParams.h
rename to src/third_party/skia/tools/sk_app/DisplayParams.h
index 959735e..afad8e1 100644
--- a/src/third_party/skia/tools/viewer/sk_app/DisplayParams.h
+++ b/src/third_party/skia/tools/sk_app/DisplayParams.h
@@ -7,8 +7,9 @@
 #ifndef DisplayParams_DEFINED
 #define DisplayParams_DEFINED
 
-#include "GrContextOptions.h"
-#include "SkImageInfo.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkSurfaceProps.h"
+#include "include/gpu/GrContextOptions.h"
 
 namespace sk_app {
 
@@ -16,12 +17,17 @@
     DisplayParams()
         : fColorType(kN32_SkColorType)
         , fColorSpace(nullptr)
-        , fMSAASampleCount(0) {}
+        , fMSAASampleCount(1)
+        , fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
+        , fDisableVsync(false)
+    {}
 
     SkColorType         fColorType;
     sk_sp<SkColorSpace> fColorSpace;
     int                 fMSAASampleCount;
     GrContextOptions    fGrContextOptions;
+    SkSurfaceProps      fSurfaceProps;
+    bool                fDisableVsync;
 };
 
 }   // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/GLWindowContext.cpp b/src/third_party/skia/tools/sk_app/GLWindowContext.cpp
new file mode 100644
index 0000000..6e6130b
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/GLWindowContext.cpp
@@ -0,0 +1,98 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkSurface.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContext.h"
+#include "src/core/SkMathPriv.h"
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/gl/GrGLDefines.h"
+#include "src/gpu/gl/GrGLUtil.h"
+#include "src/image/SkImage_Base.h"
+#include "tools/sk_app/GLWindowContext.h"
+
+namespace sk_app {
+
+GLWindowContext::GLWindowContext(const DisplayParams& params)
+    : WindowContext(params)
+    , fBackendContext(nullptr)
+    , fSurface(nullptr) {
+    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
+}
+
+void GLWindowContext::initializeContext() {
+    SkASSERT(!fContext);
+
+    fBackendContext = this->onInitializeContext();
+    fContext = GrContext::MakeGL(fBackendContext, fDisplayParams.fGrContextOptions);
+    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
+        fDisplayParams.fMSAASampleCount /= 2;
+        this->initializeContext();
+        return;
+    }
+}
+
+void GLWindowContext::destroyContext() {
+    fSurface.reset(nullptr);
+
+    if (fContext) {
+        // in case we have outstanding refs to this guy (lua?)
+        fContext->abandonContext();
+        fContext.reset();
+    }
+
+    fBackendContext.reset(nullptr);
+
+    this->onDestroyContext();
+}
+
+sk_sp<SkSurface> GLWindowContext::getBackbufferSurface() {
+    if (nullptr == fSurface) {
+        if (fContext) {
+            GrGLint buffer;
+            GR_GL_CALL(fBackendContext.get(), GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer));
+
+            GrGLFramebufferInfo fbInfo;
+            fbInfo.fFBOID = buffer;
+            fbInfo.fFormat = GR_GL_RGBA8;
+
+            GrBackendRenderTarget backendRT(fWidth,
+                                            fHeight,
+                                            fSampleCount,
+                                            fStencilBits,
+                                            fbInfo);
+
+            fSurface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
+                                                              kBottomLeft_GrSurfaceOrigin,
+                                                              kRGBA_8888_SkColorType,
+                                                              fDisplayParams.fColorSpace,
+                                                              &fDisplayParams.fSurfaceProps);
+        }
+    }
+
+    return fSurface;
+}
+
+void GLWindowContext::swapBuffers() {
+    this->onSwapBuffers();
+}
+
+void GLWindowContext::resize(int w, int h) {
+    this->destroyContext();
+    this->initializeContext();
+}
+
+void GLWindowContext::setDisplayParams(const DisplayParams& params) {
+    fDisplayParams = params;
+    this->destroyContext();
+    this->initializeContext();
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/GLWindowContext.h b/src/third_party/skia/tools/sk_app/GLWindowContext.h
similarity index 82%
rename from src/third_party/skia/tools/viewer/sk_app/GLWindowContext.h
rename to src/third_party/skia/tools/sk_app/GLWindowContext.h
index 09d544a..8d3085b 100644
--- a/src/third_party/skia/tools/viewer/sk_app/GLWindowContext.h
+++ b/src/third_party/skia/tools/sk_app/GLWindowContext.h
@@ -9,12 +9,12 @@
 #define GLWindowContext_DEFINED
 
 
-#include "gl/GrGLInterface.h"
+#include "include/gpu/gl/GrGLInterface.h"
 
-#include "SkRefCnt.h"
-#include "SkSurface.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSurface.h"
 
-#include "WindowContext.h"
+#include "tools/sk_app/WindowContext.h"
 
 class GrContext;
 
@@ -31,16 +31,12 @@
 
     void setDisplayParams(const DisplayParams& params) override;
 
-    GrBackendContext getBackendContext() override {
-        return (GrBackendContext) fBackendContext.get();
-    }
-
 protected:
     GLWindowContext(const DisplayParams&);
     // This should be called by subclass constructor. It is also called when window/display
     // parameters change. This will in turn call onInitializeContext().
     void initializeContext();
-    virtual void onInitializeContext() = 0;
+    virtual sk_sp<const GrGLInterface> onInitializeContext() = 0;
 
     // This should be called by subclass destructor. It is also called when window/display
     // parameters change prior to initializing a new GL context. This will in turn call
diff --git a/src/third_party/skia/tools/sk_app/MetalWindowContext.h b/src/third_party/skia/tools/sk_app/MetalWindowContext.h
new file mode 100644
index 0000000..8fe19bf
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/MetalWindowContext.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef MetalWindowContext_DEFINED
+#define MetalWindowContext_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSurface.h"
+
+#include "tools/sk_app/WindowContext.h"
+
+#import <Metal/Metal.h>
+#import <QuartzCore/CAMetalLayer.h>
+
+namespace sk_app {
+
+class MetalWindowContext : public WindowContext {
+public:
+    sk_sp<SkSurface> getBackbufferSurface() override;
+
+    bool isValid() override { return fValid; }
+
+    void swapBuffers() override;
+
+    void setDisplayParams(const DisplayParams& params) override;
+
+protected:
+    MetalWindowContext(const DisplayParams&);
+    // This should be called by subclass constructor. It is also called when window/display
+    // parameters change. This will in turn call onInitializeContext().
+    void initializeContext();
+    virtual bool onInitializeContext() = 0;
+
+    // This should be called by subclass destructor. It is also called when window/display
+    // parameters change prior to initializing a new Metal context. This will in turn call
+    // onDestroyContext().
+    void destroyContext();
+    virtual void onDestroyContext() = 0;
+
+    bool                        fValid;
+    id<MTLDevice>               fDevice;
+    id<MTLCommandQueue>         fQueue;
+    CAMetalLayer*               fMetalLayer;
+    id<CAMetalDrawable>         fCurrentDrawable;
+};
+
+}   // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/MetalWindowContext.mm b/src/third_party/skia/tools/sk_app/MetalWindowContext.mm
new file mode 100644
index 0000000..fbcc849
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/MetalWindowContext.mm
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkSurface.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/mtl/GrMtlTypes.h"
+#include "src/core/SkMathPriv.h"
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/image/SkImage_Base.h"
+#include "tools/sk_app/MetalWindowContext.h"
+
+using sk_app::DisplayParams;
+using sk_app::MetalWindowContext;
+
+namespace sk_app {
+
+MetalWindowContext::MetalWindowContext(const DisplayParams& params)
+    : WindowContext(params)
+    , fValid(false) {
+
+    fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
+}
+
+void MetalWindowContext::initializeContext() {
+    SkASSERT(!fContext);
+
+    fDevice = MTLCreateSystemDefaultDevice();
+    fQueue = [fDevice newCommandQueue];
+
+    if (fDisplayParams.fMSAASampleCount > 1) {
+        if (@available(macOS 10.11, iOS 9.0, *)) {
+            if (![fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
+                return;
+            }
+        } else {
+            return;
+        }
+    }
+    fSampleCount = fDisplayParams.fMSAASampleCount;
+    fStencilBits = 8;
+
+    fValid = this->onInitializeContext();
+
+    fContext = GrContext::MakeMetal((__bridge void*)fDevice, (__bridge void*)fQueue,
+                                    fDisplayParams.fGrContextOptions);
+    if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
+        fDisplayParams.fMSAASampleCount /= 2;
+        this->initializeContext();
+        return;
+    }
+}
+
+void MetalWindowContext::destroyContext() {
+    if (fContext) {
+        // in case we have outstanding refs to this guy (lua?)
+        fContext->abandonContext();
+        fContext.reset();
+    }
+
+    this->onDestroyContext();
+
+    fMetalLayer = nil;
+    fValid = false;
+
+    [fQueue release];
+    [fDevice release];
+}
+
+sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
+    sk_sp<SkSurface> surface;
+    if (fContext) {
+        GrMTLHandle drawable;
+        surface = SkSurface::MakeFromCAMetalLayer(fContext.get(), (__bridge GrMTLHandle)fMetalLayer,
+                                                  kTopLeft_GrSurfaceOrigin, fSampleCount,
+                                                  kBGRA_8888_SkColorType,
+                                                  fDisplayParams.fColorSpace,
+                                                  &fDisplayParams.fSurfaceProps,
+                                                  &drawable);
+        // ARC is off in sk_app, so we need to release the CF ref manually
+        fCurrentDrawable = (id<CAMetalDrawable>)drawable;
+        CFRelease(drawable);
+    }
+
+    return surface;
+}
+
+void MetalWindowContext::swapBuffers() {
+    id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
+    commandBuffer.label = @"Present";
+
+    [commandBuffer presentDrawable:fCurrentDrawable];
+    [commandBuffer commit];
+    fCurrentDrawable = nil;
+}
+
+void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
+    this->destroyContext();
+    fDisplayParams = params;
+    this->initializeContext();
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/RasterWindowContext.h b/src/third_party/skia/tools/sk_app/RasterWindowContext.h
similarity index 70%
rename from src/third_party/skia/tools/viewer/sk_app/RasterWindowContext.h
rename to src/third_party/skia/tools/sk_app/RasterWindowContext.h
index 75bde03..4a01aab 100644
--- a/src/third_party/skia/tools/viewer/sk_app/RasterWindowContext.h
+++ b/src/third_party/skia/tools/sk_app/RasterWindowContext.h
@@ -8,7 +8,7 @@
 #ifndef RasterWindowContext_DEFINED
 #define RasterWindowContext_DEFINED
 
-#include "WindowContext.h"
+#include "tools/sk_app/WindowContext.h"
 
 namespace sk_app {
 
@@ -16,9 +16,6 @@
 public:
     RasterWindowContext(const DisplayParams& params) : WindowContext(params) {}
 
-    // Explicitly convert nullptr to GrBackendContext is needed for compiling
-    GrBackendContext getBackendContext() override { return (GrBackendContext) nullptr; }
-
 protected:
     bool isGpuContext() override { return false; }
 };
diff --git a/src/third_party/skia/tools/sk_app/VulkanWindowContext.cpp b/src/third_party/skia/tools/sk_app/VulkanWindowContext.cpp
new file mode 100644
index 0000000..793c88c
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/VulkanWindowContext.cpp
@@ -0,0 +1,544 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/VulkanWindowContext.h"
+
+#include "include/core/SkSurface.h"
+#include "include/gpu/GrBackendSemaphore.h"
+#include "include/gpu/GrBackendSurface.h"
+#include "include/gpu/GrContext.h"
+#include "src/core/SkAutoMalloc.h"
+
+#include "include/gpu/vk/GrVkExtensions.h"
+#include "include/gpu/vk/GrVkTypes.h"
+#include "src/gpu/vk/GrVkImage.h"
+#include "src/gpu/vk/GrVkUtil.h"
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
+#undef CreateSemaphore
+#endif
+
+#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
+#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
+
+namespace sk_app {
+
+VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
+                                         CreateVkSurfaceFn createVkSurface,
+                                         CanPresentFn canPresent,
+                                         PFN_vkGetInstanceProcAddr instProc,
+                                         PFN_vkGetDeviceProcAddr devProc)
+    : WindowContext(params)
+    , fCreateVkSurfaceFn(createVkSurface)
+    , fCanPresentFn(canPresent)
+    , fSurface(VK_NULL_HANDLE)
+    , fSwapchain(VK_NULL_HANDLE)
+    , fImages(nullptr)
+    , fImageLayouts(nullptr)
+    , fSurfaces(nullptr)
+    , fBackbuffers(nullptr) {
+    fGetInstanceProcAddr = instProc;
+    fGetDeviceProcAddr = devProc;
+    this->initializeContext();
+}
+
+void VulkanWindowContext::initializeContext() {
+    // any config code here (particularly for msaa)?
+
+    PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
+    PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr;
+    auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
+                                                    VkInstance instance, VkDevice device) {
+        if (device != VK_NULL_HANDLE) {
+            return getDeviceProc(device, proc_name);
+        }
+        return getInstanceProc(instance, proc_name);
+    };
+    GrVkBackendContext backendContext;
+    GrVkExtensions extensions;
+    VkPhysicalDeviceFeatures2 features;
+    if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features,
+                                             &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) {
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+
+    if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
+        !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+
+    fInstance = backendContext.fInstance;
+    fPhysicalDevice = backendContext.fPhysicalDevice;
+    fDevice = backendContext.fDevice;
+    fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
+    fGraphicsQueue = backendContext.fQueue;
+
+    PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
+            reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
+                    backendContext.fGetProc("vkGetPhysicalDeviceProperties",
+                                            backendContext.fInstance,
+                                            VK_NULL_HANDLE));
+    if (!localGetPhysicalDeviceProperties) {
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+    VkPhysicalDeviceProperties physDeviceProperties;
+    localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
+    uint32_t physDevVersion = physDeviceProperties.apiVersion;
+
+    fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
+                                       backendContext.fInstanceVersion, physDevVersion,
+                                       &extensions));
+
+    GET_PROC(DestroyInstance);
+    if (fDebugCallback != VK_NULL_HANDLE) {
+        GET_PROC(DestroyDebugReportCallbackEXT);
+    }
+    GET_PROC(DestroySurfaceKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
+    GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
+    GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
+    GET_DEV_PROC(DeviceWaitIdle);
+    GET_DEV_PROC(QueueWaitIdle);
+    GET_DEV_PROC(DestroyDevice);
+    GET_DEV_PROC(CreateSwapchainKHR);
+    GET_DEV_PROC(DestroySwapchainKHR);
+    GET_DEV_PROC(GetSwapchainImagesKHR);
+    GET_DEV_PROC(AcquireNextImageKHR);
+    GET_DEV_PROC(QueuePresentKHR);
+    GET_DEV_PROC(GetDeviceQueue);
+
+    fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
+
+    fSurface = fCreateVkSurfaceFn(fInstance);
+    if (VK_NULL_HANDLE == fSurface) {
+        this->destroyContext();
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+
+    VkBool32 supported;
+    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
+                                                       fSurface, &supported);
+    if (VK_SUCCESS != res) {
+        this->destroyContext();
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+
+    if (!this->createSwapchain(-1, -1, fDisplayParams)) {
+        this->destroyContext();
+        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+        return;
+    }
+
+    // create presentQueue
+    fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
+    sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+}
+
+bool VulkanWindowContext::createSwapchain(int width, int height,
+                                          const DisplayParams& params) {
+    // check for capabilities
+    VkSurfaceCapabilitiesKHR caps;
+    VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    uint32_t surfaceFormatCount;
+    res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
+                                              nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
+    VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
+    res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
+                                              surfaceFormats);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    uint32_t presentModeCount;
+    res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
+                                                   nullptr);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
+    VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
+    res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
+                                                   presentModes);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    VkExtent2D extent = caps.currentExtent;
+    // use the hints
+    if (extent.width == (uint32_t)-1) {
+        extent.width = width;
+        extent.height = height;
+    }
+
+    // clamp width; to protect us from broken hints
+    if (extent.width < caps.minImageExtent.width) {
+        extent.width = caps.minImageExtent.width;
+    } else if (extent.width > caps.maxImageExtent.width) {
+        extent.width = caps.maxImageExtent.width;
+    }
+    // clamp height
+    if (extent.height < caps.minImageExtent.height) {
+        extent.height = caps.minImageExtent.height;
+    } else if (extent.height > caps.maxImageExtent.height) {
+        extent.height = caps.maxImageExtent.height;
+    }
+
+    fWidth = (int)extent.width;
+    fHeight = (int)extent.height;
+
+    uint32_t imageCount = caps.minImageCount + 2;
+    if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
+        // Application must settle for fewer images than desired:
+        imageCount = caps.maxImageCount;
+    }
+
+    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
+    SkASSERT(caps.supportedTransforms & caps.currentTransform);
+    SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
+                                             VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
+    VkCompositeAlphaFlagBitsKHR composite_alpha =
+        (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
+                                        VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
+                                        VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+
+    // Pick our surface format.
+    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
+    VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
+    for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
+        VkFormat localFormat = surfaceFormats[i].format;
+        if (GrVkFormatIsSupported(localFormat)) {
+            surfaceFormat = localFormat;
+            colorSpace = surfaceFormats[i].colorSpace;
+            break;
+        }
+    }
+    fDisplayParams = params;
+    fSampleCount = SkTMax(1, params.fMSAASampleCount);
+    fStencilBits = 8;
+
+    if (VK_FORMAT_UNDEFINED == surfaceFormat) {
+        return false;
+    }
+
+    SkColorType colorType;
+    switch (surfaceFormat) {
+        case VK_FORMAT_R8G8B8A8_UNORM: // fall through
+        case VK_FORMAT_R8G8B8A8_SRGB:
+            colorType = kRGBA_8888_SkColorType;
+            break;
+        case VK_FORMAT_B8G8R8A8_UNORM: // fall through
+            colorType = kBGRA_8888_SkColorType;
+            break;
+        default:
+            return false;
+    }
+
+    // If mailbox mode is available, use it, as it is the lowest-latency non-
+    // tearing mode. If not, fall back to FIFO which is always available.
+    VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
+    bool hasImmediate = false;
+    for (uint32_t i = 0; i < presentModeCount; ++i) {
+        // use mailbox
+        if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
+            mode = VK_PRESENT_MODE_MAILBOX_KHR;
+        }
+        if (VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i]) {
+            hasImmediate = true;
+        }
+    }
+    if (params.fDisableVsync && hasImmediate) {
+        mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
+    }
+
+    VkSwapchainCreateInfoKHR swapchainCreateInfo;
+    memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
+    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+    swapchainCreateInfo.surface = fSurface;
+    swapchainCreateInfo.minImageCount = imageCount;
+    swapchainCreateInfo.imageFormat = surfaceFormat;
+    swapchainCreateInfo.imageColorSpace = colorSpace;
+    swapchainCreateInfo.imageExtent = extent;
+    swapchainCreateInfo.imageArrayLayers = 1;
+    swapchainCreateInfo.imageUsage = usageFlags;
+
+    uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
+    if (fGraphicsQueueIndex != fPresentQueueIndex) {
+        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
+        swapchainCreateInfo.queueFamilyIndexCount = 2;
+        swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
+    } else {
+        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+        swapchainCreateInfo.queueFamilyIndexCount = 0;
+        swapchainCreateInfo.pQueueFamilyIndices = nullptr;
+    }
+
+    swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    swapchainCreateInfo.compositeAlpha = composite_alpha;
+    swapchainCreateInfo.presentMode = mode;
+    swapchainCreateInfo.clipped = true;
+    swapchainCreateInfo.oldSwapchain = fSwapchain;
+
+    res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
+    if (VK_SUCCESS != res) {
+        return false;
+    }
+
+    // destroy the old swapchain
+    if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
+        fDeviceWaitIdle(fDevice);
+
+        this->destroyBuffers();
+
+        fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
+    }
+
+    this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
+
+    return true;
+}
+
+void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
+    fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
+    SkASSERT(fImageCount);
+    fImages = new VkImage[fImageCount];
+    fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
+
+    // set up initial image layouts and create surfaces
+    fImageLayouts = new VkImageLayout[fImageCount];
+    fSurfaces = new sk_sp<SkSurface>[fImageCount];
+    for (uint32_t i = 0; i < fImageCount; ++i) {
+        fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
+
+        GrVkImageInfo info;
+        info.fImage = fImages[i];
+        info.fAlloc = GrVkAlloc();
+        info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+        info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+        info.fFormat = format;
+        info.fLevelCount = 1;
+        info.fCurrentQueueFamily = fPresentQueueIndex;
+
+        if (fSampleCount == 1) {
+            GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
+
+            fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(
+                    fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, colorType,
+                    fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
+        } else {
+            GrBackendTexture backendTexture(fWidth, fHeight, info);
+
+            // We don't set the sampled usage bit on the swapchain so this can't be a GrTexture.
+            fSurfaces[i] = SkSurface::MakeFromBackendTextureAsRenderTarget(
+                    fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
+                    colorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
+
+        }
+    }
+
+    // set up the backbuffers
+    VkSemaphoreCreateInfo semaphoreInfo;
+    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = nullptr;
+    semaphoreInfo.flags = 0;
+
+    // we create one additional backbuffer structure here, because we want to
+    // give the command buffers they contain a chance to finish before we cycle back
+    fBackbuffers = new BackbufferInfo[fImageCount + 1];
+    for (uint32_t i = 0; i < fImageCount + 1; ++i) {
+        fBackbuffers[i].fImageIndex = -1;
+        GR_VK_CALL_ERRCHECK(fInterface,
+                            CreateSemaphore(fDevice, &semaphoreInfo,
+                                            nullptr, &fBackbuffers[i].fRenderSemaphore));
+    }
+    fCurrentBackbufferIndex = fImageCount;
+}
+
+void VulkanWindowContext::destroyBuffers() {
+
+    if (fBackbuffers) {
+        for (uint32_t i = 0; i < fImageCount + 1; ++i) {
+            fBackbuffers[i].fImageIndex = -1;
+            GR_VK_CALL(fInterface,
+                       DestroySemaphore(fDevice,
+                                        fBackbuffers[i].fRenderSemaphore,
+                                        nullptr));
+        }
+    }
+
+    delete[] fBackbuffers;
+    fBackbuffers = nullptr;
+
+    // Does this actually free the surfaces?
+    delete[] fSurfaces;
+    fSurfaces = nullptr;
+    delete[] fImageLayouts;
+    fImageLayouts = nullptr;
+    delete[] fImages;
+    fImages = nullptr;
+}
+
+VulkanWindowContext::~VulkanWindowContext() {
+    this->destroyContext();
+}
+
+void VulkanWindowContext::destroyContext() {
+    if (this->isValid()) {
+        fQueueWaitIdle(fPresentQueue);
+        fDeviceWaitIdle(fDevice);
+
+        this->destroyBuffers();
+
+        if (VK_NULL_HANDLE != fSwapchain) {
+            fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
+            fSwapchain = VK_NULL_HANDLE;
+        }
+
+        if (VK_NULL_HANDLE != fSurface) {
+            fDestroySurfaceKHR(fInstance, fSurface, nullptr);
+            fSurface = VK_NULL_HANDLE;
+        }
+    }
+
+    fContext.reset();
+    fInterface.reset();
+
+    if (VK_NULL_HANDLE != fDevice) {
+        fDestroyDevice(fDevice, nullptr);
+        fDevice = VK_NULL_HANDLE;
+    }
+
+#ifdef SK_ENABLE_VK_LAYERS
+    if (fDebugCallback != VK_NULL_HANDLE) {
+        fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
+    }
+#endif
+
+    fPhysicalDevice = VK_NULL_HANDLE;
+
+    if (VK_NULL_HANDLE != fInstance) {
+        fDestroyInstance(fInstance, nullptr);
+        fInstance = VK_NULL_HANDLE;
+    }
+}
+
+VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
+    SkASSERT(fBackbuffers);
+
+    ++fCurrentBackbufferIndex;
+    if (fCurrentBackbufferIndex > fImageCount) {
+        fCurrentBackbufferIndex = 0;
+    }
+
+    BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
+    return backbuffer;
+}
+
+sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
+    BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
+    SkASSERT(backbuffer);
+
+    // semaphores should be in unsignaled state
+    VkSemaphoreCreateInfo semaphoreInfo;
+    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
+    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    semaphoreInfo.pNext = nullptr;
+    semaphoreInfo.flags = 0;
+    VkSemaphore semaphore;
+    GR_VK_CALL_ERRCHECK(fInterface, CreateSemaphore(fDevice, &semaphoreInfo,
+                                                    nullptr, &semaphore));
+
+    // acquire the image
+    VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
+                                        semaphore, VK_NULL_HANDLE,
+                                        &backbuffer->fImageIndex);
+    if (VK_ERROR_SURFACE_LOST_KHR == res) {
+        // need to figure out how to create a new vkSurface without the platformData*
+        // maybe use attach somehow? but need a Window
+        GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
+        return nullptr;
+    }
+    if (VK_ERROR_OUT_OF_DATE_KHR == res) {
+        // tear swapchain down and try again
+        if (!this->createSwapchain(-1, -1, fDisplayParams)) {
+            GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
+            return nullptr;
+        }
+        backbuffer = this->getAvailableBackbuffer();
+
+        // acquire the image
+        res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
+                                   semaphore, VK_NULL_HANDLE,
+                                   &backbuffer->fImageIndex);
+
+        if (VK_SUCCESS != res) {
+            GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
+            return nullptr;
+        }
+    }
+
+    SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
+
+    GrBackendSemaphore beSemaphore;
+    beSemaphore.initVulkan(semaphore);
+
+    surface->wait(1, &beSemaphore);
+
+    return sk_ref_sp(surface);
+}
+
+void VulkanWindowContext::swapBuffers() {
+
+    BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
+    SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
+
+    GrBackendSemaphore beSemaphore;
+    beSemaphore.initVulkan(backbuffer->fRenderSemaphore);
+
+    GrFlushInfo info;
+    info.fNumSemaphores = 1;
+    info.fSignalSemaphores = &beSemaphore;
+    surface->flush(SkSurface::BackendSurfaceAccess::kPresent, info);
+
+    // Submit present operation to present queue
+    const VkPresentInfoKHR presentInfo =
+    {
+        VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
+        NULL, // pNext
+        1, // waitSemaphoreCount
+        &backbuffer->fRenderSemaphore, // pWaitSemaphores
+        1, // swapchainCount
+        &fSwapchain, // pSwapchains
+        &backbuffer->fImageIndex, // pImageIndices
+        NULL // pResults
+    };
+
+    fQueuePresentKHR(fPresentQueue, &presentInfo);
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/VulkanWindowContext.h b/src/third_party/skia/tools/sk_app/VulkanWindowContext.h
new file mode 100644
index 0000000..2db9e79
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/VulkanWindowContext.h
@@ -0,0 +1,121 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef VulkanWindowContext_DEFINED
+#define VulkanWindowContext_DEFINED
+
+#include "include/core/SkTypes.h"
+
+#ifdef SK_VULKAN
+
+#include "include/gpu/vk/GrVkVulkan.h"
+
+#include "include/gpu/vk/GrVkBackendContext.h"
+#include "src/gpu/vk/GrVkInterface.h"
+#include "tools/gpu/vk/VkTestUtils.h"
+#include "tools/sk_app/WindowContext.h"
+
+class GrRenderTarget;
+
+namespace sk_app {
+
+class VulkanWindowContext : public WindowContext {
+public:
+    ~VulkanWindowContext() override;
+
+    sk_sp<SkSurface> getBackbufferSurface() override;
+    void swapBuffers() override;
+
+    bool isValid() override { return fDevice != VK_NULL_HANDLE; }
+
+    void resize(int w, int h) override {
+        this->createSwapchain(w, h, fDisplayParams);
+    }
+
+    void setDisplayParams(const DisplayParams& params) override {
+        this->destroyContext();
+        fDisplayParams = params;
+        this->initializeContext();
+    }
+
+    /** Platform specific function that creates a VkSurfaceKHR for a window */
+    using CreateVkSurfaceFn = std::function<VkSurfaceKHR(VkInstance)>;
+    /** Platform specific function that determines whether presentation will succeed. */
+    using CanPresentFn = sk_gpu_test::CanPresentFn;
+
+    VulkanWindowContext(const DisplayParams&, CreateVkSurfaceFn, CanPresentFn,
+                        PFN_vkGetInstanceProcAddr, PFN_vkGetDeviceProcAddr);
+
+private:
+    void initializeContext();
+    void destroyContext();
+
+    struct BackbufferInfo {
+        uint32_t        fImageIndex;          // image this is associated with
+        VkSemaphore     fRenderSemaphore;     // we wait on this for rendering to be done
+    };
+
+    BackbufferInfo* getAvailableBackbuffer();
+    bool createSwapchain(int width, int height, const DisplayParams& params);
+    void createBuffers(VkFormat format, SkColorType colorType);
+    void destroyBuffers();
+
+    VkInstance fInstance = VK_NULL_HANDLE;
+    VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE;
+    VkDevice fDevice = VK_NULL_HANDLE;
+    VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE;
+
+    // Create functions
+    CreateVkSurfaceFn fCreateVkSurfaceFn;
+    CanPresentFn      fCanPresentFn;
+
+    // Vulkan GetProcAddr functions
+    PFN_vkGetInstanceProcAddr fGetInstanceProcAddr = nullptr;
+    PFN_vkGetDeviceProcAddr fGetDeviceProcAddr = nullptr;
+
+    // WSI interface functions
+    PFN_vkDestroySurfaceKHR fDestroySurfaceKHR = nullptr;
+    PFN_vkGetPhysicalDeviceSurfaceSupportKHR fGetPhysicalDeviceSurfaceSupportKHR = nullptr;
+    PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fGetPhysicalDeviceSurfaceCapabilitiesKHR =nullptr;
+    PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fGetPhysicalDeviceSurfaceFormatsKHR = nullptr;
+    PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fGetPhysicalDeviceSurfacePresentModesKHR =nullptr;
+
+    PFN_vkCreateSwapchainKHR fCreateSwapchainKHR = nullptr;
+    PFN_vkDestroySwapchainKHR fDestroySwapchainKHR = nullptr;
+    PFN_vkGetSwapchainImagesKHR fGetSwapchainImagesKHR = nullptr;
+    PFN_vkAcquireNextImageKHR fAcquireNextImageKHR = nullptr;
+    PFN_vkQueuePresentKHR fQueuePresentKHR = nullptr;
+
+    PFN_vkDestroyInstance fDestroyInstance = nullptr;
+    PFN_vkDeviceWaitIdle fDeviceWaitIdle = nullptr;
+    PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr;
+    PFN_vkQueueWaitIdle fQueueWaitIdle = nullptr;
+    PFN_vkDestroyDevice fDestroyDevice = nullptr;
+    PFN_vkGetDeviceQueue fGetDeviceQueue = nullptr;
+
+    sk_sp<const GrVkInterface> fInterface;
+
+    VkSurfaceKHR      fSurface;
+    VkSwapchainKHR    fSwapchain;
+    uint32_t          fGraphicsQueueIndex;
+    VkQueue           fGraphicsQueue;
+    uint32_t          fPresentQueueIndex;
+    VkQueue           fPresentQueue;
+
+    uint32_t               fImageCount;
+    VkImage*               fImages;         // images in the swapchain
+    VkImageLayout*         fImageLayouts;   // layouts of these images when not color attachment
+    sk_sp<SkSurface>*      fSurfaces;       // surfaces client renders to (may not be based on rts)
+    BackbufferInfo*        fBackbuffers;
+    uint32_t               fCurrentBackbufferIndex;
+};
+
+}   // namespace sk_app
+
+#endif // SK_VULKAN
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/Window.cpp b/src/third_party/skia/tools/sk_app/Window.cpp
new file mode 100644
index 0000000..2ccad55
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/Window.cpp
@@ -0,0 +1,159 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "tools/sk_app/Window.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkSurface.h"
+#include "tools/sk_app/WindowContext.h"
+
+namespace sk_app {
+
+Window::Window() {}
+
+Window::~Window() {}
+
+void Window::detach() { fWindowContext = nullptr; }
+
+void Window::visitLayers(std::function<void(Layer*)> visitor) {
+    for (int i = 0; i < fLayers.count(); ++i) {
+        if (fLayers[i]->fActive) {
+            visitor(fLayers[i]);
+        }
+    }
+}
+
+bool Window::signalLayers(std::function<bool(Layer*)> visitor) {
+    for (int i = fLayers.count() - 1; i >= 0; --i) {
+        if (fLayers[i]->fActive && visitor(fLayers[i])) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void Window::onBackendCreated() {
+    this->visitLayers([](Layer* layer) { layer->onBackendCreated(); });
+}
+
+bool Window::onChar(SkUnichar c, skui::ModifierKey modifiers) {
+    return this->signalLayers([=](Layer* layer) { return layer->onChar(c, modifiers); });
+}
+
+bool Window::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) {
+    return this->signalLayers([=](Layer* layer) { return layer->onKey(key, state, modifiers); });
+}
+
+bool Window::onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) {
+    return this->signalLayers([=](Layer* layer) { return layer->onMouse(x, y, state, modifiers); });
+}
+
+bool Window::onMouseWheel(float delta, skui::ModifierKey modifiers) {
+    return this->signalLayers([=](Layer* layer) { return layer->onMouseWheel(delta, modifiers); });
+}
+
+bool Window::onTouch(intptr_t owner, skui::InputState state, float x, float y) {
+    return this->signalLayers([=](Layer* layer) { return layer->onTouch(owner, state, x, y); });
+}
+
+bool Window::onFling(skui::InputState state) {
+    return this->signalLayers([=](Layer* layer) { return layer->onFling(state); });
+}
+
+bool Window::onPinch(skui::InputState state, float scale, float x, float y) {
+    return this->signalLayers([=](Layer* layer) { return layer->onPinch(state, scale, x, y); });
+}
+
+void Window::onUIStateChanged(const SkString& stateName, const SkString& stateValue) {
+    this->visitLayers([=](Layer* layer) { layer->onUIStateChanged(stateName, stateValue); });
+}
+
+void Window::onPaint() {
+    if (!fWindowContext) {
+        return;
+    }
+    markInvalProcessed();
+    this->visitLayers([](Layer* layer) { layer->onPrePaint(); });
+    sk_sp<SkSurface> backbuffer = fWindowContext->getBackbufferSurface();
+    if (backbuffer) {
+        // draw into the canvas of this surface
+        this->visitLayers([=](Layer* layer) { layer->onPaint(backbuffer.get()); });
+
+        backbuffer->flush();
+
+        fWindowContext->swapBuffers();
+    } else {
+        printf("no backbuffer!?\n");
+        // try recreating testcontext
+    }
+}
+
+void Window::onResize(int w, int h) {
+    if (!fWindowContext) {
+        return;
+    }
+    fWindowContext->resize(w, h);
+    this->visitLayers([=](Layer* layer) { layer->onResize(w, h); });
+}
+
+int Window::width() const {
+    if (!fWindowContext) {
+        return 0;
+    }
+    return fWindowContext->width();
+}
+
+int Window::height() const {
+    if (!fWindowContext) {
+        return 0;
+    }
+    return fWindowContext->height();
+}
+
+void Window::setRequestedDisplayParams(const DisplayParams& params, bool /* allowReattach */) {
+    fRequestedDisplayParams = params;
+    if (fWindowContext) {
+        fWindowContext->setDisplayParams(fRequestedDisplayParams);
+    }
+}
+
+int Window::sampleCount() const {
+    if (!fWindowContext) {
+        return 0;
+    }
+    return fWindowContext->sampleCount();
+}
+
+int Window::stencilBits() const {
+    if (!fWindowContext) {
+        return -1;
+    }
+    return fWindowContext->stencilBits();
+}
+
+GrContext* Window::getGrContext() const {
+    if (!fWindowContext) {
+        return nullptr;
+    }
+    return fWindowContext->getGrContext();
+}
+
+void Window::inval() {
+    if (!fWindowContext) {
+        return;
+    }
+    if (!fIsContentInvalidated) {
+        fIsContentInvalidated = true;
+        onInval();
+    }
+}
+
+void Window::markInvalProcessed() {
+    fIsContentInvalidated = false;
+}
+
+}   // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/Window.h b/src/third_party/skia/tools/sk_app/Window.h
new file mode 100644
index 0000000..76be662
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/Window.h
@@ -0,0 +1,154 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef Window_DEFINED
+#define Window_DEFINED
+
+#include "include/core/SkRect.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkTDArray.h"
+#include "tools/sk_app/DisplayParams.h"
+#include "tools/skui/InputState.h"
+#include "tools/skui/Key.h"
+#include "tools/skui/ModifierKey.h"
+
+class GrContext;
+class SkCanvas;
+class SkSurface;
+class SkSurfaceProps;
+
+namespace sk_app {
+
+class WindowContext;
+
+class Window {
+public:
+    static Window* CreateNativeWindow(void* platformData);
+
+    virtual ~Window();
+
+    virtual void setTitle(const char*) = 0;
+    virtual void show() = 0;
+
+    // JSON-formatted UI state for Android. Do nothing by default
+    virtual void setUIState(const char*) {}
+
+    // Shedules an invalidation event for window if one is not currently pending.
+    // Make sure that either onPaint or markInvalReceived is called when the client window consumes
+    // the the inval event. They unset fIsContentInvalided which allow future onInval.
+    void inval();
+
+    virtual bool scaleContentToFit() const { return false; }
+
+    enum BackendType {
+        kNativeGL_BackendType,
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+        kANGLE_BackendType,
+#endif
+#ifdef SK_DAWN
+        kDawn_BackendType,
+#endif
+#ifdef SK_VULKAN
+        kVulkan_BackendType,
+#endif
+#ifdef SK_METAL
+        kMetal_BackendType,
+#endif
+        kRaster_BackendType,
+
+        kLast_BackendType = kRaster_BackendType
+    };
+    enum {
+        kBackendTypeCount = kLast_BackendType + 1
+    };
+
+    virtual bool attach(BackendType) = 0;
+    void detach();
+
+    // input handling
+
+    class Layer {
+    public:
+        Layer() : fActive(true) {}
+        virtual ~Layer() = default;
+
+        bool getActive() { return fActive; }
+        void setActive(bool active) { fActive = active; }
+
+        // return value of 'true' means 'I have handled this event'
+        virtual void onBackendCreated() {}
+        virtual void onAttach(Window* window) {}
+        virtual bool onChar(SkUnichar c, skui::ModifierKey) { return false; }
+        virtual bool onKey(skui::Key, skui::InputState, skui::ModifierKey) { return false; }
+        virtual bool onMouse(int x, int y, skui::InputState, skui::ModifierKey) { return false; }
+        virtual bool onMouseWheel(float delta, skui::ModifierKey) { return false; }
+        virtual bool onTouch(intptr_t owner, skui::InputState, float x, float y) { return false; }
+        // Platform-detected gesture events
+        virtual bool onFling(skui::InputState state) { return false; }
+        virtual bool onPinch(skui::InputState state, float scale, float x, float y) { return false; }
+        virtual void onUIStateChanged(const SkString& stateName, const SkString& stateValue) {}
+        virtual void onPrePaint() {}
+        virtual void onPaint(SkSurface*) {}
+        virtual void onResize(int width, int height) {}
+
+    private:
+        friend class Window;
+        bool fActive;
+    };
+
+    void pushLayer(Layer* layer) {
+        layer->onAttach(this);
+        fLayers.push_back(layer);
+    }
+
+    void onBackendCreated();
+    bool onChar(SkUnichar c, skui::ModifierKey modifiers);
+    bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers);
+    bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers);
+    bool onMouseWheel(float delta, skui::ModifierKey modifiers);
+    bool onTouch(intptr_t owner, skui::InputState state, float x, float y);  // multi-owner = multi-touch
+    // Platform-detected gesture events
+    bool onFling(skui::InputState state);
+    bool onPinch(skui::InputState state, float scale, float x, float y);
+    void onUIStateChanged(const SkString& stateName, const SkString& stateValue);
+    void onPaint();
+    void onResize(int width, int height);
+
+    int width() const;
+    int height() const;
+
+    virtual const DisplayParams& getRequestedDisplayParams() { return fRequestedDisplayParams; }
+    virtual void setRequestedDisplayParams(const DisplayParams&, bool allowReattach = true);
+
+    // Actual parameters in effect, obtained from the native window.
+    int sampleCount() const;
+    int stencilBits() const;
+
+    // Returns null if there is not a GPU backend or if the backend is not yet created.
+    GrContext* getGrContext() const;
+
+protected:
+    Window();
+
+    SkTDArray<Layer*>      fLayers;
+    DisplayParams          fRequestedDisplayParams;
+
+    std::unique_ptr<WindowContext> fWindowContext;
+
+    virtual void onInval() = 0;
+
+    // Uncheck fIsContentInvalided to allow future inval/onInval.
+    void markInvalProcessed();
+
+    bool fIsContentInvalidated = false;  // use this to avoid duplicate invalidate events
+
+    void visitLayers(std::function<void(Layer*)> visitor);
+    bool signalLayers(std::function<bool(Layer*)> visitor);
+};
+
+}   // namespace sk_app
+#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/WindowContext.h b/src/third_party/skia/tools/sk_app/WindowContext.h
similarity index 66%
rename from src/third_party/skia/tools/viewer/sk_app/WindowContext.h
rename to src/third_party/skia/tools/sk_app/WindowContext.h
index fbd2756..5b1058e 100644
--- a/src/third_party/skia/tools/viewer/sk_app/WindowContext.h
+++ b/src/third_party/skia/tools/sk_app/WindowContext.h
@@ -7,12 +7,12 @@
 #ifndef WindowContext_DEFINED
 #define WindowContext_DEFINED
 
-#include "DisplayParams.h"
-#include "GrTypes.h"
-#include "SkRefCnt.h"
-#include "SkSurfaceProps.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSurfaceProps.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/GrTypes.h"
+#include "tools/sk_app/DisplayParams.h"
 
-class GrContext;
 class SkSurface;
 class GrRenderTarget;
 
@@ -21,11 +21,10 @@
 class WindowContext {
 public:
     WindowContext(const DisplayParams& params)
-        : fContext(nullptr)
-        , fDisplayParams(params)
-        , fSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)
-        , fSampleCount(0)
-        , fStencilBits(0) {}
+            : fContext(nullptr)
+            , fDisplayParams(params)
+            , fSampleCount(1)
+            , fStencilBits(0) {}
 
     virtual ~WindowContext() {}
 
@@ -40,13 +39,7 @@
     const DisplayParams& getDisplayParams() { return fDisplayParams; }
     virtual void setDisplayParams(const DisplayParams& params) = 0;
 
-    SkSurfaceProps getSurfaceProps() const { return fSurfaceProps; }
-    void setSurfaceProps(const SkSurfaceProps& props) {
-        fSurfaceProps = props;
-    }
-
-    virtual GrBackendContext getBackendContext() = 0;
-    GrContext* getGrContext() const { return fContext; }
+    GrContext* getGrContext() const { return fContext.get(); }
 
     int width() const { return fWidth; }
     int height() const { return fHeight; }
@@ -56,13 +49,11 @@
 protected:
     virtual bool isGpuContext() { return true;  }
 
-    GrContext*        fContext;
+    sk_sp<GrContext>        fContext;
 
     int               fWidth;
     int               fHeight;
     DisplayParams     fDisplayParams;
-    GrPixelConfig     fPixelConfig;
-    SkSurfaceProps    fSurfaceProps;
 
     // parameters obtained from the native window
     // Note that the platform .cpp file is responsible for
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/GLWindowContext_android.cpp b/src/third_party/skia/tools/sk_app/android/GLWindowContext_android.cpp
similarity index 71%
rename from src/third_party/skia/tools/viewer/sk_app/android/GLWindowContext_android.cpp
rename to src/third_party/skia/tools/sk_app/android/GLWindowContext_android.cpp
index 12c12a7..624b8af 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/GLWindowContext_android.cpp
+++ b/src/third_party/skia/tools/sk_app/android/GLWindowContext_android.cpp
@@ -6,11 +6,11 @@
  * found in the LICENSE file.
  */
 
-#include <GLES/gl.h> 
-
-#include "WindowContextFactory_android.h"
-#include "../GLWindowContext.h"
 #include <EGL/egl.h>
+#include <GLES/gl.h>
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/android/WindowContextFactory_android.h"
 
 using sk_app::GLWindowContext;
 using sk_app::DisplayParams;
@@ -25,7 +25,7 @@
 
     void onSwapBuffers() override;
 
-    void onInitializeContext() override;
+    sk_sp<const GrGLInterface> onInitializeContext() override;
     void onDestroyContext() override;
 
 private:
@@ -57,7 +57,7 @@
     this->destroyContext();
 }
 
-void GLWindowContext_android::onInitializeContext() {
+sk_sp<const GrGLInterface> GLWindowContext_android::onInitializeContext() {
     fWidth = ANativeWindow_getWidth(fNativeWindow);
     fHeight = ANativeWindow_getHeight(fNativeWindow);
 
@@ -70,6 +70,8 @@
     SkAssertResult(eglBindAPI(EGL_OPENGL_ES_API));
 
     EGLint numConfigs = 0;
+    EGLint eglSampleCnt = fDisplayParams.fMSAASampleCount > 1 ? fDisplayParams.fMSAASampleCount > 1
+                                                              : 0;
     const EGLint configAttribs[] = {
         EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -78,8 +80,8 @@
         EGL_BLUE_SIZE, 8,
         EGL_ALPHA_SIZE, 8,
         EGL_STENCIL_SIZE, 8,
-        EGL_SAMPLE_BUFFERS, fDisplayParams.fMSAASampleCount ? 1 : 0,
-        EGL_SAMPLES, fDisplayParams.fMSAASampleCount,
+        EGL_SAMPLE_BUFFERS, eglSampleCnt ? 1 : 0,
+        EGL_SAMPLES, eglSampleCnt,
         EGL_NONE
     };
 
@@ -99,29 +101,11 @@
 //    SkDebugf("Vendor: %s", eglQueryString(fDisplay, EGL_VENDOR));
 //    SkDebugf("Extensions: %s", eglQueryString(fDisplay, EGL_EXTENSIONS));
 
-    // These values are the same as the corresponding VG colorspace attributes,
-    // which were accepted starting in EGL 1.2. For some reason in 1.4, sRGB
-    // became hidden behind an extension, but it looks like devices aren't
-    // advertising that extension (including Nexus 5X). So just check version?
-    const EGLint srgbWindowAttribs[] = {
-        /*EGL_GL_COLORSPACE_KHR*/ 0x309D, /*EGL_GL_COLORSPACE_SRGB_KHR*/ 0x3089,
-        EGL_NONE,
-    };
-    const EGLint* windowAttribs = nullptr;
-    auto srgbColorSpace = SkColorSpace::MakeSRGB();
-    if (srgbColorSpace == fDisplayParams.fColorSpace && majorVersion == 1 && minorVersion >= 2) {
-        windowAttribs = srgbWindowAttribs;
-    }
-
-    fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, windowAttribs);
-    if (EGL_NO_SURFACE == fSurfaceAndroid && windowAttribs) {
-        // Try again without sRGB
-        fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, nullptr);
-    }
+    fSurfaceAndroid = eglCreateWindowSurface(fDisplay, surfaceConfig, fNativeWindow, nullptr);
     SkASSERT(EGL_NO_SURFACE != fSurfaceAndroid);
 
     SkAssertResult(eglMakeCurrent(fDisplay, fSurfaceAndroid, fSurfaceAndroid, fEGLContext));
-    // GLWindowContext::initializeContext will call GrGLCreateNativeInterface so we
+    // GLWindowContext::initializeContext will call GrGLMakeNativeInterface so we
     // won't call it here.
 
     glClearStencil(0);
@@ -131,6 +115,11 @@
 
     eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_STENCIL_SIZE, &fStencilBits);
     eglGetConfigAttrib(fDisplay, surfaceConfig, EGL_SAMPLES, &fSampleCount);
+    fSampleCount = SkTMax(fSampleCount, 1);
+
+    eglSwapInterval(fDisplay, fDisplayParams.fDisableVsync ? 0 : 1);
+
+    return GrGLMakeNativeInterface();
 }
 
 void GLWindowContext_android::onDestroyContext() {
@@ -155,10 +144,10 @@
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewGLForAndroid(ANativeWindow* window, const DisplayParams& params) {
-    WindowContext* ctx = new GLWindowContext_android(window, params);
+std::unique_ptr<WindowContext> MakeGLForAndroid(ANativeWindow* window,
+                                                const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new GLWindowContext_android(window, params));
     if (!ctx->isValid()) {
-        delete ctx;
         return nullptr;
     }
     return ctx;
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/RasterWindowContext_android.cpp b/src/third_party/skia/tools/sk_app/android/RasterWindowContext_android.cpp
similarity index 87%
rename from src/third_party/skia/tools/viewer/sk_app/android/RasterWindowContext_android.cpp
rename to src/third_party/skia/tools/sk_app/android/RasterWindowContext_android.cpp
index 101e51e..701963c 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/RasterWindowContext_android.cpp
+++ b/src/third_party/skia/tools/sk_app/android/RasterWindowContext_android.cpp
@@ -6,10 +6,10 @@
  * found in the LICENSE file.
  */
 
-#include "WindowContextFactory_android.h"
-#include "../RasterWindowContext.h"
-#include "SkSurface.h"
-#include "SkTypes.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkTypes.h"
+#include "tools/sk_app/RasterWindowContext.h"
+#include "tools/sk_app/android/WindowContextFactory_android.h"
 
 using sk_app::RasterWindowContext;
 using sk_app::DisplayParams;
@@ -95,10 +95,10 @@
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewRasterForAndroid(ANativeWindow* window, const DisplayParams& params) {
-    WindowContext* ctx = new RasterWindowContext_android(window, params);
+std::unique_ptr<WindowContext> MakeRasterForAndroid(ANativeWindow* window,
+                                                    const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_android(window, params));
     if (!ctx->isValid()) {
-        delete ctx;
         return nullptr;
     }
     return ctx;
diff --git a/src/third_party/skia/tools/sk_app/android/VulkanWindowContext_android.cpp b/src/third_party/skia/tools/sk_app/android/VulkanWindowContext_android.cpp
new file mode 100644
index 0000000..90466ad
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/android/VulkanWindowContext_android.cpp
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/vk/GrVkVulkan.h"
+
+#include "tools/sk_app/android/WindowContextFactory_android.h"
+
+#include "tools/sk_app/VulkanWindowContext.h"
+
+#include "tools/gpu/vk/VkTestUtils.h"
+
+namespace sk_app {
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeVulkanForAndroid(ANativeWindow* window,
+                                                    const DisplayParams& params) {
+    PFN_vkGetInstanceProcAddr instProc;
+    PFN_vkGetDeviceProcAddr devProc;
+    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
+        return nullptr;
+    }
+
+    auto createVkSurface = [window, instProc] (VkInstance instance) -> VkSurfaceKHR {
+        PFN_vkCreateAndroidSurfaceKHR createAndroidSurfaceKHR =
+                (PFN_vkCreateAndroidSurfaceKHR) instProc(instance, "vkCreateAndroidSurfaceKHR");
+
+        if (!window) {
+            return VK_NULL_HANDLE;
+        }
+        VkSurfaceKHR surface;
+
+        VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+        memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+        surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+        surfaceCreateInfo.pNext = nullptr;
+        surfaceCreateInfo.flags = 0;
+        surfaceCreateInfo.window = window;
+
+        VkResult res = createAndroidSurfaceKHR(instance, &surfaceCreateInfo,
+                                               nullptr, &surface);
+        return (VK_SUCCESS == res) ? surface : VK_NULL_HANDLE;
+    };
+
+    auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
+
+    std::unique_ptr<WindowContext> ctx(
+            new VulkanWindowContext(params, createVkSurface, canPresent, instProc, devProc));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/WindowContextFactory_android.h b/src/third_party/skia/tools/sk_app/android/WindowContextFactory_android.h
similarity index 61%
rename from src/third_party/skia/tools/viewer/sk_app/android/WindowContextFactory_android.h
rename to src/third_party/skia/tools/sk_app/android/WindowContextFactory_android.h
index 00198da..f7f2349 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/WindowContextFactory_android.h
+++ b/src/third_party/skia/tools/sk_app/android/WindowContextFactory_android.h
@@ -11,6 +11,7 @@
 
 #include <android/native_window_jni.h>
 
+#include <memory>
 
 namespace sk_app {
 
@@ -19,11 +20,11 @@
 
 namespace window_context_factory {
 
-WindowContext* NewVulkanForAndroid(ANativeWindow*, const DisplayParams&);
+std::unique_ptr<WindowContext> MakeVulkanForAndroid(ANativeWindow*, const DisplayParams&);
 
-WindowContext* NewGLForAndroid(ANativeWindow*, const DisplayParams&);
+std::unique_ptr<WindowContext> MakeGLForAndroid(ANativeWindow*, const DisplayParams&);
 
-WindowContext* NewRasterForAndroid(ANativeWindow*, const DisplayParams&);
+std::unique_ptr<WindowContext> MakeRasterForAndroid(ANativeWindow*, const DisplayParams&);
 
 }  // namespace window_context_factory
 
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/Window_android.cpp b/src/third_party/skia/tools/sk_app/android/Window_android.cpp
similarity index 71%
rename from src/third_party/skia/tools/viewer/sk_app/android/Window_android.cpp
rename to src/third_party/skia/tools/sk_app/android/Window_android.cpp
index 16ad430..f1924c4 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/Window_android.cpp
+++ b/src/third_party/skia/tools/sk_app/android/Window_android.cpp
@@ -5,9 +5,9 @@
 * found in the LICENSE file.
 */
 
-#include "Window_android.h"
-#include "WindowContextFactory_android.h"
-#include "../WindowContext.h"
+#include "tools/sk_app/WindowContext.h"
+#include "tools/sk_app/android/WindowContextFactory_android.h"
+#include "tools/sk_app/android/Window_android.h"
 
 namespace sk_app {
 
@@ -31,7 +31,7 @@
     fSkiaAndroidApp->setTitle(title);
 }
 
-void Window_android::setUIState(const Json::Value& state) {
+void Window_android::setUIState(const char* state) {
     fSkiaAndroidApp->setUIState(state);
 }
 
@@ -49,17 +49,17 @@
     switch (fBackendType) {
         case kNativeGL_BackendType:
         default:
-            fWindowContext = window_context_factory::NewGLForAndroid(window,
-                                                                     fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeGLForAndroid(window, fRequestedDisplayParams);
             break;
         case kRaster_BackendType:
-            fWindowContext = window_context_factory::NewRasterForAndroid(window,
-                                                                         fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeRasterForAndroid(window, fRequestedDisplayParams);
             break;
 #ifdef SK_VULKAN
         case kVulkan_BackendType:
-            fWindowContext = window_context_factory::NewVulkanForAndroid(window,
-                                                                         fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeVulkanForAndroid(window, fRequestedDisplayParams);
             break;
 #endif
     }
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/Window_android.h b/src/third_party/skia/tools/sk_app/android/Window_android.h
similarity index 85%
rename from src/third_party/skia/tools/viewer/sk_app/android/Window_android.h
rename to src/third_party/skia/tools/sk_app/android/Window_android.h
index 7918011..23ec817 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/Window_android.h
+++ b/src/third_party/skia/tools/sk_app/android/Window_android.h
@@ -8,8 +8,8 @@
 #ifndef Window_android_DEFINED
 #define Window_android_DEFINED
 
-#include "../Window.h"
-#include "surface_glue_android.h"
+#include "tools/sk_app/Window.h"
+#include "tools/sk_app/android/surface_glue_android.h"
 
 namespace sk_app {
 
@@ -27,7 +27,7 @@
 
     bool attach(BackendType) override;
     void onInval() override;
-    void setUIState(const Json::Value& state) override;
+    void setUIState(const char* state) override;
 
     void paintIfNeeded();
 
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/main_android.cpp b/src/third_party/skia/tools/sk_app/android/main_android.cpp
similarity index 95%
rename from src/third_party/skia/tools/viewer/sk_app/android/main_android.cpp
rename to src/third_party/skia/tools/sk_app/android/main_android.cpp
index cb8db6c..3eaea2c 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/main_android.cpp
+++ b/src/third_party/skia/tools/sk_app/android/main_android.cpp
@@ -10,8 +10,8 @@
 
 #include <android_native_app_glue.h>
 
-#include "../Application.h"
-#include "Timer.h"
+#include "tools/sk_app/Application.h"
+#include "tools/timer/Timer.h"
 
 using sk_app::Application;
 
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.cpp b/src/third_party/skia/tools/sk_app/android/surface_glue_android.cpp
similarity index 80%
rename from src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.cpp
rename to src/third_party/skia/tools/sk_app/android/surface_glue_android.cpp
index 4fb6c3d..840ce5a 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.cpp
+++ b/src/third_party/skia/tools/sk_app/android/surface_glue_android.cpp
@@ -5,7 +5,7 @@
 * found in the LICENSE file.
 */
 
-#include "surface_glue_android.h"
+#include "tools/sk_app/android/surface_glue_android.h"
 
 #include <jni.h>
 #include <pthread.h>
@@ -13,32 +13,59 @@
 #include <unistd.h>
 #include <unordered_map>
 
+#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
 #include <android/input.h>
 #include <android/keycodes.h>
 #include <android/looper.h>
 #include <android/native_window_jni.h>
 
-#include "../Application.h"
-#include "SkTypes.h"
-#include "SkUtils.h"
-#include "Window_android.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkTo.h"
+#include "src/utils/SkUTF.h"
+#include "tools/ResourceFactory.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/android/Window_android.h"
+
 
 namespace sk_app {
 
+static void config_resource_mgr(JNIEnv* env, jobject assetManager) {
+    static AAssetManager* gAAssetManager = nullptr;
+    SkASSERT(assetManager);
+    gAAssetManager = AAssetManager_fromJava(env, assetManager);
+    SkASSERT(gAAssetManager);
+    gResourceFactory = [](const char* resource) -> sk_sp<SkData> {
+        if (!gAAssetManager) {
+            return nullptr;
+        }
+        SkString path = SkStringPrintf("resources/%s", resource);
+        AAsset* asset = AAssetManager_open(gAAssetManager, path.c_str(), AASSET_MODE_STREAMING);
+        if (!asset) {
+            return nullptr;
+        }
+        size_t size = SkToSizeT(AAsset_getLength(asset));
+        sk_sp<SkData> data = SkData::MakeUninitialized(size);
+        (void)AAsset_read(asset, data->writable_data(), size);
+        AAsset_close(asset);
+        return data;
+    };
+}
+
 static const int LOOPER_ID_MESSAGEPIPE = 1;
 
-static const std::unordered_map<int, Window::Key> ANDROID_TO_WINDOW_KEYMAP({
-    {AKEYCODE_SOFT_LEFT, Window::Key::kLeft},
-    {AKEYCODE_SOFT_RIGHT, Window::Key::kRight}
+static const std::unordered_map<int, skui::Key> ANDROID_TO_WINDOW_KEYMAP({
+    {AKEYCODE_SOFT_LEFT,  skui::Key::kLeft },
+    {AKEYCODE_SOFT_RIGHT, skui::Key::kRight}
 });
 
-static const std::unordered_map<int, Window::InputState> ANDROID_TO_WINDOW_STATEMAP({
-    {AMOTION_EVENT_ACTION_DOWN, Window::kDown_InputState},
-    {AMOTION_EVENT_ACTION_POINTER_DOWN, Window::kDown_InputState},
-    {AMOTION_EVENT_ACTION_UP, Window::kUp_InputState},
-    {AMOTION_EVENT_ACTION_POINTER_UP, Window::kUp_InputState},
-    {AMOTION_EVENT_ACTION_MOVE, Window::kMove_InputState},
-    {AMOTION_EVENT_ACTION_CANCEL, Window::kUp_InputState},
+static const std::unordered_map<int, skui::InputState> ANDROID_TO_WINDOW_STATEMAP({
+    {AMOTION_EVENT_ACTION_DOWN,         skui::InputState::kDown },
+    {AMOTION_EVENT_ACTION_POINTER_DOWN, skui::InputState::kDown },
+    {AMOTION_EVENT_ACTION_UP,           skui::InputState::kUp   },
+    {AMOTION_EVENT_ACTION_POINTER_UP,   skui::InputState::kUp   },
+    {AMOTION_EVENT_ACTION_MOVE,         skui::InputState::kMove },
+    {AMOTION_EVENT_ACTION_CANCEL,       skui::InputState::kUp   },
 });
 
 SkiaAndroidApp::SkiaAndroidApp(JNIEnv* env, jobject androidApp) {
@@ -71,8 +98,8 @@
     fPThreadEnv->DeleteLocalRef(titleString);
 }
 
-void SkiaAndroidApp::setUIState(const Json::Value& state) const {
-    jstring jstr = fPThreadEnv->NewStringUTF(state.toStyledString().c_str());
+void SkiaAndroidApp::setUIState(const char* state) const {
+    jstring jstr = fPThreadEnv->NewStringUTF(state);
     fPThreadEnv->CallVoidMethod(fAndroidApp, fSetStateMethodID, jstr);
     fPThreadEnv->DeleteLocalRef(jstr);
 }
@@ -139,8 +166,8 @@
             auto it = ANDROID_TO_WINDOW_KEYMAP.find(message.fKeycode);
             SkASSERT(it != ANDROID_TO_WINDOW_KEYMAP.end());
             // No modifier is supported so far
-            skiaAndroidApp->fWindow->onKey(it->second, Window::kDown_InputState, 0);
-            skiaAndroidApp->fWindow->onKey(it->second, Window::kUp_InputState, 0);
+            skiaAndroidApp->fWindow->onKey(it->second, skui::InputState::kDown, skui::ModifierKey::kNone);
+            skiaAndroidApp->fWindow->onKey(it->second, skui::InputState::kUp, skui::ModifierKey::kNone);
             break;
         }
         case kTouched: {
@@ -208,7 +235,10 @@
 
 extern "C"  // extern "C" is needed for JNI (although the method itself is in C++)
     JNIEXPORT jlong JNICALL
-    Java_org_skia_viewer_ViewerApplication_createNativeApp(JNIEnv* env, jobject application) {
+    Java_org_skia_viewer_ViewerApplication_createNativeApp(JNIEnv* env,
+                                                           jobject application,
+                                                           jobject assetManager) {
+    config_resource_mgr(env, assetManager);
     SkiaAndroidApp* skiaAndroidApp = new SkiaAndroidApp(env, application);
     return (jlong)((size_t)skiaAndroidApp);
 }
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.h b/src/third_party/skia/tools/sk_app/android/surface_glue_android.h
similarity index 91%
rename from src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.h
rename to src/third_party/skia/tools/sk_app/android/surface_glue_android.h
index 3bbf3af..f73fe56 100644
--- a/src/third_party/skia/tools/viewer/sk_app/android/surface_glue_android.h
+++ b/src/third_party/skia/tools/sk_app/android/surface_glue_android.h
@@ -12,10 +12,10 @@
 
 #include <android/native_window_jni.h>
 
-#include "SkString.h"
+#include "include/core/SkString.h"
 
-#include "../Application.h"
-#include "../Window.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/Window.h"
 
 namespace sk_app {
 
@@ -57,7 +57,7 @@
 
     // These must be called in SkiaAndroidApp's own pthread because the JNIEnv is thread sensitive
     void setTitle(const char* title) const;
-    void setUIState(const Json::Value& state) const;
+    void setUIState(const char* state) const;
 
 private:
     pthread_t fThread;
diff --git a/src/third_party/skia/tools/sk_app/ios/GLWindowContext_ios.mm b/src/third_party/skia/tools/sk_app/ios/GLWindowContext_ios.mm
new file mode 100644
index 0000000..a21f88b
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/GLWindowContext_ios.mm
@@ -0,0 +1,169 @@
+
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/ios/WindowContextFactory_ios.h"
+
+#import <OpenGLES/ES3/gl.h>
+#import <UIKit/UIKit.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::IOSWindowInfo;
+using sk_app::GLWindowContext;
+
+@interface GLView : MainView
+@end
+
+@implementation GLView
++ (Class) layerClass {
+    return [CAEAGLLayer class];
+}
+@end
+
+namespace {
+
+class GLWindowContext_ios : public GLWindowContext {
+public:
+    GLWindowContext_ios(const IOSWindowInfo&, const DisplayParams&);
+
+    ~GLWindowContext_ios() override;
+
+    void onSwapBuffers() override;
+
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+    void onDestroyContext() override;
+
+    void resize(int w, int h) override;
+
+private:
+    sk_app::Window_ios*  fWindow;
+    UIViewController*    fViewController;
+    GLView*              fGLView;
+    EAGLContext*         fGLContext;
+    GLuint               fFramebuffer;
+    GLuint               fRenderbuffer;
+
+    typedef GLWindowContext INHERITED;
+};
+
+GLWindowContext_ios::GLWindowContext_ios(const IOSWindowInfo& info, const DisplayParams& params)
+    : INHERITED(params)
+    , fWindow(info.fWindow)
+    , fViewController(info.fViewController)
+    , fGLContext(nil) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+GLWindowContext_ios::~GLWindowContext_ios() {
+    this->destroyContext();
+    [fGLView removeFromSuperview];
+    [fGLView release];
+}
+
+sk_sp<const GrGLInterface> GLWindowContext_ios::onInitializeContext() {
+    SkASSERT(nil != fViewController);
+    SkASSERT(!fGLContext);
+
+    CGRect frameRect = [fViewController.view frame];
+    fGLView = [[[GLView alloc] initWithFrame:frameRect] initWithWindow:fWindow];
+    [fViewController.view addSubview:fGLView];
+
+    fGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
+
+    if (!fGLContext)
+    {
+        SkDebugf("Could Not Create OpenGL ES Context\n");
+        return nullptr;
+    }
+
+    if (![EAGLContext setCurrentContext:fGLContext]) {
+        SkDebugf("Could Not Set OpenGL ES Context As Current\n");
+        this->onDestroyContext();
+        return nullptr;
+    }
+
+    // Set up EAGLLayer
+    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)fGLView.layer;
+    eaglLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO,
+                                     kEAGLDrawablePropertyColorFormat     : kEAGLColorFormatRGBA8 };
+    eaglLayer.opaque = YES;
+    eaglLayer.frame = frameRect;
+    eaglLayer.contentsGravity = kCAGravityTopLeft;
+
+    // Set up framebuffer
+    glGenFramebuffers(1, &fFramebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, fFramebuffer);
+
+    glGenRenderbuffers(1, &fRenderbuffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderbuffer);
+
+    [fGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
+
+    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status != GL_FRAMEBUFFER_COMPLETE) {
+        SkDebugf("Invalid Framebuffer\n");
+        this->onDestroyContext();
+        return nullptr;
+    }
+
+    glClearStencil(0);
+    glClearColor(0, 0, 0, 255);
+    glStencilMask(0xffffffff);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    fStencilBits = 8;
+    fSampleCount = 1; // TODO: handle multisampling
+
+    fWidth = fViewController.view.frame.size.width;
+    fHeight = fViewController.view.frame.size.height;
+
+    glViewport(0, 0, fWidth, fHeight);
+
+    return GrGLMakeNativeInterface();
+}
+
+void GLWindowContext_ios::onDestroyContext() {
+    glDeleteFramebuffers(1, &fFramebuffer);
+    glDeleteRenderbuffers(1, &fRenderbuffer);
+    [EAGLContext setCurrentContext:nil];
+    [fGLContext release];
+    fGLContext = nil;
+}
+
+void GLWindowContext_ios::onSwapBuffers() {
+    glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
+    [fGLContext presentRenderbuffer:GL_RENDERBUFFER];
+}
+
+void GLWindowContext_ios::resize(int w, int h) {
+    // TODO: handle rotation
+    // [fGLContext update];
+     INHERITED::resize(w, h);
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeGLForIOS(const IOSWindowInfo& info,
+                                            const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new GLWindowContext_ios(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/ios/MetalWindowContext_ios.mm b/src/third_party/skia/tools/sk_app/ios/MetalWindowContext_ios.mm
new file mode 100644
index 0000000..f05ac20
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/MetalWindowContext_ios.mm
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/MetalWindowContext.h"
+#include "tools/sk_app/ios/WindowContextFactory_ios.h"
+
+#import <Metal/Metal.h>
+#import <UIKit/UIKit.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::IOSWindowInfo;
+using sk_app::MetalWindowContext;
+
+@interface MetalView : MainView
+@end
+
+@implementation MetalView
++ (Class) layerClass {
+    return [CAMetalLayer class];
+}
+@end
+
+namespace {
+
+class MetalWindowContext_ios : public MetalWindowContext {
+public:
+    MetalWindowContext_ios(const IOSWindowInfo&, const DisplayParams&);
+
+    ~MetalWindowContext_ios() override;
+
+    bool onInitializeContext() override;
+    void onDestroyContext() override;
+
+    void resize(int w, int h) override;
+
+private:
+    sk_app::Window_ios*  fWindow;
+    UIViewController*    fViewController;
+    MetalView*           fMetalView;
+
+    typedef MetalWindowContext INHERITED;
+};
+
+MetalWindowContext_ios::MetalWindowContext_ios(const IOSWindowInfo& info,
+                                               const DisplayParams& params)
+    : INHERITED(params)
+    , fWindow(info.fWindow)
+    , fViewController(info.fViewController) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+MetalWindowContext_ios::~MetalWindowContext_ios() {
+    this->destroyContext();
+    [fMetalView removeFromSuperview];
+    [fMetalView release];
+}
+
+bool MetalWindowContext_ios::onInitializeContext() {
+    SkASSERT(nil != fWindow);
+    SkASSERT(nil != fViewController);
+
+    CGRect frameRect = [fViewController.view frame];
+    fMetalView = [[[MetalView alloc] initWithFrame:frameRect] initWithWindow:fWindow];
+    [fViewController.view addSubview:fMetalView];
+
+    fMetalLayer = (CAMetalLayer*)fMetalView.layer;
+    fMetalLayer.device = fDevice;
+    fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
+    fMetalLayer.drawableSize = frameRect.size;
+    fMetalLayer.frame = frameRect;
+
+    // TODO: need solution for iOS
+    // BOOL useVsync = fDisplayParams.fDisableVsync ? NO : YES;
+    // fMetalLayer.displaySyncEnabled = useVsync;
+    fMetalLayer.contentsGravity = kCAGravityTopLeft;
+
+    fWidth = frameRect.size.width;
+    fHeight = frameRect.size.height;
+
+    return true;
+}
+
+void MetalWindowContext_ios::onDestroyContext() {}
+
+void MetalWindowContext_ios::resize(int w, int h) {
+    // TODO: handle rotation
+    fMetalLayer.drawableSize = fMetalView.frame.size;
+    fMetalLayer.frame = fMetalView.frame;
+    fWidth = w;
+    fHeight = h;
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeMetalForIOS(const IOSWindowInfo& info,
+                                               const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new MetalWindowContext_ios(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/ios/RasterWindowContext_ios.mm b/src/third_party/skia/tools/sk_app/ios/RasterWindowContext_ios.mm
new file mode 100644
index 0000000..16a21f4
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/RasterWindowContext_ios.mm
@@ -0,0 +1,196 @@
+
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColorFilter.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/ToolUtils.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/ios/WindowContextFactory_ios.h"
+
+#import <OpenGLES/ES3/gl.h>
+#import <UIKit/UIKit.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::IOSWindowInfo;
+using sk_app::GLWindowContext;
+
+@interface RasterView : MainView
+@end
+
+@implementation RasterView
++ (Class) layerClass {
+    return [CAEAGLLayer class];
+}
+@end
+
+namespace {
+
+// TODO: This still uses GL to handle the update rather than using a purely raster backend,
+// for historical reasons. Writing a pure raster backend would be better in the long run.
+
+class RasterWindowContext_ios : public GLWindowContext {
+public:
+    RasterWindowContext_ios(const IOSWindowInfo&, const DisplayParams&);
+
+    ~RasterWindowContext_ios() override;
+
+    sk_sp<SkSurface> getBackbufferSurface() override;
+
+    void onSwapBuffers() override;
+
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+    void onDestroyContext() override;
+
+    void resize(int w, int h) override;
+
+private:
+    sk_app::Window_ios*  fWindow;
+    UIViewController*    fViewController;
+    RasterView*          fRasterView;
+    EAGLContext*         fGLContext;
+    GLuint               fFramebuffer;
+    GLuint               fRenderbuffer;
+    sk_sp<SkSurface>     fBackbufferSurface;
+
+    typedef GLWindowContext INHERITED;
+};
+
+RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info,
+                                                 const DisplayParams& params)
+    : INHERITED(params)
+    , fWindow(info.fWindow)
+    , fViewController(info.fViewController)
+    , fGLContext(nil) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+RasterWindowContext_ios::~RasterWindowContext_ios() {
+    this->destroyContext();
+    [fRasterView removeFromSuperview];
+    [fRasterView release];
+}
+
+sk_sp<const GrGLInterface> RasterWindowContext_ios::onInitializeContext() {
+    SkASSERT(nil != fViewController);
+    SkASSERT(!fGLContext);
+
+    CGRect frameRect = [fViewController.view frame];
+    fRasterView = [[[RasterView alloc] initWithFrame:frameRect] initWithWindow:fWindow];
+    [fViewController.view addSubview:fRasterView];
+
+    fGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
+
+    if (!fGLContext)
+    {
+        SkDebugf("Could Not Create OpenGL ES Context\n");
+        return nullptr;
+    }
+
+    if (![EAGLContext setCurrentContext:fGLContext]) {
+        SkDebugf("Could Not Set OpenGL ES Context As Current\n");
+        this->onDestroyContext();
+        return nullptr;
+    }
+
+    // Set up EAGLLayer
+    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)fRasterView.layer;
+    eaglLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO,
+                                     kEAGLDrawablePropertyColorFormat     : kEAGLColorFormatRGBA8 };
+    eaglLayer.opaque = YES;
+    eaglLayer.frame = frameRect;
+    eaglLayer.contentsGravity = kCAGravityTopLeft;
+
+    // Set up framebuffer
+    glGenFramebuffers(1, &fFramebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, fFramebuffer);
+
+    glGenRenderbuffers(1, &fRenderbuffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderbuffer);
+
+    [fGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
+
+    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status != GL_FRAMEBUFFER_COMPLETE) {
+        SkDebugf("Invalid Framebuffer\n");
+        this->onDestroyContext();
+        return nullptr;
+    }
+
+    glClearStencil(0);
+    glClearColor(0, 0, 0, 255);
+    glStencilMask(0xffffffff);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    fStencilBits = 8;
+    fSampleCount = 1; // TODO: handle multisampling
+
+    fWidth = fViewController.view.frame.size.width;
+    fHeight = fViewController.view.frame.size.height;
+
+    glViewport(0, 0, fWidth, fHeight);
+
+    // make the offscreen image
+    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
+                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
+    fBackbufferSurface = SkSurface::MakeRaster(info);
+    return GrGLMakeNativeInterface();
+}
+
+void RasterWindowContext_ios::onDestroyContext() {
+    glDeleteFramebuffers(1, &fFramebuffer);
+    glDeleteRenderbuffers(1, &fRenderbuffer);
+    [EAGLContext setCurrentContext:nil];
+    [fGLContext release];
+    fGLContext = nil;
+}
+
+sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() {
+    return fBackbufferSurface;
+}
+
+void RasterWindowContext_ios::onSwapBuffers() {
+    if (fBackbufferSurface) {
+        // We made/have an off-screen surface. Get the contents as an SkImage:
+        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
+
+        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
+        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
+        gpuCanvas->drawImage(snapshot, 0, 0);
+        gpuCanvas->flush();
+        glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer);
+        [fGLContext presentRenderbuffer:GL_RENDERBUFFER];
+    }
+}
+
+void RasterWindowContext_ios::resize(int w, int h) {
+    // TODO: handle rotation
+    // [fGLContext update];
+     INHERITED::resize(w, h);
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info,
+                                                const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/ios/WindowContextFactory_ios.h b/src/third_party/skia/tools/sk_app/ios/WindowContextFactory_ios.h
new file mode 100644
index 0000000..513e23a
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/WindowContextFactory_ios.h
@@ -0,0 +1,46 @@
+
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef WindowContextFactory_ios_DEFINED
+#define WindowContextFactory_ios_DEFINED
+
+#include "tools/sk_app/ios/Window_ios.h"
+
+#import <UIKit/UIKit.h>
+
+#include "tools/sk_app/WindowContext.h"
+
+#include <memory>
+
+namespace sk_app {
+
+struct DisplayParams;
+
+namespace window_context_factory {
+
+struct IOSWindowInfo {
+    sk_app::Window_ios* fWindow;
+    UIViewController*   fViewController;
+};
+
+inline std::unique_ptr<WindowContext> MakeVulkanForIOS(const IOSWindowInfo&, const DisplayParams&) {
+    // No Vulkan support on iOS yet.
+    return nullptr;
+}
+
+std::unique_ptr<WindowContext> MakeMetalForIOS(const IOSWindowInfo&, const DisplayParams&);
+
+std::unique_ptr<WindowContext> MakeGLForIOS(const IOSWindowInfo&, const DisplayParams&);
+
+std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo&, const DisplayParams&);
+
+}  // namespace window_context_factory
+
+}  // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/ios/Window_ios.h b/src/third_party/skia/tools/sk_app/ios/Window_ios.h
new file mode 100644
index 0000000..037f992
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/Window_ios.h
@@ -0,0 +1,61 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef Window_ios_DEFINED
+#define Window_ios_DEFINED
+
+#include "include/private/SkChecksum.h"
+#include "src/core/SkTDynamicHash.h"
+#include "tools/sk_app/Window.h"
+
+#import <UIKit/UIKit.h>
+
+namespace sk_app {
+
+class Window_ios : public Window {
+public:
+    Window_ios()
+            : INHERITED()
+            , fWindow(nil) {}
+    ~Window_ios() override { this->closeWindow(); }
+
+    bool initWindow();
+
+    void setTitle(const char*) override {}
+    void show() override {}
+
+    bool attach(BackendType) override;
+
+    void onInval() override;
+
+    static void PaintWindow();
+
+    UIWindow* uiWindow() { return fWindow; }
+
+    static Window_ios* MainWindow() { return gWindow; }
+
+private:
+    void closeWindow();
+
+    UIWindow*    fWindow;
+
+    static Window_ios* gWindow; // there should be only one
+
+    typedef Window INHERITED;
+};
+
+}   // namespace sk_app
+
+//////////////////////////////////////////////////////////////////////////
+
+@interface MainView : UIView
+
+- (MainView*)initWithWindow:(sk_app::Window_ios*)initWindow;
+
+@end
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/ios/Window_ios.mm b/src/third_party/skia/tools/sk_app/ios/Window_ios.mm
new file mode 100644
index 0000000..82d8a73
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/Window_ios.mm
@@ -0,0 +1,251 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "tools/sk_app/ios/WindowContextFactory_ios.h"
+#include "tools/sk_app/ios/Window_ios.h"
+
+@interface WindowViewController : UIViewController
+
+- (WindowViewController*)initWithWindow:(sk_app::Window_ios*)initWindow;
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////
+
+using sk_app::Window;
+
+namespace sk_app {
+
+Window_ios* Window_ios::gWindow = nullptr;
+
+Window* Window::CreateNativeWindow(void*) {
+    // already have a window
+    if (Window_ios::MainWindow()) {
+        return nullptr;
+    }
+
+    Window_ios* window = new Window_ios();
+    if (!window->initWindow()) {
+        delete window;
+        return nullptr;
+    }
+
+    return window;
+}
+
+bool Window_ios::initWindow() {
+    // we already have a window
+    if (fWindow) {
+        return true;
+    }
+
+    // Create a view controller to track certain events
+    WindowViewController* viewController = [[WindowViewController alloc] initWithWindow:this];
+    if (nil == viewController) {
+        return false;
+    }
+
+    fWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+    if (nil == fWindow) {
+        [viewController release];
+        return false;
+    }
+    fWindow.backgroundColor = [UIColor whiteColor];
+
+    viewController.view = nil;
+    [fWindow setRootViewController:viewController];
+    [fWindow makeKeyAndVisible];
+
+    gWindow = this;
+
+    return true;
+}
+
+void Window_ios::closeWindow() {
+    if (nil != fWindow) {
+        gWindow = nullptr;
+        [fWindow release];
+        fWindow = nil;
+    }
+}
+
+bool Window_ios::attach(BackendType attachType) {
+    this->initWindow();
+
+    window_context_factory::IOSWindowInfo info;
+    info.fWindow = this;
+    info.fViewController = fWindow.rootViewController;
+    switch (attachType) {
+        case kRaster_BackendType:
+            fWindowContext = MakeRasterForIOS(info, fRequestedDisplayParams);
+            break;
+#ifdef SK_METAL
+        case kMetal_BackendType:
+            fWindowContext = MakeMetalForIOS(info, fRequestedDisplayParams);
+            break;
+#endif
+        case kNativeGL_BackendType:
+        default:
+            fWindowContext = MakeGLForIOS(info, fRequestedDisplayParams);
+            break;
+    }
+    this->onBackendCreated();
+
+    return (SkToBool(fWindowContext));
+}
+
+void Window_ios::PaintWindow() {
+    gWindow->onPaint();
+}
+
+void Window_ios::onInval() {
+    // TODO: send expose event
+}
+
+}   // namespace sk_app
+
+///////////////////////////////////////////////////////////////////////////////
+
+@implementation WindowViewController {
+    sk_app::Window_ios* fWindow;
+}
+
+- (WindowViewController*)initWithWindow:(sk_app::Window_ios *)initWindow {
+    fWindow = initWindow;
+
+    return self;
+}
+
+- (void)viewDidLoad {
+    // nothing yet
+}
+
+- (void)didReceiveMemoryWarning {
+    // nothing yet
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size
+       withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    // handle rotations here
+}
+@end
+
+///////////////////////////////////////////////////////////////////////////////
+
+@implementation MainView {
+    sk_app::Window_ios* fWindow;
+}
+
+- (IBAction)panGestureAction:(UIGestureRecognizer*)sender {
+    CGPoint location = [sender locationInView:self];
+    switch (sender.state) {
+        case UIGestureRecognizerStateBegan:
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kDown, skui::ModifierKey::kNone);
+            break;
+        case UIGestureRecognizerStateChanged:
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kMove, skui::ModifierKey::kNone);
+            break;
+        case UIGestureRecognizerStateEnded:
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kUp, skui::ModifierKey::kNone);
+            break;
+        case UIGestureRecognizerStateCancelled:
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kUp, skui::ModifierKey::kNone);
+            break;
+        default:
+            break;
+    }
+}
+
+- (IBAction)tapGestureAction:(UIGestureRecognizer*)sender {
+    CGPoint location = [sender locationInView:self];
+    switch (sender.state) {
+        case UIGestureRecognizerStateEnded:
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kDown, skui::ModifierKey::kNone);
+            fWindow->onMouse(location.x, location.y,
+                             skui::InputState::kUp, skui::ModifierKey::kNone);
+            break;
+        default:
+            break;
+    }
+}
+
+- (IBAction)pinchGestureAction:(UIGestureRecognizer*)sender {
+    CGPoint location = [sender locationInView:self];
+    UIPinchGestureRecognizer* pinchGestureRecognizer = (UIPinchGestureRecognizer*) sender;
+    float scale = pinchGestureRecognizer.scale;
+    switch (sender.state) {
+        case UIGestureRecognizerStateBegan:
+            fWindow->onPinch(skui::InputState::kDown, scale, location.x, location.y);
+            break;
+        case UIGestureRecognizerStateChanged:
+            fWindow->onPinch(skui::InputState::kMove, scale, location.x, location.y);
+            break;
+        case UIGestureRecognizerStateEnded:
+            fWindow->onPinch(skui::InputState::kUp, scale, location.x, location.y);
+            break;
+        case UIGestureRecognizerStateCancelled:
+            fWindow->onPinch(skui::InputState::kUp, scale, location.x, location.y);
+            break;
+        default:
+            break;
+    }
+}
+
+- (IBAction)swipeRightGestureAction:(UIGestureRecognizer*)sender {
+    if (UIGestureRecognizerStateEnded == sender.state) {
+        fWindow->onFling(skui::InputState::kRight);
+    }
+}
+
+- (IBAction)swipeLeftGestureAction:(UIGestureRecognizer*)sender {
+    if (UIGestureRecognizerStateEnded == sender.state) {
+        fWindow->onFling(skui::InputState::kLeft);
+    }
+}
+
+- (MainView*)initWithWindow:(sk_app::Window_ios *)initWindow {
+    self = [super init];
+
+    UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];
+    panGestureRecognizer.maximumNumberOfTouches = 1;
+    [panGestureRecognizer addTarget:self action:@selector(panGestureAction:)];
+    [self addGestureRecognizer:panGestureRecognizer];
+
+    UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
+    [tapGestureRecognizer addTarget:self action:@selector(tapGestureAction:)];
+    [self addGestureRecognizer:tapGestureRecognizer];
+
+    UIPinchGestureRecognizer* pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] init];
+    [pinchGestureRecognizer addTarget:self action:@selector(pinchGestureAction:)];
+    [self addGestureRecognizer:pinchGestureRecognizer];
+
+    UISwipeGestureRecognizer* swipeRightGestureRecognizer = [[UISwipeGestureRecognizer alloc] init];
+    swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
+    [swipeRightGestureRecognizer addTarget:self action:@selector(swipeRightGestureAction:)];
+    [self addGestureRecognizer:swipeRightGestureRecognizer];
+
+    UISwipeGestureRecognizer* swipeLeftGestureRecognizer = [[UISwipeGestureRecognizer alloc] init];
+    swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
+    [swipeLeftGestureRecognizer addTarget:self action:@selector(swipeLeftGestureAction:)];
+    [self addGestureRecognizer:swipeLeftGestureRecognizer];
+
+    // disable pan recognition until swipes fail
+    [panGestureRecognizer requireGestureRecognizerToFail:swipeLeftGestureRecognizer];
+    [panGestureRecognizer requireGestureRecognizerToFail:swipeRightGestureRecognizer];
+
+    fWindow = initWindow;
+
+    return self;
+}
+
+@end
+
diff --git a/src/third_party/skia/tools/sk_app/ios/main_ios.mm b/src/third_party/skia/tools/sk_app/ios/main_ios.mm
new file mode 100644
index 0000000..3bcc236
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/ios/main_ios.mm
@@ -0,0 +1,106 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "include/core/SkTypes.h"
+#include "include/private/SkTHash.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/ios/Window_ios.h"
+#include "tools/timer/Timer.h"
+
+#import <UIKit/UIKit.h>
+
+using sk_app::Application;
+
+////////////////////////////////////////////////////////////////////
+
+@interface AppDelegate : UIResponder<UIApplicationDelegate>
+
+@property (nonatomic, assign) BOOL done;
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
+@implementation AppDelegate
+
+@synthesize done = _done;
+@synthesize window = _window;
+
+- (void)applicationWillTerminate:(UIApplication *)sender {
+    _done = TRUE;
+}
+
+- (void)launchApp {
+    // Extract argc and argv from NSProcessInfo
+    NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+    int argc = arguments.count;
+    char** argv = (char **)malloc((argc+1) * sizeof(char *));
+    int i = 0;
+    for (NSString* string in arguments) {
+        size_t bufferSize = (string.length+1) * sizeof(char);
+        argv[i] = (char*)malloc(bufferSize);
+        [string getCString:argv[i]
+                 maxLength:bufferSize
+                  encoding:NSUTF8StringEncoding];
+        ++i;
+    }
+    argv[i] = NULL;
+
+    Application* app = Application::Create(argc, argv, nullptr);
+
+    // Free the memory we used for argc and argv
+    for (i = 0; i < argc; i++) {
+        free(argv[i]);
+    }
+    free(argv);
+
+    sk_app::Window_ios* mainWindow = sk_app::Window_ios::MainWindow();
+    if (!mainWindow) {
+        return;
+    }
+    self.window = mainWindow->uiWindow();
+
+    // take over the main event loop
+    bool done = false;
+    while (!done) {
+        // TODO: consider using a dispatch queue or CADisplayLink instead of this
+        const CFTimeInterval kSeconds = 0.000002;
+        CFRunLoopRunResult result;
+        do {
+            result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kSeconds, TRUE);
+        } while (result == kCFRunLoopRunHandledSource);
+
+        // TODO: is this the right approach for iOS?
+        // Rather than depending on an iOS event to drive this, we treat our window
+        // invalidation flag as a separate event stream. Window::onPaint() will clear
+        // the invalidation flag, effectively removing it from the stream.
+        sk_app::Window_ios::PaintWindow();
+
+        app->onIdle();
+    }
+    delete app;
+}
+
+- (BOOL)application:(UIApplication *)application
+        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+    // let the system event loop run once, then launch into our main loop
+    [self performSelector:@selector(launchApp) withObject:nil afterDelay:0.0];
+
+    return YES;
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////
+
+int main(int argc, char **argv) {
+    /* Give over control to run loop, AppDelegate will handle most things from here */
+    @autoreleasepool {
+        UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/src/third_party/skia/tools/sk_app/mac/DawnMTLWindowContext_mac.mm b/src/third_party/skia/tools/sk_app/mac/DawnMTLWindowContext_mac.mm
new file mode 100644
index 0000000..2ce22f3
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/DawnMTLWindowContext_mac.mm
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/DawnWindowContext.h"
+#include "tools/sk_app/mac/WindowContextFactory_mac.h"
+#include "common/SwapChainUtils.h"
+#include "dawn/dawncpp.h"
+#include "dawn/dawn_wsi.h"
+#include "dawn_native/DawnNative.h"
+#include "dawn_native/MetalBackend.h"
+
+#import <Metal/Metal.h>
+#import <QuartzCore/CAMetalLayer.h>
+#import <Cocoa/Cocoa.h>
+
+namespace sk_app {
+
+using sk_app::window_context_factory::MacWindowInfo;
+
+class DawnMTLWindowContext : public DawnWindowContext {
+public:
+    DawnMTLWindowContext(const MacWindowInfo& info, const DisplayParams& params);
+    ~DawnMTLWindowContext() override;
+    dawn::Device onInitializeContext() override;
+    void onDestroyContext() override;
+    DawnSwapChainImplementation createSwapChainImplementation(int width, int height,
+                                                              const DisplayParams& params) override;
+    void onSwapBuffers() override;
+private:
+    NSView*              fMainView;
+    id<MTLDevice>        fMTLDevice;
+    CAMetalLayer*        fLayer;
+};
+
+class SwapChainImplMTL {
+public:
+    typedef void WSIContext;
+    static DawnSwapChainImplementation Create(id<MTLDevice> device, CAMetalLayer* layer) {
+        auto impl = new SwapChainImplMTL(device, layer);
+        return CreateSwapChainImplementation<SwapChainImplMTL>(impl);
+    }
+
+    void Init(WSIContext* ctx) {}
+
+    SwapChainImplMTL(id<MTLDevice> device, CAMetalLayer* layer)
+      : fQueue([device newCommandQueue])
+      , fLayer(layer) {}
+
+    ~SwapChainImplMTL() {}
+
+    DawnSwapChainError Configure(DawnTextureFormat format, DawnTextureUsage,
+            uint32_t width, uint32_t height) {
+        if (format != DAWN_TEXTURE_FORMAT_RGBA8_UNORM) {
+            return "unsupported format";
+        }
+        SkASSERT(width > 0);
+        SkASSERT(height > 0);
+
+        return DAWN_SWAP_CHAIN_NO_ERROR;
+    }
+
+    DawnSwapChainError GetNextTexture(DawnSwapChainNextTexture* nextTexture) {
+        fCurrentDrawable = [fLayer nextDrawable];
+
+        nextTexture->texture.ptr = reinterpret_cast<void*>(fCurrentDrawable.texture);
+
+        return DAWN_SWAP_CHAIN_NO_ERROR;
+    }
+
+    DawnSwapChainError Present() {
+        id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
+        [commandBuffer presentDrawable: fCurrentDrawable];
+        [commandBuffer commit];
+        return DAWN_SWAP_CHAIN_NO_ERROR;
+    }
+private:
+    id<MTLCommandQueue>  fQueue;
+    CAMetalLayer*        fLayer;
+    id<CAMetalDrawable>  fCurrentDrawable = nil;
+};
+
+DawnMTLWindowContext::DawnMTLWindowContext(const MacWindowInfo& info, const DisplayParams& params)
+    : DawnWindowContext(params, dawn::TextureFormat::BGRA8Unorm)
+    , fMainView(info.fMainView) {
+    CGSize size = fMainView.bounds.size;
+    this->initializeContext(size.width, size.height);
+}
+
+DawnMTLWindowContext::~DawnMTLWindowContext() {
+    this->destroyContext();
+}
+
+DawnSwapChainImplementation DawnMTLWindowContext::createSwapChainImplementation(
+        int width, int height, const DisplayParams& params) {
+    return SwapChainImplMTL::Create(fMTLDevice, fLayer);
+}
+
+dawn::Device DawnMTLWindowContext::onInitializeContext() {
+    dawn::Device device = this->createDevice(dawn_native::BackendType::Metal);
+    if (!device) {
+        return nullptr;
+    }
+
+    fMTLDevice = dawn_native::metal::GetMetalDevice(device.Get());
+
+    CGSize size;
+    size.width = width();
+    size.height = height();
+
+    fLayer = [CAMetalLayer layer];
+    [fLayer setDevice:fMTLDevice];
+    [fLayer setPixelFormat: MTLPixelFormatBGRA8Unorm];
+    [fLayer setFramebufferOnly: YES];
+    [fLayer setDrawableSize: size];
+    [fLayer setColorspace: CGColorSpaceCreateDeviceRGB()];
+
+    [fMainView setWantsLayer: YES];
+    [fMainView setLayer: fLayer];
+
+    return device;
+}
+
+void DawnMTLWindowContext::onDestroyContext() {
+}
+
+void DawnMTLWindowContext::onSwapBuffers() {
+}
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeDawnMTLForMac(const MacWindowInfo& winInfo,
+                                                 const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new DawnMTLWindowContext(winInfo, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/mac/GLWindowContext_mac.mm b/src/third_party/skia/tools/sk_app/mac/GLWindowContext_mac.mm
new file mode 100644
index 0000000..0edcaa9
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/GLWindowContext_mac.mm
@@ -0,0 +1,174 @@
+
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/mac/WindowContextFactory_mac.h"
+
+#include <OpenGL/gl.h>
+#include <Cocoa/Cocoa.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::MacWindowInfo;
+using sk_app::GLWindowContext;
+
+namespace {
+
+class GLWindowContext_mac : public GLWindowContext {
+public:
+    GLWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
+
+    ~GLWindowContext_mac() override;
+
+    void onSwapBuffers() override;
+
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+    void onDestroyContext() override;
+
+    void resize(int w, int h) override;
+
+private:
+    NSView*              fMainView;
+    NSOpenGLContext*     fGLContext;
+    NSOpenGLPixelFormat* fPixelFormat;
+
+    typedef GLWindowContext INHERITED;
+};
+
+GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params)
+    : INHERITED(params)
+    , fMainView(info.fMainView)
+    , fGLContext(nil) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+GLWindowContext_mac::~GLWindowContext_mac() {
+    [fPixelFormat release];
+    fPixelFormat = nil;
+    [fGLContext release];
+    fGLContext = nil;
+}
+
+sk_sp<const GrGLInterface> GLWindowContext_mac::onInitializeContext() {
+    SkASSERT(nil != fMainView);
+
+    if (!fGLContext) {
+        // set up pixel format
+        constexpr int kMaxAttributes = 18;
+        NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
+        int numAttributes = 0;
+        attributes[numAttributes++] = NSOpenGLPFAAccelerated;
+        attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
+        attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
+        attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
+        attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
+        attributes[numAttributes++] = NSOpenGLPFAColorSize;
+        attributes[numAttributes++] = 24;
+        attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
+        attributes[numAttributes++] = 8;
+        attributes[numAttributes++] = NSOpenGLPFADepthSize;
+        attributes[numAttributes++] = 0;
+        attributes[numAttributes++] = NSOpenGLPFAStencilSize;
+        attributes[numAttributes++] = 8;
+        if (fDisplayParams.fMSAASampleCount > 1) {
+            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
+            attributes[numAttributes++] = 1;
+            attributes[numAttributes++] = NSOpenGLPFASamples;
+            attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
+        } else {
+            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
+            attributes[numAttributes++] = 0;
+        }
+        attributes[numAttributes++] = 0;
+        SkASSERT(numAttributes <= kMaxAttributes);
+
+        fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+        if (nil == fPixelFormat) {
+            return nullptr;
+        }
+
+        // create context
+        fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
+        if (nil == fGLContext) {
+            [fPixelFormat release];
+            fPixelFormat = nil;
+            return nullptr;
+        }
+
+        // TODO: support Retina displays
+        [fMainView setWantsBestResolutionOpenGLSurface:NO];
+        [fGLContext setView:fMainView];
+    }
+
+    GLint swapInterval = fDisplayParams.fDisableVsync ? 0 : 1;
+    [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+
+    // make context current
+    [fGLContext makeCurrentContext];
+
+    glClearStencil(0);
+    glClearColor(0, 0, 0, 255);
+    glStencilMask(0xffffffff);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    GLint stencilBits;
+    [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
+    fStencilBits = stencilBits;
+    GLint sampleCount;
+    [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
+    fSampleCount = sampleCount;
+    fSampleCount = SkTMax(fSampleCount, 1);
+
+    const NSRect viewportRect = [fMainView frame];
+    fWidth = viewportRect.size.width;
+    fHeight = viewportRect.size.height;
+
+    glViewport(0, 0, fWidth, fHeight);
+
+    return GrGLMakeNativeInterface();
+}
+
+void GLWindowContext_mac::onDestroyContext() {
+    // We only need to tear down the GLContext if we've changed the sample count.
+    if (fGLContext && fSampleCount != fDisplayParams.fMSAASampleCount) {
+        [fPixelFormat release];
+        fPixelFormat = nil;
+        [fGLContext release];
+        fGLContext = nil;
+    }
+}
+
+void GLWindowContext_mac::onSwapBuffers() {
+    [fGLContext flushBuffer];
+}
+
+void GLWindowContext_mac::resize(int w, int h) {
+    [fGLContext update];
+    INHERITED::resize(w, h);
+}
+
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeGLForMac(const MacWindowInfo& info,
+                                            const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new GLWindowContext_mac(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/mac/MetalWindowContext_mac.mm b/src/third_party/skia/tools/sk_app/mac/MetalWindowContext_mac.mm
new file mode 100644
index 0000000..765980f
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/MetalWindowContext_mac.mm
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/MetalWindowContext.h"
+#include "tools/sk_app/mac/WindowContextFactory_mac.h"
+
+#import <Cocoa/Cocoa.h>
+#import <QuartzCore/CAConstraintLayoutManager.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::MacWindowInfo;
+using sk_app::MetalWindowContext;
+
+namespace {
+
+class MetalWindowContext_mac : public MetalWindowContext {
+public:
+    MetalWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
+
+    ~MetalWindowContext_mac() override;
+
+    bool onInitializeContext() override;
+    void onDestroyContext() override;
+
+    void resize(int w, int h) override;
+
+private:
+    NSView*              fMainView;
+
+    typedef MetalWindowContext INHERITED;
+};
+
+MetalWindowContext_mac::MetalWindowContext_mac(const MacWindowInfo& info,
+                                               const DisplayParams& params)
+    : INHERITED(params)
+    , fMainView(info.fMainView) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+MetalWindowContext_mac::~MetalWindowContext_mac() {
+    this->destroyContext();
+}
+
+bool MetalWindowContext_mac::onInitializeContext() {
+    SkASSERT(nil != fMainView);
+
+    fMetalLayer = [CAMetalLayer layer];
+    fMetalLayer.device = fDevice;
+    fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
+
+    NSRect frameRect = [fMainView frame];
+    fMetalLayer.drawableSize = frameRect.size;
+    fMetalLayer.frame = frameRect;
+
+    BOOL useVsync = fDisplayParams.fDisableVsync ? NO : YES;
+    fMetalLayer.displaySyncEnabled = useVsync;  // TODO: need solution for 10.12 or lower
+    fMetalLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
+    fMetalLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
+    fMetalLayer.contentsGravity = kCAGravityTopLeft;
+
+    fMainView.layer = fMetalLayer;
+    fMainView.wantsLayer = YES;
+
+    fWidth = frameRect.size.width;
+    fHeight = frameRect.size.height;
+
+    return true;
+}
+
+void MetalWindowContext_mac::onDestroyContext() {
+    fMainView.layer = nil;
+    fMainView.wantsLayer = NO;
+}
+
+void MetalWindowContext_mac::resize(int w, int h) {
+    fMetalLayer.drawableSize = fMainView.frame.size;
+    fMetalLayer.frame = fMainView.frame;
+    fWidth = w;
+    fHeight = h;
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeMetalForMac(const MacWindowInfo& info,
+                                               const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new MetalWindowContext_mac(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/mac/RasterWindowContext_mac.mm b/src/third_party/skia/tools/sk_app/mac/RasterWindowContext_mac.mm
new file mode 100644
index 0000000..337a3fe
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/RasterWindowContext_mac.mm
@@ -0,0 +1,187 @@
+
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColorFilter.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/ToolUtils.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/mac/WindowContextFactory_mac.h"
+
+#include <OpenGL/gl.h>
+
+#include <Cocoa/Cocoa.h>
+
+using sk_app::DisplayParams;
+using sk_app::window_context_factory::MacWindowInfo;
+using sk_app::GLWindowContext;
+
+namespace {
+
+// TODO: This still uses GL to handle the update rather than using a purely raster backend,
+// for historical reasons. Writing a pure raster backend would be better in the long run.
+
+class RasterWindowContext_mac : public GLWindowContext {
+public:
+    RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
+
+    ~RasterWindowContext_mac() override;
+
+    sk_sp<SkSurface> getBackbufferSurface() override;
+
+    void onSwapBuffers() override;
+
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+    void onDestroyContext() override {}
+
+    void resize(int w, int h) override;
+
+private:
+    NSView*              fMainView;
+    NSOpenGLContext*     fGLContext;
+    NSOpenGLPixelFormat* fPixelFormat;
+    sk_sp<SkSurface>     fBackbufferSurface;
+
+    typedef GLWindowContext INHERITED;
+};
+
+RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
+                                                 const DisplayParams& params)
+    : INHERITED(params)
+    , fMainView(info.fMainView)
+    , fGLContext(nil) {
+
+    // any config code here (particularly for msaa)?
+
+    this->initializeContext();
+}
+
+RasterWindowContext_mac::~RasterWindowContext_mac() {
+    [fPixelFormat release];
+    fPixelFormat = nil;
+    [fGLContext release];
+    fGLContext = nil;
+}
+
+sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() {
+    SkASSERT(nil != fMainView);
+
+    if (!fGLContext) {
+        // set up pixel format
+        constexpr int kMaxAttributes = 18;
+        NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
+        int numAttributes = 0;
+        attributes[numAttributes++] = NSOpenGLPFAAccelerated;
+        attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
+        attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
+        attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
+        attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
+        attributes[numAttributes++] = NSOpenGLPFAColorSize;
+        attributes[numAttributes++] = 24;
+        attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
+        attributes[numAttributes++] = 8;
+        attributes[numAttributes++] = NSOpenGLPFADepthSize;
+        attributes[numAttributes++] = 0;
+        attributes[numAttributes++] = NSOpenGLPFAStencilSize;
+        attributes[numAttributes++] = 8;
+        if (fDisplayParams.fMSAASampleCount > 1) {
+            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
+            attributes[numAttributes++] = 1;
+            attributes[numAttributes++] = NSOpenGLPFASamples;
+            attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
+        } else {
+            attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
+            attributes[numAttributes++] = 0;
+        }
+        attributes[numAttributes++] = 0;
+        SkASSERT(numAttributes <= kMaxAttributes);
+
+        fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
+        if (nil == fPixelFormat) {
+            return nullptr;
+        }
+
+        // create context
+        fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
+        if (nil == fGLContext) {
+            [fPixelFormat release];
+            fPixelFormat = nil;
+            return nullptr;
+        }
+
+        [fGLContext setView:fMainView];
+
+        GLint swapInterval = fDisplayParams.fDisableVsync ? 0 : 1;
+        [fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
+    }
+
+    // make context current
+    [fGLContext makeCurrentContext];
+
+    glClearStencil(0);
+    glClearColor(0, 0, 0, 255);
+    glStencilMask(0xffffffff);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    GLint stencilBits;
+    [fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
+    fStencilBits = stencilBits;
+    GLint sampleCount;
+    [fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
+    fSampleCount = sampleCount;
+    fSampleCount = SkTMax(fSampleCount, 1);
+
+    const NSRect viewportRect = [fMainView frame];
+    fWidth = viewportRect.size.width;
+    fHeight = viewportRect.size.height;
+    glViewport(0, 0, fWidth, fHeight);
+
+    // make the offscreen image
+    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
+                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
+    fBackbufferSurface = SkSurface::MakeRaster(info);
+    return GrGLMakeNativeInterface();
+}
+
+sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
+
+void RasterWindowContext_mac::onSwapBuffers() {
+    if (fBackbufferSurface) {
+        // We made/have an off-screen surface. Get the contents as an SkImage:
+        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
+
+        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
+        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
+        gpuCanvas->drawImage(snapshot, 0, 0);
+        gpuCanvas->flush();
+
+        [fGLContext flushBuffer];
+    }
+}
+
+void RasterWindowContext_mac::resize(int w, int h) {
+    [fGLContext update];
+    INHERITED::resize(w, h);
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo& info,
+                                                const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_mac(info, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/mac/WindowContextFactory_mac.h b/src/third_party/skia/tools/sk_app/mac/WindowContextFactory_mac.h
new file mode 100644
index 0000000..6833297
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/WindowContextFactory_mac.h
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef WindowContextFactory_mac_DEFINED
+#define WindowContextFactory_mac_DEFINED
+
+#include "tools/sk_app/WindowContext.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include <memory>
+
+namespace sk_app {
+
+struct DisplayParams;
+
+namespace window_context_factory {
+
+struct MacWindowInfo {
+    NSView*   fMainView;
+};
+
+#ifdef SK_VULKAN
+std::unique_ptr<WindowContext> MakeVulkanForMac(const MacWindowInfo&, const DisplayParams&);
+#else
+inline std::unique_ptr<WindowContext> MakeVulkanForMac(const MacWindowInfo&, const DisplayParams&) {
+    // No Vulkan support on Mac.
+    return nullptr;
+}
+#endif
+
+std::unique_ptr<WindowContext> MakeGLForMac(const MacWindowInfo&, const DisplayParams&);
+
+#ifdef SK_DAWN
+std::unique_ptr<WindowContext> MakeDawnMTLForMac(const MacWindowInfo&, const DisplayParams&);
+#endif
+
+std::unique_ptr<WindowContext> MakeRasterForMac(const MacWindowInfo&, const DisplayParams&);
+#ifdef SK_METAL
+std::unique_ptr<WindowContext> MakeMetalForMac(const MacWindowInfo&, const DisplayParams&);
+#endif
+
+}  // namespace window_context_factory
+
+}  // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/mac/Window_mac.h b/src/third_party/skia/tools/sk_app/mac/Window_mac.h
new file mode 100644
index 0000000..761cd40
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/Window_mac.h
@@ -0,0 +1,60 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef Window_mac_DEFINED
+#define Window_mac_DEFINED
+
+#include "src/core/SkTDynamicHash.h"
+#include "tools/sk_app/Window.h"
+
+#import <Cocoa/Cocoa.h>
+
+namespace sk_app {
+
+class Window_mac : public Window {
+public:
+    Window_mac()
+            : INHERITED()
+            , fWindow(nil) {}
+    ~Window_mac() override {
+        this->closeWindow();
+    }
+
+    bool initWindow();
+
+    void setTitle(const char*) override;
+    void show() override;
+
+    bool attach(BackendType) override;
+
+    void onInval() override {}
+
+    static void PaintWindows();
+
+    static const NSInteger& GetKey(const Window_mac& w) {
+        return w.fWindowNumber;
+    }
+
+    static uint32_t Hash(const NSInteger& windowNumber) {
+        return windowNumber;
+    }
+
+    NSWindow* window() { return fWindow; }
+    void closeWindow();
+
+private:
+    NSWindow*    fWindow;
+    NSInteger    fWindowNumber;
+
+    static SkTDynamicHash<Window_mac, NSInteger> gWindowMap;
+
+    typedef Window INHERITED;
+};
+
+}   // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/sk_app/mac/Window_mac.mm b/src/third_party/skia/tools/sk_app/mac/Window_mac.mm
new file mode 100644
index 0000000..f3f5238
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/Window_mac.mm
@@ -0,0 +1,378 @@
+/*
+* Copyright 2019 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "src/core/SkUtils.h"
+#include "tools/sk_app/mac/WindowContextFactory_mac.h"
+#include "tools/sk_app/mac/Window_mac.h"
+#include "tools/skui/ModifierKey.h"
+
+@interface WindowDelegate : NSObject<NSWindowDelegate>
+
+- (WindowDelegate*)initWithWindow:(sk_app::Window_mac*)initWindow;
+
+@end
+
+@interface MainView : NSView
+
+- (MainView*)initWithWindow:(sk_app::Window_mac*)initWindow;
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////
+
+using sk_app::Window;
+
+namespace sk_app {
+
+SkTDynamicHash<Window_mac, NSInteger> Window_mac::gWindowMap;
+
+Window* Window::CreateNativeWindow(void*) {
+    Window_mac* window = new Window_mac();
+    if (!window->initWindow()) {
+        delete window;
+        return nullptr;
+    }
+
+    return window;
+}
+
+bool Window_mac::initWindow() {
+    // we already have a window
+    if (fWindow) {
+        return true;
+    }
+
+    // Create a delegate to track certain events
+    WindowDelegate* delegate = [[WindowDelegate alloc] initWithWindow:this];
+    if (nil == delegate) {
+        return false;
+    }
+
+    // Create Cocoa window
+    constexpr int initialWidth = 1280;
+    constexpr int initialHeight = 960;
+    NSRect windowRect = NSMakeRect(100, 100, initialWidth, initialHeight);
+
+    NSUInteger windowStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
+                              NSMiniaturizableWindowMask);
+
+    fWindow = [[NSWindow alloc] initWithContentRect:windowRect styleMask:windowStyle
+                                backing:NSBackingStoreBuffered defer:NO];
+    if (nil == fWindow) {
+        [delegate release];
+        return false;
+    }
+
+    // create view
+    MainView* view = [[MainView alloc] initWithWindow:this] ;
+    if (nil == view) {
+        [fWindow release];
+        [delegate release];
+        return false;
+    }
+
+    [fWindow setContentView:view];
+    [fWindow makeFirstResponder:view];
+    [fWindow setDelegate:delegate];
+    [fWindow setAcceptsMouseMovedEvents:YES];
+    [fWindow setRestorable:NO];
+
+    // Should be retained by window now
+    [view release];
+
+    fWindowNumber = fWindow.windowNumber;
+    gWindowMap.add(this);
+
+    return true;
+}
+
+void Window_mac::closeWindow() {
+    if (nil != fWindow) {
+        gWindowMap.remove(fWindowNumber);
+        if (sk_app::Window_mac::gWindowMap.count() < 1) {
+            [NSApp terminate:fWindow];
+        }
+        [fWindow close];
+        fWindow = nil;
+    }
+}
+
+void Window_mac::setTitle(const char* title) {
+    NSString *titleString = [NSString stringWithCString:title encoding:NSUTF8StringEncoding];
+    [fWindow setTitle:titleString];
+}
+
+void Window_mac::show() {
+    [fWindow orderFront:nil];
+
+    [NSApp activateIgnoringOtherApps:YES];
+    [fWindow makeKeyAndOrderFront:NSApp];
+}
+
+bool Window_mac::attach(BackendType attachType) {
+    this->initWindow();
+
+    window_context_factory::MacWindowInfo info;
+    info.fMainView = [fWindow contentView];
+    switch (attachType) {
+        case kRaster_BackendType:
+            fWindowContext = MakeRasterForMac(info, fRequestedDisplayParams);
+            break;
+#ifdef SK_DAWN
+        case kDawn_BackendType:
+            fWindowContext = MakeDawnMTLForMac(info, fRequestedDisplayParams);
+            break;
+#endif
+#ifdef SK_VULKAN
+        case kVulkan_BackendType:
+            fWindowContext = MakeVulkanForMac(info, fRequestedDisplayParams);
+            break;
+#endif
+#ifdef SK_METAL
+        case kMetal_BackendType:
+            fWindowContext = MakeMetalForMac(info, fRequestedDisplayParams);
+            break;
+#endif
+        case kNativeGL_BackendType:
+        default:
+            fWindowContext = MakeGLForMac(info, fRequestedDisplayParams);
+            break;
+    }
+    this->onBackendCreated();
+
+    return (SkToBool(fWindowContext));
+}
+
+void Window_mac::PaintWindows() {
+    SkTDynamicHash<Window_mac, NSInteger>::Iter iter(&gWindowMap);
+    while (!iter.done()) {
+        if ((*iter).fIsContentInvalidated) {
+            (*iter).onPaint();
+        }
+        ++iter;
+    }
+}
+
+}   // namespace sk_app
+
+///////////////////////////////////////////////////////////////////////////////
+
+@implementation WindowDelegate {
+    sk_app::Window_mac* fWindow;
+}
+
+- (WindowDelegate*)initWithWindow:(sk_app::Window_mac *)initWindow {
+    fWindow = initWindow;
+
+    return self;
+}
+
+- (void)windowDidResize:(NSNotification *)notification {
+    const NSRect mainRect = [fWindow->window().contentView bounds];
+
+    fWindow->onResize(mainRect.size.width, mainRect.size.height);
+    fWindow->inval();
+}
+
+- (BOOL)windowShouldClose:(NSWindow*)sender {
+    fWindow->closeWindow();
+
+    return FALSE;
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////
+
+static skui::Key get_key(unsigned short vk) {
+    // This will work with an ANSI QWERTY keyboard.
+    // Something more robust would be needed to support alternate keyboards.
+    static const struct {
+        unsigned short fVK;
+        skui::Key    fKey;
+    } gPair[] = {
+        { 0x33, skui::Key::kBack },
+        { 0x24, skui::Key::kOK },
+        { 0x7E, skui::Key::kUp },
+        { 0x7D, skui::Key::kDown },
+        { 0x7B, skui::Key::kLeft },
+        { 0x7C, skui::Key::kRight },
+        { 0x30, skui::Key::kTab },
+        { 0x74, skui::Key::kPageUp },
+        { 0x79, skui::Key::kPageDown },
+        { 0x73, skui::Key::kHome },
+        { 0x77, skui::Key::kEnd },
+        { 0x75, skui::Key::kDelete },
+        { 0x35, skui::Key::kEscape },
+        { 0x38, skui::Key::kShift },
+        { 0x3C, skui::Key::kShift },
+        { 0x3B, skui::Key::kCtrl },
+        { 0x3E, skui::Key::kCtrl },
+        { 0x3A, skui::Key::kOption },
+        { 0x3D, skui::Key::kOption },
+        { 0x00, skui::Key::kA },
+        { 0x08, skui::Key::kC },
+        { 0x09, skui::Key::kV },
+        { 0x07, skui::Key::kX },
+        { 0x10, skui::Key::kY },
+        { 0x06, skui::Key::kZ },
+    };
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
+        if (gPair[i].fVK == vk) {
+            return gPair[i].fKey;
+        }
+    }
+
+    return skui::Key::kNONE;
+}
+
+static skui::ModifierKey get_modifiers(const NSEvent* event) {
+    NSUInteger modifierFlags = [event modifierFlags];
+    skui::ModifierKey modifiers = skui::ModifierKey::kNone;
+
+    if (modifierFlags & NSEventModifierFlagCommand) {
+        modifiers |= skui::ModifierKey::kCommand;
+    }
+    if (modifierFlags & NSEventModifierFlagShift) {
+        modifiers |= skui::ModifierKey::kShift;
+    }
+    if (modifierFlags & NSEventModifierFlagControl) {
+        modifiers |= skui::ModifierKey::kControl;
+    }
+    if (modifierFlags & NSEventModifierFlagOption) {
+        modifiers |= skui::ModifierKey::kOption;
+    }
+
+    if ((NSKeyDown == [event type] || NSKeyUp == [event type]) &&
+        NO == [event isARepeat]) {
+        modifiers |= skui::ModifierKey::kFirstPress;
+    }
+
+    return modifiers;
+}
+
+@implementation MainView {
+    sk_app::Window_mac* fWindow;
+    // A TrackingArea prevents us from capturing events outside the view
+    NSTrackingArea* fTrackingArea;
+}
+
+- (MainView*)initWithWindow:(sk_app::Window_mac *)initWindow {
+    self = [super init];
+
+    fWindow = initWindow;
+    fTrackingArea = nil;
+
+    [self updateTrackingAreas];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    [fTrackingArea release];
+    [super dealloc];
+}
+
+- (BOOL)isOpaque {
+    return YES;
+}
+
+- (BOOL)canBecomeKeyView {
+    return YES;
+}
+
+- (BOOL)acceptsFirstResponder {
+    return YES;
+}
+
+- (void)updateTrackingAreas {
+    if (fTrackingArea != nil) {
+        [self removeTrackingArea:fTrackingArea];
+        [fTrackingArea release];
+    }
+
+    const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
+                                          NSTrackingActiveInKeyWindow |
+                                          NSTrackingEnabledDuringMouseDrag |
+                                          NSTrackingCursorUpdate |
+                                          NSTrackingInVisibleRect |
+                                          NSTrackingAssumeInside;
+
+    fTrackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
+                                                options:options
+                                                  owner:self
+                                               userInfo:nil];
+
+    [self addTrackingArea:fTrackingArea];
+    [super updateTrackingAreas];
+}
+
+- (void)keyDown:(NSEvent *)event {
+    skui::Key key = get_key([event keyCode]);
+    if (key != skui::Key::kNONE) {
+        if (!fWindow->onKey(key, skui::InputState::kDown, get_modifiers(event))) {
+            if (skui::Key::kEscape == key) {
+                [NSApp terminate:fWindow->window()];
+            }
+        }
+    }
+
+    NSString* characters = [event charactersIgnoringModifiers];
+    NSUInteger len = [characters length];
+    if (len > 0) {
+        unichar* charBuffer = new unichar[len+1];
+        [characters getCharacters:charBuffer range:NSMakeRange(0, len)];
+        for (NSUInteger i = 0; i < len; ++i) {
+            (void) fWindow->onChar((SkUnichar) charBuffer[i], get_modifiers(event));
+        }
+        delete [] charBuffer;
+    }
+}
+
+- (void)keyUp:(NSEvent *)event {
+    skui::Key key = get_key([event keyCode]);
+    if (key != skui::Key::kNONE) {
+        (void) fWindow->onKey(key, skui::InputState::kUp, get_modifiers(event));
+    }
+}
+
+- (void)mouseDown:(NSEvent *)event {
+    const NSPoint pos = [event locationInWindow];
+    const NSRect rect = [fWindow->window().contentView frame];
+    fWindow->onMouse(pos.x, rect.size.height - pos.y, skui::InputState::kDown,
+                    get_modifiers(event));
+}
+
+- (void)mouseUp:(NSEvent *)event {
+    const NSPoint pos = [event locationInWindow];
+    const NSRect rect = [fWindow->window().contentView frame];
+    fWindow->onMouse(pos.x, rect.size.height - pos.y, skui::InputState::kUp,
+                     get_modifiers(event));
+}
+
+- (void)mouseDragged:(NSEvent *)event {
+    [self mouseMoved:event];
+}
+
+- (void)mouseMoved:(NSEvent *)event {
+    const NSPoint pos = [event locationInWindow];
+    const NSRect rect = [fWindow->window().contentView frame];
+    fWindow->onMouse(pos.x, rect.size.height - pos.y, skui::InputState::kMove,
+                     get_modifiers(event));
+}
+
+- (void)scrollWheel:(NSEvent *)event {
+    // TODO: support hasPreciseScrollingDeltas?
+    fWindow->onMouseWheel([event scrollingDeltaY], get_modifiers(event));
+}
+
+- (void)drawRect:(NSRect)rect {
+    fWindow->onPaint();
+}
+
+@end
diff --git a/src/third_party/skia/tools/sk_app/mac/main_mac.mm b/src/third_party/skia/tools/sk_app/mac/main_mac.mm
new file mode 100644
index 0000000..f200abf
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/mac/main_mac.mm
@@ -0,0 +1,113 @@
+/*
+* Copyright 2019 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/mac/Window_mac.h"
+
+@interface AppDelegate : NSObject<NSApplicationDelegate, NSWindowDelegate>
+
+@property (nonatomic, assign) BOOL done;
+
+@end
+
+@implementation AppDelegate : NSObject
+
+@synthesize done = _done;
+
+- (id)init {
+    self = [super init];
+    _done = FALSE;
+    return self;
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
+    _done = TRUE;
+    return NSTerminateCancel;
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification {
+    [NSApp stop:nil];
+}
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+using sk_app::Application;
+using sk_app::Window_mac;
+
+int main(int argc, char * argv[]) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
+    // we only run on systems that support at least Core Profile 3.2
+    return EXIT_FAILURE;
+#endif
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    [NSApplication sharedApplication];
+
+    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+    //Create the application menu.
+    NSMenu* menuBar=[[NSMenu alloc] initWithTitle:@"AMainMenu"];
+    [NSApp setMainMenu:menuBar];
+
+    NSMenuItem* item;
+    NSMenu* subMenu;
+
+    item=[[NSMenuItem alloc] initWithTitle:@"Apple" action:NULL keyEquivalent:@""];
+    [menuBar addItem:item];
+    subMenu=[[NSMenu alloc] initWithTitle:@"Apple"];
+    [menuBar setSubmenu:subMenu forItem:item];
+    [item release];
+    item=[[NSMenuItem alloc] initWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
+    [subMenu addItem:item];
+    [item release];
+    [subMenu release];
+
+    // Set AppDelegate to catch certain global events
+    AppDelegate* appDelegate = [[AppDelegate alloc] init];
+    [NSApp setDelegate:appDelegate];
+
+    Application* app = Application::Create(argc, argv, nullptr);
+
+    // This will run until the application finishes launching, then lets us take over
+    [NSApp run];
+
+    // Now we process the events
+    while (![appDelegate done]) {
+        NSEvent* event;
+        do {
+            event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                       untilDate:[NSDate distantPast]
+                                          inMode:NSDefaultRunLoopMode
+                                         dequeue:YES];
+            [NSApp sendEvent:event];
+        } while (event != nil);
+
+        [pool drain];
+        pool = [[NSAutoreleasePool alloc] init];
+
+        // Rather than depending on a Mac event to drive this, we treat our window
+        // invalidation flag as a separate event stream. Window::onPaint() will clear
+        // the invalidation flag, effectively removing it from the stream.
+        Window_mac::PaintWindows();
+
+        app->onIdle();
+    }
+
+    delete app;
+
+    [NSApp setDelegate:nil];
+    [appDelegate release];
+
+    [menuBar release];
+    [pool release];
+
+    return EXIT_SUCCESS;
+}
diff --git a/src/third_party/skia/tools/sk_app/unix/DawnVulkanWindowContext_unix.cpp b/src/third_party/skia/tools/sk_app/unix/DawnVulkanWindowContext_unix.cpp
new file mode 100644
index 0000000..b8eee27
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/DawnVulkanWindowContext_unix.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/DawnWindowContext.h"
+#include "tools/sk_app/unix/WindowContextFactory_unix.h"
+#include "dawn_native/DawnNative.h"
+#include "dawn_native/VulkanBackend.h"
+#include "src/ports/SkOSLibrary.h"
+#include "tools/gpu/vk/VkTestUtils.h"
+
+#include <vulkan/vulkan.h>
+#include <X11/Xlib-xcb.h>
+
+using sk_app::window_context_factory::XlibWindowInfo;
+using sk_app::DisplayParams;
+using sk_app::DawnWindowContext;
+
+namespace sk_app {
+
+class DawnVulkanWindowContext_xlib : public DawnWindowContext {
+public:
+    DawnVulkanWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
+    ~DawnVulkanWindowContext_xlib() override {}
+    dawn::Device onInitializeContext() override;
+    void onDestroyContext() override {}
+    DawnSwapChainImplementation createSwapChainImplementation(
+            int width, int height, const DisplayParams& params) override;
+    void onSwapBuffers() override {}
+
+private:
+    Display*     fDisplay;
+    XWindow      fWindow;
+    VkSurfaceKHR fVkSurface = nullptr;
+
+    typedef DawnWindowContext INHERITED;
+};
+
+DawnVulkanWindowContext_xlib::DawnVulkanWindowContext_xlib(const XlibWindowInfo& winInfo,
+                                                           const DisplayParams& params)
+        : INHERITED(params, dawn::TextureFormat::BGRA8Unorm)
+        , fDisplay(winInfo.fDisplay)
+        , fWindow(winInfo.fWindow) {
+    XWindow root;
+    int x, y;
+    unsigned int border_width, depth;
+    unsigned int width, height;
+    XGetGeometry(fDisplay, fWindow, &root, &x, &y, &width, &height, &border_width, &depth);
+    this->initializeContext(width, height);
+}
+
+DawnSwapChainImplementation DawnVulkanWindowContext_xlib::createSwapChainImplementation(
+        int width, int height, const DisplayParams& params) {
+    return dawn_native::vulkan::CreateNativeSwapChainImpl(fDevice.Get(), fVkSurface);
+}
+
+dawn::Device DawnVulkanWindowContext_xlib::onInitializeContext() {
+    dawn::Device device = this->createDevice(dawn_native::BackendType::Vulkan);
+    if (!device) {
+        return nullptr;
+    }
+
+    void *vkLib = DynamicLoadLibrary("libvulkan.so.1");
+    if (!vkLib) {
+        return nullptr;
+    }
+    VkInstance instance = dawn_native::vulkan::GetInstance(device.Get());
+    if (!instance) {
+        return nullptr;
+    }
+    auto createXcbSurfaceKHR =
+        reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(GetProcedureAddress(vkLib,
+                                                                        "vkCreateXcbSurfaceKHR"));
+    if (!createXcbSurfaceKHR) {
+        printf("couldn't get extensions :(\n");
+        return nullptr;
+    }
+
+    VkXcbSurfaceCreateInfoKHR surfaceCreateInfo;
+    memset(&surfaceCreateInfo, 0, sizeof(VkXcbSurfaceCreateInfoKHR));
+    surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+    surfaceCreateInfo.pNext = nullptr;
+    surfaceCreateInfo.flags = 0;
+    surfaceCreateInfo.connection = XGetXCBConnection(fDisplay);
+    surfaceCreateInfo.window = fWindow;
+
+    createXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &fVkSurface);
+    return device;
+}
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeDawnVulkanForXlib(const XlibWindowInfo& winInfo,
+                                                     const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new DawnVulkanWindowContext_xlib(winInfo, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}
+
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/unix/GLWindowContext_unix.cpp b/src/third_party/skia/tools/sk_app/unix/GLWindowContext_unix.cpp
new file mode 100644
index 0000000..4de886d
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/GLWindowContext_unix.cpp
@@ -0,0 +1,196 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/gl/GrGLInterface.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/unix/WindowContextFactory_unix.h"
+
+#include <GL/gl.h>
+
+using sk_app::window_context_factory::XlibWindowInfo;
+using sk_app::DisplayParams;
+using sk_app::GLWindowContext;
+
+namespace {
+
+static bool gCtxErrorOccurred = false;
+static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
+    gCtxErrorOccurred = true;
+    return 0;
+}
+
+class GLWindowContext_xlib : public GLWindowContext {
+public:
+    GLWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
+    ~GLWindowContext_xlib() override;
+
+    void onSwapBuffers() override;
+
+    void onDestroyContext() override;
+
+protected:
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+
+private:
+    GLWindowContext_xlib(void*, const DisplayParams&);
+
+    Display*     fDisplay;
+    XWindow      fWindow;
+    GLXFBConfig* fFBConfig;
+    XVisualInfo* fVisualInfo;
+    GLXContext   fGLContext;
+
+    typedef GLWindowContext INHERITED;
+};
+
+GLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo, const DisplayParams& params)
+        : INHERITED(params)
+        , fDisplay(winInfo.fDisplay)
+        , fWindow(winInfo.fWindow)
+        , fFBConfig(winInfo.fFBConfig)
+        , fVisualInfo(winInfo.fVisualInfo)
+        , fGLContext() {
+    fWidth = winInfo.fWidth;
+    fHeight = winInfo.fHeight;
+    this->initializeContext();
+}
+
+using CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+
+sk_sp<const GrGLInterface> GLWindowContext_xlib::onInitializeContext() {
+    SkASSERT(fDisplay);
+    SkASSERT(!fGLContext);
+    sk_sp<const GrGLInterface> interface;
+    bool current = false;
+
+    // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
+    // created with this rather than glXCreateContext.
+    CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
+            (const GLubyte*)"glXCreateContextAttribsARB");
+    if (createContextAttribs && fFBConfig) {
+        // Install Xlib error handler that will set gCtxErrorOccurred
+        int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
+
+        // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
+        // have been removed).
+        for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
+            // Ganesh prefers a compatibility profile for possible NVPR support. However, RenderDoc
+            // requires a core profile. Edit this code to use RenderDoc.
+            for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+                                GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
+                gCtxErrorOccurred = false;
+                int attribs[] = {
+                        GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
+                        GLX_CONTEXT_PROFILE_MASK_ARB, profile,
+                        0
+                };
+                fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
+
+                // Sync to ensure any errors generated are processed.
+                XSync(fDisplay, False);
+                if (gCtxErrorOccurred) { continue; }
+
+                if (fGLContext && profile == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB &&
+                    glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
+                    current = true;
+                    // Look to see if RenderDoc is attached. If so, re-create the context with a
+                    // core profile.
+                    interface = GrGLMakeNativeInterface();
+                    if (interface && interface->fExtensions.has("GL_EXT_debug_tool")) {
+                        interface.reset();
+                        glXMakeCurrent(fDisplay, None, nullptr);
+                        glXDestroyContext(fDisplay, fGLContext);
+                        current = false;
+                        fGLContext = nullptr;
+                    }
+                }
+                if (fGLContext) {
+                    break;
+                }
+            }
+        }
+        // Restore the original error handler
+        XSetErrorHandler(oldHandler);
+    }
+    if (!fGLContext) {
+        fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
+    }
+    if (!fGLContext) {
+        return nullptr;
+    }
+
+    if (!current && !glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
+        return nullptr;
+    }
+
+    const char* glxExtensions = glXQueryExtensionsString(fDisplay, DefaultScreen(fDisplay));
+    if (glxExtensions) {
+        if (strstr(glxExtensions, "GLX_EXT_swap_control")) {
+            PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
+                    (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB(
+                            (const GLubyte*)"glXSwapIntervalEXT");
+            glXSwapIntervalEXT(fDisplay, fWindow, fDisplayParams.fDisableVsync ? 0 : 1);
+        }
+    }
+
+    glClearStencil(0);
+    glClearColor(0, 0, 0, 0);
+    glStencilMask(0xffffffff);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+
+    glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
+    glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
+    fSampleCount = SkTMax(fSampleCount, 1);
+
+    XWindow root;
+    int x, y;
+    unsigned int border_width, depth;
+    XGetGeometry(fDisplay, fWindow, &root, &x, &y, (unsigned int*)&fWidth, (unsigned int*)&fHeight,
+                 &border_width, &depth);
+    glViewport(0, 0, fWidth, fHeight);
+
+    return interface ? interface : GrGLMakeNativeInterface();
+}
+
+GLWindowContext_xlib::~GLWindowContext_xlib() {
+    this->destroyContext();
+}
+
+void GLWindowContext_xlib::onDestroyContext() {
+    if (!fDisplay || !fGLContext) {
+        return;
+    }
+    glXMakeCurrent(fDisplay, None, nullptr);
+    glXDestroyContext(fDisplay, fGLContext);
+    fGLContext = nullptr;
+}
+
+void GLWindowContext_xlib::onSwapBuffers() {
+    if (fDisplay && fGLContext) {
+        glXSwapBuffers(fDisplay, fWindow);
+    }
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeGLForXlib(const XlibWindowInfo& winInfo,
+                                             const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new GLWindowContext_xlib(winInfo, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/RasterWindowContext_unix.cpp b/src/third_party/skia/tools/sk_app/unix/RasterWindowContext_unix.cpp
similarity index 83%
rename from src/third_party/skia/tools/viewer/sk_app/unix/RasterWindowContext_unix.cpp
rename to src/third_party/skia/tools/sk_app/unix/RasterWindowContext_unix.cpp
index 6bfa6fd..e8ae942 100644
--- a/src/third_party/skia/tools/viewer/sk_app/unix/RasterWindowContext_unix.cpp
+++ b/src/third_party/skia/tools/sk_app/unix/RasterWindowContext_unix.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
-#include "WindowContextFactory_unix.h"
-#include "../RasterWindowContext.h"
-#include "SkSurface.h"
+#include "include/core/SkSurface.h"
+#include "tools/sk_app/RasterWindowContext.h"
+#include "tools/sk_app/unix/WindowContextFactory_unix.h"
 
 using sk_app::RasterWindowContext;
 using sk_app::DisplayParams;
@@ -54,7 +54,7 @@
 void RasterWindowContext_xlib::resize(int  w, int h) {
     SkImageInfo info = SkImageInfo::Make(w, h, fDisplayParams.fColorType, kPremul_SkAlphaType,
                                          fDisplayParams.fColorSpace);
-    fBackbufferSurface = SkSurface::MakeRaster(info);
+    fBackbufferSurface = SkSurface::MakeRaster(info, &fDisplayParams.fSurfaceProps);
 
 }
 
@@ -90,11 +90,11 @@
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewRasterForXlib(const XlibWindowInfo& info, const DisplayParams& params) {
-    WindowContext* ctx = new RasterWindowContext_xlib(info.fDisplay, info.fWindow, info.fWidth,
-                                                      info.fHeight, params);
+std::unique_ptr<WindowContext> MakeRasterForXlib(const XlibWindowInfo& info,
+                                                 const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_xlib(
+            info.fDisplay, info.fWindow, info.fWidth, info.fHeight, params));
     if (!ctx->isValid()) {
-        delete ctx;
         ctx = nullptr;
     }
     return ctx;
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp b/src/third_party/skia/tools/sk_app/unix/VulkanWindowContext_unix.cpp
similarity index 64%
rename from src/third_party/skia/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp
rename to src/third_party/skia/tools/sk_app/unix/VulkanWindowContext_unix.cpp
index b94e8ed..6f0ce0a 100644
--- a/src/third_party/skia/tools/viewer/sk_app/unix/VulkanWindowContext_unix.cpp
+++ b/src/third_party/skia/tools/sk_app/unix/VulkanWindowContext_unix.cpp
@@ -6,26 +6,35 @@
  * found in the LICENSE file.
  */
 
+#include "include/gpu/vk/GrVkVulkan.h"
 
-#include "vk/GrVkInterface.h"
-#include "vk/GrVkUtil.h"
+#include "src/gpu/vk/GrVkInterface.h"
+#include "src/gpu/vk/GrVkUtil.h"
+
+#include "tools/gpu/vk/VkTestUtils.h"
+
+#include "tools/sk_app/VulkanWindowContext.h"
+#include "tools/sk_app/unix/WindowContextFactory_unix.h"
 
 #include <X11/Xlib-xcb.h>
 
-#include "WindowContextFactory_unix.h"
-#include "../VulkanWindowContext.h"
-
 namespace sk_app {
 
 namespace window_context_factory {
 
-WindowContext* NewVulkanForXlib(const XlibWindowInfo& info, const DisplayParams& displayParams) {
-    auto createVkSurface = [&info](VkInstance instance) -> VkSurfaceKHR {
+std::unique_ptr<WindowContext> MakeVulkanForXlib(const XlibWindowInfo& info,
+                                                 const DisplayParams& displayParams) {
+    PFN_vkGetInstanceProcAddr instProc;
+    PFN_vkGetDeviceProcAddr devProc;
+    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
+        return nullptr;
+    }
+
+    auto createVkSurface = [&info, instProc](VkInstance instance) -> VkSurfaceKHR {
         static PFN_vkCreateXcbSurfaceKHR createXcbSurfaceKHR = nullptr;
         if (!createXcbSurfaceKHR) {
             createXcbSurfaceKHR =
-                    (PFN_vkCreateXcbSurfaceKHR) vkGetInstanceProcAddr(instance,
-                                                                      "vkCreateXcbSurfaceKHR");
+                    (PFN_vkCreateXcbSurfaceKHR) instProc(instance, "vkCreateXcbSurfaceKHR");
         }
 
         VkSurfaceKHR surface;
@@ -46,15 +55,14 @@
         return surface;
     };
 
-    auto canPresent = [&info](VkInstance instance, VkPhysicalDevice physDev,
+    auto canPresent = [&info, instProc](VkInstance instance, VkPhysicalDevice physDev,
                               uint32_t queueFamilyIndex) {
         static PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR
                                                 getPhysicalDeviceXcbPresentationSupportKHR = nullptr;
         if (!getPhysicalDeviceXcbPresentationSupportKHR) {
             getPhysicalDeviceXcbPresentationSupportKHR =
                 (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)
-                        vkGetInstanceProcAddr(instance,
-                                              "vkGetPhysicalDeviceXcbPresentationSupportKHR");
+                    instProc(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR");
         }
 
 
@@ -66,12 +74,12 @@
                                                                     visualID);
         return (VK_FALSE != check);
     };
-    WindowContext* context = new VulkanWindowContext(displayParams, createVkSurface, canPresent);
-    if (!context->isValid()) {
-        delete context;
+    std::unique_ptr<WindowContext> ctx(
+            new VulkanWindowContext(displayParams, createVkSurface, canPresent, instProc, devProc));
+    if (!ctx->isValid()) {
         return nullptr;
     }
-    return context;
+    return ctx;
 }
 
 }  // namespace VulkanWindowContextFactory
diff --git a/src/third_party/skia/tools/sk_app/unix/WindowContextFactory_unix.h b/src/third_party/skia/tools/sk_app/unix/WindowContextFactory_unix.h
new file mode 100644
index 0000000..4731097
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/WindowContextFactory_unix.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef WindowContextFactory_unix_DEFINED
+#define WindowContextFactory_unix_DEFINED
+
+// dawncpp.h and X.h don't get along. Include this first, before X11 defines None, Success etc.
+#ifdef SK_DAWN
+#include "dawn/dawncpp.h"
+#endif
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#include <memory>
+
+typedef Window XWindow;
+
+namespace sk_app {
+
+class WindowContext;
+struct DisplayParams;
+
+namespace window_context_factory {
+
+struct XlibWindowInfo {
+    Display*     fDisplay;
+    XWindow      fWindow;
+    GLXFBConfig* fFBConfig;
+    XVisualInfo* fVisualInfo;
+    int          fWidth;
+    int          fHeight;
+};
+
+std::unique_ptr<WindowContext> MakeVulkanForXlib(const XlibWindowInfo&, const DisplayParams&);
+
+std::unique_ptr<WindowContext> MakeGLForXlib(const XlibWindowInfo&, const DisplayParams&);
+
+#ifdef SK_DAWN
+std::unique_ptr<WindowContext> MakeDawnVulkanForXlib(const XlibWindowInfo&, const DisplayParams&);
+#endif
+
+std::unique_ptr<WindowContext> MakeRasterForXlib(const XlibWindowInfo&, const DisplayParams&);
+
+}  // namespace window_context_factory
+
+}  // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.cpp b/src/third_party/skia/tools/sk_app/unix/Window_unix.cpp
similarity index 73%
rename from src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.cpp
rename to src/third_party/skia/tools/sk_app/unix/Window_unix.cpp
index ef0d85e..32e0447 100644
--- a/src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.cpp
+++ b/src/third_party/skia/tools/sk_app/unix/Window_unix.cpp
@@ -2,20 +2,26 @@
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
+* f 49
+* Prev
+* Up
+*
+*
 * found in the LICENSE file.
 */
 
 //#include <tchar.h>
 
-#include "WindowContextFactory_unix.h"
+#include "tools/sk_app/unix/WindowContextFactory_unix.h"
 
-#include "SkUtils.h"
-#include "Timer.h"
-#include "../GLWindowContext.h"
-#include "Window_unix.h"
+#include "src/utils/SkUTF.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/unix/Window_unix.h"
+#include "tools/skui/ModifierKey.h"
+#include "tools/timer/Timer.h"
 
 extern "C" {
-    #include "keysym2ucs.h"
+    #include "tools/sk_app/unix/keysym2ucs.h"
 }
 #include <X11/Xutil.h>
 #include <X11/XKBlib.h>
@@ -37,8 +43,8 @@
     return window;
 }
 
-const long kEventMask = ExposureMask | StructureNotifyMask | 
-                        KeyPressMask | KeyReleaseMask | 
+const long kEventMask = ExposureMask | StructureNotifyMask |
+                        KeyPressMask | KeyReleaseMask |
                         PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
 
 bool Window_unix::initWindow(Display* display) {
@@ -72,7 +78,7 @@
         None
     };
     SkASSERT(nullptr == fVisualInfo);
-    if (fRequestedDisplayParams.fMSAASampleCount > 0) {
+    if (fRequestedDisplayParams.fMSAASampleCount > 1) {
         static const GLint kChooseFBConifgAttCnt = SK_ARRAY_COUNT(kChooseFBConfigAtt);
         GLint msaaChooseFBConfigAtt[kChooseFBConifgAttCnt + 4];
         memcpy(msaaChooseFBConfigAtt, kChooseFBConfigAtt, sizeof(kChooseFBConfigAtt));
@@ -184,57 +190,57 @@
     }
 }
 
-static Window::Key get_key(KeySym keysym) {
+static skui::Key get_key(KeySym keysym) {
     static const struct {
         KeySym      fXK;
-        Window::Key fKey;
+        skui::Key fKey;
     } gPair[] = {
-        { XK_BackSpace, Window::Key::kBack },
-        { XK_Clear, Window::Key::kBack },
-        { XK_Return, Window::Key::kOK },
-        { XK_Up, Window::Key::kUp },
-        { XK_Down, Window::Key::kDown },
-        { XK_Left, Window::Key::kLeft },
-        { XK_Right, Window::Key::kRight },
-        { XK_Tab, Window::Key::kTab },
-        { XK_Page_Up, Window::Key::kPageUp },
-        { XK_Page_Down, Window::Key::kPageDown },
-        { XK_Home, Window::Key::kHome },
-        { XK_End, Window::Key::kEnd },
-        { XK_Delete, Window::Key::kDelete },
-        { XK_Escape, Window::Key::kEscape },
-        { XK_Shift_L, Window::Key::kShift },
-        { XK_Shift_R, Window::Key::kShift },
-        { XK_Control_L, Window::Key::kCtrl },
-        { XK_Control_R, Window::Key::kCtrl },
-        { XK_Alt_L, Window::Key::kOption },
-        { XK_Alt_R, Window::Key::kOption },
-        { 'A', Window::Key::kA },
-        { 'C', Window::Key::kC },
-        { 'V', Window::Key::kV },
-        { 'X', Window::Key::kX },
-        { 'Y', Window::Key::kY },
-        { 'Z', Window::Key::kZ },
+        { XK_BackSpace, skui::Key::kBack     },
+        { XK_Clear,     skui::Key::kBack     },
+        { XK_Return,    skui::Key::kOK       },
+        { XK_Up,        skui::Key::kUp       },
+        { XK_Down,      skui::Key::kDown     },
+        { XK_Left,      skui::Key::kLeft     },
+        { XK_Right,     skui::Key::kRight    },
+        { XK_Tab,       skui::Key::kTab      },
+        { XK_Page_Up,   skui::Key::kPageUp   },
+        { XK_Page_Down, skui::Key::kPageDown },
+        { XK_Home,      skui::Key::kHome     },
+        { XK_End,       skui::Key::kEnd      },
+        { XK_Delete,    skui::Key::kDelete   },
+        { XK_Escape,    skui::Key::kEscape   },
+        { XK_Shift_L,   skui::Key::kShift    },
+        { XK_Shift_R,   skui::Key::kShift    },
+        { XK_Control_L, skui::Key::kCtrl     },
+        { XK_Control_R, skui::Key::kCtrl     },
+        { XK_Alt_L,     skui::Key::kOption   },
+        { XK_Alt_R,     skui::Key::kOption   },
+        { 'A',          skui::Key::kA        },
+        { 'C',          skui::Key::kC        },
+        { 'V',          skui::Key::kV        },
+        { 'X',          skui::Key::kX        },
+        { 'Y',          skui::Key::kY        },
+        { 'Z',          skui::Key::kZ        },
     };
     for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
         if (gPair[i].fXK == keysym) {
             return gPair[i].fKey;
         }
     }
-    return Window::Key::kNONE;
+    return skui::Key::kNONE;
 }
 
-static uint32_t get_modifiers(const XEvent& event) {
+static skui::ModifierKey get_modifiers(const XEvent& event) {
     static const struct {
         unsigned    fXMask;
-        unsigned    fSkMask;
+        skui::ModifierKey  fSkMask;
     } gModifiers[] = {
-        { ShiftMask,   Window::kShift_ModifierKey },
-        { ControlMask, Window::kControl_ModifierKey },
-        { Mod1Mask,    Window::kOption_ModifierKey },
+        { ShiftMask,   skui::ModifierKey::kShift },
+        { ControlMask, skui::ModifierKey::kControl },
+        { Mod1Mask,    skui::ModifierKey::kOption },
     };
 
-    auto modifiers = 0;
+    skui::ModifierKey modifiers = skui::ModifierKey::kNone;
     for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
         if (event.xkey.state & gModifiers[i].fXMask) {
             modifiers |= gModifiers[i].fSkMask;
@@ -262,7 +268,7 @@
             switch (event.xbutton.button) {
                 case Button1:
                     this->onMouse(event.xbutton.x, event.xbutton.y,
-                                  Window::kDown_InputState, get_modifiers(event));
+                                  skui::InputState::kDown, get_modifiers(event));
                     break;
                 case Button4:
                     this->onMouseWheel(1.0f, get_modifiers(event));
@@ -276,21 +282,21 @@
         case ButtonRelease:
             if (event.xbutton.button == Button1) {
                 this->onMouse(event.xbutton.x, event.xbutton.y,
-                              Window::kUp_InputState, get_modifiers(event));
+                              skui::InputState::kUp, get_modifiers(event));
             }
             break;
 
         case MotionNotify:
             this->onMouse(event.xmotion.x, event.xmotion.y,
-                          Window::kMove_InputState, get_modifiers(event));
+                          skui::InputState::kMove, get_modifiers(event));
             break;
 
         case KeyPress: {
             int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
             KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode, 0, shiftLevel);
-            Window::Key key = get_key(keysym);
-            if (key != Window::Key::kNONE) {
-                if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
+            skui::Key key = get_key(keysym);
+            if (key != skui::Key::kNONE) {
+                if (!this->onKey(key, skui::InputState::kDown, get_modifiers(event))) {
                     if (keysym == XK_Escape) {
                         return true;
                     }
@@ -307,11 +313,11 @@
             int shiftLevel = (event.xkey.state & ShiftMask) ? 1 : 0;
             KeySym keysym = XkbKeycodeToKeysym(fDisplay, event.xkey.keycode,
                                                0, shiftLevel);
-            Window::Key key = get_key(keysym);
-            (void) this->onKey(key, Window::kUp_InputState, 
+            skui::Key key = get_key(keysym);
+            (void) this->onKey(key, skui::InputState::kUp,
                                get_modifiers(event));
         } break;
-        
+
 
         default:
             // these events should be handled in the main event loop
@@ -325,7 +331,7 @@
 void Window_unix::setTitle(const char* title) {
     XTextProperty textproperty;
     XStringListToTextProperty(const_cast<char**>(&title), 1, &textproperty);
-    XSetWMName(fDisplay, fWindow, &textproperty);    
+    XSetWMName(fDisplay, fWindow, &textproperty);
 }
 
 void Window_unix::show() {
@@ -333,6 +339,8 @@
 }
 
 bool Window_unix::attach(BackendType attachType) {
+    fBackend = attachType;
+
     this->initWindow(fDisplay);
 
     window_context_factory::XlibWindowInfo winInfo;
@@ -350,18 +358,25 @@
     }
 
     switch (attachType) {
+#ifdef SK_DAWN
+        case kDawn_BackendType:
+            fWindowContext =
+                    window_context_factory::MakeDawnVulkanForXlib(winInfo, fRequestedDisplayParams);
+            break;
+#endif
 #ifdef SK_VULKAN
         case kVulkan_BackendType:
-            fWindowContext = window_context_factory::NewVulkanForXlib(winInfo,
-                                                                      fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeVulkanForXlib(winInfo, fRequestedDisplayParams);
             break;
 #endif
         case kNativeGL_BackendType:
-            fWindowContext = window_context_factory::NewGLForXlib(winInfo, fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeGLForXlib(winInfo, fRequestedDisplayParams);
             break;
         case kRaster_BackendType:
-            fWindowContext = window_context_factory::NewRasterForXlib(winInfo,
-                                                                      fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeRasterForXlib(winInfo, fRequestedDisplayParams);
             break;
     }
     this->onBackendCreated();
@@ -380,8 +395,25 @@
     event.xexpose.width = this->width();
     event.xexpose.height = this->height();
     event.xexpose.count = 0;
-    
+
     XSendEvent(fDisplay, fWindow, False, 0, &event);
 }
 
+void Window_unix::setRequestedDisplayParams(const DisplayParams& params, bool allowReattach) {
+#if defined(SK_VULKAN)
+    // Vulkan on unix crashes if we try to reinitialize the vulkan context without remaking the
+    // window.
+    if (fBackend == kVulkan_BackendType && allowReattach) {
+        // Need to change these early, so attach() creates the window context correctly
+        fRequestedDisplayParams = params;
+
+        this->detach();
+        this->attach(fBackend);
+        return;
+    }
+#endif
+
+    INHERITED::setRequestedDisplayParams(params, allowReattach);
+}
+
 }   // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.h b/src/third_party/skia/tools/sk_app/unix/Window_unix.h
similarity index 70%
rename from src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.h
rename to src/third_party/skia/tools/sk_app/unix/Window_unix.h
index 73f21af..417a79b 100644
--- a/src/third_party/skia/tools/viewer/sk_app/unix/Window_unix.h
+++ b/src/third_party/skia/tools/sk_app/unix/Window_unix.h
@@ -8,11 +8,12 @@
 #ifndef Window_unix_DEFINED
 #define Window_unix_DEFINED
 
-#include <X11/Xlib.h>
+#include "include/private/SkChecksum.h"
+#include "src/core/SkTDynamicHash.h"
+#include "tools/sk_app/Window.h"
+
 #include <GL/glx.h>
-#include "../Window.h"
-#include "SkChecksum.h"
-#include "SkTDynamicHash.h"
+#include <X11/Xlib.h>
 
 typedef Window XWindow;
 
@@ -20,13 +21,14 @@
 
 class Window_unix : public Window {
 public:
-    Window_unix() : Window()
-                  , fDisplay(nullptr)
-                  , fWindow(0)
-                  , fGC(nullptr)
-                  , fFBConfig(nullptr)
-                  , fVisualInfo(nullptr)
-                  , fMSAASampleCount(0) {}
+    Window_unix()
+            : Window()
+            , fDisplay(nullptr)
+            , fWindow(0)
+            , fGC(nullptr)
+            , fFBConfig(nullptr)
+            , fVisualInfo(nullptr)
+            , fMSAASampleCount(1) {}
     ~Window_unix() override { this->closeWindow(); }
 
     bool initWindow(Display* display);
@@ -51,10 +53,10 @@
     static SkTDynamicHash<Window_unix, XWindow> gWindowMap;
 
     void markPendingPaint() { fPendingPaint = true; }
-    void finishPaint() { 
+    void finishPaint() {
         if (fPendingPaint) {
-            this->onPaint(); 
-            fPendingPaint = false; 
+            this->onPaint();
+            fPendingPaint = false;
         }
     }
 
@@ -65,13 +67,15 @@
             fPendingHeight = height;
         }
     }
-    void finishResize() { 
+    void finishResize() {
         if (fPendingResize) {
-            this->onResize(fPendingWidth, fPendingHeight); 
+            this->onResize(fPendingWidth, fPendingHeight);
             fPendingResize = false;
-        } 
+        }
     }
 
+    void setRequestedDisplayParams(const DisplayParams&, bool allowReattach) override;
+
 private:
     void closeWindow();
 
@@ -88,6 +92,10 @@
     int      fPendingWidth;
     int      fPendingHeight;
     bool     fPendingResize;
+
+    BackendType fBackend;
+
+    typedef Window INHERITED;
 };
 
 }   // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/unix/keysym2ucs.c b/src/third_party/skia/tools/sk_app/unix/keysym2ucs.c
new file mode 100644
index 0000000..00e3052
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/keysym2ucs.c
@@ -0,0 +1,848 @@
+/* $XFree86$
+ * This module converts keysym values into the corresponding ISO 10646
+ * (UCS, Unicode) values.
+ *
+ * The array keysymtab[] contains pairs of X11 keysym values for graphical
+ * characters and the corresponding Unicode value. The function
+ * keysym2ucs() maps a keysym onto a Unicode value using a binary search,
+ * therefore keysymtab[] must remain SORTED by keysym value.
+ *
+ * The keysym -> UTF-8 conversion will hopefully one day be provided
+ * by Xlib via XmbLookupString() and should ideally not have to be
+ * done in X applications. But we are not there yet.
+ *
+ * We allow to represent any UCS character in the range U-00000000 to
+ * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
+ * This admittedly does not cover the entire 31-bit space of UCS, but
+ * it does cover all of the characters up to U-10FFFF, which can be
+ * represented by UTF-16, and more, and it is very unlikely that higher
+ * UCS codes will ever be assigned by ISO. So to get Unicode character
+ * U+ABCD you can directly use keysym 0x0100abcd.
+ *
+ * NOTE: The comments in the table below contain the actual character
+ * encoded in UTF-8, so for viewing and editing best use an editor in
+ * UTF-8 mode.
+ *
+ * Author: Markus G. Kuhn <http://www.cl.cam.ac.uk/~mgk25/>,
+ *         University of Cambridge, April 2001
+ *
+ * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
+ * an initial draft of the mapping table.
+ *
+ * This software is in the public domain. Share and enjoy!
+ *
+ * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl)
+ */
+
+#include "tools/sk_app/unix/keysym2ucs.h"
+
+struct codepair {
+  unsigned short keysym;
+  unsigned short ucs;
+} keysymtab[] = {
+  { 0x01a1, 0x0104 }, /*                     Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
+  { 0x01a2, 0x02d8 }, /*                       breve ˘ BREVE */
+  { 0x01a3, 0x0141 }, /*                     Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
+  { 0x01a5, 0x013d }, /*                      Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
+  { 0x01a6, 0x015a }, /*                      Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
+  { 0x01a9, 0x0160 }, /*                      Scaron Š LATIN CAPITAL LETTER S WITH CARON */
+  { 0x01aa, 0x015e }, /*                    Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
+  { 0x01ab, 0x0164 }, /*                      Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
+  { 0x01ac, 0x0179 }, /*                      Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
+  { 0x01ae, 0x017d }, /*                      Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
+  { 0x01af, 0x017b }, /*                   Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+  { 0x01b1, 0x0105 }, /*                     aogonek ą LATIN SMALL LETTER A WITH OGONEK */
+  { 0x01b2, 0x02db }, /*                      ogonek ˛ OGONEK */
+  { 0x01b3, 0x0142 }, /*                     lstroke ł LATIN SMALL LETTER L WITH STROKE */
+  { 0x01b5, 0x013e }, /*                      lcaron ľ LATIN SMALL LETTER L WITH CARON */
+  { 0x01b6, 0x015b }, /*                      sacute ś LATIN SMALL LETTER S WITH ACUTE */
+  { 0x01b7, 0x02c7 }, /*                       caron ˇ CARON */
+  { 0x01b9, 0x0161 }, /*                      scaron š LATIN SMALL LETTER S WITH CARON */
+  { 0x01ba, 0x015f }, /*                    scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
+  { 0x01bb, 0x0165 }, /*                      tcaron ť LATIN SMALL LETTER T WITH CARON */
+  { 0x01bc, 0x017a }, /*                      zacute ź LATIN SMALL LETTER Z WITH ACUTE */
+  { 0x01bd, 0x02dd }, /*                 doubleacute ˝ DOUBLE ACUTE ACCENT */
+  { 0x01be, 0x017e }, /*                      zcaron ž LATIN SMALL LETTER Z WITH CARON */
+  { 0x01bf, 0x017c }, /*                   zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
+  { 0x01c0, 0x0154 }, /*                      Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
+  { 0x01c3, 0x0102 }, /*                      Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
+  { 0x01c5, 0x0139 }, /*                      Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
+  { 0x01c6, 0x0106 }, /*                      Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
+  { 0x01c8, 0x010c }, /*                      Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
+  { 0x01ca, 0x0118 }, /*                     Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
+  { 0x01cc, 0x011a }, /*                      Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
+  { 0x01cf, 0x010e }, /*                      Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
+  { 0x01d0, 0x0110 }, /*                     Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
+  { 0x01d1, 0x0143 }, /*                      Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
+  { 0x01d2, 0x0147 }, /*                      Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
+  { 0x01d5, 0x0150 }, /*                Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+  { 0x01d8, 0x0158 }, /*                      Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
+  { 0x01d9, 0x016e }, /*                       Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
+  { 0x01db, 0x0170 }, /*                Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+  { 0x01de, 0x0162 }, /*                    Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
+  { 0x01e0, 0x0155 }, /*                      racute ŕ LATIN SMALL LETTER R WITH ACUTE */
+  { 0x01e3, 0x0103 }, /*                      abreve ă LATIN SMALL LETTER A WITH BREVE */
+  { 0x01e5, 0x013a }, /*                      lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
+  { 0x01e6, 0x0107 }, /*                      cacute ć LATIN SMALL LETTER C WITH ACUTE */
+  { 0x01e8, 0x010d }, /*                      ccaron č LATIN SMALL LETTER C WITH CARON */
+  { 0x01ea, 0x0119 }, /*                     eogonek ę LATIN SMALL LETTER E WITH OGONEK */
+  { 0x01ec, 0x011b }, /*                      ecaron ě LATIN SMALL LETTER E WITH CARON */
+  { 0x01ef, 0x010f }, /*                      dcaron ď LATIN SMALL LETTER D WITH CARON */
+  { 0x01f0, 0x0111 }, /*                     dstroke đ LATIN SMALL LETTER D WITH STROKE */
+  { 0x01f1, 0x0144 }, /*                      nacute ń LATIN SMALL LETTER N WITH ACUTE */
+  { 0x01f2, 0x0148 }, /*                      ncaron ň LATIN SMALL LETTER N WITH CARON */
+  { 0x01f5, 0x0151 }, /*                odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+  { 0x01f8, 0x0159 }, /*                      rcaron ř LATIN SMALL LETTER R WITH CARON */
+  { 0x01f9, 0x016f }, /*                       uring ů LATIN SMALL LETTER U WITH RING ABOVE */
+  { 0x01fb, 0x0171 }, /*                udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+  { 0x01fe, 0x0163 }, /*                    tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
+  { 0x01ff, 0x02d9 }, /*                    abovedot ˙ DOT ABOVE */
+  { 0x02a1, 0x0126 }, /*                     Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
+  { 0x02a6, 0x0124 }, /*                 Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+  { 0x02a9, 0x0130 }, /*                   Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
+  { 0x02ab, 0x011e }, /*                      Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
+  { 0x02ac, 0x0134 }, /*                 Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+  { 0x02b1, 0x0127 }, /*                     hstroke ħ LATIN SMALL LETTER H WITH STROKE */
+  { 0x02b6, 0x0125 }, /*                 hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
+  { 0x02b9, 0x0131 }, /*                    idotless ı LATIN SMALL LETTER DOTLESS I */
+  { 0x02bb, 0x011f }, /*                      gbreve ğ LATIN SMALL LETTER G WITH BREVE */
+  { 0x02bc, 0x0135 }, /*                 jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
+  { 0x02c5, 0x010a }, /*                   Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
+  { 0x02c6, 0x0108 }, /*                 Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+  { 0x02d5, 0x0120 }, /*                   Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
+  { 0x02d8, 0x011c }, /*                 Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+  { 0x02dd, 0x016c }, /*                      Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
+  { 0x02de, 0x015c }, /*                 Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+  { 0x02e5, 0x010b }, /*                   cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
+  { 0x02e6, 0x0109 }, /*                 ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
+  { 0x02f5, 0x0121 }, /*                   gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
+  { 0x02f8, 0x011d }, /*                 gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
+  { 0x02fd, 0x016d }, /*                      ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
+  { 0x02fe, 0x015d }, /*                 scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
+  { 0x03a2, 0x0138 }, /*                         kra ĸ LATIN SMALL LETTER KRA */
+  { 0x03a3, 0x0156 }, /*                    Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
+  { 0x03a5, 0x0128 }, /*                      Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
+  { 0x03a6, 0x013b }, /*                    Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
+  { 0x03aa, 0x0112 }, /*                     Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
+  { 0x03ab, 0x0122 }, /*                    Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
+  { 0x03ac, 0x0166 }, /*                      Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
+  { 0x03b3, 0x0157 }, /*                    rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
+  { 0x03b5, 0x0129 }, /*                      itilde ĩ LATIN SMALL LETTER I WITH TILDE */
+  { 0x03b6, 0x013c }, /*                    lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
+  { 0x03ba, 0x0113 }, /*                     emacron ē LATIN SMALL LETTER E WITH MACRON */
+  { 0x03bb, 0x0123 }, /*                    gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
+  { 0x03bc, 0x0167 }, /*                      tslash ŧ LATIN SMALL LETTER T WITH STROKE */
+  { 0x03bd, 0x014a }, /*                         ENG Ŋ LATIN CAPITAL LETTER ENG */
+  { 0x03bf, 0x014b }, /*                         eng ŋ LATIN SMALL LETTER ENG */
+  { 0x03c0, 0x0100 }, /*                     Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
+  { 0x03c7, 0x012e }, /*                     Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
+  { 0x03cc, 0x0116 }, /*                   Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
+  { 0x03cf, 0x012a }, /*                     Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
+  { 0x03d1, 0x0145 }, /*                    Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
+  { 0x03d2, 0x014c }, /*                     Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
+  { 0x03d3, 0x0136 }, /*                    Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
+  { 0x03d9, 0x0172 }, /*                     Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
+  { 0x03dd, 0x0168 }, /*                      Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
+  { 0x03de, 0x016a }, /*                     Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
+  { 0x03e0, 0x0101 }, /*                     amacron ā LATIN SMALL LETTER A WITH MACRON */
+  { 0x03e7, 0x012f }, /*                     iogonek į LATIN SMALL LETTER I WITH OGONEK */
+  { 0x03ec, 0x0117 }, /*                   eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
+  { 0x03ef, 0x012b }, /*                     imacron ī LATIN SMALL LETTER I WITH MACRON */
+  { 0x03f1, 0x0146 }, /*                    ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
+  { 0x03f2, 0x014d }, /*                     omacron ō LATIN SMALL LETTER O WITH MACRON */
+  { 0x03f3, 0x0137 }, /*                    kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
+  { 0x03f9, 0x0173 }, /*                     uogonek ų LATIN SMALL LETTER U WITH OGONEK */
+  { 0x03fd, 0x0169 }, /*                      utilde ũ LATIN SMALL LETTER U WITH TILDE */
+  { 0x03fe, 0x016b }, /*                     umacron ū LATIN SMALL LETTER U WITH MACRON */
+  { 0x047e, 0x203e }, /*                    overline ‾ OVERLINE */
+  { 0x04a1, 0x3002 }, /*               kana_fullstop 。 IDEOGRAPHIC FULL STOP */
+  { 0x04a2, 0x300c }, /*         kana_openingbracket 「 LEFT CORNER BRACKET */
+  { 0x04a3, 0x300d }, /*         kana_closingbracket 」 RIGHT CORNER BRACKET */
+  { 0x04a4, 0x3001 }, /*                  kana_comma 、 IDEOGRAPHIC COMMA */
+  { 0x04a5, 0x30fb }, /*            kana_conjunctive ・ KATAKANA MIDDLE DOT */
+  { 0x04a6, 0x30f2 }, /*                     kana_WO ヲ KATAKANA LETTER WO */
+  { 0x04a7, 0x30a1 }, /*                      kana_a ァ KATAKANA LETTER SMALL A */
+  { 0x04a8, 0x30a3 }, /*                      kana_i ィ KATAKANA LETTER SMALL I */
+  { 0x04a9, 0x30a5 }, /*                      kana_u ゥ KATAKANA LETTER SMALL U */
+  { 0x04aa, 0x30a7 }, /*                      kana_e ェ KATAKANA LETTER SMALL E */
+  { 0x04ab, 0x30a9 }, /*                      kana_o ォ KATAKANA LETTER SMALL O */
+  { 0x04ac, 0x30e3 }, /*                     kana_ya ャ KATAKANA LETTER SMALL YA */
+  { 0x04ad, 0x30e5 }, /*                     kana_yu ュ KATAKANA LETTER SMALL YU */
+  { 0x04ae, 0x30e7 }, /*                     kana_yo ョ KATAKANA LETTER SMALL YO */
+  { 0x04af, 0x30c3 }, /*                    kana_tsu ッ KATAKANA LETTER SMALL TU */
+  { 0x04b0, 0x30fc }, /*              prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
+  { 0x04b1, 0x30a2 }, /*                      kana_A ア KATAKANA LETTER A */
+  { 0x04b2, 0x30a4 }, /*                      kana_I イ KATAKANA LETTER I */
+  { 0x04b3, 0x30a6 }, /*                      kana_U ウ KATAKANA LETTER U */
+  { 0x04b4, 0x30a8 }, /*                      kana_E エ KATAKANA LETTER E */
+  { 0x04b5, 0x30aa }, /*                      kana_O オ KATAKANA LETTER O */
+  { 0x04b6, 0x30ab }, /*                     kana_KA カ KATAKANA LETTER KA */
+  { 0x04b7, 0x30ad }, /*                     kana_KI キ KATAKANA LETTER KI */
+  { 0x04b8, 0x30af }, /*                     kana_KU ク KATAKANA LETTER KU */
+  { 0x04b9, 0x30b1 }, /*                     kana_KE ケ KATAKANA LETTER KE */
+  { 0x04ba, 0x30b3 }, /*                     kana_KO コ KATAKANA LETTER KO */
+  { 0x04bb, 0x30b5 }, /*                     kana_SA サ KATAKANA LETTER SA */
+  { 0x04bc, 0x30b7 }, /*                    kana_SHI シ KATAKANA LETTER SI */
+  { 0x04bd, 0x30b9 }, /*                     kana_SU ス KATAKANA LETTER SU */
+  { 0x04be, 0x30bb }, /*                     kana_SE セ KATAKANA LETTER SE */
+  { 0x04bf, 0x30bd }, /*                     kana_SO ソ KATAKANA LETTER SO */
+  { 0x04c0, 0x30bf }, /*                     kana_TA タ KATAKANA LETTER TA */
+  { 0x04c1, 0x30c1 }, /*                    kana_CHI チ KATAKANA LETTER TI */
+  { 0x04c2, 0x30c4 }, /*                    kana_TSU ツ KATAKANA LETTER TU */
+  { 0x04c3, 0x30c6 }, /*                     kana_TE テ KATAKANA LETTER TE */
+  { 0x04c4, 0x30c8 }, /*                     kana_TO ト KATAKANA LETTER TO */
+  { 0x04c5, 0x30ca }, /*                     kana_NA ナ KATAKANA LETTER NA */
+  { 0x04c6, 0x30cb }, /*                     kana_NI ニ KATAKANA LETTER NI */
+  { 0x04c7, 0x30cc }, /*                     kana_NU ヌ KATAKANA LETTER NU */
+  { 0x04c8, 0x30cd }, /*                     kana_NE ネ KATAKANA LETTER NE */
+  { 0x04c9, 0x30ce }, /*                     kana_NO ノ KATAKANA LETTER NO */
+  { 0x04ca, 0x30cf }, /*                     kana_HA ハ KATAKANA LETTER HA */
+  { 0x04cb, 0x30d2 }, /*                     kana_HI ヒ KATAKANA LETTER HI */
+  { 0x04cc, 0x30d5 }, /*                     kana_FU フ KATAKANA LETTER HU */
+  { 0x04cd, 0x30d8 }, /*                     kana_HE ヘ KATAKANA LETTER HE */
+  { 0x04ce, 0x30db }, /*                     kana_HO ホ KATAKANA LETTER HO */
+  { 0x04cf, 0x30de }, /*                     kana_MA マ KATAKANA LETTER MA */
+  { 0x04d0, 0x30df }, /*                     kana_MI ミ KATAKANA LETTER MI */
+  { 0x04d1, 0x30e0 }, /*                     kana_MU ム KATAKANA LETTER MU */
+  { 0x04d2, 0x30e1 }, /*                     kana_ME メ KATAKANA LETTER ME */
+  { 0x04d3, 0x30e2 }, /*                     kana_MO モ KATAKANA LETTER MO */
+  { 0x04d4, 0x30e4 }, /*                     kana_YA ヤ KATAKANA LETTER YA */
+  { 0x04d5, 0x30e6 }, /*                     kana_YU ユ KATAKANA LETTER YU */
+  { 0x04d6, 0x30e8 }, /*                     kana_YO ヨ KATAKANA LETTER YO */
+  { 0x04d7, 0x30e9 }, /*                     kana_RA ラ KATAKANA LETTER RA */
+  { 0x04d8, 0x30ea }, /*                     kana_RI リ KATAKANA LETTER RI */
+  { 0x04d9, 0x30eb }, /*                     kana_RU ル KATAKANA LETTER RU */
+  { 0x04da, 0x30ec }, /*                     kana_RE レ KATAKANA LETTER RE */
+  { 0x04db, 0x30ed }, /*                     kana_RO ロ KATAKANA LETTER RO */
+  { 0x04dc, 0x30ef }, /*                     kana_WA ワ KATAKANA LETTER WA */
+  { 0x04dd, 0x30f3 }, /*                      kana_N ン KATAKANA LETTER N */
+  { 0x04de, 0x309b }, /*                 voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
+  { 0x04df, 0x309c }, /*             semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+  { 0x05ac, 0x060c }, /*                Arabic_comma ، ARABIC COMMA */
+  { 0x05bb, 0x061b }, /*            Arabic_semicolon ؛ ARABIC SEMICOLON */
+  { 0x05bf, 0x061f }, /*        Arabic_question_mark ؟ ARABIC QUESTION MARK */
+  { 0x05c1, 0x0621 }, /*                Arabic_hamza ء ARABIC LETTER HAMZA */
+  { 0x05c2, 0x0622 }, /*          Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
+  { 0x05c3, 0x0623 }, /*          Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
+  { 0x05c4, 0x0624 }, /*           Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
+  { 0x05c5, 0x0625 }, /*       Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
+  { 0x05c6, 0x0626 }, /*           Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
+  { 0x05c7, 0x0627 }, /*                 Arabic_alef ا ARABIC LETTER ALEF */
+  { 0x05c8, 0x0628 }, /*                  Arabic_beh ب ARABIC LETTER BEH */
+  { 0x05c9, 0x0629 }, /*           Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
+  { 0x05ca, 0x062a }, /*                  Arabic_teh ت ARABIC LETTER TEH */
+  { 0x05cb, 0x062b }, /*                 Arabic_theh ث ARABIC LETTER THEH */
+  { 0x05cc, 0x062c }, /*                 Arabic_jeem ج ARABIC LETTER JEEM */
+  { 0x05cd, 0x062d }, /*                  Arabic_hah ح ARABIC LETTER HAH */
+  { 0x05ce, 0x062e }, /*                 Arabic_khah خ ARABIC LETTER KHAH */
+  { 0x05cf, 0x062f }, /*                  Arabic_dal د ARABIC LETTER DAL */
+  { 0x05d0, 0x0630 }, /*                 Arabic_thal ذ ARABIC LETTER THAL */
+  { 0x05d1, 0x0631 }, /*                   Arabic_ra ر ARABIC LETTER REH */
+  { 0x05d2, 0x0632 }, /*                 Arabic_zain ز ARABIC LETTER ZAIN */
+  { 0x05d3, 0x0633 }, /*                 Arabic_seen س ARABIC LETTER SEEN */
+  { 0x05d4, 0x0634 }, /*                Arabic_sheen ش ARABIC LETTER SHEEN */
+  { 0x05d5, 0x0635 }, /*                  Arabic_sad ص ARABIC LETTER SAD */
+  { 0x05d6, 0x0636 }, /*                  Arabic_dad ض ARABIC LETTER DAD */
+  { 0x05d7, 0x0637 }, /*                  Arabic_tah ط ARABIC LETTER TAH */
+  { 0x05d8, 0x0638 }, /*                  Arabic_zah ظ ARABIC LETTER ZAH */
+  { 0x05d9, 0x0639 }, /*                  Arabic_ain ع ARABIC LETTER AIN */
+  { 0x05da, 0x063a }, /*                Arabic_ghain غ ARABIC LETTER GHAIN */
+  { 0x05e0, 0x0640 }, /*              Arabic_tatweel ـ ARABIC TATWEEL */
+  { 0x05e1, 0x0641 }, /*                  Arabic_feh ف ARABIC LETTER FEH */
+  { 0x05e2, 0x0642 }, /*                  Arabic_qaf ق ARABIC LETTER QAF */
+  { 0x05e3, 0x0643 }, /*                  Arabic_kaf ك ARABIC LETTER KAF */
+  { 0x05e4, 0x0644 }, /*                  Arabic_lam ل ARABIC LETTER LAM */
+  { 0x05e5, 0x0645 }, /*                 Arabic_meem م ARABIC LETTER MEEM */
+  { 0x05e6, 0x0646 }, /*                 Arabic_noon ن ARABIC LETTER NOON */
+  { 0x05e7, 0x0647 }, /*                   Arabic_ha ه ARABIC LETTER HEH */
+  { 0x05e8, 0x0648 }, /*                  Arabic_waw و ARABIC LETTER WAW */
+  { 0x05e9, 0x0649 }, /*          Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
+  { 0x05ea, 0x064a }, /*                  Arabic_yeh ي ARABIC LETTER YEH */
+  { 0x05eb, 0x064b }, /*             Arabic_fathatan ً ARABIC FATHATAN */
+  { 0x05ec, 0x064c }, /*             Arabic_dammatan ٌ ARABIC DAMMATAN */
+  { 0x05ed, 0x064d }, /*             Arabic_kasratan ٍ ARABIC KASRATAN */
+  { 0x05ee, 0x064e }, /*                Arabic_fatha َ ARABIC FATHA */
+  { 0x05ef, 0x064f }, /*                Arabic_damma ُ ARABIC DAMMA */
+  { 0x05f0, 0x0650 }, /*                Arabic_kasra ِ ARABIC KASRA */
+  { 0x05f1, 0x0651 }, /*               Arabic_shadda ّ ARABIC SHADDA */
+  { 0x05f2, 0x0652 }, /*                Arabic_sukun ْ ARABIC SUKUN */
+  { 0x06a1, 0x0452 }, /*                 Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
+  { 0x06a2, 0x0453 }, /*               Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
+  { 0x06a3, 0x0451 }, /*                 Cyrillic_io ё CYRILLIC SMALL LETTER IO */
+  { 0x06a4, 0x0454 }, /*                Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
+  { 0x06a5, 0x0455 }, /*               Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
+  { 0x06a6, 0x0456 }, /*                 Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+  { 0x06a7, 0x0457 }, /*                Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
+  { 0x06a8, 0x0458 }, /*                 Cyrillic_je ј CYRILLIC SMALL LETTER JE */
+  { 0x06a9, 0x0459 }, /*                Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
+  { 0x06aa, 0x045a }, /*                Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
+  { 0x06ab, 0x045b }, /*                Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
+  { 0x06ac, 0x045c }, /*               Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
+  { 0x06ae, 0x045e }, /*         Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
+  { 0x06af, 0x045f }, /*               Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
+  { 0x06b0, 0x2116 }, /*                  numerosign № NUMERO SIGN */
+  { 0x06b1, 0x0402 }, /*                 Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
+  { 0x06b2, 0x0403 }, /*               Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
+  { 0x06b3, 0x0401 }, /*                 Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
+  { 0x06b4, 0x0404 }, /*                Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+  { 0x06b5, 0x0405 }, /*               Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
+  { 0x06b6, 0x0406 }, /*                 Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+  { 0x06b7, 0x0407 }, /*                Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
+  { 0x06b8, 0x0408 }, /*                 Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
+  { 0x06b9, 0x0409 }, /*                Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
+  { 0x06ba, 0x040a }, /*                Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
+  { 0x06bb, 0x040b }, /*                Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
+  { 0x06bc, 0x040c }, /*               Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
+  { 0x06be, 0x040e }, /*         Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
+  { 0x06bf, 0x040f }, /*               Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
+  { 0x06c0, 0x044e }, /*                 Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
+  { 0x06c1, 0x0430 }, /*                  Cyrillic_a а CYRILLIC SMALL LETTER A */
+  { 0x06c2, 0x0431 }, /*                 Cyrillic_be б CYRILLIC SMALL LETTER BE */
+  { 0x06c3, 0x0446 }, /*                Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
+  { 0x06c4, 0x0434 }, /*                 Cyrillic_de д CYRILLIC SMALL LETTER DE */
+  { 0x06c5, 0x0435 }, /*                 Cyrillic_ie е CYRILLIC SMALL LETTER IE */
+  { 0x06c6, 0x0444 }, /*                 Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
+  { 0x06c7, 0x0433 }, /*                Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
+  { 0x06c8, 0x0445 }, /*                 Cyrillic_ha х CYRILLIC SMALL LETTER HA */
+  { 0x06c9, 0x0438 }, /*                  Cyrillic_i и CYRILLIC SMALL LETTER I */
+  { 0x06ca, 0x0439 }, /*             Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
+  { 0x06cb, 0x043a }, /*                 Cyrillic_ka к CYRILLIC SMALL LETTER KA */
+  { 0x06cc, 0x043b }, /*                 Cyrillic_el л CYRILLIC SMALL LETTER EL */
+  { 0x06cd, 0x043c }, /*                 Cyrillic_em м CYRILLIC SMALL LETTER EM */
+  { 0x06ce, 0x043d }, /*                 Cyrillic_en н CYRILLIC SMALL LETTER EN */
+  { 0x06cf, 0x043e }, /*                  Cyrillic_o о CYRILLIC SMALL LETTER O */
+  { 0x06d0, 0x043f }, /*                 Cyrillic_pe п CYRILLIC SMALL LETTER PE */
+  { 0x06d1, 0x044f }, /*                 Cyrillic_ya я CYRILLIC SMALL LETTER YA */
+  { 0x06d2, 0x0440 }, /*                 Cyrillic_er р CYRILLIC SMALL LETTER ER */
+  { 0x06d3, 0x0441 }, /*                 Cyrillic_es с CYRILLIC SMALL LETTER ES */
+  { 0x06d4, 0x0442 }, /*                 Cyrillic_te т CYRILLIC SMALL LETTER TE */
+  { 0x06d5, 0x0443 }, /*                  Cyrillic_u у CYRILLIC SMALL LETTER U */
+  { 0x06d6, 0x0436 }, /*                Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
+  { 0x06d7, 0x0432 }, /*                 Cyrillic_ve в CYRILLIC SMALL LETTER VE */
+  { 0x06d8, 0x044c }, /*           Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
+  { 0x06d9, 0x044b }, /*               Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
+  { 0x06da, 0x0437 }, /*                 Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
+  { 0x06db, 0x0448 }, /*                Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
+  { 0x06dc, 0x044d }, /*                  Cyrillic_e э CYRILLIC SMALL LETTER E */
+  { 0x06dd, 0x0449 }, /*              Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
+  { 0x06de, 0x0447 }, /*                Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
+  { 0x06df, 0x044a }, /*           Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
+  { 0x06e0, 0x042e }, /*                 Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
+  { 0x06e1, 0x0410 }, /*                  Cyrillic_A А CYRILLIC CAPITAL LETTER A */
+  { 0x06e2, 0x0411 }, /*                 Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
+  { 0x06e3, 0x0426 }, /*                Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
+  { 0x06e4, 0x0414 }, /*                 Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
+  { 0x06e5, 0x0415 }, /*                 Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
+  { 0x06e6, 0x0424 }, /*                 Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
+  { 0x06e7, 0x0413 }, /*                Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
+  { 0x06e8, 0x0425 }, /*                 Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
+  { 0x06e9, 0x0418 }, /*                  Cyrillic_I И CYRILLIC CAPITAL LETTER I */
+  { 0x06ea, 0x0419 }, /*             Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
+  { 0x06eb, 0x041a }, /*                 Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
+  { 0x06ec, 0x041b }, /*                 Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
+  { 0x06ed, 0x041c }, /*                 Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
+  { 0x06ee, 0x041d }, /*                 Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
+  { 0x06ef, 0x041e }, /*                  Cyrillic_O О CYRILLIC CAPITAL LETTER O */
+  { 0x06f0, 0x041f }, /*                 Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
+  { 0x06f1, 0x042f }, /*                 Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
+  { 0x06f2, 0x0420 }, /*                 Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
+  { 0x06f3, 0x0421 }, /*                 Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
+  { 0x06f4, 0x0422 }, /*                 Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
+  { 0x06f5, 0x0423 }, /*                  Cyrillic_U У CYRILLIC CAPITAL LETTER U */
+  { 0x06f6, 0x0416 }, /*                Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
+  { 0x06f7, 0x0412 }, /*                 Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
+  { 0x06f8, 0x042c }, /*           Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
+  { 0x06f9, 0x042b }, /*               Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
+  { 0x06fa, 0x0417 }, /*                 Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
+  { 0x06fb, 0x0428 }, /*                Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
+  { 0x06fc, 0x042d }, /*                  Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
+  { 0x06fd, 0x0429 }, /*              Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
+  { 0x06fe, 0x0427 }, /*                Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
+  { 0x06ff, 0x042a }, /*           Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
+  { 0x07a1, 0x0386 }, /*           Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
+  { 0x07a2, 0x0388 }, /*         Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
+  { 0x07a3, 0x0389 }, /*             Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
+  { 0x07a4, 0x038a }, /*            Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
+  { 0x07a5, 0x03aa }, /*         Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+  { 0x07a7, 0x038c }, /*         Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
+  { 0x07a8, 0x038e }, /*         Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
+  { 0x07a9, 0x03ab }, /*       Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+  { 0x07ab, 0x038f }, /*           Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
+  { 0x07ae, 0x0385 }, /*        Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
+  { 0x07af, 0x2015 }, /*              Greek_horizbar ― HORIZONTAL BAR */
+  { 0x07b1, 0x03ac }, /*           Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
+  { 0x07b2, 0x03ad }, /*         Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
+  { 0x07b3, 0x03ae }, /*             Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
+  { 0x07b4, 0x03af }, /*            Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
+  { 0x07b5, 0x03ca }, /*          Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+  { 0x07b6, 0x0390 }, /*    Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+  { 0x07b7, 0x03cc }, /*         Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
+  { 0x07b8, 0x03cd }, /*         Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
+  { 0x07b9, 0x03cb }, /*       Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+  { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+  { 0x07bb, 0x03ce }, /*           Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
+  { 0x07c1, 0x0391 }, /*                 Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
+  { 0x07c2, 0x0392 }, /*                  Greek_BETA Β GREEK CAPITAL LETTER BETA */
+  { 0x07c3, 0x0393 }, /*                 Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
+  { 0x07c4, 0x0394 }, /*                 Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
+  { 0x07c5, 0x0395 }, /*               Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
+  { 0x07c6, 0x0396 }, /*                  Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
+  { 0x07c7, 0x0397 }, /*                   Greek_ETA Η GREEK CAPITAL LETTER ETA */
+  { 0x07c8, 0x0398 }, /*                 Greek_THETA Θ GREEK CAPITAL LETTER THETA */
+  { 0x07c9, 0x0399 }, /*                  Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
+  { 0x07ca, 0x039a }, /*                 Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
+  { 0x07cb, 0x039b }, /*                Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
+  { 0x07cc, 0x039c }, /*                    Greek_MU Μ GREEK CAPITAL LETTER MU */
+  { 0x07cd, 0x039d }, /*                    Greek_NU Ν GREEK CAPITAL LETTER NU */
+  { 0x07ce, 0x039e }, /*                    Greek_XI Ξ GREEK CAPITAL LETTER XI */
+  { 0x07cf, 0x039f }, /*               Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
+  { 0x07d0, 0x03a0 }, /*                    Greek_PI Π GREEK CAPITAL LETTER PI */
+  { 0x07d1, 0x03a1 }, /*                   Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
+  { 0x07d2, 0x03a3 }, /*                 Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
+  { 0x07d4, 0x03a4 }, /*                   Greek_TAU Τ GREEK CAPITAL LETTER TAU */
+  { 0x07d5, 0x03a5 }, /*               Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
+  { 0x07d6, 0x03a6 }, /*                   Greek_PHI Φ GREEK CAPITAL LETTER PHI */
+  { 0x07d7, 0x03a7 }, /*                   Greek_CHI Χ GREEK CAPITAL LETTER CHI */
+  { 0x07d8, 0x03a8 }, /*                   Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
+  { 0x07d9, 0x03a9 }, /*                 Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
+  { 0x07e1, 0x03b1 }, /*                 Greek_alpha α GREEK SMALL LETTER ALPHA */
+  { 0x07e2, 0x03b2 }, /*                  Greek_beta β GREEK SMALL LETTER BETA */
+  { 0x07e3, 0x03b3 }, /*                 Greek_gamma γ GREEK SMALL LETTER GAMMA */
+  { 0x07e4, 0x03b4 }, /*                 Greek_delta δ GREEK SMALL LETTER DELTA */
+  { 0x07e5, 0x03b5 }, /*               Greek_epsilon ε GREEK SMALL LETTER EPSILON */
+  { 0x07e6, 0x03b6 }, /*                  Greek_zeta ζ GREEK SMALL LETTER ZETA */
+  { 0x07e7, 0x03b7 }, /*                   Greek_eta η GREEK SMALL LETTER ETA */
+  { 0x07e8, 0x03b8 }, /*                 Greek_theta θ GREEK SMALL LETTER THETA */
+  { 0x07e9, 0x03b9 }, /*                  Greek_iota ι GREEK SMALL LETTER IOTA */
+  { 0x07ea, 0x03ba }, /*                 Greek_kappa κ GREEK SMALL LETTER KAPPA */
+  { 0x07eb, 0x03bb }, /*                Greek_lambda λ GREEK SMALL LETTER LAMDA */
+  { 0x07ec, 0x03bc }, /*                    Greek_mu μ GREEK SMALL LETTER MU */
+  { 0x07ed, 0x03bd }, /*                    Greek_nu ν GREEK SMALL LETTER NU */
+  { 0x07ee, 0x03be }, /*                    Greek_xi ξ GREEK SMALL LETTER XI */
+  { 0x07ef, 0x03bf }, /*               Greek_omicron ο GREEK SMALL LETTER OMICRON */
+  { 0x07f0, 0x03c0 }, /*                    Greek_pi π GREEK SMALL LETTER PI */
+  { 0x07f1, 0x03c1 }, /*                   Greek_rho ρ GREEK SMALL LETTER RHO */
+  { 0x07f2, 0x03c3 }, /*                 Greek_sigma σ GREEK SMALL LETTER SIGMA */
+  { 0x07f3, 0x03c2 }, /*       Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
+  { 0x07f4, 0x03c4 }, /*                   Greek_tau τ GREEK SMALL LETTER TAU */
+  { 0x07f5, 0x03c5 }, /*               Greek_upsilon υ GREEK SMALL LETTER UPSILON */
+  { 0x07f6, 0x03c6 }, /*                   Greek_phi φ GREEK SMALL LETTER PHI */
+  { 0x07f7, 0x03c7 }, /*                   Greek_chi χ GREEK SMALL LETTER CHI */
+  { 0x07f8, 0x03c8 }, /*                   Greek_psi ψ GREEK SMALL LETTER PSI */
+  { 0x07f9, 0x03c9 }, /*                 Greek_omega ω GREEK SMALL LETTER OMEGA */
+  { 0x08a1, 0x23b7 }, /*                 leftradical ⎷ ??? */
+  { 0x08a2, 0x250c }, /*              topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
+  { 0x08a3, 0x2500 }, /*              horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
+  { 0x08a4, 0x2320 }, /*                 topintegral ⌠ TOP HALF INTEGRAL */
+  { 0x08a5, 0x2321 }, /*                 botintegral ⌡ BOTTOM HALF INTEGRAL */
+  { 0x08a6, 0x2502 }, /*               vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
+  { 0x08a7, 0x23a1 }, /*            topleftsqbracket ⎡ ??? */
+  { 0x08a8, 0x23a3 }, /*            botleftsqbracket ⎣ ??? */
+  { 0x08a9, 0x23a4 }, /*           toprightsqbracket ⎤ ??? */
+  { 0x08aa, 0x23a6 }, /*           botrightsqbracket ⎦ ??? */
+  { 0x08ab, 0x239b }, /*               topleftparens ⎛ ??? */
+  { 0x08ac, 0x239d }, /*               botleftparens ⎝ ??? */
+  { 0x08ad, 0x239e }, /*              toprightparens ⎞ ??? */
+  { 0x08ae, 0x23a0 }, /*              botrightparens ⎠ ??? */
+  { 0x08af, 0x23a8 }, /*        leftmiddlecurlybrace ⎨ ??? */
+  { 0x08b0, 0x23ac }, /*       rightmiddlecurlybrace ⎬ ??? */
+/*  0x08b1                          topleftsummation ? ??? */
+/*  0x08b2                          botleftsummation ? ??? */
+/*  0x08b3                 topvertsummationconnector ? ??? */
+/*  0x08b4                 botvertsummationconnector ? ??? */
+/*  0x08b5                         toprightsummation ? ??? */
+/*  0x08b6                         botrightsummation ? ??? */
+/*  0x08b7                      rightmiddlesummation ? ??? */
+  { 0x08bc, 0x2264 }, /*               lessthanequal ≤ LESS-THAN OR EQUAL TO */
+  { 0x08bd, 0x2260 }, /*                    notequal ≠ NOT EQUAL TO */
+  { 0x08be, 0x2265 }, /*            greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
+  { 0x08bf, 0x222b }, /*                    integral ∫ INTEGRAL */
+  { 0x08c0, 0x2234 }, /*                   therefore ∴ THEREFORE */
+  { 0x08c1, 0x221d }, /*                   variation ∝ PROPORTIONAL TO */
+  { 0x08c2, 0x221e }, /*                    infinity ∞ INFINITY */
+  { 0x08c5, 0x2207 }, /*                       nabla ∇ NABLA */
+  { 0x08c8, 0x223c }, /*                 approximate ∼ TILDE OPERATOR */
+  { 0x08c9, 0x2243 }, /*                similarequal ≃ ASYMPTOTICALLY EQUAL TO */
+  { 0x08cd, 0x21d4 }, /*                    ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
+  { 0x08ce, 0x21d2 }, /*                     implies ⇒ RIGHTWARDS DOUBLE ARROW */
+  { 0x08cf, 0x2261 }, /*                   identical ≡ IDENTICAL TO */
+  { 0x08d6, 0x221a }, /*                     radical √ SQUARE ROOT */
+  { 0x08da, 0x2282 }, /*                  includedin ⊂ SUBSET OF */
+  { 0x08db, 0x2283 }, /*                    includes ⊃ SUPERSET OF */
+  { 0x08dc, 0x2229 }, /*                intersection ∩ INTERSECTION */
+  { 0x08dd, 0x222a }, /*                       union ∪ UNION */
+  { 0x08de, 0x2227 }, /*                  logicaland ∧ LOGICAL AND */
+  { 0x08df, 0x2228 }, /*                   logicalor ∨ LOGICAL OR */
+  { 0x08ef, 0x2202 }, /*           partialderivative ∂ PARTIAL DIFFERENTIAL */
+  { 0x08f6, 0x0192 }, /*                    function ƒ LATIN SMALL LETTER F WITH HOOK */
+  { 0x08fb, 0x2190 }, /*                   leftarrow ← LEFTWARDS ARROW */
+  { 0x08fc, 0x2191 }, /*                     uparrow ↑ UPWARDS ARROW */
+  { 0x08fd, 0x2192 }, /*                  rightarrow → RIGHTWARDS ARROW */
+  { 0x08fe, 0x2193 }, /*                   downarrow ↓ DOWNWARDS ARROW */
+/*  0x09df                                     blank ? ??? */
+  { 0x09e0, 0x25c6 }, /*                soliddiamond ◆ BLACK DIAMOND */
+  { 0x09e1, 0x2592 }, /*                checkerboard ▒ MEDIUM SHADE */
+  { 0x09e2, 0x2409 }, /*                          ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
+  { 0x09e3, 0x240c }, /*                          ff ␌ SYMBOL FOR FORM FEED */
+  { 0x09e4, 0x240d }, /*                          cr ␍ SYMBOL FOR CARRIAGE RETURN */
+  { 0x09e5, 0x240a }, /*                          lf ␊ SYMBOL FOR LINE FEED */
+  { 0x09e8, 0x2424 }, /*                          nl ␤ SYMBOL FOR NEWLINE */
+  { 0x09e9, 0x240b }, /*                          vt ␋ SYMBOL FOR VERTICAL TABULATION */
+  { 0x09ea, 0x2518 }, /*              lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
+  { 0x09eb, 0x2510 }, /*               uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
+  { 0x09ec, 0x250c }, /*                upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
+  { 0x09ed, 0x2514 }, /*               lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
+  { 0x09ee, 0x253c }, /*               crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+  { 0x09ef, 0x23ba }, /*              horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
+  { 0x09f0, 0x23bb }, /*              horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
+  { 0x09f1, 0x2500 }, /*              horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
+  { 0x09f2, 0x23bc }, /*              horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
+  { 0x09f3, 0x23bd }, /*              horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
+  { 0x09f4, 0x251c }, /*                       leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+  { 0x09f5, 0x2524 }, /*                      rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+  { 0x09f6, 0x2534 }, /*                        bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+  { 0x09f7, 0x252c }, /*                        topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+  { 0x09f8, 0x2502 }, /*                     vertbar │ BOX DRAWINGS LIGHT VERTICAL */
+  { 0x0aa1, 0x2003 }, /*                     emspace   EM SPACE */
+  { 0x0aa2, 0x2002 }, /*                     enspace   EN SPACE */
+  { 0x0aa3, 0x2004 }, /*                    em3space   THREE-PER-EM SPACE */
+  { 0x0aa4, 0x2005 }, /*                    em4space   FOUR-PER-EM SPACE */
+  { 0x0aa5, 0x2007 }, /*                  digitspace   FIGURE SPACE */
+  { 0x0aa6, 0x2008 }, /*                  punctspace   PUNCTUATION SPACE */
+  { 0x0aa7, 0x2009 }, /*                   thinspace   THIN SPACE */
+  { 0x0aa8, 0x200a }, /*                   hairspace   HAIR SPACE */
+  { 0x0aa9, 0x2014 }, /*                      emdash — EM DASH */
+  { 0x0aaa, 0x2013 }, /*                      endash – EN DASH */
+/*  0x0aac                               signifblank ? ??? */
+  { 0x0aae, 0x2026 }, /*                    ellipsis … HORIZONTAL ELLIPSIS */
+  { 0x0aaf, 0x2025 }, /*             doubbaselinedot ‥ TWO DOT LEADER */
+  { 0x0ab0, 0x2153 }, /*                    onethird ⅓ VULGAR FRACTION ONE THIRD */
+  { 0x0ab1, 0x2154 }, /*                   twothirds ⅔ VULGAR FRACTION TWO THIRDS */
+  { 0x0ab2, 0x2155 }, /*                    onefifth ⅕ VULGAR FRACTION ONE FIFTH */
+  { 0x0ab3, 0x2156 }, /*                   twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
+  { 0x0ab4, 0x2157 }, /*                 threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
+  { 0x0ab5, 0x2158 }, /*                  fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
+  { 0x0ab6, 0x2159 }, /*                    onesixth ⅙ VULGAR FRACTION ONE SIXTH */
+  { 0x0ab7, 0x215a }, /*                  fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
+  { 0x0ab8, 0x2105 }, /*                      careof ℅ CARE OF */
+  { 0x0abb, 0x2012 }, /*                     figdash ‒ FIGURE DASH */
+  { 0x0abc, 0x2329 }, /*            leftanglebracket ⟨ LEFT-POINTING ANGLE BRACKET */
+/*  0x0abd                              decimalpoint ? ??? */
+  { 0x0abe, 0x232a }, /*           rightanglebracket ⟩ RIGHT-POINTING ANGLE BRACKET */
+/*  0x0abf                                    marker ? ??? */
+  { 0x0ac3, 0x215b }, /*                   oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
+  { 0x0ac4, 0x215c }, /*                threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
+  { 0x0ac5, 0x215d }, /*                 fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
+  { 0x0ac6, 0x215e }, /*                seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
+  { 0x0ac9, 0x2122 }, /*                   trademark ™ TRADE MARK SIGN */
+  { 0x0aca, 0x2613 }, /*               signaturemark ☓ SALTIRE */
+/*  0x0acb                         trademarkincircle ? ??? */
+  { 0x0acc, 0x25c1 }, /*            leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
+  { 0x0acd, 0x25b7 }, /*           rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
+  { 0x0ace, 0x25cb }, /*                emopencircle ○ WHITE CIRCLE */
+  { 0x0acf, 0x25af }, /*             emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
+  { 0x0ad0, 0x2018 }, /*         leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */
+  { 0x0ad1, 0x2019 }, /*        rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */
+  { 0x0ad2, 0x201c }, /*         leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
+  { 0x0ad3, 0x201d }, /*        rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
+  { 0x0ad4, 0x211e }, /*                prescription ℞ PRESCRIPTION TAKE */
+  { 0x0ad6, 0x2032 }, /*                     minutes ′ PRIME */
+  { 0x0ad7, 0x2033 }, /*                     seconds ″ DOUBLE PRIME */
+  { 0x0ad9, 0x271d }, /*                  latincross ✝ LATIN CROSS */
+/*  0x0ada                                  hexagram ? ??? */
+  { 0x0adb, 0x25ac }, /*            filledrectbullet ▬ BLACK RECTANGLE */
+  { 0x0adc, 0x25c0 }, /*         filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
+  { 0x0add, 0x25b6 }, /*        filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
+  { 0x0ade, 0x25cf }, /*              emfilledcircle ● BLACK CIRCLE */
+  { 0x0adf, 0x25ae }, /*                emfilledrect ▮ BLACK VERTICAL RECTANGLE */
+  { 0x0ae0, 0x25e6 }, /*            enopencircbullet ◦ WHITE BULLET */
+  { 0x0ae1, 0x25ab }, /*          enopensquarebullet ▫ WHITE SMALL SQUARE */
+  { 0x0ae2, 0x25ad }, /*              openrectbullet ▭ WHITE RECTANGLE */
+  { 0x0ae3, 0x25b3 }, /*             opentribulletup △ WHITE UP-POINTING TRIANGLE */
+  { 0x0ae4, 0x25bd }, /*           opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
+  { 0x0ae5, 0x2606 }, /*                    openstar ☆ WHITE STAR */
+  { 0x0ae6, 0x2022 }, /*          enfilledcircbullet • BULLET */
+  { 0x0ae7, 0x25aa }, /*            enfilledsqbullet ▪ BLACK SMALL SQUARE */
+  { 0x0ae8, 0x25b2 }, /*           filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
+  { 0x0ae9, 0x25bc }, /*         filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
+  { 0x0aea, 0x261c }, /*                 leftpointer ☜ WHITE LEFT POINTING INDEX */
+  { 0x0aeb, 0x261e }, /*                rightpointer ☞ WHITE RIGHT POINTING INDEX */
+  { 0x0aec, 0x2663 }, /*                        club ♣ BLACK CLUB SUIT */
+  { 0x0aed, 0x2666 }, /*                     diamond ♦ BLACK DIAMOND SUIT */
+  { 0x0aee, 0x2665 }, /*                       heart ♥ BLACK HEART SUIT */
+  { 0x0af0, 0x2720 }, /*                maltesecross ✠ MALTESE CROSS */
+  { 0x0af1, 0x2020 }, /*                      dagger † DAGGER */
+  { 0x0af2, 0x2021 }, /*                doubledagger ‡ DOUBLE DAGGER */
+  { 0x0af3, 0x2713 }, /*                   checkmark ✓ CHECK MARK */
+  { 0x0af4, 0x2717 }, /*                 ballotcross ✗ BALLOT X */
+  { 0x0af5, 0x266f }, /*                musicalsharp ♯ MUSIC SHARP SIGN */
+  { 0x0af6, 0x266d }, /*                 musicalflat ♭ MUSIC FLAT SIGN */
+  { 0x0af7, 0x2642 }, /*                  malesymbol ♂ MALE SIGN */
+  { 0x0af8, 0x2640 }, /*                femalesymbol ♀ FEMALE SIGN */
+  { 0x0af9, 0x260e }, /*                   telephone ☎ BLACK TELEPHONE */
+  { 0x0afa, 0x2315 }, /*           telephonerecorder ⌕ TELEPHONE RECORDER */
+  { 0x0afb, 0x2117 }, /*         phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
+  { 0x0afc, 0x2038 }, /*                       caret ‸ CARET */
+  { 0x0afd, 0x201a }, /*          singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */
+  { 0x0afe, 0x201e }, /*          doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
+/*  0x0aff                                    cursor ? ??? */
+  { 0x0ba3, 0x003c }, /*                   leftcaret < LESS-THAN SIGN */
+  { 0x0ba6, 0x003e }, /*                  rightcaret > GREATER-THAN SIGN */
+  { 0x0ba8, 0x2228 }, /*                   downcaret ∨ LOGICAL OR */
+  { 0x0ba9, 0x2227 }, /*                     upcaret ∧ LOGICAL AND */
+  { 0x0bc0, 0x00af }, /*                     overbar ¯ MACRON */
+  { 0x0bc2, 0x22a5 }, /*                    downtack ⊥ UP TACK */
+  { 0x0bc3, 0x2229 }, /*                      upshoe ∩ INTERSECTION */
+  { 0x0bc4, 0x230a }, /*                   downstile ⌊ LEFT FLOOR */
+  { 0x0bc6, 0x005f }, /*                    underbar _ LOW LINE */
+  { 0x0bca, 0x2218 }, /*                         jot ∘ RING OPERATOR */
+  { 0x0bcc, 0x2395 }, /*                        quad ⎕ APL FUNCTIONAL SYMBOL QUAD */
+  { 0x0bce, 0x22a4 }, /*                      uptack ⊤ DOWN TACK */
+  { 0x0bcf, 0x25cb }, /*                      circle ○ WHITE CIRCLE */
+  { 0x0bd3, 0x2308 }, /*                     upstile ⌈ LEFT CEILING */
+  { 0x0bd6, 0x222a }, /*                    downshoe ∪ UNION */
+  { 0x0bd8, 0x2283 }, /*                   rightshoe ⊃ SUPERSET OF */
+  { 0x0bda, 0x2282 }, /*                    leftshoe ⊂ SUBSET OF */
+  { 0x0bdc, 0x22a2 }, /*                    lefttack ⊢ RIGHT TACK */
+  { 0x0bfc, 0x22a3 }, /*                   righttack ⊣ LEFT TACK */
+  { 0x0cdf, 0x2017 }, /*        hebrew_doublelowline ‗ DOUBLE LOW LINE */
+  { 0x0ce0, 0x05d0 }, /*                hebrew_aleph א HEBREW LETTER ALEF */
+  { 0x0ce1, 0x05d1 }, /*                  hebrew_bet ב HEBREW LETTER BET */
+  { 0x0ce2, 0x05d2 }, /*                hebrew_gimel ג HEBREW LETTER GIMEL */
+  { 0x0ce3, 0x05d3 }, /*                hebrew_dalet ד HEBREW LETTER DALET */
+  { 0x0ce4, 0x05d4 }, /*                   hebrew_he ה HEBREW LETTER HE */
+  { 0x0ce5, 0x05d5 }, /*                  hebrew_waw ו HEBREW LETTER VAV */
+  { 0x0ce6, 0x05d6 }, /*                 hebrew_zain ז HEBREW LETTER ZAYIN */
+  { 0x0ce7, 0x05d7 }, /*                 hebrew_chet ח HEBREW LETTER HET */
+  { 0x0ce8, 0x05d8 }, /*                  hebrew_tet ט HEBREW LETTER TET */
+  { 0x0ce9, 0x05d9 }, /*                  hebrew_yod י HEBREW LETTER YOD */
+  { 0x0cea, 0x05da }, /*            hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
+  { 0x0ceb, 0x05db }, /*                 hebrew_kaph כ HEBREW LETTER KAF */
+  { 0x0cec, 0x05dc }, /*                hebrew_lamed ל HEBREW LETTER LAMED */
+  { 0x0ced, 0x05dd }, /*             hebrew_finalmem ם HEBREW LETTER FINAL MEM */
+  { 0x0cee, 0x05de }, /*                  hebrew_mem מ HEBREW LETTER MEM */
+  { 0x0cef, 0x05df }, /*             hebrew_finalnun ן HEBREW LETTER FINAL NUN */
+  { 0x0cf0, 0x05e0 }, /*                  hebrew_nun נ HEBREW LETTER NUN */
+  { 0x0cf1, 0x05e1 }, /*               hebrew_samech ס HEBREW LETTER SAMEKH */
+  { 0x0cf2, 0x05e2 }, /*                 hebrew_ayin ע HEBREW LETTER AYIN */
+  { 0x0cf3, 0x05e3 }, /*              hebrew_finalpe ף HEBREW LETTER FINAL PE */
+  { 0x0cf4, 0x05e4 }, /*                   hebrew_pe פ HEBREW LETTER PE */
+  { 0x0cf5, 0x05e5 }, /*            hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
+  { 0x0cf6, 0x05e6 }, /*                 hebrew_zade צ HEBREW LETTER TSADI */
+  { 0x0cf7, 0x05e7 }, /*                 hebrew_qoph ק HEBREW LETTER QOF */
+  { 0x0cf8, 0x05e8 }, /*                 hebrew_resh ר HEBREW LETTER RESH */
+  { 0x0cf9, 0x05e9 }, /*                 hebrew_shin ש HEBREW LETTER SHIN */
+  { 0x0cfa, 0x05ea }, /*                  hebrew_taw ת HEBREW LETTER TAV */
+  { 0x0da1, 0x0e01 }, /*                  Thai_kokai ก THAI CHARACTER KO KAI */
+  { 0x0da2, 0x0e02 }, /*                Thai_khokhai ข THAI CHARACTER KHO KHAI */
+  { 0x0da3, 0x0e03 }, /*               Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
+  { 0x0da4, 0x0e04 }, /*               Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
+  { 0x0da5, 0x0e05 }, /*                Thai_khokhon ฅ THAI CHARACTER KHO KHON */
+  { 0x0da6, 0x0e06 }, /*             Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
+  { 0x0da7, 0x0e07 }, /*                 Thai_ngongu ง THAI CHARACTER NGO NGU */
+  { 0x0da8, 0x0e08 }, /*                Thai_chochan จ THAI CHARACTER CHO CHAN */
+  { 0x0da9, 0x0e09 }, /*               Thai_choching ฉ THAI CHARACTER CHO CHING */
+  { 0x0daa, 0x0e0a }, /*               Thai_chochang ช THAI CHARACTER CHO CHANG */
+  { 0x0dab, 0x0e0b }, /*                   Thai_soso ซ THAI CHARACTER SO SO */
+  { 0x0dac, 0x0e0c }, /*                Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
+  { 0x0dad, 0x0e0d }, /*                 Thai_yoying ญ THAI CHARACTER YO YING */
+  { 0x0dae, 0x0e0e }, /*                Thai_dochada ฎ THAI CHARACTER DO CHADA */
+  { 0x0daf, 0x0e0f }, /*                Thai_topatak ฏ THAI CHARACTER TO PATAK */
+  { 0x0db0, 0x0e10 }, /*                Thai_thothan ฐ THAI CHARACTER THO THAN */
+  { 0x0db1, 0x0e11 }, /*          Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
+  { 0x0db2, 0x0e12 }, /*             Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
+  { 0x0db3, 0x0e13 }, /*                  Thai_nonen ณ THAI CHARACTER NO NEN */
+  { 0x0db4, 0x0e14 }, /*                  Thai_dodek ด THAI CHARACTER DO DEK */
+  { 0x0db5, 0x0e15 }, /*                  Thai_totao ต THAI CHARACTER TO TAO */
+  { 0x0db6, 0x0e16 }, /*               Thai_thothung ถ THAI CHARACTER THO THUNG */
+  { 0x0db7, 0x0e17 }, /*              Thai_thothahan ท THAI CHARACTER THO THAHAN */
+  { 0x0db8, 0x0e18 }, /*               Thai_thothong ธ THAI CHARACTER THO THONG */
+  { 0x0db9, 0x0e19 }, /*                   Thai_nonu น THAI CHARACTER NO NU */
+  { 0x0dba, 0x0e1a }, /*               Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
+  { 0x0dbb, 0x0e1b }, /*                  Thai_popla ป THAI CHARACTER PO PLA */
+  { 0x0dbc, 0x0e1c }, /*               Thai_phophung ผ THAI CHARACTER PHO PHUNG */
+  { 0x0dbd, 0x0e1d }, /*                   Thai_fofa ฝ THAI CHARACTER FO FA */
+  { 0x0dbe, 0x0e1e }, /*                Thai_phophan พ THAI CHARACTER PHO PHAN */
+  { 0x0dbf, 0x0e1f }, /*                  Thai_fofan ฟ THAI CHARACTER FO FAN */
+  { 0x0dc0, 0x0e20 }, /*             Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
+  { 0x0dc1, 0x0e21 }, /*                   Thai_moma ม THAI CHARACTER MO MA */
+  { 0x0dc2, 0x0e22 }, /*                  Thai_yoyak ย THAI CHARACTER YO YAK */
+  { 0x0dc3, 0x0e23 }, /*                  Thai_rorua ร THAI CHARACTER RO RUA */
+  { 0x0dc4, 0x0e24 }, /*                     Thai_ru ฤ THAI CHARACTER RU */
+  { 0x0dc5, 0x0e25 }, /*                 Thai_loling ล THAI CHARACTER LO LING */
+  { 0x0dc6, 0x0e26 }, /*                     Thai_lu ฦ THAI CHARACTER LU */
+  { 0x0dc7, 0x0e27 }, /*                 Thai_wowaen ว THAI CHARACTER WO WAEN */
+  { 0x0dc8, 0x0e28 }, /*                 Thai_sosala ศ THAI CHARACTER SO SALA */
+  { 0x0dc9, 0x0e29 }, /*                 Thai_sorusi ษ THAI CHARACTER SO RUSI */
+  { 0x0dca, 0x0e2a }, /*                  Thai_sosua ส THAI CHARACTER SO SUA */
+  { 0x0dcb, 0x0e2b }, /*                  Thai_hohip ห THAI CHARACTER HO HIP */
+  { 0x0dcc, 0x0e2c }, /*                Thai_lochula ฬ THAI CHARACTER LO CHULA */
+  { 0x0dcd, 0x0e2d }, /*                   Thai_oang อ THAI CHARACTER O ANG */
+  { 0x0dce, 0x0e2e }, /*               Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
+  { 0x0dcf, 0x0e2f }, /*              Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
+  { 0x0dd0, 0x0e30 }, /*                  Thai_saraa ะ THAI CHARACTER SARA A */
+  { 0x0dd1, 0x0e31 }, /*             Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
+  { 0x0dd2, 0x0e32 }, /*                 Thai_saraaa า THAI CHARACTER SARA AA */
+  { 0x0dd3, 0x0e33 }, /*                 Thai_saraam ำ THAI CHARACTER SARA AM */
+  { 0x0dd4, 0x0e34 }, /*                  Thai_sarai ิ THAI CHARACTER SARA I */
+  { 0x0dd5, 0x0e35 }, /*                 Thai_saraii ี THAI CHARACTER SARA II */
+  { 0x0dd6, 0x0e36 }, /*                 Thai_saraue ึ THAI CHARACTER SARA UE */
+  { 0x0dd7, 0x0e37 }, /*                Thai_sarauee ื THAI CHARACTER SARA UEE */
+  { 0x0dd8, 0x0e38 }, /*                  Thai_sarau ุ THAI CHARACTER SARA U */
+  { 0x0dd9, 0x0e39 }, /*                 Thai_sarauu ู THAI CHARACTER SARA UU */
+  { 0x0dda, 0x0e3a }, /*                Thai_phinthu ฺ THAI CHARACTER PHINTHU */
+/*  0x0dde                    Thai_maihanakat_maitho ? ??? */
+  { 0x0ddf, 0x0e3f }, /*                   Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
+  { 0x0de0, 0x0e40 }, /*                  Thai_sarae เ THAI CHARACTER SARA E */
+  { 0x0de1, 0x0e41 }, /*                 Thai_saraae แ THAI CHARACTER SARA AE */
+  { 0x0de2, 0x0e42 }, /*                  Thai_sarao โ THAI CHARACTER SARA O */
+  { 0x0de3, 0x0e43 }, /*          Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
+  { 0x0de4, 0x0e44 }, /*         Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
+  { 0x0de5, 0x0e45 }, /*            Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
+  { 0x0de6, 0x0e46 }, /*               Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
+  { 0x0de7, 0x0e47 }, /*              Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
+  { 0x0de8, 0x0e48 }, /*                  Thai_maiek ่ THAI CHARACTER MAI EK */
+  { 0x0de9, 0x0e49 }, /*                 Thai_maitho ้ THAI CHARACTER MAI THO */
+  { 0x0dea, 0x0e4a }, /*                 Thai_maitri ๊ THAI CHARACTER MAI TRI */
+  { 0x0deb, 0x0e4b }, /*            Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
+  { 0x0dec, 0x0e4c }, /*            Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
+  { 0x0ded, 0x0e4d }, /*               Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
+  { 0x0df0, 0x0e50 }, /*                 Thai_leksun ๐ THAI DIGIT ZERO */
+  { 0x0df1, 0x0e51 }, /*                Thai_leknung ๑ THAI DIGIT ONE */
+  { 0x0df2, 0x0e52 }, /*                Thai_leksong ๒ THAI DIGIT TWO */
+  { 0x0df3, 0x0e53 }, /*                 Thai_leksam ๓ THAI DIGIT THREE */
+  { 0x0df4, 0x0e54 }, /*                  Thai_leksi ๔ THAI DIGIT FOUR */
+  { 0x0df5, 0x0e55 }, /*                  Thai_lekha ๕ THAI DIGIT FIVE */
+  { 0x0df6, 0x0e56 }, /*                 Thai_lekhok ๖ THAI DIGIT SIX */
+  { 0x0df7, 0x0e57 }, /*                Thai_lekchet ๗ THAI DIGIT SEVEN */
+  { 0x0df8, 0x0e58 }, /*                Thai_lekpaet ๘ THAI DIGIT EIGHT */
+  { 0x0df9, 0x0e59 }, /*                 Thai_lekkao ๙ THAI DIGIT NINE */
+  { 0x0ea1, 0x3131 }, /*               Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
+  { 0x0ea2, 0x3132 }, /*          Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
+  { 0x0ea3, 0x3133 }, /*           Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
+  { 0x0ea4, 0x3134 }, /*                Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
+  { 0x0ea5, 0x3135 }, /*           Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
+  { 0x0ea6, 0x3136 }, /*           Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
+  { 0x0ea7, 0x3137 }, /*               Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
+  { 0x0ea8, 0x3138 }, /*          Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
+  { 0x0ea9, 0x3139 }, /*                Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
+  { 0x0eaa, 0x313a }, /*          Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
+  { 0x0eab, 0x313b }, /*           Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
+  { 0x0eac, 0x313c }, /*           Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
+  { 0x0ead, 0x313d }, /*            Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
+  { 0x0eae, 0x313e }, /*           Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
+  { 0x0eaf, 0x313f }, /*          Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
+  { 0x0eb0, 0x3140 }, /*           Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
+  { 0x0eb1, 0x3141 }, /*                Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
+  { 0x0eb2, 0x3142 }, /*                Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
+  { 0x0eb3, 0x3143 }, /*           Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
+  { 0x0eb4, 0x3144 }, /*            Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
+  { 0x0eb5, 0x3145 }, /*                 Hangul_Sios ㅅ HANGUL LETTER SIOS */
+  { 0x0eb6, 0x3146 }, /*            Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
+  { 0x0eb7, 0x3147 }, /*                Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
+  { 0x0eb8, 0x3148 }, /*                Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
+  { 0x0eb9, 0x3149 }, /*           Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
+  { 0x0eba, 0x314a }, /*                Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
+  { 0x0ebb, 0x314b }, /*               Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
+  { 0x0ebc, 0x314c }, /*                Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
+  { 0x0ebd, 0x314d }, /*               Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
+  { 0x0ebe, 0x314e }, /*                Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
+  { 0x0ebf, 0x314f }, /*                    Hangul_A ㅏ HANGUL LETTER A */
+  { 0x0ec0, 0x3150 }, /*                   Hangul_AE ㅐ HANGUL LETTER AE */
+  { 0x0ec1, 0x3151 }, /*                   Hangul_YA ㅑ HANGUL LETTER YA */
+  { 0x0ec2, 0x3152 }, /*                  Hangul_YAE ㅒ HANGUL LETTER YAE */
+  { 0x0ec3, 0x3153 }, /*                   Hangul_EO ㅓ HANGUL LETTER EO */
+  { 0x0ec4, 0x3154 }, /*                    Hangul_E ㅔ HANGUL LETTER E */
+  { 0x0ec5, 0x3155 }, /*                  Hangul_YEO ㅕ HANGUL LETTER YEO */
+  { 0x0ec6, 0x3156 }, /*                   Hangul_YE ㅖ HANGUL LETTER YE */
+  { 0x0ec7, 0x3157 }, /*                    Hangul_O ㅗ HANGUL LETTER O */
+  { 0x0ec8, 0x3158 }, /*                   Hangul_WA ㅘ HANGUL LETTER WA */
+  { 0x0ec9, 0x3159 }, /*                  Hangul_WAE ㅙ HANGUL LETTER WAE */
+  { 0x0eca, 0x315a }, /*                   Hangul_OE ㅚ HANGUL LETTER OE */
+  { 0x0ecb, 0x315b }, /*                   Hangul_YO ㅛ HANGUL LETTER YO */
+  { 0x0ecc, 0x315c }, /*                    Hangul_U ㅜ HANGUL LETTER U */
+  { 0x0ecd, 0x315d }, /*                  Hangul_WEO ㅝ HANGUL LETTER WEO */
+  { 0x0ece, 0x315e }, /*                   Hangul_WE ㅞ HANGUL LETTER WE */
+  { 0x0ecf, 0x315f }, /*                   Hangul_WI ㅟ HANGUL LETTER WI */
+  { 0x0ed0, 0x3160 }, /*                   Hangul_YU ㅠ HANGUL LETTER YU */
+  { 0x0ed1, 0x3161 }, /*                   Hangul_EU ㅡ HANGUL LETTER EU */
+  { 0x0ed2, 0x3162 }, /*                   Hangul_YI ㅢ HANGUL LETTER YI */
+  { 0x0ed3, 0x3163 }, /*                    Hangul_I ㅣ HANGUL LETTER I */
+  { 0x0ed4, 0x11a8 }, /*             Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
+  { 0x0ed5, 0x11a9 }, /*        Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
+  { 0x0ed6, 0x11aa }, /*         Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
+  { 0x0ed7, 0x11ab }, /*              Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
+  { 0x0ed8, 0x11ac }, /*         Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
+  { 0x0ed9, 0x11ad }, /*         Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
+  { 0x0eda, 0x11ae }, /*             Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
+  { 0x0edb, 0x11af }, /*              Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
+  { 0x0edc, 0x11b0 }, /*        Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
+  { 0x0edd, 0x11b1 }, /*         Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
+  { 0x0ede, 0x11b2 }, /*         Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
+  { 0x0edf, 0x11b3 }, /*          Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
+  { 0x0ee0, 0x11b4 }, /*         Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
+  { 0x0ee1, 0x11b5 }, /*        Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
+  { 0x0ee2, 0x11b6 }, /*         Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
+  { 0x0ee3, 0x11b7 }, /*              Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
+  { 0x0ee4, 0x11b8 }, /*              Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
+  { 0x0ee5, 0x11b9 }, /*          Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
+  { 0x0ee6, 0x11ba }, /*               Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
+  { 0x0ee7, 0x11bb }, /*          Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
+  { 0x0ee8, 0x11bc }, /*              Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
+  { 0x0ee9, 0x11bd }, /*              Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
+  { 0x0eea, 0x11be }, /*              Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
+  { 0x0eeb, 0x11bf }, /*             Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
+  { 0x0eec, 0x11c0 }, /*              Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
+  { 0x0eed, 0x11c1 }, /*             Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
+  { 0x0eee, 0x11c2 }, /*              Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
+  { 0x0eef, 0x316d }, /*     Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
+  { 0x0ef0, 0x3171 }, /*    Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
+  { 0x0ef1, 0x3178 }, /*    Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
+  { 0x0ef2, 0x317f }, /*              Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
+  { 0x0ef3, 0x3181 }, /*    Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
+  { 0x0ef4, 0x3184 }, /*   Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
+  { 0x0ef5, 0x3186 }, /*          Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
+  { 0x0ef6, 0x318d }, /*                Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
+  { 0x0ef7, 0x318e }, /*               Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
+  { 0x0ef8, 0x11eb }, /*            Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
+  { 0x0ef9, 0x11f0 }, /*  Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
+  { 0x0efa, 0x11f9 }, /*        Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
+  { 0x0eff, 0x20a9 }, /*                  Korean_Won ₩ WON SIGN */
+  { 0x13a4, 0x20ac }, /*                        Euro € EURO SIGN */
+  { 0x13bc, 0x0152 }, /*                          OE Œ LATIN CAPITAL LIGATURE OE */
+  { 0x13bd, 0x0153 }, /*                          oe œ LATIN SMALL LIGATURE OE */
+  { 0x13be, 0x0178 }, /*                  Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
+  { 0x20ac, 0x20ac }, /*                    EuroSign € EURO SIGN */
+};
+
+long keysym2ucs(KeySym keysym)
+{
+    int min = 0;
+    int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
+    int mid;
+
+    /* first check for Latin-1 characters (1:1 mapping) */
+    if ((keysym >= 0x0020 && keysym <= 0x007e) ||
+        (keysym >= 0x00a0 && keysym <= 0x00ff))
+        return keysym;
+
+    /* also check for directly encoded 24-bit UCS characters */
+    if ((keysym & 0xff000000) == 0x01000000)
+    return keysym & 0x00ffffff;
+
+    /* binary search in table */
+    while (max >= min) {
+    mid = (min + max) / 2;
+    if (keysymtab[mid].keysym < keysym)
+        min = mid + 1;
+    else if (keysymtab[mid].keysym > keysym)
+        max = mid - 1;
+    else {
+        /* found it */
+        return keysymtab[mid].ucs;
+    }
+    }
+
+    /* no matching Unicode value found */
+    return -1;
+}
diff --git a/src/third_party/skia/tools/sk_app/unix/keysym2ucs.h b/src/third_party/skia/tools/sk_app/unix/keysym2ucs.h
new file mode 100644
index 0000000..0287f02
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/keysym2ucs.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/*
+ * This module converts keysym values into the corresponding ISO 10646-1
+ * (UCS, Unicode) values.
+ */
+
+#include <X11/X.h>
+
+long keysym2ucs(KeySym keysym);
diff --git a/src/third_party/skia/tools/sk_app/unix/main_unix.cpp b/src/third_party/skia/tools/sk_app/unix/main_unix.cpp
new file mode 100644
index 0000000..ecdb021
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/unix/main_unix.cpp
@@ -0,0 +1,92 @@
+/*
+
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "include/core/SkTypes.h"
+#include "include/private/SkTHash.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/unix/Window_unix.h"
+#include "tools/timer/Timer.h"
+
+int main(int argc, char**argv) {
+    XInitThreads();
+    Display* display = XOpenDisplay(nullptr);
+
+    sk_app::Application* app = sk_app::Application::Create(argc, argv, (void*)display);
+
+    // Get the file descriptor for the X display
+    const int x11_fd = ConnectionNumber(display);
+
+    bool done = false;
+    while (!done) {
+        if (0 == XPending(display)) {
+            // Only call select() when we have no events.
+
+            // Create a file description set containing x11_fd
+            fd_set in_fds;
+            FD_ZERO(&in_fds);
+            FD_SET(x11_fd, &in_fds);
+
+            // Set a sleep timer
+            struct timeval tv;
+            tv.tv_usec = 10;
+            tv.tv_sec = 0;
+
+            // Wait for an event on the file descriptor or for timer expiration
+            (void)select(1, &in_fds, nullptr, nullptr, &tv);
+        }
+
+        // Handle all pending XEvents (if any) and flush the input
+        // Only handle a finite number of events before finishing resize and paint..
+        if (int count = XPending(display)) {
+            // collapse any Expose and Resize events.
+            SkTHashSet<sk_app::Window_unix*> pendingWindows;
+            while (count-- && !done) {
+                XEvent event;
+                XNextEvent(display, &event);
+
+                sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window);
+                if (!win) {
+                    continue;
+                }
+
+                // paint and resize events get collapsed
+                switch (event.type) {
+                case Expose:
+                    win->markPendingPaint();
+                    pendingWindows.add(win);
+                    break;
+                case ConfigureNotify:
+                    win->markPendingResize(event.xconfigurerequest.width,
+                                           event.xconfigurerequest.height);
+                    pendingWindows.add(win);
+                    break;
+                default:
+                    if (win->handleEvent(event)) {
+                        done = true;
+                    }
+                    break;
+                }
+            }
+            pendingWindows.foreach([](sk_app::Window_unix* win) {
+                win->finishResize();
+                win->finishPaint();
+            });
+        } else {
+            // We are only really "idle" when the timer went off with zero events.
+            app->onIdle();
+        }
+
+        XFlush(display);
+    }
+
+    delete app;
+
+    XCloseDisplay(display);
+
+    return 0;
+}
diff --git a/src/third_party/skia/tools/sk_app/win/ANGLEWindowContext_win.cpp b/src/third_party/skia/tools/sk_app/win/ANGLEWindowContext_win.cpp
new file mode 100644
index 0000000..5fcccb2
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/win/ANGLEWindowContext_win.cpp
@@ -0,0 +1,179 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#define EGL_EGL_PROTOTYPES 1
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "include/gpu/gl/GrGLAssembleInterface.h"
+#include "src/gpu/gl/GrGLDefines.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/win/WindowContextFactory_win.h"
+
+using sk_app::GLWindowContext;
+using sk_app::DisplayParams;
+
+namespace {
+
+EGLDisplay get_angle_egl_display(HDC hdc) {
+    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
+    eglGetPlatformDisplayEXT =
+            (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
+
+    // We expect ANGLE to support this extension
+    if (!eglGetPlatformDisplayEXT) {
+        return EGL_NO_DISPLAY;
+    }
+
+    // We currently only support D3D11 ANGLE.
+    static constexpr EGLint kType = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
+    static constexpr EGLint attribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, kType, EGL_NONE};
+    return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, hdc, attribs);
+}
+
+class ANGLEGLWindowContext_win : public GLWindowContext {
+public:
+    ANGLEGLWindowContext_win(HWND, const DisplayParams&);
+    ~ANGLEGLWindowContext_win() override;
+
+protected:
+    void onSwapBuffers() override;
+
+    sk_sp<const GrGLInterface> onInitializeContext() override;
+    void onDestroyContext() override;
+
+private:
+    HWND fHWND;
+    EGLDisplay fDisplay = EGL_NO_DISPLAY;
+    EGLContext fEGLContext = EGL_NO_CONTEXT;
+    EGLSurface fEGLSurface = EGL_NO_SURFACE;
+
+    typedef GLWindowContext INHERITED;
+};
+
+ANGLEGLWindowContext_win::ANGLEGLWindowContext_win(HWND wnd, const DisplayParams& params)
+        : INHERITED(params), fHWND(wnd) {
+    this->initializeContext();
+}
+
+ANGLEGLWindowContext_win::~ANGLEGLWindowContext_win() { this->destroyContext(); }
+
+sk_sp<const GrGLInterface> ANGLEGLWindowContext_win::onInitializeContext() {
+    HDC dc = GetDC(fHWND);
+    fDisplay = get_angle_egl_display(dc);
+    if (EGL_NO_DISPLAY == fDisplay) {
+        return nullptr;
+    }
+
+    EGLint majorVersion;
+    EGLint minorVersion;
+    if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) {
+        SkDebugf("Could not initialize display!\n");
+        return nullptr;
+    }
+    EGLint numConfigs;
+    fSampleCount = this->getDisplayParams().fMSAASampleCount;
+    const int sampleBuffers = fSampleCount > 1 ? 1 : 0;
+    const int eglSampleCnt = fSampleCount > 1 ? fSampleCount : 0;
+    const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE,
+                                    // We currently only support ES3.
+                                    EGL_OPENGL_ES3_BIT,
+                                    EGL_RED_SIZE,
+                                    8,
+                                    EGL_GREEN_SIZE,
+                                    8,
+                                    EGL_BLUE_SIZE,
+                                    8,
+                                    EGL_ALPHA_SIZE,
+                                    8,
+                                    EGL_SAMPLE_BUFFERS,
+                                    sampleBuffers,
+                                    EGL_SAMPLES,
+                                    eglSampleCnt,
+                                    EGL_NONE};
+
+    EGLConfig surfaceConfig;
+    if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
+        SkDebugf("Could not create choose config!\n");
+        return nullptr;
+    }
+    // We currently only support ES3.
+    const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+    fEGLContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs);
+    if (EGL_NO_CONTEXT == fEGLContext) {
+        SkDebugf("Could not create context!\n");
+        return nullptr;
+    }
+    fEGLSurface = eglCreateWindowSurface(fDisplay, surfaceConfig, fHWND, nullptr);
+    if (EGL_NO_SURFACE == fEGLSurface) {
+        SkDebugf("Could not create surface!\n");
+        return nullptr;
+    }
+    if (!eglMakeCurrent(fDisplay, fEGLSurface, fEGLSurface, fEGLContext)) {
+        SkDebugf("Could not make contxt current!\n");
+        return nullptr;
+    }
+
+    sk_sp<const GrGLInterface> interface(GrGLMakeAssembledInterface(
+            nullptr,
+            [](void* ctx, const char name[]) -> GrGLFuncPtr { return eglGetProcAddress(name); }));
+    if (interface) {
+        interface->fFunctions.fClearStencil(0);
+        interface->fFunctions.fClearColor(0, 0, 0, 0);
+        interface->fFunctions.fStencilMask(0xffffffff);
+        interface->fFunctions.fClear(GR_GL_STENCIL_BUFFER_BIT | GR_GL_COLOR_BUFFER_BIT);
+
+        // use DescribePixelFormat to get the stencil depth.
+        int pixelFormat = GetPixelFormat(dc);
+        PIXELFORMATDESCRIPTOR pfd;
+        DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
+        fStencilBits = pfd.cStencilBits;
+
+        RECT rect;
+        GetClientRect(fHWND, &rect);
+        fWidth = rect.right - rect.left;
+        fHeight = rect.bottom - rect.top;
+        interface->fFunctions.fViewport(0, 0, fWidth, fHeight);
+    }
+    return interface;
+}
+
+void ANGLEGLWindowContext_win::onDestroyContext() {
+    eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    if (EGL_NO_CONTEXT != fEGLContext) {
+        eglDestroyContext(fDisplay, fEGLContext);
+    }
+    if (EGL_NO_SURFACE != fEGLSurface) {
+        eglDestroySurface(fDisplay, fEGLSurface);
+    }
+    if (EGL_NO_DISPLAY != fDisplay) {
+        eglTerminate(fDisplay);
+    }
+}
+
+void ANGLEGLWindowContext_win::onSwapBuffers() {
+    if (!eglSwapBuffers(fDisplay, fEGLSurface)) {
+        SkDebugf("Could not complete eglSwapBuffers.\n");
+    }
+}
+
+}  // anonymous namespace
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeANGLEForWin(HWND wnd, const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new ANGLEGLWindowContext_win(wnd, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}  // namespace window_context_factory
+}  // namespace sk_app
diff --git a/src/third_party/skia/tools/sk_app/win/DawnD3D12WindowContext_win.cpp b/src/third_party/skia/tools/sk_app/win/DawnD3D12WindowContext_win.cpp
new file mode 100644
index 0000000..b5e8599
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/win/DawnD3D12WindowContext_win.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/sk_app/DawnWindowContext.h"
+#include "tools/sk_app/win/WindowContextFactory_win.h"
+#include "dawn/dawncpp.h"
+#include "dawn/dawn_wsi.h"
+#include "dawn_native/DawnNative.h"
+#include "dawn_native/D3D12Backend.h"
+#include "common/SwapChainUtils.h"
+
+namespace sk_app {
+
+class DawnD3D12WindowContext : public DawnWindowContext {
+public:
+    DawnD3D12WindowContext(HWND hwnd, const DisplayParams& params);
+    virtual ~DawnD3D12WindowContext();
+    dawn::Device onInitializeContext() override;
+    void onDestroyContext() override;
+    DawnSwapChainImplementation createSwapChainImplementation(
+            int width, int height, const DisplayParams& params) override;
+    void onSwapBuffers() override;
+private:
+    HWND                 fWindow;
+};
+
+// NOTE: this texture format must match the one in D3D12's swap chain impl
+DawnD3D12WindowContext::DawnD3D12WindowContext(HWND hwnd, const DisplayParams& params)
+    : DawnWindowContext(params, dawn::TextureFormat::RGBA8Unorm)
+    , fWindow(hwnd) {
+    RECT rect;
+    GetClientRect(hwnd, &rect);
+    this->initializeContext(rect.right - rect.left, rect.bottom - rect.top);
+}
+
+DawnD3D12WindowContext::~DawnD3D12WindowContext() {
+    this->destroyContext();
+}
+
+DawnSwapChainImplementation DawnD3D12WindowContext::createSwapChainImplementation(
+        int width, int height, const DisplayParams& params) {
+    return dawn_native::d3d12::CreateNativeSwapChainImpl(fDevice.Get(), fWindow);
+}
+
+dawn::Device DawnD3D12WindowContext::onInitializeContext() {
+    return this->createDevice(dawn_native::BackendType::D3D12);
+}
+
+void DawnD3D12WindowContext::onDestroyContext() {
+}
+
+void DawnD3D12WindowContext::onSwapBuffers() {
+}
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeDawnD3D12ForWin(HWND hwnd,
+                                                   const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new DawnD3D12WindowContext(hwnd, params));
+    if (!ctx->isValid()) {
+        return nullptr;
+    }
+    return ctx;
+}
+
+}
+
+}   //namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/GLWindowContext_win.cpp b/src/third_party/skia/tools/sk_app/win/GLWindowContext_win.cpp
similarity index 72%
rename from src/third_party/skia/tools/viewer/sk_app/win/GLWindowContext_win.cpp
rename to src/third_party/skia/tools/sk_app/win/GLWindowContext_win.cpp
index 20c3d91..32c47b4 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/GLWindowContext_win.cpp
+++ b/src/third_party/skia/tools/sk_app/win/GLWindowContext_win.cpp
@@ -6,17 +6,29 @@
  * found in the LICENSE file.
  */
 
-#include "WindowContextFactory_win.h"
+#include "include/gpu/gl/GrGLInterface.h"
+#include "src/utils/win/SkWGL.h"
+#include "tools/sk_app/GLWindowContext.h"
+#include "tools/sk_app/win/WindowContextFactory_win.h"
+
+#include <Windows.h>
 #include <GL/gl.h>
 
- // windows stuff
-#include "win/SkWGL.h"
-
-#include "../GLWindowContext.h"
-
 using sk_app::GLWindowContext;
 using sk_app::DisplayParams;
 
+#if defined(_M_ARM64)
+
+namespace sk_app {
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeGLForWin(HWND, const DisplayParams&) { return nullptr; }
+
+}  // namespace window_context_factory
+}  // namespace sk_app
+
+#else
+
 namespace {
 
 class GLWindowContext_win : public GLWindowContext {
@@ -27,7 +39,7 @@
 protected:
     void onSwapBuffers() override;
 
-    void onInitializeContext() override;
+    sk_sp<const GrGLInterface> onInitializeContext() override;
     void onDestroyContext() override;
 
 private:
@@ -51,26 +63,31 @@
     this->destroyContext();
 }
 
-void GLWindowContext_win::onInitializeContext() {
+sk_sp<const GrGLInterface> GLWindowContext_win::onInitializeContext() {
     HDC dc = GetDC(fHWND);
 
     fHGLRC = SkCreateWGLContext(dc, fDisplayParams.fMSAASampleCount, false /* deepColor */,
                                 kGLPreferCompatibilityProfile_SkWGLContextRequest);
     if (NULL == fHGLRC) {
-        return;
+        return nullptr;
+    }
+
+    SkWGLExtensions extensions;
+    if (extensions.hasExtension(dc, "WGL_EXT_swap_control")) {
+        extensions.swapInterval(fDisplayParams.fDisableVsync ? 0 : 1);
     }
 
     // Look to see if RenderDoc is attached. If so, re-create the context with a core profile
     if (wglMakeCurrent(dc, fHGLRC)) {
-        const GrGLInterface* glInterface = GrGLCreateNativeInterface();
-        bool renderDocAttached = glInterface->hasExtension("GL_EXT_debug_tool");
-        SkSafeUnref(glInterface);
+        auto interface = GrGLMakeNativeInterface();
+        bool renderDocAttached = interface->hasExtension("GL_EXT_debug_tool");
+        interface.reset(nullptr);
         if (renderDocAttached) {
             wglDeleteContext(fHGLRC);
             fHGLRC = SkCreateWGLContext(dc, fDisplayParams.fMSAASampleCount, false /* deepColor */,
                                         kGLPreferCoreProfile_SkWGLContextRequest);
             if (NULL == fHGLRC) {
-                return;
+                return nullptr;
             }
         }
     }
@@ -88,7 +105,6 @@
         fStencilBits = pfd.cStencilBits;
 
         // Get sample count if the MSAA WGL extension is present
-        SkWGLExtensions extensions;
         if (extensions.hasExtension(dc, "WGL_ARB_multisample")) {
             static const int kSampleCountAttr = SK_WGL_SAMPLES;
             extensions.getPixelFormatAttribiv(dc,
@@ -97,8 +113,9 @@
                                               1,
                                               &kSampleCountAttr,
                                               &fSampleCount);
+            fSampleCount = SkTMax(fSampleCount, 1);
         } else {
-            fSampleCount = 0;
+            fSampleCount = 1;
         }
 
         RECT rect;
@@ -107,6 +124,7 @@
         fHeight = rect.bottom - rect.top;
         glViewport(0, 0, fWidth, fHeight);
     }
+    return GrGLMakeNativeInterface();
 }
 
 
@@ -128,10 +146,9 @@
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewGLForWin(HWND wnd, const DisplayParams& params) {
-    GLWindowContext_win* ctx = new GLWindowContext_win(wnd, params);
+std::unique_ptr<WindowContext> MakeGLForWin(HWND wnd, const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new GLWindowContext_win(wnd, params));
     if (!ctx->isValid()) {
-        delete ctx;
         return nullptr;
     }
     return ctx;
@@ -139,3 +156,5 @@
 
 }  // namespace window_context_factory
 }  // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/RasterWindowContext_win.cpp b/src/third_party/skia/tools/sk_app/win/RasterWindowContext_win.cpp
similarity index 87%
rename from src/third_party/skia/tools/viewer/sk_app/win/RasterWindowContext_win.cpp
rename to src/third_party/skia/tools/sk_app/win/RasterWindowContext_win.cpp
index 85bb65e..9548220 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/RasterWindowContext_win.cpp
+++ b/src/third_party/skia/tools/sk_app/win/RasterWindowContext_win.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "../RasterWindowContext.h"
-#include "SkAutoMalloc.h"
-#include "SkSurface.h"
-#include "WindowContextFactory_win.h"
+#include "include/core/SkSurface.h"
+#include "src/core/SkAutoMalloc.h"
+#include "tools/sk_app/RasterWindowContext.h"
+#include "tools/sk_app/win/WindowContextFactory_win.h"
 
 #include <Windows.h>
 
@@ -40,14 +40,14 @@
     : INHERITED(params)
     , fWnd(wnd) {
     RECT rect;
-    GetWindowRect(wnd, &rect);
+    GetClientRect(wnd, &rect);
     this->resize(rect.right - rect.left, rect.bottom - rect.top);
 }
 
 void RasterWindowContext_win::setDisplayParams(const DisplayParams& params) {
     fDisplayParams = params;
     RECT rect;
-    GetWindowRect(fWnd, &rect);
+    GetClientRect(fWnd, &rect);
     this->resize(rect.right - rect.left, rect.bottom - rect.top);
 }
 
@@ -87,10 +87,9 @@
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewRasterForWin(HWND wnd, const DisplayParams& params) {
-    WindowContext* ctx = new RasterWindowContext_win(wnd, params);
+std::unique_ptr<WindowContext> MakeRasterForWin(HWND wnd, const DisplayParams& params) {
+    std::unique_ptr<WindowContext> ctx(new RasterWindowContext_win(wnd, params));
     if (!ctx->isValid()) {
-        delete ctx;
         ctx = nullptr;
     }
     return ctx;
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/VulkanWindowContext_win.cpp b/src/third_party/skia/tools/sk_app/win/VulkanWindowContext_win.cpp
similarity index 61%
rename from src/third_party/skia/tools/viewer/sk_app/win/VulkanWindowContext_win.cpp
rename to src/third_party/skia/tools/sk_app/win/VulkanWindowContext_win.cpp
index 521a1ee..909c961 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/VulkanWindowContext_win.cpp
+++ b/src/third_party/skia/tools/sk_app/win/VulkanWindowContext_win.cpp
@@ -6,24 +6,35 @@
  * found in the LICENSE file.
  */
 
+#include "include/gpu/vk/GrVkVulkan.h"
+
+#include "tools/sk_app/win/WindowContextFactory_win.h"
+
+#include "tools/sk_app/VulkanWindowContext.h"
+#include "tools/sk_app/win/Window_win.h"
+
+#include "src/gpu/vk/GrVkInterface.h"
+#include "src/gpu/vk/GrVkUtil.h"
+
+#include "tools/gpu/vk/VkTestUtils.h"
+
 #include <Windows.h>
-#include "WindowContextFactory_win.h"
-
-#include "../VulkanWindowContext.h"
-#include "Window_win.h"
-
-#include "vk/GrVkInterface.h"
-#include "vk/GrVkUtil.h"
 
 namespace sk_app {
 namespace window_context_factory {
 
-WindowContext* NewVulkanForWin(HWND hwnd, const DisplayParams& params) {
-    auto createVkSurface = [hwnd] (VkInstance instance) -> VkSurfaceKHR {
+std::unique_ptr<WindowContext> MakeVulkanForWin(HWND hwnd, const DisplayParams& params) {
+    PFN_vkGetInstanceProcAddr instProc;
+    PFN_vkGetDeviceProcAddr devProc;
+    if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
+        return nullptr;
+    }
+
+    auto createVkSurface = [hwnd, instProc] (VkInstance instance) -> VkSurfaceKHR {
         static PFN_vkCreateWin32SurfaceKHR createWin32SurfaceKHR = nullptr;
         if (!createWin32SurfaceKHR) {
             createWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
-                vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
+                instProc(instance, "vkCreateWin32SurfaceKHR");
         }
         HINSTANCE hinstance = GetModuleHandle(0);
         VkSurfaceKHR surface;
@@ -44,24 +55,23 @@
         return surface;
     };
 
-    auto canPresent = [hwnd] (VkInstance instance, VkPhysicalDevice physDev,
-                             uint32_t queueFamilyIndex) {
+    auto canPresent = [instProc] (VkInstance instance, VkPhysicalDevice physDev,
+                                  uint32_t queueFamilyIndex) {
         static PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR
                                             getPhysicalDeviceWin32PresentationSupportKHR = nullptr;
         if (!getPhysicalDeviceWin32PresentationSupportKHR) {
             getPhysicalDeviceWin32PresentationSupportKHR =
                 (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
-                    vkGetInstanceProcAddr(instance,
-                                          "vkGetPhysicalDeviceWin32PresentationSupportKHR");
+                    instProc(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
         }
 
         VkBool32 check = getPhysicalDeviceWin32PresentationSupportKHR(physDev, queueFamilyIndex);
         return (VK_FALSE != check);
     };
 
-    WindowContext* ctx = new VulkanWindowContext(params, createVkSurface, canPresent);
+    std::unique_ptr<WindowContext> ctx(
+            new VulkanWindowContext(params, createVkSurface, canPresent, instProc, devProc));
     if (!ctx->isValid()) {
-        delete ctx;
         return nullptr;
     }
     return ctx;
diff --git a/src/third_party/skia/tools/sk_app/win/WindowContextFactory_win.h b/src/third_party/skia/tools/sk_app/win/WindowContextFactory_win.h
new file mode 100644
index 0000000..33dd6d4
--- /dev/null
+++ b/src/third_party/skia/tools/sk_app/win/WindowContextFactory_win.h
@@ -0,0 +1,39 @@
+
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef WindowContextFactory_win_DEFINED
+#define WindowContextFactory_win_DEFINED
+
+#include <Windows.h>
+
+#include <memory>
+
+namespace sk_app {
+
+class WindowContext;
+struct DisplayParams;
+
+namespace window_context_factory {
+
+std::unique_ptr<WindowContext> MakeVulkanForWin(HWND, const DisplayParams&);
+
+std::unique_ptr<WindowContext> MakeGLForWin(HWND, const DisplayParams&);
+
+std::unique_ptr<WindowContext> MakeANGLEForWin(HWND, const DisplayParams&);
+
+#ifdef SK_DAWN
+std::unique_ptr<WindowContext> MakeDawnD3D12ForWin(HWND, const DisplayParams&);
+#endif
+
+std::unique_ptr<WindowContext> MakeRasterForWin(HWND, const DisplayParams&);
+
+}  // namespace window_context_factory
+
+}  // namespace sk_app
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/Window_win.cpp b/src/third_party/skia/tools/sk_app/win/Window_win.cpp
similarity index 70%
rename from src/third_party/skia/tools/viewer/sk_app/win/Window_win.cpp
rename to src/third_party/skia/tools/sk_app/win/Window_win.cpp
index 0fb6513..43ed343 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/Window_win.cpp
+++ b/src/third_party/skia/tools/sk_app/win/Window_win.cpp
@@ -5,17 +5,21 @@
 * found in the LICENSE file.
 */
 
-#include "Window_win.h"
+#include "include/gpu/vk/GrVkVulkan.h"
+
+#include "tools/sk_app/win/Window_win.h"
 
 #include <tchar.h>
 #include <windows.h>
 #include <windowsx.h>
 
-#include "SkUtils.h"
-#include "../WindowContext.h"
-#include "WindowContextFactory_win.h"
+#include "src/core/SkUtils.h"
+#include "tools/sk_app/WindowContext.h"
+#include "tools/sk_app/win/WindowContextFactory_win.h"
+#include "tools/skui/ModifierKey.h"
+
 #ifdef SK_VULKAN
-#include "../VulkanWindowContext.h"
+#include "tools/sk_app/VulkanWindowContext.h"
 #endif
 
 namespace sk_app {
@@ -72,11 +76,11 @@
         wcex.cbWndExtra = 0;
         wcex.hInstance = fHInstance;
         wcex.hIcon = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);
-        wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);;
+        wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
         wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
         wcex.lpszMenuName = nullptr;
         wcex.lpszClassName = gSZWindowClass;
-        wcex.hIconSm = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);;
+        wcex.hIconSm = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);
 
         if (!RegisterClassEx(&wcex)) {
             return false;
@@ -101,7 +105,7 @@
 
         // Set the position of the window to the top left corner.
         posX = posY = 0;
-    } 
+    }
     */
  //   gIsFullscreen = fullscreen;
 
@@ -119,71 +123,71 @@
     return true;
 }
 
-static Window::Key get_key(WPARAM vk) {
+static skui::Key get_key(WPARAM vk) {
     static const struct {
         WPARAM      fVK;
-        Window::Key fKey;
+        skui::Key fKey;
     } gPair[] = {
-        { VK_BACK, Window::Key::kBack },
-        { VK_CLEAR, Window::Key::kBack },
-        { VK_RETURN, Window::Key::kOK },
-        { VK_UP, Window::Key::kUp },
-        { VK_DOWN, Window::Key::kDown },
-        { VK_LEFT, Window::Key::kLeft },
-        { VK_RIGHT, Window::Key::kRight },
-        { VK_TAB, Window::Key::kTab },
-        { VK_PRIOR, Window::Key::kPageUp },
-        { VK_NEXT, Window::Key::kPageDown },
-        { VK_HOME, Window::Key::kHome },
-        { VK_END, Window::Key::kEnd },
-        { VK_DELETE, Window::Key::kDelete },
-        { VK_ESCAPE, Window::Key::kEscape },
-        { VK_SHIFT, Window::Key::kShift },
-        { VK_CONTROL, Window::Key::kCtrl },
-        { VK_MENU, Window::Key::kOption },
-        { 'A', Window::Key::kA },
-        { 'C', Window::Key::kC },
-        { 'V', Window::Key::kV },
-        { 'X', Window::Key::kX },
-        { 'Y', Window::Key::kY },
-        { 'Z', Window::Key::kZ },
+        { VK_BACK,    skui::Key::kBack     },
+        { VK_CLEAR,   skui::Key::kBack     },
+        { VK_RETURN,  skui::Key::kOK       },
+        { VK_UP,      skui::Key::kUp       },
+        { VK_DOWN,    skui::Key::kDown     },
+        { VK_LEFT,    skui::Key::kLeft     },
+        { VK_RIGHT,   skui::Key::kRight    },
+        { VK_TAB,     skui::Key::kTab      },
+        { VK_PRIOR,   skui::Key::kPageUp   },
+        { VK_NEXT,    skui::Key::kPageDown },
+        { VK_HOME,    skui::Key::kHome     },
+        { VK_END,     skui::Key::kEnd      },
+        { VK_DELETE,  skui::Key::kDelete   },
+        { VK_ESCAPE,  skui::Key::kEscape   },
+        { VK_SHIFT,   skui::Key::kShift    },
+        { VK_CONTROL, skui::Key::kCtrl     },
+        { VK_MENU,    skui::Key::kOption   },
+        { 'A',        skui::Key::kA        },
+        { 'C',        skui::Key::kC        },
+        { 'V',        skui::Key::kV        },
+        { 'X',        skui::Key::kX        },
+        { 'Y',        skui::Key::kY        },
+        { 'Z',        skui::Key::kZ        },
     };
     for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
         if (gPair[i].fVK == vk) {
             return gPair[i].fKey;
         }
     }
-    return Window::Key::kNONE;
+    return skui::Key::kNONE;
 }
 
-static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {
-    uint32_t modifiers = 0;
+static skui::ModifierKey get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {
+    skui::ModifierKey modifiers = skui::ModifierKey::kNone;
 
     switch (message) {
         case WM_UNICHAR:
         case WM_CHAR:
             if (0 == (lParam & (1 << 30))) {
-                modifiers |= Window::kFirstPress_ModifierKey;
+                modifiers |= skui::ModifierKey::kFirstPress;
             }
             if (lParam & (1 << 29)) {
-                modifiers |= Window::kOption_ModifierKey;
+                modifiers |= skui::ModifierKey::kOption;
             }
             break;
 
         case WM_KEYDOWN:
         case WM_SYSKEYDOWN:
             if (0 == (lParam & (1 << 30))) {
-                modifiers |= Window::kFirstPress_ModifierKey;
+                modifiers |= skui::ModifierKey::kFirstPress;
             }
             if (lParam & (1 << 29)) {
-                modifiers |= Window::kOption_ModifierKey;
+                modifiers |= skui::ModifierKey::kOption;
             }
             break;
 
         case WM_KEYUP:
         case WM_SYSKEYUP:
             if (lParam & (1 << 29)) {
-                modifiers |= Window::kOption_ModifierKey;
+                modifiers |= skui::ModifierKey::kOption;
             }
             break;
 
@@ -192,10 +196,10 @@
         case WM_MOUSEMOVE:
         case WM_MOUSEWHEEL:
             if (wParam & MK_CONTROL) {
-                modifiers |= Window::kControl_ModifierKey;
+                modifiers |= skui::ModifierKey::kControl;
             }
             if (wParam & MK_SHIFT) {
-                modifiers |= Window::kShift_ModifierKey;
+                modifiers |= skui::ModifierKey::kShift;
             }
             break;
     }
@@ -235,25 +239,25 @@
             break;
 
         case WM_UNICHAR:
-            eventHandled = window->onChar((SkUnichar)wParam, 
+            eventHandled = window->onChar((SkUnichar)wParam,
                                           get_modifiers(message, wParam, lParam));
             break;
 
         case WM_CHAR: {
             const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam);
-            eventHandled = window->onChar(SkUTF16_NextUnichar(&c), 
+            eventHandled = window->onChar(SkUTF16_NextUnichar(&c),
                                           get_modifiers(message, wParam, lParam));
         } break;
 
         case WM_KEYDOWN:
         case WM_SYSKEYDOWN:
-            eventHandled = window->onKey(get_key(wParam), Window::kDown_InputState, 
+            eventHandled = window->onKey(get_key(wParam), skui::InputState::kDown,
                                          get_modifiers(message, wParam, lParam));
             break;
 
         case WM_KEYUP:
         case WM_SYSKEYUP:
-            eventHandled = window->onKey(get_key(wParam), Window::kUp_InputState,
+            eventHandled = window->onKey(get_key(wParam), skui::InputState::kUp,
                                          get_modifiers(message, wParam, lParam));
             break;
 
@@ -270,10 +274,10 @@
             //    yPos -= rc.top;
             //}
 
-            Window::InputState istate = ((wParam & MK_LBUTTON) != 0) ? Window::kDown_InputState
-                                                                     : Window::kUp_InputState;
+            skui::InputState istate = ((wParam & MK_LBUTTON) != 0) ? skui::InputState::kDown
+                                                                     : skui::InputState::kUp;
 
-            eventHandled = window->onMouse(xPos, yPos, istate, 
+            eventHandled = window->onMouse(xPos, yPos, istate,
                                             get_modifiers(message, wParam, lParam));
         } break;
 
@@ -289,7 +293,7 @@
             //    yPos -= rc.top;
             //}
 
-            eventHandled = window->onMouse(xPos, yPos, Window::kMove_InputState,
+            eventHandled = window->onMouse(xPos, yPos, skui::InputState::kMove,
                                            get_modifiers(message, wParam, lParam));
         } break;
 
@@ -303,24 +307,24 @@
             std::unique_ptr<TOUCHINPUT[]> inputs(new TOUCHINPUT[numInputs]);
             if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, inputs.get(),
                                   sizeof(TOUCHINPUT))) {
-                RECT rect;
-                GetClientRect(hWnd, &rect);
+                POINT topLeft = {0, 0};
+                ClientToScreen(hWnd, &topLeft);
                 for (uint16_t i = 0; i < numInputs; ++i) {
                     TOUCHINPUT ti = inputs[i];
-                    Window::InputState state;
+                    skui::InputState state;
                     if (ti.dwFlags & TOUCHEVENTF_DOWN) {
-                        state = Window::kDown_InputState;
+                        state = skui::InputState::kDown;
                     } else if (ti.dwFlags & TOUCHEVENTF_MOVE) {
-                        state = Window::kMove_InputState;
+                        state = skui::InputState::kMove;
                     } else if (ti.dwFlags & TOUCHEVENTF_UP) {
-                        state = Window::kUp_InputState;
+                        state = skui::InputState::kUp;
                     } else {
                         continue;
                     }
                     // TOUCHINPUT coordinates are in 100ths of pixels
                     // Adjust for that, and make them window relative
-                    LONG tx = (ti.x / 100) - rect.left;
-                    LONG ty = (ti.y / 100) - rect.top;
+                    LONG tx = (ti.x / 100) - topLeft.x;
+                    LONG ty = (ti.y / 100) - topLeft.y;
                     eventHandled = window->onTouch(ti.dwID, state, tx, ty) || eventHandled;
                 }
             }
@@ -347,16 +351,28 @@
 
     switch (attachType) {
         case kNativeGL_BackendType:
-            fWindowContext = window_context_factory::NewGLForWin(fHWnd, fRequestedDisplayParams);
+            fWindowContext = window_context_factory::MakeGLForWin(fHWnd, fRequestedDisplayParams);
             break;
+#if SK_ANGLE
+        case kANGLE_BackendType:
+            fWindowContext =
+                    window_context_factory::MakeANGLEForWin(fHWnd, fRequestedDisplayParams);
+            break;
+#endif
+#ifdef SK_DAWN
+        case kDawn_BackendType:
+            fWindowContext =
+                    window_context_factory::MakeDawnD3D12ForWin(fHWnd, fRequestedDisplayParams);
+            break;
+#endif
         case kRaster_BackendType:
-            fWindowContext = window_context_factory::NewRasterForWin(fHWnd,
-                                                                     fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeRasterForWin(fHWnd, fRequestedDisplayParams);
             break;
 #ifdef SK_VULKAN
         case kVulkan_BackendType:
-            fWindowContext = window_context_factory::NewVulkanForWin(fHWnd,
-                                                                     fRequestedDisplayParams);
+            fWindowContext =
+                    window_context_factory::MakeVulkanForWin(fHWnd, fRequestedDisplayParams);
             break;
 #endif
     }
@@ -376,7 +392,7 @@
         // Need to change these early, so attach() creates the window context correctly
         fRequestedDisplayParams = params;
 
-        delete fWindowContext;
+        fWindowContext = nullptr;
         this->closeWindow();
         this->init(fHInstance);
         this->attach(fBackend);
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/Window_win.h b/src/third_party/skia/tools/sk_app/win/Window_win.h
similarity index 95%
rename from src/third_party/skia/tools/viewer/sk_app/win/Window_win.h
rename to src/third_party/skia/tools/sk_app/win/Window_win.h
index 139ab87..9e108e0 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/Window_win.h
+++ b/src/third_party/skia/tools/sk_app/win/Window_win.h
@@ -8,8 +8,9 @@
 #ifndef Window_win_DEFINED
 #define Window_win_DEFINED
 
+#include "tools/sk_app/Window.h"
+
 #include <windows.h>
-#include "../Window.h"
 
 namespace sk_app {
 
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/main_win.cpp b/src/third_party/skia/tools/sk_app/win/main_win.cpp
similarity index 77%
rename from src/third_party/skia/tools/viewer/sk_app/win/main_win.cpp
rename to src/third_party/skia/tools/sk_app/win/main_win.cpp
index 4800258..5a7fdc1 100644
--- a/src/third_party/skia/tools/viewer/sk_app/win/main_win.cpp
+++ b/src/third_party/skia/tools/sk_app/win/main_win.cpp
@@ -8,10 +8,10 @@
 #include <windows.h>
 #include <tchar.h>
 
-#include "SkTypes.h"
-#include "Timer.h"
-#include "Window_win.h"
-#include "../Application.h"
+#include "include/core/SkTypes.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/win/Window_win.h"
+#include "tools/timer/Timer.h"
 
 using sk_app::Application;
 
@@ -62,15 +62,28 @@
 
     Application* app = Application::Create(argc, argv, (void*)hInstance);
 
-    MSG msg = { 0 };
+    MSG msg;
+    memset(&msg, 0, sizeof(msg));
+
+    bool idled = false;
 
     // Main message loop
     while (WM_QUIT != msg.message) {
         if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
             TranslateMessage(&msg);
+
+            if (WM_PAINT == msg.message) {
+                // Ensure that call onIdle at least once per WM_PAINT, or mouse events can
+                // overwhelm the message processing loop, and prevent animation from running.
+                if (!idled) {
+                    app->onIdle();
+                }
+                idled = false;
+            }
             DispatchMessage(&msg);
         } else {
             app->onIdle();
+            idled = true;
         }
     }
 
diff --git a/src/third_party/skia/tools/sk_tool_utils.cpp b/src/third_party/skia/tools/sk_tool_utils.cpp
deleted file mode 100644
index 47f4aae..0000000
--- a/src/third_party/skia/tools/sk_tool_utils.cpp
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "sk_tool_utils.h"
-#include "sk_tool_utils_flags.h"
-
-#include "Resources.h"
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkCommonFlags.h"
-#include "SkFontMgr.h"
-#include "SkFontStyle.h"
-#include "SkPixelRef.h"
-#include "SkPoint3.h"
-#include "SkShader.h"
-#include "SkTestScalerContext.h"
-#include "SkTextBlob.h"
-
-DEFINE_bool(portableFonts, false, "Use portable fonts");
-
-namespace sk_tool_utils {
-
-/* these are the default fonts chosen by Chrome for serif, sans-serif, and monospace */
-static const char* gStandardFontNames[][3] = {
-    { "Times", "Helvetica", "Courier" }, // Mac
-    { "Times New Roman", "Helvetica", "Courier" }, // iOS
-    { "Times New Roman", "Arial", "Courier New" }, // Win
-    { "Times New Roman", "Arial", "Monospace" }, // Ubuntu
-    { "serif", "sans-serif", "monospace" }, // Android
-    { "Tinos", "Arimo", "Cousine" } // ChromeOS
-};
-
-const char* platform_font_name(const char* name) {
-    SkString platform = major_platform_os_name();
-    int index;
-    if (!strcmp(name, "serif")) {
-        index = 0;
-    } else if (!strcmp(name, "san-serif")) {
-        index = 1;
-    } else if (!strcmp(name, "monospace")) {
-        index = 2;
-    } else {
-        return name;
-    }
-    if (platform.equals("Mac")) {
-        return gStandardFontNames[0][index];
-    }
-    if (platform.equals("iOS")) {
-        return gStandardFontNames[1][index];
-    }
-    if (platform.equals("Win")) {
-        return gStandardFontNames[2][index];
-    }
-    if (platform.equals("Ubuntu") || platform.equals("Debian")) {
-        return gStandardFontNames[3][index];
-    }
-    if (platform.equals("Android")) {
-        return gStandardFontNames[4][index];
-    }
-    if (platform.equals("ChromeOS")) {
-        return gStandardFontNames[5][index];
-    }
-    return name;
-}
-
-const char* platform_os_emoji() {
-    const char* osName = platform_os_name();
-    if (!strcmp(osName, "Android") || !strcmp(osName, "Ubuntu") || !strcmp(osName, "Debian")) {
-        return "CBDT";
-    }
-    if (!strncmp(osName, "Mac", 3) || !strncmp(osName, "iOS", 3)) {
-        return "SBIX";
-    }
-    if (!strncmp(osName, "Win", 3)) {
-        return "COLR";
-    }
-    return "";
-}
-
-sk_sp<SkTypeface> emoji_typeface() {
-    if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) {
-        return MakeResourceAsTypeface("/fonts/Funkster.ttf");
-    }
-    if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX")) {
-        return SkTypeface::MakeFromName("Apple Color Emoji", SkFontStyle());
-    }
-    if (!strcmp(sk_tool_utils::platform_os_emoji(), "COLR")) {
-        sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-        const char *colorEmojiFontName = "Segoe UI Emoji";
-        sk_sp<SkTypeface> typeface(fm->matchFamilyStyle(colorEmojiFontName, SkFontStyle()));
-        if (typeface) {
-            return typeface;
-        }
-        sk_sp<SkTypeface> fallback(fm->matchFamilyStyleCharacter(
-            colorEmojiFontName, SkFontStyle(), nullptr /* bcp47 */, 0 /* bcp47Count */,
-            0x1f4b0 /* character: 💰 */));
-        if (fallback) {
-            return fallback;
-        }
-        // If we don't have Segoe UI Emoji and can't find a fallback, try Segoe UI Symbol.
-        // Windows 7 does not have Segoe UI Emoji; Segoe UI Symbol has the (non - color) emoji.
-        return SkTypeface::MakeFromName("Segoe UI Symbol", SkFontStyle());
-    }
-    return nullptr;
-}
-
-const char* emoji_sample_text() {
-    if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) {
-        return "Hamburgefons";
-    }
-    if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX") ||
-        !strcmp(sk_tool_utils::platform_os_emoji(), "COLR"))
-    {
-        return "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85"  // 💰🏡🎅
-               "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80"  // 🍪🍕🚀
-               "\xF0\x9F\x9A\xBB" "\xF0\x9F\x92\xA9" "\xF0\x9F\x93\xB7" // 🚻💩📷
-               "\xF0\x9F\x93\xA6" // 📦
-               "\xF0\x9F\x87\xBA" "\xF0\x9F\x87\xB8" "\xF0\x9F\x87\xA6"; // 🇺🇸🇦
-    }
-    return "";
-}
-
-const char* platform_os_name() {
-    for (int index = 0; index < FLAGS_key.count(); index += 2) {
-        if (!strcmp("os", FLAGS_key[index])) {
-            return FLAGS_key[index + 1];
-        }
-    }
-    // when running SampleApp or dm without a --key pair, omit the platform name
-    return "";
-}
-
-// omit version number in returned value
-SkString major_platform_os_name() {
-    SkString name;
-    for (int index = 0; index < FLAGS_key.count(); index += 2) {
-        if (!strcmp("os", FLAGS_key[index])) {
-            const char* platform = FLAGS_key[index + 1];
-            const char* end = platform;
-            while (*end && (*end < '0' || *end > '9')) {
-                ++end;
-            }
-            name.append(platform, end - platform);
-            break;
-        }
-    }
-    return name;
-}
-
-const char* platform_extra_config(const char* config) {
-    for (int index = 0; index < FLAGS_key.count(); index += 2) {
-        if (!strcmp("extra_config", FLAGS_key[index]) && !strcmp(config, FLAGS_key[index + 1])) {
-            return config;
-        }
-    }
-    return "";
-}
-
-const char* colortype_name(SkColorType ct) {
-    switch (ct) {
-        case kUnknown_SkColorType:      return "Unknown";
-        case kAlpha_8_SkColorType:      return "Alpha_8";
-        case kARGB_4444_SkColorType:    return "ARGB_4444";
-        case kRGB_565_SkColorType:      return "RGB_565";
-        case kRGBA_8888_SkColorType:    return "RGBA_8888";
-        case kBGRA_8888_SkColorType:    return "BGRA_8888";
-        case kRGBA_F16_SkColorType:     return "RGBA_F16";
-        default:
-            SkASSERT(false);
-            return "unexpected colortype";
-    }
-}
-
-SkColor color_to_565(SkColor color) {
-    SkPMColor pmColor = SkPreMultiplyColor(color);
-    U16CPU color16 = SkPixel32ToPixel16(pmColor);
-    return SkPixel16ToColor(color16);
-}
-
-sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style) {
-    return create_font(name, style);
-}
-
-void set_portable_typeface(SkPaint* paint, const char* name, SkFontStyle style) {
-    paint->setTypeface(create_font(name, style));
-}
-
-void write_pixels(SkCanvas* canvas, const SkBitmap& bitmap, int x, int y,
-                  SkColorType colorType, SkAlphaType alphaType) {
-    SkBitmap tmp(bitmap);
-    const SkImageInfo info = SkImageInfo::Make(tmp.width(), tmp.height(), colorType, alphaType);
-
-    canvas->writePixels(info, tmp.getPixels(), tmp.rowBytes(), x, y);
-}
-
-sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size) {
-    SkBitmap bm;
-    bm.allocPixels(SkImageInfo::MakeS32(2 * size, 2 * size, kPremul_SkAlphaType));
-    bm.eraseColor(c1);
-    bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
-    bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
-    return SkShader::MakeBitmapShader(
-            bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
-}
-
-SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) {
-    SkBitmap bitmap;
-    bitmap.allocPixels(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
-    SkCanvas canvas(bitmap);
-
-    sk_tool_utils::draw_checkerboard(&canvas, c1, c2, checkSize);
-    return bitmap;
-}
-
-void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) {
-    SkPaint paint;
-    paint.setShader(create_checkerboard_shader(c1, c2, size));
-    paint.setBlendMode(SkBlendMode::kSrc);
-    canvas->drawPaint(paint);
-}
-
-SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y,
-                              int textSize, const char* str) {
-    SkBitmap bitmap;
-    bitmap.allocN32Pixels(w, h);
-    SkCanvas canvas(bitmap);
-
-    SkPaint paint;
-    paint.setAntiAlias(true);
-    sk_tool_utils::set_portable_typeface(&paint);
-    paint.setColor(c);
-    paint.setTextSize(SkIntToScalar(textSize));
-
-    canvas.clear(0x00000000);
-    canvas.drawString(str, SkIntToScalar(x), SkIntToScalar(y), paint);
-
-    // Tag data as sRGB (without doing any color space conversion). Color-space aware configs
-    // will process this correctly but legacy configs will render as if this returned N32.
-    SkBitmap result;
-    result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
-    result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0);
-    return result;
-}
-
-void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint,
-                      SkScalar x, SkScalar y) {
-    SkPaint paint(origPaint);
-    SkTDArray<uint16_t> glyphs;
-
-    size_t len = strlen(text);
-    glyphs.append(paint.textToGlyphs(text, len, nullptr));
-    paint.textToGlyphs(text, len, glyphs.begin());
-
-    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-    const SkTextBlobBuilder::RunBuffer& run = builder->allocRun(paint, glyphs.count(), x, y,
-                                                                nullptr);
-    memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t));
-}
-
-static inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) {
-    SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
-    unsigned char r = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255);
-    unsigned char g = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
-    unsigned char b = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255);
-    *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
-}
-
-void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) {
-    const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
-                                         dst.fTop + (dst.height() / 2.0f));
-    const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f);
-
-    SkVector3 norm;
-
-    for (int y = dst.fTop; y < dst.fBottom; ++y) {
-        for (int x = dst.fLeft; x < dst.fRight; ++x) {
-            norm.fX = (x + 0.5f - center.fX) / halfSize.fX;
-            norm.fY = (y + 0.5f - center.fY) / halfSize.fY;
-
-            SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY;
-            if (tmp >= 1.0f) {
-                norm.set(0.0f, 0.0f, 1.0f);
-            } else {
-                norm.fZ = sqrtf(1.0f - tmp);
-            }
-
-            norm_to_rgb(bm, x, y, norm);
-        }
-    }
-}
-
-void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) {
-    const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
-                                         dst.fTop + (dst.height() / 2.0f));
-
-    SkIRect inner = dst;
-    inner.inset(dst.width()/4, dst.height()/4);
-
-    SkPoint3 norm;
-    const SkPoint3 left =  SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
-    const SkPoint3 up =    SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
-    const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2,  0.0f, SK_ScalarRoot2Over2);
-    const SkPoint3 down =  SkPoint3::Make(0.0f,  SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
-
-    for (int y = dst.fTop; y < dst.fBottom; ++y) {
-        for (int x = dst.fLeft; x < dst.fRight; ++x) {
-            if (inner.contains(x, y)) {
-                norm.set(0.0f, 0.0f, 1.0f);
-            } else {
-                SkScalar locX = x + 0.5f - center.fX;
-                SkScalar locY = y + 0.5f - center.fY;
-
-                if (locX >= 0.0f) {
-                    if (locY > 0.0f) {
-                        norm = locX >= locY ? right : down;   // LR corner
-                    } else {
-                        norm = locX > -locY ? right : up;     // UR corner
-                    }
-                } else {
-                    if (locY > 0.0f) {
-                        norm = -locX > locY ? left : down;    // LL corner
-                    } else {
-                        norm = locX > locY ? up : left;       // UL corner
-                    }
-                }
-            }
-
-            norm_to_rgb(bm, x, y, norm);
-        }
-    }
-}
-
-void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) {
-    const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
-                                         dst.fTop + (dst.height() / 2.0f));
-
-    static const SkScalar k1OverRoot3 = 0.5773502692f;
-
-    SkPoint3 norm;
-    const SkPoint3 leftUp =  SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3);
-    const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3,  -k1OverRoot3, k1OverRoot3);
-    const SkPoint3 down =  SkPoint3::Make(0.0f,  SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
-
-    for (int y = dst.fTop; y < dst.fBottom; ++y) {
-        for (int x = dst.fLeft; x < dst.fRight; ++x) {
-            SkScalar locX = x + 0.5f - center.fX;
-            SkScalar locY = y + 0.5f - center.fY;
-
-            if (locX >= 0.0f) {
-                if (locY > 0.0f) {
-                    norm = locX >= locY ? rightUp : down;   // LR corner
-                } else {
-                    norm = rightUp;
-                }
-            } else {
-                if (locY > 0.0f) {
-                    norm = -locX > locY ? leftUp : down;    // LL corner
-                } else {
-                    norm = leftUp;
-                }
-            }
-
-            norm_to_rgb(bm, x, y, norm);
-        }
-    }
-}
-
-#if defined(_MSC_VER)
-    // MSVC takes ~2 minutes to compile this function with optimization.
-    // We don't really care to wait that long for this function.
-    #pragma optimize("", off)
-#endif
-void make_big_path(SkPath& path) {
-    #include "BigPathBench.inc"
-}
-
-static float gaussian2d_value(int x, int y, float sigma) {
-    // don't bother with the scale term since we're just going to normalize the
-    // kernel anyways
-    float temp = expf(-(x*x + y*y)/(2*sigma*sigma));
-    return temp;
-}
-
-static float* create_2d_kernel(float sigma, int* filterSize) {
-    // We will actually take 2*halfFilterSize+1 samples (i.e., our filter kernel
-    // sizes are always odd)
-    int halfFilterSize = SkScalarCeilToInt(6*sigma)/2;
-    int wh = *filterSize = 2*halfFilterSize + 1;
-
-    float* temp = new float[wh*wh];
-
-    float filterTot = 0.0f;
-    for (int yOff = 0; yOff < wh; ++yOff) {
-        for (int xOff = 0; xOff < wh; ++xOff) {
-            temp[yOff*wh+xOff] = gaussian2d_value(xOff-halfFilterSize, yOff-halfFilterSize, sigma);
-
-            filterTot += temp[yOff*wh+xOff];
-        }
-    }
-
-    // normalize the kernel
-    for (int yOff = 0; yOff < wh; ++yOff) {
-        for (int xOff = 0; xOff < wh; ++xOff) {
-            temp[yOff*wh+xOff] /= filterTot;
-        }
-    }
-
-    return temp;
-}
-
-static SkPMColor blur_pixel(const SkBitmap& bm, int x, int y, float* kernel, int wh) {
-    SkASSERT(wh & 0x1);
-
-    int halfFilterSize = (wh-1)/2;
-
-    float r = 0.0f, g = 0.0f, b = 0.0f;
-    for (int yOff = 0; yOff < wh; ++yOff) {
-        int ySamp = y + yOff - halfFilterSize;
-
-        if (ySamp < 0) {
-            ySamp = 0;
-        } else if (ySamp > bm.height()-1) {
-            ySamp = bm.height()-1;
-        }
-
-        for (int xOff = 0; xOff < wh; ++xOff) {
-            int xSamp = x + xOff - halfFilterSize;
-
-            if (xSamp < 0) {
-                xSamp = 0;
-            } else if (xSamp > bm.width()-1) {
-                xSamp = bm.width()-1;
-            }
-
-            float filter = kernel[yOff*wh + xOff];
-
-            SkPMColor c = *bm.getAddr32(xSamp, ySamp);
-
-            r += SkGetPackedR32(c) * filter;
-            g += SkGetPackedG32(c) * filter;
-            b += SkGetPackedB32(c) * filter;
-        }
-    }
-
-    U8CPU r8, g8, b8;
-
-    r8 = (U8CPU) (r+0.5f);
-    g8 = (U8CPU) (g+0.5f);
-    b8 = (U8CPU) (b+0.5f);
-
-    return SkPackARGB32(255, r8, g8, b8);
-}
-
-SkBitmap slow_blur(const SkBitmap& src, float sigma) {
-    SkBitmap dst;
-
-    dst.allocN32Pixels(src.width(), src.height(), true);
-
-    int wh;
-    std::unique_ptr<float[]> kernel(create_2d_kernel(sigma, &wh));
-
-    for (int y = 0; y < src.height(); ++y) {
-        for (int x = 0; x < src.width(); ++x) {
-            *dst.getAddr32(x, y) = blur_pixel(src, x, y, kernel.get(), wh);
-        }
-    }
-
-    return dst;
-}
-
-// compute the intersection point between the diagonal and the ellipse in the
-// lower right corner
-static SkPoint intersection(SkScalar w, SkScalar h) {
-    SkASSERT(w > 0.0f || h > 0.0f);
-
-    return SkPoint::Make(w / SK_ScalarSqrt2, h / SK_ScalarSqrt2);
-}
-
-// Use the intersection of the corners' diagonals with their ellipses to shrink
-// the bounding rect
-SkRect compute_central_occluder(const SkRRect& rr) {
-    const SkRect r = rr.getBounds();
-
-    SkScalar newL = r.fLeft, newT = r.fTop, newR = r.fRight, newB = r.fBottom;
-
-    SkVector radii = rr.radii(SkRRect::kUpperLeft_Corner);
-    if (!radii.isZero()) {
-        SkPoint p = intersection(radii.fX, radii.fY);
-
-        newL = SkTMax(newL, r.fLeft + radii.fX - p.fX);
-        newT = SkTMax(newT, r.fTop + radii.fY - p.fY);
-    }
-
-    radii = rr.radii(SkRRect::kUpperRight_Corner);
-    if (!radii.isZero()) {
-        SkPoint p = intersection(radii.fX, radii.fY);
-
-        newR = SkTMin(newR, r.fRight + p.fX - radii.fX);
-        newT = SkTMax(newT, r.fTop + radii.fY - p.fY);
-    }
-
-    radii = rr.radii(SkRRect::kLowerRight_Corner);
-    if (!radii.isZero()) {
-        SkPoint p = intersection(radii.fX, radii.fY);
-
-        newR = SkTMin(newR, r.fRight + p.fX - radii.fX);
-        newB = SkTMin(newB, r.fBottom - radii.fY + p.fY);
-    }
-
-    radii = rr.radii(SkRRect::kLowerLeft_Corner);
-    if (!radii.isZero()) {
-        SkPoint p = intersection(radii.fX, radii.fY);
-
-        newL = SkTMax(newL, r.fLeft + radii.fX - p.fX);
-        newB = SkTMin(newB, r.fBottom - radii.fY + p.fY);
-    }
-
-    return SkRect::MakeLTRB(newL, newT, newR, newB);
-}
-
-// The widest inset rect
-SkRect compute_widest_occluder(const SkRRect& rr) {
-    const SkRect& r = rr.getBounds();
-
-    const SkVector& ul = rr.radii(SkRRect::kUpperLeft_Corner);
-    const SkVector& ur = rr.radii(SkRRect::kUpperRight_Corner);
-    const SkVector& lr = rr.radii(SkRRect::kLowerRight_Corner);
-    const SkVector& ll = rr.radii(SkRRect::kLowerLeft_Corner);
-
-    SkScalar maxT = SkTMax(ul.fY, ur.fY);
-    SkScalar maxB = SkTMax(ll.fY, lr.fY);
-
-    return SkRect::MakeLTRB(r.fLeft, r.fTop + maxT, r.fRight, r.fBottom - maxB);
-
-}
-
-// The tallest inset rect
-SkRect compute_tallest_occluder(const SkRRect& rr) {
-    const SkRect& r = rr.getBounds();
-
-    const SkVector& ul = rr.radii(SkRRect::kUpperLeft_Corner);
-    const SkVector& ur = rr.radii(SkRRect::kUpperRight_Corner);
-    const SkVector& lr = rr.radii(SkRRect::kLowerRight_Corner);
-    const SkVector& ll = rr.radii(SkRRect::kLowerLeft_Corner);
-
-    SkScalar maxL = SkTMax(ul.fX, ll.fX);
-    SkScalar maxR = SkTMax(ur.fX, lr.fX);
-
-    return SkRect::MakeLTRB(r.fLeft + maxL, r.fTop, r.fRight - maxR, r.fBottom);
-}
-
-bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
-    SkPixmap srcPM;
-    if (!src.peekPixels(&srcPM)) {
-        return false;
-    }
-
-    SkBitmap tmpDst;
-    SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
-    if (!tmpDst.setInfo(dstInfo)) {
-        return false;
-    }
-
-    if (!tmpDst.tryAllocPixels()) {
-        return false;
-    }
-
-    SkPixmap dstPM;
-    if (!tmpDst.peekPixels(&dstPM)) {
-        return false;
-    }
-
-    if (!srcPM.readPixels(dstPM)) {
-        return false;
-    }
-
-    dst->swap(tmpDst);
-    return true;
-}
-
-void copy_to_g8(SkBitmap* dst, const SkBitmap& src) {
-    SkASSERT(kBGRA_8888_SkColorType == src.colorType() ||
-             kRGBA_8888_SkColorType == src.colorType());
-
-    SkImageInfo grayInfo = src.info().makeColorType(kGray_8_SkColorType);
-    dst->allocPixels(grayInfo);
-    uint8_t* dst8 = (uint8_t*)dst->getPixels();
-    const uint32_t* src32 = (const uint32_t*)src.getPixels();
-
-    const int w = src.width();
-    const int h = src.height();
-    const bool isBGRA = (kBGRA_8888_SkColorType == src.colorType());
-    for (int y = 0; y < h; ++y) {
-        if (isBGRA) {
-            // BGRA
-            for (int x = 0; x < w; ++x) {
-                uint32_t s = src32[x];
-                dst8[x] = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF);
-            }
-        } else {
-            // RGBA
-            for (int x = 0; x < w; ++x) {
-                uint32_t s = src32[x];
-                dst8[x] = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF);
-            }
-        }
-        src32 = (const uint32_t*)((const char*)src32 + src.rowBytes());
-        dst8 += dst->rowBytes();
-    }
-}
-
-}  // namespace sk_tool_utils
diff --git a/src/third_party/skia/tools/sk_tool_utils.h b/src/third_party/skia/tools/sk_tool_utils.h
deleted file mode 100644
index 6283225..0000000
--- a/src/third_party/skia/tools/sk_tool_utils.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef sk_tool_utils_DEFINED
-#define sk_tool_utils_DEFINED
-
-#include "SkColor.h"
-#include "SkImageEncoder.h"
-#include "SkImageInfo.h"
-#include "SkPixelSerializer.h"
-#include "SkRandom.h"
-#include "SkStream.h"
-#include "SkTDArray.h"
-#include "SkTypeface.h"
-
-class SkBitmap;
-class SkCanvas;
-class SkColorFilter;
-class SkPaint;
-class SkPath;
-class SkRRect;
-class SkShader;
-class SkTestFont;
-class SkTextBlobBuilder;
-
-namespace sk_tool_utils {
-
-    const char* colortype_name(SkColorType);
-
-    /**
-     * Map opaque colors from 8888 to 565.
-     */
-    SkColor color_to_565(SkColor color);
-
-    /**
-     * Return a color emoji typeface if available.
-     */
-    sk_sp<SkTypeface> emoji_typeface();
-
-    /**
-     * If the platform supports color emoji, return sample text the emoji can render.
-     */
-    const char* emoji_sample_text();
-
-    /**
-     * If the platform supports color emoji, return the type (i.e. "CBDT", "SBIX", "").
-     */
-    const char* platform_os_emoji();
-
-    /**
-     * Return the platform name with the version number ("Mac10.9", "Win8", etc.) if available.
-     */
-    const char* platform_os_name();
-
-    /**
-     * Return the platform name without the version number ("Mac", "Win", etc.) if available.
-     */
-    SkString major_platform_os_name();
-
-    /**
-     * Return the platform extra config (e.g. "GDI") if available.
-     */
-    const char* platform_extra_config(const char* config);
-
-    /**
-     * Map serif, san-serif, and monospace to the platform-specific font name.
-     */
-    const char* platform_font_name(const char* name);
-
-    /**
-     * Sets the paint to use a platform-independent text renderer
-     */
-    void set_portable_typeface(SkPaint* paint, const char* name = nullptr,
-                               SkFontStyle style = SkFontStyle());
-
-    /**
-     * Returns a platform-independent text renderer.
-     */
-    sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style);
-
-    /** Call to clean up portable font references. */
-    void release_portable_typefaces();
-
-    /**
-     *  Call canvas->writePixels() by using the pixels from bitmap, but with an info that claims
-     *  the pixels are colorType + alphaType
-     */
-    void write_pixels(SkCanvas*, const SkBitmap&, int x, int y, SkColorType, SkAlphaType);
-
-    // private to sk_tool_utils
-    sk_sp<SkTypeface> create_font(const char* name, SkFontStyle);
-
-    /** Returns a newly created CheckerboardShader. */
-    sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size);
-
-    /** Draw a checkerboard pattern in the current canvas, restricted to
-        the current clip, using SkXfermode::kSrc_Mode. */
-    void draw_checkerboard(SkCanvas* canvas,
-                           SkColor color1,
-                           SkColor color2,
-                           int checkSize);
-
-    /** Make it easier to create a bitmap-based checkerboard */
-    SkBitmap create_checkerboard_bitmap(int w, int h,
-                                        SkColor c1, SkColor c2,
-                                        int checkSize);
-
-    /** A default checkerboard. */
-    inline void draw_checkerboard(SkCanvas* canvas) {
-        sk_tool_utils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8);
-    }
-
-    SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y,
-                                  int textSize, const char* str);
-
-    // A helper for inserting a drawtext call into a SkTextBlobBuilder
-    void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint,
-                          SkScalar x, SkScalar y);
-
-    void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst);
-
-    void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst);
-
-    void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst);
-
-    void make_big_path(SkPath& path);
-
-    // Return a blurred version of 'src'. This doesn't use a separable filter
-    // so it is slow!
-    SkBitmap slow_blur(const SkBitmap& src, float sigma);
-
-    SkRect compute_central_occluder(const SkRRect& rr);
-    SkRect compute_widest_occluder(const SkRRect& rr);
-    SkRect compute_tallest_occluder(const SkRRect& rr);
-
-    // A helper object to test the topological sorting code (TopoSortBench.cpp & TopoSortTest.cpp)
-    class TopoTestNode {
-    public:
-        TopoTestNode(int id) : fID(id), fOutputPos(-1), fTempMark(false) { }
-
-        void dependsOn(TopoTestNode* src) {
-            *fDependencies.append() = src;
-        }
-
-        int id() const { return fID; }
-        void reset() { fOutputPos = -1; }
-
-        int outputPos() const { return fOutputPos; }
-
-        // check that the topological sort is valid for this node
-        bool check() {
-            if (-1 == fOutputPos) {
-                return false;
-            }
-
-            for (int i = 0; i < fDependencies.count(); ++i) {
-                if (-1 == fDependencies[i]->outputPos()) {
-                    return false;
-                }
-                // This node should've been output after all the nodes on which it depends
-                if (fOutputPos < fDependencies[i]->outputPos()) {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        // The following 7 methods are needed by the topological sort
-        static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; }
-        static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; }
-        static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; }
-        static void Output(TopoTestNode* node, int outputPos) {
-            SkASSERT(-1 != outputPos);
-            node->fOutputPos = outputPos;
-        }
-        static bool WasOutput(TopoTestNode* node) { return (-1 != node->fOutputPos); }
-        static int NumDependencies(TopoTestNode* node) { return node->fDependencies.count(); }
-        static TopoTestNode* Dependency(TopoTestNode* node, int index) {
-            return node->fDependencies[index];
-        }
-
-        // Helper functions for TopoSortBench & TopoSortTest
-        static void AllocNodes(SkTDArray<TopoTestNode*>* graph, int num) {
-            graph->setReserve(num);
-
-            for (int i = 0; i < num; ++i) {
-                *graph->append() = new TopoTestNode(i);
-            }
-        }
-
-        static void DeallocNodes(SkTDArray<TopoTestNode*>* graph) {
-            for (int i = 0; i < graph->count(); ++i) {
-                delete (*graph)[i];
-            }
-        }
-
-        #ifdef SK_DEBUG
-        static void Print(const SkTDArray<TopoTestNode*>& graph) {
-            for (int i = 0; i < graph.count(); ++i) {
-                SkDebugf("%d, ", graph[i]->id());
-            }
-            SkDebugf("\n");
-        }
-        #endif
-
-        // randomize the array
-        static void Shuffle(SkTDArray<TopoTestNode*>* graph, SkRandom* rand) {
-            for (int i = graph->count()-1; i > 0; --i) {
-                int swap = rand->nextU() % (i+1);
-
-                TopoTestNode* tmp = (*graph)[i];
-                (*graph)[i] = (*graph)[swap];
-                (*graph)[swap] = tmp;
-            }
-        }
-
-    private:
-        int  fID;
-        int  fOutputPos;
-        bool fTempMark;
-
-        SkTDArray<TopoTestNode*> fDependencies;
-    };
-
-    template <typename T>
-    inline bool EncodeImageToFile(const char* path, const T& src, SkEncodedImageFormat f, int q) {
-        SkFILEWStream file(path);
-        return file.isValid() && SkEncodeImage(&file, src, f, q);
-    }
-
-    template <typename T>
-    inline sk_sp<SkData> EncodeImageToData(const T& src, SkEncodedImageFormat f, int q) {
-        SkDynamicMemoryWStream buf;
-        return SkEncodeImage(&buf, src , f, q) ? buf.detachAsData() : nullptr;
-    }
-
-    /**
-     * Uses SkEncodeImage to serialize images that are not already
-     * encoded as SkEncodedImageFormat::kPNG images.
-     */
-    inline sk_sp<SkPixelSerializer> MakePixelSerializer() {
-        struct EncodeImagePixelSerializer final : SkPixelSerializer {
-            bool onUseEncodedData(const void*, size_t) override { return true; }
-            SkData* onEncode(const SkPixmap& pmap) override {
-                return EncodeImageToData(pmap, SkEncodedImageFormat::kPNG, 100).release();
-            }
-        };
-        return sk_make_sp<EncodeImagePixelSerializer>();
-    }
-
-    bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src);
-    void copy_to_g8(SkBitmap* dst, const SkBitmap& src);
-
-}  // namespace sk_tool_utils
-
-#endif  // sk_tool_utils_DEFINED
diff --git a/src/third_party/skia/tools/sk_tool_utils_flags.h b/src/third_party/skia/tools/sk_tool_utils_flags.h
deleted file mode 100644
index ee15fbd..0000000
--- a/src/third_party/skia/tools/sk_tool_utils_flags.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef sk_tool_utils_flags_DEFINED
-#define sk_tool_utils_flags_DEFINED
-
-#include "SkCommandLineFlags.h"
-
-DECLARE_bool(portableFonts);
-DECLARE_bool(resourceFonts);
-
-#endif  // sk_tool_utils_flags_DEFINED
diff --git a/src/third_party/skia/tools/sk_tool_utils_font.cpp b/src/third_party/skia/tools/sk_tool_utils_font.cpp
deleted file mode 100644
index bdd88d0..0000000
--- a/src/third_party/skia/tools/sk_tool_utils_font.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Resources.h"
-#include "SkFontMgr.h"
-#include "SkMutex.h"
-#include "SkOSFile.h"
-#include "SkTestScalerContext.h"
-#include "SkUtils.h"
-#include "sk_tool_utils.h"
-
-namespace sk_tool_utils {
-
-#include "test_font_monospace.inc"
-#include "test_font_sans_serif.inc"
-#include "test_font_serif.inc"
-#include "test_font_index.inc"
-
-void release_portable_typefaces() {
-    for (int index = 0; index < gTestFontsCount; ++index) {
-        SkTestFontData& fontData = gTestFonts[index];
-        fontData.fCachedFont.reset();
-    }
-}
-
-SK_DECLARE_STATIC_MUTEX(gTestFontMutex);
-
-sk_sp<SkTypeface> create_font(const char* name, SkFontStyle style) {
-    SkTestFontData* fontData = nullptr;
-    const SubFont* sub;
-    if (name) {
-        for (int index = 0; index < gSubFontsCount; ++index) {
-            sub = &gSubFonts[index];
-            if (!strcmp(name, sub->fName) && sub->fStyle == style) {
-                fontData = &sub->fFont;
-                break;
-            }
-        }
-        if (!fontData) {
-            // Once all legacy callers to portable fonts are converted, replace this with
-            // SK_ABORT();
-            SkDebugf("missing %s weight %d, width %d, slant %d\n",
-                     name, style.weight(), style.width(), style.slant());
-            // If we called SkTypeface::CreateFromName() here we'd recurse infinitely,
-            // so we reimplement its core logic here inline without the recursive aspect.
-            sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-            return sk_sp<SkTypeface>(fm->legacyCreateTypeface(name, style));
-        }
-    } else {
-        sub = &gSubFonts[gDefaultFontIndex];
-        fontData = &sub->fFont;
-    }
-    sk_sp<SkTestFont> font;
-    {
-        SkAutoMutexAcquire ac(gTestFontMutex);
-        if (fontData->fCachedFont) {
-            font = fontData->fCachedFont;
-        } else {
-            font = sk_make_sp<SkTestFont>(*fontData);
-            SkDEBUGCODE(font->fDebugName = sub->fName);
-            SkDEBUGCODE(font->fDebugStyle = sub->fStyle);
-            fontData->fCachedFont = font;
-        }
-    }
-    return sk_make_sp<SkTestTypeface>(std::move(font), style);
-}
-
-}
diff --git a/src/third_party/skia/tools/skdiff/skdiff.cpp b/src/third_party/skia/tools/skdiff/skdiff.cpp
index c7ddf7d..f1abc9f 100644
--- a/src/third_party/skia/tools/skdiff/skdiff.cpp
+++ b/src/third_party/skia/tools/skdiff/skdiff.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "skdiff.h"
-#include "SkBitmap.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkTypes.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkColorPriv.h"
+#include "include/core/SkTypes.h"
+#include "tools/skdiff/skdiff.h"
 
 /*static*/ char const * const DiffRecord::ResultNames[DiffRecord::kResultCount] = {
     "EqualBits",
diff --git a/src/third_party/skia/tools/skdiff/skdiff.h b/src/third_party/skia/tools/skdiff/skdiff.h
index 6bdaadc..4ab79b8 100644
--- a/src/third_party/skia/tools/skdiff/skdiff.h
+++ b/src/third_party/skia/tools/skdiff/skdiff.h
@@ -8,13 +8,13 @@
 #ifndef skdiff_DEFINED
 #define skdiff_DEFINED
 
-#include "SkBitmap.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkString.h"
-#include "../private/SkTDArray.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkColorPriv.h"
+#include "include/core/SkString.h"
+#include "include/private/SkTDArray.h"
 
-#if defined(SK_BUILD_FOR_WIN32)
+#if defined(SK_BUILD_FOR_WIN)
     #define PATH_DIV_STR "\\"
     #define PATH_DIV_CHAR '\\'
 #else
diff --git a/src/third_party/skia/tools/skdiff/skdiff_html.cpp b/src/third_party/skia/tools/skdiff/skdiff_html.cpp
index 6f3c3b0..4e5a83c 100644
--- a/src/third_party/skia/tools/skdiff/skdiff_html.cpp
+++ b/src/third_party/skia/tools/skdiff/skdiff_html.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "skdiff.h"
-#include "skdiff_html.h"
-#include "SkStream.h"
-#include "SkTime.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTime.h"
+#include "tools/skdiff/skdiff.h"
+#include "tools/skdiff/skdiff_html.h"
 
 /// Make layout more consistent by scaling image to 240 height, 360 width,
 /// or natural size, whichever is smallest.
@@ -245,7 +245,7 @@
     if (outputDir.size() > 0 && PATH_DIV_CHAR == outputDir[0]) {
         isPathAbsolute = true;
     }
-#ifdef SK_BUILD_FOR_WIN32
+#ifdef SK_BUILD_FOR_WIN
     // On Windows, absolute paths can also start with "x:", where x is any
     // drive letter.
     if (outputDir.size() > 1 && ':' == outputDir[1]) {
diff --git a/src/third_party/skia/tools/skdiff/skdiff_html.h b/src/third_party/skia/tools/skdiff/skdiff_html.h
index eefbebf..a881498 100644
--- a/src/third_party/skia/tools/skdiff/skdiff_html.h
+++ b/src/third_party/skia/tools/skdiff/skdiff_html.h
@@ -8,7 +8,7 @@
 #ifndef skdiff_html_DEFINED
 #define skdiff_html_DEFINED
 
-#include "skdiff.h"
+#include "tools/skdiff/skdiff.h"
 class SkString;
 
 void print_diff_page(const int matchCount,
diff --git a/src/third_party/skia/tools/skdiff/skdiff_image.cpp b/src/third_party/skia/tools/skdiff/skdiff_image.cpp
deleted file mode 100644
index cb446d4..0000000
--- a/src/third_party/skia/tools/skdiff/skdiff_image.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "skdiff.h"
-#include "skdiff_utils.h"
-#include "SkBitmap.h"
-#include "SkData.h"
-#include "SkImageEncoder.h"
-#include "SkOSFile.h"
-#include "SkTypes.h"
-
-#include <stdio.h>
-
-/// If outputDir.isEmpty(), don't write out diff files.
-static void create_diff_images (DiffMetricProc dmp,
-                                const int colorThreshold,
-                                const SkString& baseFile,
-                                const SkString& comparisonFile,
-                                const SkString& outputDir,
-                                const SkString& outputFilename,
-                                DiffRecord* drp) {
-    SkASSERT(!baseFile.isEmpty());
-    SkASSERT(!comparisonFile.isEmpty());
-
-    drp->fBase.fFilename = baseFile;
-    drp->fBase.fFullPath = baseFile;
-    drp->fBase.fStatus = DiffResource::kSpecified_Status;
-
-    drp->fComparison.fFilename = comparisonFile;
-    drp->fComparison.fFullPath = comparisonFile;
-    drp->fComparison.fStatus = DiffResource::kSpecified_Status;
-
-    sk_sp<SkData> baseFileBits = read_file(drp->fBase.fFullPath.c_str());
-    if (baseFileBits) {
-        drp->fBase.fStatus = DiffResource::kRead_Status;
-    }
-    sk_sp<SkData> comparisonFileBits = read_file(drp->fComparison.fFullPath.c_str());
-    if (comparisonFileBits) {
-        drp->fComparison.fStatus = DiffResource::kRead_Status;
-    }
-    if (nullptr == baseFileBits || nullptr == comparisonFileBits) {
-        if (nullptr == baseFileBits) {
-            drp->fBase.fStatus = DiffResource::kCouldNotRead_Status;
-        }
-        if (nullptr == comparisonFileBits) {
-            drp->fComparison.fStatus = DiffResource::kCouldNotRead_Status;
-        }
-        drp->fResult = DiffRecord::kCouldNotCompare_Result;
-        return;
-    }
-
-    if (are_buffers_equal(baseFileBits.get(), comparisonFileBits.get())) {
-        drp->fResult = DiffRecord::kEqualBits_Result;
-        return;
-    }
-
-    get_bitmap(baseFileBits, drp->fBase, false);
-    get_bitmap(comparisonFileBits, drp->fComparison, false);
-    if (DiffResource::kDecoded_Status != drp->fBase.fStatus ||
-        DiffResource::kDecoded_Status != drp->fComparison.fStatus)
-    {
-        drp->fResult = DiffRecord::kCouldNotCompare_Result;
-        return;
-    }
-
-    create_and_write_diff_image(drp, dmp, colorThreshold, outputDir, outputFilename);
-    //TODO: copy fBase.fFilename and fComparison.fFilename to outputDir
-    //      svn and git often present tmp files to diff tools which are promptly deleted
-
-    //TODO: serialize drp to outputDir
-    //      write a tool to deserialize them and call print_diff_page
-
-    SkASSERT(DiffRecord::kUnknown_Result != drp->fResult);
-}
-
-static void usage (char * argv0) {
-    SkDebugf("Skia image diff tool\n");
-    SkDebugf("\n"
-"Usage: \n"
-"    %s <baseFile> <comparisonFile>\n" , argv0);
-    SkDebugf(
-"\nArguments:"
-"\n    --failonresult <result>: After comparing all file pairs, exit with nonzero"
-"\n                             return code (number of file pairs yielding this"
-"\n                             result) if any file pairs yielded this result."
-"\n                             This flag may be repeated, in which case the"
-"\n                             return code will be the number of fail pairs"
-"\n                             yielding ANY of these results."
-"\n    --failonstatus <baseStatus> <comparisonStatus>: exit with nonzero return"
-"\n                             code if any file pairs yeilded this status."
-"\n    --help: display this info"
-"\n    --listfilenames: list all filenames for each result type in stdout"
-"\n    --nodiffs: don't write out image diffs, just generate report on stdout"
-"\n    --outputdir: directory to write difference images"
-"\n    --threshold <n>: only report differences > n (per color channel) [default 0]"
-"\n    -u: ignored. Recognized for compatibility with svn diff."
-"\n    -L: first occurrence label for base, second occurrence label for comparison."
-"\n        Labels must be of the form \"<filename>(\t<specifier>)?\"."
-"\n        The base <filename> will be used to create files in outputdir."
-"\n"
-"\n    baseFile: baseline image file."
-"\n    comparisonFile: comparison image file"
-"\n"
-"\nIf no sort is specified, it will sort by fraction of pixels mismatching."
-"\n");
-}
-
-const int kNoError = 0;
-const int kGenericError = -1;
-
-int main(int argc, char** argv) {
-    DiffMetricProc diffProc = compute_diff_pmcolor;
-
-    // Maximum error tolerated in any one color channel in any one pixel before
-    // a difference is reported.
-    int colorThreshold = 0;
-    SkString baseFile;
-    SkString baseLabel;
-    SkString comparisonFile;
-    SkString comparisonLabel;
-    SkString outputDir;
-
-    bool listFilenames = false;
-
-    bool failOnResultType[DiffRecord::kResultCount];
-    for (int i = 0; i < DiffRecord::kResultCount; i++) {
-        failOnResultType[i] = false;
-    }
-
-    bool failOnStatusType[DiffResource::kStatusCount][DiffResource::kStatusCount];
-    for (int base = 0; base < DiffResource::kStatusCount; ++base) {
-        for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
-            failOnStatusType[base][comparison] = false;
-        }
-    }
-
-    int i;
-    int numUnflaggedArguments = 0;
-    int numLabelArguments = 0;
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "--failonresult")) {
-            if (argc == ++i) {
-                SkDebugf("failonresult expects one argument.\n");
-                continue;
-            }
-            DiffRecord::Result type = DiffRecord::getResultByName(argv[i]);
-            if (type != DiffRecord::kResultCount) {
-                failOnResultType[type] = true;
-            } else {
-                SkDebugf("ignoring unrecognized result <%s>\n", argv[i]);
-            }
-            continue;
-        }
-        if (!strcmp(argv[i], "--failonstatus")) {
-            if (argc == ++i) {
-                SkDebugf("failonstatus missing base status.\n");
-                continue;
-            }
-            bool baseStatuses[DiffResource::kStatusCount];
-            if (!DiffResource::getMatchingStatuses(argv[i], baseStatuses)) {
-                SkDebugf("unrecognized base status <%s>\n", argv[i]);
-            }
-
-            if (argc == ++i) {
-                SkDebugf("failonstatus missing comparison status.\n");
-                continue;
-            }
-            bool comparisonStatuses[DiffResource::kStatusCount];
-            if (!DiffResource::getMatchingStatuses(argv[i], comparisonStatuses)) {
-                SkDebugf("unrecognized comarison status <%s>\n", argv[i]);
-            }
-
-            for (int base = 0; base < DiffResource::kStatusCount; ++base) {
-                for (int comparison = 0; comparison < DiffResource::kStatusCount; ++comparison) {
-                    failOnStatusType[base][comparison] |=
-                        baseStatuses[base] && comparisonStatuses[comparison];
-                }
-            }
-            continue;
-        }
-        if (!strcmp(argv[i], "--help")) {
-            usage(argv[0]);
-            return kNoError;
-        }
-        if (!strcmp(argv[i], "--listfilenames")) {
-            listFilenames = true;
-            continue;
-        }
-        if (!strcmp(argv[i], "--outputdir")) {
-            if (argc == ++i) {
-                SkDebugf("outputdir expects one argument.\n");
-                continue;
-            }
-            outputDir.set(argv[i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "--threshold")) {
-            colorThreshold = atoi(argv[++i]);
-            continue;
-        }
-        if (!strcmp(argv[i], "-u")) {
-            //we don't produce unified diffs, ignore parameter to work with svn diff
-            continue;
-        }
-        if (!strcmp(argv[i], "-L")) {
-            if (argc == ++i) {
-                SkDebugf("label expects one argument.\n");
-                continue;
-            }
-            switch (numLabelArguments++) {
-                case 0:
-                    baseLabel.set(argv[i]);
-                    continue;
-                case 1:
-                    comparisonLabel.set(argv[i]);
-                    continue;
-                default:
-                    SkDebugf("extra label argument <%s>\n", argv[i]);
-                    usage(argv[0]);
-                    return kGenericError;
-            }
-            continue;
-        }
-        if (argv[i][0] != '-') {
-            switch (numUnflaggedArguments++) {
-                case 0:
-                    baseFile.set(argv[i]);
-                    continue;
-                case 1:
-                    comparisonFile.set(argv[i]);
-                    continue;
-                default:
-                    SkDebugf("extra unflagged argument <%s>\n", argv[i]);
-                    usage(argv[0]);
-                    return kGenericError;
-            }
-        }
-
-        SkDebugf("Unrecognized argument <%s>\n", argv[i]);
-        usage(argv[0]);
-        return kGenericError;
-    }
-
-    if (numUnflaggedArguments != 2) {
-        usage(argv[0]);
-        return kGenericError;
-    }
-
-    if (listFilenames) {
-        printf("Base file is [%s]\n", baseFile.c_str());
-    }
-
-    if (listFilenames) {
-        printf("Comparison file is [%s]\n", comparisonFile.c_str());
-    }
-
-    if (outputDir.isEmpty()) {
-        if (listFilenames) {
-            printf("Not writing any diffs. No output dir specified.\n");
-        }
-    } else {
-        if (!outputDir.endsWith(PATH_DIV_STR)) {
-            outputDir.append(PATH_DIV_STR);
-        }
-        if (listFilenames) {
-            printf("Writing diffs. Output dir is [%s]\n", outputDir.c_str());
-        }
-    }
-
-    // Some obscure documentation about diff/patch labels:
-    //
-    // Posix says the format is: <filename><tab><date>
-    //     It also states that if a filename contains <tab> or <newline>
-    //     the result is implementation defined
-    //
-    // Svn diff --diff-cmd provides labels of the form: <filename><tab><revision>
-    //
-    // Git diff --ext-diff does not supply arguments compatible with diff.
-    //     However, it does provide the filename directly.
-    //     skimagediff_git.sh: skimagediff %2 %5 -L "%1\t(%3)" -L "%1\t(%6)"
-    //
-    // Git difftool sets $LOCAL, $REMOTE, $MERGED, and $BASE instead of command line parameters.
-    //     difftool.<>.cmd: skimagediff $LOCAL $REMOTE -L "$MERGED\t(local)" -L "$MERGED\t(remote)"
-    //
-    // Diff will write any specified label verbatim. Without a specified label diff will write
-    //     <filename><tab><date>
-    //     However, diff will encode the filename as a cstring if the filename contains
-    //         Any of <space> or <double quote>
-    //         A char less than 32
-    //         Any escapable character \\, \a, \b, \t, \n, \v, \f, \r
-    //
-    // Patch decodes:
-    //     If first <non-white-space> is <double quote>, parse filename from cstring.
-    //     If there is a <tab> after the first <non-white-space>, filename is
-    //         [first <non-white-space>, the next run of <white-space> with an embedded <tab>).
-    //     Otherwise the filename is [first <non-space>, the next <white-space>).
-    //
-    // The filename /dev/null means the file does not exist (used in adds and deletes).
-
-    // Considering the above, skimagediff will consider the contents of a -L parameter as
-    //     <filename>(\t<specifier>)?
-    SkString outputFile;
-
-    if (baseLabel.isEmpty()) {
-        baseLabel.set(baseFile);
-        outputFile = baseLabel;
-    } else {
-        const char* baseLabelCstr = baseLabel.c_str();
-        const char* tab = strchr(baseLabelCstr, '\t');
-        if (nullptr == tab) {
-            outputFile = baseLabel;
-        } else {
-            outputFile.set(baseLabelCstr, tab - baseLabelCstr);
-        }
-    }
-    if (comparisonLabel.isEmpty()) {
-        comparisonLabel.set(comparisonFile);
-    }
-    printf("Base:       %s\n", baseLabel.c_str());
-    printf("Comparison: %s\n", comparisonLabel.c_str());
-
-    DiffRecord dr;
-    create_diff_images(diffProc, colorThreshold, baseFile, comparisonFile, outputDir, outputFile,
-                       &dr);
-
-    if (DiffResource::isStatusFailed(dr.fBase.fStatus)) {
-        printf("Base %s.\n", DiffResource::getStatusDescription(dr.fBase.fStatus));
-    }
-    if (DiffResource::isStatusFailed(dr.fComparison.fStatus)) {
-        printf("Comparison %s.\n", DiffResource::getStatusDescription(dr.fComparison.fStatus));
-    }
-    printf("Base and Comparison %s.\n", DiffRecord::getResultDescription(dr.fResult));
-
-    if (DiffRecord::kDifferentPixels_Result == dr.fResult) {
-        printf("%.4f%% of pixels differ", 100 * dr.fFractionDifference);
-        printf(" (%.4f%%  weighted)", 100 * dr.fWeightedFraction);
-        if (dr.fFractionDifference < 0.01) {
-            printf(" %d pixels", static_cast<int>(dr.fFractionDifference *
-                                                  dr.fBase.fBitmap.width() *
-                                                  dr.fBase.fBitmap.height()));
-        }
-
-        printf("\nAverage color mismatch: ");
-        printf("%d", static_cast<int>(MAX3(dr.fAverageMismatchR,
-                                           dr.fAverageMismatchG,
-                                           dr.fAverageMismatchB)));
-        printf("\nMax color mismatch: ");
-        printf("%d", MAX3(dr.fMaxMismatchR,
-                          dr.fMaxMismatchG,
-                          dr.fMaxMismatchB));
-        printf("\n");
-    }
-    printf("\n");
-
-    int num_failing_results = 0;
-    if (failOnResultType[dr.fResult]) {
-        ++num_failing_results;
-    }
-    if (failOnStatusType[dr.fBase.fStatus][dr.fComparison.fStatus]) {
-        ++num_failing_results;
-    }
-
-    return num_failing_results;
-}
diff --git a/src/third_party/skia/tools/skdiff/skdiff_main.cpp b/src/third_party/skia/tools/skdiff/skdiff_main.cpp
index 59e9b0a..df6e2a1 100644
--- a/src/third_party/skia/tools/skdiff/skdiff_main.cpp
+++ b/src/third_party/skia/tools/skdiff/skdiff_main.cpp
@@ -4,18 +4,18 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "skdiff.h"
-#include "skdiff_html.h"
-#include "skdiff_utils.h"
-#include "SkBitmap.h"
-#include "SkData.h"
-#include "SkImageEncoder.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkStream.h"
-#include "SkPixelRef.h"
-#include "../private/SkTDArray.h"
-#include "../private/SkTSearch.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImageEncoder.h"
+#include "include/core/SkPixelRef.h"
+#include "include/core/SkStream.h"
+#include "include/private/SkTDArray.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkTSearch.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/skdiff/skdiff.h"
+#include "tools/skdiff/skdiff_html.h"
+#include "tools/skdiff/skdiff_utils.h"
 
 #include <stdlib.h>
 
@@ -183,14 +183,14 @@
         uint32_t mismatchValue;
 
         if (drp->fBase.fFilename.equals(drp->fComparison.fFilename)) {
-            fResultsOfType[drp->fResult].push(new SkString(drp->fBase.fFilename));
+            fResultsOfType[drp->fResult].push_back(new SkString(drp->fBase.fFilename));
         } else {
             SkString* blame = new SkString("(");
             blame->append(drp->fBase.fFilename);
             blame->append(", ");
             blame->append(drp->fComparison.fFilename);
             blame->append(")");
-            fResultsOfType[drp->fResult].push(blame);
+            fResultsOfType[drp->fResult].push_back(blame);
         }
         switch (drp->fResult) {
           case DiffRecord::kEqualBits_Result:
@@ -215,7 +215,7 @@
             break;
           case DiffRecord::kCouldNotCompare_Result:
             fNumMismatches++;
-            fStatusOfType[drp->fBase.fStatus][drp->fComparison.fStatus].push(
+            fStatusOfType[drp->fBase.fStatus][drp->fComparison.fStatus].push_back(
                     new SkString(drp->fBase.fFilename));
             break;
           case DiffRecord::kUnknown_Result:
@@ -274,7 +274,7 @@
         pathRelativeToRootDir.append(fileName);
         if (string_contains_any_of(pathRelativeToRootDir, matchSubstrings) &&
             !string_contains_any_of(pathRelativeToRootDir, nomatchSubstrings)) {
-            files->push(new SkString(pathRelativeToRootDir));
+            files->push_back(new SkString(pathRelativeToRootDir));
         }
     }
 
@@ -344,7 +344,7 @@
     if (resource.fBitmap.empty() && !DiffResource::isStatusFailed(resource.fStatus)) {
         sk_sp<SkData> fileBits(read_file(resource.fFullPath.c_str()));
         if (fileBits) {
-            get_bitmap(fileBits, resource, true);
+            get_bitmap(fileBits, resource, true, true);
         } else {
             SkDebugf("WARNING: couldn't read %s file <%s>\n", name, resource.fFullPath.c_str());
             resource.fStatus = DiffResource::kCouldNotRead_Status;
@@ -375,6 +375,7 @@
 /// If outputDir.isEmpty(), don't write out diff files.
 static void create_diff_images (DiffMetricProc dmp,
                                 const int colorThreshold,
+                                bool ignoreColorSpace,
                                 RecordArray* differences,
                                 const SkString& baseDir,
                                 const SkString& comparisonDir,
@@ -495,8 +496,8 @@
                 VERBOSE_STATUS("MATCH", ANSI_COLOR_GREEN, baseFiles[i]);
             } else {
                 AutoReleasePixels arp(drp);
-                get_bitmap(baseFileBits, drp->fBase, false);
-                get_bitmap(comparisonFileBits, drp->fComparison, false);
+                get_bitmap(baseFileBits, drp->fBase, false, ignoreColorSpace);
+                get_bitmap(comparisonFileBits, drp->fComparison, false, ignoreColorSpace);
                 VERBOSE_STATUS("DIFFERENT", ANSI_COLOR_RED, baseFiles[i]);
                 if (DiffResource::kDecoded_Status == drp->fBase.fStatus &&
                     DiffResource::kDecoded_Status == drp->fComparison.fStatus) {
@@ -515,7 +516,7 @@
             get_bounds(*drp);
         }
         SkASSERT(DiffRecord::kUnknown_Result != drp->fResult);
-        differences->push(drp);
+        differences->push_back(drp);
         summary->add(drp);
     }
 
@@ -536,7 +537,7 @@
         if (getBounds) {
             get_bounds(*drp);
         }
-        differences->push(drp);
+        differences->push_back(drp);
         summary->add(drp);
     }
 
@@ -557,7 +558,7 @@
         if (getBounds) {
             get_bounds(*drp);
         }
-        differences->push(drp);
+        differences->push_back(drp);
         summary->add(drp);
     }
 
@@ -585,6 +586,7 @@
 "\n    --match <substring>: compare files whose filenames contain this substring;"
 "\n                         if unspecified, compare ALL files."
 "\n                         this flag may be repeated."
+"\n    --nocolorspace: Ignore color space of images."
 "\n    --nodiffs: don't write out image diffs or index.html, just generate"
 "\n               report on stdout"
 "\n    --nomatch <substring>: regardless of --match, DO NOT compare files whose"
@@ -630,6 +632,7 @@
     bool recurseIntoSubdirs = true;
     bool verbose = false;
     bool listFailingBase = false;
+    bool ignoreColorSpace = false;
 
     RecordArray differences;
     DiffSummary summary;
@@ -702,7 +705,11 @@
             continue;
         }
         if (!strcmp(argv[i], "--match")) {
-            matchSubstrings.push(new SkString(argv[++i]));
+            matchSubstrings.push_back(new SkString(argv[++i]));
+            continue;
+        }
+        if (!strcmp(argv[i], "--nocolorspace")) {
+            ignoreColorSpace = true;
             continue;
         }
         if (!strcmp(argv[i], "--nodiffs")) {
@@ -710,7 +717,7 @@
             continue;
         }
         if (!strcmp(argv[i], "--nomatch")) {
-            nomatchSubstrings.push(new SkString(argv[++i]));
+            nomatchSubstrings.push_back(new SkString(argv[++i]));
             continue;
         }
         if (!strcmp(argv[i], "--noprintdirs")) {
@@ -802,10 +809,10 @@
     // If no matchSubstrings were specified, match ALL strings
     // (except for whatever nomatchSubstrings were specified, if any).
     if (matchSubstrings.isEmpty()) {
-        matchSubstrings.push(new SkString(""));
+        matchSubstrings.push_back(new SkString(""));
     }
 
-    create_diff_images(diffProc, colorThreshold, &differences,
+    create_diff_images(diffProc, colorThreshold, ignoreColorSpace, &differences,
                        baseDir, comparisonDir, outputDir,
                        matchSubstrings, nomatchSubstrings, recurseIntoSubdirs, generateDiffs,
                        verbose, &summary);
diff --git a/src/third_party/skia/tools/skdiff/skdiff_utils.cpp b/src/third_party/skia/tools/skdiff/skdiff_utils.cpp
index 7a1b7e8..38468dc 100644
--- a/src/third_party/skia/tools/skdiff/skdiff_utils.cpp
+++ b/src/third_party/skia/tools/skdiff/skdiff_utils.cpp
@@ -4,15 +4,15 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "skdiff.h"
-#include "skdiff_utils.h"
-#include "sk_tool_utils.h"
-#include "SkBitmap.h"
-#include "SkCodec.h"
-#include "SkData.h"
-#include "SkImageEncoder.h"
-#include "SkStream.h"
-#include "SkTypes.h"
+#include "include/codec/SkCodec.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImageEncoder.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTypes.h"
+#include "tools/ToolUtils.h"
+#include "tools/skdiff/skdiff.h"
+#include "tools/skdiff/skdiff_utils.h"
 
 #include <memory>
 
@@ -34,15 +34,27 @@
     return data;
 }
 
-bool get_bitmap(sk_sp<SkData> fileBits, DiffResource& resource, bool sizeOnly) {
-    std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(fileBits));
+bool get_bitmap(sk_sp<SkData> fileBits, DiffResource& resource, bool sizeOnly,
+                bool ignoreColorSpace) {
+    auto codec = SkCodec::MakeFromData(fileBits);
     if (!codec) {
         SkDebugf("ERROR: could not create codec for <%s>\n", resource.fFullPath.c_str());
         resource.fStatus = DiffResource::kCouldNotDecode_Status;
         return false;
     }
 
-    if (!resource.fBitmap.setInfo(codec->getInfo().makeColorType(kN32_SkColorType))) {
+    // If we're "ignoring" color space, then we want the raw pixel values from each image, so we
+    // decode to the original color space. If we want to account for color spaces, then we want to
+    // decode each image to the same color space, so that colors that are the "same" (but encoded
+    // differently) are transformed to some canonical representation prior to comparison.
+    //
+    // TODO: Use something wider than sRGB to avoid clipping with out-of-gamut colors.
+    SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
+    if (!ignoreColorSpace) {
+        info = info.makeColorSpace(SkColorSpace::MakeSRGB());
+    }
+
+    if (!resource.fBitmap.setInfo(info.makeColorType(kN32_SkColorType))) {
         SkDebugf("ERROR: could not set bitmap info for <%s>\n", resource.fFullPath.c_str());
         resource.fStatus = DiffResource::kCouldNotDecode_Status;
         return false;
@@ -80,10 +92,9 @@
 
 bool write_bitmap(const SkString& path, const SkBitmap& bitmap) {
     SkBitmap copy;
-    sk_tool_utils::copy_to(&copy, kN32_SkColorType, bitmap);
+    ToolUtils::copy_to(&copy, kN32_SkColorType, bitmap);
     force_all_opaque(copy);
-    return sk_tool_utils::EncodeImageToFile(path.c_str(), copy,
-                                      SkEncodedImageFormat::kPNG, 100);
+    return ToolUtils::EncodeImageToFile(path.c_str(), copy, SkEncodedImageFormat::kPNG, 100);
 }
 
 /// Return a copy of the "input" string, within which we have replaced all instances
diff --git a/src/third_party/skia/tools/skdiff/skdiff_utils.h b/src/third_party/skia/tools/skdiff/skdiff_utils.h
index c799325..9a6385c 100644
--- a/src/third_party/skia/tools/skdiff/skdiff_utils.h
+++ b/src/third_party/skia/tools/skdiff/skdiff_utils.h
@@ -8,7 +8,7 @@
 #ifndef skdiff_utils_DEFINED
 #define skdiff_utils_DEFINED
 
-#include "skdiff.h"
+#include "tools/skdiff/skdiff.h"
 
 class SkBitmap;
 class SkData;
@@ -25,7 +25,8 @@
 sk_sp<SkData> read_file(const char* file_path);
 
 /** Decodes the fileBits into the resource.fBitmap. Returns false on failure. */
-bool get_bitmap(sk_sp<SkData> fileBits, DiffResource& resource, bool sizeOnly);
+bool get_bitmap(sk_sp<SkData> fileBits, DiffResource& resource, bool sizeOnly,
+                bool ignoreColorSpace);
 
 /** Writes the bitmap as a PNG to the path specified. */
 bool write_bitmap(const SkString& path, const SkBitmap& bitmap);
diff --git a/src/third_party/skia/tools/skhello.cpp b/src/third_party/skia/tools/skhello.cpp
index 2ab8069..cd84eab 100644
--- a/src/third_party/skia/tools/skhello.cpp
+++ b/src/third_party/skia/tools/skhello.cpp
@@ -5,18 +5,18 @@
  * found in the LICENSE file.
  */
 
-#include "SkCanvas.h"
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkDocument.h"
-#include "SkGraphics.h"
-#include "SkSurface.h"
-#include "SkImage.h"
-#include "SkStream.h"
-#include "SkString.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkData.h"
+#include "include/core/SkDocument.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkString.h"
+#include "include/core/SkSurface.h"
+#include "tools/flags/CommandLineFlags.h"
 
-DEFINE_string2(outFile, o, "skhello", "The filename to write the image.");
-DEFINE_string2(text, t, "Hello", "The string to write.");
+static DEFINE_string2(outFile, o, "skhello", "The filename to write the image.");
+static DEFINE_string2(text, t, "Hello", "The string to write.");
 
 static void doDraw(SkCanvas* canvas, const SkPaint& paint, const char text[]) {
     SkRect bounds = canvas->getLocalClipBounds();
@@ -44,7 +44,7 @@
 
 static bool do_document(int w, int h, const char path[], const char text[],
                         const SkPaint& paint) {
-    sk_sp<SkDocument> doc(SkDocument::MakePDF(path));
+    auto doc = SkPDF::MakeDocument(path);
     if (doc.get()) {
         SkScalar width = SkIntToScalar(w);
         SkScalar height = SkIntToScalar(h);
@@ -55,8 +55,8 @@
 }
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("");
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::SetUsage("");
+    CommandLineFlags::Parse(argc, argv);
 
     SkAutoGraphics ag;
     SkString path("skhello");
diff --git a/src/third_party/skia/tools/skiaserve/Request.cpp b/src/third_party/skia/tools/skiaserve/Request.cpp
index 12f3596..ef1934e 100644
--- a/src/third_party/skia/tools/skiaserve/Request.cpp
+++ b/src/third_party/skia/tools/skiaserve/Request.cpp
@@ -5,13 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "Request.h"
+#include "tools/skiaserve/Request.h"
 
-#include "SkPictureRecorder.h"
-#include "SkPixelSerializer.h"
-#include "SkPM4fPriv.h"
-#include "picture_utils.h"
-#include "sk_tool_utils.h"
+#include "include/core/SkPictureRecorder.h"
+#include "src/utils/SkJSONWriter.h"
+#include "tools/ToolUtils.h"
 
 using namespace sk_gpu_test;
 
@@ -28,50 +26,29 @@
     , fOverdraw(false)
     , fColorMode(0) {
     // create surface
-#if SK_SUPPORT_GPU
     GrContextOptions grContextOpts;
     fContextFactory = new GrContextFactory(grContextOpts);
-#else
-    fContextFactory = nullptr;
-#endif
 }
 
 Request::~Request() {
-#if SK_SUPPORT_GPU
     if (fContextFactory) {
         delete fContextFactory;
     }
-#endif
-}
-
-SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
-    SkBitmap* bmp = new SkBitmap();
-    if (!bmp->tryAllocPixels(canvas->imageInfo()) || !canvas->readPixels(*bmp, 0, 0)) {
-        fprintf(stderr, "Can't read pixels\n");
-        delete bmp;
-        return nullptr;
-    }
-    return bmp;
 }
 
 sk_sp<SkData> Request::writeCanvasToPng(SkCanvas* canvas) {
     // capture pixels
-    std::unique_ptr<SkBitmap> bmp(this->getBitmapFromCanvas(canvas));
-    SkASSERT(bmp);
-
-    // Convert to format suitable for PNG output
-    sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bmp);
-    SkASSERT(encodedBitmap.get());
+    SkBitmap bmp;
+    bmp.allocPixels(canvas->imageInfo());
+    SkAssertResult(canvas->readPixels(bmp, 0, 0));
 
     // write to an opaque png (black background)
     SkDynamicMemoryWStream buffer;
-    SkDrawCommand::WritePNG(encodedBitmap->bytes(), bmp->width(), bmp->height(),
-                            buffer, true);
+    DrawCommand::WritePNG(bmp, buffer);
     return buffer.detachAsData();
 }
 
 SkCanvas* Request::getCanvas() {
-#if SK_SUPPORT_GPU
     GrContextFactory* factory = fContextFactory;
     GLTestContext* gl = factory->getContextInfo(GrContextFactory::kGL_ContextType,
             GrContextFactory::ContextOverrides::kNone).glContext();
@@ -79,14 +56,9 @@
         gl = factory->getContextInfo(GrContextFactory::kGLES_ContextType,
                                      GrContextFactory::ContextOverrides::kNone).glContext();
     }
-    if (!gl) {
-        gl = factory->getContextInfo(GrContextFactory::kMESA_ContextType,
-                                     GrContextFactory::ContextOverrides::kNone).glContext();
-    }
     if (gl) {
         gl->makeCurrent();
     }
-#endif
     SkASSERT(fDebugCanvas);
 
     // create the appropriate surface if necessary
@@ -97,14 +69,9 @@
     return target;
 }
 
-void Request::drawToCanvas(int n, int m) {
-    SkCanvas* target = this->getCanvas();
-    fDebugCanvas->drawTo(target, n, m);
-}
-
 sk_sp<SkData> Request::drawToPng(int n, int m) {
     //fDebugCanvas->setOverdrawViz(true);
-    this->drawToCanvas(n, m);
+    fDebugCanvas->drawTo(this->getCanvas(), n, m);
     //fDebugCanvas->setOverdrawViz(false);
     return writeCanvasToPng(this->getCanvas());
 }
@@ -118,32 +85,17 @@
 
     fDebugCanvas->draw(canvas);
 
-    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
-
-    SkDynamicMemoryWStream outStream;
-
-    sk_sp<SkPixelSerializer> serializer = sk_tool_utils::MakePixelSerializer();
-    picture->serialize(&outStream, serializer.get());
-
-    return outStream.detachAsData();
+    return recorder.finishRecordingAsPicture()->serialize();
 }
 
 GrContext* Request::getContext() {
-#if SK_SUPPORT_GPU
     GrContext* result = fContextFactory->get(GrContextFactory::kGL_ContextType,
                                              GrContextFactory::ContextOverrides::kNone);
     if (!result) {
         result = fContextFactory->get(GrContextFactory::kGLES_ContextType,
                                       GrContextFactory::ContextOverrides::kNone);
     }
-    if (!result) {
-        result = fContextFactory->get(GrContextFactory::kMESA_ContextType,
-                                      GrContextFactory::ContextOverrides::kNone);
-    }
     return result;
-#else
-    return nullptr;
-#endif
 }
 
 SkIRect Request::getBounds() {
@@ -151,11 +103,9 @@
     if (fPicture) {
         bounds = fPicture->cullRect().roundOut();
         if (fGPUEnabled) {
-#if SK_SUPPORT_GPU
-            int maxRTSize = this->getContext()->caps()->maxRenderTargetSize();
+            int maxRTSize = this->getContext()->maxRenderTargetSize();
             bounds = SkIRect::MakeWH(SkTMin(bounds.width(), maxRTSize),
                                      SkTMin(bounds.height(), maxRTSize));
-#endif
         }
     } else {
         bounds = SkIRect::MakeWH(kDefaultWidth, kDefaultHeight);
@@ -189,8 +139,8 @@
     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
                     ? SkColorSpace::MakeSRGBLinear()
                     : SkColorSpace::MakeSRGB();
-    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
-                                         kPremul_SkAlphaType, cap.fSRGB ? colorSpace : nullptr);
+    SkImageInfo info = SkImageInfo::Make(bounds.size(), cap.fColorType, kPremul_SkAlphaType,
+                                         cap.fSRGB ? colorSpace : nullptr);
     return SkSurface::MakeRaster(info).release();
 }
 
@@ -201,8 +151,8 @@
     auto colorSpace = kRGBA_F16_SkColorType == cap.fColorType
                     ? SkColorSpace::MakeSRGBLinear()
                     : SkColorSpace::MakeSRGB();
-    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
-                                         kPremul_SkAlphaType, cap.fSRGB ? colorSpace: nullptr);
+    SkImageInfo info = SkImageInfo::Make(bounds.size(), cap.fColorType, kPremul_SkAlphaType,
+                                         cap.fSRGB ? colorSpace : nullptr);
     SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info).release();
     return surface;
 }
@@ -254,7 +204,7 @@
 
     // pour picture into debug canvas
     SkIRect bounds = this->getBounds();
-    fDebugCanvas.reset(new SkDebugCanvas(bounds.width(), bounds.height()));
+    fDebugCanvas.reset(new DebugCanvas(bounds.width(), bounds.height()));
     fDebugCanvas->drawPicture(fPicture);
 
     // for some reason we need to 'flush' the debug canvas by drawing all of the ops
@@ -265,25 +215,29 @@
 
 sk_sp<SkData> Request::getJsonOps(int n) {
     SkCanvas* canvas = this->getCanvas();
-    Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
-    root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
-    root["drawGpuOpBounds"] = Json::Value(fDebugCanvas->getDrawGpuOpBounds());
-    root["colorMode"] = Json::Value(fColorMode);
     SkDynamicMemoryWStream stream;
-    stream.writeText(Json::FastWriter().write(root).c_str());
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
+    writer.beginObject(); // root
 
+    writer.appendString("mode", fGPUEnabled ? "gpu" : "cpu");
+    writer.appendBool("drawGpuOpBounds", fDebugCanvas->getDrawGpuOpBounds());
+    writer.appendS32("colorMode", fColorMode);
+    fDebugCanvas->toJSON(writer, fUrlDataManager, n, canvas);
+
+    writer.endObject(); // root
+    writer.flush();
     return stream.detachAsData();
 }
 
-sk_sp<SkData> Request::getJsonOpList(int n) {
+sk_sp<SkData> Request::getJsonOpsTask(int n) {
     SkCanvas* canvas = this->getCanvas();
     SkASSERT(fGPUEnabled);
-
-    Json::Value result = fDebugCanvas->toJSONOpList(n, canvas);
-
     SkDynamicMemoryWStream stream;
-    stream.writeText(Json::FastWriter().write(result).c_str());
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
 
+    fDebugCanvas->toJSONOpsTask(writer, n, canvas);
+
+    writer.flush();
     return stream.detachAsData();
 }
 
@@ -296,29 +250,27 @@
     fDebugCanvas->drawTo(canvas, n);
 
     // make some json
+    SkDynamicMemoryWStream stream;
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
+
     SkMatrix vm = fDebugCanvas->getCurrentMatrix();
     SkIRect clip = fDebugCanvas->getCurrentClip();
-    Json::Value info(Json::objectValue);
-    info["ViewMatrix"] = SkDrawCommand::MakeJsonMatrix(vm);
-    info["ClipRect"] = SkDrawCommand::MakeJsonIRect(clip);
 
-    std::string json = Json::FastWriter().write(info);
+    writer.beginObject(); // root
+    writer.appendName("ViewMatrix");
+    DrawCommand::MakeJsonMatrix(writer, vm);
+    writer.appendName("ClipRect");
+    DrawCommand::MakeJsonIRect(writer, clip);
+    writer.endObject(); // root
 
-    // We don't want the null terminator so strlen is correct
-    return SkData::MakeWithCopy(json.c_str(), strlen(json.c_str()));
+    // TODO: Old code explicitly avoided the null terminator in the returned data. Important?
+    writer.flush();
+    return stream.detachAsData();
 }
 
 SkColor Request::getPixel(int x, int y) {
-    SkCanvas* canvas = this->getCanvas();
-    canvas->flush();
-    std::unique_ptr<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
-    SkASSERT(bitmap);
-
-    // Convert to format suitable for inspection
-    sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
-    SkASSERT(encodedBitmap);
-
-    const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
-    SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
-    return result;
+    SkBitmap bmp;
+    bmp.allocPixels(this->getCanvas()->imageInfo().makeWH(1, 1));
+    SkAssertResult(this->getCanvas()->readPixels(bmp, x, y));
+    return bmp.getColor(0, 0);
 }
diff --git a/src/third_party/skia/tools/skiaserve/Request.h b/src/third_party/skia/tools/skiaserve/Request.h
index 7f41748..e3dfada 100644
--- a/src/third_party/skia/tools/skiaserve/Request.h
+++ b/src/third_party/skia/tools/skiaserve/Request.h
@@ -8,18 +8,16 @@
 #ifndef Request_DEFINED
 #define Request_DEFINED
 
-#include "SkTypes.h"
+#include "include/core/SkTypes.h"
 
-#if SK_SUPPORT_GPU
-#include "GrContextFactory.h"
-#endif
+#include "tools/gpu/GrContextFactory.h"
 
-#include "SkDebugCanvas.h"
-#include "SkPicture.h"
-#include "SkStream.h"
-#include "SkSurface.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "tools/debugger/DebugCanvas.h"
 
-#include "UrlDataManager.h"
+#include "tools/UrlDataManager.h"
 
 namespace sk_gpu_test {
 class GrContextFactory;
@@ -41,7 +39,6 @@
     sk_sp<SkData> drawToPng(int n, int m = -1);
     sk_sp<SkData> writeOutSkp();
     SkCanvas* getCanvas();
-    SkBitmap* getBitmapFromCanvas(SkCanvas* canvas);
     bool enableGPU(bool enable);
     bool setOverdraw(bool enable);
     bool setColorMode(int mode);
@@ -54,7 +51,7 @@
     sk_sp<SkData> getJsonOps(int n);
 
     // Returns a json list of ops as an SkData
-    sk_sp<SkData> getJsonOpList(int n);
+    sk_sp<SkData> getJsonOpsTask(int n);
 
     // Returns json with the viewMatrix and clipRect
     sk_sp<SkData> getJsonInfo(int n);
@@ -63,12 +60,11 @@
     SkColor getPixel(int x, int y);
 
     UploadContext* fUploadContext;
-    std::unique_ptr<SkDebugCanvas> fDebugCanvas;
+    std::unique_ptr<DebugCanvas> fDebugCanvas;
     UrlDataManager fUrlDataManager;
 
 private:
     sk_sp<SkData> writeCanvasToPng(SkCanvas* canvas);
-    void drawToCanvas(int n, int m = -1);
     SkSurface* createCPUSurface();
     SkSurface* createGPUSurface();
     SkIRect getBounds();
diff --git a/src/third_party/skia/tools/skiaserve/Response.cpp b/src/third_party/skia/tools/skiaserve/Response.cpp
index 61470f1..d74963a 100644
--- a/src/third_party/skia/tools/skiaserve/Response.cpp
+++ b/src/third_party/skia/tools/skiaserve/Response.cpp
@@ -5,17 +5,17 @@
  * found in the LICENSE file.
  */
 
-#include "Response.h"
+#include "tools/skiaserve/Response.h"
+
+#include "tools/skiaserve/Request.h"
+
+#include "include/core/SkData.h"
+#include "include/core/SkString.h"
+#include "tools/flags/CommandLineFlags.h"
 
 #include "microhttpd.h"
 
-#include "Request.h"
-
-#include "SkCommandLineFlags.h"
-#include "SkData.h"
-#include "SkString.h"
-
-DEFINE_string(source, "https://debugger.skia.org", "Where to load the web UI from.");
+static DEFINE_string(source, "https://debugger-assets.skia.org", "Where to load the web UI from.");
 
 static SkString generate_template(SkString source) {
     SkString debuggerTemplate;
@@ -24,18 +24,18 @@
         "<html>\n"
         "<head>\n"
         "    <title>SkDebugger</title>\n"
-        "    <meta charset=\"utf-8\" />\n"
-        "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=egde,chrome=1\">\n"
-        "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
-        "    <script src=\"%s/res/js/core.js\" type=\"text/javascript\" charset=\"utf-8\"></script>\n"
-        "    <link href=\"%s/res/vul/elements.html\" rel=\"import\" />\n"
-        "    <link rel='shortcut icon' href='https://debugger.skia.org/res/img/favicon.ico' type='image/x-icon'/ >"
+        "    <meta charset='utf-8' />\n"
+        "    <meta http-equiv='X-UA-Compatible' content='IE=egde,chrome=1'>\n"
+        "    <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n"
+        "    <script src='%s/res/js/core.js' type='text/javascript' charset='utf-8'></script>\n"
+        "    <link href='%s/res/vul/elements.html' rel='import' />\n"
+        "    <link rel='shortcut icon' href='%s/res/img/favicon.ico' type='image/x-icon'/ >"
         "</head>\n"
-        "<body class=\"fullbleed layout vertical\">\n"
+        "<body class='fullbleed layout vertical'>\n"
             "  <debugger-app-sk>This is the app."
             "  </debugger-app-sk>\n"
         "</body>\n"
-        "</html>", source.c_str(), source.c_str());
+        "</html>", source.c_str(), source.c_str(), source.c_str());
     return debuggerTemplate;
 }
 
diff --git a/src/third_party/skia/tools/skiaserve/skiaserve.cpp b/src/third_party/skia/tools/skiaserve/skiaserve.cpp
index 29dd1b4..0a64db7 100644
--- a/src/third_party/skia/tools/skiaserve/skiaserve.cpp
+++ b/src/third_party/skia/tools/skiaserve/skiaserve.cpp
@@ -5,16 +5,16 @@
  * found in the LICENSE file.
  */
 
-#include "Request.h"
-#include "Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
-#include "SkCommandLineFlags.h"
-#include "SkGraphics.h"
+#include "include/core/SkGraphics.h"
+#include "tools/flags/CommandLineFlags.h"
+
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
 
-#include "urlhandlers/UrlHandler.h"
-
 #include <errno.h>
 
 #if !defined _WIN32
@@ -24,9 +24,9 @@
 
 using namespace Response;
 
-DEFINE_int32(port, 8888, "The port to listen on.");
-DEFINE_string(address, "127.0.0.1", "The address to bind to.");
-DEFINE_bool(hosted, false, "Running in hosted mode on debugger.skia.org.");
+static DEFINE_int(port, 8888, "The port to listen on.");
+static DEFINE_string(address, "127.0.0.1", "The address to bind to.");
+static DEFINE_bool(hosted, false, "Running in hosted mode on debugger.skia.org.");
 
 class UrlManager {
 public:
@@ -110,7 +110,7 @@
                               &answer_to_connection, &request,
                               MHD_OPTION_SOCK_ADDR, &address,
                               MHD_OPTION_END);
-    if (NULL == daemon) {
+    if (nullptr == daemon) {
         SkDebugf("Could not initialize daemon\n");
         return 1;
     }
@@ -133,7 +133,7 @@
 
 #if !defined SK_BUILD_FOR_IOS
 int main(int argc, char** argv) {
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::Parse(argc, argv);
     return skiaserve_main();
 }
 #endif
diff --git a/src/third_party/skia/tools/skiaserve/tester/tester.py b/src/third_party/skia/tools/skiaserve/tester/tester.py
index b99529c..9bf4c51 100644
--- a/src/third_party/skia/tools/skiaserve/tester/tester.py
+++ b/src/third_party/skia/tools/skiaserve/tester/tester.py
@@ -57,7 +57,7 @@
     def post(self):
         with open(self.skp, 'rb') as payload:
             files = {'file': payload}
-    
+
             # upload skp
             return Check(requests.post(self.url + '/new', files=files))
 
@@ -73,7 +73,7 @@
 
     def enable_gpu(self):
         return Check(requests.post(self.url + '/enableGPU/1'))
-    
+
     def disable_gpu(self):
         return Check(requests.post(self.url + '/enableGPU/0'))
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/BreakHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/BreakHandler.cpp
index f4f741f..5013c6d 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/BreakHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/BreakHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
@@ -47,15 +47,15 @@
         request->fDebugCanvas->getDrawCommandAt(i)->execute(canvas);
     }
     SkColor target = request->getPixel(x, y);
-    Json::Value response(Json::objectValue);
-    Json::Value startColor(Json::arrayValue);
-    startColor.append(Json::Value(SkColorGetR(target)));
-    startColor.append(Json::Value(SkColorGetG(target)));
-    startColor.append(Json::Value(SkColorGetB(target)));
-    startColor.append(Json::Value(SkColorGetA(target)));
-    response["startColor"] = startColor;
-    response["endColor"] = startColor;
-    response["endOp"] = Json::Value(n);
+
+    SkDynamicMemoryWStream stream;
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kFast);
+    writer.beginObject(); // root
+
+    writer.appendName("startColor");
+    DrawCommand::MakeJsonColor(writer, target);
+
+    bool changed = false;
     for (int i = n + 1; i < n + count; ++i) {
         int index = i % count;
         if (index == 0) {
@@ -67,18 +67,21 @@
         request->fDebugCanvas->getDrawCommandAt(index)->execute(canvas);
         SkColor current = request->getPixel(x, y);
         if (current != target) {
-            Json::Value endColor(Json::arrayValue);
-            endColor.append(Json::Value(SkColorGetR(current)));
-            endColor.append(Json::Value(SkColorGetG(current)));
-            endColor.append(Json::Value(SkColorGetB(current)));
-            endColor.append(Json::Value(SkColorGetA(current)));
-            response["endColor"] = endColor;
-            response["endOp"] = Json::Value(index);
+            writer.appendName("endColor");
+            DrawCommand::MakeJsonColor(writer, current);
+            writer.appendS32("endOp", index);
+            changed = true;
             break;
         }
     }
+    if (!changed) {
+        writer.appendName("endColor");
+        DrawCommand::MakeJsonColor(writer, target);
+        writer.appendS32("endOp", n);
+    }
     canvas->restoreToCount(saveCount);
-    SkDynamicMemoryWStream stream;
-    stream.writeText(Json::FastWriter().write(response).c_str());
+
+    writer.endObject(); // root
+    writer.flush();
     return SendData(connection, stream.detachAsData().get(), "application/json");
 }
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/ClipAlphaHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/ClipAlphaHandler.cpp
index a931f93..3032eee 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/ClipAlphaHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/ClipAlphaHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/CmdHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/CmdHandler.cpp
index c8ec82d..fa78766 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/CmdHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/CmdHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/ColorModeHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/ColorModeHandler.cpp
index 25cdf7d..a4c308d 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/ColorModeHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/ColorModeHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/DataHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/DataHandler.cpp
index 83a9be4..8df8288 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/DataHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/DataHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/DownloadHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/DownloadHandler.cpp
index 17bf867..6f344bd 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/DownloadHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/DownloadHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/EnableGPUHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/EnableGPUHandler.cpp
index 7364ef0..a458cad 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/EnableGPUHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/EnableGPUHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/ImgHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/ImgHandler.cpp
index 659c215..652b619 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/ImgHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/ImgHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/InfoHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/InfoHandler.cpp
index 9335458..d276605 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/InfoHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/InfoHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/OpBoundsHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/OpBoundsHandler.cpp
index e9a120f..94f4e6b 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/OpBoundsHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/OpBoundsHandler.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 #include "microhttpd.h"
 
 using namespace Response;
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/OpsHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/OpsHandler.cpp
index 852c526..0c55419 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/OpsHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/OpsHandler.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 #include "microhttpd.h"
 
 using namespace Response;
@@ -31,7 +31,7 @@
     if (0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
         int n = request->getLastOp();
 
-        sk_sp<SkData> data(request->getJsonOpList(n));
+        sk_sp<SkData> data(request->getJsonOpsTask(n));
         return SendData(connection, data.get(), "application/json");
     }
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/OverdrawHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/OverdrawHandler.cpp
index 7f8c404..e7441aa 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/OverdrawHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/OverdrawHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/PostHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/PostHandler.cpp
index 634a2e5..22b8b50 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/PostHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/PostHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/QuitHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/QuitHandler.cpp
index fa8045c..230a0f8 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/QuitHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/QuitHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/RootHandler.cpp b/src/third_party/skia/tools/skiaserve/urlhandlers/RootHandler.cpp
index 647c198..3ff04fe 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/RootHandler.cpp
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/RootHandler.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
-#include "UrlHandler.h"
+#include "tools/skiaserve/urlhandlers/UrlHandler.h"
 
 #include "microhttpd.h"
-#include "../Request.h"
-#include "../Response.h"
+#include "tools/skiaserve/Request.h"
+#include "tools/skiaserve/Response.h"
 
 using namespace Response;
 
diff --git a/src/third_party/skia/tools/skiaserve/urlhandlers/UrlHandler.h b/src/third_party/skia/tools/skiaserve/urlhandlers/UrlHandler.h
index 95fa476..eb17b5c 100644
--- a/src/third_party/skia/tools/skiaserve/urlhandlers/UrlHandler.h
+++ b/src/third_party/skia/tools/skiaserve/urlhandlers/UrlHandler.h
@@ -7,7 +7,7 @@
 #ifndef UrlHandler_DEFINED
 #define UrlHandler_DEFINED
 
-#include "SkColor.h"
+#include "include/core/SkColor.h"
 
 struct MHD_Connection;
 struct Request;
diff --git a/src/third_party/skia/tools/skottie-wasm-perf/Makefile b/src/third_party/skia/tools/skottie-wasm-perf/Makefile
new file mode 100644
index 0000000..7863cdf
--- /dev/null
+++ b/src/third_party/skia/tools/skottie-wasm-perf/Makefile
@@ -0,0 +1,2 @@
+serve:
+	python -m SimpleHTTPServer 8004
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skottie-wasm-perf/package.json b/src/third_party/skia/tools/skottie-wasm-perf/package.json
new file mode 100644
index 0000000..fbbf162
--- /dev/null
+++ b/src/third_party/skia/tools/skottie-wasm-perf/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "skottie-wasm-perf",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "dependencies": {
+    "command-line-args": "^5.0.2",
+    "command-line-usage": "^5.0.3",
+    "express": "^4.16.3",
+    "lottie-web": "5.2.1",
+    "node-fetch": "^2.2.0",
+    "puppeteer": "~1.17.0"
+  },
+  "devDependencies": {},
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC"
+}
diff --git a/src/third_party/skia/tools/skottie-wasm-perf/parse_perf_csvs.py b/src/third_party/skia/tools/skottie-wasm-perf/parse_perf_csvs.py
new file mode 100644
index 0000000..89d27cd
--- /dev/null
+++ b/src/third_party/skia/tools/skottie-wasm-perf/parse_perf_csvs.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python2
+#
+# Copyright 2019 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Helper script that takes as input 2 CSVs downloaded from perf.skia.org and
+# outputs a CSV with test_name, avg_value1 (from CSV1), avg_value2 (from CSV2),
+# perc_diff between avg_value1 and avg_value2.
+# This script also discards NUM_OUTLIERS_TO_REMOVE min values and
+# NUM_OUTLIERS_TO_REMOVE max values.
+
+
+import csv
+import optparse
+import sys
+import re
+
+
+MISSING_STR = 'N/A'
+NUM_OUTLIERS_TO_REMOVE = 2
+
+
+def read_from_csv(csv_file):
+  test_to_avg = {}
+  with open(csv_file, 'rb') as f:
+    csv_reader = csv.reader(f, delimiter=',')
+    # First row should contain headers. Validate that it does.
+    header_row = csv_reader.next()
+    if header_row[0] != 'id':
+      raise Exception('%s in unexpected format' % csv_file)
+    p = re.compile('^.*,test=(.*),$')
+    for v in csv_reader:
+      # Extract the test name.
+      result = p.search(v[0])
+      test_name = result.group(1)
+
+      vals = [float(i) for i in v[1:]]
+      vals.sort()
+      # Discard outliers.
+      vals = vals[NUM_OUTLIERS_TO_REMOVE:-NUM_OUTLIERS_TO_REMOVE]
+      # Find the avg val.
+      avg_val = reduce(lambda x, y: x+y, vals) / float(len(vals))
+      test_to_avg[test_name] = avg_val
+  return test_to_avg
+
+
+def combine_results(d1, d2):
+  test_to_result = {}
+  for test1, v1 in d1.items():
+    v2 = d2.get(test1, MISSING_STR)
+    perc_diff = MISSING_STR
+    if v2 != MISSING_STR:
+      diff = v2 - v1
+      avg = (v2 + v1)/2
+      perc_diff = 0 if avg == 0 else diff/avg * 100
+    result = {
+        'test_name': test1,
+        'csv1': v1,
+        'csv2': v2,
+        'perc_diff': perc_diff,
+    }
+    test_to_result[test1] = result
+
+  # Also add keys in d2 and not d1.
+  for test2, v2 in d2.items():
+    if test2 in test_to_result:
+      continue
+    test_to_result[test2] = {
+      'test_name': test2,
+      'csv1': MISSING_STR,
+      'csv2': v2,
+      'perc_diff': MISSING_STR,
+    }
+
+  return test_to_result
+
+
+def write_to_csv(output_dict, output_csv):
+  with open(output_csv, 'w') as f:
+    fieldnames = ['test_name', 'csv1', 'csv2', 'perc_diff']
+    writer = csv.DictWriter(f, fieldnames=fieldnames)
+    writer.writeheader()
+    tests = output_dict.keys()
+    tests.sort()
+    for test in tests:
+      writer.writerow(output_dict[test])
+
+
+def parse_and_output(csv1, csv2, output_csv):
+  test_to_avg1 = read_from_csv(csv1)
+  test_to_avg2 = read_from_csv(csv2)
+  output_dict = combine_results(test_to_avg1, test_to_avg2)
+  write_to_csv(output_dict, output_csv)
+
+
+def main():
+  option_parser = optparse.OptionParser()
+  option_parser.add_option(
+      '', '--csv1', type=str,
+      help='The first CSV to parse.')
+  option_parser.add_option(
+      '', '--csv2', type=str,
+      help='The second CSV to parse.')
+  option_parser.add_option(
+      '', '--output_csv', type=str,
+      help='The file to write the output CSV to.')
+  options, _ = option_parser.parse_args()
+  sys.exit(parse_and_output(options.csv1, options.csv2, options.output_csv))
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.html b/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.html
new file mode 100644
index 0000000..2d53a73
--- /dev/null
+++ b/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>Skottie-WASM Perf</title>
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=egde,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <script src="res/canvaskit.js" type="text/javascript" charset="utf-8"></script>
+    <style type="text/css" media="screen">
+      body {
+        margin: 0;
+        padding: 0;
+      }
+    </style>
+</head>
+<body>
+  <main>
+    <canvas id=anim width=1000 height=1000 style="height: 1000px; width: 1000px;"></canvas>
+  </main>
+  <script type="text/javascript" charset="utf-8">
+    (function() {
+      const PATH = '/res/lottie.json';
+
+      let lottieJSON = null;
+      let CK = null;
+
+     CanvasKitInit({
+        locateFile: (file) => '/res/'+file,
+    }).ready().then((CanvasKit) => {
+        CK = CanvasKit;
+        Bench(CK, lottieJSON);
+    });
+
+    fetch(PATH).then((resp) => {
+      resp.text().then((json) => {
+        lottieJSON = json;
+        Bench(CK, lottieJSON);
+      });
+    });
+  })();
+
+  const maxFrames = 25;
+  const maxLoops = 5;
+
+  function Bench(CK, json) {
+    if (!CK || !json) {
+      return;
+    }
+
+    const animation = CK.MakeManagedAnimation(json, null);
+    if (!animation) {
+      console.error('Could not process JSON');
+      return
+    }
+
+    const surface = CK.MakeCanvasSurface("anim");
+    if (!surface) {
+      console.error('Could not make surface');
+      return;
+    }
+    const canvas = surface.getCanvas();
+
+    let c = document.getElementById('anim');
+    // If CanvasKit was unable to instantiate a WebGL context, it will fallback
+    // to CPU and add a ck-replaced class to the canvas element.
+    window._gpu = CK.gpu && !c.classList.contains('ck-replaced');
+
+    const t_rate = 1.0 / (maxFrames-1);
+    let seek = 0;
+    let frame = 0;
+    let loop = 0;
+    const drawFrame = () => {
+      if (frame >= maxFrames) {
+        // Reached the end of one loop.
+        loop++;
+        if (loop == maxLoops) {
+          // These are global variables to talk with puppeteer.
+          window._skottieDone = true;
+          return;
+        }
+        // Reset frame and seek to restart the loop.
+        frame = 0;
+        seek = 0;
+      }
+
+      let damage = animation.seek(seek);
+      if (damage.fRight > damage.fLeft && damage.fBottom > damage.fTop) {
+        animation.render(canvas, {
+                         fLeft: 0,
+                         fTop: 0,
+                         fRight: 1000,
+                         fBottom: 1000
+                         });
+        surface.flush();
+      }
+      console.log("Used seek: " + seek);
+      seek += t_rate;
+      frame++;
+      window.requestAnimationFrame(drawFrame);
+    };
+    window.requestAnimationFrame(drawFrame);
+  }
+  </script>
+</body>
+</html>
diff --git a/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.js b/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.js
new file mode 100644
index 0000000..3f25ae4
--- /dev/null
+++ b/src/third_party/skia/tools/skottie-wasm-perf/skottie-wasm-perf.js
@@ -0,0 +1,179 @@
+/**
+ * Command line application to run Skottie-WASM perf on a Lottie file in the
+ * browser and then exporting the result.
+ *
+ */
+const puppeteer = require('puppeteer');
+const express = require('express');
+const fs = require('fs');
+const commandLineArgs = require('command-line-args');
+const commandLineUsage= require('command-line-usage');
+const fetch = require('node-fetch');
+
+const opts = [
+  {
+    name: 'canvaskit_js',
+    typeLabel: '{underline file}',
+    description: 'The path to canvaskit.js.'
+  },
+  {
+    name: 'canvaskit_wasm',
+    typeLabel: '{underline file}',
+    description: 'The path to canvaskit.wasm.'
+  },
+  {
+    name: 'input',
+    typeLabel: '{underline file}',
+    description: 'The Lottie JSON file to process.'
+  },
+  {
+    name: 'output',
+    typeLabel: '{underline file}',
+    description: 'The perf file to write. Defaults to perf.json',
+  },
+  {
+    name: 'use_gpu',
+    description: 'Whether we should run in non-headless mode with GPU.',
+    type: Boolean,
+  },
+  {
+    name: 'port',
+    description: 'The port number to use, defaults to 8081.',
+    type: Number,
+  },
+  {
+    name: 'help',
+    alias: 'h',
+    type: Boolean,
+    description: 'Print this usage guide.'
+  },
+];
+
+const usage = [
+  {
+    header: 'Skottie WASM Perf',
+    content: "Command line application to run Skottie-WASM perf."
+  },
+  {
+    header: 'Options',
+    optionList: opts,
+  },
+];
+
+// Parse and validate flags.
+const options = commandLineArgs(opts);
+
+if (!options.output) {
+  options.output = 'perf.json';
+}
+if (!options.port) {
+  options.port = 8081;
+}
+
+if (options.help) {
+  console.log(commandLineUsage(usage));
+  process.exit(0);
+}
+
+if (!options.canvaskit_js) {
+  console.error('You must supply path to canvaskit.js.');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+if (!options.canvaskit_wasm) {
+  console.error('You must supply path to canvaskit.wasm.');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+if (!options.input) {
+  console.error('You must supply a Lottie JSON filename.');
+  console.log(commandLineUsage(usage));
+  process.exit(1);
+}
+
+// Start up a web server to serve the three files we need.
+let canvasKitJS = fs.readFileSync(options.canvaskit_js, 'utf8');
+let canvasKitWASM = fs.readFileSync(options.canvaskit_wasm, 'binary');
+let driverHTML = fs.readFileSync('skottie-wasm-perf.html', 'utf8');
+let lottieJSON = fs.readFileSync(options.input, 'utf8');
+
+const app = express();
+app.get('/', (req, res) => res.send(driverHTML));
+app.get('/res/canvaskit.wasm', function(req, res) {
+  res.type('application/wasm');
+  res.send(new Buffer(canvasKitWASM, 'binary'));
+});
+app.get('/res/canvaskit.js', (req, res) => res.send(canvasKitJS));
+app.get('/res/lottie.json', (req, res) => res.send(lottieJSON));
+app.listen(options.port, () => console.log('- Local web server started.'))
+
+// Utility function.
+async function wait(ms) {
+    await new Promise(resolve => setTimeout(() => resolve(), ms));
+    return ms;
+}
+
+const targetURL = "http://localhost:" + options.port + "/";
+const viewPort = {width: 1000, height: 1000};
+
+// Drive chrome to load the web page from the server we have running.
+async function driveBrowser() {
+  console.log('- Launching chrome for ' + options.input);
+  let browser;
+  let page;
+  const headless = !options.use_gpu;
+  let browser_args = [
+      '--no-sandbox',
+      '--disable-setuid-sandbox',
+      '--window-size=' + viewPort.width + ',' + viewPort.height,
+  ];
+  if (options.use_gpu) {
+    browser_args.push('--ignore-gpu-blacklist');
+    browser_args.push('--ignore-gpu-blocklist');
+    browser_args.push('--enable-gpu-rasterization');
+  }
+  console.log("Running with headless: " + headless + " args: " + browser_args);
+  try {
+    browser = await puppeteer.launch({headless: headless, args: browser_args});
+    page = await browser.newPage();
+    await page.setViewport(viewPort);
+  } catch (e) {
+    console.log('Could not open the browser.', e);
+    process.exit(1);
+  }
+  console.log("Loading " + targetURL);
+  try {
+    // Start trace.
+    await page.tracing.start({
+      path: options.output,
+      screenshots: false,
+      categories: ["blink", "cc", "gpu"]
+    });
+
+    await page.goto(targetURL, {
+      timeout: 60000,
+      waitUntil: 'networkidle0'
+    });
+
+    console.log('Waiting 60s for run to be done');
+    await page.waitForFunction('window._skottieDone === true', {
+      timeout: 60000,
+    });
+
+    // Stop Trace.
+    await page.tracing.stop();
+  } catch(e) {
+    console.log('Timed out while loading or drawing. Either the JSON file was ' +
+                'too big or hit a bug.', e);
+    await browser.close();
+    process.exit(1);
+  }
+
+  await browser.close();
+  // Need to call exit() because the web server is still running.
+  process.exit(0);
+}
+
+driveBrowser();
diff --git a/src/third_party/skia/tools/skottie2movie.cpp b/src/third_party/skia/tools/skottie2movie.cpp
new file mode 100644
index 0000000..e12ad3c
--- /dev/null
+++ b/src/third_party/skia/tools/skottie2movie.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "experimental/ffmpeg/SkVideoEncoder.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkTime.h"
+#include "modules/skottie/include/Skottie.h"
+#include "modules/skottie/utils/SkottieUtils.h"
+#include "src/utils/SkOSPath.h"
+
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/gpu/GrContextFactory.h"
+
+#include "include/gpu/GrContextOptions.h"
+
+static DEFINE_string2(input, i, "", "skottie animation to render");
+static DEFINE_string2(output, o, "", "mp4 file to create");
+static DEFINE_string2(assetPath, a, "", "path to assets needed for json file");
+static DEFINE_int_2(fps, f, 25, "fps");
+static DEFINE_bool2(verbose, v, false, "verbose mode");
+static DEFINE_bool2(loop, l, false, "loop mode for profiling");
+static DEFINE_int(set_dst_width, 0, "set destination width (height will be computed)");
+static DEFINE_bool2(gpu, g, false, "use GPU for rendering");
+
+static void produce_frame(SkSurface* surf, skottie::Animation* anim, double frame_time) {
+    anim->seekFrameTime(frame_time);
+    surf->getCanvas()->clear(SK_ColorWHITE);
+    anim->render(surf->getCanvas());
+}
+
+struct AsyncRec {
+    SkImageInfo info;
+    SkVideoEncoder* encoder;
+};
+
+int main(int argc, char** argv) {
+    SkGraphics::Init();
+
+    CommandLineFlags::SetUsage("Converts skottie to a mp4");
+    CommandLineFlags::Parse(argc, argv);
+
+    if (FLAGS_input.count() == 0) {
+        SkDebugf("-i input_file.json argument required\n");
+        return -1;
+    }
+
+    auto contextType = sk_gpu_test::GrContextFactory::kGL_ContextType;
+    GrContextOptions grCtxOptions;
+    sk_gpu_test::GrContextFactory factory(grCtxOptions);
+
+    SkString assetPath;
+    if (FLAGS_assetPath.count() > 0) {
+        assetPath.set(FLAGS_assetPath[0]);
+    } else {
+        assetPath = SkOSPath::Dirname(FLAGS_input[0]);
+    }
+    SkDebugf("assetPath %s\n", assetPath.c_str());
+
+    auto animation = skottie::Animation::Builder()
+        .setResourceProvider(skottie_utils::FileResourceProvider::Make(assetPath))
+        .makeFromFile(FLAGS_input[0]);
+    if (!animation) {
+        SkDebugf("failed to load %s\n", FLAGS_input[0]);
+        return -1;
+    }
+
+    SkISize dim = animation->size().toRound();
+    double duration = animation->duration();
+    int fps = FLAGS_fps;
+    if (fps < 1) {
+        fps = 1;
+    } else if (fps > 240) {
+        fps = 240;
+    }
+
+    float scale = 1;
+    if (FLAGS_set_dst_width > 0) {
+        scale = FLAGS_set_dst_width / (float)dim.width();
+        dim = { FLAGS_set_dst_width, SkScalarRoundToInt(scale * dim.height()) };
+    }
+
+    const int frames = SkScalarRoundToInt(duration * fps);
+    const double frame_duration = 1.0 / fps;
+
+    if (FLAGS_verbose) {
+        SkDebugf("Size %dx%d duration %g, fps %d, frame_duration %g\n",
+                 dim.width(), dim.height(), duration, fps, frame_duration);
+    }
+
+    SkVideoEncoder encoder;
+
+    GrContext* context = nullptr;
+    sk_sp<SkSurface> surf;
+    sk_sp<SkData> data;
+
+    const auto info = SkImageInfo::MakeN32Premul(dim);
+    do {
+        double loop_start = SkTime::GetSecs();
+
+        if (!encoder.beginRecording(dim, fps)) {
+            SkDEBUGF("Invalid video stream configuration.\n");
+            return -1;
+        }
+
+        // lazily allocate the surfaces
+        if (!surf) {
+            if (FLAGS_gpu) {
+                context = factory.getContextInfo(contextType).grContext();
+                surf = SkSurface::MakeRenderTarget(context,
+                                                   SkBudgeted::kNo,
+                                                   info,
+                                                   0,
+                                                   GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
+                                                   nullptr);
+                if (!surf) {
+                    context = nullptr;
+                }
+            }
+            if (!surf) {
+                surf = SkSurface::MakeRaster(info);
+            }
+            surf->getCanvas()->scale(scale, scale);
+        }
+
+        for (int i = 0; i <= frames; ++i) {
+            double ts = i * 1.0 / fps;
+            if (FLAGS_verbose) {
+                SkDebugf("rendering frame %d ts %g\n", i, ts);
+            }
+
+            double normal_time = i * 1.0 / frames;
+            double frame_time = normal_time * duration;
+
+            produce_frame(surf.get(), animation.get(), frame_time);
+
+            AsyncRec asyncRec = { info, &encoder };
+            if (context) {
+                surf->asyncRescaleAndReadPixels(info, {0, 0, info.width(), info.height()},
+                                                SkSurface::RescaleGamma::kSrc, kNone_SkFilterQuality,
+                                                [](void* ctx, const void* data, size_t rb) {
+                    AsyncRec* rec = (AsyncRec*)ctx;
+                    rec->encoder->addFrame({rec->info, data, rb});
+                }, &asyncRec);
+            } else {
+                SkPixmap pm;
+                SkAssertResult(surf->peekPixels(&pm));
+                encoder.addFrame(pm);
+            }
+        }
+        data = encoder.endRecording();
+
+        if (FLAGS_loop) {
+            double loop_dur = SkTime::GetSecs() - loop_start;
+            SkDebugf("recording secs %g, frames %d, recording fps %d\n",
+                     loop_dur, frames, (int)(frames / loop_dur));
+        }
+    } while (FLAGS_loop);
+
+    if (FLAGS_output.count() == 0) {
+        SkDebugf("missing -o output_file.mp4 argument\n");
+        return 0;
+    }
+
+    SkFILEWStream ostream(FLAGS_output[0]);
+    if (!ostream.isValid()) {
+        SkDebugf("Can't create output file %s\n", FLAGS_output[0]);
+        return -1;
+    }
+    ostream.write(data->data(), data->size());
+    return 0;
+}
diff --git a/src/third_party/skia/tools/skp/generate_page_set.py b/src/third_party/skia/tools/skp/generate_page_set.py
new file mode 100644
index 0000000..3ca71ba
--- /dev/null
+++ b/src/third_party/skia/tools/skp/generate_page_set.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# Copyright (c) 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script that generates a page_set for the webpages_playback.py script."""
+
+import jinja2
+import os
+
+
+PAGE_SET_TEMPLATE = 'page_set_template'
+PAGE_SET_DIR = 'page_sets'
+
+
+def main():
+  created_page_sets = []
+  while True:
+    user_agent = raw_input('user agent? (mobile/desktop/tablet): ')
+    url_name = raw_input('URL name? (eg: google): ')
+    url = raw_input('URL? (eg: http://www.google.com): ')
+    comment = raw_input('Reason for adding the URL? (eg: go/skia-skps-3-2019): ')
+
+    with open(PAGE_SET_TEMPLATE) as f:
+      t = jinja2.Template(f.read())
+    subs = {
+      'user_agent': user_agent,
+      'url_name': url_name,
+      'url': url,
+      'comment': comment,
+    }
+
+    page_set_name = 'skia_%s_%s.py' % (url_name, user_agent)
+    page_set_path = os.path.join(PAGE_SET_DIR, page_set_name)
+    with open(page_set_path, 'w') as f:
+      f.write(t.render(**subs))
+    created_page_sets.append(page_set_path)
+    print '\nPage set has been created in %s\n\n' % page_set_path
+
+    keep_going = raw_input('Do you have more page sets to create? (y/n)')
+    if keep_going != 'y':
+      break
+
+  print '\n\nSummarizing all created page sets:'
+  for page_set_path in created_page_sets:
+    print '* %s' % page_set_path
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/third_party/skia/tools/skp/page_set_template b/src/third_party/skia/tools/skp/page_set_template
new file mode 100644
index 0000000..d0d01cf
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_set_template
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class Skia{{ user_agent|capitalize }}Page(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(Skia{{ user_agent|capitalize }}Page, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.Shared{{ user_agent|capitalize }}PageState)
+    self.archive_data_file = 'data/skia_{{url_name}}_{{user_agent}}.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class Skia{{ url_name|capitalize }}{{ user_agent|capitalize }}PageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(Skia{{ url_name|capitalize }}{{ user_agent|capitalize }}PageSet, self).__init__(
+      archive_data_file='data/skia_{{url_name}}_{{user_agent}}.json')
+
+    urls_list = [
+      # {{comment}}
+      '{{url}}',
+    ]
+
+    for url in urls_list:
+      self.AddStory(Skia{{ user_agent|capitalize }}Page(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/__init__.py b/src/third_party/skia/tools/skp/page_sets/__init__.py
new file mode 100644
index 0000000..4a12e35
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_amazon_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_amazon_mobile.py
new file mode 100644
index 0000000..814bb8a
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_amazon_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaBuildbotMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaBuildbotMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_amazon_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaAmazonMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaAmazonMobilePageSet, self).__init__(
+      archive_data_file='data/skia_amazon_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.amazon.com/s?k=nicolas+cage&ref=is_box_',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaBuildbotMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_baidu_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_baidu_mobile.py
new file mode 100644
index 0000000..58dc713
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_baidu_mobile.py
@@ -0,0 +1,41 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_baidu_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaBaiduMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaBaiduMobilePageSet, self).__init__(
+      archive_data_file='data/skia_baidu_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      ('http://www.baidu.com/s?wd=barack+obama&rsv_bp=0&rsv_spt=3&rsv_sug3=9'
+       '&rsv_sug=0&rsv_sug4=3824&rsv_sug1=3&inputT=4920'),
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_booking_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_booking_mobile.py
new file mode 100644
index 0000000..d158bcd
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_booking_mobile.py
@@ -0,0 +1,41 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_booking_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(30)
+
+
+class SkiaBookingMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaBookingMobilePageSet, self).__init__(
+      archive_data_file='data/skia_booking_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      ('http://www.booking.com/searchresults.html?src=searchresults'
+       '&latitude=65.0500&longitude=25.4667'),
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_capitalvolkswagen_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_capitalvolkswagen_mobile.py
new file mode 100644
index 0000000..3db39a4
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_capitalvolkswagen_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_capitalvolkswagen_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(30)
+
+
+class SkiaCapitalvolkswagenMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaCapitalvolkswagenMobilePageSet, self).__init__(
+      archive_data_file='data/skia_capitalvolkswagen_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      ('https://www.capitolvolkswagen.com/new-vehicles/'),
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_carsvg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_carsvg_desktop.py
index 8b9cc05..9e0670a 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_carsvg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_carsvg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_carsvg_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_chalkboard_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_chalkboard_desktop.py
index 5aedcda..d5ebd3d 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_chalkboard_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_chalkboard_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_chalkboard_desktop.json'
 
@@ -30,8 +30,8 @@
 
     urls_list = [
       # Why: from fmalita
-      ('http://ie.microsoft.com/testdrive/Performance/Chalkboard/Images/'
-       'Chalkboard.svg'),
+      ('https://testdrive-archive.azurewebsites.net/performance/chalkboard/'
+       'Images/Chalkboard.svg'),
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_cnn_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_cnn_desktop.py
new file mode 100644
index 0000000..06cd8c3
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_cnn_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_cnn_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaCnnDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaCnnDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_cnn_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://www.cnn.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_cnn_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_cnn_mobile.py
new file mode 100644
index 0000000..63d2f17
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_cnn_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_cnn_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaCnnMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaCnnMobilePageSet, self).__init__(
+      archive_data_file='data/skia_cnn_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://www.cnn.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_cnnarticle_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_cnnarticle_mobile.py
new file mode 100644
index 0000000..5cb8231
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_cnnarticle_mobile.py
@@ -0,0 +1,41 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_cnnarticle_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaCnnarticleMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaCnnarticleMobilePageSet, self).__init__(
+      archive_data_file='data/skia_cnnarticle_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      ('https://www.cnn.com/2019/05/16/entertainment/'
+       'the-big-bang-theory-series-finale-review/index.html'),
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_css3gradients_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_css3gradients_desktop.py
index c6ddb63..594faf1 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_css3gradients_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_css3gradients_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_css3gradients_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_deviantart_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_deviantart_mobile.py
new file mode 100644
index 0000000..326822d
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_deviantart_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_deviantart_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(45)
+
+
+class SkiaDeviantartMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaDeviantartMobilePageSet, self).__init__(
+      archive_data_file='data/skia_deviantart_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.deviantart.com/whats-hot/',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_digg_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_digg_tablet.py
similarity index 69%
rename from src/third_party/skia/tools/skp/page_sets/skia_digg_nexus10.py
rename to src/third_party/skia/tools/skp/page_sets/skia_digg_tablet.py
index 2d3288f..fe64ceb 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_digg_nexus10.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_digg_tablet.py
@@ -14,22 +14,21 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.Shared10InchTabletPageState)
-    self.archive_data_file = 'data/skia_digg_nexus10.json'
+        shared_page_state_class=shared_page_state.SharedTabletPageState)
+    self.archive_data_file = 'data/skia_digg_tablet.json'
 
   def RunNavigateSteps(self, action_runner):
     action_runner.Navigate(self.url)
-    action_runner.Wait(5)
+    action_runner.Wait(30)
 
-class SkiaDiggNexus10PageSet(story.StorySet):
-
+class SkiaDiggTabletPageSet(story.StorySet):
   """ Pages designed to represent the median, not highly optimized web """
 
   def __init__(self):
-    super(SkiaDiggNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_digg_nexus10.json')
+    super(SkiaDiggTabletPageSet, self).__init__(
+      archive_data_file='data/skia_digg_tablet.json')
 
     urls_list = [
       # Why: from Clank CY.
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_ebay_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_ebay_desktop.py
new file mode 100644
index 0000000..80f41cb
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_ebay_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_ebay_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaEbayDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaEbayDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_ebay_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://www.ebay.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_espn_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_espn_desktop.py
index a7c7e20..aae4e3c 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_espn_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_espn_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_espn_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_facebook_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_facebook_desktop.py
new file mode 100644
index 0000000..7fcb17d
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_facebook_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_facebook_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaFacebookDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaFacebookDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_facebook_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.facebook.com/barackobama',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_facebook_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_facebook_mobile.py
new file mode 100644
index 0000000..77a63ba
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_facebook_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_facebook_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(30)
+
+
+class SkiaFacebookMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaFacebookMobilePageSet, self).__init__(
+      archive_data_file='data/skia_facebook_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://facebook.com/barackobama',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_forecastio_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_forecastio_mobile.py
new file mode 100644
index 0000000..03bd4dd
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_forecastio_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_forecastio_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaForecastioMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaForecastioMobilePageSet, self).__init__(
+      archive_data_file='data/skia_forecastio_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://forecast.io',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_gamedeksiam_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_gamedeksiam_nexus10.py
deleted file mode 100644
index 1f36f1d..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_gamedeksiam_nexus10.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.Shared10InchTabletPageState)
-    self.archive_data_file = 'data/skia_gamedeksiam_nexus10.json'
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(5)
-
-
-class SkiaGamedeksiamNexus10PageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaGamedeksiamNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_gamedeksiam_nexus10.json')
-
-    urls_list = [
-      # Why: from Tom W's list.
-      'http://game.deksiam.in.th/',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_gmail_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_gmail_desktop.py
new file mode 100644
index 0000000..2e97800
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_gmail_desktop.py
@@ -0,0 +1,52 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+import os
+
+from page_sets.login_helpers import google_login
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+from telemetry.util import wpr_modes
+
+
+class SkiaBuildbotDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaBuildbotDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_gmail_desktop.json'
+
+  def RunSmoothness(self, action_runner):
+    action_runner.ScrollElement()
+
+  def RunNavigateSteps(self, action_runner):
+    if self.wpr_mode != wpr_modes.WPR_REPLAY:
+      credentials_path = os.path.join(
+          os.path.dirname(os.path.abspath(__file__)), 'data/credentials.json')
+      google_login.BaseLoginGoogle(action_runner, 'google', credentials_path)
+      action_runner.Wait(10)
+    action_runner.Navigate(self.url)
+    action_runner.Wait(10)
+
+
+class SkiaGmailDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGmailDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_gmail_desktop.json')
+
+    urls_list = [
+      # Why: productivity, top google properties, long email .
+      'https://mail.google.com/mail/?shva=1#inbox/13ba91194d0b8a2e',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_gmail_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_gmail_nexus10.py
deleted file mode 100644
index 9a3411d..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_gmail_nexus10.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.Shared10InchTabletPageState)
-    self.archive_data_file = 'data/skia_gmail_nexus10.json'
-    self.credentials = 'google'
-
-  def RunSmoothness(self, action_runner):
-    action_runner.ScrollElement()
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(10)
-
-
-class SkiaGmailNexus10PageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaGmailNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_gmail_nexus10.json')
-
-    urls_list = [
-      # Why: productivity, top google properties
-      'https://mail.google.com/mail/',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_gmailthread_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_gmailthread_desktop.py
deleted file mode 100644
index 6316b0b..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_gmailthread_desktop.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_gmailthread_desktop.json'
-    self.credentials = 'google'
-
-  def RunSmoothness(self, action_runner):
-    action_runner.ScrollElement()
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(15)
-
-
-class SkiaGmailthreadDesktopPageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaGmailthreadDesktopPageSet, self).__init__(
-      archive_data_file='data/skia_gmailthread_desktop.json')
-
-    urls_list = [
-      # Why: productivity, top google properties, long email thread.
-      'https://mail.google.com/mail/?shva=1#inbox/13ba91194d0b8a2e',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlecalendar_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googlecalendar_desktop.py
new file mode 100644
index 0000000..a21ab7c
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googlecalendar_desktop.py
@@ -0,0 +1,49 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+import os
+
+from page_sets.login_helpers import google_login
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+from telemetry.util import wpr_modes
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_googlecalendar_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    if self.wpr_mode != wpr_modes.WPR_REPLAY:
+      credentials_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                    'data/credentials.json')
+      google_login.BaseLoginGoogle(action_runner, 'google', credentials_path)
+      action_runner.Wait(15)
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGooglecalendarDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGooglecalendarDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_googlecalendar_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.google.com/calendar/',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googledocs_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googledocs_desktop.py
new file mode 100644
index 0000000..24f2ee2
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googledocs_desktop.py
@@ -0,0 +1,50 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+import os
+
+from page_sets.login_helpers import google_login
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+from telemetry.util import wpr_modes
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_googledocs_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    if self.wpr_mode != wpr_modes.WPR_REPLAY:
+      credentials_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                    'data/credentials.json')
+      google_login.BaseLoginGoogle(action_runner, 'google', credentials_path)
+      action_runner.Wait(15)
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGoogledocsDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGoogledocsDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_googledocs_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      ('https://docs.google.com/document/d/'
+       '1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view'),
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlehome_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googlehome_desktop.py
deleted file mode 100644
index 5c5779c..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_googlehome_desktop.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_googlehome_desktop.json'
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(5)
-
-
-class SkiaGooglehomeDesktopPageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaGooglehomeDesktopPageSet, self).__init__(
-      archive_data_file='data/skia_googlehome_desktop.json')
-
-    urls_list = [
-      # Why: top google property; a google tab is often open
-      'http://www.google.com/',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googleimagesearch_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googleimagesearch_desktop.py
new file mode 100644
index 0000000..06599ee
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googleimagesearch_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_googleimagesearch_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGoogleimagesearchDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGoogleimagesearchDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_googleimagesearch_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.google.com/search?q=cats&tbm=isch',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlenews_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_googlenews_mobile.py
new file mode 100644
index 0000000..23956e6
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googlenews_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_googlenews_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGooglenewsMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGooglenewsMobilePageSet, self).__init__(
+      archive_data_file='data/skia_googlenews_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://news.google.com/',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_desktop.py
new file mode 100644
index 0000000..1c828fa
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_googlesearch_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGooglesearchDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGooglesearchDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_googlesearch_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.google.com/#hl=en&q=barack+obama',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_mobile.py
new file mode 100644
index 0000000..5ccb2aa
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googlesearch_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_googlesearch_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaGooglesearchMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaGooglesearchMobilePageSet, self).__init__(
+      archive_data_file='data/skia_googlesearch_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.google.co.uk/search?hl=en&q=barack+obama&cad=h',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_googlespreadsheet_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_googlespreadsheet_desktop.py
index ce65456..ad6bc98 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_googlespreadsheet_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_googlespreadsheet_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_googlespreadsheet_desktop.json'
 
@@ -31,7 +31,7 @@
     urls_list = [
       # Why: from Tom W's list.
       ('https://docs.google.com/spreadsheets/d/'
-       '1YnmSPu-p-1nj-lkWd8q_GRgzjiWzg_6A-HvFYqVoVxI/edit?usp=sharing'),
+       '1YnmSPu-p-1nj-lkWd8q_GRgzjiWzg_6A-HvFYqVoVxI/edit#gid=0'),
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_jsfiddlebigcar_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_jsfiddlebigcar_desktop.py
deleted file mode 100644
index 57b14fd..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_jsfiddlebigcar_desktop.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_jsfiddlebigcar_desktop.json'
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(5)
-
-
-class SkiaJsfiddlebigcarDesktopPageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaJsfiddlebigcarDesktopPageSet, self).__init__(
-      archive_data_file='data/skia_jsfiddlebigcar_desktop.json')
-
-    urls_list = [
-      # Why: Page from Chromium's silk test cases
-      'http://jsfiddle.net/vBQHH/3/embedded/result/',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_linkedin_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_linkedin_desktop.py
new file mode 100644
index 0000000..fa7552f
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_linkedin_desktop.py
@@ -0,0 +1,50 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+import os
+
+from page_sets.login_helpers import linkedin_login
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+from telemetry.util import wpr_modes
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_linkedin_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    if self.wpr_mode != wpr_modes.WPR_REPLAY:
+      credentials_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                                    'data/credentials.json')
+      linkedin_login.LoginDesktopAccount(action_runner, 'linkedin',
+                                         credentials_path)
+      action_runner.Wait(15)
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaLinkedinDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaLinkedinDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_linkedin_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.linkedin.com/in/linustorvalds',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_mapsvg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_mapsvg_desktop.py
index a5f7649..e1694c4 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_mapsvg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_mapsvg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_mapsvg_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_mozilla_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_mozilla_tablet.py
similarity index 71%
rename from src/third_party/skia/tools/skp/page_sets/skia_mozilla_nexus10.py
rename to src/third_party/skia/tools/skp/page_sets/skia_mozilla_tablet.py
index be56b4c..3537deb 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_mozilla_nexus10.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_mozilla_tablet.py
@@ -14,23 +14,22 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_mozilla_nexus10.json'
+        shared_page_state_class=shared_page_state.SharedTabletPageState)
+    self.archive_data_file = 'data/skia_mozilla_tablet.json'
 
   def RunNavigateSteps(self, action_runner):
     action_runner.Navigate(self.url)
     action_runner.Wait(5)
 
 
-class SkiaMozillaNexus10PageSet(story.StorySet):
-
+class SkiaMozillaTabletPageSet(story.StorySet):
   """ Pages designed to represent the median, not highly optimized web """
 
   def __init__(self):
-    super(SkiaMozillaNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_mozilla_nexus10.json')
+    super(SkiaMozillaTabletPageSet, self).__init__(
+      archive_data_file='data/skia_mozilla_tablet.json')
 
     urls_list = [
       # Why:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_nytimes_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_nytimes_desktop.py
index 6276bdf..9124965 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_nytimes_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_nytimes_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_nytimes_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_pokemonwiki_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_pokemonwiki_desktop.py
index def33eb..3464193 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_pokemonwiki_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_pokemonwiki_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_pokemonwiki_desktop.json'
 
@@ -33,8 +33,8 @@
       archive_data_file='data/skia_pokemonwiki_desktop.json')
 
     urls_list = [
-      # Why: http://code.google.com/p/chromium/issues/detail?id=136555
-      'http://en.wikipedia.org/wiki/List_of_Pok%C3%A9mon',
+      # go/skia-skps-3-19
+      'https://pokemondb.net/pokedex/all',
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_pravda_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_pravda_tablet.py
similarity index 71%
rename from src/third_party/skia/tools/skp/page_sets/skia_pravda_nexus10.py
rename to src/third_party/skia/tools/skp/page_sets/skia_pravda_tablet.py
index 35d042e..944b60b 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_pravda_nexus10.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_pravda_tablet.py
@@ -14,23 +14,22 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.Shared10InchTabletPageState)
-    self.archive_data_file = 'data/skia_pravda_nexus10.json'
+        shared_page_state_class=shared_page_state.SharedTabletPageState)
+    self.archive_data_file = 'data/skia_pravda_tablet.json'
 
   def RunNavigateSteps(self, action_runner):
     action_runner.Navigate(self.url)
     action_runner.Wait(5)
 
 
-class SkiaPravdaNexus10PageSet(story.StorySet):
-
+class SkiaPravdaTabletPageSet(story.StorySet):
   """ Pages designed to represent the median, not highly optimized web """
 
   def __init__(self):
-    super(SkiaPravdaNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_pravda_nexus10.json')
+    super(SkiaPravdaTabletPageSet, self).__init__(
+      archive_data_file='data/skia_pravda_tablet.json')
 
     urls_list = [
       # Why: cyrillic font test case
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_reddit_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_reddit_mobile.py
new file mode 100644
index 0000000..fe51114
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_reddit_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_reddit_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(30)
+
+
+class SkiaRedditMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaRedditMobilePageSet, self).__init__(
+      archive_data_file='data/skia_reddit_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.reddit.com/r/programming/comments/1g96ve/',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_samoasvg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_samoasvg_desktop.py
index ca2e907..6689ffd 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_samoasvg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_samoasvg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_samoasvg_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_slashdot_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_slashdot_mobile.py
new file mode 100644
index 0000000..08f1b71
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_slashdot_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_slashdot_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaSlashdotMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaSlashdotMobilePageSet, self).__init__(
+      archive_data_file='data/skia_slashdot_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://slashdot.org',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_techcrunch_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_techcrunch_mobile.py
new file mode 100644
index 0000000..16a8937
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_techcrunch_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_techcrunch_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaTechcrunchMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaTechcrunchMobilePageSet, self).__init__(
+      archive_data_file='data/skia_techcrunch_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://techcrunch.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_theverge_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_theverge_desktop.py
index 76f3a92..107e404 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_theverge_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_theverge_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_theverge_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_theverge_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_theverge_mobile.py
new file mode 100644
index 0000000..9e4159a
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_theverge_mobile.py
@@ -0,0 +1,41 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaBuildbotMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaBuildbotMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_theverge_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaThevergeMobilePageSet(story.StorySet):
+
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaThevergeMobilePageSet, self).__init__(
+      archive_data_file='data/skia_theverge_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://theverge.com/',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaBuildbotMobilePage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_tiger8svg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_tiger8svg_desktop.py
index d950a74..b7e7877 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_tiger8svg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_tiger8svg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_tiger8svg_desktop.json'
 
@@ -34,7 +34,8 @@
 
     urls_list = [
       # Why: from skbug.com/4713
-      'http://www.googledrive.com/host/0B5nDjttF0gt9QzJjdjRNVlNvems',
+      ('https://storage.googleapis.com/skia-infra-testdata/images-for-skps/'
+       'tiger-8.svg'),
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_tigersvg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_tigersvg_desktop.py
index fb40acb..9d14e30 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_tigersvg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_tigersvg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_tigersvg_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_twitter_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_twitter_desktop.py
new file mode 100644
index 0000000..a6f19ae
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_twitter_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_twitter_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaTwitterDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaTwitterDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_twitter_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://twitter.com/katyperry',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_ugamsolutions_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_ugamsolutions_desktop.py
deleted file mode 100644
index 26b643e..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_ugamsolutions_desktop.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_ugamsolutions_desktop.json'
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.Wait(15)
-
-
-class SkiaUgamsolutionsDesktopPageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaUgamsolutionsDesktopPageSet, self).__init__(
-      archive_data_file='data/skia_ugamsolutions_desktop.json')
-
-    urls_list = [
-      # Why: for crbug.com/447291
-      'http://www.ugamsolutions.com',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_unicodetable_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_unicodetable_desktop.py
deleted file mode 100644
index b4c90f0..0000000
--- a/src/third_party/skia/tools/skp/page_sets/skia_unicodetable_desktop.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0401,W0614
-
-
-from telemetry import story
-from telemetry.page import page as page_module
-from telemetry.page import shared_page_state
-
-
-class SkiaBuildbotDesktopPage(page_module.Page):
-
-  def __init__(self, url, page_set):
-    super(SkiaBuildbotDesktopPage, self).__init__(
-        url=url,
-        page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
-    self.archive_data_file = 'data/skia_unicodetable_desktop.json'
-
-  def RunNavigateSteps(self, action_runner):
-    action_runner.Navigate(self.url)
-    action_runner.ScrollPage(distance=100000)
-    action_runner.Wait(20)
-
-
-class SkiaUnicodetableDesktopPageSet(story.StorySet):
-
-  """ Pages designed to represent the median, not highly optimized web """
-
-  def __init__(self):
-    super(SkiaUnicodetableDesktopPageSet, self).__init__(
-      archive_data_file='data/skia_unicodetable_desktop.json')
-
-    urls_list = [
-      # Why: stress tests for fonts (from skia:3574).
-      'http://unicode-table.com/en/',
-    ]
-
-    for url in urls_list:
-      self.AddStory(SkiaBuildbotDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_weather_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_weather_desktop.py
new file mode 100644
index 0000000..5a2ffa3
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_weather_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_weather_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaWeatherDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaWeatherDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_weather_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://weather.com/weather/today/l/94043:4:US',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_desktop.py
index 10bb061..363d697 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_wikipedia_desktop.json'
 
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_mobile.py
new file mode 100644
index 0000000..28076d2
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_wikipedia_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_wikipedia_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaWikipediaMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaWikipediaMobilePageSet, self).__init__(
+      archive_data_file='data/skia_wikipedia_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://en.wikipedia.org/wiki/Wikipedia',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_worldjournal_nexus10.py b/src/third_party/skia/tools/skp/page_sets/skia_worldjournal_tablet.py
similarity index 67%
rename from src/third_party/skia/tools/skp/page_sets/skia_worldjournal_nexus10.py
rename to src/third_party/skia/tools/skp/page_sets/skia_worldjournal_tablet.py
index 713a4aa..b7d62b8 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_worldjournal_nexus10.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_worldjournal_tablet.py
@@ -14,19 +14,18 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
-        shared_page_state_class=shared_page_state.Shared10InchTabletPageState)
-    self.archive_data_file = 'data/skia_worldjournal_nexus10.json'
+        shared_page_state_class=shared_page_state.SharedTabletPageState)
+    self.archive_data_file = 'data/skia_worldjournal_tablet.json'
 
 
-class SkiaWorldjournalNexus10PageSet(story.StorySet):
-
+class SkiaWorldjournalTabletPageSet(story.StorySet):
   """ Pages designed to represent the median, not highly optimized web """
 
   def __init__(self):
-    super(SkiaWorldjournalNexus10PageSet, self).__init__(
-      archive_data_file='data/skia_worldjournal_nexus10.json')
+    super(SkiaWorldjournalTabletPageSet, self).__init__(
+      archive_data_file='data/skia_worldjournal_tablet.json')
 
     urls_list = [
       # Why: Chinese font test case
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_wowwiki_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_wowwiki_desktop.py
index 54e9acb..78ab738 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_wowwiki_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_wowwiki_desktop.py
@@ -14,14 +14,15 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_wowwiki_desktop.json'
 
   def RunNavigateSteps(self, action_runner):
     action_runner.Navigate(self.url)
-    action_runner.Wait(25)
+    action_runner.ScrollPage(distance=6000000)
+    action_runner.Wait(60)
 
 
 class SkiaWowwikiDesktopPageSet(story.StorySet):
@@ -33,8 +34,9 @@
       archive_data_file='data/skia_wowwiki_desktop.json')
 
     urls_list = [
-      # Why: http://code.google.com/p/chromium/issues/detail?id=136555
-      'http://www.wowwiki.com/World_of_Warcraft:_Mists_of_Pandaria',
+      # Why: go/skia-skps-3-2019
+      ('https://wowwiki.fandom.com/wiki/World_of_Warcraft:'
+       '_Wrath_of_the_Lich_King'),
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_yahooanswers_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_yahooanswers_desktop.py
new file mode 100644
index 0000000..3204360
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_yahooanswers_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_yahooanswers_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaYahooanswersDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaYahooanswersDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_yahooanswers_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://answers.yahoo.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_yahoosports_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_yahoosports_desktop.py
new file mode 100644
index 0000000..0a7cd79
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_yahoosports_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_yahoosports_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaYahoosportsDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaYahoosportsDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_yahoosports_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://sports.yahoo.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_ynevsvg_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_ynevsvg_desktop.py
index 04acd10..cd63195 100644
--- a/src/third_party/skia/tools/skp/page_sets/skia_ynevsvg_desktop.py
+++ b/src/third_party/skia/tools/skp/page_sets/skia_ynevsvg_desktop.py
@@ -14,8 +14,8 @@
   def __init__(self, url, page_set):
     super(SkiaBuildbotDesktopPage, self).__init__(
         url=url,
+        name=url,
         page_set=page_set,
-        credentials_path='data/credentials.json',
         shared_page_state_class=shared_page_state.SharedDesktopPageState)
     self.archive_data_file = 'data/skia_ynevsvg_desktop.json'
 
@@ -34,7 +34,8 @@
 
     urls_list = [
       # Why: from skbug.com/4713
-      'http://www.googledrive.com/host/0B5nDjttF0gt9QjRKdEZ5MEVYc2c',
+      ('https://storage.googleapis.com/skia-infra-testdata/images-for-skps/'
+       'ynev.svg'),
     ]
 
     for url in urls_list:
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_youtube_desktop.py b/src/third_party/skia/tools/skp/page_sets/skia_youtube_desktop.py
new file mode 100644
index 0000000..513a067
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_youtube_desktop.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaDesktopPage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaDesktopPage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+    self.archive_data_file = 'data/skia_youtube_desktop.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaYoutubeDesktopPageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaYoutubeDesktopPageSet, self).__init__(
+      archive_data_file='data/skia_youtube_desktop.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'http://www.youtube.com',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaDesktopPage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/page_sets/skia_youtube_mobile.py b/src/third_party/skia/tools/skp/page_sets/skia_youtube_mobile.py
new file mode 100644
index 0000000..4e23040
--- /dev/null
+++ b/src/third_party/skia/tools/skp/page_sets/skia_youtube_mobile.py
@@ -0,0 +1,40 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# pylint: disable=W0401,W0614
+
+
+from telemetry import story
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+
+class SkiaMobilePage(page_module.Page):
+
+  def __init__(self, url, page_set):
+    super(SkiaMobilePage, self).__init__(
+        url=url,
+        name=url,
+        page_set=page_set,
+        shared_page_state_class=shared_page_state.SharedMobilePageState)
+    self.archive_data_file = 'data/skia_youtube_mobile.json'
+
+  def RunNavigateSteps(self, action_runner):
+    action_runner.Navigate(self.url)
+    action_runner.Wait(15)
+
+
+class SkiaYoutubeMobilePageSet(story.StorySet):
+  """ Pages designed to represent the median, not highly optimized web """
+
+  def __init__(self):
+    super(SkiaYoutubeMobilePageSet, self).__init__(
+      archive_data_file='data/skia_youtube_mobile.json')
+
+    urls_list = [
+      # go/skia-skps-3-2019
+      'https://www.youtube.com/watch?v=9hBpF_Zj4OA',
+    ]
+
+    for url in urls_list:
+      self.AddStory(SkiaMobilePage(url, self))
\ No newline at end of file
diff --git a/src/third_party/skia/tools/skp/webpages_playback.py b/src/third_party/skia/tools/skp/webpages_playback.py
index b800d85..1b5d5f9 100644
--- a/src/third_party/skia/tools/skp/webpages_playback.py
+++ b/src/third_party/skia/tools/skp/webpages_playback.py
@@ -33,11 +33,10 @@
 to capture archives and/or capture SKP files. Majority of the time it should be
 a newly built chrome binary.
 
-The --data_store flag controls where the needed artifacts, such as
-credential files, are downloaded from. It also controls where the
-generated artifacts, such as recorded webpages and resulting skp renderings,
-are uploaded to. URLs with scheme 'gs://' use Google Storage. Otherwise
-use local filesystem.
+The --data_store flag controls where the needed artifacts are downloaded from.
+It also controls where the generated artifacts, such as recorded webpages and
+resulting skp renderings, are uploaded to. URLs with scheme 'gs://' use Google
+Storage. Otherwise use local filesystem.
 
 The --upload=True flag means generated artifacts will be
 uploaded or copied to the location specified by --data_store. (default value is
@@ -52,6 +51,7 @@
 they can be added to the buildbots with no breakages.
 """
 
+import datetime
 import glob
 import optparse
 import os
@@ -92,14 +92,14 @@
 # Dictionary of device to platform prefixes for SKP files.
 DEVICE_TO_PLATFORM_PREFIX = {
     'desktop': 'desk',
-    'galaxynexus': 'mobi',
-    'nexus10': 'tabl'
+    'mobile': 'mobi',
+    'tablet': 'tabl'
 }
 
 # How many times the record_wpr binary should be retried.
 RETRY_RECORD_WPR_COUNT = 5
 # How many times the run_benchmark binary should be retried.
-RETRY_RUN_MEASUREMENT_COUNT = 5
+RETRY_RUN_MEASUREMENT_COUNT = 3
 
 # Location of the credentials.json file in Google Storage.
 CREDENTIALS_GS_PATH = 'playback/credentials/credentials.json'
@@ -111,10 +111,20 @@
 
 # Dictionary of supported Chromium page sets to their file prefixes.
 CHROMIUM_PAGE_SETS_TO_PREFIX = {
-    'key_mobile_sites_smooth.py': 'keymobi',
-    'top_25_smooth.py': 'top25desk',
 }
 
+PAGE_SETS_TO_EXCLUSIONS = {
+    # See skbug.com/7348
+    'key_mobile_sites_smooth.py': '"(digg|worldjournal|twitter|espn)"',
+    # See skbug.com/7421
+    'top_25_smooth.py': '"(mail\.google\.com)"',
+}
+
+
+class InvalidSKPException(Exception):
+  """Raised when the created SKP is invalid."""
+  pass
+
 
 def remove_prefix(s, prefix):
   if s.startswith(prefix):
@@ -200,19 +210,14 @@
       self.gs.download_file(CREDENTIALS_GS_PATH, CREDENTIALS_FILE_PATH)
 
     if not os.path.isfile(CREDENTIALS_FILE_PATH):
-      print """\n\nCould not locate credentials file in the storage.
-      Please create a %s file that contains:
+      raise Exception("""Could not locate credentials file in the storage.
+      Please create a credentials file in gs://%s that contains:
       {
         "google": {
           "username": "google_testing_account_username",
           "password": "google_testing_account_password"
-        },
-        "facebook": {
-          "username": "facebook_testing_account_username",
-          "password": "facebook_testing_account_password"
         }
-      }\n\n""" % CREDENTIALS_FILE_PATH
-      raw_input("Please press a key when you are ready to proceed...")
+      }\n\n""" % CREDENTIALS_GS_PATH)
 
     # Delete any left over data files in the data directory.
     for archive_file in glob.glob(
@@ -227,10 +232,12 @@
 
     # Loop through all page_sets.
     for page_set in self._page_sets:
-
+      if os.path.basename(page_set) == '__init__.py':
+        continue
       page_set_basename = os.path.basename(page_set).split('.')[0]
       page_set_json_name = page_set_basename + '.json'
-      wpr_data_file = page_set.split(os.path.sep)[-1].split('.')[0] + '_000.wpr'
+      wpr_data_file_glob = (
+          page_set.split(os.path.sep)[-1].split('.')[0] + '_*.wprgo')
       page_set_dir = os.path.dirname(page_set)
 
       if self._IsChromiumPageSet(page_set):
@@ -254,9 +261,11 @@
 
             # Copy over the created archive into the local webpages archive
             # directory.
-            shutil.copy(
-              os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file),
-              self._local_record_webpages_archive_dir)
+            for wpr_data_file in glob.glob(os.path.join(
+                LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file_glob)):
+              shutil.copy(
+                os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR, wpr_data_file),
+                self._local_record_webpages_archive_dir)
             shutil.copy(
               os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
                            page_set_json_name),
@@ -274,9 +283,9 @@
 
       else:
         # Get the webpages archive so that it can be replayed.
-        self._DownloadWebpagesArchive(wpr_data_file, page_set_json_name)
+        self._DownloadWebpagesArchive(wpr_data_file_glob, page_set_json_name)
 
-      run_benchmark_cmd = (
+      run_benchmark_cmd = [
           'PYTHONPATH=%s:%s:$PYTHONPATH' % (page_set_dir, self._catapult_dir),
           'DISPLAY=%s' % X11_DISPLAY,
           'timeout', '1800',
@@ -288,28 +297,36 @@
           '--page-set-name=%s' % page_set_basename,
           '--page-set-base-dir=%s' % page_set_dir,
           '--skp-outdir=%s' % TMP_SKP_DIR,
-          '--also-run-disabled-tests'
-      )
+          '--also-run-disabled-tests',
+      ]
+
+      exclusions = PAGE_SETS_TO_EXCLUSIONS.get(os.path.basename(page_set))
+      if exclusions:
+        run_benchmark_cmd.append('--story-filter-exclude=' + exclusions)
 
       for _ in range(RETRY_RUN_MEASUREMENT_COUNT):
         try:
           print '\n\n=======Capturing SKP of %s=======\n\n' % page_set
           subprocess.check_call(' '.join(run_benchmark_cmd), shell=True)
         except subprocess.CalledProcessError:
-          # skpicture_printer sometimes fails with AssertionError but the
-          # captured SKP is still valid. This is a known issue.
-          pass
-
-        # Rename generated SKP files into more descriptive names.
-        try:
-          self._RenameSkpFiles(page_set)
-          # Break out of the retry loop since there were no errors.
-          break
-        except Exception:
           # There was a failure continue with the loop.
           traceback.print_exc()
           print '\n\n=======Retrying %s=======\n\n' % page_set
           time.sleep(10)
+          continue
+
+        try:
+          # Rename generated SKP files into more descriptive names.
+          self._RenameSkpFiles(page_set)
+        except InvalidSKPException:
+          # There was a failure continue with the loop.
+          traceback.print_exc()
+          print '\n\n=======Retrying %s=======\n\n' % page_set
+          time.sleep(10)
+          continue
+
+        # Break out of the retry loop since there were no errors.
+        break
       else:
         # If we get here then run_benchmark did not succeed and thus did not
         # break out of the loop.
@@ -362,11 +379,16 @@
       print '\n\n=======Uploading to Partner bucket %s =======\n\n' % (
           PARTNERS_GS_BUCKET)
       partner_gs = GoogleStorageDataStore(PARTNERS_GS_BUCKET)
-      partner_gs.delete_path(SKPICTURES_DIR_NAME)
-      print 'Uploading %s to %s' % (self._local_skp_dir, SKPICTURES_DIR_NAME)
-      partner_gs.upload_dir_contents(self._local_skp_dir, SKPICTURES_DIR_NAME)
+      timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%d')
+      upload_dir = posixpath.join(SKPICTURES_DIR_NAME, timestamp)
+      try:
+        partner_gs.delete_path(upload_dir)
+      except subprocess.CalledProcessError:
+        print 'Cannot delete %s because it does not exist yet.' % upload_dir
+      print 'Uploading %s to %s' % (self._local_skp_dir, upload_dir)
+      partner_gs.upload_dir_contents(self._local_skp_dir, upload_dir)
       print '\n\n=======New SKPs have been uploaded to %s =======\n\n' % (
-          posixpath.join(partner_gs.target_name(), SKPICTURES_DIR_NAME))
+          posixpath.join(partner_gs.target_name(), upload_dir))
 
     return 0
 
@@ -400,6 +422,10 @@
 
     Look into the subdirectory of TMP_SKP_DIR and find the most interesting
     .skp in there to be this page_set's representative .skp.
+
+    Throws InvalidSKPException if the chosen .skp is less than 1KB. This
+    typically happens when there is a 404 or a redirect loop. Anything greater
+    than 1KB seems to have captured at least some useful information.
     """
     subdirs = glob.glob(os.path.join(TMP_SKP_DIR, '*'))
     for site in subdirs:
@@ -420,6 +446,11 @@
       shutil.move(largest_skp, dest)
       self._skp_files.append(filename)
       shutil.rmtree(site)
+      skp_size = os.path.getsize(dest)
+      if skp_size < 1024:
+        raise InvalidSKPException(
+            'Size of %s is only %d. Something is wrong.' % (dest, skp_size))
+
 
   def _CreateLocalStorageDirs(self):
     """Creates required local storage directories for this script."""
@@ -439,9 +470,7 @@
     gs = self.gs
     if (gs.does_storage_object_exist(wpr_source) and
         gs.does_storage_object_exist(page_set_source)):
-      gs.download_file(wpr_source,
-                       os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
-                                    wpr_data_file))
+      gs.download_file(wpr_source, LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR)
       gs.download_file(page_set_source,
                        os.path.join(LOCAL_REPLAY_WEBPAGES_ARCHIVE_DIR,
                                     page_set_json_name))
diff --git a/src/third_party/skia/tools/skp_parser.cpp b/src/third_party/skia/tools/skp_parser.cpp
index 887c50d..595209f 100644
--- a/src/third_party/skia/tools/skp_parser.cpp
+++ b/src/third_party/skia/tools/skp_parser.cpp
@@ -5,17 +5,36 @@
  * found in the LICENSE file.
  */
 
-#include <iostream>
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "include/utils/SkNullCanvas.h"
+#include "tools/debugger/DebugCanvas.h"
 
-#include "SkDebugCanvas.h"
-#include "SkNullCanvas.h"
-#include "SkStream.h"
+#include <iostream>
 
 #ifdef SK_BUILD_FOR_WIN
 #include <fcntl.h>
 #include <io.h>
 #endif
 
+/*
+If you execute skp_parser with one argument, it spits out a json representation
+of the skp, but that's incomplete since it's missing many binary blobs (these
+could represent images or typefaces or just anything that doesn't currently
+have a json representation).  Each unique blob is labeled with a string in the
+form "data/%d".  So for example:
+
+    tools/git-sync-deps
+    bin/gn gen out/debug
+    ninja -C out/debug dm skp_parser
+    out/debug/dm -m grayscale -w /tmp/dm --config skp
+    out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp | less
+    out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp | grep data
+    out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp data/0 | file -
+    out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp data/0 > /tmp/data0.png
+
+"data/0" is an image that the SKP serializer has encoded as PNG.
+*/
 int main(int argc, char** argv) {
     if (argc < 2) {
         SkDebugf("Usage:\n  %s SKP_FILE [DATA_URL]\n", argv[0]);
@@ -32,12 +51,16 @@
         return 3;
     }
     SkISize size = pic->cullRect().roundOut().size();
-    SkDebugCanvas debugCanvas(size.width(), size.height());
+    DebugCanvas debugCanvas(size.width(), size.height());
     pic->playback(&debugCanvas);
     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
     UrlDataManager dataManager(SkString("data"));
-    Json::Value json = debugCanvas.toJSON(
-            dataManager, debugCanvas.getSize(), nullCanvas.get());
+    SkDynamicMemoryWStream stream;
+    SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
+    writer.beginObject(); // root
+    debugCanvas.toJSON(writer, dataManager, debugCanvas.getSize(), nullCanvas.get());
+    writer.endObject(); // root
+    writer.flush();
     if (argc > 2) {
         if (UrlDataManager::UrlData* data =
             dataManager.getDataFromUrl(SkString(argv[2]))) {
@@ -53,7 +76,8 @@
             return 4;
         }
     } else {
-        Json::StyledStreamWriter("  ").write(std::cout, json);
+        sk_sp<SkData> data = stream.detachAsData();
+        fwrite(data->data(), data->size(), 1, stdout);
     }
     return 0;
 }
diff --git a/src/third_party/skia/tools/skpbench/_adb.py b/src/third_party/skia/tools/skpbench/_adb.py
index 66ef623..9601dcb 100644
--- a/src/third_party/skia/tools/skpbench/_adb.py
+++ b/src/third_party/skia/tools/skpbench/_adb.py
@@ -5,16 +5,18 @@
 
 from __future__ import print_function
 import re
+import time
 import subprocess
 import sys
 
 class Adb:
-  def __init__(self, device_serial=None, echo=False):
-    self.__invocation = ['adb']
+  def __init__(self, device_serial=None, adb_binary=None, echo=False):
+    self.__invocation = [adb_binary]
     if device_serial:
       self.__invocation.extend(['-s', device_serial])
     self.__echo = echo
     self.__is_root = None
+    self.__has_established_connection = False
 
   def shell(self, cmd):
     if self.__echo:
@@ -24,6 +26,7 @@
   def check(self, cmd):
     if self.__echo:
       self.__echo_shell_cmd(cmd)
+    self.__establish_connection()
     result = subprocess.check_output(self.__invocation + ['shell', cmd])
     if self.__echo:
       print(result, file=sys.stderr)
@@ -32,7 +35,7 @@
   def root(self):
     if not self.is_root():
       self.__invoke('root')
-      self.__invoke('wait-for-device')
+      self.__has_established_connection = False
       self.__is_root = None
     return self.is_root()
 
@@ -44,6 +47,11 @@
   def remount(self):
     self.__invoke('remount')
 
+  def reboot(self):
+    self.__is_root = None
+    self.shell('reboot')
+    self.__has_established_connection = False
+
   def __echo_shell_cmd(self, cmd):
     escaped = [re.sub(r'([^a-zA-Z0-9])', r'\\\1', x)
                for x in cmd.strip().splitlines()]
@@ -51,4 +59,15 @@
                   " '\n>' ".join(escaped))
 
   def __invoke(self, *args):
+    self.__establish_connection()
     subprocess.call(self.__invocation + list(args), stdout=sys.stderr)
+
+  def __establish_connection(self):
+    if self.__has_established_connection:
+      return
+    self.__has_established_connection = True
+    self.__invoke('wait-for-device')
+    while True:
+      time.sleep(1)
+      if '1' == self.check('getprop sys.boot_completed').strip():
+        break
diff --git a/src/third_party/skia/tools/skpbench/_adb_path.py b/src/third_party/skia/tools/skpbench/_adb_path.py
index 4d8bce4..966ab44 100644
--- a/src/third_party/skia/tools/skpbench/_adb_path.py
+++ b/src/third_party/skia/tools/skpbench/_adb_path.py
@@ -9,9 +9,9 @@
 
 __ADB = None
 
-def init(device_serial):
+def init(device_serial, adb_binary):
   global __ADB
-  __ADB = Adb(device_serial)
+  __ADB = Adb(device_serial, adb_binary)
 
 def join(*pathnames):
   return '/'.join(pathnames)
@@ -20,12 +20,14 @@
   return pathname.rsplit('/', maxsplit=1)[-1]
 
 def find_skps(skps):
+  # root first, in case skps reside in a protected directory
+  __ADB.root()
   escapedskps = [re.sub(r'([^a-zA-Z0-9_/\.\*\?\[\!\]])', r'\\\1', x)
                  for x in skps]
   return __ADB.check('''\
     for PATHNAME in %s; do
       if [ -d "$PATHNAME" ]; then
-        find "$PATHNAME" -maxdepth 1 -name *.skp
+        find "$PATHNAME" -maxdepth 1 -name '*.skp' -o -name '*.mskp'
       else
         echo "$PATHNAME"
       fi
diff --git a/src/third_party/skia/tools/skpbench/_hardware.py b/src/third_party/skia/tools/skpbench/_hardware.py
index de8848d..9283243 100644
--- a/src/third_party/skia/tools/skpbench/_hardware.py
+++ b/src/third_party/skia/tools/skpbench/_hardware.py
@@ -41,10 +41,6 @@
     """Prints any info that may help improve or debug hardware monitoring."""
     pass
 
-  def sleep(self, sleeptime):
-    """Puts the hardware into a resting state for a fixed amount of time."""
-    time.sleep(sleeptime)
-
 
 class HardwareException(Exception):
   """Gets thrown when certain hardware state is not what we expect.
diff --git a/src/third_party/skia/tools/skpbench/_hardware_android.py b/src/third_party/skia/tools/skpbench/_hardware_android.py
index ebaba0a..499247b 100644
--- a/src/third_party/skia/tools/skpbench/_hardware_android.py
+++ b/src/third_party/skia/tools/skpbench/_hardware_android.py
@@ -16,10 +16,12 @@
 
     if self._adb.root():
       self._adb.remount()
-      self._initial_ASLR = \
-        self._adb.check('cat /proc/sys/kernel/randomize_va_space')
 
   def __enter__(self):
+    Hardware.__enter__(self)
+    if not self._adb.is_root() and self._adb.root():
+      self._adb.remount()
+
     self._adb.shell('\n'.join([
       # turn on airplane mode.
       '''
@@ -27,9 +29,9 @@
 
       # disable GPS.
       '''
-      for MODE in gps wifi network; do
-        settings put secure location_providers_allowed -$MODE
-      done''']))
+      settings put secure location_providers_allowed -gps
+      settings put secure location_providers_allowed -wifi
+      settings put secure location_providers_allowed -network''']))
 
     if self._adb.is_root():
       self._adb.shell('\n'.join([
@@ -53,23 +55,11 @@
       print("WARNING: no adb root access; results may be unreliable.",
             file=sys.stderr)
 
-    return Hardware.__enter__(self)
+    return self
 
   def __exit__(self, exception_type, exception_value, traceback):
     Hardware.__exit__(self, exception_type, exception_value, traceback)
-
-    if self._adb.is_root():
-      self._adb.shell('\n'.join([
-        # restore ASLR.
-        '''
-        echo %s > /proc/sys/kernel/randomize_va_space''' % self._initial_ASLR,
-
-        # revive the gui.
-        '''
-        setprop ctl.start drm
-        setprop ctl.start surfaceflinger
-        setprop ctl.start zygote
-        setprop ctl.start media''']))
+    self._adb.reboot() # some devices struggle waking up; just hard reboot.
 
   def sanity_check(self):
     Hardware.sanity_check(self)
@@ -102,6 +92,3 @@
       done''')
 
     Hardware.print_debug_diagnostics(self)
-
-  def sleep(self, sleeptime):
-    Hardware.sleep(self, sleeptime)
diff --git a/src/third_party/skia/tools/skpbench/_hardware_nexus_6p.py b/src/third_party/skia/tools/skpbench/_hardware_nexus_6p.py
index 077933b..e640835 100644
--- a/src/third_party/skia/tools/skpbench/_hardware_nexus_6p.py
+++ b/src/third_party/skia/tools/skpbench/_hardware_nexus_6p.py
@@ -14,23 +14,9 @@
     HardwareAndroid.__init__(self, adb)
 
   def __enter__(self):
-    self._lock_clocks()
-    return HardwareAndroid.__enter__(self)
-
-  def __exit__(self, exception_type, exception_value, exception_traceback):
-    HardwareAndroid.__exit__(self, exception_type,
-                             exception_value, exception_traceback)
-    self._unlock_clocks()
-
-  def _lock_clocks(self):
+    HardwareAndroid.__enter__(self)
     if not self._adb.is_root():
-      return
-
-    self._adb.shell('''\
-      stop thermal-engine
-      stop thermald
-      stop perfd
-      stop mpdecision''')
+      return self
 
     # enable and lock 3 of 4 big cores.
     self._adb.shell('''\
@@ -72,51 +58,7 @@
       echo 9887 > /sys/class/devfreq/qcom,gpubw.70/max_freq
       echo 9887 > /sys/class/devfreq/qcom,gpubw.70/min_freq''')
 
-  def _unlock_clocks(self):
-    if not self._adb.is_root():
-      return
-
-    # restore ddr settings to default.
-    self._adb.shell('''\
-      echo 1525 > /sys/class/devfreq/qcom,cpubw.32/min_freq
-      echo 9887 > /sys/class/devfreq/qcom,cpubw.32/max_freq
-      echo bw_hwmon > /sys/class/devfreq/qcom,cpubw.32/governor
-      echo 1525 > /sys/class/devfreq/qcom,gpubw.70/min_freq
-      echo 9887 > /sys/class/devfreq/qcom,gpubw.70/max_freq
-      echo bw_hwmon > /sys/class/devfreq/qcom,gpubw.70/governor''')
-
-    # restore gpu settings to default.
-    self._adb.shell('''\
-      echo 180000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
-      echo 600000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
-      echo 180000000 > /sys/class/kgsl/kgsl-3d0/gpuclk
-      echo msm-adreno-tz > /sys/class/kgsl/kgsl-3d0/devfreq/governor
-      echo 0 > /sys/class/kgsl/kgsl-3d0/idle_timer
-      echo 0 > /sys/class/kgsl/kgsl-3d0/force_clk_on
-      echo 0 > /sys/class/kgsl/kgsl-3d0/force_rail_on
-      echo 0 > /sys/class/kgsl/kgsl-3d0/force_bus_on
-      echo 1 > /sys/class/kgsl/kgsl-3d0/bus_split''')
-
-    # turn the disabled cores back on.
-    self._adb.shell('''\
-      for N in 7 3 2 1 0; do
-        echo 1 > /sys/devices/system/cpu/cpu$N/online
-      done''')
-
-    # unlock the 3 enabled big cores.
-    self._adb.shell('''\
-      for N in 6 5 4; do
-        echo 633600 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
-        echo 1958400 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
-        echo 0 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
-        echo interactive > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
-      done''')
-
-    self._adb.shell('''\
-      start mpdecision
-      start perfd
-      start thermald
-      start thermal-engine''')
+    return self
 
   def sanity_check(self):
     HardwareAndroid.sanity_check(self)
@@ -148,8 +90,3 @@
        for i in range(4, 7)]
 
     Expectation.check_all(expectations, result.splitlines())
-
-  def sleep(self, sleeptime):
-    self._unlock_clocks()
-    HardwareAndroid.sleep(self, sleeptime)
-    self._lock_clocks()
diff --git a/src/third_party/skia/tools/skpbench/_hardware_pixel.py b/src/third_party/skia/tools/skpbench/_hardware_pixel.py
new file mode 100644
index 0000000..7c254ac
--- /dev/null
+++ b/src/third_party/skia/tools/skpbench/_hardware_pixel.py
@@ -0,0 +1,90 @@
+# Copyright 2017 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from _hardware import Expectation
+from _hardware_android import HardwareAndroid
+
+CPU_CLOCK_RATE = 1670400
+GPU_CLOCK_RATE = 315000000
+
+class HardwarePixel(HardwareAndroid):
+  def __init__(self, adb):
+    HardwareAndroid.__init__(self, adb)
+
+  def __enter__(self):
+    HardwareAndroid.__enter__(self)
+    if not self._adb.is_root():
+      return self
+
+    self._adb.shell('\n'.join([
+      # enable and lock the two fast cores.
+      '''
+      stop thermal-engine
+      stop perfd
+
+      for N in 3 2; do
+        echo 1 > /sys/devices/system/cpu/cpu$N/online
+        echo userspace > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
+      done''' % tuple(CPU_CLOCK_RATE for _ in range(3)),
+
+      # turn off the two slow cores
+      '''
+      for N in 1 0; do
+        echo 0 > /sys/devices/system/cpu/cpu$N/online
+      done''',
+
+      # pylint: disable=line-too-long
+
+      # Set GPU bus and idle timer
+      # Set DDR frequency to max
+      # Set GPU to performance mode, 315 MHZ
+      # See https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/tests/scripts/prep_marlfish.sh
+      '''
+      echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split
+      echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on
+      echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer
+
+      echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/min_freq
+
+      echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor
+      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
+      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
+
+      echo 4 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
+      echo 4 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel''' %
+      tuple(GPU_CLOCK_RATE for _ in range(2))]))
+
+    return self
+
+  def sanity_check(self):
+    HardwareAndroid.sanity_check(self)
+
+    if not self._adb.is_root():
+      return
+
+    result = self._adb.check(' '.join(
+      ['cat',
+       '/sys/class/power_supply/battery/capacity',
+       '/sys/devices/system/cpu/online'] + \
+      ['/sys/devices/system/cpu/cpu%i/cpufreq/scaling_cur_freq' % i
+       for i in range(2, 4)] + \
+      ['/sys/kernel/debug/clk/bimc_clk/measure',
+       '/sys/class/thermal/thermal_zone22/temp',
+       '/sys/class/thermal/thermal_zone23/temp']))
+
+    expectations = \
+      [Expectation(int, min_value=30, name='battery', sleeptime=30*60),
+       Expectation(str, exact_value='2-3', name='online cpus')] + \
+      [Expectation(int, exact_value=CPU_CLOCK_RATE, name='cpu_%i clock rate' %i)
+       for i in range(2, 4)] + \
+       [Expectation(long, min_value=902390000, max_value=902409999,
+                   name='measured ddr clock', sleeptime=10),
+       Expectation(int, max_value=41000, name='pm8994_tz temperature'),
+       Expectation(int, max_value=40, name='msm_therm temperature')]
+
+    Expectation.check_all(expectations, result.splitlines())
diff --git a/src/third_party/skia/tools/skpbench/_hardware_pixel2.py b/src/third_party/skia/tools/skpbench/_hardware_pixel2.py
new file mode 100644
index 0000000..a42cafa
--- /dev/null
+++ b/src/third_party/skia/tools/skpbench/_hardware_pixel2.py
@@ -0,0 +1,119 @@
+# Copyright 2018 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from _hardware import Expectation
+from _hardware_android import HardwareAndroid
+
+CPU_CLOCK_RATE = 2035200
+MEM_CLOCK_RATE = 13763
+GPU_CLOCK_RATE = 670000000
+GPU_POWER_LEVEL = 1  # lower is faster, minimum is 0
+
+class HardwarePixel2(HardwareAndroid):
+  def __init__(self, adb):
+    HardwareAndroid.__init__(self, adb)
+
+  def __enter__(self):
+    HardwareAndroid.__enter__(self)
+    if not self._adb.is_root():
+      return self
+
+    self._adb.shell('\n'.join([
+      '''
+      stop thermal-engine
+      stop perfd''',
+
+      # turn off the slow cores and one fast core
+      '''
+      for N in 0 1 2 3 7; do
+        echo 0 > /sys/devices/system/cpu/cpu$N/online
+      done''',
+
+      # lock 3 fast cores: two for Skia and one for the OS
+      '''
+      for N in 4 5 6; do
+        echo 1 > /sys/devices/system/cpu/cpu$N/online
+        echo userspace > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
+        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
+      done''' % tuple(CPU_CLOCK_RATE for _ in range(3)),
+
+      # Set GPU bus and idle timer
+      '''
+      echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split''',
+      # csmartdalton, 4-26-2018: this line hangs my device
+      # echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on
+      '''
+      echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer''',
+
+      # Set mem frequency to max
+      '''
+      echo %i > /sys/class/devfreq/soc\:qcom,gpubw/min_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,gpubw/max_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,cpubw/min_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,cpubw/max_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,mincpubw/min_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,mincpubw/max_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,memlat-cpu0/min_freq
+      echo %i > /sys/class/devfreq/soc\:qcom,memlat-cpu0/max_freq''' %
+      tuple(MEM_CLOCK_RATE for _ in range(8)),
+
+      # Set GPU to performance mode
+      '''
+      echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor
+      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
+      echo %i > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq''' %
+      tuple(GPU_CLOCK_RATE for _ in range(2)),
+
+      # Set GPU power level
+      '''
+      echo %i > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
+      echo %i > /sys/class/kgsl/kgsl-3d0/min_pwrlevel''' %
+      tuple(GPU_POWER_LEVEL for _ in range(2))]))
+
+    assert('msm_therm' == self._adb.check(\
+                          'cat /sys/class/thermal/thermal_zone10/type').strip())
+    assert('pm8998_tz' == self._adb.check(\
+                          'cat /sys/class/thermal/thermal_zone7/type').strip())
+
+    return self
+
+  def sanity_check(self):
+    HardwareAndroid.sanity_check(self)
+
+    if not self._adb.is_root():
+      return
+
+    result = self._adb.check(' '.join(
+      ['cat',
+       '/sys/class/power_supply/battery/capacity',
+       '/sys/devices/system/cpu/online'] + \
+      ['/sys/devices/system/cpu/cpu%i/cpufreq/scaling_cur_freq' % i
+       for i in range(4, 7)] + \
+      # Unfortunately we can't monitor the gpu clock:
+      #
+      #   /sys/class/kgsl/kgsl-3d0/devfreq/cur_freq
+      #
+      # It doesn't respect the min_freq/max_freq values when not under load.
+      ['/sys/kernel/debug/clk/bimc_clk/measure',
+       '/sys/class/kgsl/kgsl-3d0/temp',
+       '/sys/class/kgsl/kgsl-3d0/throttling',
+       '/sys/class/thermal/thermal_zone10/temp',
+       '/sys/class/thermal/thermal_zone7/temp']))
+
+    expectations = \
+      [Expectation(int, min_value=30, name='battery', sleeptime=30*60),
+       Expectation(str, exact_value='4-6', name='online cpus')] + \
+      [Expectation(int, exact_value=CPU_CLOCK_RATE, name='cpu_%i clock rate' %i)
+       for i in range(4, 7)] + \
+      [Expectation(long, min_value=902390000, max_value=902409999,
+                   name='measured ddr clock', sleeptime=10),
+       Expectation(int, max_value=750, name='gpu temperature'),
+       Expectation(int, exact_value=1, name='gpu throttling'),
+       Expectation(int, max_value=75, name='msm_therm temperature'),
+       Expectation(int, max_value=75000, name='pm8998_tz temperature')]
+
+    Expectation.check_all(expectations, result.splitlines())
diff --git a/src/third_party/skia/tools/skpbench/_hardware_pixel_c.py b/src/third_party/skia/tools/skpbench/_hardware_pixel_c.py
index a1cd17a..5d0b9f1 100644
--- a/src/third_party/skia/tools/skpbench/_hardware_pixel_c.py
+++ b/src/third_party/skia/tools/skpbench/_hardware_pixel_c.py
@@ -6,44 +6,37 @@
 from _hardware import HardwareException, Expectation
 from _hardware_android import HardwareAndroid
 
-CPU_CLOCK_RATE = 1836000
-GPU_EMC_PROFILE = '0c: core 921 MHz emc 1600 MHz a A d D *'
-GPU_EMC_PROFILE_ID = '0c'
+CPU_CLOCK_RATE = 1326000
+# If you run adb cat /sys/devices/57000000.gpu/pstate it shows all
+# possible configurations, with a * next to the current one.
+GPU_EMC_PROFILE = '04: core 307 MHz emc 1065 MHz a A d D *'
+GPU_EMC_PROFILE_ID = '04'
 
 class HardwarePixelC(HardwareAndroid):
   def __init__(self, adb):
     HardwareAndroid.__init__(self, adb)
 
   def __enter__(self):
-    self._lock_clocks()
-    return HardwareAndroid.__enter__(self)
-
-  def __exit__(self, exception_type, exception_value, exception_traceback):
-    HardwareAndroid.__exit__(self, exception_type,
-                             exception_value, exception_traceback)
-    self._unlock_clocks()
-
-  def filter_line(self, line):
-    JUNK = ['NvRmPrivGetChipPlatform: Could not read platform information',
-            'Expected on kernels without fuse support, using silicon']
-    return False if line in JUNK else HardwareAndroid.filter_line(self, line)
-
-  def _lock_clocks(self):
+    HardwareAndroid.__enter__(self)
     if not self._adb.is_root():
-      return
+      return self
 
     self._adb.shell('\n'.join([
-      # turn on and lock the first 3 cores.
+      # pylint: disable=line-too-long
+      # Based on https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/tests/scripts/prep_ryu.sh
+      # All CPUs have the same scaling settings, so we only need to set it once
       '''
-      for N in 0 1 2; do
-        echo 1 > /sys/devices/system/cpu/cpu$N/online
-        echo userspace > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
-        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
-        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
-        echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
-      done''' % tuple(CPU_CLOCK_RATE for _ in range(3)),
+      stop thermal-engine
+      stop perfd
 
-      # turn off the fourth core.
+      echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+      echo %i > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
+      echo %i > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
+      echo %i > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
+      ''' % tuple(CPU_CLOCK_RATE for _ in range(3)),
+      # turn off the fourth core. This will hopefully produce less heat, allowing
+      # for more consistent results.  3 cores should be enough to run Ganesh,
+      # the graphics driver, and the OS.
       '''
       echo 0 > /sys/devices/system/cpu/cpu3/online''',
 
@@ -52,28 +45,12 @@
       chown root:root /sys/devices/57000000.gpu/pstate
       echo %s > /sys/devices/57000000.gpu/pstate''' % GPU_EMC_PROFILE_ID]))
 
-  def _unlock_clocks(self):
-    if not self._adb.is_root():
-      return
+    return self
 
-    self._adb.shell('\n'.join([
-      # unlock gpu/emc clocks.
-      '''
-      echo auto > /sys/devices/57000000.gpu/pstate
-      chown system:system /sys/devices/57000000.gpu/pstate''',
-
-      # turn the fourth core back on.
-      '''
-      echo 1 > /sys/devices/system/cpu/cpu3/online''',
-
-      # unlock the first 3 cores.
-      '''
-      for N in 2 1 0; do
-        echo 1912500 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_max_freq
-        echo 51000 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_min_freq
-        echo 0 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
-        echo interactive >/sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
-      done''']))
+  def filter_line(self, line):
+    JUNK = ['NvRmPrivGetChipPlatform: Could not read platform information',
+            'Expected on kernels without fuse support, using silicon']
+    return False if line in JUNK else HardwareAndroid.filter_line(self, line)
 
   def sanity_check(self):
     HardwareAndroid.sanity_check(self)
@@ -109,8 +86,3 @@
       [Expectation(str, exact_value=GPU_EMC_PROFILE, name='gpu/emc profile')]
 
     Expectation.check_all(expectations, result.splitlines())
-
-  def sleep(self, sleeptime):
-    self._unlock_clocks()
-    HardwareAndroid.sleep(self, sleeptime)
-    self._lock_clocks()
diff --git a/src/third_party/skia/tools/skpbench/_os_path.py b/src/third_party/skia/tools/skpbench/_os_path.py
index 42b1c42..2c10265 100644
--- a/src/third_party/skia/tools/skpbench/_os_path.py
+++ b/src/third_party/skia/tools/skpbench/_os_path.py
@@ -17,6 +17,7 @@
   for skp in skps:
     if (path.isdir(skp)):
       pathnames.extend(glob.iglob(path.join(skp, '*.skp')))
+      pathnames.extend(glob.iglob(path.join(skp, '*.mskp')))
     else:
       pathnames.append(skp)
   return pathnames
diff --git a/src/third_party/skia/tools/skpbench/skpbench.cpp b/src/third_party/skia/tools/skpbench/skpbench.cpp
index c0ead46..b1d0cc0 100644
--- a/src/third_party/skia/tools/skpbench/skpbench.cpp
+++ b/src/third_party/skia/tools/skpbench/skpbench.cpp
@@ -5,24 +5,37 @@
  * found in the LICENSE file.
  */
 
-#include "GpuTimer.h"
-#include "GrContextFactory.h"
-#include "SkGr.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkPictureRecorder.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkSurfaceProps.h"
+#include "include/effects/SkPerlinNoiseShader.h"
+#include "include/private/SkDeferredDisplayList.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkTaskGroup.h"
+#include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/SkGr.h"
+#include "src/utils/SkMultiPictureDocument.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/DDLPromiseImageHelper.h"
+#include "tools/DDLTileHelper.h"
+#include "tools/SkSharingProc.h"
+#include "tools/ToolUtils.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/flags/CommonFlags.h"
+#include "tools/flags/CommonFlagsConfig.h"
+#include "tools/gpu/GpuTimer.h"
+#include "tools/gpu/GrContextFactory.h"
 
-#include "SkCanvas.h"
-#include "SkCommonFlagsPathRenderer.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkPerlinNoiseShader.h"
-#include "SkPicture.h"
-#include "SkPictureRecorder.h"
-#include "SkStream.h"
-#include "SkSurface.h"
-#include "SkSurfaceProps.h"
-#include "picture_utils.h"
-#include "sk_tool_utils.h"
-#include "flags/SkCommandLineFlags.h"
-#include "flags/SkCommonFlagsConfig.h"
+#ifdef SK_XML
+#include "experimental/svg/model/SkSVGDOM.h"
+#include "src/xml/SkDOM.h"
+#endif
+
 #include <stdlib.h>
 #include <algorithm>
 #include <array>
@@ -31,25 +44,35 @@
 #include <vector>
 
 /**
- * This is a minimalist program whose sole purpose is to open an skp file, benchmark it on a single
- * config, and exit. It is intended to be used through skpbench.py rather than invoked directly.
- * Limiting the entire process to a single config/skp pair helps to keep the results repeatable.
+ * This is a minimalist program whose sole purpose is to open a .skp or .svg file, benchmark it on a
+ * single config, and exit. It is intended to be used through skpbench.py rather than invoked
+ * directly. Limiting the entire process to a single config/skp pair helps to keep the results
+ * repeatable.
  *
  * No tiling, looping, or other fanciness is used; it just draws the skp whole into a size-matched
  * render target and syncs the GPU after each draw.
  *
+ * Well, maybe a little fanciness, MSKP's can be loaded and played. The animation is played as many
+ * times as necessary to reach the target sample duration and FPS is reported.
+ *
  * Currently, only GPU configs are supported.
  */
 
-DEFINE_int32(duration, 5000, "number of milliseconds to run the benchmark");
-DEFINE_int32(sampleMs, 50, "minimum duration of a sample");
-DEFINE_bool(gpuClock, false, "time on the gpu clock (gpu work only)");
-DEFINE_bool(fps, false, "use fps instead of ms");
-DEFINE_string(skp, "", "path to a single .skp file, or 'warmup' for a builtin warmup run");
-DEFINE_string(png, "", "if set, save a .png proof to disk at this file location");
-DEFINE_int32(verbosity, 4, "level of verbosity (0=none to 5=debug)");
-DEFINE_bool(suppressHeader, false, "don't print a header row before the results");
-DEFINE_pathrenderer_flag;
+static DEFINE_bool(ddl, false, "record the skp into DDLs before rendering");
+static DEFINE_int(ddlNumAdditionalThreads, 0,
+                    "number of DDL recording threads in addition to main one");
+static DEFINE_int(ddlTilingWidthHeight, 0, "number of tiles along one edge when in DDL mode");
+static DEFINE_bool(ddlRecordTime, false, "report just the cpu time spent recording DDLs");
+
+static DEFINE_int(duration, 5000, "number of milliseconds to run the benchmark");
+static DEFINE_int(sampleMs, 50, "minimum duration of a sample");
+static DEFINE_bool(gpuClock, false, "time on the gpu clock (gpu work only)");
+static DEFINE_bool(fps, false, "use fps instead of ms");
+static DEFINE_string(src, "",
+                     "path to a single .skp or .svg file, or 'warmup' for a builtin warmup run");
+static DEFINE_string(png, "", "if set, save a .png proof to disk at this file location");
+static DEFINE_int(verbosity, 4, "level of verbosity (0=none to 5=debug)");
+static DEFINE_bool(suppressHeader, false, "don't print a header row before the results");
 
 static const char* header =
 "   accum    median       max       min   stddev  samples  sample_ms  clock  metric  config    bench";
@@ -57,6 +80,8 @@
 static const char* resultFormat =
 "%8.4g  %8.4g  %8.4g  %8.4g  %6.3g%%  %7li  %9i  %-5s  %-6s  %-9s %s";
 
+static constexpr int kNumFlushesToPrimeCache = 3;
+
 struct Sample {
     using duration = std::chrono::nanoseconds;
 
@@ -93,23 +118,169 @@
     kSoftware     = 70
 };
 
-static void draw_skp_and_flush(SkCanvas*, const SkPicture*);
+static void draw_skp_and_flush(SkSurface*, const SkPicture*);
 static sk_sp<SkPicture> create_warmup_skp();
+static sk_sp<SkPicture> create_skp_from_svg(SkStream*, const char* filename);
 static bool mkdir_p(const SkString& name);
-static SkString join(const SkCommandLineFlags::StringArray&);
+static SkString         join(const CommandLineFlags::StringArray&);
 static void exitf(ExitErr, const char* format, ...);
 
-static void run_benchmark(const sk_gpu_test::FenceSync* fenceSync, SkCanvas* canvas,
-                          const SkPicture* skp, std::vector<Sample>* samples) {
+// An interface used by both static SKPs and animated SKPs
+class SkpProducer {
+ public:
+  virtual ~SkpProducer() {}
+  // Draw an SkPicture to the provided surface, flush the surface, and sync the GPU.
+  // You may use the static draw_skp_and_flush declared above.
+  // returned int tells how many draw/flush/sync were done.
+  virtual int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) = 0;
+};
+
+class StaticSkp : public SkpProducer {
+ public:
+  StaticSkp(sk_sp<SkPicture> skp) : fSkp(skp) {}
+
+    int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) override {
+        draw_skp_and_flush(surface, fSkp.get());
+        gpuSync.syncToPreviousFrame();
+        return 1;
+    }
+ private:
+  sk_sp<SkPicture> fSkp;
+};
+
+// A class for playing/benchmarking a multi frame SKP file.
+// the recorded frames are looped over repeatedly.
+// This type of benchmark may have a much higher std dev in frame times.
+class MultiFrameSkp : public SkpProducer {
+public:
+    MultiFrameSkp(const std::vector<SkDocumentPage>& frames) : fFrames(frames){}
+
+    static std::unique_ptr<MultiFrameSkp> MakeFromFile(const SkString& path) {
+        // Load the multi frame skp at the given filename.
+        std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(path.c_str());
+        if (!stream) { return nullptr; }
+
+        // Attempt to deserialize with an image sharing serial proc.
+        auto deserialContext = std::make_unique<SkSharingDeserialContext>();
+        SkDeserialProcs procs;
+        procs.fImageProc = SkSharingDeserialContext::deserializeImage;
+        procs.fImageCtx = deserialContext.get();
+
+        // The outer format of multi-frame skps is the multi-picture document, which is a
+        // skp file containing subpictures separated by annotations.
+        int page_count = SkMultiPictureDocumentReadPageCount(stream.get());
+        if (!page_count) {
+            return nullptr;
+        }
+        std::vector<SkDocumentPage> frames(page_count); // can't call reserve, why?
+        if (!SkMultiPictureDocumentRead(stream.get(), frames.data(), page_count, &procs)) {
+            return nullptr;
+        }
+
+        return std::make_unique<MultiFrameSkp>(frames);
+    }
+
+    // Draw the whole animation once.
+    int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) override {
+        for (int i=0; i<this->count(); i++){
+            draw_skp_and_flush(surface, this->frame(i).get());
+            gpuSync.syncToPreviousFrame();
+        }
+        return this->count();
+    }
+    // Return the requested frame.
+    sk_sp<SkPicture> frame(int n) const { return fFrames[n].fPicture; }
+    // Return the number of frames in the recording.
+    int count() const { return fFrames.size(); }
+private:
+    std::vector<SkDocumentPage> fFrames;
+};
+
+static void ddl_sample(GrContext* context, DDLTileHelper* tiles, GpuSync* gpuSync, Sample* sample,
+                       std::chrono::high_resolution_clock::time_point* startStopTime) {
+    using clock = std::chrono::high_resolution_clock;
+
+    clock::time_point start = *startStopTime;
+
+    tiles->createDDLsInParallel();
+
+    if (!FLAGS_ddlRecordTime) {
+        tiles->drawAllTilesAndFlush(context, true);
+        if (gpuSync) {
+            gpuSync->syncToPreviousFrame();
+        }
+    }
+
+    *startStopTime = clock::now();
+
+    tiles->resetAllTiles();
+
+    if (sample) {
+        SkASSERT(gpuSync);
+        sample->fDuration += *startStopTime - start;
+        sample->fFrames++;
+    }
+}
+
+static void run_ddl_benchmark(const sk_gpu_test::FenceSync* fenceSync,
+                              GrContext* context, SkCanvas* finalCanvas,
+                              SkPicture* inputPicture, std::vector<Sample>* samples) {
     using clock = std::chrono::high_resolution_clock;
     const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
     const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
 
-    draw_skp_and_flush(canvas, skp);
-    GpuSync gpuSync(fenceSync);
+    SkIRect viewport = finalCanvas->imageInfo().bounds();
 
-    draw_skp_and_flush(canvas, skp);
-    gpuSync.syncToPreviousFrame();
+    DDLPromiseImageHelper promiseImageHelper;
+    sk_sp<SkData> compressedPictureData = promiseImageHelper.deflateSKP(inputPicture);
+    if (!compressedPictureData) {
+        exitf(ExitErr::kUnavailable, "DDL: conversion of skp failed");
+    }
+
+    promiseImageHelper.uploadAllToGPU(context);
+
+    DDLTileHelper tiles(finalCanvas, viewport, FLAGS_ddlTilingWidthHeight);
+
+    tiles.createSKPPerTile(compressedPictureData.get(), promiseImageHelper);
+
+    SkTaskGroup::Enabler enabled(FLAGS_ddlNumAdditionalThreads);
+
+    clock::time_point startStopTime = clock::now();
+
+    ddl_sample(context, &tiles, nullptr, nullptr, &startStopTime);
+    GpuSync gpuSync(fenceSync);
+    ddl_sample(context, &tiles, &gpuSync, nullptr, &startStopTime);
+
+    clock::duration cumulativeDuration = std::chrono::milliseconds(0);
+
+    do {
+        samples->emplace_back();
+        Sample& sample = samples->back();
+
+        do {
+            ddl_sample(context, &tiles, &gpuSync, &sample, &startStopTime);
+        } while (sample.fDuration < sampleDuration);
+
+        cumulativeDuration += sample.fDuration;
+    } while (cumulativeDuration < benchDuration || 0 == samples->size() % 2);
+
+    if (!FLAGS_png.isEmpty()) {
+        // The user wants to see the final result
+        tiles.composeAllTiles(finalCanvas);
+    }
+}
+
+static void run_benchmark(const sk_gpu_test::FenceSync* fenceSync, SkSurface* surface,
+                          SkpProducer* skpp, std::vector<Sample>* samples) {
+    using clock = std::chrono::high_resolution_clock;
+    const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
+    const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
+
+    GpuSync gpuSync(fenceSync);
+    int i = 0;
+    do {
+        i += skpp->drawAndFlushAndSync(surface, gpuSync);
+    } while(i < kNumFlushesToPrimeCache);
 
     clock::time_point now = clock::now();
     const clock::time_point endTime = now + benchDuration;
@@ -120,18 +291,15 @@
         Sample& sample = samples->back();
 
         do {
-            draw_skp_and_flush(canvas, skp);
-            gpuSync.syncToPreviousFrame();
-
-            now = clock::now();
-            sample.fDuration = now - sampleStart;
-            ++sample.fFrames;
+          sample.fFrames += skpp->drawAndFlushAndSync(surface, gpuSync);
+          now = clock::now();
+          sample.fDuration = now - sampleStart;
         } while (sample.fDuration < sampleDuration);
     } while (now < endTime || 0 == samples->size() % 2);
 }
 
 static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer* gpuTimer,
-                                   const sk_gpu_test::FenceSync* fenceSync, SkCanvas* canvas,
+                                   const sk_gpu_test::FenceSync* fenceSync, SkSurface* surface,
                                    const SkPicture* skp, std::vector<Sample>* samples) {
     using sk_gpu_test::PlatformTimerQuery;
     using clock = std::chrono::steady_clock;
@@ -143,13 +311,16 @@
                         "results may be unreliable\n");
     }
 
-    draw_skp_and_flush(canvas, skp);
+    draw_skp_and_flush(surface, skp);
     GpuSync gpuSync(fenceSync);
 
-    gpuTimer->queueStart();
-    draw_skp_and_flush(canvas, skp);
-    PlatformTimerQuery previousTime = gpuTimer->queueStop();
-    gpuSync.syncToPreviousFrame();
+    PlatformTimerQuery previousTime = 0;
+    for (int i = 1; i < kNumFlushesToPrimeCache; ++i) {
+        gpuTimer->queueStart();
+        draw_skp_and_flush(surface, skp);
+        previousTime = gpuTimer->queueStop();
+        gpuSync.syncToPreviousFrame();
+    }
 
     clock::time_point now = clock::now();
     const clock::time_point endTime = now + benchDuration;
@@ -161,7 +332,7 @@
 
         do {
             gpuTimer->queueStart();
-            draw_skp_and_flush(canvas, skp);
+            draw_skp_and_flush(surface, skp);
             PlatformTimerQuery time = gpuTimer->queueStop();
             gpuSync.syncToPreviousFrame();
 
@@ -223,9 +394,10 @@
 }
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("Use skpbench.py instead. "
-                                 "You usually don't want to use this program directly.");
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::SetUsage(
+            "Use skpbench.py instead. "
+            "You usually don't want to use this program directly.");
+    CommandLineFlags::Parse(argc, argv);
 
     if (!FLAGS_suppressHeader) {
         printf("%s\n", header);
@@ -244,39 +416,57 @@
     }
 
     // Parse the skp.
-    if (FLAGS_skp.count() != 1) {
-        exitf(ExitErr::kUsage, "invalid skp '%s': must specify a single skp file, or 'warmup'",
-                               join(FLAGS_skp).c_str());
+    if (FLAGS_src.count() != 1) {
+        exitf(ExitErr::kUsage,
+              "invalid input '%s': must specify a single .skp or .svg file, or 'warmup'",
+              join(FLAGS_src).c_str());
     }
+
+    SkGraphics::Init();
+
     sk_sp<SkPicture> skp;
-    SkString skpname;
-    if (0 == strcmp(FLAGS_skp[0], "warmup")) {
+    std::unique_ptr<MultiFrameSkp> mskp; // populated if the file is multi frame.
+    SkString srcname;
+    if (0 == strcmp(FLAGS_src[0], "warmup")) {
         skp = create_warmup_skp();
-        skpname = "warmup";
+        srcname = "warmup";
     } else {
-        const char* skpfile = FLAGS_skp[0];
-        std::unique_ptr<SkStream> skpstream(SkStream::MakeFromFile(skpfile));
-        if (!skpstream) {
-            exitf(ExitErr::kIO, "failed to open skp file %s", skpfile);
+        SkString srcfile(FLAGS_src[0]);
+        std::unique_ptr<SkStream> srcstream(SkStream::MakeFromFile(srcfile.c_str()));
+        if (!srcstream) {
+            exitf(ExitErr::kIO, "failed to open file %s", srcfile.c_str());
         }
-        skp = SkPicture::MakeFromStream(skpstream.get());
+        if (srcfile.endsWith(".svg")) {
+            skp = create_skp_from_svg(srcstream.get(), srcfile.c_str());
+        } else if (srcfile.endsWith(".mskp")) {
+            mskp = MultiFrameSkp::MakeFromFile(srcfile);
+            // populate skp with it's first frame, for width height determination.
+            skp = mskp->frame(0);
+        } else {
+            skp = SkPicture::MakeFromStream(srcstream.get());
+        }
         if (!skp) {
-            exitf(ExitErr::kData, "failed to parse skp file %s", skpfile);
+            exitf(ExitErr::kData, "failed to parse file %s", srcfile.c_str());
         }
-        skpname = SkOSPath::Basename(skpfile);
+        srcname = SkOSPath::Basename(srcfile.c_str());
     }
     int width = SkTMin(SkScalarCeilToInt(skp->cullRect().width()), 2048),
         height = SkTMin(SkScalarCeilToInt(skp->cullRect().height()), 2048);
     if (FLAGS_verbosity >= 3 &&
         (width != skp->cullRect().width() || height != skp->cullRect().height())) {
         fprintf(stderr, "%s is too large (%ix%i), cropping to %ix%i.\n",
-                        skpname.c_str(), SkScalarCeilToInt(skp->cullRect().width()),
+                        srcname.c_str(), SkScalarCeilToInt(skp->cullRect().width()),
                         SkScalarCeilToInt(skp->cullRect().height()), width, height);
     }
 
+    if (config->getSurfType() != SkCommandLineConfigGpu::SurfType::kDefault) {
+        exitf(ExitErr::kUnavailable, "This tool only supports the default surface type. (%s)",
+              config->getTag().c_str());
+    }
+
     // Create a context.
     GrContextOptions ctxOptions;
-    ctxOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    SetCtxOptionsFromCommonFlags(&ctxOptions);
     sk_gpu_test::GrContextFactory factory(ctxOptions);
     sk_gpu_test::ContextInfo ctxInfo =
         factory.getContextInfo(config->getContextType(), config->getContextOverrides());
@@ -285,14 +475,17 @@
         exitf(ExitErr::kUnavailable, "failed to create context for config %s",
                                      config->getTag().c_str());
     }
-    if (ctx->caps()->maxRenderTargetSize() < SkTMax(width, height)) {
+    if (ctx->maxRenderTargetSize() < SkTMax(width, height)) {
         exitf(ExitErr::kUnavailable, "render target size %ix%i not supported by platform (max: %i)",
-                                     width, height, ctx->caps()->maxRenderTargetSize());
+              width, height, ctx->maxRenderTargetSize());
     }
-    GrPixelConfig grPixConfig = SkImageInfo2GrPixelConfig(config->getColorType(),
-                                                          config->getColorSpace(),
-                                                          *ctx->caps());
-    int supportedSampleCount = ctx->caps()->getSampleCount(config->getSamples(), grPixConfig);
+    GrBackendFormat format = ctx->defaultBackendFormat(config->getColorType(), GrRenderable::kYes);
+    if (!format.isValid()) {
+        exitf(ExitErr::kUnavailable, "failed to get GrBackendFormat from SkColorType: %d",
+                                     config->getColorType());
+    }
+    int supportedSampleCount = ctx->priv().caps()->getRenderTargetSampleCount(
+            config->getSamples(), format);
     if (supportedSampleCount != config->getSamples()) {
         exitf(ExitErr::kUnavailable, "sample count %i not supported by platform",
                                      config->getSamples());
@@ -329,15 +522,25 @@
     SkCanvas* canvas = surface->getCanvas();
     canvas->translate(-skp->cullRect().x(), -skp->cullRect().y());
     if (!FLAGS_gpuClock) {
-        run_benchmark(testCtx->fenceSync(), canvas, skp.get(), &samples);
+        if (FLAGS_ddl) {
+            run_ddl_benchmark(testCtx->fenceSync(), ctx, canvas, skp.get(), &samples);
+        } else if (!mskp) {
+            auto s = std::make_unique<StaticSkp>(skp);
+            run_benchmark(testCtx->fenceSync(), surface.get(), s.get(), &samples);
+        } else {
+            run_benchmark(testCtx->fenceSync(), surface.get(), mskp.get(), &samples);
+        }
     } else {
+        if (FLAGS_ddl) {
+            exitf(ExitErr::kUnavailable, "DDL: GPU-only timing not supported");
+        }
         if (!testCtx->gpuTimingSupport()) {
             exitf(ExitErr::kUnavailable, "GPU does not support timing");
         }
-        run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), canvas, skp.get(),
-                               &samples);
+        run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), surface.get(),
+                               skp.get(), &samples);
     }
-    print_result(samples, config->getTag().c_str(), skpname.c_str());
+    print_result(samples, config->getTag().c_str(), srcname.c_str());
 
     // Save a proof (if one was requested).
     if (!FLAGS_png.isEmpty()) {
@@ -346,12 +549,10 @@
         if (!surface->getCanvas()->readPixels(bmp, 0, 0)) {
             exitf(ExitErr::kUnavailable, "failed to read canvas pixels for png");
         }
-        const SkString &dirname = SkOSPath::Dirname(FLAGS_png[0]),
-                       &basename = SkOSPath::Basename(FLAGS_png[0]);
-        if (!mkdir_p(dirname)) {
-            exitf(ExitErr::kIO, "failed to create directory \"%s\" for png", dirname.c_str());
+        if (!mkdir_p(SkOSPath::Dirname(FLAGS_png[0]))) {
+            exitf(ExitErr::kIO, "failed to create directory for png \"%s\"", FLAGS_png[0]);
         }
-        if (!sk_tools::write_bitmap_to_disk(bmp, dirname, nullptr, basename)) {
+        if (!ToolUtils::EncodeImageToFile(FLAGS_png[0], bmp, SkEncodedImageFormat::kPNG, 100)) {
             exitf(ExitErr::kIO, "failed to save png to \"%s\"", FLAGS_png[0]);
         }
     }
@@ -359,9 +560,10 @@
     exit(0);
 }
 
-static void draw_skp_and_flush(SkCanvas* canvas, const SkPicture* skp) {
+static void draw_skp_and_flush(SkSurface* surface, const SkPicture* skp) {
+    auto canvas = surface->getCanvas();
     canvas->drawPicture(skp);
-    canvas->flush();
+    surface->flush();
 }
 
 static sk_sp<SkPicture> create_warmup_skp() {
@@ -377,7 +579,7 @@
 
     // Use a big path to (theoretically) warmup the CPU.
     SkPath bigPath;
-    sk_tool_utils::make_big_path(bigPath);
+    ToolUtils::make_big_path(bigPath);
     recording->drawPath(bigPath, stroke);
 
     // Use a perlin shader to warmup the GPU.
@@ -388,14 +590,38 @@
     return recorder.finishRecordingAsPicture();
 }
 
+static sk_sp<SkPicture> create_skp_from_svg(SkStream* stream, const char* filename) {
+#ifdef SK_XML
+    SkDOM xml;
+    if (!xml.build(*stream)) {
+        exitf(ExitErr::kData, "failed to parse xml in file %s", filename);
+    }
+    sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
+    if (!svg) {
+        exitf(ExitErr::kData, "failed to build svg dom from file %s", filename);
+    }
+
+    static constexpr SkRect bounds{0, 0, 1200, 1200};
+    SkPictureRecorder recorder;
+    SkCanvas* recording = recorder.beginRecording(bounds);
+
+    svg->setContainerSize(SkSize::Make(recording->getBaseLayerSize()));
+    svg->render(recording);
+
+    return recorder.finishRecordingAsPicture();
+#endif
+    exitf(ExitErr::kData, "SK_XML is disabled; cannot open svg file %s", filename);
+    return nullptr;
+}
+
 bool mkdir_p(const SkString& dirname) {
-    if (dirname.isEmpty()) {
+    if (dirname.isEmpty() || dirname == SkString("/")) {
         return true;
     }
     return mkdir_p(SkOSPath::Dirname(dirname.c_str())) && sk_mkdir(dirname.c_str());
 }
 
-static SkString join(const SkCommandLineFlags::StringArray& stringArray) {
+static SkString join(const CommandLineFlags::StringArray& stringArray) {
     SkString joined;
     for (int i = 0; i < stringArray.count(); ++i) {
         joined.appendf(i ? " %s" : "%s", stringArray[i]);
diff --git a/src/third_party/skia/tools/skpbench/skpbench.py b/src/third_party/skia/tools/skpbench/skpbench.py
index ef44577..7e40df4 100755
--- a/src/third_party/skia/tools/skpbench/skpbench.py
+++ b/src/third_party/skia/tools/skpbench/skpbench.py
@@ -33,6 +33,8 @@
   help="path to the skpbench binary")
 __argparse.add_argument('--adb',
   action='store_true', help="execute skpbench over adb")
+__argparse.add_argument('--adb_binary', default='adb',
+  help="The name of the adb binary to use.")
 __argparse.add_argument('-s', '--device-serial',
   help="if using adb, ID of the specific device to target "
        "(only required if more than 1 device is attached)")
@@ -54,18 +56,39 @@
   help="perform timing on the gpu clock instead of cpu (gpu work only)")
 __argparse.add_argument('--fps',
   action='store_true', help="use fps instead of ms")
+__argparse.add_argument('--pr',
+  help="comma- or space-separated list of GPU path renderers, including: "
+       "[[~]all [~]default [~]dashline [~]nvpr [~]msaa [~]aaconvex "
+       "[~]aalinearizing [~]small [~]tess]")
+__argparse.add_argument('--cc',
+  action='store_true', help="allow coverage counting shortcuts to render paths")
+__argparse.add_argument('--nocache',
+  action='store_true', help="disable caching of path mask textures")
 __argparse.add_argument('-c', '--config',
   default='gl', help="comma- or space-separated list of GPU configs")
 __argparse.add_argument('-a', '--resultsfile',
   help="optional file to append results into")
-__argparse.add_argument('skps',
+__argparse.add_argument('--ddl',
+  action='store_true', help="record the skp into DDLs before rendering")
+__argparse.add_argument('--ddlNumAdditionalThreads',
+  type=int, default=0,
+  help="number of DDL recording threads in addition to main one")
+__argparse.add_argument('--ddlTilingWidthHeight',
+  type=int, default=0, help="number of tiles along one edge when in DDL mode")
+__argparse.add_argument('--ddlRecordTime',
+  action='store_true', help="report just the cpu time spent recording DDLs")
+__argparse.add_argument('--gpuThreads',
+  type=int, default=-1,
+  help="Create this many extra threads to assist with GPU work, including"
+       " software path rendering. Defaults to two.")
+__argparse.add_argument('srcs',
   nargs='+',
-  help=".skp files or directories to expand for .skp files")
+  help=".skp files or directories to expand for .skp files, and/or .svg files")
 
 FLAGS = __argparse.parse_args()
 if FLAGS.adb:
   import _adb_path as _path
-  _path.init(FLAGS.device_serial)
+  _path.init(FLAGS.device_serial, FLAGS.adb_binary)
 else:
   import _os_path as _path
 
@@ -108,11 +131,31 @@
     ARGV.extend(['--gpuClock', 'true'])
   if FLAGS.fps:
     ARGV.extend(['--fps', 'true'])
+  if FLAGS.pr:
+    ARGV.extend(['--pr'] + re.split(r'[ ,]', FLAGS.pr))
+  if FLAGS.cc:
+    ARGV.extend(['--cc', 'true'])
+  if FLAGS.nocache:
+    ARGV.extend(['--cachePathMasks', 'false'])
+  if FLAGS.gpuThreads != -1:
+    ARGV.extend(['--gpuThreads', str(FLAGS.gpuThreads)])
+
+  # DDL parameters
+  if FLAGS.ddl:
+    ARGV.extend(['--ddl', 'true'])
+  if FLAGS.ddlNumAdditionalThreads:
+    ARGV.extend(['--ddlNumAdditionalThreads',
+                 str(FLAGS.ddlNumAdditionalThreads)])
+  if FLAGS.ddlTilingWidthHeight:
+    ARGV.extend(['--ddlTilingWidthHeight', str(FLAGS.ddlTilingWidthHeight)])
+  if FLAGS.ddlRecordTime:
+    ARGV.extend(['--ddlRecordTime', 'true'])
+
   if FLAGS.adb:
     if FLAGS.device_serial is None:
-      ARGV[:0] = ['adb', 'shell']
+      ARGV[:0] = [FLAGS.adb_binary, 'shell']
     else:
-      ARGV[:0] = ['adb', '-s', FLAGS.device_serial, 'shell']
+      ARGV[:0] = [FLAGS.adb_binary, '-s', FLAGS.device_serial, 'shell']
 
   @classmethod
   def get_header(cls, outfile=sys.stdout):
@@ -128,7 +171,7 @@
     print('running %i second warmup...' % warmup_time, file=sys.stderr)
     commandline = cls.ARGV + ['--duration', str(warmup_time * 1000),
                               '--config', config,
-                              '--skp', 'warmup']
+                              '--src', 'warmup']
     dump_commandline_if_verbose(commandline)
     output = subprocess.check_output(commandline, stderr=subprocess.STDOUT)
 
@@ -139,8 +182,8 @@
         return
     raise Exception('Invalid warmup output:\n%s' % output)
 
-  def __init__(self, skp, config, max_stddev, best_result=None):
-    self.skp = skp
+  def __init__(self, src, config, max_stddev, best_result=None):
+    self.src = src
     self.config = config
     self.max_stddev = max_stddev
     self.best_result = best_result
@@ -163,11 +206,11 @@
     self._schedule_hardware_poll()
 
     commandline = self.ARGV + ['--config', self.config,
-                               '--skp', self.skp,
+                               '--src', self.src,
                                '--suppressHeader', 'true']
     if FLAGS.write_path:
       pngfile = _path.join(FLAGS.write_path, self.config,
-                           _path.basename(self.skp) + '.png')
+                           _path.basename(self.src) + '.png')
       commandline.extend(['--png', pngfile])
     dump_commandline_if_verbose(commandline)
     self._proc = subprocess.Popen(commandline, stdout=subprocess.PIPE,
@@ -230,59 +273,75 @@
     print(line, file=resultsfile)
     resultsfile.flush()
 
-def run_benchmarks(configs, skps, hardware, resultsfile=None):
-  emit_result(SKPBench.get_header(), resultsfile)
-  benches = collections.deque([(skp, config, FLAGS.max_stddev)
-                               for skp in skps
+def run_benchmarks(configs, srcs, hardware, resultsfile=None):
+  hasheader = False
+  benches = collections.deque([(src, config, FLAGS.max_stddev)
+                               for src in srcs
                                for config in configs])
   while benches:
-    benchargs = benches.popleft()
-    with SKPBench(*benchargs) as skpbench:
-      try:
-        skpbench.execute(hardware)
-        if skpbench.best_result:
-          emit_result(skpbench.best_result.format(FLAGS.suffix), resultsfile)
-        else:
-          print("WARNING: no result for %s with config %s" %
-                (skpbench.skp, skpbench.config), file=sys.stderr)
-
-      except StddevException:
-        retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
-        if FLAGS.verbosity >= 1:
-          print("stddev is too high for %s/%s (%s%%, max=%.2f%%), "
-                "re-queuing with max=%.2f%%." %
-                (skpbench.best_result.config, skpbench.best_result.bench,
-                 skpbench.best_result.stddev, skpbench.max_stddev,
-                 retry_max_stddev),
-                file=sys.stderr)
-        benches.append((skpbench.skp, skpbench.config, retry_max_stddev,
-                        skpbench.best_result))
-
-      except HardwareException as exception:
-        skpbench.terminate()
-        if FLAGS.verbosity >= 4:
-          hardware.print_debug_diagnostics()
-        if FLAGS.verbosity >= 1:
-          print("%s; taking a %i second nap..." %
-                (exception.message, exception.sleeptime), file=sys.stderr)
-        benches.appendleft(benchargs) # retry the same bench next time.
-        hardware.sleep(exception.sleeptime)
-        if FLAGS.verbosity >= 4:
-          hardware.print_debug_diagnostics()
+    try:
+      with hardware:
         SKPBench.run_warmup(hardware.warmup_time, configs[0])
+        if not hasheader:
+          emit_result(SKPBench.get_header(), resultsfile)
+          hasheader = True
+        while benches:
+          benchargs = benches.popleft()
+          with SKPBench(*benchargs) as skpbench:
+            try:
+              skpbench.execute(hardware)
+              if skpbench.best_result:
+                emit_result(skpbench.best_result.format(FLAGS.suffix),
+                            resultsfile)
+              else:
+                print("WARNING: no result for %s with config %s" %
+                      (skpbench.src, skpbench.config), file=sys.stderr)
+
+            except StddevException:
+              retry_max_stddev = skpbench.max_stddev * math.sqrt(2)
+              if FLAGS.verbosity >= 1:
+                print("stddev is too high for %s/%s (%s%%, max=%.2f%%), "
+                      "re-queuing with max=%.2f%%." %
+                      (skpbench.best_result.config, skpbench.best_result.bench,
+                       skpbench.best_result.stddev, skpbench.max_stddev,
+                       retry_max_stddev),
+                      file=sys.stderr)
+              benches.append((skpbench.src, skpbench.config, retry_max_stddev,
+                              skpbench.best_result))
+
+            except HardwareException as exception:
+              skpbench.terminate()
+              if FLAGS.verbosity >= 4:
+                hardware.print_debug_diagnostics()
+              if FLAGS.verbosity >= 1:
+                print("%s; rebooting and taking a %i second nap..." %
+                      (exception.message, exception.sleeptime), file=sys.stderr)
+              benches.appendleft(benchargs) # retry the same bench next time.
+              raise # wake hw up from benchmarking mode before the nap.
+
+    except HardwareException as exception:
+      time.sleep(exception.sleeptime)
 
 def main():
   # Delimiter is ',' or ' ', skip if nested inside parens (e.g. gpu(a=b,c=d)).
   DELIMITER = r'[, ](?!(?:[^(]*\([^)]*\))*[^()]*\))'
   configs = re.split(DELIMITER, FLAGS.config)
-  skps = _path.find_skps(FLAGS.skps)
+  srcs = _path.find_skps(FLAGS.srcs)
+  assert srcs
 
   if FLAGS.adb:
-    adb = Adb(FLAGS.device_serial, echo=(FLAGS.verbosity >= 5))
+    adb = Adb(FLAGS.device_serial, FLAGS.adb_binary,
+              echo=(FLAGS.verbosity >= 5))
     model = adb.check('getprop ro.product.model').strip()
     if model == 'Pixel C':
       from _hardware_pixel_c import HardwarePixelC
       hardware = HardwarePixelC(adb)
+    elif model == 'Pixel':
+      from _hardware_pixel import HardwarePixel
+      hardware = HardwarePixel(adb)
+    elif model == 'Pixel 2':
+      from _hardware_pixel2 import HardwarePixel2
+      hardware = HardwarePixel2(adb)
     elif model == 'Nexus 6P':
       from _hardware_nexus_6p import HardwareNexus6P
       hardware = HardwareNexus6P(adb)
@@ -294,13 +353,11 @@
   else:
     hardware = Hardware()
 
-  with hardware:
-    SKPBench.run_warmup(hardware.warmup_time, configs[0])
-    if FLAGS.resultsfile:
-      with open(FLAGS.resultsfile, mode='a+') as resultsfile:
-        run_benchmarks(configs, skps, hardware, resultsfile=resultsfile)
-    else:
-      run_benchmarks(configs, skps, hardware)
+  if FLAGS.resultsfile:
+    with open(FLAGS.resultsfile, mode='a+') as resultsfile:
+      run_benchmarks(configs, srcs, hardware, resultsfile=resultsfile)
+  else:
+    run_benchmarks(configs, srcs, hardware)
 
 
 if __name__ == '__main__':
diff --git a/src/third_party/skia/tools/skpinfo.cpp b/src/third_party/skia/tools/skpinfo.cpp
index 104322f..2fa2831 100644
--- a/src/third_party/skia/tools/skpinfo.cpp
+++ b/src/third_party/skia/tools/skpinfo.cpp
@@ -5,18 +5,20 @@
  * found in the LICENSE file.
  */
 
-#include "SkCommandLineFlags.h"
-#include "SkPicture.h"
-#include "SkPictureData.h"
-#include "SkStream.h"
-#include "SkFontDescriptor.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "include/private/SkTo.h"
+#include "src/core/SkFontDescriptor.h"
+#include "src/core/SkPictureCommon.h"
+#include "src/core/SkPictureData.h"
+#include "tools/flags/CommandLineFlags.h"
 
-DEFINE_string2(input, i, "", "skp on which to report");
-DEFINE_bool2(version, v, true, "version");
-DEFINE_bool2(cullRect, c, true, "cullRect");
-DEFINE_bool2(flags, f, true, "flags");
-DEFINE_bool2(tags, t, true, "tags");
-DEFINE_bool2(quiet, q, false, "quiet");
+static DEFINE_string2(input, i, "", "skp on which to report");
+static DEFINE_bool2(version, v, true, "version");
+static DEFINE_bool2(cullRect, c, true, "cullRect");
+static DEFINE_bool2(flags, f, true, "flags");
+static DEFINE_bool2(tags, t, true, "tags");
+static DEFINE_bool2(quiet, q, false, "quiet");
 
 // This tool can print simple information about an SKP but its main use
 // is just to check if an SKP has been truncated during the recording
@@ -30,8 +32,8 @@
 static const int kIOError = 5;
 
 int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("Prints information about an skp file");
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::SetUsage("Prints information about an skp file");
+    CommandLineFlags::Parse(argc, argv);
 
     if (FLAGS_input.count() != 1) {
         if (!FLAGS_quiet) {
@@ -51,7 +53,7 @@
     size_t totStreamSize = stream.getLength();
 
     SkPictInfo info;
-    if (!SkPicture::InternalOnly_StreamIsSKP(&stream, &info)) {
+    if (!SkPicture_StreamIsSKP(&stream, &info)) {
         return kNotAnSKP;
     }
 
@@ -63,30 +65,10 @@
                  info.fCullRect.fLeft, info.fCullRect.fTop,
                  info.fCullRect.fRight, info.fCullRect.fBottom);
     }
-    if (FLAGS_flags && !FLAGS_quiet) {
-        SkDebugf("Flags: ");
-        bool needsSeparator = false;
-        if (info.fFlags & SkPictInfo::kCrossProcess_Flag) {
-            SkDebugf("kCrossProcess");
-            needsSeparator = true;
-        }
-        if (info.fFlags & SkPictInfo::kScalarIsFloat_Flag) {
-            if (needsSeparator) {
-                SkDebugf("|");
-            }
-            SkDebugf("kScalarIsFloat");
-            needsSeparator = true;
-        }
-        if (info.fFlags & SkPictInfo::kPtrIs64Bit_Flag) {
-            if (needsSeparator) {
-                SkDebugf("|");
-            }
-            SkDebugf("kPtrIs64Bit");
-        }
-        SkDebugf("\n");
-    }
 
-    if (!stream.readBool()) {
+    bool hasData;
+    if (!stream.readBool(&hasData)) { return kTruncatedFile; }
+    if (!hasData) {
         // If we read true there's a picture playback object flattened
         // in the file; if false, there isn't a playback, so we're done
         // reading the file.
@@ -94,12 +76,14 @@
     }
 
     for (;;) {
-        uint32_t tag = stream.readU32();
+        uint32_t tag;
+        if (!stream.readU32(&tag)) { return kTruncatedFile; }
         if (SK_PICT_EOF_TAG == tag) {
             break;
         }
 
-        uint32_t chunkSize = stream.readU32();
+        uint32_t chunkSize;
+        if (!stream.readU32(&chunkSize)) { return kTruncatedFile; }
         size_t curPos = stream.getPosition();
 
         // "move" doesn't error out when seeking beyond the end of file
diff --git a/src/third_party/skia/tools/skpmaker.cpp b/src/third_party/skia/tools/skpmaker.cpp
deleted file mode 100644
index a3ccd61..0000000
--- a/src/third_party/skia/tools/skpmaker.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Simple tool to generate SKP files for testing.
- */
-
-#include "SkCanvas.h"
-#include "SkColor.h"
-#include "SkCommandLineFlags.h"
-#include "SkPaint.h"
-#include "SkPicture.h"
-#include "SkPictureRecorder.h"
-#include "SkScalar.h"
-#include "SkStream.h"
-
-#include <stdlib.h>
-
-// Flags used by this file, alphabetically:
-DEFINE_int32(blue, 128, "Value of blue color channel in image, 0-255.");
-DEFINE_int32(border, 4, "Width of the black border around the image.");
-DEFINE_int32(green, 128, "Value of green color channel in image, 0-255.");
-DEFINE_int32(height, 200, "Height of canvas to create.");
-DEFINE_int32(red, 128, "Value of red color channel in image, 0-255.");
-DEFINE_int32(width, 300, "Width of canvas to create.");
-DEFINE_string(writePath, "", "Filepath to write the SKP into.");
-
-// Create a 'width' by 'height' skp with a 'border'-wide black border around
-// a 'color' rectangle.
-static void make_skp(SkScalar width, SkScalar height, SkScalar border, SkColor color,
-                     const char *writePath) {
-    SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(width, height, nullptr, 0);
-    SkPaint paint;
-    paint.setStyle(SkPaint::kFill_Style);
-    paint.setColor(SK_ColorBLACK);
-    SkRect r = SkRect::MakeWH(width, height);
-    canvas->drawRect(r, paint);
-    paint.setColor(color);
-    r.inset(border, border);
-    canvas->drawRect(r, paint);
-    SkFILEWStream stream(writePath);
-    recorder.finishRecordingAsPicture()->serialize(&stream);
-}
-
-int main(int argc, char** argv) {
-    SkCommandLineFlags::SetUsage("Creates a simple .skp file for testing.");
-    SkCommandLineFlags::Parse(argc, argv);
-
-    // Validate flags.
-    if ((FLAGS_blue < 0) || (FLAGS_blue > 255)) {
-        SkDebugf("--blue must be within range [0,255]\n");
-        exit(-1);
-    }
-    if ((FLAGS_green < 0) || (FLAGS_green > 255)) {
-        SkDebugf("--green must be within range [0,255]\n");
-        exit(-1);
-    }
-    if (FLAGS_height <= 0) {
-        SkDebugf("--height must be >0\n");
-        exit(-1);
-    }
-    if ((FLAGS_red < 0) || (FLAGS_red > 255)) {
-        SkDebugf("--red must be within range [0,255]\n");
-        exit(-1);
-    }
-    if (FLAGS_width <= 0) {
-        SkDebugf("--width must be >0\n");
-        exit(-1);
-    }
-    if (FLAGS_writePath.isEmpty()) {
-        SkDebugf("--writePath must be nonempty\n");
-        exit(-1);
-    }
-
-    SkColor color = SkColorSetRGB(FLAGS_red, FLAGS_green, FLAGS_blue);
-    make_skp(SkIntToScalar(FLAGS_width),
-             SkIntToScalar(FLAGS_height),
-             SkIntToScalar(FLAGS_border),
-             color, FLAGS_writePath[0]);
-    return 0;
-}
diff --git a/src/third_party/skia/tools/skqp/README.md b/src/third_party/skia/tools/skqp/README.md
new file mode 100644
index 0000000..e652795
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/README.md
@@ -0,0 +1,92 @@
+SkQP
+====
+
+SkQP (Skia Quality Program) is a component of the Android CTS (Compatablity
+Test Suite) that tests an Android device's GPU and OpenGLES & Vulkan drivers
+using Skia's existing unit & rendering tests.
+
+See https://skia.org/dev/testing/skqp for pre-build APKs.
+
+How to build and run the SkQP tests
+-----------------------------------
+
+1.  Get the dependencies:
+
+    -   You will need Java JDK 8, `git`, and `python`.
+
+    -   Install Chromium's [depot\_tools](http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html).  Add it to your `PATH`.
+
+            git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'
+            export PATH="${PWD}/depot_tools:${PATH}"
+
+    -   Install the [Android NDK](https://developer.android.com/ndk/downloads/).
+
+            ( cd ~; unzip ~/Downloads/android-ndk-*.zip )
+            ANDROID_NDK=$(ls -d ~/android-ndk-*)   # Or wherever you installed the Android NDK.
+
+    -   Install the [Android SDK](https://developer.android.com/studio/#command-tools).
+        Set the `ANDROID_HOME` environment variable.
+
+            mkdir ~/android-sdk
+            ( cd ~/android-sdk; unzip ~/Downloads/sdk-tools-*.zip )
+            yes | ~/android-sdk/tools/bin/sdkmanager --licenses
+            export ANDROID_HOME=~/android-sdk  # Or wherever you installed the Android SDK.
+
+        Put `adb` in your `PATH`.
+
+            export PATH="${PATH}:${ANDROID_HOME}/platform-tools"
+
+2.  Get the right version of Skia:
+
+        git clone https://skia.googlesource.com/skia.git
+        cd skia
+        git checkout origin/skqp/dev  # or whatever release tag you need
+
+3.  Build the APK:
+
+        tools/git-sync-deps
+        tools/skqp/make_universal_apk
+
+4.  Build, install, and run.
+
+        adb install -r out/skqp/skqp-universal-debug.apk
+        adb logcat -c
+        adb shell am instrument -w org.skia.skqp
+
+5.  Monitor the output with:
+
+        adb logcat TestRunner org.skia.skqp skia "*:S"
+
+    Note the test's output path on the device.  It will look something like this:
+
+        01-23 15:22:12.688 27158 27173 I org.skia.skqp:
+        output written to "/storage/emulated/0/Android/data/org.skia.skqp/files/output"
+
+6.  Retrieve and view the report with:
+
+        OUTPUT_LOCATION="/storage/emulated/0/Android/data/org.skia.skqp/files/output"
+        adb pull $OUTPUT_LOCATION /tmp/
+        bin/sysopen /tmp/output/skqp_report/report.html
+
+Running a single test
+---------------------
+
+To run a single test, for example `gles_aarectmodes`:
+
+    adb shell am instrument -e class 'org.skia.skqp.SkQPRunner#gles_aarectmodes' -w org.skia.skqp
+
+Unit tests can be run with the `unitTest_` prefix:
+
+    adb shell am instrument -e class 'org.skia.skqp.SkQPRunner#unitTest_GrSurface -w org.skia.skqp
+
+Run as a non-APK executable
+---------------------------
+
+1.  Follow steps 1-3 as above.
+
+2.  Build the SkQP program, load files on the device, and run skqp:
+
+        gn gen out/skqp-arm
+        ninja -C out/skqp-arm skqp
+        python tools/skqp/run_skqp_exe out/skqp-arm
+
diff --git a/src/third_party/skia/tools/skqp/README_ALGORITHM.md b/src/third_party/skia/tools/skqp/README_ALGORITHM.md
new file mode 100644
index 0000000..c1eb23b
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/README_ALGORITHM.md
@@ -0,0 +1,96 @@
+SkQP Render Test Algorithm
+==========================
+
+The following is a description of the render test validation algorithm that
+will be used by the version of SkQP that will be released for Android Q-release.
+
+There is a global macro constant: `SK_SKQP_GLOBAL_ERROR_TOLERANCE`, which
+reflects the `gn` variable `skia_skqp_global_error_tolerance`.  This is usually
+set to 8.
+
+First, look for a file named `skqp/rendertests.txt` in the
+`platform_tools/android/apps/skqp/src/main/assets` directory.  The format of
+this file is:  each line contains one render test name, followed by a comma,
+followed by an integer.  The integer is the `passing_threshold` for that test.
+
+For each test, we have a `max_image` and a `min_image`.  These are PNG-encoded
+images stored in SkQP's APK's asset directory (in the paths `gmkb/${TEST}/min.png`
+and `gmkb/${TEST}/max.png`).
+
+The test input is a rendered image.  This will be produced by running one of
+the render tests against the either the `vk` (Vulkan) or `gles` (OpenGL ES)
+Skia backend.
+
+Here is psuedocode for the error calculation:
+
+    function calculate_pixel_error(pixel_value, pixel_max, pixel_min):
+        pixel_error = 0
+
+        for color_channel in { red, green, blue, alpha }:
+            value = get_color(pixel_value, color_channel)
+            v_max = get_color(pixel_max,   color_channel)
+            v_min = get_color(pixel_min,   color_channel)
+
+            if value > v_max:
+                channel_error = value - v_max
+            elif value < v_min:
+                channel_error = v_min - value
+            else:
+                channel_error = 0
+            pixel_error = max(pixel_error, channel_error)
+
+        return max(0, pixel_error - SK_SKQP_GLOBAL_ERROR_TOLERANCE);
+
+    function get_error(rendered_image, max_image, min_image):
+        assert(dimensions(rendered_image) == dimensions(max_image))
+        assert(dimensions(rendered_image) == dimensions(min_image))
+
+        max_error = 0
+        bad_pixels = 0
+        total_error = 0
+
+        error_image = allocate_bitmap(dimensions(rendered_image))
+
+        for xy in list_all_pixel_coordinates(rendered_image):
+            pixel_error = calculate_pixel_error(rendered_image(xy),
+                                                max_image(xy),
+                                                min_image(xy))
+            if pixel_error > 0:
+                for neighboring_xy in find_neighbors(xy):
+                    if not inside(neighboring_xy, dimensions(rendered_image)):
+                        continue
+                    pixel_error = min(pixel_error,
+                                      calculate_pixel_error(rendered_image(xy),
+                                                            max_image(neighboring_xy),
+                                                            min_image(neighboring_xy)))
+
+            if pixel_error > 0:
+                max_error = max(max_error, pixel_error)
+                bad_pixels += 1
+                total_error += pixel_error
+
+                error_image(xy) = linear_interpolation(black, red, pixel_error)
+            else:
+                error_image(xy) = white
+
+        return ((total_error, max_error, bad_pixels), error_image)
+
+For each render test, there is a threshold value for `total_error`, :
+`passing_threshold`.
+
+If `passing_threshold >= 0 && total_error > passing_threshold`, then the test
+is a failure and is included in the report.  if `passing_threshold == -1`, then
+the test always passes, but we do execute the test to verify that the driver
+does not crash.
+
+We generate a report with the following information for each test:
+
+    backend_name,render_test_name,max_error,bad_pixels,total_error
+
+in CSV format in the file `out.csv`.  A HTML report of just the failing tests
+is written to the file `report.html`.  This version includes four images for
+each test:  `rendered_image`, `max_image`, `min_image`, and `error_image`, as
+well as the three metrics: `max_error`, `bad_pixels`, and `total_error`.
+
+
+
diff --git a/src/third_party/skia/tools/skqp/README_GENERATING_MODELS.md b/src/third_party/skia/tools/skqp/README_GENERATING_MODELS.md
new file mode 100644
index 0000000..b852564
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/README_GENERATING_MODELS.md
@@ -0,0 +1,84 @@
+How SkQP Generates Render Test Models
+=====================================
+
+We will, at regular intervals, generate new models from the [master branch of
+Skia][1].  Here is how that process works:
+
+0.  Choose a commit to make the branch from
+
+        COMMIT=origin/master
+
+    Or use the script to find the best one:
+
+        cd SKIA_SOURCE_DIRECTORY
+        git fetch origin
+        COMMIT=$(python tools/skqp/find_commit_with_best_gold_results.py \
+                 origin/master ^origin/skqp/dev)
+
+1.  Get the positively triaged results from Gold and generate models:
+
+        cd SKIA_SOURCE_DIRECTORY
+        git fetch origin
+        git checkout "$COMMIT"
+        python tools/skqp/cut_release.py HEAD~10 HEAD
+
+    This will create the following files:
+
+        platform_tools/android/apps/skqp/src/main/assets/files.checksum
+        platform_tools/android/apps/skqp/src/main/assets/skqp/rendertests.txt
+        platform_tools/android/apps/skqp/src/main/assets/skqp/unittests.txt
+
+    These three files can be commited to Skia to create a new commit.  Make
+    `origin/skqp/dev` a parent of this commit (without merging it in), and
+    push this new commit to `origin/skqp/dev`, using this script:
+
+        sh tools/skqp/branch_skqp_dev.sh
+
+    Review and submit the change:
+
+        git push origin HEAD:refs/for/skqp/dev
+        bin/sysopen https://review.skia.org/$(bin/gerrit-number HEAD)
+
+    (Optional) Make a SkQP APK.
+
+        tools/skqp/docker_build_universal_apk.sh
+
+    (Optional) Test the SkQP APK:
+
+        tools/skqp/test_apk.sh (LOCATION)/skqp-universal-debug.apk
+
+    (Once changes land) Upload the SkQP APK.
+
+        tools/skqp/upload_apk HEAD (LOCATION)/skqp-universal-debug.apk
+
+
+`tools/skqp/cut_release.py`
+---------------------------
+
+This tool will call `make_skqp_model` to generate the `m{ax,in}.png` files for
+each render test.
+
+Then it calls `jitter_gms` to see which render tests pass the jitter test.
+`jitter_gms` respects the `bad_gms.txt` file by ignoring the render tests
+enumerated in that file.  Tests which pass the jitter test are enumerated in
+the file `good.txt`, those that fail in the `bad.txt` file.
+
+Next, the `skqp/rendertests.txt` file is created.  This file lists the render
+tests that will be executed by SkQP.  These are the union of the tests
+enumerated in the `good.txt` and `bad.txt` files.  If the render test is found
+in the `good.txt` file and the model exists, its per-test threshold is set
+to 0 (a later CL can manually change this, if needed).  Otherwise, the
+threshold is set to -1; this indicated that the rendertest will be executed (to
+verify that the driver will not crash), but the output will not be compared
+against the model.  Unnecessary models will be removed.
+
+Next, all of the files that represent the models are uploaded to cloud storage.
+A single checksum hash is kept in the  `files.checksum` file.  This is enough
+to re-download those files later, but we don't have to fill the git repository
+with a lot of binary data.
+
+Finally, a list of the current gpu unit tests is created and stored in
+`skqp/unittests.txt`.
+
+[1]: https://skia.googlesource.com/skia/+log/master "Skia Master Branch"
+[2]: https://gold.skia.org/search                   "Skia Gold Search"
diff --git a/src/third_party/skia/tools/skqp/bad_gms.txt b/src/third_party/skia/tools/skqp/bad_gms.txt
new file mode 100644
index 0000000..7e7bf51
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/bad_gms.txt
@@ -0,0 +1,11 @@
+arcs_as_paths
+drawbitmaprect
+drawbitmaprect-imagerect
+etc1
+ovals_as_paths
+p3
+perlinnoise
+radial_gradient_precision
+readpixels
+skbug1719
+zero_length_paths_aa
diff --git a/src/third_party/skia/tools/skqp/branch_skqp_dev.sh b/src/third_party/skia/tools/skqp/branch_skqp_dev.sh
new file mode 100755
index 0000000..2662c1e
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/branch_skqp_dev.sh
@@ -0,0 +1,13 @@
+#! /bin/sh
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+set -xe
+set -- platform_tools/android/apps/skqp/src/main/assets/files.checksum       \
+       platform_tools/android/apps/skqp/src/main/assets/skqp/rendertests.txt \
+       platform_tools/android/apps/skqp/src/main/assets/skqp/unittests.txt
+for arg; do [ -f "$arg" ] || exit 1; done
+MSG="$(printf 'Cut SkQP %s\n\nNo-Try: true' "$(date +%Y-%m-%d)")"
+git merge -s ours origin/skqp/dev -m "$MSG"
+git add "$@"
+git commit --amend --reuse-message=HEAD
diff --git a/src/third_party/skia/tools/skqp/clean_app.sh b/src/third_party/skia/tools/skqp/clean_app.sh
new file mode 100755
index 0000000..d6b5284
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/clean_app.sh
@@ -0,0 +1,17 @@
+#! /bin/sh
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -e
+
+# Change to the root and remove previously added build assets from the source
+# tree of the SKQP app.
+cd "$(dirname "$0")/../.."
+cd platform_tools/android/apps
+git clean -fxd skqp/build \
+               skqp/src/main/assets/gmkb \
+               skqp/src/main/assets/resources \
+               skqp/src/main/libs \
+               .gradle build viewer/build
diff --git a/src/third_party/skia/tools/skqp/create_apk.py b/src/third_party/skia/tools/skqp/create_apk.py
new file mode 100755
index 0000000..2f6d94e
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/create_apk.py
@@ -0,0 +1,235 @@
+#! /usr/bin/env python
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+'''
+This script can be run with no arguments, in which case it will produce an
+APK with native libraries for all four architectures: arm, arm64, x86, and
+x64.  You can instead list the architectures you want as arguments to this
+script.  For example:
+
+    python create_apk.py arm x86
+
+The environment variables ANDROID_NDK and ANDROID_HOME must be set to the
+locations of the Android NDK and SDK.
+
+Additionally, `ninja` should be in your path.
+
+It assumes that the source tree is in the desired state, e.g. by having
+run 'python tools/git-sync-deps' in the root of the skia checkout.
+
+We also assume that the 'resources' directory has been copied to
+'platform_tools/android/apps/skqp/src/main/assets', and the
+'tools/skqp/download_model' script has been run.
+
+Also:
+  * If the environment variable SKQP_BUILD_DIR is set, many of the
+    intermediate build objects will be placed here.
+  * If the environment variable SKQP_OUTPUT_DIR is set, the final APK
+    will be placed in this directory.
+  * If the environment variable SKQP_DEBUG is set, Skia will be compiled
+    in debug mode.
+'''
+
+import os
+import re
+import subprocess
+import sys
+import shutil
+import time
+
+import skqp_gn_args
+
+def print_cmd(cmd, o):
+    m = re.compile('[^A-Za-z0-9_./-]')
+    o.write('+ ')
+    for c in cmd:
+        if m.search(c) is not None:
+            o.write(repr(c) + ' ')
+        else:
+            o.write(c + ' ')
+    o.write('\n')
+    o.flush()
+
+def check_call(cmd, **kwargs):
+    print_cmd(cmd, sys.stdout)
+    return subprocess.check_call(cmd, **kwargs)
+
+def find_name(searchpath, filename):
+    for dirpath, _, filenames in os.walk(searchpath):
+        if filename in filenames:
+            yield os.path.join(dirpath, filename)
+
+def check_ninja():
+    with open(os.devnull, 'w') as devnull:
+        return subprocess.call(['ninja', '--version'],
+                               stdout=devnull, stderr=devnull) == 0
+
+def remove(p):
+    if not os.path.islink(p) and os.path.isdir(p):
+        shutil.rmtree(p)
+    elif os.path.lexists(p):
+        os.remove(p)
+    assert not os.path.exists(p)
+
+def makedirs(dst):
+    if not os.path.exists(dst):
+        os.makedirs(dst)
+
+class RemoveFiles(object):
+    def __init__(self, *args):
+        self.args = args
+    def __enter__(self):
+        pass
+    def __exit__(self, a, b, c):
+        for arg in self.args:
+            remove(arg)
+
+class ChDir(object):
+    def __init__(self, d):
+        self.orig = os.getcwd()
+        os.chdir(d)
+    def __enter__(self):
+        pass
+    def __exit__(self, a, b, c):
+        os.chdir(self.orig)
+
+def make_symlinked_subdir(target, working_dir):
+    newdir = os.path.join(working_dir, os.path.basename(target))
+    makedirs(newdir)
+    os.symlink(os.path.relpath(newdir, os.path.dirname(target)), target)
+
+def accept_android_license(android_home):
+    proc = subprocess.Popen(
+            [android_home + '/tools/bin/sdkmanager', '--licenses'],
+            stdin=subprocess.PIPE)
+    while proc.poll() is None:
+        proc.stdin.write('y\n')
+        time.sleep(1)
+
+# pylint: disable=bad-whitespace
+skia_to_android_arch_name_map = {'arm'  : 'armeabi-v7a',
+                                 'arm64': 'arm64-v8a'  ,
+                                 'x86'  : 'x86'        ,
+                                 'x64'  : 'x86_64'     }
+
+def create_apk_impl(opts):
+    build_dir, final_output_dir = opts.build_dir, opts.final_output_dir
+
+    assert os.path.exists('bin/gn')  # Did you `tools/git-syc-deps`?
+
+    for d in [build_dir, final_output_dir]:
+        makedirs(d)
+
+    apps_dir = 'platform_tools/android/apps'
+    app = 'skqp'
+    lib = 'lib%s_app.so' % app
+
+    # These are the locations in the tree where the gradle needs or will create
+    # not-checked-in files.  Treat them specially to keep the tree clean.
+    remove(build_dir + '/libs')
+    build_paths = [apps_dir + '/.gradle',
+                   apps_dir + '/' + app + '/build',
+                   apps_dir + '/' + app + '/src/main/libs']
+    for path in build_paths:
+        remove(path)
+        try:
+            make_symlinked_subdir(path, build_dir)
+        except OSError:
+            sys.stderr.write('failed to create symlink "%s"\n' % path)
+
+    lib_dir = '%s/%s/src/main/libs' % (apps_dir, app)
+    apk_build_dir = '%s/%s/build/outputs/apk' % (apps_dir, app)
+    for d in [lib_dir, apk_build_dir]:
+        shutil.rmtree(d, True)  # force rebuild
+
+    with RemoveFiles(*build_paths):
+        for arch in opts.architectures:
+            build = os.path.join(build_dir, arch)
+            gn_args = opts.gn_args(arch)
+            args = ' '.join('%s=%s' % (k, v) for k, v in gn_args.items())
+            check_call(['bin/gn', 'gen', build, '--args=' + args])
+            check_call(['ninja', '-C', build, lib])
+            dst = '%s/%s' % (lib_dir, skia_to_android_arch_name_map[arch])
+            makedirs(dst)
+            shutil.copy(os.path.join(build, lib), dst)
+
+        accept_android_license(opts.android_home)
+        env_copy = os.environ.copy()
+        env_copy['ANDROID_HOME'] = opts.android_home
+        env_copy['ANDROID_NDK_HOME'] = opts.android_ndk
+        # Why does gradlew need to be called from this directory?
+        check_call(['apps/gradlew', '-p' 'apps/' + app,
+                    '-P', 'suppressNativeBuild',
+                    ':%s:assembleUniversalDebug' % app],
+                    env=env_copy, cwd='platform_tools/android')
+
+        apk_name = app + "-universal-debug.apk"
+
+        apk_list = list(find_name(apk_build_dir, apk_name))
+        assert len(apk_list) == 1
+
+        out = os.path.join(final_output_dir, apk_name)
+        shutil.move(apk_list[0], out)
+        sys.stdout.write(out + '\n')
+
+    arches = '_'.join(sorted(opts.architectures))
+    copy = os.path.join(final_output_dir, "%s-%s-debug.apk" % (app, arches))
+    shutil.copyfile(out, copy)
+    sys.stdout.write(copy + '\n')
+
+    sys.stdout.write('* * * COMPLETE * * *\n\n')
+
+
+def create_apk(opts):
+    skia_dir = os.path.abspath(os.path.dirname(__file__) + '/../..')
+    assert os.path.exists(skia_dir)
+    with ChDir(skia_dir):
+        create_apk_impl(opts)
+
+class SkQP_Build_Options(object):
+    def __init__(self):
+        assert '/' in [os.sep, os.altsep]  # 'a/b' over os.path.join('a', 'b')
+        self.error = ''
+        if not check_ninja():
+            self.error += '`ninja` is not in the path.\n'
+        for var in ['ANDROID_NDK', 'ANDROID_HOME']:
+            if not os.path.exists(os.environ.get(var, '')):
+                self.error += 'Environment variable `%s` is not set.\n' % var
+        self.android_ndk = os.path.abspath(os.environ['ANDROID_NDK'])
+        self.android_home = os.path.abspath(os.environ['ANDROID_HOME'])
+        args = sys.argv[1:]
+        for arg in args:
+            if arg not in skia_to_android_arch_name_map:
+                self.error += ('Argument %r is not in %r\n' %
+                               (arg, skia_to_android_arch_name_map.keys()))
+        self.architectures = args if args else skia_to_android_arch_name_map.keys()
+        default_build = os.path.dirname(__file__) + '/../../out/skqp'
+        self.build_dir = os.path.abspath(os.environ.get('SKQP_BUILD_DIR', default_build))
+        self.final_output_dir = os.path.abspath(os.environ.get('SKQP_OUTPUT_DIR', default_build))
+        self.debug = bool(os.environ.get('SKQP_DEBUG', ''))
+
+    def gn_args(self, arch):
+        return skqp_gn_args.GetGNArgs(arch, self.android_ndk, self.debug, 26)
+
+    def write(self, o):
+        for k, v in [('ANDROID_NDK', self.android_ndk),
+                     ('ANDROID_HOME', self.android_home),
+                     ('SKQP_OUTPUT_DIR', self.final_output_dir),
+                     ('SKQP_BUILD_DIR', self.build_dir),
+                     ('SKQP_DEBUG', self.debug),
+                     ('Architectures', self.architectures)]:
+            o.write('%s = %r\n' % (k, v))
+        o.flush()
+
+def main():
+    options = SkQP_Build_Options()
+    if options.error:
+        sys.stderr.write(options.error + __doc__)
+        sys.exit(1)
+    options.write(sys.stdout)
+    create_apk(options)
+
+if __name__ == '__main__':
+    main()
diff --git a/src/third_party/skia/tools/skqp/cut_release.py b/src/third_party/skia/tools/skqp/cut_release.py
new file mode 100755
index 0000000..fba4f6c
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/cut_release.py
@@ -0,0 +1,168 @@
+#! /usr/bin/env python
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+import json
+import md5
+import multiprocessing
+import os
+import shutil
+import sys
+import tempfile
+import urllib
+import urllib2
+
+from subprocess import check_call, check_output
+
+assert '/' in [os.sep, os.altsep] and os.pardir == '..'
+
+ASSETS = 'platform_tools/android/apps/skqp/src/main/assets'
+BUCKET = 'skia-skqp-assets'
+
+def make_skqp_model(arg):
+    name, urls, exe = arg
+    tmp = tempfile.mkdtemp()
+    for url in urls:
+        urllib.urlretrieve(url, tmp + '/' + url[url.rindex('/') + 1:])
+    check_call([exe, tmp, ASSETS + '/gmkb/' + name])
+    shutil.rmtree(tmp)
+    sys.stdout.write(name + ' ')
+    sys.stdout.flush()
+
+def goldgetter(meta, exe):
+    assert os.path.exists(exe)
+    jobs = []
+    for rec in meta:
+        urls = [d['URL'] for d in rec['digests']
+                if d['status'] == 'positive' and
+                (set(d['paramset']['config']) & set(['vk', 'gles']))]
+        if urls:
+            jobs.append((rec['testName'], urls, exe))
+    pool = multiprocessing.Pool(processes=20)
+    pool.map(make_skqp_model, jobs)
+    sys.stdout.write('\n')
+    return set((n for n, _, _ in jobs))
+
+def gold(first_commit, last_commit):
+    c1, c2 = (check_output(['git', 'rev-parse', c]).strip()
+            for c in (first_commit, last_commit))
+    f = urllib2.urlopen('https://public-gold.skia.org/json/export?' + urllib.urlencode([
+        ('fbegin', c1),
+        ('fend', c2),
+        ('query', 'config=gles&config=vk&source_type=gm'),
+        ('pos', 'true'),
+        ('neg', 'false'),
+        ('unt', 'false')
+    ]))
+    j = json.load(f)
+    f.close()
+    return j
+
+def gset(path):
+    s = set()
+    if os.path.isfile(path):
+        with open(path, 'r') as f:
+            for line in f:
+                s.add(line.strip())
+    return s
+
+def make_rendertest_list(models, good, bad):
+    assert good.isdisjoint(bad)
+    do_score = good & models
+    no_score = bad | (good - models)
+    to_delete = models & bad
+    for d in to_delete:
+        path = ASSETS + '/gmkb/' + d
+        if os.path.isdir(path):
+            shutil.rmtree(path)
+    results = dict()
+    for n in do_score:
+        results[n] = 0
+    for n in no_score:
+        results[n] = -1
+    return ''.join('%s,%d\n' % (n, results[n]) for n in sorted(results))
+
+def get_digest(path):
+    m = md5.new()
+    with open(path, 'r') as f:
+        m.update(f.read())
+    return m.hexdigest()
+
+def upload_cmd(path, digest):
+    return ['gsutil', 'cp', path, 'gs://%s/%s' % (BUCKET, digest)]
+
+def upload_model():
+    bucket_url = 'gs://%s/' % BUCKET
+    extant = set((u.replace(bucket_url, '', 1)
+                  for u in check_output(['gsutil', 'ls', bucket_url]).splitlines() if u))
+    cmds = []
+    filelist = []
+    for dirpath, _, filenames in os.walk(ASSETS + '/gmkb'):
+        for filename in filenames:
+            path = os.path.join(dirpath, filename)
+            digest = get_digest(path)
+            if digest not in extant:
+                cmds.append(upload_cmd(path, digest))
+            filelist.append('%s;%s\n' % (digest, os.path.relpath(path, ASSETS)))
+    tmp = tempfile.mkdtemp()
+    filelist_path = tmp + '/x'
+    with open(filelist_path, 'w') as o:
+        for l in filelist:
+            o.write(l)
+    filelist_digest = get_digest(filelist_path)
+    if filelist_digest not in extant:
+        cmds.append(upload_cmd(filelist_path, filelist_digest))
+
+    pool = multiprocessing.Pool(processes=20)
+    pool.map(check_call, cmds)
+    shutil.rmtree(tmp)
+    return filelist_digest
+
+def remove(x):
+    if os.path.isdir(x) and not os.path.islink(x):
+        shutil.rmtree(x)
+    if os.path.exists(x):
+        os.remove(x)
+
+def main(first_commit, last_commit):
+    check_call(upload_cmd('/dev/null', get_digest('/dev/null')))
+
+    os.chdir(os.path.dirname(__file__) + '/../..')
+    remove(ASSETS + '/files.checksum')
+    for d in [ASSETS + '/gmkb', ASSETS + '/skqp', ]:
+        remove(d)
+        os.mkdir(d)
+
+    check_call([sys.executable, 'tools/git-sync-deps'],
+               env=dict(os.environ, GIT_SYNC_DEPS_QUIET='T'))
+    build = 'out/ndebug'
+    check_call(['bin/gn', 'gen', build,
+                '--args=cc="clang" cxx="clang++" is_debug=false'])
+    check_call(['ninja', '-C', build,
+                'jitter_gms', 'list_gpu_unit_tests', 'make_skqp_model'])
+
+    models = goldgetter(gold(first_commit, last_commit), build + '/make_skqp_model')
+
+    check_call([build + '/jitter_gms', 'tools/skqp/bad_gms.txt'])
+
+    with open(ASSETS + '/skqp/rendertests.txt', 'w') as o:
+        o.write(make_rendertest_list(models, gset('good.txt'), gset('bad.txt')))
+
+    remove('good.txt')
+    remove('bad.txt')
+
+    with open(ASSETS + '/skqp/unittests.txt', 'w') as o:
+        o.write(check_output([build + '/list_gpu_unit_tests']))
+
+    with open(ASSETS + '/files.checksum', 'w') as o:
+        o.write(upload_model() + '\n')
+
+    sys.stdout.write(ASSETS + '/files.checksum\n')
+    sys.stdout.write(ASSETS + '/skqp/rendertests.txt\n')
+    sys.stdout.write(ASSETS + '/skqp/unittests.txt\n')
+
+if __name__ == '__main__':
+    if len(sys.argv) != 3:
+        sys.stderr.write('Usage:\n  %s C1 C2\n\n' % sys.argv[0])
+        sys.exit(1)
+    main(sys.argv[1], sys.argv[2])
diff --git a/src/third_party/skia/tools/skqp/docker_build_universal_apk.sh b/src/third_party/skia/tools/skqp/docker_build_universal_apk.sh
new file mode 100755
index 0000000..963a37b
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/docker_build_universal_apk.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+#    You may need to run as root for docker permissions.
+#
+#    You *must* run `tools/git-sync-deps` first.
+
+if [ "$SKQP_OUTPUT_DIR" ]; then
+    mkdir -p "$SKQP_OUTPUT_DIR" || exit 1
+    OUT="$(cd "$SKQP_OUTPUT_DIR"; pwd)"
+else
+    OUT="$(mktemp -d "${TMPDIR:-/tmp}/skqp_apk.XXXXXXXXXX")"
+fi
+SKIA_ROOT="$(cd "$(dirname "$0")/../.."; pwd)"
+
+cd "${SKIA_ROOT}/infra/skqp/docker"
+
+docker build -t android-skqp ./android-skqp/
+
+NAME=$(date +android_em_%Y%m%d_%H%M%S)
+
+docker run --rm -d --name "$NAME" \
+        --env=DEVICE="Samsung Galaxy S6" \
+        --volume="$SKIA_ROOT":/SRC \
+        --volume="$OUT":/OUT \
+        android-skqp
+
+BUILD="$(docker exec "$NAME" mktemp -d)"
+
+docker exec \
+    --env=SKQP_OUTPUT_DIR=/OUT \
+    --env=SKQP_BUILD_DIR="$BUILD" \
+    "$NAME" /SRC/tools/skqp/make_universal_apk.py
+
+if [ -f "$OUT"/skqp-universal-debug.apk ]; then
+    docker exec "$NAME" find /OUT -type f -exec chmod 0666 '{}' '+'
+fi
+
+docker kill "$NAME"
+
+ls -l "$OUT"/*.apk 2> /dev/null
diff --git a/src/third_party/skia/tools/skqp/docker_run_apk.sh b/src/third_party/skia/tools/skqp/docker_run_apk.sh
new file mode 100755
index 0000000..5c54bf4
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/docker_run_apk.sh
@@ -0,0 +1,43 @@
+#! /bin/sh
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+#   You may need to run as root for docker permissions.
+#
+#   The SKQP_ARGS environment variable affects this script.
+
+if ! [ -f "$1" ] ; then
+  echo "Usage:  $0 SKQP_APK_FILE_PATH" >&2
+  exit 1
+fi
+
+APK_DIR="$(cd "$(dirname "$1")"; pwd)"
+APK_FILE="$(basename "$1")"
+DST="$(mktemp -d "${TMPDIR:-/tmp}/skqp_emulated_test.XXXXXXXXXX")"
+SED_CMD='s/^.* org.skia.skqp: output written to "\([^"]*\)".*$/\1/p'
+SKQP="$(cd $(dirname "$0"); pwd)"
+
+set -x
+
+cd "${SKQP}/../../infra/skqp/docker"
+
+docker build -t android-skqp ./android-skqp/ > "$DST"/docker-build || exit 2
+
+docker run --privileged --rm -d \
+  --name android_em \
+  --env=DEVICE="Samsung Galaxy S6" \
+  --env=SKQP_SLEEP="30" \
+  --env=SKQP_ARGS="$SKQP_ARGS" \
+  --volume="$DST":/DST \
+  --volume="$APK_DIR":/APK:ro \
+  --volume="$SKQP":/SKQP:ro \
+  android-skqp > "$DST"/docker-run || exit 3
+
+docker exec android_em sh "/SKQP/run_apk.sh" "/APK/$APK_FILE" "/DST"
+
+docker kill android_em
+
+"${SKQP}/../../bin/sysopen" "$DST"/skqp_report_*/report.html
diff --git a/src/third_party/skia/tools/skqp/download_model b/src/third_party/skia/tools/skqp/download_model
new file mode 100755
index 0000000..68ef50d
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/download_model
@@ -0,0 +1,6 @@
+#! /usr/bin/env python
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import download_model
+download_model.main()
diff --git a/src/third_party/skia/tools/skqp/download_model.py b/src/third_party/skia/tools/skqp/download_model.py
new file mode 100755
index 0000000..fb0020e
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/download_model.py
@@ -0,0 +1,69 @@
+#! /usr/bin/env python
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import hashlib
+import multiprocessing
+import os
+import shutil
+import sys
+import tempfile
+import urllib2
+
+def checksum(path):
+    if not os.path.exists(path):
+        return None
+    m = hashlib.md5()
+    with open(path, 'rb') as f:
+        while True:
+            buf = f.read(4096)
+            if not buf:
+                return m.hexdigest()
+            m.update(buf)
+
+def download(md5, path):
+    if not md5 == checksum(path):
+        dirname = os.path.dirname(path)
+        if dirname and not os.path.exists(dirname):
+            try:
+                os.makedirs(dirname)
+            except OSError:
+                pass  # ignore race condition
+        url = 'https://storage.googleapis.com/skia-skqp-assets/' + md5
+        with open(path, 'wb') as o:
+            shutil.copyfileobj(urllib2.urlopen(url), o)
+
+def tmp(prefix):
+    fd, path = tempfile.mkstemp(prefix=prefix)
+    os.close(fd)
+    return path
+
+def main():
+    target_dir = os.path.join('platform_tools', 'android', 'apps', 'skqp', 'src', 'main', 'assets')
+    os.chdir(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, target_dir))
+    checksum_path = 'files.checksum'
+    if not os.path.isfile(checksum_path):
+        sys.stderr.write('Error: "%s" is missing.\n' % os.path.join(target_dir, checksum_path))
+        sys.exit(1)
+    file_list_file = tmp('files_')
+    with open(checksum_path, 'r') as f:
+        md5 = f.read().strip()
+        assert(len(md5) == 32)
+        download(md5, file_list_file)
+    with open(file_list_file, 'r') as f:
+        records = []
+        for line in f:
+            md5, path = line.strip().split(';', 1)
+            records.append((md5, path))
+    sys.stderr.write('Downloading %d files.\n' % len(records))
+    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count() * 2)
+    for record in records:
+        pool.apply_async(download, record, callback=lambda x: sys.stderr.write('.'))
+    pool.close()
+    pool.join()
+    sys.stderr.write('\n')
+
+if __name__ == '__main__':
+    main()
diff --git a/src/third_party/skia/tools/skqp/find_commit_with_best_gold_results.py b/src/third_party/skia/tools/skqp/find_commit_with_best_gold_results.py
new file mode 100755
index 0000000..49d2a4a
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/find_commit_with_best_gold_results.py
@@ -0,0 +1,122 @@
+#! /usr/bin/env python
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+import re
+import subprocess
+import sys
+import threading
+import urllib
+import urllib2
+
+
+assert '/' in [os.sep, os.altsep]
+
+
+skia_directory = os.path.abspath(os.path.dirname(__file__) + '/../..')
+
+
+def get_jobs():
+    path = skia_directory + '/infra/bots/jobs.json'
+    reg = re.compile('Test-(?P<os>[A-Za-z0-9_]+)-'
+                     '(?P<compiler>[A-Za-z0-9_]+)-'
+                     '(?P<model>[A-Za-z0-9_]+)-GPU-'
+                     '(?P<cpu_or_gpu_value>[A-Za-z0-9_]+)-'
+                     '(?P<arch>[A-Za-z0-9_]+)-'
+                     '(?P<configuration>[A-Za-z0-9_]+)-'
+                     'All(-(?P<extra_config>[A-Za-z0-9_]+)|)')
+    keys = ['os', 'compiler', 'model', 'cpu_or_gpu_value', 'arch',
+            'configuration', 'extra_config']
+    def fmt(s):
+        return s.encode('utf-8') if s is not None else ''
+    with open(path) as f:
+        jobs = json.load(f)
+    for job in jobs:
+        m = reg.match(job)
+        if m is not None:
+            yield [(k, fmt(m.group(k))) for k in keys]
+
+
+def gold_export_url(job, config, first_commit, last_commit):
+    qq = [('source_type', 'gm'), ('config', config)] + job
+    query = [
+        ('fbegin', first_commit),
+        ('fend', last_commit),
+        ('query', urllib.urlencode(qq)),
+        ('pos', 'true'),
+        ('neg', 'false'),
+        ('unt', 'false'),
+        ('head', 'true')
+    ]
+    return 'https://public-gold.skia.org/json/export?' + urllib.urlencode(query)
+
+
+def get_results_for_commit(commit, jobs):
+    sys.stderr.write('%s\n' % commit)
+    sys.stderr.flush()
+    CONFIGS = ['gles', 'vk']
+    passing_tests_for_all_jobs = []
+    def process(url):
+        testResults = json.load(urllib2.urlopen(url))
+        sys.stderr.write('.')
+        sys.stderr.flush()
+        passing_tests = 0
+        for t in testResults:
+            assert t['digests']
+            passing_tests += 1
+        passing_tests_for_all_jobs.append(passing_tests)
+    all_urls = [gold_export_url(job, config, commit, commit)
+                for job in jobs for config in CONFIGS]
+    threads = [threading.Thread(target=process, args=(url,)) for url in all_urls]
+    for t in threads:
+        t.start()
+    for t in threads:
+        t.join()
+    result = sum(passing_tests_for_all_jobs)
+    sys.stderr.write('\n%d\n' % result)
+    sys.stderr.flush()
+    return result
+
+
+def find_best_commit(commits):
+    jobs = [j for j in get_jobs()]
+    results = []
+    for commit_name in commits:
+        commit_hash = subprocess.check_output(['git', 'rev-parse', commit_name]).strip()
+        results.append((commit_hash, get_results_for_commit(commit_hash, jobs)))
+
+    best_result = max(r for h, r in results)
+    for h, r in results:
+        if r == best_result:
+            return h
+    return None
+
+
+def generate_commit_list(args):
+    return subprocess.check_output(['git', 'log', '--format=%H'] + args).splitlines()
+
+
+def main(args):
+    os.chdir(skia_directory)
+    subprocess.check_call(['git', 'fetch', 'origin'])
+    sys.stderr.write('%s\n' % ' '.join(args))
+    commits = generate_commit_list(args)
+    sys.stderr.write('%d\n' % len(commits))
+    best = find_best_commit(commits)
+    sys.stderr.write('DONE:\n')
+    sys.stderr.flush()
+    sys.stdout.write('%s\n' % best)
+
+
+usage = '''Example usage:
+    python %s origin/master ^origin/skqp/dev < /dev/null > LOG 2>&1 & disown
+'''
+
+if __name__ == '__main__':
+    if len(sys.argv) < 2:
+        sys.stderr.write(usage % sys.argv[0])
+        sys.exit(1)
+    main(sys.argv[1:])
diff --git a/src/third_party/skia/tools/skqp/generate_gn_args b/src/third_party/skia/tools/skqp/generate_gn_args
new file mode 100755
index 0000000..ad1db01
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/generate_gn_args
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import os
+import sys
+
+import skqp_gn_args
+
+def parse_args():
+    parser = argparse.ArgumentParser(description='Generate args.gn file.')
+    parser.add_argument('target_build_dir')
+    parser.add_argument('android_ndk_dir' )
+    parser.add_argument('--arch',  metavar='architecture', default='arm',
+        help='defaults to "arm", valid values: "arm" "arm64" "x86" "x64"')
+    parser.add_argument('--api_level', type=int, metavar='api_level',
+        default=26, help='android API level, defaults to 26')
+    parser.add_argument('--debug', default=False, action='store_true',
+        help='compile native code in debug mode, defaults to false')
+    args = parser.parse_args()
+    result = skqp_gn_args.GetGNArgs(args.arch,
+                                    os.path.abspath(args.android_ndk_dir),
+                                    args.debug,
+                                    args.api_level)
+    return args.target_build_dir, result)
+
+def write_gn(o, args):
+    l = max(len(k) for k in args)
+    for k, v in sorted(args.items()):
+        o.write('%-*s = %s\n' % (l, k, v))
+
+def make_args_gn(out_dir, args):
+    if out_dir == '-':
+        write_gn(sys.stdout, args)
+        return
+    if not os.path.exists(out_dir):
+        os.makedirs(out_dir)
+    with open(os.path.join(out_dir, 'args.gn'), 'w') as o:
+        write_gn(o, args)
+
+if __name__ == '__main__':
+    build_dir, args = parse_args()
+    make_args_gn(build_dir, args)
diff --git a/src/third_party/skia/tools/skqp/gn_to_bp.py b/src/third_party/skia/tools/skqp/gn_to_bp.py
new file mode 100755
index 0000000..8fd614a
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/gn_to_bp.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generate Android.bp for Skia from GN configuration.
+
+import argparse
+import json
+import os
+import pprint
+import string
+import subprocess
+import sys
+import tempfile
+
+root_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                        os.pardir, os.pardir)
+skia_gn_dir = os.path.join(root_dir, 'gn')
+sys.path.insert(0, skia_gn_dir)
+
+import gn_to_bp_utils
+
+from skqp_gn_args import SkqpGnArgs
+
+# First we start off with a template for Android.bp,
+# with holes for source lists and include directories.
+bp = string.Template('''// This file is autogenerated by tools/skqp/gn_to_bp.py.
+
+cc_library_shared {
+    name: "libskqp_app",
+    sdk_version: "26",
+    stl: "libc++_static",
+    compile_multilib: "both",
+
+    cflags: [
+        $cflags
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+    ],
+
+    cppflags:[
+        $cflags_cc
+    ],
+
+    local_include_dirs: [
+        $local_includes
+    ],
+
+    srcs: [
+        "third_party/vulkanmemoryallocator/GrVulkanMemoryAllocator.cpp",
+        $srcs
+    ],
+
+    arch: {
+        arm: {
+            srcs: [
+                $arm_srcs
+            ],
+
+            neon: {
+                srcs: [
+                    $arm_neon_srcs
+                ],
+            },
+        },
+
+        arm64: {
+            srcs: [
+                $arm64_srcs
+            ],
+        },
+
+        mips: {
+            srcs: [
+                $none_srcs
+            ],
+        },
+
+        mips64: {
+            srcs: [
+                $none_srcs
+            ],
+        },
+
+        x86: {
+            srcs: [
+                $x86_srcs
+            ],
+        },
+
+        x86_64: {
+            srcs: [
+                $x86_srcs
+            ],
+        },
+    },
+
+    shared_libs: [
+          "libandroid",
+          "libEGL",
+          "libGLESv2",
+          "liblog",
+          "libvulkan",
+          "libz",
+    ],
+    static_libs: [
+          "libexpat",
+          "libjpeg_static_ndk",
+          "libpng_ndk",
+          "libwebp-decode",
+          "libwebp-encode",
+    ]
+}''')
+
+# We'll run GN to get the main source lists and include directories for Skia.
+gn_args = {
+  'target_cpu': '"none"',
+  'target_os':  '"android"',
+
+  # setup skqp
+  'is_debug':   'false',
+  'ndk_api':    '26',
+
+  # specify that the Android.bp will supply the necessary components
+  'skia_use_system_expat':         'true', # removed this when gn is fixed
+  'skia_use_system_libpng':        'true',
+  'skia_use_system_libwebp':       'true',
+  'skia_use_system_libjpeg_turbo': 'true',
+  'skia_use_system_zlib':          'true',
+}
+
+for k, v in SkqpGnArgs.iteritems():
+    gn_args[k] = v
+
+js = gn_to_bp_utils.GenerateJSONFromGN(gn_args)
+
+def strip_slashes(lst):
+  return {str(p.lstrip('/')) for p in lst}
+
+srcs            = strip_slashes(js['targets']['//:libskqp_app']['sources'])
+cflags          = strip_slashes(js['targets']['//:libskqp_app']['cflags'])
+cflags_cc       = strip_slashes(js['targets']['//:libskqp_app']['cflags_cc'])
+local_includes  = strip_slashes(js['targets']['//:libskqp_app']['include_dirs'])
+defines      = {str(d) for d in js['targets']['//:libskqp_app']['defines']}
+
+defines.update(["SK_ENABLE_DUMP_GPU", "SK_BUILD_FOR_SKQP"])
+cflags_cc.update(['-Wno-extra-semi-stmt'])
+
+gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'sources', srcs, None)
+gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'include_dirs',
+                                   local_includes, 'freetype')
+gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'defines',
+                                   defines, None)
+
+# No need to list headers or other extra flags.
+srcs = {s for s in srcs           if not s.endswith('.h')}
+cflags = gn_to_bp_utils.CleanupCFlags(cflags)
+cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc)
+
+# We need to add the include path to the vulkan defines and header file set in
+# then skia_vulkan_header gn arg that is used for framework builds.
+local_includes.add("platform_tools/android/vulkan")
+
+# Get architecture specific source files
+defs = gn_to_bp_utils.GetArchSources(os.path.join(skia_gn_dir, 'opts.gni'))
+
+# Add source file until fix lands in
+# https://skia-review.googlesource.com/c/skia/+/101820
+srcs.add("src/ports/SkFontMgr_empty_factory.cpp")
+
+# Turn a list of strings into the style bpfmt outputs.
+def bpfmt(indent, lst, sort=True):
+  if sort:
+    lst = sorted(lst)
+  return ('\n' + ' '*indent).join('"%s",' % v for v in lst)
+
+# Most defines go into SkUserConfig.h, where they're seen by Skia and its users.
+gn_to_bp_utils.WriteUserConfig('include/config/SkUserConfig.h', defines)
+
+# OK!  We have everything to fill in Android.bp...
+with open('Android.bp', 'w') as f:
+  print >>f, bp.substitute({
+    'local_includes': bpfmt(8, local_includes),
+    'srcs':           bpfmt(8, srcs),
+    'cflags':         bpfmt(8, cflags, False),
+    'cflags_cc':      bpfmt(8, cflags_cc),
+
+    'arm_srcs':       bpfmt(16, defs['armv7']),
+    'arm_neon_srcs':  bpfmt(20, defs['neon']),
+    'arm64_srcs':     bpfmt(16, defs['arm64'] +
+                                defs['crc32']),
+    'none_srcs':      bpfmt(16, defs['none']),
+    'x86_srcs':       bpfmt(16, defs['sse2'] +
+                                defs['ssse3'] +
+                                defs['sse41'] +
+                                defs['sse42'] +
+                                defs['avx'] +
+                                defs['hsw']),
+  })
+
diff --git a/src/third_party/skia/tools/skqp/jitter_gms.cpp b/src/third_party/skia/tools/skqp/jitter_gms.cpp
new file mode 100644
index 0000000..be26eef
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/jitter_gms.cpp
@@ -0,0 +1,153 @@
+// Copyright 2018 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+// Jitter GMs
+//
+// Re-execute rendering tests with slight translational changes and see if
+// there is a significant change.  Print `1` if the named test has no
+// significant change, `0` otherwise
+
+#include "gm/gm.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkExecutor.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPoint.h"
+#include "include/core/SkSize.h"
+#include "include/core/SkTypes.h"
+#include "include/private/SkSemaphore.h"
+#include "tools/Registry.h"
+#include "tools/skqp/src/skqp.h"
+#include "tools/skqp/src/skqp_model.h"
+
+#include <math.h>
+#include <algorithm>
+#include <cstdio>
+#include <fstream>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+// Error tolerance distance in 8888 color space with Manhattan metric on color channel.
+static constexpr uint8_t kSkiaSkqpGlobalErrorTolerance = 8;
+
+// Number of times to jitter the canvas.
+static constexpr int kNumberOfJitters = 7;
+
+// Distance to translate the canvas in each jitter (direction will be different each time).
+static constexpr float kJitterMagnitude = 0.03125f;
+
+// The `kNumberOfJitters` different runs will each go in a different direction.
+// this is the angle (in radians) for the first one.
+static constexpr float kPhase = 0.3f;
+
+static void do_gm(SkBitmap* bm, skiagm::GM* gm, SkPoint jitter) {
+    SkASSERT(bm);
+    SkASSERT(gm);
+    SkASSERT(bm->dimensions() == gm->getISize());
+    SkCanvas canvas(*bm);
+    SkAutoCanvasRestore autoCanvasRestore(&canvas, true);
+    canvas.clear(SK_ColorWHITE);
+    canvas.translate(jitter.x(), jitter.y());
+    gm->draw(&canvas);
+    canvas.flush();
+}
+
+// Return true if passes jitter test.
+static bool test_jitter(skiagm::GM* gm) {
+    SkASSERT(gm);
+    SkISize size = gm->getISize();
+    SkBitmap control, experimental;
+    control.allocN32Pixels(size.width(), size.height());
+    experimental.allocN32Pixels(size.width(), size.height());
+    do_gm(&control, gm, {0, 0});
+    for (int i = 0; i < kNumberOfJitters; ++i) {
+        float angle = i * (6.2831853f / kNumberOfJitters) + kPhase;
+        do_gm(&experimental, gm, SkPoint{kJitterMagnitude * cosf(angle),
+                                         kJitterMagnitude * sinf(angle)});
+        SkQP::RenderOutcome result = skqp::Check(
+                control.pixmap(), control.pixmap(), experimental.pixmap(),
+                kSkiaSkqpGlobalErrorTolerance, nullptr);
+        if (result.fTotalError > 0) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool do_this_test(const char* name,
+                    const std::vector<std::string>& doNotRun,
+                    const std::vector<std::string>& testOnlyThese) {
+    for (const std::string& bad : doNotRun) {
+        if (bad == name) {
+            return false;
+        }
+    }
+    for (const std::string& good : testOnlyThese) {
+        if (good == name) {
+            return true;
+        }
+    }
+    return testOnlyThese.empty();
+}
+
+
+int main(int argc, char** argv) {
+    std::vector<std::string> doNotRun;
+    std::vector<std::string> testOnlyThese;
+    if (argc > 1) {
+        std::ifstream ifs(argv[1]);
+        if (ifs.is_open()) {
+            std::string str;
+            while (std::getline(ifs, str)) {
+                doNotRun.push_back(str);
+            }
+        }
+    }
+    if (argc > 2) {
+        for (int i = 2; i < argc; ++i) {
+            testOnlyThese.emplace_back(argv[i]);
+        }
+    }
+    SkGraphics::Init();
+    std::mutex mutex;
+    std::vector<std::string> goodResults;
+    std::vector<std::string> badResults;
+
+    int total = 0;
+    SkSemaphore semaphore;
+    auto executor = SkExecutor::MakeFIFOThreadPool();
+    for (skiagm::GMFactory factory : skiagm::GMRegistry::Range()) {
+        ++total;
+        executor->add([factory, &mutex, &goodResults, &badResults,
+                       &semaphore, &doNotRun, &testOnlyThese](){
+            std::unique_ptr<skiagm::GM> gm(factory());
+            const char* name = gm->getName();
+            if (do_this_test(name, doNotRun, testOnlyThese)) {
+                bool success = test_jitter(gm.get());
+                std::lock_guard<std::mutex> lock(mutex);
+                if (success) {
+                    goodResults.emplace_back(name);
+                } else {
+                    badResults.emplace_back(name);
+                }
+                fputc('.', stderr);
+                fflush(stderr);
+            }
+            semaphore.signal();
+        });
+    }
+    while (total-- > 0) { semaphore.wait(); }
+    fputc('\n', stderr);
+    fflush(stderr);
+    std::sort(goodResults.begin(), goodResults.end());
+    std::sort(badResults.begin(), badResults.end());
+    std::ofstream good("good.txt");
+    std::ofstream bad("bad.txt");
+    for (const std::string& s : goodResults) { good << s << '\n'; }
+    for (const std::string& s : badResults) { bad << s << '\n'; }
+    fprintf(stderr, "good = %u\nbad = %u\n\n",
+            (unsigned)goodResults.size(), (unsigned)badResults.size());
+}
diff --git a/src/third_party/skia/tools/skqp/make_apk.sh b/src/third_party/skia/tools/skqp/make_apk.sh
new file mode 100755
index 0000000..cd1bb7b
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/make_apk.sh
@@ -0,0 +1,5 @@
+#! /bin/sh
+# Copyright 2019 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+exec python "$(dirname "$0")"/make_universal_apk.py "$@"
diff --git a/src/third_party/skia/tools/skqp/make_apk_list.py b/src/third_party/skia/tools/skqp/make_apk_list.py
new file mode 100755
index 0000000..dacbc24
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/make_apk_list.py
@@ -0,0 +1,132 @@
+#! /usr/bin/env python
+
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from subprocess import call, check_output, CalledProcessError
+import os
+import re
+import sys
+import tempfile
+
+HEADER = '''<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>SkQP Pre-built APKs</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<style>
+body {
+font-family:sans-serif;
+max-width:50em;
+margin:8px auto;
+padding:0 8px;
+}
+table { max-width:100%; border-collapse: collapse; }
+td { padding:12px 8px; vertical-align:top; }
+tr:nth-child(even) {background: #F2F2F2; color:#000;}
+tr:nth-child(odd)  {background: #FFFFFF; color:#000;}
+</style>
+</head>
+<body>
+<h1>SkQP Pre-built APKs</h1>
+'''
+FOOTER = '</body>\n</html>\n'
+
+BUCKET = 'skia-skqp'
+
+NAME_FMT = 'skqp-universal-%s.apk'
+
+def get_existing_files():
+    cmd = ['gsutil', 'ls', 'gs://' + BUCKET]
+    try:
+        output = check_output(cmd)
+    except (OSError, CalledProcessError):
+        sys.stderr.write('command: "%s" failed.\n' % ' '.join(cmd))
+        sys.exit(1)
+    result = set()
+    regex = re.compile('gs://%s/%s' % (BUCKET, NAME_FMT % '([0-9a-f]+)'))
+    for line in output.split('\n'):
+        m = regex.match(line.strip())
+        if m is not None:
+            result.add(m.group(1))
+    return result
+
+def find(v, extant):
+    l = min(16, len(v))
+    while l > 8:
+        if v[:l] in extant:
+            return v[:l]
+        l -= 1
+    return None
+
+def nowrap(s):
+    return (s.replace(' ', u'\u00A0'.encode('utf-8'))
+             .replace('-', u'\u2011'.encode('utf-8')))
+
+def rev_parse(arg):
+    if isinstance(arg, tuple):
+        remote_url, branch = arg
+        for remote in check_output(['git', 'remote']).strip().split('\n'):
+            remote = remote.strip()
+            url = check_output(['git', 'remote', 'get-url', remote]).strip()
+            if url == remote_url:
+                arg = remote + '/' + branch
+                break
+    return check_output(['git', 'rev-parse', arg]).strip()
+
+
+def table(o, remote, branch, excludes):
+    env_copy = os.environ.copy()
+    env_copy['TZ'] = ''
+    extant = get_existing_files()
+
+    commits = [rev_parse((remote, branch))]
+    for exclude in excludes:
+        commits.append('^' + rev_parse(exclude))
+
+    o.write('<h2>Remote: %s<br>Branch: %s</h2>\n' % (remote, branch))
+    o.write('<table>\n<tr><th>APK</th><th>Date</th><th>Commit</th></tr>\n')
+    git_cmd = ['git', 'log', '--format=%H;%cd;%<(100,trunc)%s',
+               '--date=format-local:%Y-%m-%d %H:%M:%S %Z'] + commits
+    commits = check_output(git_cmd, env=env_copy)
+    for line in commits.split('\n'):
+        line = line.strip()
+        if not line:
+            continue
+        commit, date, subj = line.split(';', 2)
+        short = find(commit, extant)
+        if short is not None:
+            apk_name =  NAME_FMT % short
+            url = 'https://storage.googleapis.com/%s/%s' % (BUCKET, apk_name)
+        else:
+            apk_name, url =  '', ''
+        commit_url = '%s/+/%s' % (remote, commit)
+        o.write('<tr>\n<td><a href="%s">%s</a></td>\n'
+                '<td>%s</td>\n<td><a href="%s">%s</a></td>\n</tr>\n' %
+                (url, nowrap(apk_name), nowrap(date), commit_url, subj))
+    o.write('</table>\n')
+
+def main():
+    origin    = 'https://skia.googlesource.com/skia'
+    aosp_skqp = 'https://android.googlesource.com/platform/external/skqp'
+
+    assert '/' in [os.sep, os.altsep] and '..' == os.pardir
+    os.chdir(os.path.join(os.path.dirname(__file__), '../..'))
+    d = tempfile.mkdtemp()
+    path = os.path.join(d, 'apklist.html')
+    with open(path, 'w') as o:
+        o.write(HEADER)
+        table(o, origin,    'skqp/dev',     [(origin, 'master'), '3e34285f2a0'])
+        table(o, origin,    'skqp/release', [(origin, 'master'), '09ab171c5c0'])
+        table(o, aosp_skqp, 'pie-cts-dev',  ['f084c17322'])
+        o.write(FOOTER)
+    print path
+    call([sys.executable, 'bin/sysopen', path])
+    gscmd = 'gsutil -h "Content-Type:text/html" cp "%s" gs://skia-skqp/apklist'
+    print gscmd % path
+
+if __name__ == '__main__':
+    main()
+
diff --git a/src/third_party/skia/tools/skqp/make_skqp_model.cpp b/src/third_party/skia/tools/skqp/make_skqp_model.cpp
new file mode 100644
index 0000000..62ae5d0
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/make_skqp_model.cpp
@@ -0,0 +1,82 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/codec/SkCodec.h"
+#include "include/core/SkBitmap.h"
+#include "include/encode/SkPngEncoder.h"
+#include "src/core/SkOSFile.h"
+
+static void update(SkBitmap* maxBitmap, SkBitmap* minBitmap, const SkBitmap& bm) {
+    SkASSERT(!bm.drawsNothing());
+    SkASSERT(4 == bm.bytesPerPixel());
+    if (maxBitmap->drawsNothing()) {
+        maxBitmap->allocPixels(bm.info());
+        maxBitmap->eraseColor(0x00000000);
+        minBitmap->allocPixels(bm.info());
+        minBitmap->eraseColor(0xFFFFFFFF);
+    }
+    SkASSERT_RELEASE(maxBitmap->info() == bm.info());
+    const SkPixmap& pmin = minBitmap->pixmap();
+    const SkPixmap& pmax = maxBitmap->pixmap();
+    const SkPixmap& pm = bm.pixmap();
+    for (int y = 0; y < pm.height(); ++y) {
+        for (int x = 0; x < pm.width(); ++x) {
+            uint32_t* minPtr = pmin.writable_addr32(x, y);
+            uint32_t* maxPtr = pmax.writable_addr32(x, y);
+            uint8_t minColor[4], maxColor[4], color[4];
+            memcpy(minColor, minPtr, 4);
+            memcpy(maxColor, maxPtr, 4);
+            memcpy(color, pm.addr32(x, y), 4);
+            for (unsigned i = 0; i < 4; ++i) {
+                minColor[i] = std::min(minColor[i], color[i]);
+                maxColor[i] = std::max(maxColor[i], color[i]);
+            }
+            memcpy(minPtr, minColor, 4);
+            memcpy(maxPtr, maxColor, 4);
+        }
+    }
+}
+
+static SkBitmap decode_to_srgb_8888_unpremul(const char* path) {
+    SkBitmap dst;
+    if (auto codec = SkCodec::MakeFromData(SkData::MakeFromFileName(path))) {
+        SkISize size = codec->getInfo().dimensions();
+        SkASSERT(!size.isEmpty());
+        dst.allocPixels(SkImageInfo::Make(
+                    size.width(), size.height(), kRGBA_8888_SkColorType,
+                    kUnpremul_SkAlphaType, SkColorSpace::MakeSRGB()));
+        if (SkCodec::kSuccess != codec->getPixels(dst.pixmap())) {
+            dst.reset();
+        }
+    }
+    return dst;
+}
+
+bool encode_png(const char* path, const SkPixmap& pixmap) {
+    if (!pixmap.addr()) {
+        return false;
+    }
+    SkPngEncoder::Options encOpts;
+    encOpts.fZLibLevel = 9;  // slow encode;
+    SkFILEWStream o(path);
+    return o.isValid() && SkPngEncoder::Encode(&o, pixmap, encOpts);
+}
+
+int main(int argc, char** argv) {
+    SkASSERT_RELEASE(argc > 2);
+    const char* src_dir = argv[1];
+    const char* dst_dir = argv[2];
+    SkBitmap maxBitmap, minBitmap;
+    SkOSFile::Iter iter(src_dir);
+    SkString name;
+    while (iter.next(&name)) {
+        name.prependf("%s/", src_dir);
+        SkBitmap bm = decode_to_srgb_8888_unpremul(name.c_str());
+        if (!bm.drawsNothing()) {
+            update(&maxBitmap, &minBitmap, bm);
+        }
+    }
+    SkASSERT_RELEASE(sk_mkdir(dst_dir));
+    encode_png(SkStringPrintf("%s/min.png", dst_dir).c_str(), minBitmap.pixmap());
+    encode_png(SkStringPrintf("%s/max.png", dst_dir).c_str(), maxBitmap.pixmap());
+}
diff --git a/src/third_party/skia/tools/skqp/make_universal_apk b/src/third_party/skia/tools/skqp/make_universal_apk
new file mode 100755
index 0000000..e90a92d
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/make_universal_apk
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+exec python "$(dirname "$0")"/make_universal_apk.py "$@"
diff --git a/src/third_party/skia/tools/skqp/make_universal_apk.py b/src/third_party/skia/tools/skqp/make_universal_apk.py
new file mode 100755
index 0000000..bbddeb1
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/make_universal_apk.py
@@ -0,0 +1,69 @@
+#! /usr/bin/env python
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+'''
+This script can be run with no arguments, in which case it will produce an
+APK with native libraries for all four architectures: arm, arm64, x86, and
+x64.  You can instead list the architectures you want as arguments to this
+script.  For example:
+
+    python make_universal_apk.py arm x86
+
+The environment variables ANDROID_NDK and ANDROID_HOME must be set to the
+locations of the Android NDK and SDK.
+
+Additionally, `ninja` should be in your path.
+
+It assumes that the source tree is in the desired state, e.g. by having
+run 'python tools/git-sync-deps' in the root of the skia checkout.
+
+Also:
+  * If the environment variable SKQP_BUILD_DIR is set, many of the
+    intermediate build objects will be placed here.
+  * If the environment variable SKQP_OUTPUT_DIR is set, the final APK
+    will be placed in this directory.
+  * If the environment variable SKQP_DEBUG is set, Skia will be compiled
+    in debug mode.
+'''
+
+import os
+import sys
+
+import create_apk
+import download_model
+
+def make_apk(opts):
+    assert '/' in [os.sep, os.altsep]  # 'a/b' over os.path.join('a', 'b')
+
+    skia_dir = os.path.dirname(__file__) + '/../..'
+    create_apk.makedirs(opts.build_dir)
+    assets_dir = skia_dir + '/platform_tools/android/apps/skqp/src/main/assets'
+    gmkb = assets_dir + '/gmkb'
+    resources_path = assets_dir + '/resources'
+
+    with create_apk.RemoveFiles(resources_path, gmkb):  # always clean up
+        create_apk.remove(gmkb)
+        create_apk.make_symlinked_subdir(gmkb, opts.build_dir)
+
+        create_apk.remove(resources_path)
+        os.symlink('../../../../../../../resources', resources_path)
+
+        if os.path.exists(assets_dir + '/files.checksum'):
+            download_model.main()
+        else:
+            sys.stderr.write(
+                    '\n* * *  Note: SkQP models are missing!  * * *\n\n')
+        create_apk.create_apk(opts)
+
+def main():
+    options = create_apk.SkQP_Build_Options()
+    if options.error:
+        sys.stderr.write(options.error + __doc__)
+        sys.exit(1)
+    options.write(sys.stdout)
+    make_apk(options)
+
+if __name__ == '__main__':
+    main()
diff --git a/src/third_party/skia/tools/skqp/release.sh b/src/third_party/skia/tools/skqp/release.sh
new file mode 100755
index 0000000..ac898de
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/release.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+cd "$(dirname "$0")/../.."
+
+set -e -x
+
+[ -f platform_tools/android/apps/skqp/src/main/assets/files.checksum       ] || exit 1
+[ -f platform_tools/android/apps/skqp/src/main/assets/skqp/rendertests.txt ] || exit 1
+[ -f platform_tools/android/apps/skqp/src/main/assets/skqp/unittests.txt   ] || exit 1
+
+python tools/skqp/gn_to_bp.py
+python tools/skqp/download_model
+python tools/skqp/setup_resources
+
+touch MODULE_LICENSE_BSD
+
+cat > platform_tools/android/apps/skqp/src/main/Android.mk <<- "EOM"
+	# Copyright 2019 Google LLC.
+	# Use of this source code is governed by a BSD-style license that can be
+	# found in the LICENSE file.
+	LOCAL_PATH:= $(call my-dir)
+	include $(CLEAR_VARS)
+	LOCAL_MODULE_TAGS := tests optional
+	LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+	LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+	LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
+	LOCAL_JNI_SHARED_LIBRARIES := libskqp_app
+	LOCAL_MULTILIB := both
+	LOCAL_USE_AAPT2 := true
+	LOCAL_STATIC_ANDROID_LIBRARIES := android-support-design
+	LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner-axt
+	LOCAL_SRC_FILES := $(call all-java-files-under, java)
+	LOCAL_PACKAGE_NAME := CtsSkQPTestCases
+	LOCAL_SDK_VERSION := test_current
+	include $(BUILD_CTS_PACKAGE)
+EOM
+
+cat > include/config/SkUserConfigManual.h <<- "EOM"
+	// Copyright 2019 Google LLC.
+	// Use of this source code is governed by a BSD-style license that can be
+	// found in the LICENSE file.
+	#ifndef SkUserConfigManual_DEFINED
+	#define SkUserConfigManual_DEFINED
+	// DON'T DEFINE THINGS HERE AS IT WILL RESULT IN DIFFERENCES WITH
+	// THE VERSION OF SKQP PUBLISHED ON SKIA.ORG
+	#endif // SkUserConfigManual_DEFINED
+EOM
+
+cat > platform_tools/android/apps/skqp/src/main/AndroidTest.xml <<- "EOM"
+	<?xml version="1.0" encoding="utf-8"?>
+	<!--
+	Copyright 2019 Google LLC.
+	Use of this source code is governed by a BSD-style license that can be
+	found in the LICENSE file.
+	-->
+	<configuration description="Config for CTS SkQP test cases">
+	<option name="test-suite-tag" value="cts" />
+	<option name="not-shardable" value="true" />
+	<option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+	<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+	<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+	<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+	<option name="cleanup-apks" value="true" />
+	<option name="test-file-name" value="CtsSkQPTestCases.apk" />
+	</target_preparer>
+	<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+	<option name="package" value="org.skia.skqp" />
+	<option name="runtime-hint" value="7m" />
+	</test>
+	</configuration>
+EOM
+
+[ -f platform_tools/android/apps/skqp/src/main/assets/.gitignore ] && \
+    git rm platform_tools/android/apps/skqp/src/main/assets/.gitignore
+
+git add                                                       \
+    Android.bp                                                \
+    MODULE_LICENSE_BSD                                        \
+    include/config/SkUserConfig.h                             \
+    include/config/SkUserConfigManual.h                       \
+    platform_tools/android/apps/skqp/src/main/Android.mk      \
+    platform_tools/android/apps/skqp/src/main/AndroidTest.xml \
+    platform_tools/android/apps/skqp/src/main/assets
diff --git a/src/third_party/skia/tools/skqp/run_apk.sh b/src/third_party/skia/tools/skqp/run_apk.sh
new file mode 100644
index 0000000..b35933e
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/run_apk.sh
@@ -0,0 +1,39 @@
+#! /bin/sh
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Note:
+#   The ANDROID_SERIAL, SKQP_ARGS, and SKQP_SLEEP environment variables affect
+#   this script.
+
+if ! [ -f "$1" ] || ! [ -d "$2" ] ; then
+  echo "Usage:  $0 SKQP_APK_FILE_PATH RESULTS_DIRECTORY" >&2
+  exit 1
+fi
+
+SED_CMD='s/^.* org.skia.skqp: output written to "\([^"]*\)".*$/\1/p'
+APK="$1"
+DST="$2"
+
+printf '\n\nAPK = "%s"\nDST = "%s"\n\n' "$APK" "$DST"
+
+set -x
+
+timeout 60 adb wait-for-device || exit 1
+
+sleep ${SKQP_SLEEP:-0}
+
+adb uninstall org.skia.skqp > /dev/null 2>&1
+
+adb install "$APK" || exit 1
+
+adb logcat -c
+
+adb shell am instrument $SKQP_ARGS -w org.skia.skqp 2>&1 | tee "$DST"/stdout
+
+adb logcat -d TestRunner org.skia.skqp skia DEBUG '*:S' > "$DST"/logcat
+
+ODIR="$(sed -n "$SED_CMD" "$DST"/logcat | head -1)"
+
+if adb shell "test -d '$ODIR'"; then adb pull "$ODIR" "$DST"; fi
diff --git a/src/third_party/skia/tools/skqp/run_skqp_exe b/src/third_party/skia/tools/skqp/run_skqp_exe
new file mode 100755
index 0000000..7b17425
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/run_skqp_exe
@@ -0,0 +1,53 @@
+#! /usr/bin/env python
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import subprocess
+import tempfile
+import sysopen
+import sys
+
+def skqp(build):
+    def adb(*args):
+        sys.stdout.write("adb '" + "' '".join(args) + "'\n")
+        subprocess.check_call(['adb'] + list(args))
+
+    assert os.path.isdir(build)
+    build = os.path.abspath(build)
+
+    os.chdir(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
+
+    adb('shell', 'rm -rf /data/local/tmp/skqp; mkdir -p /data/local/tmp/skqp')
+
+    adb('push',
+        os.path.join(*'platform_tools/android/apps/skqp/src/main/assets'.split('/')),
+        '/data/local/tmp/skqp/skqp_assets')
+
+    adb('push', os.path.join(build, 'skqp'), '/data/local/tmp/skqp/skqp')
+
+    cmd = "cd /data/local/tmp/skqp; ./skqp skqp_assets report"
+    sys.stdout.write("adb 'shell' '%s'\n" % cmd)
+    ret = subprocess.call(['adb', 'shell', cmd])
+
+    tmpdir = tempfile.mkdtemp(prefix='skqp')
+
+    adb('pull', "/data/local/tmp/report", tmpdir)
+
+    return ret, os.path.join(tmpdir, 'report')
+
+if __name__ == '__main__':
+    if len(sys.argv) != 2 or not os.path.isdir(sys.argv[1]):
+        sys.stderr.write('Usage\n  %s BUILD_DIR\n\n' % sys.argv[0])
+        sys.exit(1)
+    try:
+        ret, report = skqp(sys.argv[1])
+    except subprocess.CalledProcessError:
+        sys.stderr.write('Command failed.\n')
+        sys.exit(1)
+
+    sys.stdout.write('\nReturn code: %d\nOutput written to "%s"\n' % (ret, report))
+    sysopen.sysopen(os.path.join(report, 'report.html'))
+
diff --git a/src/third_party/skia/tools/skqp/setup_resources b/src/third_party/skia/tools/skqp/setup_resources
new file mode 100755
index 0000000..22f27a8
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/setup_resources
@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+
+# Copyright 2018 Google Inc.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import sys
+
+if __name__ == '__main__':
+    skia = os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir)
+    dst = os.path.join(skia, 'platform_tools', 'android', 'apps', 'skqp',
+                       'src', 'main', 'assets', 'resources')
+    if os.path.isdir(dst) and not os.path.islink(dst):
+        shutil.rmtree(dst)
+    elif os.path.exists(dst):
+        os.remove(dst)
+    shutil.copytree(os.path.join(skia, 'resources'), dst)
+
diff --git a/src/third_party/skia/tools/skqp/skqp_gn_args.py b/src/third_party/skia/tools/skqp/skqp_gn_args.py
new file mode 100644
index 0000000..1f1f052
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/skqp_gn_args.py
@@ -0,0 +1,32 @@
+# Copyright 2019 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+SkqpGnArgs = {
+    'extra_cflags':                     '[ "-DSK_ENABLE_DUMP_GPU", "-DSK_BUILD_FOR_SKQP" ]',
+    'skia_enable_fontmgr_android':      'false',
+    'skia_enable_fontmgr_empty':        'true',
+    'skia_enable_pdf':                  'false',
+    'skia_enable_skottie':              'false',
+    'skia_skqp_global_error_tolerance': '8',
+    'skia_tools_require_resources':     'true',
+    'skia_use_dng_sdk':                 'false',
+    'skia_use_expat':                   'true',
+    'skia_use_icu':                     'false',
+    'skia_use_libheif':                 'false',
+    'skia_use_lua':                     'false',
+    'skia_use_piex':                    'false',
+    'skia_use_vulkan':                  'true',
+}
+
+def GetGNArgs(arch, android_ndk, debug, api_level):
+    def gn_quote(s):
+        return '"%s"' % s
+    gn_args = {
+        'target_cpu':  gn_quote(arch),
+        'ndk':         gn_quote(android_ndk),
+        'is_debug':    'true' if debug else 'false',
+        'ndk_api':     api_level,
+    }
+    gn_args.update(SkqpGnArgs)
+    return gn_args
diff --git a/src/third_party/skia/tools/skqp/src/jni_skqp.cpp b/src/third_party/skia/tools/skqp/src/jni_skqp.cpp
new file mode 100644
index 0000000..43d8dd2
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/jni_skqp.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <mutex>
+
+#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
+#include <jni.h>
+#include <sys/stat.h>
+
+#include "include/core/SkStream.h"
+#include "include/private/SkTo.h"
+#include "tools/ResourceFactory.h"
+
+#include "tools/skqp/src/skqp.h"
+
+////////////////////////////////////////////////////////////////////////////////
+extern "C" {
+JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nInit(JNIEnv*, jobject, jobject, jstring);
+JNIEXPORT jlong JNICALL Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv*, jobject, jint, jint);
+JNIEXPORT jobjectArray JNICALL Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv*, jobject, jint);
+JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject);
+}  // extern "C"
+////////////////////////////////////////////////////////////////////////////////
+
+static AAssetManager* gAAssetManager = nullptr;
+
+static sk_sp<SkData> open_asset_data(const char* path) {
+    sk_sp<SkData> data;
+    if (gAAssetManager) {
+        if (AAsset* asset = AAssetManager_open(gAAssetManager, path, AASSET_MODE_STREAMING)) {
+            if (size_t size = SkToSizeT(AAsset_getLength(asset))) {
+                data = SkData::MakeUninitialized(size);
+                int ret = AAsset_read(asset, data->writable_data(), size);
+                if (ret != SkToInt(size)) {
+                    SkDebugf("ERROR: AAsset_read != AAsset_getLength (%s)\n", path);
+                }
+            }
+            AAsset_close(asset);
+        }
+    }
+    return data;
+}
+
+namespace {
+struct AndroidAssetManager : public SkQPAssetManager {
+    sk_sp<SkData> open(const char* path) override { return open_asset_data(path); }
+};
+}
+
+// TODO(halcanary): Should not have global variables; SkQP Java object should
+// own pointers and manage concurency.
+static AndroidAssetManager gAndroidAssetManager;
+static std::mutex gMutex;
+static SkQP gSkQP;
+
+#define jassert(env, cond, ret) do { if (!(cond)) { \
+    (env)->ThrowNew((env)->FindClass("java/lang/Exception"), \
+                    __FILE__ ": assert(" #cond ") failed."); \
+    return ret; } } while (0)
+
+static void set_string_array_element(JNIEnv* env, jobjectArray a, const char* s, unsigned i) {
+    jstring jstr = env->NewStringUTF(s);
+    jassert(env, jstr != nullptr,);
+    env->SetObjectArrayElement(a, (jsize)i, jstr);
+    env->DeleteLocalRef(jstr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkData> get_resource(const char* resource) {
+    return open_asset_data((std::string("resources/")  + resource).c_str());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T, typename F>
+jobjectArray to_java_string_array(JNIEnv* env,
+                                  const std::vector<T>& array,
+                                  F toString) {
+    jclass stringClass = env->FindClass("java/lang/String");
+    jassert(env, stringClass, nullptr);
+    jobjectArray jarray = env->NewObjectArray((jint)array.size(), stringClass, nullptr);
+    jassert(env, jarray != nullptr, nullptr);
+    for (unsigned i = 0; i < array.size(); ++i) {
+        set_string_array_element(env, jarray, std::string(toString(array[i])).c_str(), i);
+    }
+    return jarray;
+}
+
+static std::string to_string(JNIEnv* env, jstring jString) {
+    const char* utf8String = env->GetStringUTFChars(jString, nullptr);
+    jassert(env, utf8String && utf8String[0], "");
+    std::string sString(utf8String);
+    env->ReleaseStringUTFChars(jString, utf8String);
+    return sString;
+}
+
+void Java_org_skia_skqp_SkQP_nInit(JNIEnv* env, jobject object, jobject assetManager,
+                                   jstring dataDir) {
+    jclass SkQP_class = env->GetObjectClass(object);
+
+    // tools/Resources
+    gResourceFactory = &get_resource;
+
+    std::string reportDirectory = to_string(env, dataDir);
+
+    jassert(env, assetManager,);
+    // This global must be set before using AndroidAssetManager
+    gAAssetManager = AAssetManager_fromJava(env, assetManager);
+    jassert(env, gAAssetManager,);
+
+    std::lock_guard<std::mutex> lock(gMutex);
+    gSkQP.init(&gAndroidAssetManager, reportDirectory.c_str());
+
+    auto backends = gSkQP.getSupportedBackends();
+    jassert(env, backends.size() > 0,);
+    auto gms = gSkQP.getGMs();
+    jassert(env, gms.size() > 0,);
+    auto unitTests = gSkQP.getUnitTests();
+    jassert(env, unitTests.size() > 0,);
+
+    constexpr char kStringArrayType[] = "[Ljava/lang/String;";
+    env->SetObjectField(object, env->GetFieldID(SkQP_class, "mBackends", kStringArrayType),
+                        to_java_string_array(env, backends, SkQP::GetBackendName));
+    env->SetObjectField(object, env->GetFieldID(SkQP_class, "mUnitTests", kStringArrayType),
+                        to_java_string_array(env, unitTests, SkQP::GetUnitTestName));
+    env->SetObjectField(object, env->GetFieldID(SkQP_class, "mGMs", kStringArrayType),
+                        to_java_string_array(env, gms, SkQP::GetGMName));
+}
+
+jlong Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv* env,
+                                          jobject object,
+                                          jint gmIndex,
+                                          jint backendIndex) {
+    SkQP::RenderOutcome outcome;
+    std::string except;
+    {
+        std::lock_guard<std::mutex> lock(gMutex);
+        jassert(env, backendIndex < (jint)gSkQP.getSupportedBackends().size(), -1);
+        jassert(env, gmIndex < (jint)gSkQP.getGMs().size(), -1);
+        SkQP::SkiaBackend backend = gSkQP.getSupportedBackends()[backendIndex];
+        SkQP::GMFactory gm = gSkQP.getGMs()[gmIndex];
+        std::tie(outcome, except) = gSkQP.evaluateGM(backend, gm);
+    }
+
+    if (!except.empty()) {
+        (void)env->ThrowNew(env->FindClass("org/skia/skqp/SkQPException"), except.c_str());
+    }
+    return (jlong)outcome.fTotalError;
+}
+
+jobjectArray Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv* env,
+                                                      jobject object,
+                                                      jint index) {
+    std::vector<std::string> errors;
+    {
+        jassert(env, index < (jint)gSkQP.getUnitTests().size(), nullptr);
+        std::lock_guard<std::mutex> lock(gMutex);
+        errors = gSkQP.executeTest(gSkQP.getUnitTests()[index]);
+    }
+    if (errors.size() == 0) {
+        return nullptr;
+    }
+    jclass stringClass = env->FindClass("java/lang/String");
+    jassert(env, stringClass, nullptr);
+    jobjectArray array = env->NewObjectArray(errors.size(), stringClass, nullptr);
+    for (unsigned i = 0; i < errors.size(); ++i) {
+        set_string_array_element(env, array, errors[i].c_str(), i);
+    }
+    return (jobjectArray)env->NewGlobalRef(array);
+}
+
+void Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject) {
+    std::lock_guard<std::mutex> lock(gMutex);
+    gSkQP.makeReport();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
diff --git a/src/third_party/skia/tools/skqp/src/skqp.cpp b/src/third_party/skia/tools/skqp/src/skqp.cpp
new file mode 100644
index 0000000..04f0369
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/skqp.cpp
@@ -0,0 +1,499 @@
+/*
+ * 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 "tools/skqp/src/skqp.h"
+
+#include "gm/gm.h"
+#include "include/core/SkFontStyle.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/encode/SkPngEncoder.h"
+#include "include/gpu/GrContext.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/private/SkImageInfoPriv.h"
+#include "src/core/SkFontMgrPriv.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkStreamPriv.h"
+#include "src/utils/SkOSPath.h"
+#include "tests/Test.h"
+#include "tools/fonts/TestFontMgr.h"
+#include "tools/gpu/gl/GLTestContext.h"
+#include "tools/gpu/vk/VkTestContext.h"
+
+#include <limits.h>
+#include <algorithm>
+#include <cinttypes>
+#include <sstream>
+
+#include "tools/skqp/src/skqp_model.h"
+
+#define IMAGES_DIRECTORY_PATH "images"
+#define PATH_MAX_PNG "max.png"
+#define PATH_MIN_PNG "min.png"
+#define PATH_IMG_PNG "image.png"
+#define PATH_ERR_PNG "errors.png"
+#define PATH_MODEL "model"
+
+static constexpr char kRenderTestCSVReport[] = "out.csv";
+static constexpr char kRenderTestReportPath[] = "report.html";
+static constexpr char kRenderTestsPath[] = "skqp/rendertests.txt";
+static constexpr char kUnitTestReportPath[] = "unit_tests.txt";
+static constexpr char kUnitTestsPath[]   = "skqp/unittests.txt";
+
+// Kind of like Python's readlines(), but without any allocation.
+// Calls f() on each line.
+// F is [](const char*, size_t) -> void
+template <typename F>
+static void readlines(const void* data, size_t size, F f) {
+    const char* start = (const char*)data;
+    const char* end = start + size;
+    const char* ptr = start;
+    while (ptr < end) {
+        while (*ptr++ != '\n' && ptr < end) {}
+        size_t len = ptr - start;
+        f(start, len);
+        start = ptr;
+    }
+}
+
+static void get_unit_tests(SkQPAssetManager* mgr, std::vector<SkQP::UnitTest>* unitTests) {
+    std::unordered_set<std::string> testset;
+    auto insert = [&testset](const char* s, size_t l) {
+        SkASSERT(l > 1) ;
+        if (l > 0 && s[l - 1] == '\n') {  // strip line endings.
+            --l;
+        }
+        if (l > 0) {  // only add non-empty strings.
+            testset.insert(std::string(s, l));
+        }
+    };
+    if (sk_sp<SkData> dat = mgr->open(kUnitTestsPath)) {
+        readlines(dat->data(), dat->size(), insert);
+    }
+    for (const skiatest::Test& test : skiatest::TestRegistry::Range()) {
+        if ((testset.empty() || testset.count(std::string(test.name)) > 0) && test.needsGpu) {
+            unitTests->push_back(&test);
+        }
+    }
+    auto lt = [](SkQP::UnitTest u, SkQP::UnitTest v) { return strcmp(u->name, v->name) < 0; };
+    std::sort(unitTests->begin(), unitTests->end(), lt);
+}
+
+static void get_render_tests(SkQPAssetManager* mgr,
+                             std::vector<SkQP::GMFactory>* gmlist,
+                             std::unordered_map<std::string, int64_t>* gmThresholds) {
+    auto insert = [gmThresholds](const char* s, size_t l) {
+        SkASSERT(l > 1) ;
+        if (l > 0 && s[l - 1] == '\n') {  // strip line endings.
+            --l;
+        }
+        if (l == 0) {
+            return;
+        }
+        const char* end = s + l;
+        const char* ptr = s;
+        constexpr char kDelimeter = ',';
+        while (ptr < end && *ptr != kDelimeter) { ++ptr; }
+        if (ptr + 1 >= end) {
+            SkASSERT(false);  // missing delimeter
+            return;
+        }
+        std::string key(s, ptr - s);
+        ++ptr;  // skip delimeter
+        std::string number(ptr, end - ptr);  // null-terminated copy.
+        int64_t value = 0;
+        if (1 != sscanf(number.c_str(), "%" SCNd64 , &value)) {
+            SkASSERT(false);  // Not a number
+            return;
+        }
+        gmThresholds->insert({std::move(key), value});  // (*gmThresholds)[s] = value;
+    };
+    if (sk_sp<SkData> dat = mgr->open(kRenderTestsPath)) {
+        readlines(dat->data(), dat->size(), insert);
+    }
+    using GmAndName = std::pair<SkQP::GMFactory, std::string>;
+    std::vector<GmAndName> gmsWithNames;
+    for (skiagm::GMFactory f : skiagm::GMRegistry::Range()) {
+        std::string name = SkQP::GetGMName(f);
+        if ((gmThresholds->empty() || gmThresholds->count(name) > 0)) {
+            gmsWithNames.push_back(std::make_pair(f, std::move(name)));
+        }
+    }
+    std::sort(gmsWithNames.begin(), gmsWithNames.end(),
+              [](GmAndName u, GmAndName v) { return u.second < v.second; });
+    gmlist->reserve(gmsWithNames.size());
+    for (const GmAndName& gmn : gmsWithNames) {
+        gmlist->push_back(gmn.first);
+    }
+}
+
+static std::unique_ptr<sk_gpu_test::TestContext> make_test_context(SkQP::SkiaBackend backend) {
+    using U = std::unique_ptr<sk_gpu_test::TestContext>;
+    switch (backend) {
+// TODO(halcanary): Fuchsia will have SK_SUPPORT_GPU and SK_VULKAN, but *not* SK_GL.
+#ifdef SK_GL
+        case SkQP::SkiaBackend::kGL:
+            return U(sk_gpu_test::CreatePlatformGLTestContext(kGL_GrGLStandard, nullptr));
+        case SkQP::SkiaBackend::kGLES:
+            return U(sk_gpu_test::CreatePlatformGLTestContext(kGLES_GrGLStandard, nullptr));
+#endif
+#ifdef SK_VULKAN
+        case SkQP::SkiaBackend::kVulkan:
+            return U(sk_gpu_test::CreatePlatformVkTestContext(nullptr));
+#endif
+        default:
+            return nullptr;
+    }
+}
+
+static GrContextOptions context_options(skiagm::GM* gm = nullptr) {
+    GrContextOptions grContextOptions;
+    grContextOptions.fAllowPathMaskCaching = true;
+    grContextOptions.fDisableDriverCorrectnessWorkarounds = true;
+    if (gm) {
+        gm->modifyGrContextOptions(&grContextOptions);
+    }
+    return grContextOptions;
+}
+
+static std::vector<SkQP::SkiaBackend> get_backends() {
+    std::vector<SkQP::SkiaBackend> result;
+    SkQP::SkiaBackend backends[] = {
+        #ifdef SK_GL
+        #ifndef SK_BUILD_FOR_ANDROID
+        SkQP::SkiaBackend::kGL,  // Used for testing on desktop machines.
+        #endif
+        SkQP::SkiaBackend::kGLES,
+        #endif  // SK_GL
+        #ifdef SK_VULKAN
+        SkQP::SkiaBackend::kVulkan,
+        #endif
+    };
+    for (SkQP::SkiaBackend backend : backends) {
+        std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend);
+        if (testCtx) {
+            testCtx->makeCurrent();
+            if (nullptr != testCtx->makeGrContext(context_options())) {
+                result.push_back(backend);
+            }
+        }
+    }
+    SkASSERT_RELEASE(result.size() > 0);
+    return result;
+}
+
+static void print_backend_info(const char* dstPath,
+                               const std::vector<SkQP::SkiaBackend>& backends) {
+#ifdef SK_ENABLE_DUMP_GPU
+    SkFILEWStream out(dstPath);
+    out.writeText("[\n");
+    for (SkQP::SkiaBackend backend : backends) {
+        if (std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend)) {
+            testCtx->makeCurrent();
+            if (sk_sp<GrContext> ctx = testCtx->makeGrContext(context_options())) {
+                SkString info = ctx->dump();
+                // remove null
+                out.write(info.c_str(), info.size());
+                out.writeText(",\n");
+            }
+        }
+    }
+    out.writeText("]\n");
+#endif
+}
+
+static void encode_png(const SkBitmap& src, const std::string& dst) {
+    SkFILEWStream wStream(dst.c_str());
+    SkPngEncoder::Options options;
+    bool success = wStream.isValid() && SkPngEncoder::Encode(&wStream, src.pixmap(), options);
+    SkASSERT_RELEASE(success);
+}
+
+static void write_to_file(const sk_sp<SkData>& src, const std::string& dst) {
+    SkFILEWStream wStream(dst.c_str());
+    bool success = wStream.isValid() && wStream.write(src->data(), src->size());
+    SkASSERT_RELEASE(success);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+const char* SkQP::GetBackendName(SkQP::SkiaBackend b) {
+    switch (b) {
+        case SkQP::SkiaBackend::kGL:     return "gl";
+        case SkQP::SkiaBackend::kGLES:   return "gles";
+        case SkQP::SkiaBackend::kVulkan: return "vk";
+    }
+    return "";
+}
+
+std::string SkQP::GetGMName(SkQP::GMFactory f) {
+    std::unique_ptr<skiagm::GM> gm(f ? f() : nullptr);
+    return std::string(gm ? gm->getName() : "");
+}
+
+const char* SkQP::GetUnitTestName(SkQP::UnitTest t) { return t->name; }
+
+SkQP::SkQP() {}
+
+SkQP::~SkQP() {}
+
+void SkQP::init(SkQPAssetManager* am, const char* reportDirectory) {
+    SkASSERT_RELEASE(!fAssetManager);
+    SkASSERT_RELEASE(am);
+    fAssetManager = am;
+    fReportDirectory = reportDirectory;
+
+    SkGraphics::Init();
+    gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr;
+
+    /* If the file "skqp/rendertests.txt" does not exist or is empty, run all
+       render tests.  Otherwise only run tests mentioned in that file.  */
+    get_render_tests(fAssetManager, &fGMs, &fGMThresholds);
+    /* If the file "skqp/unittests.txt" does not exist or is empty, run all gpu
+       unit tests.  Otherwise only run tests mentioned in that file.  */
+    get_unit_tests(fAssetManager, &fUnitTests);
+    fSupportedBackends = get_backends();
+
+    print_backend_info((fReportDirectory + "/grdump.txt").c_str(), fSupportedBackends);
+}
+
+std::tuple<SkQP::RenderOutcome, std::string> SkQP::evaluateGM(SkQP::SkiaBackend backend,
+                                                              SkQP::GMFactory gmFact) {
+    SkASSERT_RELEASE(fAssetManager);
+    static constexpr SkQP::RenderOutcome kError = {INT_MAX, INT_MAX, INT64_MAX};
+    static constexpr SkQP::RenderOutcome kPass = {0, 0, 0};
+
+    std::unique_ptr<sk_gpu_test::TestContext> testCtx = make_test_context(backend);
+    if (!testCtx) {
+        return std::make_tuple(kError, "Skia Failure: test context");
+    }
+    testCtx->makeCurrent();
+
+    SkASSERT(gmFact);
+    std::unique_ptr<skiagm::GM> gm(gmFact());
+    SkASSERT(gm);
+    const char* const name = gm->getName();
+    const SkISize size = gm->getISize();
+    const int w = size.width();
+    const int h = size.height();
+    const SkImageInfo info =
+        SkImageInfo::Make(w, h, skqp::kColorType, kPremul_SkAlphaType, nullptr);
+    const SkSurfaceProps props(0, SkSurfaceProps::kLegacyFontHost_InitType);
+
+    sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(
+            testCtx->makeGrContext(context_options(gm.get())).get(),
+            SkBudgeted::kNo, info, 0, &props);
+    if (!surf) {
+        return std::make_tuple(kError, "Skia Failure: gr-context");
+    }
+    gm->draw(surf->getCanvas());
+
+    SkBitmap image;
+    image.allocPixels(SkImageInfo::Make(w, h, skqp::kColorType, skqp::kAlphaType));
+
+    // SkColorTypeBytesPerPixel should be constexpr, but is not.
+    SkASSERT(SkColorTypeBytesPerPixel(skqp::kColorType) == sizeof(uint32_t));
+    // Call readPixels because we need to compare pixels.
+    if (!surf->readPixels(image.pixmap(), 0, 0)) {
+        return std::make_tuple(kError, "Skia Failure: read pixels");
+    }
+    int64_t passingThreshold = fGMThresholds.empty() ? -1 : fGMThresholds[std::string(name)];
+
+    if (-1 == passingThreshold) {
+        return std::make_tuple(kPass, "");
+    }
+    skqp::ModelResult modelResult =
+        skqp::CheckAgainstModel(name, image.pixmap(), fAssetManager);
+
+    if (!modelResult.fErrorString.empty()) {
+        return std::make_tuple(kError, std::move(modelResult.fErrorString));
+    }
+    fRenderResults.push_back(SkQP::RenderResult{backend, gmFact, modelResult.fOutcome});
+    if (modelResult.fOutcome.fMaxError <= passingThreshold) {
+        return std::make_tuple(kPass, "");
+    }
+    std::string imagesDirectory = fReportDirectory + "/" IMAGES_DIRECTORY_PATH;
+    if (!sk_mkdir(imagesDirectory.c_str())) {
+        SkDebugf("ERROR: sk_mkdir('%s');\n", imagesDirectory.c_str());
+        return std::make_tuple(modelResult.fOutcome, "");
+    }
+    std::ostringstream tmp;
+    tmp << imagesDirectory << '/' << SkQP::GetBackendName(backend) << '_' << name << '_';
+    std::string imagesPathPrefix1 = tmp.str();
+    tmp = std::ostringstream();
+    tmp << imagesDirectory << '/' << PATH_MODEL << '_' << name << '_';
+    std::string imagesPathPrefix2 = tmp.str();
+    encode_png(image,                  imagesPathPrefix1 + PATH_IMG_PNG);
+    encode_png(modelResult.fErrors,    imagesPathPrefix1 + PATH_ERR_PNG);
+    write_to_file(modelResult.fMaxPng, imagesPathPrefix2 + PATH_MAX_PNG);
+    write_to_file(modelResult.fMinPng, imagesPathPrefix2 + PATH_MIN_PNG);
+    return std::make_tuple(modelResult.fOutcome, "");
+}
+
+std::vector<std::string> SkQP::executeTest(SkQP::UnitTest test) {
+    SkASSERT_RELEASE(fAssetManager);
+    struct : public skiatest::Reporter {
+        std::vector<std::string> fErrors;
+        void reportFailed(const skiatest::Failure& failure) override {
+            SkString desc = failure.toString();
+            fErrors.push_back(std::string(desc.c_str(), desc.size()));
+        }
+    } r;
+    GrContextOptions options;
+    options.fDisableDriverCorrectnessWorkarounds = true;
+    if (test->fContextOptionsProc) {
+        test->fContextOptionsProc(&options);
+    }
+    test->proc(&r, options);
+    fUnitTestResults.push_back(UnitTestResult{test, r.fErrors});
+    return r.fErrors;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static constexpr char kDocHead[] =
+    "<!doctype html>\n"
+    "<html lang=\"en\">\n"
+    "<head>\n"
+    "<meta charset=\"UTF-8\">\n"
+    "<title>SkQP Report</title>\n"
+    "<style>\n"
+    "img { max-width:48%; border:1px green solid;\n"
+    "      image-rendering: pixelated;\n"
+    "      background-image:url('data:image/png;base64,iVBORw0KGgoA"
+    "AAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAAXNSR0IArs4c6QAAAAJiS0dEAP+H"
+    "j8y/AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAB3RJTUUH3gUBEi4DGRAQYgAAAB1J"
+    "REFUGNNjfMoAAVJQmokBDdBHgPE/lPFsYN0BABdaAwN6tehMAAAAAElFTkSuQmCC"
+    "'); }\n"
+    "</style>\n"
+    "<script>\n"
+    "function ce(t) { return document.createElement(t); }\n"
+    "function ct(n) { return document.createTextNode(n); }\n"
+    "function ac(u,v) { return u.appendChild(v); }\n"
+    "function br(u) { ac(u, ce(\"br\")); }\n"
+    "function ma(s, c) { var a = ce(\"a\"); a.href = s; ac(a, c); return a; }\n"
+    "function f(backend, gm, e1, e2, e3) {\n"
+    "  var b = ce(\"div\");\n"
+    "  var x = ce(\"h2\");\n"
+    "  var t = backend + \"_\" + gm;\n"
+    "  ac(x, ct(t));\n"
+    "  ac(b, x);\n"
+    "  ac(b, ct(\"backend: \" + backend));\n"
+    "  br(b);\n"
+    "  ac(b, ct(\"gm name: \" + gm));\n"
+    "  br(b);\n"
+    "  ac(b, ct(\"maximum error: \" + e1));\n"
+    "  br(b);\n"
+    "  ac(b, ct(\"bad pixel counts: \" + e2));\n"
+    "  br(b);\n"
+    "  ac(b, ct(\"total error: \" + e3));\n"
+    "  br(b);\n"
+    "  var q = \"" IMAGES_DIRECTORY_PATH "/\" + backend + \"_\" + gm + \"_\";\n"
+    "  var p = \"" IMAGES_DIRECTORY_PATH "/"   PATH_MODEL  "_\" + gm + \"_\";\n"
+    "  var i = ce(\"img\");\n"
+    "  i.src = q + \"" PATH_IMG_PNG "\";\n"
+    "  i.alt = \"img\";\n"
+    "  ac(b, ma(i.src, i));\n"
+    "  i = ce(\"img\");\n"
+    "  i.src = q + \"" PATH_ERR_PNG "\";\n"
+    "  i.alt = \"err\";\n"
+    "  ac(b, ma(i.src, i));\n"
+    "  br(b);\n"
+    "  ac(b, ct(\"Expectation: \"));\n"
+    "  ac(b, ma(p + \"" PATH_MAX_PNG "\", ct(\"max\")));\n"
+    "  ac(b, ct(\" | \"));\n"
+    "  ac(b, ma(p + \"" PATH_MIN_PNG "\", ct(\"min\")));\n"
+    "  ac(b, ce(\"hr\"));\n"
+    "  b.id = backend + \":\" + gm;\n"
+    "  ac(document.body, b);\n"
+    "  l = ce(\"li\");\n"
+    "  ac(l, ct(\"[\" + e3 + \"] \"));\n"
+    "  ac(l, ma(\"#\" + backend +\":\"+ gm , ct(t)));\n"
+    "  ac(document.getElementById(\"toc\"), l);\n"
+    "}\n"
+    "function main() {\n";
+
+static constexpr char kDocMiddle[] =
+    "}\n"
+    "</script>\n"
+    "</head>\n"
+    "<body onload=\"main()\">\n"
+    "<h1>SkQP Report</h1>\n";
+
+static constexpr char kDocTail[] =
+    "<ul id=\"toc\"></ul>\n"
+    "<hr>\n"
+    "<p>Left image: test result<br>\n"
+    "Right image: errors (white = no error, black = smallest error, red = biggest error; "
+    "other errors are a color between black and red.)</p>\n"
+    "<hr>\n"
+    "</body>\n"
+    "</html>\n";
+
+template <typename T>
+inline void write(SkWStream* wStream, const T& text) {
+    wStream->write(text.c_str(), text.size());
+}
+
+void SkQP::makeReport() {
+    SkASSERT_RELEASE(fAssetManager);
+    int glesErrorCount = 0, vkErrorCount = 0, gles = 0, vk = 0;
+
+    if (!sk_isdir(fReportDirectory.c_str())) {
+        SkDebugf("Report destination does not exist: '%s'\n", fReportDirectory.c_str());
+        return;
+    }
+    SkFILEWStream csvOut(SkOSPath::Join(fReportDirectory.c_str(), kRenderTestCSVReport).c_str());
+    SkFILEWStream htmOut(SkOSPath::Join(fReportDirectory.c_str(), kRenderTestReportPath).c_str());
+    SkASSERT_RELEASE(csvOut.isValid() && htmOut.isValid());
+    htmOut.writeText(kDocHead);
+    for (const SkQP::RenderResult& run : fRenderResults) {
+        switch (run.fBackend) {
+            case SkQP::SkiaBackend::kGLES: ++gles; break;
+            case SkQP::SkiaBackend::kVulkan: ++vk; break;
+            default: break;
+        }
+        const char* backendName = SkQP::GetBackendName(run.fBackend);
+        std::string gmName = SkQP::GetGMName(run.fGM);
+        const SkQP::RenderOutcome& outcome = run.fOutcome;
+        auto str = SkStringPrintf("\"%s\",\"%s\",%d,%d,%" PRId64, backendName, gmName.c_str(),
+                                  outcome.fMaxError, outcome.fBadPixelCount, outcome.fTotalError);
+        write(&csvOut, SkStringPrintf("%s\n", str.c_str()));
+
+        int64_t passingThreshold = fGMThresholds.empty() ? 0 : fGMThresholds[gmName];
+        if (passingThreshold == -1 || outcome.fMaxError <= passingThreshold) {
+            continue;
+        }
+        write(&htmOut, SkStringPrintf("  f(%s);\n", str.c_str()));
+        switch (run.fBackend) {
+            case SkQP::SkiaBackend::kGLES: ++glesErrorCount; break;
+            case SkQP::SkiaBackend::kVulkan: ++vkErrorCount; break;
+            default: break;
+        }
+    }
+    htmOut.writeText(kDocMiddle);
+    write(&htmOut, SkStringPrintf("<p>gles errors: %d (of %d)</br>\n"
+                                  "vk errors: %d (of %d)</p>\n",
+                                  glesErrorCount, gles, vkErrorCount, vk));
+    htmOut.writeText(kDocTail);
+    SkFILEWStream unitOut(SkOSPath::Join(fReportDirectory.c_str(), kUnitTestReportPath).c_str());
+    SkASSERT_RELEASE(unitOut.isValid());
+    for (const SkQP::UnitTestResult& result : fUnitTestResults) {
+        unitOut.writeText(GetUnitTestName(result.fUnitTest));
+        if (result.fErrors.empty()) {
+            unitOut.writeText(" PASSED\n* * *\n");
+        } else {
+            write(&unitOut, SkStringPrintf(" FAILED (%u errors)\n", result.fErrors.size()));
+            for (const std::string& err : result.fErrors) {
+                write(&unitOut, err);
+                unitOut.newline();
+            }
+            unitOut.writeText("* * *\n");
+        }
+    }
+}
diff --git a/src/third_party/skia/tools/skqp/src/skqp.h b/src/third_party/skia/tools/skqp/src/skqp.h
new file mode 100644
index 0000000..0ff31bb
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/skqp.h
@@ -0,0 +1,122 @@
+/*
+ * 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 skqp_DEFINED
+#define skqp_DEFINED
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <unordered_set>
+#include <unordered_map>
+#include <vector>
+
+class SkData;
+template <typename T> class sk_sp;
+
+namespace skiagm {
+class GM;
+}
+
+namespace skiatest {
+struct Test;
+}
+
+class SkStreamAsset;
+
+////////////////////////////////////////////////////////////////////////////////
+class SkQPAssetManager {
+public:
+    SkQPAssetManager() {}
+    virtual ~SkQPAssetManager() {}
+    virtual sk_sp<SkData> open(const char* path) = 0;
+private:
+    SkQPAssetManager(const SkQPAssetManager&) = delete;
+    SkQPAssetManager& operator=(const SkQPAssetManager&) = delete;
+};
+
+class SkQP {
+public:
+    enum class SkiaBackend {
+        kGL,
+        kGLES,
+        kVulkan,
+    };
+    using GMFactory = std::unique_ptr<skiagm::GM> (*)();
+    using UnitTest = const skiatest::Test*;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    /** These functions provide a descriptive name for the given value.*/
+    static std::string GetGMName(GMFactory);
+    static const char* GetUnitTestName(UnitTest);
+    static const char* GetBackendName(SkiaBackend);
+
+    SkQP();
+    ~SkQP();
+
+    /**
+        Initialize Skia and the SkQP.  Should be executed only once.
+
+        @param assetManager - provides assets for the models.  Does not take ownership.
+        @param reportDirectory - where to write out report.
+    */
+    void init(SkQPAssetManager* assetManager, const char* reportDirectory);
+
+    struct RenderOutcome {
+        // All three values will be 0 if the test passes.
+        int fMaxError = 0;        // maximum error of all pixel.
+        int fBadPixelCount = 0;   // number of pixels with non-zero error.
+        int64_t fTotalError = 0;  // sum of error for all bad pixels.
+    };
+
+    /**
+        @return render outcome and error string.  Only errors running or
+                evaluating the GM will result in a non-empty error string.
+    */
+    std::tuple<RenderOutcome, std::string> evaluateGM(SkiaBackend, GMFactory);
+
+    /** @return a (hopefully empty) list of errors produced by this unit test.  */
+    std::vector<std::string> executeTest(UnitTest);
+
+    /** Call this after running all checks to write a report into the given
+        report directory. */
+    void makeReport();
+
+    /** @return a list of backends that this version of SkQP supports.  */
+    const std::vector<SkiaBackend>& getSupportedBackends() const { return fSupportedBackends; }
+    /** @return a list of all Skia GMs in lexicographic order.  */
+    const std::vector<GMFactory>& getGMs() const { return fGMs; }
+    /** @return a list of all Skia GPU unit tests in lexicographic order.  */
+    const std::vector<UnitTest>& getUnitTests() const { return fUnitTests; }
+    ////////////////////////////////////////////////////////////////////////////
+
+private:
+    struct RenderResult {
+        SkiaBackend fBackend;
+        GMFactory fGM;
+        RenderOutcome fOutcome;
+   };
+    struct UnitTestResult {
+        UnitTest fUnitTest;
+        std::vector<std::string> fErrors;
+    };
+    std::vector<RenderResult> fRenderResults;
+    std::vector<UnitTestResult> fUnitTestResults;
+    std::vector<SkiaBackend> fSupportedBackends;
+    SkQPAssetManager* fAssetManager = nullptr;
+    std::string fReportDirectory;
+    std::vector<UnitTest> fUnitTests;
+    std::vector<GMFactory> fGMs;
+    std::unordered_map<std::string, int64_t> fGMThresholds;
+
+    SkQP(const SkQP&) = delete;
+    SkQP& operator=(const SkQP&) = delete;
+};
+#endif  // skqp_DEFINED
+
diff --git a/src/third_party/skia/tools/skqp/src/skqp_main.cpp b/src/third_party/skia/tools/skqp/src/skqp_main.cpp
new file mode 100644
index 0000000..16369cb
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/skqp_main.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <iostream>
+#include <sys/stat.h>
+
+#include "tools/skqp/src/skqp.h"
+
+#include "include/core/SkData.h"
+#include "src/core/SkOSFile.h"
+#include "tools/Resources.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+class StdAssetManager : public SkQPAssetManager {
+public:
+    StdAssetManager(const char* p) : fPrefix(p) {
+        SkASSERT(!fPrefix.empty());
+        //TODO(halcanary): does this need to be changed if I run SkQP in Windows?
+        fPrefix += "/";
+    }
+    sk_sp<SkData> open(const char* path) override {
+        return SkData::MakeFromFileName((fPrefix + path).c_str());
+    }
+private:
+    std::string fPrefix;
+};
+}
+
+static constexpr char kSkipUsage[] =
+    " TEST_MATCH_RULES:"
+    "    [~][^]substring[$] [...] of name to run.\n"
+    "    Multiple matches may be separated by spaces.\n"
+    "    ~ causes a matching name to always be skipped\n"
+    "    ^ requires the start of the name to match\n"
+    "    $ requires the end of the name to match\n"
+    "    ^ and $ requires an exact match\n"
+    "    If a name does not match any list entry,\n"
+    "    it is skipped unless some list entry starts with ~\n";
+
+static bool should_skip(const char* const* rules, size_t count, const char* name) {
+    size_t testLen = strlen(name);
+    bool anyExclude = count == 0;
+    for (size_t i = 0; i < count; ++i) {
+        const char* matchName = rules[i];
+        size_t matchLen = strlen(matchName);
+        bool matchExclude, matchStart, matchEnd;
+        if ((matchExclude = matchName[0] == '~')) {
+            anyExclude = true;
+            matchName++;
+            matchLen--;
+        }
+        if ((matchStart = matchName[0] == '^')) {
+            matchName++;
+            matchLen--;
+        }
+        if ((matchEnd = matchName[matchLen - 1] == '$')) {
+            matchLen--;
+        }
+        if (matchStart ? (!matchEnd || matchLen == testLen)
+                && strncmp(name, matchName, matchLen) == 0
+                : matchEnd ? matchLen <= testLen
+                && strncmp(name + testLen - matchLen, matchName, matchLen) == 0
+                : strstr(name, matchName) != nullptr) {
+            return matchExclude;
+        }
+    }
+    return !anyExclude;
+}
+
+int main(int argc, char** argv) {
+    if (argc < 3) {
+        std::cerr << "Usage:\n  " << argv[0]
+                  << " ASSET_DIRECTORY_PATH SKQP_REPORT_PATH [TEST_MATCH_RULES]\n"
+                  << kSkipUsage << '\n';
+        return 1;
+    }
+    SetResourcePath((std::string(argv[1]) + "/resources").c_str());
+    if (!sk_mkdir(argv[2])) {
+        std::cerr << "sk_mkdir(" << argv[2] << ") failed.\n";
+        return 2;
+    }
+    StdAssetManager mgr(argv[1]);
+    SkQP skqp;
+    skqp.init(&mgr, argv[2]);
+    int ret = 0;
+
+    const char* const* matchRules = &argv[3];
+    size_t matchRulesCount = (size_t)(argc - 3);
+
+    // Rendering Tests
+    std::ostream& out = std::cout;
+    for (auto backend : skqp.getSupportedBackends()) {
+        auto testPrefix = std::string(SkQP::GetBackendName(backend)) + "_";
+        for (auto gmFactory : skqp.getGMs()) {
+            auto testName = testPrefix + SkQP::GetGMName(gmFactory);
+            if (should_skip(matchRules, matchRulesCount, testName.c_str())) {
+                continue;
+            }
+            out << "Starting: " << testName << std::endl;
+            SkQP::RenderOutcome outcome;
+            std::string except;
+
+            std::tie(outcome, except) = skqp.evaluateGM(backend, gmFactory);
+            if (!except.empty()) {
+                out << "ERROR:    " << testName << " (" << except << ")\n";
+                ret = 1;
+            } else if (outcome.fMaxError != 0) {
+                out << "FAILED:   " << testName << " (" << outcome.fMaxError << ")\n";
+                ret = 1;
+            } else {
+                out << "Passed:   " << testName << "\n";
+            }
+            out.flush();
+        }
+    }
+
+    // Unit Tests
+    for (auto test : skqp.getUnitTests()) {
+        auto testName = std::string("unitTest_") +  SkQP::GetUnitTestName(test);
+        if (should_skip(matchRules, matchRulesCount, testName.c_str())) {
+            continue;
+        }
+        out << "Starting test: " << testName << std::endl;
+        std::vector<std::string> errors = skqp.executeTest(test);
+        if (!errors.empty()) {
+            out << "TEST FAILED (" << errors.size() << "): " << testName << "\n";
+            for (const std::string& error : errors) {
+                out << error << "\n";
+            }
+            ret = 1;
+        } else {
+            out << "Test passed:   " << testName << "\n";
+        }
+        out.flush();
+    }
+    skqp.makeReport();
+
+    return ret;
+}
diff --git a/src/third_party/skia/tools/skqp/src/skqp_model.cpp b/src/third_party/skia/tools/skqp/src/skqp_model.cpp
new file mode 100644
index 0000000..230a14f
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/skqp_model.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "tools/skqp/src/skqp.h"
+#include "tools/skqp/src/skqp_model.h"
+
+#include "include/codec/SkCodec.h"
+#include "include/core/SkBitmap.h"
+#include "include/core/SkStream.h"
+#include "src/utils/SkOSPath.h"
+
+#include <limits.h>
+
+#ifndef SK_SKQP_GLOBAL_ERROR_TOLERANCE
+#define SK_SKQP_GLOBAL_ERROR_TOLERANCE 0
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+static inline uint32_t color(const SkPixmap& pm, SkIPoint p) {
+    return *pm.addr32(p.x(), p.y());
+}
+
+static inline bool inside(SkIPoint point, SkISize dimensions) {
+    return (unsigned)point.x() < (unsigned)dimensions.width() &&
+           (unsigned)point.y() < (unsigned)dimensions.height();
+}
+
+SkQP::RenderOutcome skqp::Check(const SkPixmap& minImg,
+                                const SkPixmap& maxImg,
+                                const SkPixmap& img,
+                                unsigned tolerance,
+                                SkBitmap* errorOut) {
+    SkQP::RenderOutcome result;
+    SkISize dim = img.info().dimensions();
+    SkASSERT(minImg.info().dimensions() == dim);
+    SkASSERT(maxImg.info().dimensions() == dim);
+    static const SkIPoint kNeighborhood[9] = {
+        { 0,  0}, // ordered by closest pixels first.
+        {-1,  0}, { 1,  0}, { 0, -1}, { 0,  1},
+        {-1, -1}, { 1, -1}, {-1,  1}, { 1,  1},
+    };
+    for (int y = 0; y < dim.height(); ++y) {
+        for (int x = 0; x < dim.width(); ++x) {
+            const SkIPoint xy{x, y};
+            const uint32_t c = color(img, xy);
+            int error = INT_MAX;
+            // loop over neighborhood (halo);
+            for (SkIPoint delta : kNeighborhood) {
+                SkIPoint point = xy + delta;
+                if (inside(point, dim)) {  // skip out of pixmap bounds.
+                    int err = 0;
+                    // loop over four color channels.
+                    // Return Manhattan distance in channel-space.
+                    for (int component : {0, 8, 16, 24}) {
+                        uint8_t v    = (c                    >> component) & 0xFF,
+                                vmin = (color(minImg, point) >> component) & 0xFF,
+                                vmax = (color(maxImg, point) >> component) & 0xFF;
+                        err = SkMax32(err, SkMax32((int)v - (int)vmax, (int)vmin - (int)v));
+                    }
+                    error = SkMin32(error, err);
+                }
+            }
+            if (error > (int)tolerance) {
+                ++result.fBadPixelCount;
+                result.fTotalError += error;
+                result.fMaxError = SkMax32(error, result.fMaxError);
+                if (errorOut) {
+                    if (!errorOut->getPixels()) {
+                        errorOut->allocPixels(SkImageInfo::Make(
+                                    dim.width(), dim.height(),
+                                    kBGRA_8888_SkColorType,
+                                    kOpaque_SkAlphaType));
+                        errorOut->eraseColor(SK_ColorWHITE);
+                    }
+                    SkASSERT((unsigned)error < 256);
+                    *(errorOut->getAddr32(x, y)) = SkColorSetARGB(0xFF, (uint8_t)error, 0, 0);
+                }
+            }
+        }
+    }
+    return result;
+}
+
+static SkBitmap decode(sk_sp<SkData> data) {
+    SkBitmap bitmap;
+    if (auto codec = SkCodec::MakeFromData(std::move(data))) {
+        SkISize size = codec->getInfo().dimensions();
+        SkASSERT(!size.isEmpty());
+        SkImageInfo info = SkImageInfo::Make(size, skqp::kColorType, skqp::kAlphaType);
+        bitmap.allocPixels(info);
+        if (SkCodec::kSuccess != codec->getPixels(bitmap.pixmap())) {
+            bitmap.reset();
+        }
+    }
+    return bitmap;
+}
+
+skqp::ModelResult skqp::CheckAgainstModel(const char* name,
+                                          const SkPixmap& pm,
+                                          SkQPAssetManager* mgr) {
+    skqp::ModelResult result;
+    if (pm.colorType() != kColorType || pm.alphaType() != kAlphaType) {
+        result.fErrorString = "Model failed: source image format.";
+        return result;
+    }
+    if (pm.info().isEmpty()) {
+        result.fErrorString = "Model failed: empty source image";
+        return result;
+    }
+    constexpr char PATH_ROOT[] = "gmkb";
+    SkString img_path = SkOSPath::Join(PATH_ROOT, name);
+    SkString max_path = SkOSPath::Join(img_path.c_str(), kMaxPngPath);
+    SkString min_path = SkOSPath::Join(img_path.c_str(), kMinPngPath);
+
+    result.fMaxPng = mgr->open(max_path.c_str());
+    result.fMinPng = mgr->open(min_path.c_str());
+
+    SkBitmap max_image = decode(result.fMaxPng);
+    SkBitmap min_image = decode(result.fMinPng);
+
+    if (max_image.isNull() || min_image.isNull()) {
+        result.fErrorString = "Model missing";
+        return result;
+    }
+    if (max_image.info().dimensions() != min_image.info().dimensions()) {
+        result.fErrorString = "Model has mismatched data.";
+        return result;
+    }
+
+    if (max_image.info().dimensions() != pm.info().dimensions()) {
+        result.fErrorString = "Model data does not match source size.";
+        return result;
+    }
+    result.fOutcome = Check(min_image.pixmap(),
+                            max_image.pixmap(),
+                            pm,
+                            SK_SKQP_GLOBAL_ERROR_TOLERANCE,
+                            &result.fErrors);
+    return result;
+}
diff --git a/src/third_party/skia/tools/skqp/src/skqp_model.h b/src/third_party/skia/tools/skqp/src/skqp_model.h
new file mode 100644
index 0000000..a2feaa0
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/src/skqp_model.h
@@ -0,0 +1,58 @@
+/*
+ * 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 skqp_model_DEFINED
+#define skqp_model_DEFINED
+
+#include <cstdint>
+#include <string>
+
+#include "include/core/SkBitmap.h"
+
+#include "tools/skqp/src/skqp.h"
+
+class SkQPAssetManager;
+class SkStreamAsset;
+
+namespace skqp {
+
+/** Prefered colortype for comparing test outcomes. */
+constexpr SkColorType kColorType = kRGBA_8888_SkColorType;
+
+/** Prefered alphatype for comparing test outcomes. */
+constexpr SkAlphaType kAlphaType = kUnpremul_SkAlphaType;
+
+/** Where to find the maximum and minimum of the model. */
+constexpr char kMaxPngPath[] = "max.png";
+constexpr char kMinPngPath[] = "min.png";
+
+struct ModelResult {
+    SkBitmap fErrors; // Correct pixels are white, failing pixels scale from black
+                      // (1 value off) to red (255 off in some channel).
+    sk_sp<SkData> fMinPng;  // original model data, PNG encoded image.
+    sk_sp<SkData> fMaxPng;  // original model data, PNG encoded image.
+    SkQP::RenderOutcome fOutcome;
+    std::string fErrorString;  // if non-empty, an error occured.
+};
+
+SkQP::RenderOutcome Check(const SkPixmap& minImg,
+                          const SkPixmap& maxImg,
+                          const SkPixmap& img,
+                          unsigned tolerance,
+                          SkBitmap* errorOut);
+
+/** Check if the given test image matches the expected results.
+
+    @param name          the name of the rendering test that produced the image
+    @param image         the image to be tested.  Should be kRGBA_8888_SkColorType
+                         and kUnpremul_SkAlphaType.
+    @param assetManager  provides model data files
+*/
+
+ModelResult CheckAgainstModel(const char* name, const SkPixmap& image,
+                              SkQPAssetManager* assetManager);
+}
+#endif  // skqp_model_DEFINED
diff --git a/src/third_party/skia/tools/skqp/test_apk.sh b/src/third_party/skia/tools/skqp/test_apk.sh
new file mode 100755
index 0000000..adeb8e3
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/test_apk.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+
+# If you have more than one device attached, run `adb devices -l` and then set
+# the ANDROID_SERIAL environment variable to the correct serial number.
+
+APK="$1"
+shift
+
+if ! [ -f "$APK" ]; then
+    cat >&2 <<- EOM
+
+	Usage:
+	  $0 SKQP_APK_FILE_PATH [OPTIONAL_TESTS_TO_RUN...]
+
+	e.g.:
+	  $0 skqp-universal-debug.apk
+	or:
+	  $0 skqp-universal-debug.apk vk_hairmodes gles_gammatext gles_aarectmodes
+
+	EOM
+    exit 1
+fi
+
+if [ "$#" -gt 0 ]; then
+    SKQP_ARGS="-e class org.skia.skqp.SkQPRunner#${1}"
+    shift
+    for arg; do
+        SKQP_ARGS="${SKQP_ARGS},org.skia.skqp.SkQPRunner#${arg}"
+    done
+    export SKQP_ARGS
+fi
+
+TDIR="$(mktemp -d "${TMPDIR:-/tmp}/skqp_report.XXXXXXXXXX")"
+THIS="$(dirname "$0")"
+
+sh "$THIS/run_apk.sh" "$APK" "$TDIR"
+
+"$THIS/../../bin/sysopen" "$TDIR"/skqp_report_*/report.html
diff --git a/src/third_party/skia/tools/skqp/upload_apk b/src/third_party/skia/tools/skqp/upload_apk
new file mode 100755
index 0000000..6eb242b
--- /dev/null
+++ b/src/third_party/skia/tools/skqp/upload_apk
@@ -0,0 +1,13 @@
+#! /bin/sh
+# Copyright 2018 Google LLC.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+if [ -z "$1" ] || [ -z "$2" ]; then
+    echo usage: $0 COMMIT APK_PATH >&2
+    exit 1;
+fi
+NAME="skia-skqp/skqp-universal-$(git rev-parse "$1" | cut -b 1-16).apk"
+gsutil cp "$2" "gs://$NAME"
+echo "https://storage.googleapis.com/$NAME"
+python tools/skqp/make_apk_list.py
+
diff --git a/src/third_party/skia/tools/skui/InputState.h b/src/third_party/skia/tools/skui/InputState.h
new file mode 100644
index 0000000..90d5c6c
--- /dev/null
+++ b/src/third_party/skia/tools/skui/InputState.h
@@ -0,0 +1,14 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#ifndef skui_inputstate_DEFINED
+#define skui_inputstate_DEFINED
+namespace skui {
+enum class InputState {
+    kDown,
+    kUp,
+    kMove,   // only valid for mouse
+    kRight,  // only valid for fling
+    kLeft,   // only valid for fling
+};
+}
+#endif  // skui_inputstate_DEFINED
diff --git a/src/third_party/skia/tools/skui/Key.h b/src/third_party/skia/tools/skui/Key.h
new file mode 100644
index 0000000..d8d2cf7
--- /dev/null
+++ b/src/third_party/skia/tools/skui/Key.h
@@ -0,0 +1,59 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#ifndef skui_key_DEFINED
+#define skui_key_DEFINED
+namespace skui {
+enum class Key {
+    kNONE,    //corresponds to android's UNKNOWN
+
+    kLeftSoftKey,
+    kRightSoftKey,
+
+    kHome,    //!< the home key - added to match android
+    kBack,    //!< (CLR)
+    kSend,    //!< the green (talk) key
+    kEnd,     //!< the red key
+
+    k0,
+    k1,
+    k2,
+    k3,
+    k4,
+    k5,
+    k6,
+    k7,
+    k8,
+    k9,
+    kStar,    //!< the * key
+    kHash,    //!< the # key
+
+    kUp,
+    kDown,
+    kLeft,
+    kRight,
+
+    // Keys needed by ImGui
+    kTab,
+    kPageUp,
+    kPageDown,
+    kDelete,
+    kEscape,
+    kShift,
+    kCtrl,
+    kOption, // AKA Alt
+    kA,
+    kC,
+    kV,
+    kX,
+    kY,
+    kZ,
+
+    kOK,      //!< the center key
+
+    kVolUp,   //!< volume up    - match android
+    kVolDown, //!< volume down  - same
+    kPower,   //!< power button - same
+    kCamera,  //!< camera       - same
+};
+}
+#endif  // skui_key_DEFINED
diff --git a/src/third_party/skia/tools/skui/ModifierKey.h b/src/third_party/skia/tools/skui/ModifierKey.h
new file mode 100644
index 0000000..09c5536
--- /dev/null
+++ b/src/third_party/skia/tools/skui/ModifierKey.h
@@ -0,0 +1,22 @@
+// Copyright 2019 Google LLC.
+// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
+#ifndef skui_modifierkey_defined
+#define skui_modifierkey_defined
+
+#include "include/private/SkBitmaskEnum.h"
+
+namespace skui {
+enum class ModifierKey {
+    kNone       = 0,
+    kShift      = 1 << 0,
+    kControl    = 1 << 1,
+    kOption     = 1 << 2,   // same as ALT
+    kCommand    = 1 << 3,
+    kFirstPress = 1 << 4,
+};
+}
+
+namespace skstd {
+template <> struct is_bitmask_enum<skui::ModifierKey> : std::true_type {};
+}
+#endif  // skui_modifierkey_defined
diff --git a/src/third_party/skia/tools/svg/README.md b/src/third_party/skia/tools/svg/README.md
index 501f3c6..a3718c2 100644
--- a/src/third_party/skia/tools/svg/README.md
+++ b/src/third_party/skia/tools/svg/README.md
@@ -7,13 +7,19 @@
 svgs.txt
 --------
 This text file contains an SVG URL per line.
-The SVGs in this file have been downloaded from the internal doc here:
-https://docs.google.com/document/d/1kYRvUxZTnm1tI_0bTU0BX9jqSSTqPUhGXJVcD3Rcg2c/edit
+It is a list of the SVG files used to test rendering correctness.
 
+svgs_parse_only.txt
+-------------------
+This text file contains an SVG URL per line.
+It is a list of the SVG files used to exercise the SVG parsing code.
 
 svg_downloader.py
 -----------------
-This python script parses svgs.txt and downloads SVGs into a specified directory.
+This python script parses txt files and downloads SVGs into a specified directory.
 
 The script can be run by hand:
 $ python svg_downloader.py --output_dir /tmp/svgs/
+OR
+$ python svg_downloader.py --output_dir /tmp/svgs/ --svgs_file svgs_parse_only.txt --prefix svgparse_
+
diff --git a/src/third_party/skia/tools/svg/svg_downloader.py b/src/third_party/skia/tools/svg/svg_downloader.py
index 94a0b6f..769c8ff 100644
--- a/src/third_party/skia/tools/svg/svg_downloader.py
+++ b/src/third_party/skia/tools/svg/svg_downloader.py
@@ -15,11 +15,11 @@
 PARENT_DIR = os.path.dirname(os.path.realpath(__file__))
 
 
-def downloadSVGs(svgs_file, output_dir):
+def downloadSVGs(svgs_file, output_dir, prefix):
   with open(svgs_file, 'r') as f:
     for url in f.xreadlines():
       svg_url = url.strip()
-      dest_file = os.path.join(output_dir, os.path.basename(svg_url))
+      dest_file = os.path.join(output_dir, prefix + os.path.basename(svg_url))
       print 'Downloading %s' % svg_url
       urllib.urlretrieve(svg_url, dest_file)
 
@@ -34,8 +34,12 @@
   option_parser.add_option(
       '-o', '--output_dir',
       help='The output dir where downloaded SVGs will be stored in.')
+  option_parser.add_option(
+      '-p', '--prefix',
+      help='The prefix which downloaded SVG file will begin with.',
+      default='')
   options, unused_args = option_parser.parse_args()
 
   if not options.output_dir:
     raise Exception('Must specify --output_dir')
-  sys.exit(downloadSVGs(options.svgs_file, options.output_dir))
+  sys.exit(downloadSVGs(options.svgs_file, options.output_dir, options.prefix))
diff --git a/src/third_party/skia/tools/svg/svgs.txt b/src/third_party/skia/tools/svg/svgs.txt
index 0ffc80a..1fff186 100644
--- a/src/third_party/skia/tools/svg/svgs.txt
+++ b/src/third_party/skia/tools/svg/svgs.txt
@@ -1,68 +1,10 @@
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/AJ_Digital_Camera.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/acid.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/alphachannel.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/bozo.svg
+https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/rg1024_green_grapes.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/gallardo.svg
 https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/cartman.svg
 https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/bzrfeed.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/compass.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/displayWebStats.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/eff.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/fsm.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/gallardo.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/rg1024_green_grapes.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/usaf.svg
-https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/yinyang.svg
-https://upload.wikimedia.org/wikipedia/commons/6/6d/Alabama-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/2/2b/Alaska-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/7/7e/Arizona-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/0/0f/Seal_of_California.svg
-https://upload.wikimedia.org/wikipedia/commons/5/51/Colorado-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e5/Connecticut-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/c/c0/Delaware-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/b/bf/Florida-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e0/Georgia-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/c/c5/Hawaii-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/4/49/Idaho-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e7/Seal_of_Illinois.svg
-https://upload.wikimedia.org/wikipedia/commons/c/c4/Indiana-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/5/5a/Iowa-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/4/45/Seal_of_Kansas.svg
-https://upload.wikimedia.org/wikipedia/commons/3/35/Seal_of_Kentucky.svg
-https://upload.wikimedia.org/wikipedia/commons/2/2f/Seal_of_Louisiana.svg
-https://upload.wikimedia.org/wikipedia/commons/a/a0/Maine-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/0/00/Seal_of_Maryland_%28reverse%29.svg
-https://upload.wikimedia.org/wikipedia/commons/8/82/Seal_of_Massachusetts.svg
-https://upload.wikimedia.org/wikipedia/commons/3/3f/Seal_of_Michigan.svg
-https://upload.wikimedia.org/wikipedia/commons/6/63/Minnesota-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e3/Seal_of_Mississippi_(2014).svg
-https://upload.wikimedia.org/wikipedia/commons/d/de/Seal_of_Missouri.svg
-https://upload.wikimedia.org/wikipedia/commons/e/ed/Montana-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/6/60/Nebraska-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/7/77/Nevada-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/a/aa/Seal_of_New_Hampshire.svg
-https://upload.wikimedia.org/wikipedia/commons/8/8d/Seal_of_New_Jersey.svg
-https://upload.wikimedia.org/wikipedia/commons/3/3b/NewMexico-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/c/ca/NewYork-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/7/72/Seal_of_North_Carolina.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e7/NorthDakota-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/6/69/Seal_of_Ohio_%281967-1996%29.svg
-https://upload.wikimedia.org/wikipedia/commons/3/39/Seal_of_Oklahoma.svg
-https://upload.wikimedia.org/wikipedia/commons/c/c9/Oregon-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/e/e8/Pennsylvania_state_seal.svg
-https://upload.wikimedia.org/wikipedia/commons/7/73/RhodeIsland-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/8/80/Seal_of_South_Carolina.svg
-https://upload.wikimedia.org/wikipedia/commons/b/bb/SouthDakota-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/3/3c/Seal_of_Tennessee.svg
-https://upload.wikimedia.org/wikipedia/commons/c/cb/Seal_of_Texas.svg
-https://upload.wikimedia.org/wikipedia/commons/7/72/Seal_of_Utah_%28Alternate%29.svg
-https://upload.wikimedia.org/wikipedia/commons/5/5b/Vermont_state_seal.svg
-https://upload.wikimedia.org/wikipedia/commons/6/6f/Seal_of_Virginia.svg
-https://upload.wikimedia.org/wikipedia/commons/9/92/Washington-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/9/92/WestVirginia-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/b/b3/Wisconsin-StateSeal.svg
-https://upload.wikimedia.org/wikipedia/commons/c/c0/Wyoming-StateSeal.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg
 https://upload.wikimedia.org/wikipedia/commons/d/df/Seal_of_American_Samoa.svg
-https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg
-https://upload.wikimedia.org/wikipedia/commons/6/6c/Trajans-Column-lower-animated.svg
+https://upload.wikimedia.org/wikipedia/commons/e/e7/Seal_of_Illinois.svg
+https://upload.wikimedia.org/wikipedia/commons/6/63/A_large_blank_world_map_with_oceans_marked_in_blue.svg
diff --git a/src/third_party/skia/tools/svg/svgs_parse_only.txt b/src/third_party/skia/tools/svg/svgs_parse_only.txt
new file mode 100644
index 0000000..4aab1cb
--- /dev/null
+++ b/src/third_party/skia/tools/svg/svgs_parse_only.txt
@@ -0,0 +1,59 @@
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/AJ_Digital_Camera.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/acid.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/alphachannel.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/bozo.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/compass.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/displayWebStats.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/eff.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/fsm.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/usaf.svg
+https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/yinyang.svg
+https://upload.wikimedia.org/wikipedia/commons/6/6d/Alabama-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/2/2b/Alaska-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/7/7e/Arizona-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/0/0f/Seal_of_California.svg
+https://upload.wikimedia.org/wikipedia/commons/5/51/Colorado-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/e/e5/Connecticut-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/c/c0/Delaware-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/b/bf/Florida-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/e/e0/Georgia-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/c/c5/Hawaii-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/4/49/Idaho-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/c/c4/Indiana-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/5/5a/Iowa-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/4/45/Seal_of_Kansas.svg
+https://upload.wikimedia.org/wikipedia/commons/3/35/Seal_of_Kentucky.svg
+https://upload.wikimedia.org/wikipedia/commons/2/2f/Seal_of_Louisiana.svg
+https://upload.wikimedia.org/wikipedia/commons/a/a0/Maine-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/0/00/Seal_of_Maryland_%28reverse%29.svg
+https://upload.wikimedia.org/wikipedia/commons/8/82/Seal_of_Massachusetts.svg
+https://upload.wikimedia.org/wikipedia/commons/3/3f/Seal_of_Michigan.svg
+https://upload.wikimedia.org/wikipedia/commons/6/63/Minnesota-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/d/d1/Seal_of_Mississippi_%282014-present%29.svg
+https://upload.wikimedia.org/wikipedia/commons/d/de/Seal_of_Missouri.svg
+https://upload.wikimedia.org/wikipedia/commons/e/ed/Montana-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/6/60/Nebraska-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/7/77/Nevada-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/a/aa/Seal_of_New_Hampshire.svg
+https://upload.wikimedia.org/wikipedia/commons/8/8d/Seal_of_New_Jersey.svg
+https://upload.wikimedia.org/wikipedia/commons/3/3b/NewMexico-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/c/ca/NewYork-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/7/72/Seal_of_North_Carolina.svg
+https://upload.wikimedia.org/wikipedia/commons/e/e7/NorthDakota-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/6/69/Seal_of_Ohio_%281967-1996%29.svg
+https://upload.wikimedia.org/wikipedia/commons/3/39/Seal_of_Oklahoma.svg
+https://upload.wikimedia.org/wikipedia/commons/c/c9/Oregon-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/e/e8/Pennsylvania_state_seal.svg
+https://upload.wikimedia.org/wikipedia/commons/7/73/RhodeIsland-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/8/80/Seal_of_South_Carolina.svg
+https://upload.wikimedia.org/wikipedia/commons/b/bb/SouthDakota-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/3/3c/Seal_of_Tennessee.svg
+https://upload.wikimedia.org/wikipedia/commons/c/cb/Seal_of_Texas.svg
+https://upload.wikimedia.org/wikipedia/commons/7/72/Seal_of_Utah_%28Alternate%29.svg
+https://upload.wikimedia.org/wikipedia/commons/5/5b/Vermont_state_seal.svg
+https://upload.wikimedia.org/wikipedia/commons/6/6f/Seal_of_Virginia.svg
+https://upload.wikimedia.org/wikipedia/commons/9/92/Washington-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/9/92/WestVirginia-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/b/b3/Wisconsin-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/c/c0/Wyoming-StateSeal.svg
+https://upload.wikimedia.org/wikipedia/commons/6/6c/Trajans-Column-lower-animated.svg
diff --git a/src/third_party/skia/tools/test_font_data.cpp b/src/third_party/skia/tools/test_font_data.cpp
deleted file mode 100644
index ff0aacc..0000000
--- a/src/third_party/skia/tools/test_font_data.cpp
+++ /dev/null
@@ -1,8622 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Auto-generated by create_test_font.cpp
-
-const SkScalar CourierNewkNormalPoints[] = {
-0.339355f, -0.571289f, 0.320801f, -0.240234f, 0.319824f, -0.224609f, 0.314209f, -0.218262f,
-0.308594f, -0.211914f, 0.300293f, -0.211914f, 0.291504f, -0.211914f, 0.285889f, -0.218262f,
-0.280273f, -0.224609f, 0.279297f, -0.240234f, 0.26123f, -0.571289f, 0.260254f, -0.583008f,
-0.260254f, -0.588379f, 0.260254f, -0.60498f, 0.271729f, -0.616211f, 0.283203f, -0.627441f,
-0.300293f, -0.627441f, 0.317383f, -0.627441f, 0.328613f, -0.616211f, 0.339844f, -0.60498f,
-0.339844f, -0.587891f, 0.339844f, -0.583008f, 0.339355f, -0.571289f, 0.290527f, -0.0869141f,
-0.30957f, -0.0869141f, 0.330566f, -0.0869141f, 0.345459f, -0.0720215f, 0.360352f,
--0.0571289f, 0.360352f, -0.0361328f, 0.360352f, -0.0146484f, 0.345215f, 0, 0.330078f,
-0.0146484f, 0.30957f, 0.0146484f, 0.290527f, 0.0146484f, 0.269531f, 0.0146484f, 0.254639f,
--0.000244141f, 0.239746f, -0.0151367f, 0.239746f, -0.0356445f, 0.239746f, -0.0576172f,
-0.254883f, -0.0722656f, 0.27002f, -0.0869141f, 0.290527f, -0.0869141f, 0.484375f,
--0.642578f, 0.154297f, 0.0644531f, 0.145996f, 0.0825195f, 0.132812f, 0.0825195f,
-0.124512f, 0.0825195f, 0.118408f, 0.076416f, 0.112305f, 0.0703125f, 0.112305f, 0.0629883f,
-0.112305f, 0.0571289f, 0.117188f, 0.046875f, 0.446777f, -0.660156f, 0.452148f, -0.671387f,
-0.457031f, -0.674805f, 0.461914f, -0.678223f, 0.46875f, -0.678223f, 0.477051f, -0.678223f,
-0.483154f, -0.672119f, 0.489258f, -0.666016f, 0.489258f, -0.658691f, 0.489258f, -0.65332f,
-0.484375f, -0.642578f, 0.0478516f, -0.284668f, 0.491211f, -0.531738f, 0.501953f,
--0.537598f, 0.507324f, -0.537598f, 0.515625f, -0.537598f, 0.521729f, -0.531494f,
-0.527832f, -0.525391f, 0.527832f, -0.51709f, 0.527832f, -0.504883f, 0.51123f, -0.495605f,
-0.131348f, -0.284668f, 0.510742f, -0.0737305f, 0.527344f, -0.0644531f, 0.527344f,
--0.0522461f, 0.527344f, -0.0439453f, 0.52124f, -0.0378418f, 0.515137f, -0.0317383f,
-0.506836f, -0.0317383f, 0.501465f, -0.0317383f, 0.490723f, -0.0375977f, 0.552246f,
--0.284668f, 0.108887f, -0.0375977f, 0.0981445f, -0.0317383f, 0.0927734f, -0.0317383f,
-0.0844727f, -0.0317383f, 0.0783691f, -0.0378418f, 0.0722656f, -0.0439453f, 0.0722656f,
--0.0522461f, 0.0722656f, -0.0644531f, 0.0888672f, -0.0737305f, 0.46875f, -0.284668f,
-0.0893555f, -0.495605f, 0.0727539f, -0.504883f, 0.0727539f, -0.51709f, 0.0727539f,
--0.525391f, 0.0788574f, -0.531494f, 0.0849609f, -0.537598f, 0.0932617f, -0.537598f,
-0.0986328f, -0.537598f, 0.109375f, -0.531738f, 0.435059f, -0.190918f, 0.165527f,
--0.190918f, 0.110352f, -0.0410156f, 0.188965f, -0.0410156f, 0.203613f, -0.0410156f,
-0.209961f, -0.0354004f, 0.216309f, -0.0297852f, 0.216309f, -0.0205078f, 0.216309f,
--0.0117188f, 0.209961f, -0.00585938f, 0.203613f, 0, 0.188965f, 0, 0.0356445f, 0,
-0.0209961f, 0, 0.0146484f, -0.00585938f, 0.00830078f, -0.0117188f, 0.00830078f, -0.0205078f,
-0.00830078f, -0.0297852f, 0.0146484f, -0.0354004f, 0.0209961f, -0.0410156f, 0.0356445f,
--0.0410156f, 0.0673828f, -0.0410156f, 0.248535f, -0.530273f, 0.127441f, -0.530273f,
-0.112793f, -0.530273f, 0.106445f, -0.535889f, 0.100098f, -0.541504f, 0.100098f, -0.550781f,
-0.100098f, -0.560059f, 0.106445f, -0.565674f, 0.112793f, -0.571289f, 0.127441f, -0.571289f,
-0.333984f, -0.571289f, 0.53418f, -0.0410156f, 0.565918f, -0.0410156f, 0.580566f,
--0.0410156f, 0.586914f, -0.0354004f, 0.593262f, -0.0297852f, 0.593262f, -0.0205078f,
-0.593262f, -0.0117188f, 0.586914f, -0.00585938f, 0.580566f, 0, 0.565918f, 0, 0.413086f,
-0, 0.397949f, 0, 0.391602f, -0.00585938f, 0.385254f, -0.0117188f, 0.385254f, -0.0205078f,
-0.385254f, -0.0297852f, 0.391602f, -0.0354004f, 0.397949f, -0.0410156f, 0.413086f,
--0.0410156f, 0.491211f, -0.0410156f, 0.419434f, -0.231934f, 0.306152f, -0.530273f,
-0.291016f, -0.530273f, 0.181152f, -0.231934f, 0.480469f, -0.515137f, 0.480469f, -0.543945f,
-0.480469f, -0.558594f, 0.486084f, -0.564941f, 0.491699f, -0.571289f, 0.500977f, -0.571289f,
-0.510254f, -0.571289f, 0.515869f, -0.564941f, 0.521484f, -0.558594f, 0.521484f, -0.543945f,
-0.521484f, -0.430176f, 0.521484f, -0.415039f, 0.515869f, -0.408691f, 0.510254f, -0.402344f,
-0.500977f, -0.402344f, 0.492676f, -0.402344f, 0.487061f, -0.408203f, 0.481445f, -0.414062f,
-0.480469f, -0.427246f, 0.478027f, -0.468262f, 0.436035f, -0.5f, 0.379395f, -0.543457f,
-0.307129f, -0.543457f, 0.259766f, -0.543457f, 0.217773f, -0.522461f, 0.186523f, -0.507324f,
-0.167969f, -0.485352f, 0.135742f, -0.447266f, 0.116699f, -0.400879f, 0.103027f, -0.366699f,
-0.103027f, -0.32373f, 0.103027f, -0.251953f, 0.103027f, -0.160156f, 0.169434f, -0.0925293f,
-0.23584f, -0.0249023f, 0.32373f, -0.0249023f, 0.376465f, -0.0249023f, 0.418213f,
--0.0478516f, 0.459961f, -0.0708008f, 0.499023f, -0.117188f, 0.507324f, -0.127441f,
-0.517578f, -0.127441f, 0.526367f, -0.127441f, 0.531738f, -0.12207f, 0.537109f, -0.116699f,
-0.537109f, -0.108398f, 0.537109f, -0.097168f, 0.516113f, -0.0742188f, 0.476074f,
--0.0292969f, 0.426025f, -0.0065918f, 0.375977f, 0.0161133f, 0.324707f, 0.0161133f,
-0.280273f, 0.0161133f, 0.234375f, -0.000976562f, 0.199219f, -0.0141602f, 0.17627f,
--0.0317383f, 0.15332f, -0.0493164f, 0.119873f, -0.0910645f, 0.0864258f, -0.132812f,
-0.0742188f, -0.168213f, 0.0620117f, -0.203613f, 0.0620117f, -0.246094f, 0.0620117f,
--0.32959f, 0.0620117f, -0.390137f, 0.0944824f, -0.453369f, 0.126953f, -0.516602f,
-0.18335f, -0.550537f, 0.239746f, -0.584473f, 0.305664f, -0.584473f, 0.407227f, -0.584473f,
-0.480469f, -0.515137f, 0.438965f, -0.276367f, 0.166992f, -0.276367f, 0.166992f, -0.0410156f,
-0.222168f, -0.0410156f, 0.236816f, -0.0410156f, 0.243164f, -0.0354004f, 0.249512f,
--0.0297852f, 0.249512f, -0.0205078f, 0.249512f, -0.0117188f, 0.243164f, -0.00585938f,
-0.236816f, 0, 0.222168f, 0, 0.0795898f, 0, 0.0649414f, 0, 0.0585938f, -0.00585938f,
-0.0522461f, -0.0117188f, 0.0522461f, -0.0205078f, 0.0522461f, -0.0297852f, 0.0585938f,
--0.0354004f, 0.0649414f, -0.0410156f, 0.0795898f, -0.0410156f, 0.125977f, -0.0410156f,
-0.125977f, -0.530273f, 0.100586f, -0.530273f, 0.0854492f, -0.530273f, 0.0791016f,
--0.535889f, 0.0727539f, -0.541504f, 0.0727539f, -0.550781f, 0.0727539f, -0.560059f,
-0.0791016f, -0.565674f, 0.0854492f, -0.571289f, 0.100586f, -0.571289f, 0.222168f,
--0.571289f, 0.236816f, -0.571289f, 0.243164f, -0.565674f, 0.249512f, -0.560059f,
-0.249512f, -0.550781f, 0.249512f, -0.541504f, 0.243164f, -0.535889f, 0.236816f, -0.530273f,
-0.222168f, -0.530273f, 0.166992f, -0.530273f, 0.166992f, -0.317383f, 0.438965f, -0.317383f,
-0.438965f, -0.530273f, 0.384277f, -0.530273f, 0.369629f, -0.530273f, 0.363281f, -0.535889f,
-0.356934f, -0.541504f, 0.356934f, -0.550781f, 0.356934f, -0.560059f, 0.363037f, -0.565674f,
-0.369141f, -0.571289f, 0.384277f, -0.571289f, 0.505859f, -0.571289f, 0.520996f, -0.571289f,
-0.527344f, -0.565674f, 0.533691f, -0.560059f, 0.533691f, -0.550781f, 0.533691f, -0.541504f,
-0.527344f, -0.535889f, 0.520996f, -0.530273f, 0.505859f, -0.530273f, 0.480469f, -0.530273f,
-0.480469f, -0.0410156f, 0.526855f, -0.0410156f, 0.541504f, -0.0410156f, 0.547852f,
--0.0354004f, 0.554199f, -0.0297852f, 0.554199f, -0.0205078f, 0.554199f, -0.0117188f,
-0.547852f, -0.00585938f, 0.541504f, 0, 0.526855f, 0, 0.384277f, 0, 0.369629f, 0,
-0.363281f, -0.00585938f, 0.356934f, -0.0117188f, 0.356934f, -0.0205078f, 0.356934f,
--0.0297852f, 0.363037f, -0.0354004f, 0.369141f, -0.0410156f, 0.384277f, -0.0410156f,
-0.438965f, -0.0410156f, 0.327148f, -0.171387f, 0.280273f, -0.171387f, 0.122559f,
--0.530273f, 0.114746f, -0.530273f, 0.114746f, -0.0410156f, 0.19043f, -0.0410156f,
-0.205078f, -0.0410156f, 0.211426f, -0.0354004f, 0.217773f, -0.0297852f, 0.217773f,
--0.0205078f, 0.217773f, -0.0117188f, 0.211426f, -0.00585938f, 0.205078f, 0, 0.19043f,
-0, 0.0390625f, 0, 0.0244141f, 0, 0.0180664f, -0.00585938f, 0.0117188f, -0.0117188f,
-0.0117188f, -0.0205078f, 0.0117188f, -0.0297852f, 0.0180664f, -0.0354004f, 0.0244141f,
--0.0410156f, 0.0390625f, -0.0410156f, 0.0737305f, -0.0410156f, 0.0737305f, -0.530273f,
-0.0478516f, -0.530273f, 0.0332031f, -0.530273f, 0.0268555f, -0.535889f, 0.0205078f,
--0.541504f, 0.0205078f, -0.550781f, 0.0205078f, -0.560059f, 0.0268555f, -0.565674f,
-0.0332031f, -0.571289f, 0.0478516f, -0.571289f, 0.148438f, -0.571289f, 0.303711f,
--0.217773f, 0.456543f, -0.571289f, 0.557129f, -0.571289f, 0.572266f, -0.571289f,
-0.578613f, -0.565674f, 0.584961f, -0.560059f, 0.584961f, -0.550781f, 0.584961f, -0.541504f,
-0.578613f, -0.535889f, 0.572266f, -0.530273f, 0.557129f, -0.530273f, 0.531738f, -0.530273f,
-0.531738f, -0.0410156f, 0.565918f, -0.0410156f, 0.581055f, -0.0410156f, 0.587402f,
--0.0354004f, 0.59375f, -0.0297852f, 0.59375f, -0.0205078f, 0.59375f, -0.0117188f,
-0.587402f, -0.00585938f, 0.581055f, 0, 0.565918f, 0, 0.415039f, 0, 0.400391f, 0,
-0.393799f, -0.00585938f, 0.387207f, -0.0117188f, 0.387207f, -0.0205078f, 0.387207f,
--0.0297852f, 0.393555f, -0.0354004f, 0.399902f, -0.0410156f, 0.415039f, -0.0410156f,
-0.490723f, -0.0410156f, 0.490723f, -0.530273f, 0.481934f, -0.530273f, 0.320312f,
--0.530273f, 0.320312f, -0.0410156f, 0.426758f, -0.0410156f, 0.441406f, -0.0410156f,
-0.447754f, -0.0354004f, 0.454102f, -0.0297852f, 0.454102f, -0.0205078f, 0.454102f,
--0.0117188f, 0.447754f, -0.00585938f, 0.441406f, 0, 0.426758f, 0, 0.172363f, 0, 0.157715f,
-0, 0.151367f, -0.00585938f, 0.14502f, -0.0117188f, 0.14502f, -0.0205078f, 0.14502f,
--0.0297852f, 0.151367f, -0.0354004f, 0.157715f, -0.0410156f, 0.172363f, -0.0410156f,
-0.278809f, -0.0410156f, 0.278809f, -0.530273f, 0.11084f, -0.530273f, 0.11084f, -0.388184f,
-0.11084f, -0.373047f, 0.105225f, -0.366699f, 0.0996094f, -0.360352f, 0.090332f, -0.360352f,
-0.081543f, -0.360352f, 0.0756836f, -0.366699f, 0.0698242f, -0.373047f, 0.0698242f,
--0.388184f, 0.0698242f, -0.571289f, 0.529297f, -0.571289f, 0.529297f, -0.388184f,
-0.529297f, -0.373047f, 0.523682f, -0.366699f, 0.518066f, -0.360352f, 0.508789f, -0.360352f,
-0.499512f, -0.360352f, 0.493896f, -0.366699f, 0.488281f, -0.373047f, 0.488281f, -0.388184f,
-0.488281f, -0.530273f, 0.47998f, 0, 0.415527f, 0, 0.299316f, -0.405762f, 0.185547f,
-0, 0.121094f, 0, 0.0605469f, -0.530273f, 0.0454102f, -0.530273f, 0.0307617f, -0.530273f,
-0.0244141f, -0.535889f, 0.0180664f, -0.541504f, 0.0180664f, -0.550781f, 0.0180664f,
--0.560059f, 0.0244141f, -0.565674f, 0.0307617f, -0.571289f, 0.0454102f, -0.571289f,
-0.197754f, -0.571289f, 0.212891f, -0.571289f, 0.219238f, -0.565674f, 0.225586f, -0.560059f,
-0.225586f, -0.550781f, 0.225586f, -0.541504f, 0.219238f, -0.535889f, 0.212891f, -0.530273f,
-0.197754f, -0.530273f, 0.102051f, -0.530273f, 0.15625f, -0.046875f, 0.26709f, -0.444824f,
-0.330078f, -0.444824f, 0.443848f, -0.046875f, 0.49707f, -0.530273f, 0.400879f, -0.530273f,
-0.38623f, -0.530273f, 0.379883f, -0.535889f, 0.373535f, -0.541504f, 0.373535f, -0.550781f,
-0.373535f, -0.560059f, 0.379883f, -0.565674f, 0.38623f, -0.571289f, 0.400879f, -0.571289f,
-0.552246f, -0.571289f, 0.567383f, -0.571289f, 0.57373f, -0.565674f, 0.580078f, -0.560059f,
-0.580078f, -0.550781f, 0.580078f, -0.541504f, 0.57373f, -0.535889f, 0.567383f, -0.530273f,
-0.552246f, -0.530273f, 0.537109f, -0.530273f, 0.321777f, -0.257812f, 0.321777f, -0.0410156f,
-0.428223f, -0.0410156f, 0.442871f, -0.0410156f, 0.449219f, -0.0354004f, 0.455566f,
--0.0297852f, 0.455566f, -0.0205078f, 0.455566f, -0.0117188f, 0.449219f, -0.00585938f,
-0.442871f, 0, 0.428223f, 0, 0.173828f, 0, 0.15918f, 0, 0.152832f, -0.00585938f, 0.146484f,
--0.0117188f, 0.146484f, -0.0205078f, 0.146484f, -0.0297852f, 0.152588f, -0.0354004f,
-0.158691f, -0.0410156f, 0.173828f, -0.0410156f, 0.280273f, -0.0410156f, 0.280273f,
--0.257812f, 0.100098f, -0.530273f, 0.0756836f, -0.530273f, 0.0610352f, -0.530273f,
-0.0546875f, -0.535889f, 0.0483398f, -0.541504f, 0.0483398f, -0.550781f, 0.0483398f,
--0.560059f, 0.0546875f, -0.565674f, 0.0610352f, -0.571289f, 0.0756836f, -0.571289f,
-0.188477f, -0.571289f, 0.203125f, -0.571289f, 0.209473f, -0.565674f, 0.21582f, -0.560059f,
-0.21582f, -0.550781f, 0.21582f, -0.541504f, 0.209473f, -0.535889f, 0.203125f, -0.530273f,
-0.188477f, -0.530273f, 0.147949f, -0.530273f, 0.30127f, -0.299316f, 0.451172f, -0.530273f,
-0.411133f, -0.530273f, 0.395996f, -0.530273f, 0.389648f, -0.535889f, 0.383301f, -0.541504f,
-0.383301f, -0.550781f, 0.383301f, -0.560059f, 0.389648f, -0.565674f, 0.395996f, -0.571289f,
-0.411133f, -0.571289f, 0.523438f, -0.571289f, 0.538086f, -0.571289f, 0.544434f, -0.565674f,
-0.550781f, -0.560059f, 0.550781f, -0.550781f, 0.550781f, -0.541504f, 0.544434f, -0.535889f,
-0.538086f, -0.530273f, 0.523438f, -0.530273f, 0.499023f, -0.530273f, 0.417969f, 0,
-0.417969f, -0.059082f, 0.328613f, 0.0161133f, 0.227051f, 0.0161133f, 0.15332f, 0.0161133f,
-0.111816f, -0.0212402f, 0.0703125f, -0.0585938f, 0.0703125f, -0.112793f, 0.0703125f,
--0.172363f, 0.125f, -0.216797f, 0.179688f, -0.26123f, 0.284668f, -0.26123f, 0.312988f,
--0.26123f, 0.346191f, -0.257568f, 0.379395f, -0.253906f, 0.417969f, -0.246094f, 0.417969f,
--0.3125f, 0.417969f, -0.346191f, 0.386719f, -0.371094f, 0.355469f, -0.395996f, 0.292969f,
--0.395996f, 0.245117f, -0.395996f, 0.158691f, -0.368164f, 0.143066f, -0.363281f,
-0.138672f, -0.363281f, 0.130859f, -0.363281f, 0.125244f, -0.369141f, 0.119629f, -0.375f,
-0.119629f, -0.383789f, 0.119629f, -0.39209f, 0.124512f, -0.396973f, 0.131348f, -0.404297f,
-0.179688f, -0.416992f, 0.255859f, -0.4375f, 0.294922f, -0.4375f, 0.372559f, -0.4375f,
-0.416016f, -0.39917f, 0.459473f, -0.36084f, 0.459473f, -0.3125f, 0.459473f, -0.0410156f,
-0.51416f, -0.0410156f, 0.529297f, -0.0410156f, 0.535645f, -0.0354004f, 0.541992f,
--0.0297852f, 0.541992f, -0.0205078f, 0.541992f, -0.0117188f, 0.535645f, -0.00585938f,
-0.529297f, 0, 0.51416f, 0, 0.417969f, -0.204102f, 0.38916f, -0.212402f, 0.356934f,
--0.216309f, 0.324707f, -0.220215f, 0.289062f, -0.220215f, 0.199707f, -0.220215f,
-0.149414f, -0.181641f, 0.111328f, -0.152832f, 0.111328f, -0.112793f, 0.111328f, -0.0756836f,
-0.140381f, -0.050293f, 0.169434f, -0.0249023f, 0.225098f, -0.0249023f, 0.27832f,
--0.0249023f, 0.323975f, -0.0461426f, 0.369629f, -0.0673828f, 0.417969f, -0.11377f,
-0.145508f, -0.612793f, 0.145508f, -0.34082f, 0.219727f, -0.4375f, 0.324707f, -0.4375f,
-0.414551f, -0.4375f, 0.478516f, -0.372314f, 0.54248f, -0.307129f, 0.54248f, -0.212402f,
-0.54248f, -0.116699f, 0.477783f, -0.050293f, 0.413086f, 0.0161133f, 0.324707f, 0.0161133f,
-0.217285f, 0.0161133f, 0.145508f, -0.0805664f, 0.145508f, 0, 0.0493164f, 0, 0.034668f,
-0, 0.0283203f, -0.00585938f, 0.0219727f, -0.0117188f, 0.0219727f, -0.0205078f, 0.0219727f,
--0.0297852f, 0.0283203f, -0.0354004f, 0.034668f, -0.0410156f, 0.0493164f, -0.0410156f,
-0.104492f, -0.0410156f, 0.104492f, -0.571289f, 0.0493164f, -0.571289f, 0.034668f,
--0.571289f, 0.0283203f, -0.577148f, 0.0219727f, -0.583008f, 0.0219727f, -0.592285f,
-0.0219727f, -0.601074f, 0.0283203f, -0.606934f, 0.034668f, -0.612793f, 0.0493164f,
--0.612793f, 0.501465f, -0.210449f, 0.501465f, -0.288086f, 0.448242f, -0.342041f,
-0.39502f, -0.395996f, 0.32373f, -0.395996f, 0.252441f, -0.395996f, 0.199219f, -0.342041f,
-0.145996f, -0.288086f, 0.145996f, -0.210449f, 0.145996f, -0.132812f, 0.199219f, -0.0788574f,
-0.252441f, -0.0249023f, 0.32373f, -0.0249023f, 0.39502f, -0.0249023f, 0.448242f,
--0.0788574f, 0.501465f, -0.132812f, 0.501465f, -0.210449f, 0.471191f, -0.381348f,
-0.471191f, -0.39502f, 0.471191f, -0.410156f, 0.477051f, -0.416504f, 0.48291f, -0.422852f,
-0.491699f, -0.422852f, 0.500977f, -0.422852f, 0.506836f, -0.416504f, 0.512695f, -0.410156f,
-0.512695f, -0.39502f, 0.512695f, -0.302246f, 0.512207f, -0.287109f, 0.506592f, -0.280762f,
-0.500977f, -0.274414f, 0.491699f, -0.274414f, 0.483398f, -0.274414f, 0.477783f, -0.280029f,
-0.472168f, -0.285645f, 0.471191f, -0.298828f, 0.468262f, -0.333496f, 0.425537f, -0.364746f,
-0.382812f, -0.395996f, 0.310547f, -0.395996f, 0.219238f, -0.395996f, 0.171875f, -0.338867f,
-0.124512f, -0.281738f, 0.124512f, -0.208008f, 0.124512f, -0.128418f, 0.176758f, -0.0766602f,
-0.229004f, -0.0249023f, 0.312012f, -0.0249023f, 0.359863f, -0.0249023f, 0.409424f,
--0.0424805f, 0.458984f, -0.0600586f, 0.499023f, -0.0991211f, 0.509277f, -0.108887f,
-0.51709f, -0.108887f, 0.525391f, -0.108887f, 0.531006f, -0.103271f, 0.536621f, -0.0976562f,
-0.536621f, -0.0893555f, 0.536621f, -0.0683594f, 0.487305f, -0.0361328f, 0.407715f,
-0.0161133f, 0.310059f, 0.0161133f, 0.210938f, 0.0161133f, 0.147217f, -0.0471191f,
-0.0834961f, -0.110352f, 0.0834961f, -0.20752f, 0.0834961f, -0.306641f, 0.148682f,
--0.37207f, 0.213867f, -0.4375f, 0.312988f, -0.4375f, 0.407227f, -0.4375f, 0.471191f,
--0.381348f, 0.500977f, -0.612793f, 0.500977f, -0.0410156f, 0.555664f, -0.0410156f,
-0.570801f, -0.0410156f, 0.577148f, -0.0354004f, 0.583496f, -0.0297852f, 0.583496f,
--0.0205078f, 0.583496f, -0.0117188f, 0.577148f, -0.00585938f, 0.570801f, 0, 0.555664f,
-0, 0.459473f, 0, 0.459473f, -0.081543f, 0.388184f, 0.0161133f, 0.27832f, 0.0161133f,
-0.222656f, 0.0161133f, 0.171631f, -0.0134277f, 0.120605f, -0.0429688f, 0.0910645f,
--0.0976562f, 0.0615234f, -0.152344f, 0.0615234f, -0.210449f, 0.0615234f, -0.269043f,
-0.0910645f, -0.323486f, 0.120605f, -0.37793f, 0.171631f, -0.407715f, 0.222656f, -0.4375f,
-0.278809f, -0.4375f, 0.38623f, -0.4375f, 0.459473f, -0.339844f, 0.459473f, -0.571289f,
-0.404785f, -0.571289f, 0.389648f, -0.571289f, 0.383301f, -0.577148f, 0.376953f, -0.583008f,
-0.376953f, -0.592285f, 0.376953f, -0.601074f, 0.383301f, -0.606934f, 0.389648f, -0.612793f,
-0.404785f, -0.612793f, 0.459473f, -0.210449f, 0.459473f, -0.288574f, 0.406738f, -0.342285f,
-0.354004f, -0.395996f, 0.28125f, -0.395996f, 0.208008f, -0.395996f, 0.155273f, -0.342285f,
-0.102539f, -0.288574f, 0.102539f, -0.210449f, 0.102539f, -0.132812f, 0.155273f, -0.0788574f,
-0.208008f, -0.0249023f, 0.28125f, -0.0249023f, 0.354004f, -0.0249023f, 0.406738f,
--0.0788574f, 0.459473f, -0.132812f, 0.459473f, -0.210449f, 0.521973f, -0.20166f,
-0.104004f, -0.20166f, 0.114746f, -0.12207f, 0.170654f, -0.0734863f, 0.226562f, -0.0249023f,
-0.309082f, -0.0249023f, 0.35498f, -0.0249023f, 0.405273f, -0.0400391f, 0.455566f,
--0.0551758f, 0.487305f, -0.0800781f, 0.496582f, -0.0874023f, 0.503418f, -0.0874023f,
-0.51123f, -0.0874023f, 0.51709f, -0.0812988f, 0.522949f, -0.0751953f, 0.522949f,
--0.0668945f, 0.522949f, -0.0585938f, 0.515137f, -0.0507812f, 0.491699f, -0.0263672f,
-0.431885f, -0.00512695f, 0.37207f, 0.0161133f, 0.309082f, 0.0161133f, 0.203613f,
-0.0161133f, 0.133057f, -0.0529785f, 0.0625f, -0.12207f, 0.0625f, -0.220215f, 0.0625f,
--0.30957f, 0.128662f, -0.373535f, 0.194824f, -0.4375f, 0.29248f, -0.4375f, 0.393066f,
--0.4375f, 0.458008f, -0.371826f, 0.522949f, -0.306152f, 0.521973f, -0.20166f, 0.480469f,
--0.243164f, 0.468262f, -0.311035f, 0.41626f, -0.353516f, 0.364258f, -0.395996f, 0.29248f,
--0.395996f, 0.220703f, -0.395996f, 0.168945f, -0.354004f, 0.117188f, -0.312012f,
-0.104492f, -0.243164f, 0.272949f, -0.381348f, 0.272949f, -0.0410156f, 0.453125f,
--0.0410156f, 0.467773f, -0.0410156f, 0.474121f, -0.0354004f, 0.480469f, -0.0297852f,
-0.480469f, -0.0205078f, 0.480469f, -0.0117188f, 0.474121f, -0.00585938f, 0.467773f,
-0, 0.453125f, 0, 0.132324f, 0, 0.117676f, 0, 0.111328f, -0.00585938f, 0.10498f, -0.0117188f,
-0.10498f, -0.0205078f, 0.10498f, -0.0297852f, 0.111328f, -0.0354004f, 0.117676f,
--0.0410156f, 0.132324f, -0.0410156f, 0.231445f, -0.0410156f, 0.231445f, -0.381348f,
-0.142578f, -0.381348f, 0.12793f, -0.381348f, 0.121582f, -0.387207f, 0.115234f, -0.393066f,
-0.115234f, -0.402344f, 0.115234f, -0.411133f, 0.121582f, -0.416992f, 0.12793f, -0.422852f,
-0.142578f, -0.422852f, 0.231445f, -0.422852f, 0.231445f, -0.484863f, 0.231445f, -0.536621f,
-0.273438f, -0.574707f, 0.31543f, -0.612793f, 0.384766f, -0.612793f, 0.442871f, -0.612793f,
-0.508789f, -0.602051f, 0.533691f, -0.598145f, 0.538818f, -0.592773f, 0.543945f, -0.587402f,
-0.543945f, -0.578613f, 0.543945f, -0.569824f, 0.538086f, -0.564209f, 0.532227f, -0.558594f,
-0.522461f, -0.558594f, 0.518555f, -0.558594f, 0.509277f, -0.560059f, 0.435547f, -0.571289f,
-0.384766f, -0.571289f, 0.331055f, -0.571289f, 0.302002f, -0.544922f, 0.272949f, -0.518555f,
-0.272949f, -0.484863f, 0.272949f, -0.422852f, 0.464844f, -0.422852f, 0.479492f, -0.422852f,
-0.48584f, -0.416992f, 0.492188f, -0.411133f, 0.492188f, -0.401855f, 0.492188f, -0.393066f,
-0.48584f, -0.387207f, 0.479492f, -0.381348f, 0.464844f, -0.381348f, 0.437988f, -0.347656f,
-0.437988f, -0.422852f, 0.53418f, -0.422852f, 0.548828f, -0.422852f, 0.555176f, -0.416992f,
-0.561523f, -0.411133f, 0.561523f, -0.401855f, 0.561523f, -0.393066f, 0.555176f, -0.387207f,
-0.548828f, -0.381348f, 0.53418f, -0.381348f, 0.479004f, -0.381348f, 0.479004f, 0.0283203f,
-0.479004f, 0.0693359f, 0.461426f, 0.101562f, 0.449707f, 0.123047f, 0.422363f, 0.145996f,
-0.39502f, 0.168945f, 0.372559f, 0.178711f, 0.350098f, 0.188477f, 0.3125f, 0.188477f,
-0.196289f, 0.188477f, 0.181641f, 0.188477f, 0.175293f, 0.182861f, 0.168945f, 0.177246f,
-0.168945f, 0.167969f, 0.168945f, 0.158691f, 0.175293f, 0.152832f, 0.181641f, 0.146973f,
-0.196289f, 0.146973f, 0.313965f, 0.147461f, 0.350098f, 0.147461f, 0.37915f, 0.128906f,
-0.408203f, 0.110352f, 0.427246f, 0.074707f, 0.437988f, 0.0541992f, 0.437988f, 0.0224609f,
-0.437988f, -0.100586f, 0.37207f, -0.0102539f, 0.268066f, -0.0102539f, 0.183594f,
--0.0102539f, 0.122314f, -0.072998f, 0.0610352f, -0.135742f, 0.0610352f, -0.224121f,
-0.0610352f, -0.3125f, 0.122314f, -0.375f, 0.183594f, -0.4375f, 0.268066f, -0.4375f,
-0.37207f, -0.4375f, 0.437988f, -0.347656f, 0.437988f, -0.224121f, 0.437988f, -0.296387f,
-0.388428f, -0.346191f, 0.338867f, -0.395996f, 0.27002f, -0.395996f, 0.201172f, -0.395996f,
-0.151855f, -0.345947f, 0.102539f, -0.295898f, 0.102539f, -0.224121f, 0.102539f, -0.151855f,
-0.151855f, -0.101807f, 0.201172f, -0.0517578f, 0.27002f, -0.0517578f, 0.338867f,
--0.0517578f, 0.388428f, -0.101807f, 0.437988f, -0.151855f, 0.437988f, -0.224121f,
-0.320312f, -0.633301f, 0.320312f, -0.527344f, 0.259766f, -0.527344f, 0.259766f, -0.633301f,
-0.321777f, -0.422852f, 0.321777f, -0.0410156f, 0.48291f, -0.0410156f, 0.498047f,
--0.0410156f, 0.504395f, -0.0354004f, 0.510742f, -0.0297852f, 0.510742f, -0.0205078f,
-0.510742f, -0.0117188f, 0.504395f, -0.00585938f, 0.498047f, 0, 0.48291f, 0, 0.119629f,
-0, 0.10498f, 0, 0.0986328f, -0.00585938f, 0.0922852f, -0.0117188f, 0.0922852f, -0.0205078f,
-0.0922852f, -0.0297852f, 0.0986328f, -0.0354004f, 0.10498f, -0.0410156f, 0.119629f,
--0.0410156f, 0.280762f, -0.0410156f, 0.280762f, -0.381348f, 0.161133f, -0.381348f,
-0.146484f, -0.381348f, 0.139893f, -0.387207f, 0.133301f, -0.393066f, 0.133301f, -0.401855f,
-0.133301f, -0.411133f, 0.139648f, -0.416992f, 0.145996f, -0.422852f, 0.161133f, -0.422852f,
-0.320801f, -0.612793f, 0.320801f, -0.0410156f, 0.481934f, -0.0410156f, 0.49707f,
--0.0410156f, 0.503418f, -0.0354004f, 0.509766f, -0.0297852f, 0.509766f, -0.0205078f,
-0.509766f, -0.0117188f, 0.503418f, -0.00585938f, 0.49707f, 0, 0.481934f, 0, 0.118652f,
-0, 0.104004f, 0, 0.0976562f, -0.00585938f, 0.0913086f, -0.0117188f, 0.0913086f, -0.0205078f,
-0.0913086f, -0.0297852f, 0.0976562f, -0.0354004f, 0.104004f, -0.0410156f, 0.118652f,
--0.0410156f, 0.279785f, -0.0410156f, 0.279785f, -0.571289f, 0.161621f, -0.571289f,
-0.146973f, -0.571289f, 0.140381f, -0.577148f, 0.133789f, -0.583008f, 0.133789f, -0.592285f,
-0.133789f, -0.601074f, 0.140137f, -0.606934f, 0.146484f, -0.612793f, 0.161621f, -0.612793f,
-0.113281f, -0.422852f, 0.113281f, -0.381348f, 0.165527f, -0.4375f, 0.218262f, -0.4375f,
-0.25f, -0.4375f, 0.273926f, -0.420654f, 0.297852f, -0.403809f, 0.313965f, -0.369629f,
-0.341309f, -0.403809f, 0.369385f, -0.420654f, 0.397461f, -0.4375f, 0.425781f, -0.4375f,
-0.470215f, -0.4375f, 0.496582f, -0.408691f, 0.53125f, -0.371582f, 0.53125f, -0.327637f,
-0.53125f, -0.0410156f, 0.565918f, -0.0410156f, 0.580566f, -0.0410156f, 0.586914f,
--0.0354004f, 0.593262f, -0.0297852f, 0.593262f, -0.0205078f, 0.593262f, -0.0117188f,
-0.586914f, -0.00585938f, 0.580566f, 0, 0.565918f, 0, 0.490234f, 0, 0.490234f, -0.32373f,
-0.490234f, -0.35498f, 0.471191f, -0.375488f, 0.452148f, -0.395996f, 0.427246f, -0.395996f,
-0.404785f, -0.395996f, 0.379883f, -0.37915f, 0.35498f, -0.362305f, 0.323242f, -0.312988f,
-0.323242f, -0.0410156f, 0.357422f, -0.0410156f, 0.37207f, -0.0410156f, 0.378418f,
--0.0354004f, 0.384766f, -0.0297852f, 0.384766f, -0.0205078f, 0.384766f, -0.0117188f,
-0.378418f, -0.00585938f, 0.37207f, 0, 0.357422f, 0, 0.281738f, 0, 0.281738f, -0.320801f,
-0.281738f, -0.353516f, 0.262451f, -0.374756f, 0.243164f, -0.395996f, 0.219238f, -0.395996f,
-0.197266f, -0.395996f, 0.175781f, -0.381836f, 0.145996f, -0.361816f, 0.113281f, -0.312988f,
-0.113281f, -0.0410156f, 0.147949f, -0.0410156f, 0.162598f, -0.0410156f, 0.168945f,
--0.0354004f, 0.175293f, -0.0297852f, 0.175293f, -0.0205078f, 0.175293f, -0.0117188f,
-0.168945f, -0.00585938f, 0.162598f, 0, 0.147949f, 0, 0.0375977f, 0, 0.0229492f, 0,
-0.0166016f, -0.00585938f, 0.0102539f, -0.0117188f, 0.0102539f, -0.0205078f, 0.0102539f,
--0.0297852f, 0.0166016f, -0.0354004f, 0.0229492f, -0.0410156f, 0.0375977f, -0.0410156f,
-0.0722656f, -0.0410156f, 0.0722656f, -0.381348f, 0.0375977f, -0.381348f, 0.0229492f,
--0.381348f, 0.0166016f, -0.387207f, 0.0102539f, -0.393066f, 0.0102539f, -0.402344f,
-0.0102539f, -0.411133f, 0.0166016f, -0.416992f, 0.0229492f, -0.422852f, 0.0375977f,
--0.422852f, 0.16748f, -0.422852f, 0.16748f, -0.36084f, 0.210449f, -0.404297f, 0.245117f,
--0.420898f, 0.279785f, -0.4375f, 0.323242f, -0.4375f, 0.370117f, -0.4375f, 0.408691f,
--0.41748f, 0.436035f, -0.402832f, 0.458252f, -0.368896f, 0.480469f, -0.334961f, 0.480469f,
--0.299316f, 0.480469f, -0.0410156f, 0.515137f, -0.0410156f, 0.529785f, -0.0410156f,
-0.536133f, -0.0354004f, 0.54248f, -0.0297852f, 0.54248f, -0.0205078f, 0.54248f, -0.0117188f,
-0.536133f, -0.00585938f, 0.529785f, 0, 0.515137f, 0, 0.405273f, 0, 0.390137f, 0,
-0.383789f, -0.00585938f, 0.377441f, -0.0117188f, 0.377441f, -0.0205078f, 0.377441f,
--0.0297852f, 0.383789f, -0.0354004f, 0.390137f, -0.0410156f, 0.405273f, -0.0410156f,
-0.439453f, -0.0410156f, 0.439453f, -0.29248f, 0.439453f, -0.335938f, 0.407715f, -0.365967f,
-0.375977f, -0.395996f, 0.322754f, -0.395996f, 0.282227f, -0.395996f, 0.252441f, -0.379639f,
-0.222656f, -0.363281f, 0.16748f, -0.29834f, 0.16748f, -0.0410156f, 0.213867f, -0.0410156f,
-0.228516f, -0.0410156f, 0.234863f, -0.0354004f, 0.241211f, -0.0297852f, 0.241211f,
--0.0205078f, 0.241211f, -0.0117188f, 0.234863f, -0.00585938f, 0.228516f, 0, 0.213867f,
-0, 0.0800781f, 0, 0.0654297f, 0, 0.059082f, -0.00585938f, 0.0527344f, -0.0117188f,
-0.0527344f, -0.0205078f, 0.0527344f, -0.0297852f, 0.059082f, -0.0354004f, 0.0654297f,
--0.0410156f, 0.0800781f, -0.0410156f, 0.126465f, -0.0410156f, 0.126465f, -0.381348f,
-0.0917969f, -0.381348f, 0.0771484f, -0.381348f, 0.0708008f, -0.387207f, 0.0644531f,
--0.393066f, 0.0644531f, -0.402344f, 0.0644531f, -0.411133f, 0.0708008f, -0.416992f,
-0.0771484f, -0.422852f, 0.0917969f, -0.422852f, 0.529297f, -0.210449f, 0.529297f,
--0.116699f, 0.462158f, -0.050293f, 0.39502f, 0.0161133f, 0.300293f, 0.0161133f, 0.20459f,
-0.0161133f, 0.137695f, -0.0505371f, 0.0708008f, -0.117188f, 0.0708008f, -0.210449f,
-0.0708008f, -0.304199f, 0.137695f, -0.37085f, 0.20459f, -0.4375f, 0.300293f, -0.4375f,
-0.39502f, -0.4375f, 0.462158f, -0.371094f, 0.529297f, -0.304688f, 0.529297f, -0.210449f,
-0.487793f, -0.210449f, 0.487793f, -0.287598f, 0.432861f, -0.341797f, 0.37793f, -0.395996f,
-0.299805f, -0.395996f, 0.22168f, -0.395996f, 0.166748f, -0.341553f, 0.111816f, -0.287109f,
-0.111816f, -0.210449f, 0.111816f, -0.134277f, 0.166748f, -0.0795898f, 0.22168f, -0.0249023f,
-0.299805f, -0.0249023f, 0.37793f, -0.0249023f, 0.432861f, -0.0793457f, 0.487793f,
--0.133789f, 0.487793f, -0.210449f, 0.145508f, -0.422852f, 0.145508f, -0.348145f,
-0.182129f, -0.392578f, 0.224121f, -0.415039f, 0.266113f, -0.4375f, 0.323242f, -0.4375f,
-0.383789f, -0.4375f, 0.435059f, -0.40918f, 0.486328f, -0.380859f, 0.514404f, -0.330322f,
-0.54248f, -0.279785f, 0.54248f, -0.224121f, 0.54248f, -0.135742f, 0.479248f, -0.072998f,
-0.416016f, -0.0102539f, 0.32373f, -0.0102539f, 0.213867f, -0.0102539f, 0.145508f,
--0.0996094f, 0.145508f, 0.147461f, 0.245117f, 0.147461f, 0.259766f, 0.147461f, 0.266113f,
-0.153076f, 0.272461f, 0.158691f, 0.272461f, 0.167969f, 0.272461f, 0.176758f, 0.266113f,
-0.182617f, 0.259766f, 0.188477f, 0.245117f, 0.188477f, 0.0493164f, 0.188477f, 0.034668f,
-0.188477f, 0.0283203f, 0.182861f, 0.0219727f, 0.177246f, 0.0219727f, 0.167969f, 0.0219727f,
-0.158691f, 0.0283203f, 0.153076f, 0.034668f, 0.147461f, 0.0493164f, 0.147461f, 0.104492f,
-0.147461f, 0.104492f, -0.381348f, 0.0493164f, -0.381348f, 0.034668f, -0.381348f,
-0.0283203f, -0.387207f, 0.0219727f, -0.393066f, 0.0219727f, -0.402344f, 0.0219727f,
--0.411133f, 0.0283203f, -0.416992f, 0.034668f, -0.422852f, 0.0493164f, -0.422852f,
-0.500977f, -0.224121f, 0.500977f, -0.294922f, 0.449463f, -0.345459f, 0.397949f, -0.395996f,
-0.32373f, -0.395996f, 0.249023f, -0.395996f, 0.197266f, -0.345215f, 0.145508f, -0.294434f,
-0.145508f, -0.224121f, 0.145508f, -0.15332f, 0.197266f, -0.102539f, 0.249023f, -0.0517578f,
-0.32373f, -0.0517578f, 0.397461f, -0.0517578f, 0.449219f, -0.102295f, 0.500977f,
--0.152832f, 0.500977f, -0.224121f, 0.250977f, -0.422852f, 0.250977f, -0.319336f,
-0.331055f, -0.391602f, 0.37085f, -0.412354f, 0.410645f, -0.433105f, 0.444336f, -0.433105f,
-0.480957f, -0.433105f, 0.512451f, -0.408447f, 0.543945f, -0.383789f, 0.543945f, -0.371094f,
-0.543945f, -0.361816f, 0.537842f, -0.355713f, 0.531738f, -0.349609f, 0.522461f, -0.349609f,
-0.517578f, -0.349609f, 0.51416f, -0.351318f, 0.510742f, -0.353027f, 0.501465f, -0.362305f,
-0.484375f, -0.379395f, 0.47168f, -0.385742f, 0.458984f, -0.39209f, 0.446777f, -0.39209f,
-0.419922f, -0.39209f, 0.38208f, -0.370605f, 0.344238f, -0.349121f, 0.250977f, -0.265625f,
-0.250977f, -0.0410156f, 0.432617f, -0.0410156f, 0.447754f, -0.0410156f, 0.454102f,
--0.0354004f, 0.460449f, -0.0297852f, 0.460449f, -0.0205078f, 0.460449f, -0.0117188f,
-0.454102f, -0.00585938f, 0.447754f, 0, 0.432617f, 0, 0.11084f, 0, 0.0961914f, 0,
-0.0898438f, -0.00561523f, 0.0834961f, -0.0112305f, 0.0834961f, -0.0200195f, 0.0834961f,
--0.0283203f, 0.0895996f, -0.0339355f, 0.0957031f, -0.0395508f, 0.11084f, -0.0395508f,
-0.209961f, -0.0395508f, 0.209961f, -0.381348f, 0.134277f, -0.381348f, 0.119629f,
--0.381348f, 0.113281f, -0.387207f, 0.106934f, -0.393066f, 0.106934f, -0.402344f,
-0.106934f, -0.411133f, 0.113037f, -0.416992f, 0.119141f, -0.422852f, 0.134277f, -0.422852f,
-0.435547f, -0.395996f, 0.435547f, -0.410156f, 0.441406f, -0.416504f, 0.447266f, -0.422852f,
-0.456055f, -0.422852f, 0.465332f, -0.422852f, 0.471191f, -0.416504f, 0.477051f, -0.410156f,
-0.477051f, -0.39502f, 0.477051f, -0.324707f, 0.477051f, -0.310059f, 0.471191f, -0.303711f,
-0.465332f, -0.297363f, 0.456055f, -0.297363f, 0.447754f, -0.297363f, 0.442139f, -0.302734f,
-0.436523f, -0.308105f, 0.435547f, -0.320312f, 0.432617f, -0.349609f, 0.405273f, -0.368652f,
-0.365234f, -0.395996f, 0.299316f, -0.395996f, 0.230469f, -0.395996f, 0.192383f, -0.368164f,
-0.163574f, -0.347168f, 0.163574f, -0.321289f, 0.163574f, -0.291992f, 0.197754f, -0.272461f,
-0.221191f, -0.258789f, 0.286621f, -0.251465f, 0.37207f, -0.242188f, 0.405273f, -0.230469f,
-0.452637f, -0.213379f, 0.47583f, -0.183105f, 0.499023f, -0.152832f, 0.499023f, -0.117676f,
-0.499023f, -0.0654297f, 0.44873f, -0.0246582f, 0.398438f, 0.0161133f, 0.30127f, 0.0161133f,
-0.204102f, 0.0161133f, 0.14209f, -0.0332031f, 0.14209f, -0.0166016f, 0.140137f, -0.0117188f,
-0.138184f, -0.00683594f, 0.133057f, -0.00341797f, 0.12793f, 0, 0.121582f, 0, 0.112793f,
-0, 0.106934f, -0.00634766f, 0.101074f, -0.0126953f, 0.101074f, -0.0273438f, 0.101074f,
--0.111816f, 0.101074f, -0.126465f, 0.106689f, -0.132812f, 0.112305f, -0.13916f, 0.121582f,
--0.13916f, 0.130371f, -0.13916f, 0.136475f, -0.133057f, 0.142578f, -0.126953f, 0.142578f,
--0.116699f, 0.142578f, -0.0942383f, 0.153809f, -0.0791016f, 0.170898f, -0.0556641f,
-0.208252f, -0.0402832f, 0.245605f, -0.0249023f, 0.299805f, -0.0249023f, 0.379883f,
--0.0249023f, 0.418945f, -0.0546875f, 0.458008f, -0.0844727f, 0.458008f, -0.117676f,
-0.458008f, -0.155762f, 0.418457f, -0.178711f, 0.378418f, -0.20166f, 0.302002f, -0.209473f,
-0.225586f, -0.217285f, 0.192383f, -0.22998f, 0.15918f, -0.242676f, 0.140625f, -0.268066f,
-0.12207f, -0.293457f, 0.12207f, -0.322754f, 0.12207f, -0.375488f, 0.173828f, -0.406494f,
-0.225586f, -0.4375f, 0.297363f, -0.4375f, 0.382324f, -0.4375f, 0.435547f, -0.395996f,
-0.21582f, -0.422852f, 0.438477f, -0.422852f, 0.453125f, -0.422852f, 0.459473f, -0.416992f,
-0.46582f, -0.411133f, 0.46582f, -0.401855f, 0.46582f, -0.393066f, 0.459473f, -0.387207f,
-0.453125f, -0.381348f, 0.438477f, -0.381348f, 0.21582f, -0.381348f, 0.21582f, -0.108398f,
-0.21582f, -0.0727539f, 0.244385f, -0.0488281f, 0.272949f, -0.0249023f, 0.328125f,
--0.0249023f, 0.369629f, -0.0249023f, 0.417969f, -0.0373535f, 0.466309f, -0.0498047f,
-0.493164f, -0.0654297f, 0.50293f, -0.0717773f, 0.509277f, -0.0717773f, 0.51709f,
--0.0717773f, 0.522949f, -0.0656738f, 0.528809f, -0.0595703f, 0.528809f, -0.0512695f,
-0.528809f, -0.0439453f, 0.522461f, -0.0375977f, 0.506836f, -0.0214844f, 0.446533f,
--0.00268555f, 0.38623f, 0.0161133f, 0.331055f, 0.0161133f, 0.259277f, 0.0161133f,
-0.216797f, -0.0175781f, 0.174316f, -0.0512695f, 0.174316f, -0.108398f, 0.174316f,
--0.381348f, 0.0986328f, -0.381348f, 0.0839844f, -0.381348f, 0.0776367f, -0.387207f,
-0.0712891f, -0.393066f, 0.0712891f, -0.402344f, 0.0712891f, -0.411133f, 0.0776367f,
--0.416992f, 0.0839844f, -0.422852f, 0.0986328f, -0.422852f, 0.174316f, -0.422852f,
-0.174316f, -0.543945f, 0.174316f, -0.558594f, 0.180176f, -0.564941f, 0.186035f, -0.571289f,
-0.194824f, -0.571289f, 0.204102f, -0.571289f, 0.209961f, -0.564941f, 0.21582f, -0.558594f,
-0.21582f, -0.543945f, 0.44043f, 0, 0.44043f, -0.0600586f, 0.356445f, 0.0161133f,
-0.258789f, 0.0161133f, 0.19873f, 0.0161133f, 0.16748f, -0.0166016f, 0.126953f, -0.0595703f,
-0.126953f, -0.116699f, 0.126953f, -0.381348f, 0.0717773f, -0.381348f, 0.0571289f,
--0.381348f, 0.0507812f, -0.387207f, 0.0444336f, -0.393066f, 0.0444336f, -0.402344f,
-0.0444336f, -0.411133f, 0.0507812f, -0.416992f, 0.0571289f, -0.422852f, 0.0717773f,
--0.422852f, 0.167969f, -0.422852f, 0.167969f, -0.116699f, 0.167969f, -0.0766602f,
-0.193359f, -0.0507812f, 0.21875f, -0.0249023f, 0.256836f, -0.0249023f, 0.356934f,
--0.0249023f, 0.44043f, -0.116699f, 0.44043f, -0.381348f, 0.364746f, -0.381348f, 0.350098f,
--0.381348f, 0.34375f, -0.387207f, 0.337402f, -0.393066f, 0.337402f, -0.402344f, 0.337402f,
--0.411133f, 0.34375f, -0.416992f, 0.350098f, -0.422852f, 0.364746f, -0.422852f, 0.481445f,
--0.422852f, 0.481445f, -0.0410156f, 0.516113f, -0.0410156f, 0.530762f, -0.0410156f,
-0.537109f, -0.0354004f, 0.543457f, -0.0297852f, 0.543457f, -0.0205078f, 0.543457f,
--0.0117188f, 0.537109f, -0.00585938f, 0.530762f, 0, 0.516113f, 0, 0.302734f, 0, 0.112305f,
--0.381348f, 0.100098f, -0.381348f, 0.0854492f, -0.381348f, 0.0791016f, -0.387207f,
-0.0727539f, -0.393066f, 0.0727539f, -0.401855f, 0.0727539f, -0.408203f, 0.0759277f,
--0.41333f, 0.0791016f, -0.418457f, 0.0842285f, -0.420654f, 0.0893555f, -0.422852f,
-0.100098f, -0.422852f, 0.212402f, -0.422852f, 0.227051f, -0.422852f, 0.233398f, -0.416992f,
-0.239746f, -0.411133f, 0.239746f, -0.401855f, 0.239746f, -0.393066f, 0.233398f, -0.387207f,
-0.227051f, -0.381348f, 0.212402f, -0.381348f, 0.157227f, -0.381348f, 0.324707f, -0.0449219f,
-0.489746f, -0.381348f, 0.43457f, -0.381348f, 0.419922f, -0.381348f, 0.413574f, -0.387207f,
-0.407227f, -0.393066f, 0.407227f, -0.402344f, 0.407227f, -0.411133f, 0.413574f, -0.416992f,
-0.419922f, -0.422852f, 0.43457f, -0.422852f, 0.546387f, -0.422852f, 0.561523f, -0.422852f,
-0.567871f, -0.416992f, 0.574219f, -0.411133f, 0.574219f, -0.401855f, 0.574219f, -0.395508f,
-0.570312f, -0.390137f, 0.566406f, -0.384766f, 0.561523f, -0.383057f, 0.556641f, -0.381348f,
-0.53418f, -0.381348f, 0.274414f, 0.147461f, 0.338379f, 0.147461f, 0.353027f, 0.147461f,
-0.359375f, 0.153076f, 0.365723f, 0.158691f, 0.365723f, 0.167969f, 0.365723f, 0.176758f,
-0.359375f, 0.182617f, 0.353027f, 0.188477f, 0.338379f, 0.188477f, 0.102051f, 0.188477f,
-0.0874023f, 0.188477f, 0.0810547f, 0.182861f, 0.074707f, 0.177246f, 0.074707f, 0.167969f,
-0.074707f, 0.158691f, 0.0810547f, 0.153076f, 0.0874023f, 0.147461f, 0.102051f, 0.147461f,
-0.230469f, 0.147461f
-};
-
-const unsigned char CourierNewkNormalVerbs[] = {
-6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5,
-6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 0, 1, 1, 1,
-5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1,
-1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 0, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2,
-2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1,
-1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5,
-6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2,
-2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6,
-0, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2,
-2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2,
-2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2,
-2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6
-};
-
-const unsigned CourierNewkNormalCharCodes[] = {
-32, 33, 47, 60, 62,
-65, 67, 72, 77, 84, 87, 89, 97, 98, 99, 100, 101, 102, 103, 105, 108, 109, 110,
-111, 112, 114, 115, 116, 117, 121
-};
-
-const SkFixed CourierNewkNormalWidths[] = {
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0
-};
-
-const int CourierNewkNormalCharCodesCount = (int) SK_ARRAY_COUNT(CourierNewkNormalCharCodes);
-
-const SkPaint::FontMetrics CourierNewkNormalMetrics = {
-0x00000003, -1.021f, -0.83252f, 0.300293f, 0.679688f, 0, 0.744141f, 0, -0.121582f,
-0.622559f, 0.437988f, 0, 0.0410156f, 0.23291f
-};
-
-const SkScalar CourierNewkBoldPoints[] = {
-0.422363f, -0.161133f, 0.179199f, -0.161133f, 0.154785f, -0.100098f, 0.179199f, -0.100098f,
-0.215332f, -0.100098f, 0.230713f, -0.0861816f, 0.246094f, -0.0722656f, 0.246094f,
--0.0498047f, 0.246094f, -0.027832f, 0.230713f, -0.013916f, 0.215332f, 0, 0.179199f,
-0, 0.0444336f, 0, 0.00830078f, 0, -0.00708008f, -0.013916f, -0.0224609f, -0.027832f,
--0.0224609f, -0.050293f, -0.0224609f, -0.0727539f, -0.00634766f, -0.0869141f, 0.00976562f,
--0.101074f, 0.046875f, -0.100098f, 0.204102f, -0.491699f, 0.138672f, -0.491699f,
-0.102539f, -0.491699f, 0.0871582f, -0.505615f, 0.0717773f, -0.519531f, 0.0717773f,
--0.541992f, 0.0717773f, -0.564453f, 0.0871582f, -0.578369f, 0.102539f, -0.592285f,
-0.138672f, -0.592285f, 0.35498f, -0.591797f, 0.554199f, -0.100098f, 0.589355f, -0.100098f,
-0.600586f, -0.0922852f, 0.623047f, -0.0761719f, 0.623047f, -0.0498047f, 0.623047f,
--0.027832f, 0.60791f, -0.013916f, 0.592773f, 0, 0.556641f, 0, 0.421875f, 0, 0.385742f,
-0, 0.370361f, -0.013916f, 0.35498f, -0.027832f, 0.35498f, -0.050293f, 0.35498f, -0.0722656f,
-0.370361f, -0.0861816f, 0.385742f, -0.100098f, 0.421875f, -0.100098f, 0.446289f,
--0.100098f, 0.380859f, -0.26123f, 0.300293f, -0.459473f, 0.219238f, -0.26123f, 0.409668f,
--0.245117f, 0.195801f, -0.245117f, 0.195801f, -0.100098f, 0.211426f, -0.100098f,
-0.247559f, -0.100098f, 0.262939f, -0.0861816f, 0.27832f, -0.0722656f, 0.27832f, -0.0498047f,
-0.27832f, -0.027832f, 0.262939f, -0.013916f, 0.247559f, 0, 0.211426f, 0, 0.0888672f,
-0, 0.0527344f, 0, 0.0373535f, -0.013916f, 0.0219727f, -0.027832f, 0.0219727f, -0.050293f,
-0.0219727f, -0.0776367f, 0.0458984f, -0.0927734f, 0.0576172f, -0.100586f, 0.0957031f,
--0.100098f, 0.0957031f, -0.491699f, 0.0693359f, -0.494141f, 0.0559082f, -0.507812f,
-0.0424805f, -0.521484f, 0.0424805f, -0.541992f, 0.0424805f, -0.564453f, 0.0578613f,
--0.578369f, 0.0732422f, -0.592285f, 0.109375f, -0.592285f, 0.211426f, -0.591797f,
-0.247559f, -0.591797f, 0.262939f, -0.578125f, 0.27832f, -0.564453f, 0.27832f, -0.541992f,
-0.27832f, -0.519531f, 0.262939f, -0.505615f, 0.247559f, -0.491699f, 0.211426f, -0.491699f,
-0.195801f, -0.491699f, 0.195801f, -0.345215f, 0.409668f, -0.345215f, 0.409668f, -0.491699f,
-0.394043f, -0.491699f, 0.35791f, -0.491699f, 0.342529f, -0.505615f, 0.327148f, -0.519531f,
-0.327148f, -0.541992f, 0.327148f, -0.564453f, 0.342529f, -0.578369f, 0.35791f, -0.592285f,
-0.394043f, -0.592285f, 0.496094f, -0.591797f, 0.532227f, -0.591797f, 0.547607f, -0.578125f,
-0.562988f, -0.564453f, 0.562988f, -0.541992f, 0.562988f, -0.521484f, 0.549561f, -0.507812f,
-0.536133f, -0.494141f, 0.509766f, -0.491699f, 0.509766f, -0.100098f, 0.54834f, -0.100098f,
-0.55957f, -0.0927734f, 0.583496f, -0.0776367f, 0.583496f, -0.0498047f, 0.583496f,
--0.027832f, 0.568115f, -0.013916f, 0.552734f, 0, 0.516602f, 0, 0.394043f, 0, 0.35791f,
-0, 0.342529f, -0.013916f, 0.327148f, -0.027832f, 0.327148f, -0.050293f, 0.327148f,
--0.0722656f, 0.342773f, -0.0861816f, 0.358398f, -0.100098f, 0.394043f, -0.100098f,
-0.409668f, -0.100098f, 0.348633f, -0.491699f, 0.348633f, -0.100098f, 0.416016f, -0.100098f,
-0.452148f, -0.100098f, 0.467529f, -0.0861816f, 0.48291f, -0.0722656f, 0.48291f, -0.0498047f,
-0.48291f, -0.027832f, 0.467529f, -0.013916f, 0.452148f, 0, 0.416016f, 0, 0.181641f,
-0, 0.145508f, 0, 0.130127f, -0.013916f, 0.114746f, -0.027832f, 0.114746f, -0.050293f,
-0.114746f, -0.0722656f, 0.130127f, -0.0861816f, 0.145508f, -0.100098f, 0.181641f,
--0.100098f, 0.248535f, -0.100098f, 0.248535f, -0.491699f, 0.140137f, -0.491699f,
-0.140137f, -0.396973f, 0.140137f, -0.36084f, 0.126221f, -0.345459f, 0.112305f, -0.330078f,
-0.0898438f, -0.330078f, 0.0678711f, -0.330078f, 0.0539551f, -0.345459f, 0.0400391f,
--0.36084f, 0.0400391f, -0.396973f, 0.0400391f, -0.592285f, 0.558594f, -0.591797f,
-0.558594f, -0.396973f, 0.558594f, -0.36084f, 0.544678f, -0.345459f, 0.530762f, -0.330078f,
-0.508301f, -0.330078f, 0.486328f, -0.330078f, 0.472412f, -0.345459f, 0.458496f, -0.36084f,
-0.458496f, -0.396973f, 0.458496f, -0.491699f, 0.300293f, -0.28418f, 0.20752f, 0,
-0.0952148f, 0, 0.0356445f, -0.491699f, 0.0126953f, -0.494629f, 0.000976562f, -0.507568f,
--0.0107422f, -0.520508f, -0.0107422f, -0.540527f, -0.0107422f, -0.563965f, 0.00463867f,
--0.578125f, 0.0200195f, -0.592285f, 0.0561523f, -0.592285f, 0.189453f, -0.591797f,
-0.225586f, -0.591797f, 0.240967f, -0.578125f, 0.256348f, -0.564453f, 0.256348f, -0.541992f,
-0.256348f, -0.519531f, 0.240967f, -0.505615f, 0.225586f, -0.491699f, 0.189453f, -0.491699f,
-0.137207f, -0.491699f, 0.17041f, -0.211914f, 0.249023f, -0.444824f, 0.353027f, -0.444824f,
-0.431152f, -0.211914f, 0.464355f, -0.491699f, 0.412109f, -0.491699f, 0.375977f, -0.491699f,
-0.360596f, -0.505615f, 0.345215f, -0.519531f, 0.345215f, -0.541992f, 0.345215f, -0.564453f,
-0.360596f, -0.578369f, 0.375977f, -0.592285f, 0.412109f, -0.592285f, 0.544922f, -0.591797f,
-0.581055f, -0.591797f, 0.596436f, -0.578125f, 0.611816f, -0.564453f, 0.611816f, -0.541992f,
-0.611816f, -0.522949f, 0.599609f, -0.509277f, 0.587402f, -0.495605f, 0.564453f, -0.491699f,
-0.506836f, 0, 0.396484f, 0, 0.350586f, -0.248535f, 0.350586f, -0.100098f, 0.417969f,
--0.100098f, 0.454102f, -0.100098f, 0.469482f, -0.0861816f, 0.484863f, -0.0722656f,
-0.484863f, -0.0498047f, 0.484863f, -0.027832f, 0.469482f, -0.013916f, 0.454102f,
-0, 0.417969f, 0, 0.183105f, 0, 0.147461f, 0, 0.13208f, -0.013916f, 0.116699f, -0.027832f,
-0.116699f, -0.050293f, 0.116699f, -0.0722656f, 0.13208f, -0.0861816f, 0.147461f,
--0.100098f, 0.183105f, -0.100098f, 0.250488f, -0.100098f, 0.250488f, -0.248535f,
-0.0849609f, -0.491699f, 0.0517578f, -0.491699f, 0.036377f, -0.505859f, 0.0209961f,
--0.52002f, 0.0209961f, -0.541992f, 0.0209961f, -0.564453f, 0.036377f, -0.578369f,
-0.0517578f, -0.592285f, 0.0878906f, -0.592285f, 0.178711f, -0.591797f, 0.214844f,
--0.591797f, 0.230225f, -0.578125f, 0.245605f, -0.564453f, 0.245605f, -0.541992f,
-0.245605f, -0.508301f, 0.206055f, -0.491699f, 0.300781f, -0.352051f, 0.393555f, -0.491699f,
-0.371582f, -0.5f, 0.362305f, -0.512695f, 0.353027f, -0.525391f, 0.353027f, -0.541992f,
-0.353027f, -0.564453f, 0.368408f, -0.578125f, 0.383789f, -0.591797f, 0.419922f, -0.592285f,
-0.51416f, -0.591797f, 0.550293f, -0.591797f, 0.565674f, -0.578125f, 0.581055f, -0.564453f,
-0.581055f, -0.541992f, 0.581055f, -0.519531f, 0.56543f, -0.505615f, 0.549805f, -0.491699f,
-0.514648f, -0.491699f, 0.390137f, 0, 0.390137f, -0.0234375f, 0.352539f, -0.00341797f,
-0.307129f, 0.0065918f, 0.261719f, 0.0166016f, 0.224609f, 0.0166016f, 0.144043f, 0.0166016f,
-0.09375f, -0.026123f, 0.043457f, -0.0688477f, 0.043457f, -0.120605f, 0.043457f, -0.183594f,
-0.107666f, -0.237549f, 0.171875f, -0.291504f, 0.285156f, -0.291504f, 0.330566f, -0.291504f,
-0.390137f, -0.281738f, 0.390137f, -0.305664f, 0.390137f, -0.328125f, 0.37085f, -0.342285f,
-0.351562f, -0.356445f, 0.297363f, -0.356445f, 0.25293f, -0.356445f, 0.182129f, -0.338867f,
-0.155762f, -0.33252f, 0.141113f, -0.33252f, 0.121094f, -0.33252f, 0.107178f, -0.346924f,
-0.0932617f, -0.361328f, 0.0932617f, -0.383789f, 0.0932617f, -0.396484f, 0.0981445f,
--0.405762f, 0.103027f, -0.415039f, 0.111816f, -0.420654f, 0.120605f, -0.42627f, 0.148438f,
--0.434082f, 0.185547f, -0.444336f, 0.224121f, -0.450439f, 0.262695f, -0.456543f,
-0.293945f, -0.456543f, 0.387207f, -0.456543f, 0.438721f, -0.41626f, 0.490234f, -0.375977f,
-0.490234f, -0.306152f, 0.490234f, -0.100098f, 0.507324f, -0.100098f, 0.543457f, -0.100098f,
-0.558838f, -0.0861816f, 0.574219f, -0.0722656f, 0.574219f, -0.0498047f, 0.574219f,
--0.027832f, 0.558838f, -0.013916f, 0.543457f, 0, 0.507324f, 0, 0.390137f, -0.179199f,
-0.330078f, -0.190918f, 0.279297f, -0.190918f, 0.218262f, -0.190918f, 0.174316f, -0.161133f,
-0.146973f, -0.14209f, 0.146973f, -0.122559f, 0.146973f, -0.108398f, 0.160156f, -0.0996094f,
-0.18457f, -0.0834961f, 0.227051f, -0.0834961f, 0.263184f, -0.0834961f, 0.308838f,
--0.0976562f, 0.354492f, -0.111816f, 0.390137f, -0.13623f, 0.173828f, -0.633301f,
-0.173828f, -0.408691f, 0.210449f, -0.432617f, 0.248291f, -0.44458f, 0.286133f, -0.456543f,
-0.324707f, -0.456543f, 0.428711f, -0.456543f, 0.500977f, -0.384766f, 0.573242f, -0.312988f,
-0.573242f, -0.211426f, 0.573242f, -0.114258f, 0.504395f, -0.0490723f, 0.435547f,
-0.0161133f, 0.322754f, 0.0161133f, 0.282715f, 0.0161133f, 0.245605f, 0.00585938f,
-0.208496f, -0.00439453f, 0.173828f, -0.0244141f, 0.173828f, 0, 0.0566406f, 0, 0.0205078f,
-0, 0.00512695f, -0.013916f, -0.0102539f, -0.027832f, -0.0102539f, -0.050293f, -0.0102539f,
--0.0722656f, 0.00537109f, -0.0861816f, 0.0209961f, -0.100098f, 0.0566406f, -0.100098f,
-0.0737305f, -0.100098f, 0.0737305f, -0.533203f, 0.0566406f, -0.533203f, 0.0205078f,
--0.533203f, 0.00512695f, -0.547119f, -0.0102539f, -0.561035f, -0.0102539f, -0.583496f,
--0.0102539f, -0.605469f, 0.00512695f, -0.619385f, 0.0205078f, -0.633301f, 0.0566406f,
--0.633301f, 0.473145f, -0.208496f, 0.473145f, -0.270508f, 0.429688f, -0.313477f,
-0.38623f, -0.356445f, 0.323242f, -0.356445f, 0.260742f, -0.356445f, 0.217285f, -0.313477f,
-0.173828f, -0.270508f, 0.173828f, -0.209961f, 0.173828f, -0.154785f, 0.212891f, -0.119385f,
-0.251953f, -0.0839844f, 0.323242f, -0.0839844f, 0.394531f, -0.0839844f, 0.433838f,
--0.119385f, 0.473145f, -0.154785f, 0.473145f, -0.208496f, 0.55127f, -0.170898f, 0.140625f,
--0.170898f, 0.15625f, -0.131836f, 0.196045f, -0.10791f, 0.23584f, -0.0839844f, 0.303711f,
--0.0839844f, 0.359375f, -0.0839844f, 0.45166f, -0.10791f, 0.489746f, -0.117676f,
-0.504395f, -0.117676f, 0.524414f, -0.117676f, 0.538086f, -0.103516f, 0.551758f, -0.0893555f,
-0.551758f, -0.0678711f, 0.551758f, -0.0483398f, 0.537109f, -0.034668f, 0.517578f,
--0.0166016f, 0.441895f, -0.000244141f, 0.366211f, 0.0161133f, 0.296387f, 0.0161133f,
-0.17627f, 0.0161133f, 0.104248f, -0.0517578f, 0.0322266f, -0.119629f, 0.0322266f,
--0.21875f, 0.0322266f, -0.324219f, 0.110107f, -0.390381f, 0.187988f, -0.456543f,
-0.289551f, -0.456543f, 0.350586f, -0.456543f, 0.401611f, -0.435059f, 0.452637f, -0.413574f,
-0.477539f, -0.388672f, 0.512695f, -0.352539f, 0.535645f, -0.299316f, 0.55127f, -0.262207f,
-0.55127f, -0.213379f, 0.44043f, -0.270996f, 0.41748f, -0.313965f, 0.380371f, -0.335205f,
-0.343262f, -0.356445f, 0.291992f, -0.356445f, 0.241211f, -0.356445f, 0.204102f, -0.335205f,
-0.166992f, -0.313965f, 0.143555f, -0.270996f, 0.299316f, -0.343262f, 0.299316f, -0.100098f,
-0.441895f, -0.100098f, 0.478027f, -0.100098f, 0.493408f, -0.0861816f, 0.508789f,
--0.0722656f, 0.508789f, -0.0498047f, 0.508789f, -0.027832f, 0.493408f, -0.013916f,
-0.478027f, 0, 0.441895f, 0, 0.139648f, 0, 0.103516f, 0, 0.0881348f, -0.013916f, 0.0727539f,
--0.027832f, 0.0727539f, -0.050293f, 0.0727539f, -0.0722656f, 0.0881348f, -0.0861816f,
-0.103516f, -0.100098f, 0.139648f, -0.100098f, 0.199219f, -0.100098f, 0.199219f, -0.343262f,
-0.151367f, -0.343262f, 0.115234f, -0.343262f, 0.0998535f, -0.357178f, 0.0844727f,
--0.371094f, 0.0844727f, -0.393555f, 0.0844727f, -0.415527f, 0.0998535f, -0.429443f,
-0.115234f, -0.443359f, 0.151367f, -0.443359f, 0.199219f, -0.443359f, 0.199219f, -0.481445f,
-0.199219f, -0.546875f, 0.248291f, -0.590088f, 0.297363f, -0.633301f, 0.390625f, -0.633301f,
-0.432129f, -0.633301f, 0.486572f, -0.625732f, 0.541016f, -0.618164f, 0.556396f, -0.604492f,
-0.571777f, -0.59082f, 0.571777f, -0.569336f, 0.571777f, -0.546387f, 0.558105f, -0.531982f,
-0.544434f, -0.517578f, 0.524414f, -0.517578f, 0.515137f, -0.517578f, 0.496582f, -0.520996f,
-0.43457f, -0.533203f, 0.386719f, -0.533203f, 0.336914f, -0.533203f, 0.318115f, -0.518311f,
-0.299316f, -0.503418f, 0.299316f, -0.481445f, 0.299316f, -0.443359f, 0.453613f, -0.443359f,
-0.489746f, -0.443359f, 0.505127f, -0.429443f, 0.520508f, -0.415527f, 0.520508f, -0.393066f,
-0.520508f, -0.371094f, 0.505127f, -0.357178f, 0.489746f, -0.343262f, 0.453613f, -0.343262f,
-0.410156f, -0.413574f, 0.410156f, -0.443359f, 0.527344f, -0.443359f, 0.563477f, -0.443359f,
-0.578857f, -0.429443f, 0.594238f, -0.415527f, 0.594238f, -0.393066f, 0.594238f, -0.371094f,
-0.578857f, -0.357178f, 0.563477f, -0.343262f, 0.527344f, -0.343262f, 0.510254f, -0.343262f,
-0.510254f, 0.0209961f, 0.510254f, 0.0737305f, 0.488037f, 0.113037f, 0.46582f, 0.152344f,
-0.419922f, 0.180664f, 0.374023f, 0.208984f, 0.316406f, 0.208984f, 0.203125f, 0.208984f,
-0.166992f, 0.208984f, 0.151611f, 0.195068f, 0.13623f, 0.181152f, 0.13623f, 0.15918f,
-0.13623f, 0.136719f, 0.151611f, 0.122803f, 0.166992f, 0.108887f, 0.203125f, 0.108887f,
-0.313477f, 0.108887f, 0.359375f, 0.108887f, 0.384766f, 0.0839844f, 0.410156f, 0.059082f,
-0.410156f, 0.0209961f, 0.410156f, -0.027832f, 0.376953f, -0.00634766f, 0.342529f,
-0.00439453f, 0.308105f, 0.0151367f, 0.271973f, 0.0151367f, 0.169922f, 0.0151367f,
-0.101074f, -0.0529785f, 0.0322266f, -0.121094f, 0.0322266f, -0.221191f, 0.0322266f,
--0.321777f, 0.101074f, -0.389893f, 0.169922f, -0.458008f, 0.271973f, -0.458008f,
-0.310059f, -0.458008f, 0.344482f, -0.447021f, 0.378906f, -0.436035f, 0.410156f, -0.413574f,
-0.409668f, -0.22168f, 0.409668f, -0.276855f, 0.368896f, -0.317383f, 0.328125f, -0.35791f,
-0.270996f, -0.35791f, 0.213867f, -0.35791f, 0.173096f, -0.317383f, 0.132324f, -0.276855f,
-0.132324f, -0.22168f, 0.132324f, -0.166016f, 0.173096f, -0.125732f, 0.213867f, -0.0854492f,
-0.270996f, -0.0854492f, 0.328125f, -0.0854492f, 0.368896f, -0.125732f, 0.409668f,
--0.166016f, 0.409668f, -0.22168f, 0.145508f, -0.443359f, 0.145508f, -0.415039f, 0.169922f,
--0.438965f, 0.189697f, -0.447998f, 0.209473f, -0.457031f, 0.235352f, -0.457031f,
-0.257324f, -0.457031f, 0.278809f, -0.446289f, 0.300293f, -0.435547f, 0.320801f, -0.414062f,
-0.34668f, -0.435547f, 0.373291f, -0.446045f, 0.399902f, -0.456543f, 0.427734f, -0.456543f,
-0.483398f, -0.456543f, 0.518066f, -0.426758f, 0.563965f, -0.387695f, 0.563965f, -0.324219f,
-0.563965f, -0.100098f, 0.595215f, -0.100098f, 0.610352f, -0.0859375f, 0.625488f,
--0.0717773f, 0.625488f, -0.0498047f, 0.625488f, -0.027832f, 0.610352f, -0.013916f,
-0.595215f, 0, 0.559082f, 0, 0.463867f, 0, 0.463867f, -0.315918f, 0.463867f, -0.338867f,
-0.455566f, -0.347656f, 0.447266f, -0.356445f, 0.430176f, -0.356445f, 0.413574f, -0.356445f,
-0.399414f, -0.347656f, 0.381348f, -0.335449f, 0.355469f, -0.301758f, 0.355469f, -0.100098f,
-0.386719f, -0.100098f, 0.401855f, -0.0859375f, 0.416992f, -0.0717773f, 0.416992f,
--0.0498047f, 0.416992f, -0.027832f, 0.401855f, -0.013916f, 0.386719f, 0, 0.350586f,
-0, 0.255371f, 0, 0.255371f, -0.315918f, 0.255371f, -0.338379f, 0.246826f, -0.347412f,
-0.238281f, -0.356445f, 0.221191f, -0.356445f, 0.203613f, -0.356445f, 0.186523f, -0.345459f,
-0.169434f, -0.334473f, 0.145508f, -0.301758f, 0.145508f, -0.100098f, 0.176758f, -0.100098f,
-0.192139f, -0.0859375f, 0.20752f, -0.0717773f, 0.20752f, -0.0498047f, 0.20752f, -0.027832f,
-0.192139f, -0.013916f, 0.176758f, 0, 0.140625f, 0, 0.050293f, 0, 0.0141602f, 0, -0.0012207f,
--0.013916f, -0.0166016f, -0.027832f, -0.0166016f, -0.050293f, -0.0166016f, -0.0722656f,
--0.00146484f, -0.0861816f, 0.0136719f, -0.100098f, 0.0454102f, -0.100098f, 0.0454102f,
--0.343262f, 0.0136719f, -0.343262f, -0.00146484f, -0.357422f, -0.0166016f, -0.371582f,
--0.0166016f, -0.393555f, -0.0166016f, -0.415527f, -0.0012207f, -0.429443f, 0.0141602f,
--0.443359f, 0.050293f, -0.443359f, 0.19873f, -0.443359f, 0.19873f, -0.409668f, 0.226074f,
--0.433105f, 0.259033f, -0.444824f, 0.291992f, -0.456543f, 0.330566f, -0.456543f,
-0.419434f, -0.456543f, 0.471191f, -0.401367f, 0.512207f, -0.357422f, 0.512207f, -0.286133f,
-0.512207f, -0.100098f, 0.543945f, -0.100098f, 0.559082f, -0.0861816f, 0.574219f,
--0.0722656f, 0.574219f, -0.0498047f, 0.574219f, -0.027832f, 0.558838f, -0.013916f,
-0.543457f, 0, 0.507324f, 0, 0.416992f, 0, 0.380859f, 0, 0.365479f, -0.013916f, 0.350098f,
--0.027832f, 0.350098f, -0.050293f, 0.350098f, -0.0722656f, 0.365234f, -0.0861816f,
-0.380371f, -0.100098f, 0.412109f, -0.100098f, 0.412109f, -0.289062f, 0.412109f, -0.321777f,
-0.394531f, -0.336914f, 0.371582f, -0.356445f, 0.325684f, -0.356445f, 0.291016f, -0.356445f,
-0.264893f, -0.343018f, 0.23877f, -0.32959f, 0.19873f, -0.286133f, 0.19873f, -0.100098f,
-0.237305f, -0.100098f, 0.248535f, -0.0927734f, 0.272461f, -0.078125f, 0.272461f,
--0.0498047f, 0.272461f, -0.027832f, 0.25708f, -0.013916f, 0.241699f, 0, 0.205566f,
-0, 0.0917969f, 0, 0.0556641f, 0, 0.0402832f, -0.013916f, 0.0249023f, -0.027832f,
-0.0249023f, -0.050293f, 0.0249023f, -0.0776367f, 0.0483398f, -0.0927734f, 0.0600586f,
--0.100098f, 0.0986328f, -0.100098f, 0.0986328f, -0.343262f, 0.0668945f, -0.343262f,
-0.0517578f, -0.357422f, 0.0366211f, -0.371582f, 0.0366211f, -0.393555f, 0.0366211f,
--0.415527f, 0.052002f, -0.429443f, 0.0673828f, -0.443359f, 0.103516f, -0.443359f,
-0.560059f, -0.213379f, 0.560059f, -0.155762f, 0.528076f, -0.101807f, 0.496094f, -0.0478516f,
-0.432861f, -0.0158691f, 0.369629f, 0.0161133f, 0.300781f, 0.0161133f, 0.232422f,
-0.0161133f, 0.169922f, -0.0153809f, 0.107422f, -0.046875f, 0.074707f, -0.101074f,
-0.0419922f, -0.155273f, 0.0419922f, -0.214355f, 0.0419922f, -0.274414f, 0.0751953f,
--0.332275f, 0.108398f, -0.390137f, 0.170654f, -0.42334f, 0.23291f, -0.456543f, 0.300781f,
--0.456543f, 0.369141f, -0.456543f, 0.432373f, -0.422607f, 0.495605f, -0.388672f,
-0.527832f, -0.331299f, 0.560059f, -0.273926f, 0.560059f, -0.213379f, 0.459961f, -0.212891f,
-0.459961f, -0.26123f, 0.425293f, -0.301758f, 0.37793f, -0.356445f, 0.300781f, -0.356445f,
-0.23291f, -0.356445f, 0.1875f, -0.312988f, 0.14209f, -0.269531f, 0.14209f, -0.212402f,
-0.14209f, -0.165527f, 0.187988f, -0.124756f, 0.233887f, -0.0839844f, 0.300781f, -0.0839844f,
-0.368164f, -0.0839844f, 0.414062f, -0.124756f, 0.459961f, -0.165527f, 0.459961f,
--0.212891f, 0.175781f, -0.0551758f, 0.175781f, 0.108887f, 0.23584f, 0.108887f, 0.271973f,
-0.108887f, 0.287354f, 0.122803f, 0.302734f, 0.136719f, 0.302734f, 0.15918f, 0.302734f,
-0.181152f, 0.287354f, 0.195068f, 0.271973f, 0.208984f, 0.23584f, 0.208984f, 0.0585938f,
-0.208984f, 0.0224609f, 0.208984f, 0.00708008f, 0.195068f, -0.00830078f, 0.181152f,
--0.00830078f, 0.15918f, -0.00830078f, 0.136719f, 0.00732422f, 0.122803f, 0.0229492f,
-0.108887f, 0.0585938f, 0.108887f, 0.0756836f, 0.108887f, 0.0756836f, -0.343262f,
-0.0585938f, -0.343262f, 0.0224609f, -0.343262f, 0.00708008f, -0.357178f, -0.00830078f,
--0.371094f, -0.00830078f, -0.393555f, -0.00830078f, -0.415527f, 0.00708008f, -0.429443f,
-0.0224609f, -0.443359f, 0.0585938f, -0.443359f, 0.175781f, -0.443359f, 0.175781f,
--0.40918f, 0.210938f, -0.433105f, 0.248535f, -0.444824f, 0.286133f, -0.456543f, 0.325684f,
--0.456543f, 0.428223f, -0.456543f, 0.500488f, -0.386963f, 0.572754f, -0.317383f,
-0.572754f, -0.227539f, 0.572754f, -0.128418f, 0.487305f, -0.0639648f, 0.416016f,
--0.0102539f, 0.32666f, -0.0102539f, 0.288086f, -0.0102539f, 0.250488f, -0.0214844f,
-0.212891f, -0.0327148f, 0.175781f, -0.0551758f, 0.472656f, -0.227051f, 0.472656f,
--0.248047f, 0.456055f, -0.280518f, 0.439453f, -0.312988f, 0.405029f, -0.334717f,
-0.370605f, -0.356445f, 0.324219f, -0.356445f, 0.249512f, -0.356445f, 0.205566f, -0.300293f,
-0.175781f, -0.261719f, 0.175781f, -0.226074f, 0.175781f, -0.186035f, 0.218506f, -0.148193f,
-0.26123f, -0.110352f, 0.324219f, -0.110352f, 0.387695f, -0.110352f, 0.430176f, -0.147949f,
-0.472656f, -0.185547f, 0.472656f, -0.227051f, 0.279297f, -0.443359f, 0.279297f, -0.380859f,
-0.342285f, -0.42627f, 0.378662f, -0.441406f, 0.415039f, -0.456543f, 0.446777f, -0.456543f,
-0.495605f, -0.456543f, 0.541504f, -0.42041f, 0.572754f, -0.395996f, 0.572754f, -0.370605f,
-0.572754f, -0.349121f, 0.557861f, -0.334229f, 0.542969f, -0.319336f, 0.521973f, -0.319336f,
-0.503418f, -0.319336f, 0.48291f, -0.337891f, 0.462402f, -0.356445f, 0.446289f, -0.356445f,
-0.425293f, -0.356445f, 0.383545f, -0.330078f, 0.341797f, -0.303711f, 0.279297f, -0.250977f,
-0.279297f, -0.100098f, 0.421875f, -0.100098f, 0.458008f, -0.100098f, 0.473389f, -0.0861816f,
-0.48877f, -0.0722656f, 0.48877f, -0.0498047f, 0.48877f, -0.027832f, 0.473389f, -0.013916f,
-0.458008f, 0, 0.421875f, 0, 0.119629f, 0, 0.0834961f, 0, 0.0681152f, -0.013916f,
-0.0527344f, -0.027832f, 0.0527344f, -0.050293f, 0.0527344f, -0.0722656f, 0.0681152f,
--0.0861816f, 0.0834961f, -0.100098f, 0.119629f, -0.100098f, 0.179199f, -0.100098f,
-0.179199f, -0.343262f, 0.143066f, -0.343262f, 0.106934f, -0.343262f, 0.0915527f,
--0.357178f, 0.0761719f, -0.371094f, 0.0761719f, -0.393555f, 0.0761719f, -0.415527f,
-0.0915527f, -0.429443f, 0.106934f, -0.443359f, 0.143066f, -0.443359f, 0.408203f,
--0.326172f, 0.383789f, -0.341309f, 0.356934f, -0.348877f, 0.330078f, -0.356445f,
-0.300781f, -0.356445f, 0.242676f, -0.356445f, 0.208496f, -0.337402f, 0.193359f, -0.329102f,
-0.193359f, -0.319336f, 0.193359f, -0.308105f, 0.213867f, -0.297363f, 0.229492f, -0.289551f,
-0.283691f, -0.282227f, 0.383301f, -0.268555f, 0.422363f, -0.254883f, 0.473633f, -0.236816f,
-0.501465f, -0.201172f, 0.529297f, -0.165527f, 0.529297f, -0.125977f, 0.529297f, -0.0722656f,
-0.481934f, -0.0361328f, 0.414062f, 0.0161133f, 0.305664f, 0.0161133f, 0.262207f,
-0.0161133f, 0.225342f, 0.00854492f, 0.188477f, 0.000976562f, 0.157715f, -0.0136719f,
-0.150391f, -0.00732422f, 0.14209f, -0.00390625f, 0.133789f, -0.000488281f, 0.125f,
--0.000488281f, 0.101562f, -0.000488281f, 0.0876465f, -0.0158691f, 0.0737305f, -0.03125f,
-0.0737305f, -0.0673828f, 0.0737305f, -0.101074f, 0.0737305f, -0.137207f, 0.0876465f,
--0.152588f, 0.101562f, -0.167969f, 0.124023f, -0.167969f, 0.14209f, -0.167969f, 0.154297f,
--0.157959f, 0.166504f, -0.147949f, 0.17334f, -0.123535f, 0.196289f, -0.104004f, 0.228516f,
--0.0939941f, 0.260742f, -0.0839844f, 0.302734f, -0.0839844f, 0.371582f, -0.0839844f,
-0.409668f, -0.105469f, 0.427734f, -0.116211f, 0.427734f, -0.12793f, 0.427734f, -0.147461f,
-0.401855f, -0.160156f, 0.375977f, -0.172852f, 0.294922f, -0.181641f, 0.174316f, -0.194336f,
-0.133789f, -0.230469f, 0.0932617f, -0.266113f, 0.0932617f, -0.318359f, 0.0932617f,
--0.37207f, 0.138672f, -0.407715f, 0.200195f, -0.456543f, 0.299805f, -0.456543f, 0.334473f,
--0.456543f, 0.366455f, -0.449951f, 0.398438f, -0.443359f, 0.427734f, -0.429688f,
-0.437012f, -0.436523f, 0.445068f, -0.439941f, 0.453125f, -0.443359f, 0.459961f, -0.443359f,
-0.480469f, -0.443359f, 0.494141f, -0.427979f, 0.507812f, -0.412598f, 0.507812f, -0.376465f,
-0.507812f, -0.352051f, 0.507812f, -0.319336f, 0.5f, -0.307617f, 0.484375f, -0.285156f,
-0.45752f, -0.285156f, 0.439453f, -0.285156f, 0.425781f, -0.296387f, 0.412109f, -0.307617f,
-0.408203f, -0.326172f, 0.512695f, -0.443359f, 0.512695f, -0.100098f, 0.544434f, -0.100098f,
-0.55957f, -0.0859375f, 0.574707f, -0.0717773f, 0.574707f, -0.0498047f, 0.574707f,
--0.027832f, 0.559326f, -0.013916f, 0.543945f, 0, 0.507812f, 0, 0.412598f, 0, 0.412598f,
--0.0229492f, 0.369629f, -0.00341797f, 0.330566f, 0.00634766f, 0.291504f, 0.0161133f,
-0.256348f, 0.0161133f, 0.207031f, 0.0161133f, 0.170898f, -0.00463867f, 0.134766f,
--0.0253906f, 0.11377f, -0.0620117f, 0.0986328f, -0.0883789f, 0.0986328f, -0.12793f,
-0.0986328f, -0.343262f, 0.081543f, -0.343262f, 0.0454102f, -0.343262f, 0.0300293f,
--0.357178f, 0.0146484f, -0.371094f, 0.0146484f, -0.393555f, 0.0146484f, -0.415527f,
-0.0300293f, -0.429443f, 0.0454102f, -0.443359f, 0.081543f, -0.443359f, 0.19873f,
--0.443359f, 0.19873f, -0.145508f, 0.19873f, -0.11377f, 0.214111f, -0.098877f, 0.229492f,
--0.0839844f, 0.26123f, -0.0839844f, 0.291504f, -0.0839844f, 0.326416f, -0.0959473f,
-0.361328f, -0.10791f, 0.412598f, -0.13916f, 0.412598f, -0.343262f, 0.376465f, -0.343262f,
-0.340332f, -0.343262f, 0.324951f, -0.357178f, 0.30957f, -0.371094f, 0.30957f, -0.393555f,
-0.30957f, -0.415527f, 0.324951f, -0.429443f, 0.340332f, -0.443359f, 0.376465f, -0.443359f,
-0.244141f, -0.00341797f, 0.0708008f, -0.343262f, 0.0463867f, -0.346191f, 0.0336914f,
--0.359863f, 0.0209961f, -0.373535f, 0.0209961f, -0.393066f, 0.0209961f, -0.415527f,
-0.036377f, -0.429443f, 0.0517578f, -0.443359f, 0.0878906f, -0.443359f, 0.179199f,
--0.443359f, 0.215332f, -0.443359f, 0.230713f, -0.429443f, 0.246094f, -0.415527f,
-0.246094f, -0.393066f, 0.246094f, -0.371094f, 0.230713f, -0.357178f, 0.215332f, -0.343262f,
-0.182129f, -0.343262f, 0.300293f, -0.113281f, 0.41748f, -0.343262f, 0.385254f, -0.343262f,
-0.369873f, -0.357178f, 0.354492f, -0.371094f, 0.354492f, -0.393555f, 0.354492f, -0.415527f,
-0.369873f, -0.429443f, 0.385254f, -0.443359f, 0.421387f, -0.443359f, 0.515625f, -0.443359f,
-0.55127f, -0.443359f, 0.56665f, -0.429443f, 0.582031f, -0.415527f, 0.582031f, -0.393066f,
-0.582031f, -0.373047f, 0.568848f, -0.359131f, 0.555664f, -0.345215f, 0.529785f, -0.343262f,
-0.300293f, 0.108887f, 0.337891f, 0.108887f, 0.349609f, 0.116211f, 0.373047f, 0.131348f,
-0.373047f, 0.15918f, 0.373047f, 0.181152f, 0.357666f, 0.195068f, 0.342285f, 0.208984f,
-0.306152f, 0.208984f, 0.0878906f, 0.208984f, 0.0517578f, 0.208984f, 0.036377f, 0.195068f,
-0.0209961f, 0.181152f, 0.0209961f, 0.15918f, 0.0209961f, 0.136719f, 0.036377f, 0.122803f,
-0.0517578f, 0.108887f, 0.0878906f, 0.108887f, 0.1875f, 0.108887f
-};
-
-const unsigned char CourierNewkBoldVerbs[] = {
-6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 5, 0, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1,
-1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-5, 0, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2,
-2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6
-};
-
-const unsigned CourierNewkBoldCharCodes[] = {
-32, 65, 72, 84, 87,
-89, 97, 98, 101, 102, 103, 109, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed CourierNewkBoldWidths[] = {
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
-};
-
-const int CourierNewkBoldCharCodesCount = (int) SK_ARRAY_COUNT(CourierNewkBoldCharCodes);
-
-const SkPaint::FontMetrics CourierNewkBoldMetrics = {
-0x00000003, -1.22119f, -0.83252f, 0.300293f, 0.710449f, 0, 0.893555f, 0, -0.191895f,
-0.70166f, 0.458008f, 0, 0.100098f, 0.23291f
-};
-
-const SkScalar CourierNewkItalicPoints[] = {
-0.496582f, -0.190918f, 0.227051f, -0.190918f, 0.139648f, -0.0410156f, 0.218262f, -0.0410156f,
-0.232422f, -0.0410156f, 0.237305f, -0.0368652f, 0.242188f, -0.0327148f, 0.242188f,
--0.0249023f, 0.242188f, -0.0146484f, 0.233887f, -0.00732422f, 0.225586f, 0, 0.209473f,
-0, 0.0566406f, 0, 0.0429688f, 0, 0.0380859f, -0.00439453f, 0.0332031f, -0.00878906f,
-0.0332031f, -0.0166016f, 0.0332031f, -0.0263672f, 0.0412598f, -0.0336914f, 0.0493164f,
--0.0410156f, 0.0654297f, -0.0410156f, 0.0966797f, -0.0410156f, 0.382324f, -0.530273f,
-0.26123f, -0.530273f, 0.247559f, -0.530273f, 0.242676f, -0.534424f, 0.237793f, -0.538574f,
-0.237793f, -0.546875f, 0.237793f, -0.556641f, 0.24585f, -0.563965f, 0.253906f, -0.571289f,
-0.27002f, -0.571289f, 0.476074f, -0.571289f, 0.563965f, -0.0410156f, 0.595703f, -0.0410156f,
-0.609375f, -0.0410156f, 0.614258f, -0.0368652f, 0.619141f, -0.0327148f, 0.619141f,
--0.0249023f, 0.619141f, -0.0146484f, 0.611084f, -0.00732422f, 0.603027f, 0, 0.586914f,
-0, 0.433594f, 0, 0.419922f, 0, 0.415039f, -0.00439453f, 0.410156f, -0.00878906f,
-0.410156f, -0.0166016f, 0.410156f, -0.0263672f, 0.418213f, -0.0336914f, 0.42627f,
--0.0410156f, 0.442383f, -0.0410156f, 0.520996f, -0.0410156f, 0.489746f, -0.231934f,
-0.439941f, -0.530273f, 0.424805f, -0.530273f, 0.250977f, -0.231934f, 0.49707f, -0.276367f,
-0.224609f, -0.276367f, 0.174805f, -0.0410156f, 0.221191f, -0.0410156f, 0.243652f,
--0.0410156f, 0.248535f, -0.0368652f, 0.253418f, -0.0327148f, 0.253418f, -0.0249023f,
-0.253418f, -0.0146484f, 0.245361f, -0.00732422f, 0.237305f, 0, 0.221191f, 0, 0.0786133f,
-0, 0.0649414f, 0, 0.0605469f, -0.00561523f, 0.0561523f, -0.0112305f, 0.0561523f,
--0.019043f, 0.0561523f, -0.0288086f, 0.0637207f, -0.0349121f, 0.0712891f, -0.0410156f,
-0.0874023f, -0.0410156f, 0.133789f, -0.0410156f, 0.237793f, -0.530273f, 0.191895f,
--0.530273f, 0.171387f, -0.530273f, 0.164307f, -0.53418f, 0.157227f, -0.538086f, 0.158203f,
--0.54834f, 0.158203f, -0.557617f, 0.164795f, -0.563721f, 0.171387f, -0.569824f, 0.192383f,
--0.571777f, 0.32959f, -0.571777f, 0.347168f, -0.569336f, 0.351807f, -0.567627f, 0.356445f,
--0.565918f, 0.35791f, -0.556152f, 0.35791f, -0.545898f, 0.352051f, -0.539062f, 0.346191f,
--0.532227f, 0.325195f, -0.530273f, 0.278809f, -0.530273f, 0.233398f, -0.317383f,
-0.505859f, -0.317383f, 0.550781f, -0.530273f, 0.504395f, -0.530273f, 0.481934f, -0.530273f,
-0.477051f, -0.534424f, 0.472168f, -0.538574f, 0.472168f, -0.546875f, 0.472168f, -0.556641f,
-0.480225f, -0.563965f, 0.488281f, -0.571289f, 0.504395f, -0.571289f, 0.626465f, -0.571289f,
-0.652832f, -0.570801f, 0.661133f, -0.567383f, 0.669434f, -0.563965f, 0.67041f, -0.555176f,
-0.671387f, -0.544922f, 0.664307f, -0.538574f, 0.657227f, -0.532227f, 0.638672f, -0.530273f,
-0.592285f, -0.530273f, 0.488281f, -0.0410156f, 0.53418f, -0.0410156f, 0.554199f,
--0.0419922f, 0.560303f, -0.0354004f, 0.566406f, -0.0288086f, 0.566406f, -0.0209961f,
-0.566406f, -0.0107422f, 0.556396f, -0.00537109f, 0.546387f, 0, 0.525391f, 0, 0.393066f,
-0, 0.379395f, 0, 0.373779f, -0.00366211f, 0.368164f, -0.00732422f, 0.368164f, -0.0151367f,
-0.368164f, -0.0249023f, 0.372559f, -0.0317383f, 0.376953f, -0.0385742f, 0.400391f,
--0.0410156f, 0.446777f, -0.0410156f, 0.433105f, -0.530273f, 0.329102f, -0.0410156f,
-0.435547f, -0.0410156f, 0.449219f, -0.0410156f, 0.454102f, -0.0368652f, 0.458984f,
--0.0327148f, 0.458984f, -0.0249023f, 0.458984f, -0.0146484f, 0.450928f, -0.00732422f,
-0.442871f, 0, 0.426758f, 0, 0.172363f, 0, 0.158691f, 0, 0.153809f, -0.00439453f,
-0.148926f, -0.00878906f, 0.148926f, -0.0166016f, 0.148926f, -0.0263672f, 0.156982f,
--0.0336914f, 0.165039f, -0.0410156f, 0.181152f, -0.0410156f, 0.287598f, -0.0410156f,
-0.391602f, -0.530273f, 0.223633f, -0.530273f, 0.193359f, -0.388184f, 0.19043f, -0.373047f,
-0.18335f, -0.366699f, 0.17627f, -0.360352f, 0.166992f, -0.360352f, 0.159668f, -0.360352f,
-0.155029f, -0.36499f, 0.150391f, -0.369629f, 0.150391f, -0.375488f, 0.150391f, -0.379883f,
-0.152344f, -0.388184f, 0.191406f, -0.571289f, 0.650879f, -0.571289f, 0.611816f, -0.388184f,
-0.608887f, -0.373047f, 0.601562f, -0.366699f, 0.594238f, -0.360352f, 0.584961f, -0.360352f,
-0.578125f, -0.360352f, 0.573486f, -0.36499f, 0.568848f, -0.369629f, 0.568848f, -0.375488f,
-0.568848f, -0.379883f, 0.570801f, -0.388184f, 0.601074f, -0.530273f, 0.47998f, 0,
-0.416016f, 0, 0.385742f, -0.405762f, 0.185547f, 0, 0.121094f, 0, 0.173828f, -0.530273f,
-0.158691f, -0.530273f, 0.14502f, -0.530273f, 0.139893f, -0.534424f, 0.134766f, -0.538574f,
-0.134766f, -0.546875f, 0.134766f, -0.556641f, 0.143066f, -0.563965f, 0.151367f, -0.571289f,
-0.16748f, -0.571289f, 0.319824f, -0.571289f, 0.333496f, -0.571289f, 0.338379f, -0.567139f,
-0.343262f, -0.562988f, 0.343262f, -0.555176f, 0.343262f, -0.544922f, 0.335205f, -0.537598f,
-0.327148f, -0.530273f, 0.311035f, -0.530273f, 0.214844f, -0.530273f, 0.166504f, -0.046875f,
-0.362305f, -0.444824f, 0.424805f, -0.444824f, 0.454102f, -0.046875f, 0.609863f, -0.530273f,
-0.513672f, -0.530273f, 0.5f, -0.530273f, 0.495117f, -0.534424f, 0.490234f, -0.538574f,
-0.490234f, -0.546875f, 0.490234f, -0.556641f, 0.498291f, -0.563965f, 0.506348f, -0.571289f,
-0.522461f, -0.571289f, 0.674316f, -0.571289f, 0.687988f, -0.571289f, 0.692871f, -0.567139f,
-0.697754f, -0.562988f, 0.697754f, -0.555176f, 0.697754f, -0.547852f, 0.692871f, -0.54126f,
-0.687988f, -0.534668f, 0.681152f, -0.532227f, 0.67627f, -0.530273f, 0.650391f, -0.530273f,
-0.375977f, -0.257812f, 0.330078f, -0.0410156f, 0.436523f, -0.0410156f, 0.450195f,
--0.0410156f, 0.455078f, -0.0368652f, 0.459961f, -0.0327148f, 0.459961f, -0.0249023f,
-0.459961f, -0.0146484f, 0.451904f, -0.00732422f, 0.443848f, 0, 0.427734f, 0, 0.17334f,
-0, 0.159668f, 0, 0.154785f, -0.00439453f, 0.149902f, -0.00878906f, 0.149902f, -0.0166016f,
-0.149902f, -0.0263672f, 0.157959f, -0.0336914f, 0.166016f, -0.0410156f, 0.182129f,
--0.0410156f, 0.288574f, -0.0410156f, 0.334961f, -0.257812f, 0.212402f, -0.530273f,
-0.187988f, -0.530273f, 0.174316f, -0.530273f, 0.169434f, -0.534424f, 0.164551f, -0.538574f,
-0.164551f, -0.546875f, 0.164551f, -0.556641f, 0.172607f, -0.563965f, 0.180664f, -0.571289f,
-0.196777f, -0.571289f, 0.30957f, -0.571289f, 0.323242f, -0.571289f, 0.328125f, -0.567139f,
-0.333008f, -0.562988f, 0.333008f, -0.555176f, 0.333008f, -0.544922f, 0.324951f, -0.537598f,
-0.316895f, -0.530273f, 0.300781f, -0.530273f, 0.260254f, -0.530273f, 0.364258f, -0.299316f,
-0.563477f, -0.530273f, 0.523438f, -0.530273f, 0.509277f, -0.530273f, 0.504395f, -0.534424f,
-0.499512f, -0.538574f, 0.499512f, -0.546875f, 0.499512f, -0.556641f, 0.507568f, -0.563965f,
-0.515625f, -0.571289f, 0.531738f, -0.571289f, 0.644531f, -0.571289f, 0.658203f, -0.571289f,
-0.663086f, -0.567139f, 0.667969f, -0.562988f, 0.667969f, -0.555176f, 0.667969f, -0.544922f,
-0.659912f, -0.537598f, 0.651855f, -0.530273f, 0.635742f, -0.530273f, 0.611328f, -0.530273f,
-0.418457f, 0, 0.430664f, -0.059082f, 0.325684f, 0.0161133f, 0.223633f, 0.0161133f,
-0.158203f, 0.0161133f, 0.125f, -0.0131836f, 0.0917969f, -0.0424805f, 0.0917969f,
--0.0864258f, 0.0917969f, -0.15332f, 0.150391f, -0.201172f, 0.223145f, -0.26123f,
-0.340332f, -0.26123f, 0.396484f, -0.26123f, 0.470703f, -0.246094f, 0.484863f, -0.3125f,
-0.486328f, -0.319824f, 0.486328f, -0.327148f, 0.486328f, -0.355469f, 0.463867f, -0.372559f,
-0.433594f, -0.395996f, 0.377441f, -0.395996f, 0.330078f, -0.395996f, 0.231934f, -0.366699f,
-0.220703f, -0.363281f, 0.21582f, -0.363281f, 0.209473f, -0.363281f, 0.205078f, -0.367676f,
-0.200684f, -0.37207f, 0.200684f, -0.379395f, 0.200684f, -0.388672f, 0.207764f, -0.395996f,
-0.214844f, -0.40332f, 0.262695f, -0.415527f, 0.347168f, -0.4375f, 0.388184f, -0.4375f,
-0.458008f, -0.4375f, 0.493408f, -0.406738f, 0.528809f, -0.375977f, 0.528809f, -0.337402f,
-0.528809f, -0.324707f, 0.525879f, -0.3125f, 0.468262f, -0.0410156f, 0.523438f, -0.0410156f,
-0.537109f, -0.0410156f, 0.541992f, -0.0368652f, 0.546875f, -0.0327148f, 0.546875f,
--0.0249023f, 0.546875f, -0.0146484f, 0.538818f, -0.00732422f, 0.530762f, 0, 0.514648f,
-0, 0.461914f, -0.204102f, 0.406738f, -0.220215f, 0.335938f, -0.220215f, 0.237793f,
--0.220215f, 0.178711f, -0.174805f, 0.134277f, -0.140625f, 0.134277f, -0.0966797f,
-0.134277f, -0.0649414f, 0.157471f, -0.0449219f, 0.180664f, -0.0249023f, 0.229004f,
--0.0249023f, 0.282227f, -0.0249023f, 0.33252f, -0.0456543f, 0.382812f, -0.0664062f,
-0.442383f, -0.11377f, 0.275879f, -0.612793f, 0.218262f, -0.34082f, 0.312012f, -0.4375f,
-0.41748f, -0.4375f, 0.494141f, -0.4375f, 0.543701f, -0.388184f, 0.593262f, -0.338867f,
-0.593262f, -0.263184f, 0.593262f, -0.196289f, 0.555664f, -0.129395f, 0.518066f, -0.0625f,
-0.451416f, -0.0231934f, 0.384766f, 0.0161133f, 0.321777f, 0.0161133f, 0.213379f,
-0.0161133f, 0.162598f, -0.0805664f, 0.145508f, 0, 0.0493164f, 0, 0.0356445f, 0, 0.0307617f,
--0.00439453f, 0.0258789f, -0.00878906f, 0.0258789f, -0.0166016f, 0.0258789f, -0.0263672f,
-0.0339355f, -0.0336914f, 0.0419922f, -0.0410156f, 0.0581055f, -0.0410156f, 0.113281f,
--0.0410156f, 0.225586f, -0.571289f, 0.170898f, -0.571289f, 0.157227f, -0.571289f,
-0.152344f, -0.575684f, 0.147461f, -0.580078f, 0.147461f, -0.587891f, 0.147461f, -0.597656f,
-0.155518f, -0.605225f, 0.163574f, -0.612793f, 0.179688f, -0.612793f, 0.32959f, -0.0249023f,
-0.368164f, -0.0249023f, 0.406982f, -0.0427246f, 0.445801f, -0.0605469f, 0.477539f,
--0.0900879f, 0.509277f, -0.119629f, 0.530029f, -0.162842f, 0.550781f, -0.206055f,
-0.550781f, -0.254883f, 0.550781f, -0.313965f, 0.509521f, -0.35498f, 0.468262f, -0.395996f,
-0.407227f, -0.395996f, 0.35791f, -0.395996f, 0.301758f, -0.363525f, 0.245605f, -0.331055f,
-0.21582f, -0.2771f, 0.186035f, -0.223145f, 0.186035f, -0.167969f, 0.186035f, -0.107422f,
-0.227295f, -0.0661621f, 0.268555f, -0.0249023f, 0.32959f, -0.0249023f, 0.56543f,
--0.20166f, 0.147461f, -0.20166f, 0.145996f, -0.186523f, 0.145996f, -0.178711f, 0.145996f,
--0.111816f, 0.191406f, -0.0683594f, 0.236816f, -0.0249023f, 0.314453f, -0.0249023f,
-0.359863f, -0.0249023f, 0.413086f, -0.0397949f, 0.466309f, -0.0546875f, 0.504395f,
--0.0800781f, 0.515625f, -0.0874023f, 0.522461f, -0.0874023f, 0.528809f, -0.0874023f,
-0.533203f, -0.0827637f, 0.537598f, -0.078125f, 0.537598f, -0.0708008f, 0.537598f,
--0.0620117f, 0.529785f, -0.0541992f, 0.507324f, -0.0302734f, 0.439941f, -0.00708008f,
-0.372559f, 0.0161133f, 0.303223f, 0.0161133f, 0.213379f, 0.0161133f, 0.158936f, -0.0371094f,
-0.104492f, -0.090332f, 0.104492f, -0.172363f, 0.104492f, -0.226562f, 0.12793f, -0.274658f,
-0.151367f, -0.322754f, 0.189697f, -0.357666f, 0.228027f, -0.392578f, 0.278076f, -0.415039f,
-0.328125f, -0.4375f, 0.387207f, -0.4375f, 0.471191f, -0.4375f, 0.522217f, -0.388184f,
-0.573242f, -0.338867f, 0.573242f, -0.262207f, 0.573242f, -0.236816f, 0.56543f, -0.20166f,
-0.532227f, -0.243164f, 0.534668f, -0.310547f, 0.492188f, -0.353516f, 0.449219f, -0.395996f,
-0.376953f, -0.395996f, 0.306641f, -0.395996f, 0.245605f, -0.354492f, 0.18457f, -0.312988f,
-0.15625f, -0.243164f, 0.354004f, -0.381348f, 0.281738f, -0.0410156f, 0.461914f, -0.0410156f,
-0.475586f, -0.0410156f, 0.480469f, -0.0368652f, 0.485352f, -0.0327148f, 0.485352f,
--0.0249023f, 0.485352f, -0.0146484f, 0.477295f, -0.00732422f, 0.469238f, 0, 0.453125f,
-0, 0.132324f, 0, 0.118652f, 0, 0.11377f, -0.00439453f, 0.108887f, -0.00878906f, 0.108887f,
--0.0166016f, 0.108887f, -0.0263672f, 0.116943f, -0.0336914f, 0.125f, -0.0410156f,
-0.141113f, -0.0410156f, 0.240234f, -0.0410156f, 0.3125f, -0.381348f, 0.223633f, -0.381348f,
-0.209961f, -0.381348f, 0.205078f, -0.385742f, 0.200195f, -0.390137f, 0.200195f, -0.397949f,
-0.200195f, -0.407715f, 0.208252f, -0.415283f, 0.216309f, -0.422852f, 0.232422f, -0.422852f,
-0.321289f, -0.422852f, 0.334473f, -0.484863f, 0.345703f, -0.537109f, 0.395752f, -0.574951f,
-0.445801f, -0.612793f, 0.515625f, -0.612793f, 0.569824f, -0.612793f, 0.632324f, -0.603027f,
-0.65918f, -0.598633f, 0.66333f, -0.594238f, 0.66748f, -0.589844f, 0.66748f, -0.583496f,
-0.66748f, -0.573242f, 0.659912f, -0.565918f, 0.652344f, -0.558594f, 0.640625f, -0.558594f,
-0.637207f, -0.558594f, 0.628418f, -0.560059f, 0.557129f, -0.571289f, 0.507324f, -0.571289f,
-0.452148f, -0.571289f, 0.41748f, -0.544678f, 0.382812f, -0.518066f, 0.375977f, -0.484863f,
-0.362793f, -0.422852f, 0.554688f, -0.422852f, 0.568359f, -0.422852f, 0.572754f, -0.418945f,
-0.578125f, -0.414062f, 0.578125f, -0.40625f, 0.578125f, -0.396484f, 0.570068f, -0.388916f,
-0.562012f, -0.381348f, 0.545898f, -0.381348f, 0.511719f, -0.347656f, 0.527832f, -0.422852f,
-0.624023f, -0.422852f, 0.637695f, -0.422852f, 0.64209f, -0.418945f, 0.647949f, -0.414062f,
-0.647949f, -0.40625f, 0.647949f, -0.396484f, 0.639648f, -0.388916f, 0.631348f, -0.381348f,
-0.615234f, -0.381348f, 0.560547f, -0.381348f, 0.473145f, 0.0283203f, 0.464844f, 0.0678711f,
-0.441406f, 0.100098f, 0.424805f, 0.122559f, 0.391113f, 0.145996f, 0.357422f, 0.169434f,
-0.333984f, 0.178955f, 0.310547f, 0.188477f, 0.272461f, 0.188477f, 0.15625f, 0.188477f,
-0.142578f, 0.188477f, 0.137695f, 0.184082f, 0.132812f, 0.179688f, 0.132812f, 0.172363f,
-0.132812f, 0.162109f, 0.140869f, 0.154541f, 0.148926f, 0.146973f, 0.165039f, 0.146973f,
-0.282715f, 0.147461f, 0.317383f, 0.147461f, 0.350098f, 0.129883f, 0.382812f, 0.112305f,
-0.410645f, 0.0751953f, 0.42627f, 0.0546875f, 0.433105f, 0.0224609f, 0.459473f, -0.100586f,
-0.374023f, -0.0102539f, 0.268555f, -0.0102539f, 0.197754f, -0.0102539f, 0.150879f,
--0.0578613f, 0.104004f, -0.105469f, 0.104004f, -0.180176f, 0.104004f, -0.232422f,
-0.128418f, -0.280518f, 0.152832f, -0.328613f, 0.1875f, -0.361572f, 0.222168f, -0.394531f,
-0.266357f, -0.416016f, 0.310547f, -0.4375f, 0.361328f, -0.4375f, 0.465332f, -0.4375f,
-0.511719f, -0.347656f, 0.279785f, -0.0517578f, 0.321289f, -0.0517578f, 0.35791f,
--0.0688477f, 0.394531f, -0.0859375f, 0.423828f, -0.114014f, 0.453125f, -0.14209f,
-0.471436f, -0.181885f, 0.489746f, -0.22168f, 0.489746f, -0.263184f, 0.489746f, -0.320312f,
-0.45166f, -0.358154f, 0.413574f, -0.395996f, 0.355957f, -0.395996f, 0.274414f, -0.395996f,
-0.210205f, -0.332031f, 0.145996f, -0.268066f, 0.145996f, -0.1875f, 0.145996f, -0.12793f,
-0.184082f, -0.0898438f, 0.222168f, -0.0517578f, 0.279785f, -0.0517578f, 0.203125f,
--0.422852f, 0.194336f, -0.381348f, 0.258301f, -0.4375f, 0.312012f, -0.4375f, 0.341309f,
--0.4375f, 0.362305f, -0.42041f, 0.383301f, -0.40332f, 0.392578f, -0.369629f, 0.427246f,
--0.403809f, 0.458984f, -0.420654f, 0.490723f, -0.4375f, 0.519531f, -0.4375f, 0.555664f,
--0.4375f, 0.57959f, -0.412842f, 0.603516f, -0.388184f, 0.603516f, -0.349121f, 0.603516f,
--0.339355f, 0.600586f, -0.327637f, 0.540039f, -0.0410156f, 0.574219f, -0.0410156f,
-0.588379f, -0.0410156f, 0.593262f, -0.0368652f, 0.598145f, -0.0327148f, 0.598145f,
--0.0249023f, 0.598145f, -0.0146484f, 0.589844f, -0.00732422f, 0.581543f, 0, 0.56543f,
-0, 0.489746f, 0, 0.558594f, -0.32373f, 0.560547f, -0.332031f, 0.560547f, -0.340332f,
-0.560547f, -0.366211f, 0.546631f, -0.381104f, 0.532715f, -0.395996f, 0.512207f, -0.395996f,
-0.489746f, -0.395996f, 0.465332f, -0.382324f, 0.432617f, -0.363281f, 0.389648f, -0.312988f,
-0.331543f, -0.0410156f, 0.366211f, -0.0410156f, 0.379883f, -0.0410156f, 0.384766f,
--0.0368652f, 0.389648f, -0.0327148f, 0.389648f, -0.0249023f, 0.389648f, -0.0146484f,
-0.381592f, -0.00732422f, 0.373535f, 0, 0.357422f, 0, 0.281738f, 0, 0.350098f, -0.320801f,
-0.352051f, -0.330566f, 0.352051f, -0.339844f, 0.352051f, -0.364746f, 0.337646f, -0.380371f,
-0.323242f, -0.395996f, 0.304199f, -0.395996f, 0.282227f, -0.395996f, 0.258301f, -0.382812f,
-0.223633f, -0.362793f, 0.179688f, -0.312988f, 0.12207f, -0.0410156f, 0.15625f, -0.0410156f,
-0.17041f, -0.0410156f, 0.175293f, -0.0368652f, 0.180176f, -0.0327148f, 0.180176f,
--0.0249023f, 0.180176f, -0.0146484f, 0.171875f, -0.00732422f, 0.163574f, 0, 0.147461f,
-0, 0.0375977f, 0, 0.0239258f, 0, 0.019043f, -0.00439453f, 0.0141602f, -0.00878906f,
-0.0141602f, -0.0166016f, 0.0141602f, -0.0263672f, 0.0222168f, -0.0336914f, 0.0302734f,
--0.0410156f, 0.0463867f, -0.0410156f, 0.0805664f, -0.0410156f, 0.15332f, -0.381348f,
-0.118652f, -0.381348f, 0.10498f, -0.381348f, 0.100098f, -0.385742f, 0.0952148f, -0.390137f,
-0.0952148f, -0.397949f, 0.0952148f, -0.407715f, 0.103271f, -0.415283f, 0.111328f,
--0.422852f, 0.127441f, -0.422852f, 0.257324f, -0.422852f, 0.244141f, -0.36084f, 0.297852f,
--0.405273f, 0.335693f, -0.421387f, 0.373535f, -0.4375f, 0.41748f, -0.4375f, 0.478027f,
--0.4375f, 0.512451f, -0.405273f, 0.546875f, -0.373047f, 0.546875f, -0.321777f, 0.546875f,
--0.312012f, 0.544434f, -0.299316f, 0.489258f, -0.0410156f, 0.523926f, -0.0410156f,
-0.537598f, -0.0410156f, 0.54248f, -0.0368652f, 0.547363f, -0.0327148f, 0.547363f,
--0.0249023f, 0.547363f, -0.0146484f, 0.539307f, -0.00732422f, 0.53125f, 0, 0.515137f,
-0, 0.404785f, 0, 0.391113f, 0, 0.38623f, -0.00439453f, 0.381348f, -0.00878906f, 0.381348f,
--0.0166016f, 0.381348f, -0.0263672f, 0.389404f, -0.0336914f, 0.397461f, -0.0410156f,
-0.413574f, -0.0410156f, 0.448242f, -0.0410156f, 0.501465f, -0.29248f, 0.503906f,
--0.303711f, 0.503906f, -0.313965f, 0.503906f, -0.349609f, 0.479004f, -0.372803f,
-0.454102f, -0.395996f, 0.407715f, -0.395996f, 0.365234f, -0.395996f, 0.331787f, -0.378906f,
-0.29834f, -0.361816f, 0.230957f, -0.29834f, 0.17627f, -0.0410156f, 0.222656f, -0.0410156f,
-0.236328f, -0.0410156f, 0.241211f, -0.0368652f, 0.246094f, -0.0327148f, 0.246094f,
--0.0249023f, 0.246094f, -0.0146484f, 0.238037f, -0.00732422f, 0.22998f, 0, 0.213867f,
-0, 0.0800781f, 0, 0.0664062f, 0, 0.0615234f, -0.00439453f, 0.0566406f, -0.00878906f,
-0.0566406f, -0.0166016f, 0.0566406f, -0.0263672f, 0.0646973f, -0.0336914f, 0.0727539f,
--0.0410156f, 0.0888672f, -0.0410156f, 0.135254f, -0.0410156f, 0.20752f, -0.381348f,
-0.172852f, -0.381348f, 0.15918f, -0.381348f, 0.154297f, -0.385742f, 0.149414f, -0.390137f,
-0.149414f, -0.397949f, 0.149414f, -0.407715f, 0.157471f, -0.415283f, 0.165527f, -0.422852f,
-0.181641f, -0.422852f, 0.294922f, 0.0161133f, 0.214355f, 0.0161133f, 0.162598f, -0.0349121f,
-0.11084f, -0.0859375f, 0.11084f, -0.164551f, 0.11084f, -0.228516f, 0.149902f, -0.294678f,
-0.188965f, -0.36084f, 0.25708f, -0.39917f, 0.325195f, -0.4375f, 0.39502f, -0.4375f,
-0.475098f, -0.4375f, 0.526855f, -0.386719f, 0.578613f, -0.335938f, 0.578613f, -0.260254f,
-0.578613f, -0.193848f, 0.540771f, -0.128418f, 0.50293f, -0.0629883f, 0.434326f, -0.0234375f,
-0.365723f, 0.0161133f, 0.294922f, 0.0161133f, 0.304199f, -0.0249023f, 0.361816f,
--0.0249023f, 0.418213f, -0.057373f, 0.474609f, -0.0898438f, 0.505615f, -0.143555f,
-0.536621f, -0.197266f, 0.536621f, -0.251465f, 0.536621f, -0.312988f, 0.494141f, -0.354492f,
-0.45166f, -0.395996f, 0.385742f, -0.395996f, 0.338379f, -0.395996f, 0.297607f, -0.377197f,
-0.256836f, -0.358398f, 0.225342f, -0.328857f, 0.193848f, -0.299316f, 0.17334f, -0.258057f,
-0.152832f, -0.216797f, 0.152832f, -0.172852f, 0.152832f, -0.108887f, 0.195312f, -0.0668945f,
-0.237793f, -0.0249023f, 0.304199f, -0.0249023f, 0.235352f, -0.422852f, 0.219727f,
--0.348145f, 0.266602f, -0.393555f, 0.313232f, -0.415527f, 0.359863f, -0.4375f, 0.416504f,
--0.4375f, 0.498047f, -0.4375f, 0.546387f, -0.390381f, 0.594727f, -0.343262f, 0.594727f,
--0.268555f, 0.594727f, -0.169434f, 0.513428f, -0.0898438f, 0.432129f, -0.0102539f,
-0.325684f, -0.0102539f, 0.216309f, -0.0102539f, 0.166992f, -0.0996094f, 0.114258f,
-0.147461f, 0.213379f, 0.147461f, 0.224609f, 0.147461f, 0.228271f, 0.148926f, 0.231934f,
-0.150391f, 0.234619f, 0.154541f, 0.237305f, 0.158691f, 0.237305f, 0.163574f, 0.237305f,
-0.173828f, 0.229004f, 0.181152f, 0.220703f, 0.188477f, 0.20459f, 0.188477f, 0.00927734f,
-0.188477f, -0.00439453f, 0.188477f, -0.00927734f, 0.184082f, -0.0141602f, 0.179688f,
--0.0141602f, 0.172363f, -0.0141602f, 0.162109f, -0.00610352f, 0.154785f, 0.00195312f,
-0.147461f, 0.0180664f, 0.147461f, 0.0732422f, 0.147461f, 0.185547f, -0.381348f, 0.130371f,
--0.381348f, 0.116699f, -0.381348f, 0.111816f, -0.385742f, 0.106934f, -0.390137f,
-0.106934f, -0.397949f, 0.106934f, -0.407715f, 0.11499f, -0.415283f, 0.123047f, -0.422852f,
-0.13916f, -0.422852f, 0.333008f, -0.0517578f, 0.42041f, -0.0517578f, 0.486328f, -0.115723f,
-0.552246f, -0.179688f, 0.552246f, -0.26123f, 0.552246f, -0.318359f, 0.511963f, -0.357178f,
-0.47168f, -0.395996f, 0.40918f, -0.395996f, 0.321777f, -0.395996f, 0.255615f, -0.332031f,
-0.189453f, -0.268066f, 0.189453f, -0.189453f, 0.189453f, -0.130371f, 0.229736f, -0.0910645f,
-0.27002f, -0.0517578f, 0.333008f, -0.0517578f, 0.34082f, -0.422852f, 0.318848f, -0.319336f,
-0.416016f, -0.392578f, 0.459717f, -0.412842f, 0.503418f, -0.433105f, 0.536621f, -0.433105f,
-0.569824f, -0.433105f, 0.596436f, -0.410645f, 0.623047f, -0.388184f, 0.623047f, -0.375488f,
-0.623047f, -0.365234f, 0.615234f, -0.357422f, 0.607422f, -0.349609f, 0.59668f, -0.349609f,
-0.591797f, -0.349609f, 0.588867f, -0.351318f, 0.585938f, -0.353027f, 0.578613f, -0.362305f,
-0.56543f, -0.379395f, 0.553955f, -0.385742f, 0.54248f, -0.39209f, 0.530762f, -0.39209f,
-0.503418f, -0.39209f, 0.461182f, -0.370605f, 0.418945f, -0.349121f, 0.307617f, -0.265625f,
-0.259766f, -0.0410156f, 0.441406f, -0.0410156f, 0.455566f, -0.0410156f, 0.460449f,
--0.0368652f, 0.465332f, -0.0327148f, 0.465332f, -0.0249023f, 0.465332f, -0.0146484f,
-0.457031f, -0.00732422f, 0.44873f, 0, 0.432617f, 0, 0.11084f, 0, 0.097168f, 0, 0.0922852f,
--0.00415039f, 0.0874023f, -0.00830078f, 0.0874023f, -0.015625f, 0.0874023f, -0.0253906f,
-0.0952148f, -0.0324707f, 0.103027f, -0.0395508f, 0.119141f, -0.0395508f, 0.218262f,
--0.0395508f, 0.291016f, -0.381348f, 0.215332f, -0.381348f, 0.20166f, -0.381348f,
-0.196777f, -0.385742f, 0.191895f, -0.390137f, 0.191895f, -0.397461f, 0.191895f, -0.407715f,
-0.199951f, -0.415283f, 0.208008f, -0.422852f, 0.224121f, -0.422852f, 0.52002f, -0.395996f,
-0.522949f, -0.410156f, 0.530273f, -0.416504f, 0.537598f, -0.422852f, 0.546387f, -0.422852f,
-0.553711f, -0.422852f, 0.55835f, -0.418213f, 0.562988f, -0.413574f, 0.562988f, -0.407715f,
-0.562988f, -0.40332f, 0.561035f, -0.39502f, 0.546387f, -0.324707f, 0.542969f, -0.310059f,
-0.535889f, -0.303711f, 0.528809f, -0.297363f, 0.519531f, -0.297363f, 0.512695f, -0.297363f,
-0.508057f, -0.301758f, 0.503418f, -0.306152f, 0.503418f, -0.312012f, 0.503906f, -0.320312f,
-0.504395f, -0.324219f, 0.504395f, -0.327637f, 0.504395f, -0.354004f, 0.480957f, -0.370605f,
-0.446289f, -0.395996f, 0.383789f, -0.395996f, 0.308594f, -0.395996f, 0.26416f, -0.36377f,
-0.230957f, -0.339844f, 0.230957f, -0.312988f, 0.230957f, -0.286621f, 0.259766f, -0.27002f,
-0.280762f, -0.258301f, 0.348633f, -0.250732f, 0.416504f, -0.243164f, 0.445801f, -0.233398f,
-0.486816f, -0.220215f, 0.506836f, -0.195312f, 0.526855f, -0.17041f, 0.526855f, -0.13916f,
-0.526855f, -0.103027f, 0.500488f, -0.0668945f, 0.474121f, -0.0307617f, 0.419922f,
--0.00732422f, 0.365723f, 0.0161133f, 0.297852f, 0.0161133f, 0.249512f, 0.0161133f,
-0.212402f, 0.00366211f, 0.175293f, -0.00878906f, 0.149414f, -0.0332031f, 0.145508f,
--0.0131836f, 0.139648f, -0.00732422f, 0.131348f, 0, 0.121582f, 0, 0.114746f, 0, 0.110107f,
--0.00439453f, 0.105469f, -0.00878906f, 0.105469f, -0.0151367f, 0.105469f, -0.0195312f,
-0.106934f, -0.0273438f, 0.125f, -0.111816f, 0.12793f, -0.126465f, 0.135254f, -0.132812f,
-0.142578f, -0.13916f, 0.151855f, -0.13916f, 0.158691f, -0.13916f, 0.16333f, -0.134521f,
-0.167969f, -0.129883f, 0.167969f, -0.123535f, 0.167969f, -0.119629f, 0.166504f, -0.112305f,
-0.165039f, -0.10498f, 0.165039f, -0.101562f, 0.165039f, -0.0737305f, 0.193848f, -0.0527344f,
-0.231934f, -0.0249023f, 0.305176f, -0.0249023f, 0.392578f, -0.0249023f, 0.438477f,
--0.0595703f, 0.484375f, -0.0942383f, 0.484375f, -0.128418f, 0.484375f, -0.146973f,
-0.470947f, -0.164795f, 0.45752f, -0.182617f, 0.430176f, -0.193115f, 0.402832f, -0.203613f,
-0.340576f, -0.210205f, 0.27832f, -0.216797f, 0.249756f, -0.226807f, 0.221191f, -0.236816f,
-0.205078f, -0.257324f, 0.188965f, -0.277832f, 0.188965f, -0.304199f, 0.188965f, -0.334961f,
-0.209961f, -0.364502f, 0.230957f, -0.394043f, 0.280029f, -0.415771f, 0.329102f, -0.4375f,
-0.390137f, -0.4375f, 0.432617f, -0.4375f, 0.465088f, -0.427246f, 0.497559f, -0.416992f,
-0.52002f, -0.395996f, 0.44043f, 0, 0.453125f, -0.0600586f, 0.353027f, 0.0161133f,
-0.253906f, 0.0161133f, 0.205078f, 0.0161133f, 0.176514f, -0.0119629f, 0.147949f,
--0.0400391f, 0.147949f, -0.0834961f, 0.147949f, -0.0991211f, 0.151855f, -0.116699f,
-0.208008f, -0.381348f, 0.152832f, -0.381348f, 0.13916f, -0.381348f, 0.134277f, -0.385742f,
-0.129395f, -0.390137f, 0.129395f, -0.397949f, 0.129395f, -0.407715f, 0.137451f, -0.415283f,
-0.145508f, -0.422852f, 0.161621f, -0.422852f, 0.257812f, -0.422852f, 0.192871f, -0.116699f,
-0.190918f, -0.106445f, 0.190918f, -0.0957031f, 0.190918f, -0.0634766f, 0.209961f,
--0.0441895f, 0.229004f, -0.0249023f, 0.261719f, -0.0249023f, 0.362793f, -0.0249023f,
-0.465332f, -0.116699f, 0.521484f, -0.381348f, 0.445801f, -0.381348f, 0.432129f, -0.381348f,
-0.427246f, -0.385742f, 0.422363f, -0.390137f, 0.422363f, -0.397949f, 0.422363f, -0.407715f,
-0.43042f, -0.415283f, 0.438477f, -0.422852f, 0.45459f, -0.422852f, 0.571289f, -0.422852f,
-0.490234f, -0.0410156f, 0.524902f, -0.0410156f, 0.538574f, -0.0410156f, 0.543457f,
--0.0368652f, 0.54834f, -0.0327148f, 0.54834f, -0.0249023f, 0.54834f, -0.0146484f,
-0.540283f, -0.00732422f, 0.532227f, 0, 0.516113f, 0, 0.278809f, 0, 0.169922f, -0.381348f,
-0.157715f, -0.381348f, 0.144043f, -0.381348f, 0.138916f, -0.385742f, 0.133789f, -0.390137f,
-0.133789f, -0.397949f, 0.133789f, -0.404297f, 0.137939f, -0.410645f, 0.14209f, -0.416992f,
-0.148193f, -0.419922f, 0.154297f, -0.422852f, 0.166504f, -0.422852f, 0.27832f, -0.422852f,
-0.289062f, -0.422852f, 0.292969f, -0.421143f, 0.296875f, -0.419434f, 0.299316f, -0.415527f,
-0.301758f, -0.411621f, 0.301758f, -0.40625f, 0.301758f, -0.396484f, 0.293701f, -0.388916f,
-0.285645f, -0.381348f, 0.269531f, -0.381348f, 0.214844f, -0.381348f, 0.310059f, -0.0449219f,
-0.546875f, -0.381348f, 0.492188f, -0.381348f, 0.478516f, -0.381348f, 0.473389f, -0.385742f,
-0.468262f, -0.390137f, 0.468262f, -0.397949f, 0.468262f, -0.407715f, 0.476318f, -0.415283f,
-0.484375f, -0.422852f, 0.500977f, -0.422852f, 0.612793f, -0.422852f, 0.626465f, -0.422852f,
-0.630371f, -0.418945f, 0.63623f, -0.414062f, 0.63623f, -0.40625f, 0.63623f, -0.399414f,
-0.631592f, -0.392822f, 0.626953f, -0.38623f, 0.620117f, -0.383301f, 0.614746f, -0.381348f,
-0.591309f, -0.381348f, 0.219238f, 0.147461f, 0.283203f, 0.147461f, 0.293945f, 0.147461f,
-0.297852f, 0.148926f, 0.301758f, 0.150391f, 0.304199f, 0.154541f, 0.306641f, 0.158691f,
-0.306641f, 0.163574f, 0.306641f, 0.173828f, 0.298584f, 0.181152f, 0.290527f, 0.188477f,
-0.274414f, 0.188477f, 0.0380859f, 0.188477f, 0.0244141f, 0.188477f, 0.0195312f, 0.184082f,
-0.0146484f, 0.179688f, 0.0146484f, 0.172363f, 0.0146484f, 0.162109f, 0.0227051f,
-0.154785f, 0.0307617f, 0.147461f, 0.046875f, 0.147461f, 0.175781f, 0.147461f
-};
-
-const unsigned char CourierNewkItalicVerbs[] = {
-6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,
-1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 5, 6,
-0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1,
-1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1,
-2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5,
-6, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6
-};
-
-const unsigned CourierNewkItalicCharCodes[] = {
-32, 65,
-72, 84, 87, 89, 97, 98, 101, 102, 103, 109, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed CourierNewkItalicWidths[] = {
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
-};
-
-const int CourierNewkItalicCharCodesCount = (int) SK_ARRAY_COUNT(CourierNewkItalicCharCodes);
-
-const SkPaint::FontMetrics CourierNewkItalicMetrics = {
-0x00000003, -1.00049f, -0.83252f, 0.300293f, 0.273926f, 0, 0.923828f, 0, -0.123535f,
-0.800293f, 0.437988f, 0, 0.0410156f, 0.23291f
-};
-
-const SkScalar CourierNewkBoldItalicPoints[] = {
-0.456543f, -0.161133f, 0.213379f, -0.161133f, 0.175781f, -0.100098f, 0.200195f, -0.100098f,
-0.233887f, -0.100098f, 0.245605f, -0.0898438f, 0.257324f, -0.0795898f, 0.257324f,
--0.0605469f, 0.257324f, -0.0302734f, 0.228516f, -0.0102539f, 0.213379f, 0, 0.179199f,
-0, 0.0439453f, 0, 0.0107422f, 0, -0.0012207f, -0.010498f, -0.0131836f, -0.0209961f,
--0.0131836f, -0.0395508f, -0.0131836f, -0.0649414f, 0.00708008f, -0.0830078f, 0.0273438f,
--0.101074f, 0.0678711f, -0.100098f, 0.308594f, -0.491699f, 0.242676f, -0.491699f,
-0.209473f, -0.491699f, 0.19751f, -0.502197f, 0.185547f, -0.512695f, 0.185547f, -0.531738f,
-0.185547f, -0.561523f, 0.213867f, -0.581543f, 0.229492f, -0.592285f, 0.26416f, -0.592285f,
-0.480469f, -0.592285f, 0.575195f, -0.100098f, 0.609375f, -0.101074f, 0.62207f, -0.090332f,
-0.634766f, -0.0795898f, 0.634766f, -0.0605469f, 0.634766f, -0.0302734f, 0.605469f,
--0.0102539f, 0.59082f, 0, 0.556152f, 0, 0.421387f, 0, 0.388184f, 0, 0.376221f, -0.010498f,
-0.364258f, -0.0209961f, 0.364258f, -0.0395508f, 0.364258f, -0.0693359f, 0.392578f,
--0.0893555f, 0.408203f, -0.100098f, 0.442871f, -0.100098f, 0.467285f, -0.100098f,
-0.436035f, -0.26123f, 0.397461f, -0.459473f, 0.274414f, -0.26123f, 0.461426f, -0.245117f,
-0.247559f, -0.245117f, 0.216797f, -0.100098f, 0.232422f, -0.100098f, 0.266113f, -0.100098f,
-0.277832f, -0.0898438f, 0.289551f, -0.0795898f, 0.289551f, -0.0605469f, 0.289551f,
--0.0302734f, 0.260742f, -0.0102539f, 0.245605f, 0, 0.211426f, 0, 0.0883789f, 0, 0.0551758f,
-0, 0.0432129f, -0.010498f, 0.03125f, -0.0209961f, 0.03125f, -0.0395508f, 0.03125f,
--0.0708008f, 0.0615234f, -0.0908203f, 0.0761719f, -0.100586f, 0.116699f, -0.100098f,
-0.199707f, -0.491699f, 0.177246f, -0.493652f, 0.166748f, -0.50415f, 0.15625f, -0.514648f,
-0.15625f, -0.531738f, 0.15625f, -0.561523f, 0.185059f, -0.581543f, 0.200195f, -0.592285f,
-0.234863f, -0.592285f, 0.336914f, -0.591797f, 0.370605f, -0.591797f, 0.382568f, -0.581543f,
-0.394531f, -0.571289f, 0.394531f, -0.552246f, 0.394531f, -0.521973f, 0.365234f, -0.501953f,
-0.350098f, -0.491699f, 0.315918f, -0.491699f, 0.299805f, -0.491699f, 0.269043f, -0.345215f,
-0.48291f, -0.345215f, 0.51416f, -0.491699f, 0.498047f, -0.491699f, 0.464844f, -0.491699f,
-0.452881f, -0.502197f, 0.440918f, -0.512695f, 0.440918f, -0.531738f, 0.440918f, -0.561523f,
-0.469238f, -0.581543f, 0.484863f, -0.592285f, 0.519531f, -0.592285f, 0.621582f, -0.591797f,
-0.655273f, -0.591797f, 0.666992f, -0.581543f, 0.678711f, -0.571289f, 0.678711f, -0.552246f,
-0.678711f, -0.529785f, 0.661377f, -0.512207f, 0.644043f, -0.494629f, 0.614258f, -0.491699f,
-0.530762f, -0.100098f, 0.570801f, -0.100098f, 0.581055f, -0.0917969f, 0.594727f,
--0.0800781f, 0.594727f, -0.0605469f, 0.594727f, -0.0302734f, 0.565918f, -0.0102539f,
-0.550781f, 0, 0.516602f, 0, 0.393555f, 0, 0.360352f, 0, 0.348389f, -0.010498f, 0.336426f,
--0.0209961f, 0.336426f, -0.0395508f, 0.336426f, -0.0693359f, 0.364746f, -0.0893555f,
-0.380371f, -0.100098f, 0.415039f, -0.100098f, 0.430664f, -0.100098f, 0.453125f, -0.491699f,
-0.370117f, -0.100098f, 0.4375f, -0.100098f, 0.470703f, -0.100098f, 0.482666f, -0.0895996f,
-0.494629f, -0.0791016f, 0.494629f, -0.0605469f, 0.494629f, -0.0307617f, 0.466309f,
--0.0107422f, 0.450684f, 0, 0.416016f, 0, 0.181152f, 0, 0.147949f, 0, 0.135986f, -0.010498f,
-0.124023f, -0.0209961f, 0.124023f, -0.0395508f, 0.124023f, -0.0698242f, 0.152344f,
--0.0893555f, 0.167969f, -0.100098f, 0.202637f, -0.100098f, 0.27002f, -0.100098f,
-0.353027f, -0.491699f, 0.244629f, -0.491699f, 0.224609f, -0.396973f, 0.216797f, -0.36084f,
-0.199707f, -0.345459f, 0.182617f, -0.330078f, 0.159668f, -0.330078f, 0.142578f, -0.330078f,
-0.131348f, -0.341064f, 0.120117f, -0.352051f, 0.120117f, -0.366699f, 0.120117f, -0.376953f,
-0.124512f, -0.396973f, 0.166016f, -0.591797f, 0.684082f, -0.591797f, 0.642578f, -0.396973f,
-0.635254f, -0.36084f, 0.61792f, -0.345459f, 0.600586f, -0.330078f, 0.578125f, -0.330078f,
-0.561035f, -0.330078f, 0.549805f, -0.341064f, 0.538574f, -0.352051f, 0.538574f, -0.366699f,
-0.538574f, -0.376953f, 0.54248f, -0.396973f, 0.562988f, -0.491699f, 0.36084f, -0.28418f,
-0.20752f, 0, 0.0952148f, 0, 0.140137f, -0.491699f, 0.121094f, -0.494141f, 0.111816f,
--0.503906f, 0.102539f, -0.513672f, 0.102539f, -0.52832f, 0.102539f, -0.560547f, 0.131348f,
--0.581055f, 0.146484f, -0.592285f, 0.181641f, -0.592285f, 0.31543f, -0.591797f, 0.349121f,
--0.591797f, 0.36084f, -0.581543f, 0.372559f, -0.571289f, 0.372559f, -0.552246f, 0.372559f,
--0.522461f, 0.344238f, -0.502441f, 0.329102f, -0.491699f, 0.293945f, -0.491699f,
-0.241699f, -0.491699f, 0.215332f, -0.211914f, 0.343262f, -0.444824f, 0.447754f, -0.444824f,
-0.476074f, -0.211914f, 0.568848f, -0.491699f, 0.516602f, -0.491699f, 0.48291f, -0.491699f,
-0.470947f, -0.502197f, 0.458984f, -0.512695f, 0.458984f, -0.531738f, 0.458984f, -0.561523f,
-0.487793f, -0.581543f, 0.50293f, -0.592285f, 0.537598f, -0.592285f, 0.670898f, -0.591797f,
-0.704102f, -0.591797f, 0.716064f, -0.581543f, 0.728027f, -0.571289f, 0.728027f, -0.552246f,
-0.728027f, -0.53125f, 0.712158f, -0.513672f, 0.696289f, -0.496094f, 0.668945f, -0.491699f,
-0.506836f, 0, 0.395996f, 0, 0.40332f, -0.248535f, 0.37207f, -0.100098f, 0.438965f,
--0.100098f, 0.472656f, -0.100098f, 0.484619f, -0.0898438f, 0.496582f, -0.0795898f,
-0.496582f, -0.0605469f, 0.496582f, -0.0302734f, 0.467285f, -0.0102539f, 0.452148f,
-0, 0.417969f, 0, 0.183105f, 0, 0.149902f, 0, 0.137939f, -0.010498f, 0.125977f, -0.0209961f,
-0.125977f, -0.0395508f, 0.125977f, -0.0698242f, 0.154297f, -0.0893555f, 0.169922f,
--0.100098f, 0.20459f, -0.100098f, 0.271973f, -0.100098f, 0.303223f, -0.248535f, 0.189453f,
--0.491699f, 0.158691f, -0.491699f, 0.146729f, -0.502441f, 0.134766f, -0.513184f,
-0.134766f, -0.531738f, 0.134766f, -0.561523f, 0.163574f, -0.581543f, 0.178711f, -0.592285f,
-0.213379f, -0.592285f, 0.304688f, -0.591797f, 0.338379f, -0.591797f, 0.350098f, -0.581543f,
-0.361816f, -0.571289f, 0.361816f, -0.552246f, 0.361816f, -0.53418f, 0.349854f, -0.518311f,
-0.337891f, -0.502441f, 0.310547f, -0.491699f, 0.375488f, -0.352051f, 0.498047f, -0.491699f,
-0.467285f, -0.504883f, 0.467285f, -0.531738f, 0.467285f, -0.561523f, 0.495605f, -0.581543f,
-0.510742f, -0.591797f, 0.545898f, -0.591797f, 0.639648f, -0.591797f, 0.67334f, -0.591797f,
-0.685059f, -0.581543f, 0.696777f, -0.571289f, 0.696777f, -0.552246f, 0.696777f, -0.522949f,
-0.669434f, -0.50293f, 0.65332f, -0.491699f, 0.619141f, -0.491699f, 0.389648f, 0,
-0.394531f, -0.0234375f, 0.311035f, 0.0161133f, 0.217773f, 0.0161133f, 0.148438f,
-0.0161133f, 0.107422f, -0.019043f, 0.0664062f, -0.0541992f, 0.0664062f, -0.0991211f,
-0.0664062f, -0.135742f, 0.0947266f, -0.17627f, 0.132812f, -0.230957f, 0.199463f,
--0.26123f, 0.266113f, -0.291504f, 0.347168f, -0.291504f, 0.39209f, -0.291504f, 0.449707f,
--0.281738f, 0.45459f, -0.305664f, 0.455566f, -0.310547f, 0.455566f, -0.31543f, 0.455566f,
--0.333496f, 0.441406f, -0.343262f, 0.422852f, -0.356445f, 0.372559f, -0.356445f,
-0.32666f, -0.356445f, 0.253906f, -0.338867f, 0.226562f, -0.33252f, 0.210938f, -0.33252f,
-0.194824f, -0.33252f, 0.184082f, -0.343262f, 0.17334f, -0.354004f, 0.17334f, -0.371582f,
-0.17334f, -0.395996f, 0.188965f, -0.411865f, 0.20459f, -0.427734f, 0.274658f, -0.442139f,
-0.344727f, -0.456543f, 0.39502f, -0.456543f, 0.477051f, -0.456543f, 0.517822f, -0.422607f,
-0.558594f, -0.388672f, 0.558594f, -0.339844f, 0.558594f, -0.324219f, 0.555176f, -0.306152f,
-0.51123f, -0.100098f, 0.52832f, -0.100098f, 0.562012f, -0.100098f, 0.57373f, -0.0898438f,
-0.585449f, -0.0795898f, 0.585449f, -0.0605469f, 0.585449f, -0.0302734f, 0.556641f,
--0.0102539f, 0.541504f, 0, 0.507324f, 0, 0.427734f, -0.179199f, 0.370605f, -0.190918f,
-0.319336f, -0.190918f, 0.25293f, -0.190918f, 0.199219f, -0.155273f, 0.168457f, -0.135254f,
-0.168457f, -0.117188f, 0.168457f, -0.102539f, 0.189697f, -0.0930176f, 0.210938f,
--0.0834961f, 0.244141f, -0.0834961f, 0.278809f, -0.0834961f, 0.327881f, -0.0974121f,
-0.376953f, -0.111328f, 0.418457f, -0.13623f, 0.308594f, -0.633301f, 0.26123f, -0.408691f,
-0.344238f, -0.456543f, 0.422852f, -0.456543f, 0.511719f, -0.456543f, 0.567871f, -0.401611f,
-0.624023f, -0.34668f, 0.624023f, -0.265625f, 0.624023f, -0.195801f, 0.58667f, -0.12915f,
-0.549316f, -0.0625f, 0.475342f, -0.0231934f, 0.401367f, 0.0161133f, 0.319336f, 0.0161133f,
-0.239258f, 0.0161133f, 0.179199f, -0.0244141f, 0.173828f, 0, 0.0566406f, 0, 0.0234375f,
-0, 0.0114746f, -0.010498f, -0.000488281f, -0.0209961f, -0.000488281f, -0.0395508f,
--0.000488281f, -0.0693359f, 0.027832f, -0.0893555f, 0.043457f, -0.100098f, 0.078125f,
--0.100098f, 0.0952148f, -0.100098f, 0.187012f, -0.533203f, 0.169922f, -0.533203f,
-0.136719f, -0.533203f, 0.124756f, -0.543701f, 0.112793f, -0.554199f, 0.112793f, -0.572754f,
-0.112793f, -0.602539f, 0.141113f, -0.622559f, 0.156738f, -0.633301f, 0.191406f, -0.633301f,
-0.34082f, -0.0839844f, 0.422852f, -0.0839844f, 0.471924f, -0.129395f, 0.520996f,
--0.174805f, 0.520996f, -0.242676f, 0.520996f, -0.291016f, 0.487305f, -0.32373f, 0.453613f,
--0.356445f, 0.399414f, -0.356445f, 0.327148f, -0.356445f, 0.271484f, -0.302246f,
-0.21582f, -0.248047f, 0.21582f, -0.181641f, 0.21582f, -0.138672f, 0.24707f, -0.111328f,
-0.27832f, -0.0839844f, 0.34082f, -0.0839844f, 0.587891f, -0.170898f, 0.177246f, -0.170898f,
-0.184082f, -0.132324f, 0.218262f, -0.108154f, 0.252441f, -0.0839844f, 0.320801f,
--0.0839844f, 0.377441f, -0.0839844f, 0.474609f, -0.10791f, 0.515137f, -0.117676f,
-0.530273f, -0.117676f, 0.546387f, -0.117676f, 0.557129f, -0.107178f, 0.567871f, -0.0966797f,
-0.567871f, -0.0795898f, 0.567871f, -0.0546875f, 0.545654f, -0.0354004f, 0.523438f,
--0.0161133f, 0.440918f, 0, 0.358398f, 0.0161133f, 0.291992f, 0.0161133f, 0.1875f,
-0.0161133f, 0.130615f, -0.036377f, 0.0737305f, -0.0888672f, 0.0737305f, -0.17041f,
-0.0737305f, -0.238281f, 0.11499f, -0.306641f, 0.15625f, -0.375f, 0.232666f, -0.415771f,
-0.309082f, -0.456543f, 0.389648f, -0.456543f, 0.484375f, -0.456543f, 0.543213f, -0.404297f,
-0.602051f, -0.352051f, 0.602051f, -0.258301f, 0.602051f, -0.238281f, 0.597168f, -0.213379f,
-0.498047f, -0.270996f, 0.484863f, -0.312012f, 0.452148f, -0.334229f, 0.419434f, -0.356445f,
-0.368164f, -0.356445f, 0.316895f, -0.356445f, 0.275391f, -0.335205f, 0.233887f, -0.313965f,
-0.20166f, -0.270996f, 0.37207f, -0.343262f, 0.320801f, -0.100098f, 0.462891f, -0.100098f,
-0.496582f, -0.100098f, 0.508301f, -0.0898438f, 0.52002f, -0.0795898f, 0.52002f, -0.0605469f,
-0.52002f, -0.0302734f, 0.491211f, -0.0102539f, 0.476074f, 0, 0.441895f, 0, 0.13916f,
-0, 0.105957f, 0, 0.0939941f, -0.010498f, 0.0820312f, -0.0209961f, 0.0820312f, -0.0395508f,
-0.0820312f, -0.0698242f, 0.110352f, -0.0893555f, 0.125977f, -0.100098f, 0.160645f,
--0.100098f, 0.220703f, -0.100098f, 0.271973f, -0.343262f, 0.224121f, -0.343262f,
-0.190918f, -0.343262f, 0.178711f, -0.35376f, 0.166504f, -0.364258f, 0.166504f, -0.382812f,
-0.166504f, -0.412109f, 0.194336f, -0.432129f, 0.209961f, -0.443359f, 0.245117f, -0.443359f,
-0.293457f, -0.443359f, 0.301758f, -0.481445f, 0.31543f, -0.547852f, 0.373779f, -0.590576f,
-0.432129f, -0.633301f, 0.524902f, -0.633301f, 0.561035f, -0.633301f, 0.61377f, -0.626465f,
-0.666504f, -0.619629f, 0.680176f, -0.608398f, 0.693848f, -0.597168f, 0.693848f, -0.57959f,
-0.693848f, -0.555176f, 0.675537f, -0.536377f, 0.657227f, -0.517578f, 0.634277f, -0.517578f,
-0.625488f, -0.517578f, 0.606934f, -0.520996f, 0.547363f, -0.533203f, 0.499512f, -0.533203f,
-0.450195f, -0.533203f, 0.428223f, -0.518311f, 0.40625f, -0.503418f, 0.401855f, -0.481445f,
-0.393555f, -0.443359f, 0.547852f, -0.443359f, 0.581055f, -0.443359f, 0.593018f, -0.432861f,
-0.60498f, -0.422363f, 0.60498f, -0.403809f, 0.60498f, -0.374023f, 0.57666f, -0.354004f,
-0.561523f, -0.343262f, 0.526367f, -0.343262f, 0.486328f, -0.423828f, 0.504395f, -0.443359f,
-0.621582f, -0.443359f, 0.655273f, -0.443359f, 0.667236f, -0.432861f, 0.679199f, -0.422363f,
-0.679199f, -0.40332f, 0.679199f, -0.374512f, 0.651367f, -0.354492f, 0.635742f, -0.343262f,
-0.600586f, -0.343262f, 0.583496f, -0.343262f, 0.505859f, 0.0209961f, 0.494629f, 0.0727539f,
-0.4646f, 0.112061f, 0.43457f, 0.151367f, 0.381836f, 0.180176f, 0.329102f, 0.208984f,
-0.271973f, 0.208984f, 0.158691f, 0.208984f, 0.125488f, 0.208984f, 0.113525f, 0.19873f,
-0.101562f, 0.188477f, 0.101562f, 0.169434f, 0.101562f, 0.13916f, 0.130371f, 0.119141f,
-0.145508f, 0.108887f, 0.179688f, 0.108887f, 0.290039f, 0.108887f, 0.335938f, 0.108887f,
-0.366699f, 0.0842285f, 0.397461f, 0.0595703f, 0.405762f, 0.0209961f, 0.416016f, -0.027832f,
-0.378418f, -0.00634766f, 0.341553f, 0.00439453f, 0.304688f, 0.0151367f, 0.268555f,
-0.0151367f, 0.180664f, 0.0151367f, 0.127197f, -0.0368652f, 0.0737305f, -0.0888672f,
-0.0737305f, -0.167969f, 0.0737305f, -0.23877f, 0.112549f, -0.307129f, 0.151367f,
--0.375488f, 0.222412f, -0.416748f, 0.293457f, -0.458008f, 0.370117f, -0.458008f,
-0.401855f, -0.458008f, 0.42749f, -0.450439f, 0.453125f, -0.442871f, 0.486328f, -0.423828f,
-0.288086f, -0.0854492f, 0.355469f, -0.0854492f, 0.407715f, -0.135986f, 0.459961f,
--0.186523f, 0.459961f, -0.25f, 0.459961f, -0.29541f, 0.428223f, -0.32666f, 0.396484f,
--0.35791f, 0.348633f, -0.35791f, 0.28125f, -0.35791f, 0.229004f, -0.306885f, 0.176758f,
--0.255859f, 0.176758f, -0.194336f, 0.176758f, -0.147461f, 0.208252f, -0.116455f,
-0.239746f, -0.0854492f, 0.288086f, -0.0854492f, 0.231934f, -0.443359f, 0.228516f,
--0.413574f, 0.260254f, -0.437988f, 0.282471f, -0.447266f, 0.304688f, -0.456543f,
-0.328125f, -0.456543f, 0.375977f, -0.456543f, 0.408691f, -0.414062f, 0.438965f, -0.435547f,
-0.468018f, -0.446045f, 0.49707f, -0.456543f, 0.525391f, -0.456543f, 0.57666f, -0.456543f,
-0.606201f, -0.428223f, 0.635742f, -0.399902f, 0.635742f, -0.353516f, 0.635742f, -0.339844f,
-0.632324f, -0.324219f, 0.584961f, -0.100098f, 0.61377f, -0.100098f, 0.625488f, -0.0895996f,
-0.637207f, -0.0791016f, 0.637207f, -0.0605469f, 0.637207f, -0.0302734f, 0.608398f,
--0.0102539f, 0.593262f, 0, 0.558594f, 0, 0.463379f, 0, 0.530762f, -0.315918f, 0.532715f,
--0.32666f, 0.532715f, -0.334961f, 0.532715f, -0.344727f, 0.526123f, -0.350586f, 0.519531f,
--0.356445f, 0.505859f, -0.356445f, 0.489258f, -0.356445f, 0.474121f, -0.347656f,
-0.452637f, -0.335938f, 0.419434f, -0.301758f, 0.376465f, -0.100098f, 0.405273f, -0.100098f,
-0.416992f, -0.0895996f, 0.428711f, -0.0791016f, 0.428711f, -0.0605469f, 0.428711f,
--0.0302734f, 0.399902f, -0.0102539f, 0.384766f, 0, 0.350098f, 0, 0.254883f, 0, 0.322266f,
--0.315918f, 0.324219f, -0.326172f, 0.324219f, -0.334473f, 0.324219f, -0.344238f,
-0.317383f, -0.350342f, 0.310547f, -0.356445f, 0.297363f, -0.356445f, 0.279297f, -0.356445f,
-0.262695f, -0.347168f, 0.240723f, -0.334961f, 0.209473f, -0.301758f, 0.166504f, -0.100098f,
-0.195312f, -0.100098f, 0.207031f, -0.0895996f, 0.21875f, -0.0791016f, 0.21875f, -0.0605469f,
-0.21875f, -0.0302734f, 0.189941f, -0.0102539f, 0.174805f, 0, 0.140137f, 0, 0.0498047f,
-0, 0.0166016f, 0, 0.00463867f, -0.010498f, -0.00732422f, -0.0209961f, -0.00732422f,
--0.0395508f, -0.00732422f, -0.0639648f, 0.0124512f, -0.0822754f, 0.0322266f, -0.100586f,
-0.0664062f, -0.100098f, 0.118164f, -0.343262f, 0.0888672f, -0.343262f, 0.0771484f,
--0.354004f, 0.0654297f, -0.364746f, 0.0654297f, -0.382812f, 0.0654297f, -0.412109f,
-0.0932617f, -0.432129f, 0.108887f, -0.443359f, 0.144043f, -0.443359f, 0.29248f, -0.443359f,
-0.288086f, -0.409668f, 0.321777f, -0.435059f, 0.352051f, -0.445801f, 0.382324f, -0.456543f,
-0.421875f, -0.456543f, 0.498535f, -0.456543f, 0.538086f, -0.421631f, 0.577637f, -0.386719f,
-0.577637f, -0.330566f, 0.577637f, -0.310059f, 0.572754f, -0.286133f, 0.533203f, -0.100098f,
-0.562012f, -0.100098f, 0.57373f, -0.0895996f, 0.585449f, -0.0791016f, 0.585449f,
--0.0605469f, 0.585449f, -0.0302734f, 0.556641f, -0.0102539f, 0.541504f, 0, 0.506836f,
-0, 0.416504f, 0, 0.383301f, 0, 0.371338f, -0.010498f, 0.359375f, -0.0209961f, 0.359375f,
--0.0395508f, 0.359375f, -0.0639648f, 0.37915f, -0.0822754f, 0.398926f, -0.100586f,
-0.433105f, -0.100098f, 0.473145f, -0.289062f, 0.475586f, -0.300781f, 0.475586f, -0.311035f,
-0.475586f, -0.330078f, 0.460938f, -0.341309f, 0.440918f, -0.356445f, 0.401367f, -0.356445f,
-0.367188f, -0.356445f, 0.338135f, -0.343262f, 0.309082f, -0.330078f, 0.259277f, -0.286133f,
-0.219727f, -0.100098f, 0.259277f, -0.100098f, 0.269531f, -0.0917969f, 0.283691f,
--0.0800781f, 0.283691f, -0.0605469f, 0.283691f, -0.0302734f, 0.254883f, -0.0102539f,
-0.239746f, 0, 0.205078f, 0, 0.0913086f, 0, 0.0581055f, 0, 0.0461426f, -0.010498f,
-0.0341797f, -0.0209961f, 0.0341797f, -0.0395508f, 0.0341797f, -0.0708008f, 0.0644531f,
--0.0908203f, 0.0791016f, -0.100098f, 0.119629f, -0.100098f, 0.171387f, -0.343262f,
-0.142578f, -0.343262f, 0.130615f, -0.354004f, 0.118652f, -0.364746f, 0.118652f, -0.382812f,
-0.118652f, -0.412109f, 0.146484f, -0.432129f, 0.162109f, -0.443359f, 0.197266f, -0.443359f,
-0.29834f, 0.0161133f, 0.236328f, 0.0161133f, 0.185303f, -0.0090332f, 0.134277f, -0.0341797f,
-0.108643f, -0.0771484f, 0.0830078f, -0.120117f, 0.0830078f, -0.170898f, 0.0830078f,
--0.233887f, 0.125977f, -0.304199f, 0.168945f, -0.374512f, 0.245605f, -0.415527f,
-0.322266f, -0.456543f, 0.401855f, -0.456543f, 0.458984f, -0.456543f, 0.509277f, -0.430176f,
-0.55957f, -0.403809f, 0.584961f, -0.359619f, 0.610352f, -0.31543f, 0.610352f, -0.262695f,
-0.610352f, -0.194336f, 0.570068f, -0.12915f, 0.529785f, -0.0639648f, 0.452881f, -0.0239258f,
-0.375977f, 0.0161133f, 0.29834f, 0.0161133f, 0.318848f, -0.0839844f, 0.395508f, -0.0839844f,
-0.45166f, -0.133057f, 0.507812f, -0.182129f, 0.507812f, -0.23584f, 0.507812f, -0.288086f,
-0.472168f, -0.322266f, 0.436523f, -0.356445f, 0.377441f, -0.356445f, 0.293457f, -0.356445f,
-0.233398f, -0.293945f, 0.185547f, -0.243652f, 0.185547f, -0.193359f, 0.185547f, -0.150879f,
-0.222412f, -0.117432f, 0.259277f, -0.0839844f, 0.318848f, -0.0839844f, 0.187988f,
--0.0551758f, 0.152832f, 0.108887f, 0.212891f, 0.108887f, 0.246094f, 0.108887f, 0.258057f,
-0.119385f, 0.27002f, 0.129883f, 0.27002f, 0.148438f, 0.27002f, 0.179199f, 0.241211f,
-0.19873f, 0.226074f, 0.208984f, 0.191406f, 0.208984f, 0.0141602f, 0.208984f, -0.019043f,
-0.208984f, -0.0310059f, 0.19873f, -0.0429688f, 0.188477f, -0.0429688f, 0.169434f,
--0.0429688f, 0.139648f, -0.0146484f, 0.119629f, 0.000976562f, 0.108887f, 0.0356445f,
-0.108887f, 0.0527344f, 0.108887f, 0.148926f, -0.343262f, 0.131836f, -0.343262f, 0.0981445f,
--0.343262f, 0.0861816f, -0.35376f, 0.0742188f, -0.364258f, 0.0742188f, -0.382812f,
-0.0742188f, -0.412109f, 0.102051f, -0.432129f, 0.117676f, -0.443359f, 0.152832f,
--0.443359f, 0.27002f, -0.443359f, 0.263184f, -0.40918f, 0.343262f, -0.456543f, 0.42334f,
--0.456543f, 0.512695f, -0.456543f, 0.569336f, -0.401855f, 0.625977f, -0.347168f,
-0.625977f, -0.269043f, 0.625977f, -0.208008f, 0.587158f, -0.146973f, 0.54834f, -0.0859375f,
-0.473877f, -0.0480957f, 0.399414f, -0.0102539f, 0.32959f, -0.0102539f, 0.251953f,
--0.0102539f, 0.187988f, -0.0551758f, 0.347656f, -0.110352f, 0.418945f, -0.110352f,
-0.470947f, -0.154541f, 0.522949f, -0.19873f, 0.522949f, -0.241699f, 0.522949f, -0.291016f,
-0.489258f, -0.32373f, 0.455566f, -0.356445f, 0.400879f, -0.356445f, 0.330566f, -0.356445f,
-0.276611f, -0.306641f, 0.222656f, -0.256836f, 0.222656f, -0.211426f, 0.222656f, -0.172852f,
-0.25708f, -0.141602f, 0.291504f, -0.110352f, 0.347656f, -0.110352f, 0.374023f, -0.443359f,
-0.36084f, -0.380859f, 0.434082f, -0.426758f, 0.473389f, -0.44165f, 0.512695f, -0.456543f,
-0.544434f, -0.456543f, 0.587402f, -0.456543f, 0.620117f, -0.429932f, 0.652832f, -0.40332f,
-0.652832f, -0.381348f, 0.652832f, -0.357422f, 0.633545f, -0.338379f, 0.614258f, -0.319336f,
-0.590332f, -0.319336f, 0.571777f, -0.319336f, 0.555176f, -0.337891f, 0.538574f, -0.356445f,
-0.522461f, -0.356445f, 0.504395f, -0.356445f, 0.463867f, -0.335938f, 0.42334f, -0.31543f,
-0.333008f, -0.250977f, 0.30127f, -0.100098f, 0.443359f, -0.100098f, 0.477051f, -0.100098f,
-0.48877f, -0.0898438f, 0.500488f, -0.0795898f, 0.500488f, -0.0605469f, 0.500488f,
--0.0302734f, 0.47168f, -0.0102539f, 0.456543f, 0, 0.422363f, 0, 0.119629f, 0, 0.0864258f,
-0, 0.0744629f, -0.010498f, 0.0625f, -0.0209961f, 0.0625f, -0.0395508f, 0.0625f, -0.0698242f,
-0.0908203f, -0.0893555f, 0.106445f, -0.100098f, 0.141113f, -0.100098f, 0.201172f,
--0.100098f, 0.252441f, -0.343262f, 0.216309f, -0.343262f, 0.183105f, -0.343262f,
-0.170898f, -0.35376f, 0.158691f, -0.364258f, 0.158691f, -0.382812f, 0.158691f, -0.412109f,
-0.186523f, -0.432129f, 0.202148f, -0.443359f, 0.237793f, -0.443359f, 0.477051f, -0.326172f,
-0.456055f, -0.341309f, 0.430908f, -0.348877f, 0.405762f, -0.356445f, 0.375977f, -0.356445f,
-0.328125f, -0.356445f, 0.294434f, -0.343506f, 0.260742f, -0.330566f, 0.260742f, -0.317383f,
-0.260742f, -0.308594f, 0.271973f, -0.300781f, 0.287109f, -0.290039f, 0.343262f, -0.282227f,
-0.430176f, -0.27002f, 0.470459f, -0.256836f, 0.510742f, -0.243652f, 0.534668f, -0.214355f,
-0.558594f, -0.185059f, 0.558594f, -0.149414f, 0.558594f, -0.0776367f, 0.481445f,
--0.0307617f, 0.404297f, 0.0161133f, 0.302246f, 0.0161133f, 0.258789f, 0.0161133f,
-0.223145f, 0.00854492f, 0.1875f, 0.000976562f, 0.160156f, -0.0136719f, 0.14209f,
--0.000488281f, 0.125488f, -0.000488281f, 0.106445f, -0.000488281f, 0.0949707f, -0.0114746f,
-0.0834961f, -0.0224609f, 0.0834961f, -0.0375977f, 0.0834961f, -0.0473633f, 0.0878906f,
--0.0673828f, 0.0952148f, -0.101074f, 0.102539f, -0.137695f, 0.119873f, -0.152832f,
-0.137207f, -0.167969f, 0.159668f, -0.167969f, 0.177734f, -0.167969f, 0.1875f, -0.157959f,
-0.197266f, -0.147949f, 0.199219f, -0.123535f, 0.217773f, -0.104004f, 0.248047f, -0.0939941f,
-0.27832f, -0.0839844f, 0.320312f, -0.0839844f, 0.394043f, -0.0839844f, 0.436523f,
--0.10791f, 0.455566f, -0.118652f, 0.455566f, -0.132324f, 0.455566f, -0.151367f, 0.432129f,
--0.162598f, 0.408691f, -0.17334f, 0.333496f, -0.181641f, 0.225586f, -0.193359f, 0.191895f,
--0.22168f, 0.158203f, -0.25f, 0.158203f, -0.294434f, 0.158203f, -0.333008f, 0.183105f,
--0.367676f, 0.208008f, -0.402344f, 0.257812f, -0.42627f, 0.322266f, -0.456543f, 0.396484f,
--0.456543f, 0.431152f, -0.456543f, 0.461914f, -0.449951f, 0.492676f, -0.443359f,
-0.519043f, -0.429688f, 0.540039f, -0.443359f, 0.553711f, -0.443359f, 0.569336f, -0.443359f,
-0.580566f, -0.432373f, 0.591797f, -0.421387f, 0.591797f, -0.406738f, 0.591797f, -0.396484f,
-0.587891f, -0.376465f, 0.58252f, -0.352051f, 0.574707f, -0.315918f, 0.557373f, -0.300537f,
-0.540039f, -0.285156f, 0.517578f, -0.285156f, 0.499512f, -0.285156f, 0.488281f, -0.296387f,
-0.477051f, -0.307617f, 0.477051f, -0.326172f, 0.606445f, -0.443359f, 0.533691f, -0.100098f,
-0.5625f, -0.100098f, 0.574219f, -0.0895996f, 0.585938f, -0.0791016f, 0.585938f, -0.0605469f,
-0.585938f, -0.0307617f, 0.557617f, -0.0107422f, 0.54248f, 0, 0.507324f, 0, 0.412109f,
-0, 0.416992f, -0.0229492f, 0.322754f, 0.0161133f, 0.25f, 0.0161133f, 0.192383f, 0.0161133f,
-0.157227f, -0.0163574f, 0.12207f, -0.0488281f, 0.12207f, -0.0976562f, 0.12207f, -0.111328f,
-0.125488f, -0.12793f, 0.170898f, -0.343262f, 0.153809f, -0.343262f, 0.120605f, -0.343262f,
-0.108643f, -0.35376f, 0.0966797f, -0.364258f, 0.0966797f, -0.382812f, 0.0966797f,
--0.412598f, 0.125f, -0.432617f, 0.140137f, -0.443359f, 0.175293f, -0.443359f, 0.29248f,
--0.443359f, 0.229004f, -0.145508f, 0.226074f, -0.130371f, 0.226074f, -0.121094f,
-0.226074f, -0.105957f, 0.239014f, -0.0949707f, 0.251953f, -0.0839844f, 0.277832f,
--0.0839844f, 0.308594f, -0.0839844f, 0.345703f, -0.0957031f, 0.382812f, -0.107422f,
-0.441895f, -0.13916f, 0.485352f, -0.343262f, 0.44873f, -0.343262f, 0.415527f, -0.343262f,
-0.403564f, -0.35376f, 0.391602f, -0.364258f, 0.391602f, -0.382812f, 0.391602f, -0.412598f,
-0.419922f, -0.432617f, 0.435059f, -0.443359f, 0.470215f, -0.443359f, 0.244629f, -0.00341797f,
-0.143555f, -0.343262f, 0.122559f, -0.345703f, 0.112793f, -0.355957f, 0.103027f, -0.366211f,
-0.103027f, -0.382812f, 0.103027f, -0.412598f, 0.131348f, -0.432617f, 0.146484f, -0.443359f,
-0.181641f, -0.443359f, 0.272949f, -0.443359f, 0.306641f, -0.443359f, 0.318604f, -0.432861f,
-0.330566f, -0.422363f, 0.330566f, -0.403809f, 0.330566f, -0.379395f, 0.311035f, -0.361328f,
-0.291504f, -0.343262f, 0.254883f, -0.343262f, 0.32373f, -0.113281f, 0.489746f, -0.343262f,
-0.460449f, -0.343262f, 0.44873f, -0.354004f, 0.437012f, -0.364746f, 0.437012f, -0.382812f,
-0.437012f, -0.412109f, 0.464355f, -0.432129f, 0.47998f, -0.443359f, 0.515625f, -0.443359f,
-0.609375f, -0.443359f, 0.642578f, -0.443359f, 0.654541f, -0.432861f, 0.666504f, -0.422363f,
-0.666504f, -0.403809f, 0.666504f, -0.381348f, 0.649414f, -0.363525f, 0.632324f, -0.345703f,
-0.602539f, -0.343262f, 0.276855f, 0.108887f, 0.315918f, 0.108887f, 0.326172f, 0.117676f,
-0.340332f, 0.129395f, 0.340332f, 0.148438f, 0.340332f, 0.179199f, 0.311035f, 0.19873f,
-0.295898f, 0.208984f, 0.261719f, 0.208984f, 0.0429688f, 0.208984f, 0.00976562f, 0.208984f,
--0.00219727f, 0.19873f, -0.0141602f, 0.188477f, -0.0141602f, 0.169434f, -0.0141602f,
-0.139648f, 0.0141602f, 0.119629f, 0.0297852f, 0.108887f, 0.0644531f, 0.108887f, 0.164062f,
-0.108887f
-};
-
-const unsigned char CourierNewkBoldItalicVerbs[] = {
-6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 5, 0, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6,
-0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6
-};
-
-const unsigned CourierNewkBoldItalicCharCodes[] = {
-32,
-65, 72, 84, 87, 89, 97, 98, 101, 102, 103, 109, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed CourierNewkBoldItalicWidths[] = {
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0,
-0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0, 0x000099a0
-};
-
-const int CourierNewkBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(CourierNewkBoldItalicCharCodes);
-
-const SkPaint::FontMetrics CourierNewkBoldItalicMetrics = {
-0x2e302d23, -1.00391f, -0.83252f, 0.300293f, 0.376953f, 0, 0.941895f, 4.24199e-08f,
--0.102539f, 0.839355f, 0.458008f, 1.53766e-13f, 0.100098f, 0.23291f
-};
-
-const SkScalar LiberationSanskNormalPoints[] = {
-0.175293f, -0.193848f, 0.103027f, -0.193848f, 0.0913086f, -0.687988f, 0.187012f, -0.687988f,
-0.090332f, 0, 0.090332f, -0.0981445f, 0.185059f, -0.0981445f, 0.185059f, 0, 0.4375f,
--0.432129f, 0.399414f, -0.251953f, 0.526367f, -0.251953f, 0.526367f, -0.199219f,
-0.388184f, -0.199219f, 0.345215f, 0, 0.291504f, 0, 0.333496f, -0.199219f, 0.15625f,
--0.199219f, 0.115234f, 0, 0.0615234f, 0, 0.102539f, -0.199219f, 0.00439453f, -0.199219f,
-0.00439453f, -0.251953f, 0.114258f, -0.251953f, 0.152344f, -0.432129f, 0.0292969f,
--0.432129f, 0.0292969f, -0.484863f, 0.163086f, -0.484863f, 0.206543f, -0.684082f,
-0.260254f, -0.684082f, 0.217285f, -0.484863f, 0.394531f, -0.484863f, 0.4375f, -0.684082f,
-0.491211f, -0.684082f, 0.448242f, -0.484863f, 0.55127f, -0.484863f, 0.55127f, -0.432129f,
-0.20752f, -0.432129f, 0.168457f, -0.251953f, 0.345215f, -0.251953f, 0.383301f, -0.432129f,
-0.853516f, -0.211914f, 0.853516f, -0.150879f, 0.841064f, -0.109131f, 0.828613f, -0.0673828f,
-0.807373f, -0.041748f, 0.786133f, -0.0161133f, 0.757812f, -0.00512695f, 0.729492f,
-0.00585938f, 0.697266f, 0.00585938f, 0.665039f, 0.00585938f, 0.636963f, -0.00512695f,
-0.608887f, -0.0161133f, 0.588135f, -0.0415039f, 0.567383f, -0.0668945f, 0.55542f,
--0.108643f, 0.543457f, -0.150391f, 0.543457f, -0.211914f, 0.543457f, -0.276855f,
-0.555176f, -0.319336f, 0.566895f, -0.361816f, 0.587891f, -0.386963f, 0.608887f, -0.412109f,
-0.637451f, -0.422119f, 0.666016f, -0.432129f, 0.699219f, -0.432129f, 0.731445f, -0.432129f,
-0.759521f, -0.422119f, 0.787598f, -0.412109f, 0.80835f, -0.386963f, 0.829102f, -0.361816f,
-0.841309f, -0.319336f, 0.853516f, -0.276855f, 0.853516f, -0.211914f, 0.257324f, 0,
-0.181641f, 0, 0.631836f, -0.687988f, 0.708496f, -0.687988f, 0.192383f, -0.693848f,
-0.223633f, -0.693848f, 0.251465f, -0.683838f, 0.279297f, -0.673828f, 0.300293f, -0.648926f,
-0.321289f, -0.624023f, 0.333252f, -0.582031f, 0.345215f, -0.540039f, 0.345215f, -0.476074f,
-0.345215f, -0.414551f, 0.333008f, -0.372559f, 0.320801f, -0.330566f, 0.300049f, -0.304443f,
-0.279297f, -0.27832f, 0.250977f, -0.26709f, 0.222656f, -0.255859f, 0.19043f, -0.255859f,
-0.157715f, -0.255859f, 0.129395f, -0.26709f, 0.101074f, -0.27832f, 0.0803223f, -0.304199f,
-0.0595703f, -0.330078f, 0.0476074f, -0.37207f, 0.0356445f, -0.414062f, 0.0356445f,
--0.476074f, 0.0356445f, -0.540039f, 0.0476074f, -0.582031f, 0.0595703f, -0.624023f,
-0.0805664f, -0.648926f, 0.101562f, -0.673828f, 0.130371f, -0.683838f, 0.15918f, -0.693848f,
-0.192383f, -0.693848f, 0.78125f, -0.211914f, 0.78125f, -0.260254f, 0.775879f, -0.292236f,
-0.770508f, -0.324219f, 0.76001f, -0.343262f, 0.749512f, -0.362305f, 0.734131f, -0.370117f,
-0.71875f, -0.37793f, 0.699219f, -0.37793f, 0.678711f, -0.37793f, 0.663086f, -0.369873f,
-0.647461f, -0.361816f, 0.636719f, -0.342773f, 0.625977f, -0.32373f, 0.620605f, -0.291748f,
-0.615234f, -0.259766f, 0.615234f, -0.211914f, 0.615234f, -0.165527f, 0.62085f, -0.134277f,
-0.626465f, -0.103027f, 0.636963f, -0.0837402f, 0.647461f, -0.0644531f, 0.662842f,
--0.0561523f, 0.678223f, -0.0478516f, 0.698242f, -0.0478516f, 0.717285f, -0.0478516f,
-0.732666f, -0.0561523f, 0.748047f, -0.0644531f, 0.758789f, -0.0837402f, 0.769531f,
--0.103027f, 0.775391f, -0.134277f, 0.78125f, -0.165527f, 0.78125f, -0.211914f, 0.273438f,
--0.476074f, 0.273438f, -0.523926f, 0.268066f, -0.555664f, 0.262695f, -0.587402f,
-0.252441f, -0.606445f, 0.242188f, -0.625488f, 0.227051f, -0.633301f, 0.211914f, -0.641113f,
-0.192383f, -0.641113f, 0.171387f, -0.641113f, 0.155518f, -0.633057f, 0.139648f, -0.625f,
-0.128906f, -0.605957f, 0.118164f, -0.586914f, 0.112793f, -0.555176f, 0.107422f, -0.523438f,
-0.107422f, -0.476074f, 0.107422f, -0.429688f, 0.113037f, -0.397949f, 0.118652f, -0.366211f,
-0.12915f, -0.346924f, 0.139648f, -0.327637f, 0.155273f, -0.319336f, 0.170898f, -0.311035f,
-0.191406f, -0.311035f, 0.209961f, -0.311035f, 0.225098f, -0.319336f, 0.240234f, -0.327637f,
-0.250977f, -0.346924f, 0.261719f, -0.366211f, 0.267578f, -0.397949f, 0.273438f, -0.429688f,
-0.273438f, -0.476074f, 0.58252f, 0.00585938f, 0.535645f, 0.00585938f, 0.500488f,
--0.0102539f, 0.465332f, -0.0263672f, 0.437012f, -0.0561523f, 0.422363f, -0.043457f,
-0.403809f, -0.0317383f, 0.385254f, -0.0200195f, 0.362549f, -0.0107422f, 0.339844f,
--0.00146484f, 0.313232f, 0.00415039f, 0.286621f, 0.00976562f, 0.255371f, 0.00976562f,
-0.198242f, 0.00976562f, 0.156494f, -0.00488281f, 0.114746f, -0.0195312f, 0.0878906f,
--0.045166f, 0.0610352f, -0.0708008f, 0.0480957f, -0.105713f, 0.0351562f, -0.140625f,
-0.0351562f, -0.181152f, 0.0351562f, -0.219727f, 0.0476074f, -0.251221f, 0.0600586f,
--0.282715f, 0.0822754f, -0.30835f, 0.104492f, -0.333984f, 0.135254f, -0.354248f,
-0.166016f, -0.374512f, 0.202637f, -0.390625f, 0.193848f, -0.407227f, 0.186768f, -0.426025f,
-0.179688f, -0.444824f, 0.174316f, -0.463867f, 0.168945f, -0.48291f, 0.166016f, -0.501953f,
-0.163086f, -0.520996f, 0.163086f, -0.538086f, 0.163086f, -0.570312f, 0.172852f, -0.598389f,
-0.182617f, -0.626465f, 0.203369f, -0.647217f, 0.224121f, -0.667969f, 0.256592f, -0.679932f,
-0.289062f, -0.691895f, 0.334473f, -0.691895f, 0.370117f, -0.691895f, 0.400146f, -0.682617f,
-0.430176f, -0.67334f, 0.452148f, -0.655762f, 0.474121f, -0.638184f, 0.486328f, -0.612305f,
-0.498535f, -0.586426f, 0.498535f, -0.553223f, 0.498535f, -0.516602f, 0.482422f, -0.488037f,
-0.466309f, -0.459473f, 0.438965f, -0.437012f, 0.411621f, -0.414551f, 0.375488f, -0.39624f,
-0.339355f, -0.37793f, 0.298828f, -0.361816f, 0.329102f, -0.306152f, 0.364746f, -0.25708f,
-0.400391f, -0.208008f, 0.441895f, -0.160645f, 0.47168f, -0.20459f, 0.491455f, -0.253174f,
-0.51123f, -0.301758f, 0.525391f, -0.36084f, 0.596191f, -0.339844f, 0.579102f, -0.271973f,
-0.552979f, -0.216553f, 0.526855f, -0.161133f, 0.492676f, -0.11084f, 0.518555f, -0.0844727f,
-0.544434f, -0.0737305f, 0.570312f, -0.0629883f, 0.594238f, -0.0629883f, 0.609863f,
--0.0629883f, 0.624268f, -0.0646973f, 0.638672f, -0.0664062f, 0.651367f, -0.0708008f,
-0.651367f, -0.00488281f, 0.637695f, 0.000488281f, 0.619385f, 0.00317383f, 0.601074f,
-0.00585938f, 0.58252f, 0.00585938f, 0.424316f, -0.553223f, 0.424316f, -0.571289f,
-0.417725f, -0.585938f, 0.411133f, -0.600586f, 0.399414f, -0.611084f, 0.387695f, -0.621582f,
-0.37085f, -0.627197f, 0.354004f, -0.632812f, 0.333496f, -0.632812f, 0.286621f, -0.632812f,
-0.262207f, -0.607666f, 0.237793f, -0.58252f, 0.237793f, -0.538086f, 0.237793f, -0.509277f,
-0.246826f, -0.477783f, 0.255859f, -0.446289f, 0.269531f, -0.418945f, 0.30127f, -0.431641f,
-0.32959f, -0.445068f, 0.35791f, -0.458496f, 0.378906f, -0.474365f, 0.399902f, -0.490234f,
-0.412109f, -0.509521f, 0.424316f, -0.528809f, 0.424316f, -0.553223f, 0.388184f, -0.105957f,
-0.344727f, -0.157227f, 0.304688f, -0.213379f, 0.264648f, -0.269531f, 0.232422f, -0.329102f,
-0.177246f, -0.305664f, 0.147217f, -0.269531f, 0.117188f, -0.233398f, 0.117188f, -0.182129f,
-0.117188f, -0.155273f, 0.125732f, -0.13208f, 0.134277f, -0.108887f, 0.151855f, -0.0915527f,
-0.169434f, -0.0742188f, 0.196045f, -0.064209f, 0.222656f, -0.0541992f, 0.258301f,
--0.0541992f, 0.279785f, -0.0541992f, 0.299072f, -0.0588379f, 0.318359f, -0.0634766f,
-0.334961f, -0.0708008f, 0.351562f, -0.078125f, 0.36499f, -0.0874023f, 0.378418f,
--0.0966797f, 0.388184f, -0.105957f, 0.129883f, -0.47168f, 0.0610352f, -0.47168f,
-0.0507812f, -0.687988f, 0.140625f, -0.687988f, 0.270996f, -0.257812f, 0.270996f,
--0.189453f, 0.260742f, -0.127686f, 0.250488f, -0.065918f, 0.228516f, -0.00878906f,
-0.206543f, 0.0483398f, 0.172363f, 0.102051f, 0.138184f, 0.155762f, 0.0908203f, 0.207031f,
-0.00585938f, 0.207031f, 0.0517578f, 0.155762f, 0.0852051f, 0.102051f, 0.118652f,
-0.0483398f, 0.140137f, -0.00927734f, 0.161621f, -0.0668945f, 0.172119f, -0.128906f,
-0.182617f, -0.190918f, 0.182617f, -0.258789f, 0.182617f, -0.32666f, 0.172119f, -0.388672f,
-0.161621f, -0.450684f, 0.140137f, -0.508057f, 0.118652f, -0.56543f, 0.0852051f, -0.619385f,
-0.0517578f, -0.67334f, 0.00585938f, -0.724609f, 0.0908203f, -0.724609f, 0.138184f,
--0.67334f, 0.172363f, -0.619629f, 0.206543f, -0.565918f, 0.228516f, -0.508789f, 0.250488f,
--0.45166f, 0.260742f, -0.389648f, 0.270996f, -0.327637f, 0.270996f, -0.259766f, 0.222656f,
--0.543945f, 0.351562f, -0.594238f, 0.373535f, -0.529785f, 0.23584f, -0.494141f, 0.326172f,
--0.37207f, 0.268066f, -0.336914f, 0.194824f, -0.462891f, 0.118652f, -0.337891f, 0.0605469f,
--0.373047f, 0.152832f, -0.494141f, 0.0161133f, -0.529785f, 0.0380859f, -0.595215f,
-0.168457f, -0.542969f, 0.162598f, -0.687988f, 0.229004f, -0.687988f, 0.327637f, -0.296875f,
-0.327637f, -0.0878906f, 0.255859f, -0.0878906f, 0.255859f, -0.296875f, 0.0488281f,
--0.296875f, 0.0488281f, -0.368164f, 0.255859f, -0.368164f, 0.255859f, -0.577148f,
-0.327637f, -0.577148f, 0.327637f, -0.368164f, 0.534668f, -0.368164f, 0.534668f, -0.296875f,
-0.0444336f, -0.226562f, 0.0444336f, -0.304688f, 0.288574f, -0.304688f, 0.288574f,
--0.226562f, 0.0913086f, 0, 0.0913086f, -0.106934f, 0.186523f, -0.106934f, 0.186523f,
-0, 0, 0.00976562f, 0.200684f, -0.724609f, 0.277832f, -0.724609f, 0.0791016f, 0.00976562f,
-0.0761719f, 0, 0.0761719f, -0.074707f, 0.251465f, -0.074707f, 0.251465f, -0.604004f,
-0.0961914f, -0.493164f, 0.0961914f, -0.576172f, 0.258789f, -0.687988f, 0.339844f,
--0.687988f, 0.339844f, -0.074707f, 0.507324f, -0.074707f, 0.507324f, 0, 0.050293f,
-0, 0.050293f, -0.0620117f, 0.0751953f, -0.119141f, 0.111084f, -0.162842f, 0.146973f,
--0.206543f, 0.186523f, -0.241943f, 0.226074f, -0.277344f, 0.264893f, -0.307617f,
-0.303711f, -0.337891f, 0.334961f, -0.368164f, 0.366211f, -0.398438f, 0.385498f, -0.431641f,
-0.404785f, -0.464844f, 0.404785f, -0.506836f, 0.404785f, -0.536133f, 0.395996f, -0.55835f,
-0.387207f, -0.580566f, 0.370605f, -0.595703f, 0.354004f, -0.61084f, 0.330811f, -0.618408f,
-0.307617f, -0.625977f, 0.279297f, -0.625977f, 0.25293f, -0.625977f, 0.229736f, -0.618652f,
-0.206543f, -0.611328f, 0.188477f, -0.59668f, 0.17041f, -0.582031f, 0.158936f, -0.560303f,
-0.147461f, -0.538574f, 0.144043f, -0.509766f, 0.0541992f, -0.518066f, 0.0585938f,
--0.555176f, 0.074707f, -0.587891f, 0.0908203f, -0.620605f, 0.119141f, -0.645264f,
-0.147461f, -0.669922f, 0.187256f, -0.684082f, 0.227051f, -0.698242f, 0.279297f, -0.698242f,
-0.330566f, -0.698242f, 0.370605f, -0.686035f, 0.410645f, -0.673828f, 0.438232f, -0.649902f,
-0.46582f, -0.625977f, 0.480469f, -0.59082f, 0.495117f, -0.555664f, 0.495117f, -0.509766f,
-0.495117f, -0.475098f, 0.482666f, -0.443848f, 0.470215f, -0.412598f, 0.449463f, -0.384277f,
-0.428711f, -0.355957f, 0.401367f, -0.32959f, 0.374023f, -0.303223f, 0.344238f, -0.278076f,
-0.314453f, -0.25293f, 0.28418f, -0.228271f, 0.253906f, -0.203613f, 0.227295f, -0.178711f,
-0.200684f, -0.153809f, 0.179688f, -0.128174f, 0.158691f, -0.102539f, 0.146973f, -0.074707f,
-0.505859f, -0.074707f, 0.505859f, 0, 0.430176f, -0.155762f, 0.430176f, 0, 0.347168f,
-0, 0.347168f, -0.155762f, 0.0229492f, -0.155762f, 0.0229492f, -0.224121f, 0.337891f,
--0.687988f, 0.430176f, -0.687988f, 0.430176f, -0.225098f, 0.526855f, -0.225098f,
-0.526855f, -0.155762f, 0.347168f, -0.588867f, 0.346191f, -0.586426f, 0.342285f, -0.579346f,
-0.338379f, -0.572266f, 0.333496f, -0.563477f, 0.328613f, -0.554688f, 0.323486f, -0.545654f,
-0.318359f, -0.536621f, 0.314453f, -0.530762f, 0.138184f, -0.270996f, 0.135742f, -0.26709f,
-0.131104f, -0.260742f, 0.126465f, -0.254395f, 0.121582f, -0.247803f, 0.116699f, -0.241211f,
-0.111816f, -0.234863f, 0.106934f, -0.228516f, 0.104004f, -0.225098f, 0.347168f, -0.225098f,
-0.51416f, -0.224121f, 0.51416f, -0.172363f, 0.498535f, -0.129395f, 0.48291f, -0.0864258f,
-0.452148f, -0.0554199f, 0.421387f, -0.0244141f, 0.375732f, -0.00732422f, 0.330078f,
-0.00976562f, 0.27002f, 0.00976562f, 0.21582f, 0.00976562f, 0.175537f, -0.00292969f,
-0.135254f, -0.015625f, 0.107422f, -0.0378418f, 0.0795898f, -0.0600586f, 0.0632324f,
--0.0898438f, 0.046875f, -0.119629f, 0.0400391f, -0.153809f, 0.128906f, -0.164062f,
-0.134277f, -0.144531f, 0.144043f, -0.126221f, 0.153809f, -0.10791f, 0.170654f, -0.0935059f,
-0.1875f, -0.0791016f, 0.212158f, -0.0705566f, 0.236816f, -0.0620117f, 0.271973f,
--0.0620117f, 0.306152f, -0.0620117f, 0.333984f, -0.0725098f, 0.361816f, -0.0830078f,
-0.381592f, -0.103516f, 0.401367f, -0.124023f, 0.412109f, -0.153809f, 0.422852f, -0.183594f,
-0.422852f, -0.222168f, 0.422852f, -0.253906f, 0.412598f, -0.280518f, 0.402344f, -0.307129f,
-0.383301f, -0.326416f, 0.364258f, -0.345703f, 0.33667f, -0.356445f, 0.309082f, -0.367188f,
-0.273926f, -0.367188f, 0.251953f, -0.367188f, 0.233398f, -0.363281f, 0.214844f, -0.359375f,
-0.198975f, -0.352539f, 0.183105f, -0.345703f, 0.170166f, -0.33667f, 0.157227f, -0.327637f,
-0.145996f, -0.317871f, 0.0600586f, -0.317871f, 0.0830078f, -0.687988f, 0.474121f,
--0.687988f, 0.474121f, -0.613281f, 0.163086f, -0.613281f, 0.149902f, -0.39502f, 0.17334f,
--0.413086f, 0.208496f, -0.426025f, 0.243652f, -0.438965f, 0.291992f, -0.438965f,
-0.343262f, -0.438965f, 0.384277f, -0.42334f, 0.425293f, -0.407715f, 0.454102f, -0.37915f,
-0.48291f, -0.350586f, 0.498535f, -0.311035f, 0.51416f, -0.271484f, 0.51416f, -0.224121f,
-0.512207f, -0.225098f, 0.512207f, -0.17334f, 0.497803f, -0.130127f, 0.483398f, -0.0869141f,
-0.455322f, -0.0559082f, 0.427246f, -0.0249023f, 0.385742f, -0.00756836f, 0.344238f,
-0.00976562f, 0.290039f, 0.00976562f, 0.22998f, 0.00976562f, 0.185059f, -0.0131836f,
-0.140137f, -0.0361328f, 0.110352f, -0.0793457f, 0.0805664f, -0.122559f, 0.0656738f,
--0.185303f, 0.0507812f, -0.248047f, 0.0507812f, -0.328125f, 0.0507812f, -0.419922f,
-0.067627f, -0.489258f, 0.0844727f, -0.558594f, 0.116211f, -0.60498f, 0.147949f, -0.651367f,
-0.193604f, -0.674805f, 0.239258f, -0.698242f, 0.296875f, -0.698242f, 0.332031f, -0.698242f,
-0.362793f, -0.690918f, 0.393555f, -0.683594f, 0.418701f, -0.667236f, 0.443848f, -0.650879f,
-0.462891f, -0.624023f, 0.481934f, -0.597168f, 0.493164f, -0.558105f, 0.40918f, -0.542969f,
-0.395508f, -0.587402f, 0.365479f, -0.607178f, 0.335449f, -0.626953f, 0.295898f, -0.626953f,
-0.259766f, -0.626953f, 0.230469f, -0.609863f, 0.201172f, -0.592773f, 0.180664f, -0.558838f,
-0.160156f, -0.524902f, 0.14917f, -0.473633f, 0.138184f, -0.422363f, 0.138184f, -0.354004f,
-0.162109f, -0.398438f, 0.205566f, -0.421631f, 0.249023f, -0.444824f, 0.305176f, -0.444824f,
-0.352051f, -0.444824f, 0.390137f, -0.429688f, 0.428223f, -0.414551f, 0.455322f, -0.385986f,
-0.482422f, -0.357422f, 0.497314f, -0.31665f, 0.512207f, -0.275879f, 0.512207f, -0.225098f,
-0.422852f, -0.221191f, 0.422852f, -0.256836f, 0.414062f, -0.285645f, 0.405273f, -0.314453f,
-0.387695f, -0.334717f, 0.370117f, -0.35498f, 0.344238f, -0.365967f, 0.318359f, -0.376953f,
-0.28418f, -0.376953f, 0.260254f, -0.376953f, 0.23584f, -0.369873f, 0.211426f, -0.362793f,
-0.19165f, -0.346924f, 0.171875f, -0.331055f, 0.159424f, -0.305176f, 0.146973f, -0.279297f,
-0.146973f, -0.242188f, 0.146973f, -0.204102f, 0.156738f, -0.171143f, 0.166504f, -0.138184f,
-0.184814f, -0.11377f, 0.203125f, -0.0893555f, 0.229004f, -0.0751953f, 0.254883f,
--0.0610352f, 0.287109f, -0.0610352f, 0.318848f, -0.0610352f, 0.343994f, -0.0720215f,
-0.369141f, -0.0830078f, 0.386719f, -0.10376f, 0.404297f, -0.124512f, 0.413574f, -0.154297f,
-0.422852f, -0.184082f, 0.422852f, -0.221191f, 0.505859f, -0.616699f, 0.454102f, -0.537598f,
-0.410645f, -0.4646f, 0.367188f, -0.391602f, 0.335938f, -0.317627f, 0.304688f, -0.243652f,
-0.287354f, -0.165771f, 0.27002f, -0.0878906f, 0.27002f, 0, 0.178223f, 0, 0.178223f,
--0.0825195f, 0.197754f, -0.161865f, 0.217285f, -0.241211f, 0.250488f, -0.317627f,
-0.283691f, -0.394043f, 0.327637f, -0.467773f, 0.371582f, -0.541504f, 0.420898f, -0.613281f,
-0.0512695f, -0.613281f, 0.0512695f, -0.687988f, 0.505859f, -0.687988f, 0.508789f,
--0.35791f, 0.508789f, -0.266113f, 0.491455f, -0.197021f, 0.474121f, -0.12793f, 0.441895f,
--0.0820312f, 0.409668f, -0.0361328f, 0.363525f, -0.0131836f, 0.317383f, 0.00976562f,
-0.259766f, 0.00976562f, 0.220215f, 0.00976562f, 0.188477f, 0.00170898f, 0.156738f,
--0.00634766f, 0.131836f, -0.0234375f, 0.106934f, -0.0405273f, 0.0893555f, -0.0678711f,
-0.0717773f, -0.0952148f, 0.0610352f, -0.133789f, 0.14502f, -0.146973f, 0.158691f,
--0.102539f, 0.187744f, -0.0817871f, 0.216797f, -0.0610352f, 0.26123f, -0.0610352f,
-0.296875f, -0.0610352f, 0.326416f, -0.0778809f, 0.355957f, -0.0947266f, 0.376709f,
--0.128418f, 0.397461f, -0.162109f, 0.40918f, -0.212891f, 0.420898f, -0.263672f, 0.421875f,
--0.332031f, 0.411621f, -0.309082f, 0.393799f, -0.291016f, 0.375977f, -0.272949f,
-0.353271f, -0.260498f, 0.330566f, -0.248047f, 0.304199f, -0.241455f, 0.277832f, -0.234863f,
-0.250977f, -0.234863f, 0.204102f, -0.234863f, 0.16626f, -0.251709f, 0.128418f, -0.268555f,
-0.102051f, -0.298828f, 0.0756836f, -0.329102f, 0.0612793f, -0.371826f, 0.046875f,
--0.414551f, 0.046875f, -0.466797f, 0.046875f, -0.52002f, 0.0622559f, -0.562988f,
-0.0776367f, -0.605957f, 0.106934f, -0.635986f, 0.13623f, -0.666016f, 0.178955f, -0.682129f,
-0.22168f, -0.698242f, 0.275879f, -0.698242f, 0.390625f, -0.698242f, 0.449707f, -0.613281f,
-0.508789f, -0.52832f, 0.508789f, -0.35791f, 0.413086f, -0.442871f, 0.413086f, -0.480957f,
-0.404053f, -0.514648f, 0.39502f, -0.54834f, 0.377197f, -0.573242f, 0.359375f, -0.598145f,
-0.333252f, -0.612549f, 0.307129f, -0.626953f, 0.272949f, -0.626953f, 0.241211f, -0.626953f,
-0.21582f, -0.615723f, 0.19043f, -0.604492f, 0.172852f, -0.58374f, 0.155273f, -0.562988f,
-0.145752f, -0.533203f, 0.13623f, -0.503418f, 0.13623f, -0.466797f, 0.13623f, -0.432129f,
-0.144775f, -0.402344f, 0.15332f, -0.372559f, 0.17041f, -0.35083f, 0.1875f, -0.329102f,
-0.212891f, -0.31665f, 0.238281f, -0.304199f, 0.271973f, -0.304199f, 0.296387f, -0.304199f,
-0.321533f, -0.3125f, 0.34668f, -0.320801f, 0.366943f, -0.337891f, 0.387207f, -0.35498f,
-0.400146f, -0.381104f, 0.413086f, -0.407227f, 0.413086f, -0.442871f, 0.0913086f,
--0.427246f, 0.0913086f, -0.52832f, 0.186523f, -0.52832f, 0.186523f, -0.427246f, 0.0913086f,
-0, 0.0913086f, -0.101074f, 0.186523f, -0.101074f, 0.186523f, 0, 0.187988f, -0.101074f,
-0.187988f, -0.0249023f, 0.187988f, 0.000976562f, 0.185791f, 0.0222168f, 0.183594f,
-0.043457f, 0.178711f, 0.0617676f, 0.173828f, 0.0800781f, 0.166748f, 0.0961914f, 0.159668f,
-0.112305f, 0.149902f, 0.12793f, 0.0898438f, 0.12793f, 0.111816f, 0.0961914f, 0.123779f,
-0.0639648f, 0.135742f, 0.0317383f, 0.135742f, 0, 0.0927734f, 0, 0.0927734f, -0.101074f,
-0.0927734f, -0.427246f, 0.0927734f, -0.52832f, 0.187988f, -0.52832f, 0.187988f, -0.427246f,
-0.0493164f, -0.278809f, 0.0493164f, -0.378906f, 0.535156f, -0.583008f, 0.535156f,
--0.507812f, 0.116211f, -0.329102f, 0.535156f, -0.149902f, 0.535156f, -0.0751953f,
-0.0488281f, -0.417969f, 0.0488281f, -0.490234f, 0.534668f, -0.490234f, 0.534668f,
--0.417969f, 0.0488281f, -0.167969f, 0.0488281f, -0.240234f, 0.534668f, -0.240234f,
-0.534668f, -0.167969f, 0.0493164f, -0.0751953f, 0.0493164f, -0.149902f, 0.468262f,
--0.329102f, 0.0493164f, -0.507812f, 0.0493164f, -0.583008f, 0.535156f, -0.378906f,
-0.535156f, -0.278809f, 0.519043f, -0.503906f, 0.519043f, -0.469238f, 0.51001f, -0.442871f,
-0.500977f, -0.416504f, 0.48584f, -0.395752f, 0.470703f, -0.375f, 0.451416f, -0.358643f,
-0.432129f, -0.342285f, 0.412109f, -0.327637f, 0.39209f, -0.312988f, 0.372803f, -0.298828f,
-0.353516f, -0.284668f, 0.338135f, -0.268066f, 0.322754f, -0.251465f, 0.313232f, -0.231201f,
-0.303711f, -0.210938f, 0.303223f, -0.184082f, 0.217773f, -0.184082f, 0.21875f, -0.217773f,
-0.228271f, -0.243164f, 0.237793f, -0.268555f, 0.25293f, -0.288086f, 0.268066f, -0.307617f,
-0.287109f, -0.322998f, 0.306152f, -0.338379f, 0.325684f, -0.352295f, 0.345215f, -0.366211f,
-0.364014f, -0.380127f, 0.382812f, -0.394043f, 0.397461f, -0.411133f, 0.412109f, -0.428223f,
-0.421143f, -0.449707f, 0.430176f, -0.471191f, 0.430176f, -0.5f, 0.430176f, -0.528809f,
-0.419922f, -0.55127f, 0.409668f, -0.57373f, 0.390869f, -0.589111f, 0.37207f, -0.604492f,
-0.345459f, -0.612305f, 0.318848f, -0.620117f, 0.286133f, -0.620117f, 0.217773f, -0.620117f,
-0.177734f, -0.585938f, 0.137695f, -0.551758f, 0.130859f, -0.492188f, 0.0410156f,
--0.498047f, 0.0463867f, -0.539062f, 0.0627441f, -0.575439f, 0.0791016f, -0.611816f,
-0.108643f, -0.63916f, 0.138184f, -0.666504f, 0.181885f, -0.682373f, 0.225586f, -0.698242f,
-0.285156f, -0.698242f, 0.34082f, -0.698242f, 0.384277f, -0.68457f, 0.427734f, -0.670898f,
-0.457764f, -0.645752f, 0.487793f, -0.620605f, 0.503418f, -0.584473f, 0.519043f, -0.54834f,
-0.519043f, -0.503906f, 0.213867f, 0, 0.213867f, -0.0981445f, 0.309082f, -0.0981445f,
-0.309082f, 0, 0.928711f, -0.368652f, 0.928711f, -0.29834f, 0.912354f, -0.23999f,
-0.895996f, -0.181641f, 0.867188f, -0.139648f, 0.838379f, -0.0976562f, 0.798096f,
--0.0742188f, 0.757812f, -0.0507812f, 0.710449f, -0.0507812f, 0.683105f, -0.0507812f,
-0.663818f, -0.057373f, 0.644531f, -0.0639648f, 0.632324f, -0.0754395f, 0.620117f,
--0.0869141f, 0.614746f, -0.102539f, 0.609375f, -0.118164f, 0.609375f, -0.136719f,
-0.609375f, -0.144043f, 0.609863f, -0.154541f, 0.610352f, -0.165039f, 0.61084f, -0.170898f,
-0.60791f, -0.170898f, 0.596191f, -0.148926f, 0.579346f, -0.127197f, 0.5625f, -0.105469f,
-0.539795f, -0.088623f, 0.51709f, -0.0717773f, 0.488525f, -0.0612793f, 0.459961f,
--0.0507812f, 0.425293f, -0.0507812f, 0.384277f, -0.0507812f, 0.35376f, -0.0649414f,
-0.323242f, -0.0791016f, 0.303467f, -0.104248f, 0.283691f, -0.129395f, 0.273926f,
--0.163818f, 0.26416f, -0.198242f, 0.26416f, -0.23877f, 0.26416f, -0.297363f, 0.281494f,
--0.351318f, 0.298828f, -0.405273f, 0.331055f, -0.446533f, 0.363281f, -0.487793f,
-0.408447f, -0.512695f, 0.453613f, -0.537598f, 0.509277f, -0.537598f, 0.538574f, -0.537598f,
-0.562012f, -0.531006f, 0.585449f, -0.524414f, 0.603271f, -0.512695f, 0.621094f, -0.500977f,
-0.634277f, -0.484619f, 0.647461f, -0.468262f, 0.65625f, -0.44873f, 0.65918f, -0.44873f,
-0.678223f, -0.526855f, 0.754395f, -0.526855f, 0.697754f, -0.279785f, 0.688477f, -0.23877f,
-0.684082f, -0.209473f, 0.679688f, -0.180176f, 0.679688f, -0.15625f, 0.679688f, -0.132812f,
-0.690186f, -0.121582f, 0.700684f, -0.110352f, 0.719238f, -0.110352f, 0.749512f, -0.110352f,
-0.775635f, -0.130127f, 0.801758f, -0.149902f, 0.821045f, -0.18457f, 0.840332f, -0.219238f,
-0.851318f, -0.266113f, 0.862305f, -0.312988f, 0.862305f, -0.367676f, 0.862305f, -0.430664f,
-0.842041f, -0.484863f, 0.821777f, -0.539062f, 0.782471f, -0.578613f, 0.743164f, -0.618164f,
-0.685059f, -0.640625f, 0.626953f, -0.663086f, 0.550781f, -0.663086f, 0.485352f, -0.663086f,
-0.429932f, -0.647461f, 0.374512f, -0.631836f, 0.32959f, -0.603516f, 0.284668f, -0.575195f,
-0.250732f, -0.535889f, 0.216797f, -0.496582f, 0.193848f, -0.449707f, 0.170898f, -0.402832f,
-0.15918f, -0.349365f, 0.147461f, -0.295898f, 0.147461f, -0.239746f, 0.147461f, -0.170898f,
-0.168457f, -0.112793f, 0.189453f, -0.0546875f, 0.229736f, -0.0129395f, 0.27002f,
-0.0288086f, 0.329346f, 0.0522461f, 0.388672f, 0.0756836f, 0.46582f, 0.0756836f, 0.51709f,
-0.0756836f, 0.561523f, 0.067627f, 0.605957f, 0.0595703f, 0.643066f, 0.0478516f, 0.680176f,
-0.0361328f, 0.709473f, 0.0222168f, 0.73877f, 0.00830078f, 0.760254f, -0.00341797f,
-0.787109f, 0.0512695f, 0.762695f, 0.065918f, 0.729736f, 0.0812988f, 0.696777f, 0.0966797f,
-0.65625f, 0.109375f, 0.615723f, 0.12207f, 0.567871f, 0.130127f, 0.52002f, 0.138184f,
-0.46582f, 0.138184f, 0.373047f, 0.138184f, 0.301025f, 0.110107f, 0.229004f, 0.0820312f,
-0.179443f, 0.0317383f, 0.129883f, -0.0185547f, 0.104248f, -0.0878906f, 0.0786133f,
--0.157227f, 0.0786133f, -0.239746f, 0.0786133f, -0.307617f, 0.0939941f, -0.370117f,
-0.109375f, -0.432617f, 0.138184f, -0.486328f, 0.166992f, -0.540039f, 0.208496f, -0.583984f,
-0.25f, -0.62793f, 0.30249f, -0.65918f, 0.35498f, -0.69043f, 0.417236f, -0.70752f,
-0.479492f, -0.724609f, 0.549805f, -0.724609f, 0.647949f, -0.724609f, 0.719238f, -0.695801f,
-0.790527f, -0.666992f, 0.837158f, -0.618164f, 0.883789f, -0.569336f, 0.90625f, -0.504883f,
-0.928711f, -0.44043f, 0.928711f, -0.368652f, 0.632812f, -0.364746f, 0.632812f, -0.38916f,
-0.624512f, -0.409668f, 0.616211f, -0.430176f, 0.60083f, -0.444824f, 0.585449f, -0.459473f,
-0.563721f, -0.467529f, 0.541992f, -0.475586f, 0.514648f, -0.475586f, 0.472656f, -0.475586f,
-0.440918f, -0.454834f, 0.40918f, -0.434082f, 0.387939f, -0.400391f, 0.366699f, -0.366699f,
-0.355713f, -0.324463f, 0.344727f, -0.282227f, 0.344727f, -0.239746f, 0.344727f, -0.181152f,
-0.36792f, -0.147949f, 0.391113f, -0.114746f, 0.439453f, -0.114746f, 0.473145f, -0.114746f,
-0.502441f, -0.129883f, 0.531738f, -0.14502f, 0.555176f, -0.169922f, 0.578613f, -0.194824f,
-0.595703f, -0.227051f, 0.612793f, -0.259277f, 0.621582f, -0.293945f, 0.625977f, -0.311523f,
-0.629395f, -0.331055f, 0.632812f, -0.350586f, 0.632812f, -0.364746f, 0.569824f, 0,
-0.491211f, -0.201172f, 0.177734f, -0.201172f, 0.0986328f, 0, 0.00195312f, 0, 0.282715f,
--0.687988f, 0.388672f, -0.687988f, 0.665039f, 0, 0.375f, -0.500977f, 0.367188f, -0.520508f,
-0.360107f, -0.540527f, 0.353027f, -0.560547f, 0.347656f, -0.576904f, 0.342285f, -0.593262f,
-0.338623f, -0.604248f, 0.334961f, -0.615234f, 0.334473f, -0.617676f, 0.333496f, -0.615234f,
-0.330078f, -0.604004f, 0.32666f, -0.592773f, 0.321045f, -0.576172f, 0.31543f, -0.55957f,
-0.30835f, -0.539551f, 0.30127f, -0.519531f, 0.293945f, -0.5f, 0.206055f, -0.273926f,
-0.463379f, -0.273926f, 0.614258f, -0.193848f, 0.614258f, -0.141602f, 0.59375f, -0.104736f,
-0.573242f, -0.0678711f, 0.538574f, -0.0446777f, 0.503906f, -0.0214844f, 0.458008f,
--0.0107422f, 0.412109f, 0, 0.361328f, 0, 0.0820312f, 0, 0.0820312f, -0.687988f, 0.332031f,
--0.687988f, 0.38916f, -0.687988f, 0.434082f, -0.678467f, 0.479004f, -0.668945f, 0.510254f,
--0.648438f, 0.541504f, -0.62793f, 0.557861f, -0.596436f, 0.574219f, -0.564941f, 0.574219f,
--0.520996f, 0.574219f, -0.492188f, 0.566162f, -0.466797f, 0.558105f, -0.441406f,
-0.541748f, -0.420654f, 0.525391f, -0.399902f, 0.500732f, -0.38501f, 0.476074f, -0.370117f,
-0.443359f, -0.362793f, 0.484863f, -0.35791f, 0.516846f, -0.34375f, 0.548828f, -0.32959f,
-0.570312f, -0.307617f, 0.591797f, -0.285645f, 0.603027f, -0.256592f, 0.614258f, -0.227539f,
-0.614258f, -0.193848f, 0.480469f, -0.509766f, 0.480469f, -0.56543f, 0.442383f, -0.589355f,
-0.404297f, -0.613281f, 0.332031f, -0.613281f, 0.175293f, -0.613281f, 0.175293f, -0.395508f,
-0.332031f, -0.395508f, 0.373047f, -0.395508f, 0.401367f, -0.403564f, 0.429688f, -0.411621f,
-0.447266f, -0.426514f, 0.464844f, -0.441406f, 0.472656f, -0.462402f, 0.480469f, -0.483398f,
-0.480469f, -0.509766f, 0.52002f, -0.201172f, 0.52002f, -0.233887f, 0.508057f, -0.256836f,
-0.496094f, -0.279785f, 0.473633f, -0.294434f, 0.451172f, -0.309082f, 0.419678f, -0.315918f,
-0.388184f, -0.322754f, 0.349121f, -0.322754f, 0.175293f, -0.322754f, 0.175293f, -0.074707f,
-0.356445f, -0.074707f, 0.39209f, -0.074707f, 0.422119f, -0.0805664f, 0.452148f, -0.0864258f,
-0.473877f, -0.101074f, 0.495605f, -0.115723f, 0.507812f, -0.140137f, 0.52002f, -0.164551f,
-0.52002f, -0.201172f, 0.386719f, -0.62207f, 0.328125f, -0.62207f, 0.282959f, -0.602539f,
-0.237793f, -0.583008f, 0.207275f, -0.546875f, 0.176758f, -0.510742f, 0.161133f, -0.459961f,
-0.145508f, -0.40918f, 0.145508f, -0.347168f, 0.145508f, -0.285156f, 0.162354f, -0.233643f,
-0.179199f, -0.182129f, 0.210693f, -0.14502f, 0.242188f, -0.10791f, 0.287842f, -0.0874023f,
-0.333496f, -0.0668945f, 0.390625f, -0.0668945f, 0.430664f, -0.0668945f, 0.463623f,
--0.0773926f, 0.496582f, -0.0878906f, 0.523193f, -0.106934f, 0.549805f, -0.125977f,
-0.570801f, -0.1521f, 0.591797f, -0.178223f, 0.60791f, -0.209961f, 0.684082f, -0.171875f,
-0.665527f, -0.133301f, 0.638184f, -0.100098f, 0.61084f, -0.0668945f, 0.573975f, -0.0424805f,
-0.537109f, -0.0180664f, 0.490479f, -0.00415039f, 0.443848f, 0.00976562f, 0.38623f,
-0.00976562f, 0.302734f, 0.00976562f, 0.23999f, -0.0168457f, 0.177246f, -0.043457f,
-0.13501f, -0.0910645f, 0.0927734f, -0.138672f, 0.0717773f, -0.204102f, 0.0507812f,
--0.269531f, 0.0507812f, -0.347168f, 0.0507812f, -0.427734f, 0.072998f, -0.492676f,
-0.0952148f, -0.557617f, 0.137939f, -0.603271f, 0.180664f, -0.648926f, 0.243164f,
--0.673584f, 0.305664f, -0.698242f, 0.385742f, -0.698242f, 0.495605f, -0.698242f,
-0.569336f, -0.655273f, 0.643066f, -0.612305f, 0.677734f, -0.527832f, 0.589355f, -0.498535f,
-0.57959f, -0.522949f, 0.562988f, -0.545166f, 0.546387f, -0.567383f, 0.521484f, -0.584473f,
-0.496582f, -0.601562f, 0.463135f, -0.611816f, 0.429688f, -0.62207f, 0.386719f, -0.62207f,
-0.674316f, -0.351074f, 0.674316f, -0.265137f, 0.648438f, -0.199463f, 0.622559f, -0.133789f,
-0.577637f, -0.0895996f, 0.532715f, -0.0454102f, 0.471436f, -0.0227051f, 0.410156f,
-0, 0.339355f, 0, 0.0820312f, 0, 0.0820312f, -0.687988f, 0.30957f, -0.687988f, 0.38916f,
--0.687988f, 0.456299f, -0.668213f, 0.523438f, -0.648438f, 0.571777f, -0.607178f,
-0.620117f, -0.565918f, 0.647217f, -0.502441f, 0.674316f, -0.438965f, 0.674316f, -0.351074f,
-0.580566f, -0.351074f, 0.580566f, -0.420898f, 0.560547f, -0.470459f, 0.540527f, -0.52002f,
-0.504395f, -0.551758f, 0.468262f, -0.583496f, 0.417969f, -0.598389f, 0.367676f, -0.613281f,
-0.307617f, -0.613281f, 0.175293f, -0.613281f, 0.175293f, -0.074707f, 0.328613f, -0.074707f,
-0.382812f, -0.074707f, 0.428955f, -0.0922852f, 0.475098f, -0.109863f, 0.508789f,
--0.144531f, 0.54248f, -0.179199f, 0.561523f, -0.230957f, 0.580566f, -0.282715f, 0.580566f,
--0.351074f, 0.0820312f, 0, 0.0820312f, -0.687988f, 0.604004f, -0.687988f, 0.604004f,
--0.611816f, 0.175293f, -0.611816f, 0.175293f, -0.391113f, 0.574707f, -0.391113f,
-0.574707f, -0.315918f, 0.175293f, -0.315918f, 0.175293f, -0.0761719f, 0.624023f,
--0.0761719f, 0.624023f, 0, 0.175293f, -0.611816f, 0.175293f, -0.355957f, 0.559082f,
--0.355957f, 0.559082f, -0.278809f, 0.175293f, -0.278809f, 0.175293f, 0, 0.0820312f,
-0, 0.0820312f, -0.687988f, 0.570801f, -0.687988f, 0.570801f, -0.611816f, 0.547363f,
-0, 0.547363f, -0.318848f, 0.175293f, -0.318848f, 0.175293f, 0, 0.0820312f, 0, 0.0820312f,
--0.687988f, 0.175293f, -0.687988f, 0.175293f, -0.396973f, 0.547363f, -0.396973f,
-0.547363f, -0.687988f, 0.640625f, -0.687988f, 0.640625f, 0, 0.0922852f, 0, 0.0922852f,
--0.687988f, 0.185547f, -0.687988f, 0.185547f, 0, 0.223145f, 0.00976562f, 0.139648f,
-0.00976562f, 0.0861816f, -0.0336914f, 0.0327148f, -0.0771484f, 0.015625f, -0.170898f,
-0.106934f, -0.186035f, 0.111816f, -0.154297f, 0.123047f, -0.131592f, 0.134277f, -0.108887f,
-0.149902f, -0.0942383f, 0.165527f, -0.0795898f, 0.18457f, -0.0727539f, 0.203613f,
--0.065918f, 0.223633f, -0.065918f, 0.274414f, -0.065918f, 0.303711f, -0.10083f, 0.333008f,
--0.135742f, 0.333008f, -0.203125f, 0.333008f, -0.611816f, 0.200684f, -0.611816f,
-0.200684f, -0.687988f, 0.425781f, -0.687988f, 0.425781f, -0.205078f, 0.425781f, -0.155762f,
-0.412109f, -0.116211f, 0.398438f, -0.0766602f, 0.372314f, -0.048584f, 0.346191f,
--0.0205078f, 0.308594f, -0.00537109f, 0.270996f, 0.00976562f, 0.223145f, 0.00976562f,
-0.540039f, 0, 0.265137f, -0.332031f, 0.175293f, -0.263672f, 0.175293f, 0, 0.0820312f,
-0, 0.0820312f, -0.687988f, 0.175293f, -0.687988f, 0.175293f, -0.343262f, 0.506836f,
--0.687988f, 0.616699f, -0.687988f, 0.32373f, -0.38916f, 0.655762f, 0, 0.0820312f,
-0, 0.0820312f, -0.687988f, 0.175293f, -0.687988f, 0.175293f, -0.0761719f, 0.522949f,
--0.0761719f, 0.522949f, 0, 0.666992f, 0, 0.666992f, -0.458984f, 0.666992f, -0.483887f,
-0.66748f, -0.509766f, 0.667969f, -0.535645f, 0.668945f, -0.557129f, 0.669922f, -0.582031f,
-0.671387f, -0.605469f, 0.664551f, -0.580566f, 0.657227f, -0.556152f, 0.650879f, -0.535156f,
-0.643311f, -0.511475f, 0.635742f, -0.487793f, 0.628418f, -0.46875f, 0.450684f, 0,
-0.385254f, 0, 0.205078f, -0.46875f, 0.202148f, -0.476074f, 0.198975f, -0.48584f,
-0.195801f, -0.495605f, 0.192139f, -0.506592f, 0.188477f, -0.517578f, 0.184814f, -0.529053f,
-0.181152f, -0.540527f, 0.177734f, -0.551758f, 0.169434f, -0.577637f, 0.161621f, -0.605469f,
-0.162109f, -0.578125f, 0.163086f, -0.55127f, 0.164062f, -0.52832f, 0.164551f, -0.503174f,
-0.165039f, -0.478027f, 0.165039f, -0.458984f, 0.165039f, 0, 0.0820312f, 0, 0.0820312f,
--0.687988f, 0.20459f, -0.687988f, 0.387695f, -0.210938f, 0.391113f, -0.201172f, 0.395996f,
--0.185791f, 0.400879f, -0.17041f, 0.405273f, -0.154297f, 0.409668f, -0.138184f, 0.41333f,
--0.123779f, 0.416992f, -0.109375f, 0.418457f, -0.101562f, 0.419922f, -0.109375f,
-0.423828f, -0.124023f, 0.427734f, -0.138672f, 0.432861f, -0.154785f, 0.437988f, -0.170898f,
-0.442871f, -0.186035f, 0.447754f, -0.201172f, 0.45166f, -0.210938f, 0.631348f, -0.687988f,
-0.750977f, -0.687988f, 0.750977f, 0, 0.52832f, 0, 0.160156f, -0.585938f, 0.161133f,
--0.562012f, 0.162598f, -0.538574f, 0.163574f, -0.518555f, 0.164307f, -0.496338f,
-0.165039f, -0.474121f, 0.165039f, -0.457031f, 0.165039f, 0, 0.0820312f, 0, 0.0820312f,
--0.687988f, 0.19043f, -0.687988f, 0.5625f, -0.0981445f, 0.561035f, -0.12207f, 0.55957f,
--0.145996f, 0.558594f, -0.166504f, 0.557617f, -0.190674f, 0.556641f, -0.214844f,
-0.556641f, -0.236816f, 0.556641f, -0.687988f, 0.640625f, -0.687988f, 0.640625f, 0,
-0.72998f, -0.347168f, 0.72998f, -0.266602f, 0.706787f, -0.200684f, 0.683594f, -0.134766f,
-0.639648f, -0.0878906f, 0.595703f, -0.0410156f, 0.532227f, -0.015625f, 0.46875f,
-0.00976562f, 0.388184f, 0.00976562f, 0.303223f, 0.00976562f, 0.239258f, -0.0168457f,
-0.175293f, -0.043457f, 0.132812f, -0.0910645f, 0.090332f, -0.138672f, 0.0688477f,
--0.204102f, 0.0473633f, -0.269531f, 0.0473633f, -0.347168f, 0.0473633f, -0.427734f,
-0.0698242f, -0.492676f, 0.0922852f, -0.557617f, 0.135742f, -0.603271f, 0.179199f,
--0.648926f, 0.24292f, -0.673584f, 0.306641f, -0.698242f, 0.38916f, -0.698242f, 0.471191f,
--0.698242f, 0.534912f, -0.67334f, 0.598633f, -0.648438f, 0.641846f, -0.602539f, 0.685059f,
--0.556641f, 0.70752f, -0.491699f, 0.72998f, -0.426758f, 0.72998f, -0.347168f, 0.634766f,
--0.347168f, 0.634766f, -0.40918f, 0.618896f, -0.459961f, 0.603027f, -0.510742f, 0.572021f,
--0.546875f, 0.541016f, -0.583008f, 0.495117f, -0.602539f, 0.449219f, -0.62207f, 0.38916f,
--0.62207f, 0.327637f, -0.62207f, 0.28125f, -0.602539f, 0.234863f, -0.583008f, 0.203857f,
--0.546875f, 0.172852f, -0.510742f, 0.157471f, -0.459961f, 0.14209f, -0.40918f, 0.14209f,
--0.347168f, 0.14209f, -0.285156f, 0.157959f, -0.233643f, 0.173828f, -0.182129f, 0.204834f,
--0.144775f, 0.23584f, -0.107422f, 0.281982f, -0.0866699f, 0.328125f, -0.065918f,
-0.388184f, -0.065918f, 0.452637f, -0.065918f, 0.499268f, -0.0869141f, 0.545898f,
--0.10791f, 0.575928f, -0.145264f, 0.605957f, -0.182617f, 0.620361f, -0.234375f, 0.634766f,
--0.286133f, 0.634766f, -0.347168f, 0.614258f, -0.480957f, 0.614258f, -0.436035f,
-0.599365f, -0.397217f, 0.584473f, -0.358398f, 0.554932f, -0.329834f, 0.525391f, -0.30127f,
-0.480957f, -0.284668f, 0.436523f, -0.268066f, 0.377441f, -0.268066f, 0.175293f, -0.268066f,
-0.175293f, 0, 0.0820312f, 0, 0.0820312f, -0.687988f, 0.371582f, -0.687988f, 0.432617f,
--0.687988f, 0.478027f, -0.673096f, 0.523438f, -0.658203f, 0.553711f, -0.631104f,
-0.583984f, -0.604004f, 0.599121f, -0.565674f, 0.614258f, -0.527344f, 0.614258f, -0.480957f,
-0.520508f, -0.47998f, 0.520508f, -0.54541f, 0.480469f, -0.579346f, 0.44043f, -0.613281f,
-0.360352f, -0.613281f, 0.175293f, -0.613281f, 0.175293f, -0.341797f, 0.364258f, -0.341797f,
-0.444824f, -0.341797f, 0.482666f, -0.377441f, 0.520508f, -0.413086f, 0.520508f, -0.47998f,
-0.72998f, -0.347168f, 0.72998f, -0.274414f, 0.711182f, -0.214111f, 0.692383f, -0.153809f,
-0.656982f, -0.108398f, 0.621582f, -0.0629883f, 0.570068f, -0.0344238f, 0.518555f,
--0.00585938f, 0.453125f, 0.00292969f, 0.463379f, 0.0341797f, 0.476318f, 0.0561523f,
-0.489258f, 0.078125f, 0.505859f, 0.092041f, 0.522461f, 0.105957f, 0.542725f, 0.112549f,
-0.562988f, 0.119141f, 0.587891f, 0.119141f, 0.601562f, 0.119141f, 0.617188f, 0.117188f,
-0.632812f, 0.115234f, 0.644043f, 0.112793f, 0.644043f, 0.178223f, 0.625488f, 0.182617f,
-0.603271f, 0.185791f, 0.581055f, 0.188965f, 0.557129f, 0.188965f, 0.515137f, 0.188965f,
-0.483887f, 0.176514f, 0.452637f, 0.164062f, 0.428955f, 0.140869f, 0.405273f, 0.117676f,
-0.388184f, 0.0839844f, 0.371094f, 0.050293f, 0.35791f, 0.0078125f, 0.280762f, 0.00390625f,
-0.222412f, -0.0241699f, 0.164062f, -0.0522461f, 0.125244f, -0.0993652f, 0.0864258f,
--0.146484f, 0.0668945f, -0.209717f, 0.0473633f, -0.272949f, 0.0473633f, -0.347168f,
-0.0473633f, -0.427734f, 0.0698242f, -0.492676f, 0.0922852f, -0.557617f, 0.135742f,
--0.603271f, 0.179199f, -0.648926f, 0.24292f, -0.673584f, 0.306641f, -0.698242f, 0.38916f,
--0.698242f, 0.471191f, -0.698242f, 0.534912f, -0.67334f, 0.598633f, -0.648438f, 0.641846f,
--0.602539f, 0.685059f, -0.556641f, 0.70752f, -0.491699f, 0.72998f, -0.426758f, 0.72998f,
--0.347168f, 0.634766f, -0.347168f, 0.634766f, -0.40918f, 0.618896f, -0.459961f, 0.603027f,
--0.510742f, 0.572021f, -0.546875f, 0.541016f, -0.583008f, 0.495117f, -0.602539f,
-0.449219f, -0.62207f, 0.38916f, -0.62207f, 0.327637f, -0.62207f, 0.28125f, -0.602539f,
-0.234863f, -0.583008f, 0.203857f, -0.546875f, 0.172852f, -0.510742f, 0.157471f, -0.459961f,
-0.14209f, -0.40918f, 0.14209f, -0.347168f, 0.14209f, -0.285156f, 0.157959f, -0.233643f,
-0.173828f, -0.182129f, 0.204834f, -0.144775f, 0.23584f, -0.107422f, 0.281982f, -0.0866699f,
-0.328125f, -0.065918f, 0.388184f, -0.065918f, 0.452637f, -0.065918f, 0.499268f, -0.0869141f,
-0.545898f, -0.10791f, 0.575928f, -0.145264f, 0.605957f, -0.182617f, 0.620361f, -0.234375f,
-0.634766f, -0.286133f, 0.634766f, -0.347168f, 0.568359f, 0, 0.389648f, -0.285645f,
-0.175293f, -0.285645f, 0.175293f, 0, 0.0820312f, 0, 0.0820312f, -0.687988f, 0.405762f,
--0.687988f, 0.464355f, -0.687988f, 0.509521f, -0.674561f, 0.554688f, -0.661133f,
-0.585449f, -0.635742f, 0.616211f, -0.610352f, 0.632324f, -0.57373f, 0.648438f, -0.537109f,
-0.648438f, -0.491211f, 0.648438f, -0.458496f, 0.638916f, -0.426758f, 0.629395f, -0.39502f,
-0.608887f, -0.368652f, 0.588379f, -0.342285f, 0.556641f, -0.323242f, 0.524902f, -0.304199f,
-0.480469f, -0.296387f, 0.675781f, 0, 0.554688f, -0.490234f, 0.554688f, -0.521484f,
-0.543945f, -0.544434f, 0.533203f, -0.567383f, 0.512695f, -0.582764f, 0.492188f, -0.598145f,
-0.462891f, -0.605713f, 0.433594f, -0.613281f, 0.396484f, -0.613281f, 0.175293f, -0.613281f,
-0.175293f, -0.359375f, 0.400391f, -0.359375f, 0.44043f, -0.359375f, 0.469727f, -0.369385f,
-0.499023f, -0.379395f, 0.517822f, -0.396973f, 0.536621f, -0.414551f, 0.545654f, -0.438477f,
-0.554688f, -0.462402f, 0.554688f, -0.490234f, 0.621094f, -0.189941f, 0.621094f, -0.146484f,
-0.604248f, -0.109863f, 0.587402f, -0.0732422f, 0.552246f, -0.0466309f, 0.51709f,
--0.0200195f, 0.463623f, -0.00512695f, 0.410156f, 0.00976562f, 0.336914f, 0.00976562f,
-0.208496f, 0.00976562f, 0.136719f, -0.0351562f, 0.0649414f, -0.0800781f, 0.0454102f,
--0.165039f, 0.135742f, -0.183105f, 0.142578f, -0.15625f, 0.156738f, -0.134277f, 0.170898f,
--0.112305f, 0.195068f, -0.0964355f, 0.219238f, -0.0805664f, 0.254883f, -0.0717773f,
-0.290527f, -0.0629883f, 0.340332f, -0.0629883f, 0.381836f, -0.0629883f, 0.416504f,
--0.0700684f, 0.451172f, -0.0771484f, 0.476074f, -0.0917969f, 0.500977f, -0.106445f,
-0.514893f, -0.129639f, 0.528809f, -0.152832f, 0.528809f, -0.185059f, 0.528809f, -0.21875f,
-0.513428f, -0.239746f, 0.498047f, -0.260742f, 0.470215f, -0.274414f, 0.442383f, -0.288086f,
-0.403809f, -0.297363f, 0.365234f, -0.306641f, 0.318359f, -0.317383f, 0.289551f, -0.32373f,
-0.260498f, -0.331299f, 0.231445f, -0.338867f, 0.204834f, -0.349365f, 0.178223f, -0.359863f,
-0.154785f, -0.374023f, 0.131348f, -0.388184f, 0.114258f, -0.407959f, 0.097168f, -0.427734f,
-0.0874023f, -0.453857f, 0.0776367f, -0.47998f, 0.0776367f, -0.51416f, 0.0776367f,
--0.562988f, 0.0974121f, -0.5979f, 0.117188f, -0.632812f, 0.152344f, -0.655273f, 0.1875f,
--0.677734f, 0.235352f, -0.687988f, 0.283203f, -0.698242f, 0.338867f, -0.698242f,
-0.402832f, -0.698242f, 0.448242f, -0.688232f, 0.493652f, -0.678223f, 0.524902f, -0.658203f,
-0.556152f, -0.638184f, 0.574951f, -0.608643f, 0.59375f, -0.579102f, 0.60498f, -0.540039f,
-0.513184f, -0.523926f, 0.506348f, -0.548828f, 0.493408f, -0.568359f, 0.480469f, -0.587891f,
-0.459473f, -0.601074f, 0.438477f, -0.614258f, 0.408447f, -0.621094f, 0.378418f, -0.62793f,
-0.337891f, -0.62793f, 0.290039f, -0.62793f, 0.257568f, -0.619385f, 0.225098f, -0.61084f,
-0.205322f, -0.596191f, 0.185547f, -0.581543f, 0.177002f, -0.561768f, 0.168457f, -0.541992f,
-0.168457f, -0.519043f, 0.168457f, -0.488281f, 0.183838f, -0.468506f, 0.199219f, -0.44873f,
-0.225586f, -0.435547f, 0.251953f, -0.422363f, 0.286621f, -0.413574f, 0.321289f, -0.404785f,
-0.360352f, -0.395996f, 0.39209f, -0.388672f, 0.423584f, -0.381104f, 0.455078f, -0.373535f,
-0.483887f, -0.363037f, 0.512695f, -0.352539f, 0.537842f, -0.338379f, 0.562988f, -0.324219f,
-0.581543f, -0.303711f, 0.600098f, -0.283203f, 0.610596f, -0.255371f, 0.621094f, -0.227539f,
-0.621094f, -0.189941f, 0.351562f, -0.611816f, 0.351562f, 0, 0.258789f, 0, 0.258789f,
--0.611816f, 0.0224609f, -0.611816f, 0.0224609f, -0.687988f, 0.587891f, -0.687988f,
-0.587891f, -0.611816f, 0.381836f, 0, 0.285156f, 0, 0.00439453f, -0.687988f, 0.102539f,
--0.687988f, 0.292969f, -0.203613f, 0.300293f, -0.181641f, 0.307617f, -0.159912f,
-0.314941f, -0.138184f, 0.320801f, -0.121094f, 0.327637f, -0.101074f, 0.333984f, -0.0820312f,
-0.339844f, -0.100098f, 0.34668f, -0.120117f, 0.352539f, -0.137207f, 0.359619f, -0.158691f,
-0.366699f, -0.180176f, 0.375f, -0.203613f, 0.564453f, -0.687988f, 0.662598f, -0.687988f,
-0.737793f, 0, 0.626465f, 0, 0.507324f, -0.437012f, 0.501953f, -0.455566f, 0.49585f,
--0.480957f, 0.489746f, -0.506348f, 0.484863f, -0.529297f, 0.479004f, -0.556152f,
-0.473145f, -0.583984f, 0.466797f, -0.555664f, 0.460938f, -0.528809f, 0.455566f, -0.505371f,
-0.449707f, -0.480469f, 0.443848f, -0.455566f, 0.438477f, -0.437012f, 0.318359f, 0,
-0.207031f, 0, 0.00439453f, -0.687988f, 0.101562f, -0.687988f, 0.225098f, -0.250977f,
-0.233398f, -0.220215f, 0.240967f, -0.189941f, 0.248535f, -0.159668f, 0.253906f, -0.135742f,
-0.260254f, -0.107422f, 0.265625f, -0.0820312f, 0.272949f, -0.115723f, 0.280762f,
--0.148438f, 0.28418f, -0.162109f, 0.287598f, -0.177246f, 0.291016f, -0.192383f, 0.294678f,
--0.207031f, 0.29834f, -0.22168f, 0.302002f, -0.235107f, 0.305664f, -0.248535f, 0.308594f,
--0.259766f, 0.428223f, -0.687988f, 0.517578f, -0.687988f, 0.637207f, -0.259766f,
-0.640137f, -0.248535f, 0.643799f, -0.235107f, 0.647461f, -0.22168f, 0.651123f, -0.207275f,
-0.654785f, -0.192871f, 0.658203f, -0.177734f, 0.661621f, -0.162598f, 0.665039f, -0.148926f,
-0.672852f, -0.116211f, 0.680176f, -0.0820312f, 0.680664f, -0.0820312f, 0.68457f,
--0.098877f, 0.688477f, -0.115723f, 0.694336f, -0.141113f, 0.700195f, -0.166504f,
-0.707275f, -0.196045f, 0.714355f, -0.225586f, 0.72168f, -0.250977f, 0.843262f, -0.687988f,
-0.94043f, -0.687988f, 0.542969f, 0, 0.336426f, -0.300781f, 0.125488f, 0, 0.0224609f,
-0, 0.28418f, -0.357422f, 0.0424805f, -0.687988f, 0.145508f, -0.687988f, 0.336914f,
--0.417969f, 0.522949f, -0.687988f, 0.625977f, -0.687988f, 0.390625f, -0.36084f, 0.645996f,
-0, 0.379395f, -0.285156f, 0.379395f, 0, 0.286621f, 0, 0.286621f, -0.285156f, 0.0219727f,
--0.687988f, 0.124512f, -0.687988f, 0.333984f, -0.360352f, 0.54248f, -0.687988f, 0.64502f,
--0.687988f, 0.57959f, 0, 0.0317383f, 0, 0.0317383f, -0.0698242f, 0.450684f, -0.611816f,
-0.0673828f, -0.611816f, 0.0673828f, -0.687988f, 0.556641f, -0.687988f, 0.556641f,
--0.620117f, 0.137695f, -0.0761719f, 0.57959f, -0.0761719f, 0.0712891f, 0.20752f,
-0.0712891f, -0.724609f, 0.27002f, -0.724609f, 0.27002f, -0.661621f, 0.15625f, -0.661621f,
-0.15625f, 0.144531f, 0.27002f, 0.144531f, 0.27002f, 0.20752f, 0.19873f, 0.00976562f,
-0, -0.724609f, 0.0771484f, -0.724609f, 0.277832f, 0.00976562f, 0.0078125f, 0.20752f,
-0.0078125f, 0.144531f, 0.121582f, 0.144531f, 0.121582f, -0.661621f, 0.0078125f, -0.661621f,
-0.0078125f, -0.724609f, 0.206543f, -0.724609f, 0.206543f, 0.20752f, 0.384277f, -0.328613f,
-0.233398f, -0.637695f, 0.0839844f, -0.328613f, 0.00488281f, -0.328613f, 0.18457f,
--0.687988f, 0.283691f, -0.687988f, 0.464355f, -0.328613f, 0.212891f, -0.586426f,
-0.0517578f, -0.722168f, 0.0517578f, -0.736328f, 0.152832f, -0.736328f, 0.258789f,
--0.596191f, 0.258789f, -0.586426f, 0.202148f, 0.00976562f, 0.122559f, 0.00976562f,
-0.0825195f, -0.0322266f, 0.0424805f, -0.0742188f, 0.0424805f, -0.147461f, 0.0424805f,
--0.199707f, 0.0622559f, -0.233154f, 0.0820312f, -0.266602f, 0.114014f, -0.285645f,
-0.145996f, -0.304688f, 0.187012f, -0.312012f, 0.228027f, -0.319336f, 0.270508f, -0.320312f,
-0.38916f, -0.322266f, 0.38916f, -0.351074f, 0.38916f, -0.383789f, 0.382324f, -0.406738f,
-0.375488f, -0.429688f, 0.361328f, -0.443848f, 0.347168f, -0.458008f, 0.325928f, -0.4646f,
-0.304688f, -0.471191f, 0.275879f, -0.471191f, 0.250488f, -0.471191f, 0.22998f, -0.467529f,
-0.209473f, -0.463867f, 0.194336f, -0.454346f, 0.179199f, -0.444824f, 0.169922f, -0.428467f,
-0.160645f, -0.412109f, 0.157715f, -0.387207f, 0.065918f, -0.395508f, 0.0708008f,
--0.426758f, 0.0844727f, -0.452881f, 0.0981445f, -0.479004f, 0.123291f, -0.498047f,
-0.148438f, -0.51709f, 0.186279f, -0.527588f, 0.224121f, -0.538086f, 0.277832f, -0.538086f,
-0.377441f, -0.538086f, 0.427734f, -0.492432f, 0.478027f, -0.446777f, 0.478027f, -0.360352f,
-0.478027f, -0.132812f, 0.478027f, -0.09375f, 0.488281f, -0.0739746f, 0.498535f, -0.0541992f,
-0.527344f, -0.0541992f, 0.534668f, -0.0541992f, 0.541992f, -0.0551758f, 0.549316f,
--0.0561523f, 0.556152f, -0.0576172f, 0.556152f, -0.00292969f, 0.539551f, 0.000976562f,
-0.523193f, 0.00292969f, 0.506836f, 0.00488281f, 0.488281f, 0.00488281f, 0.463379f,
-0.00488281f, 0.445557f, -0.00170898f, 0.427734f, -0.00830078f, 0.416504f, -0.0217285f,
-0.405273f, -0.0351562f, 0.399414f, -0.0549316f, 0.393555f, -0.074707f, 0.39209f,
--0.101074f, 0.38916f, -0.101074f, 0.375f, -0.0756836f, 0.358154f, -0.0551758f, 0.341309f,
--0.034668f, 0.318848f, -0.0202637f, 0.296387f, -0.00585938f, 0.267822f, 0.00195312f,
-0.239258f, 0.00976562f, 0.202148f, 0.00976562f, 0.222168f, -0.0561523f, 0.26416f,
--0.0561523f, 0.295654f, -0.0715332f, 0.327148f, -0.0869141f, 0.3479f, -0.11084f,
-0.368652f, -0.134766f, 0.378906f, -0.163086f, 0.38916f, -0.191406f, 0.38916f, -0.217285f,
-0.38916f, -0.260742f, 0.292969f, -0.258789f, 0.260742f, -0.258301f, 0.231689f, -0.25415f,
-0.202637f, -0.25f, 0.180664f, -0.237793f, 0.158691f, -0.225586f, 0.145752f, -0.203613f,
-0.132812f, -0.181641f, 0.132812f, -0.145996f, 0.132812f, -0.103027f, 0.156006f, -0.0795898f,
-0.179199f, -0.0561523f, 0.222168f, -0.0561523f, 0.51416f, -0.266602f, 0.51416f, 0.00976562f,
-0.319824f, 0.00976562f, 0.259766f, 0.00976562f, 0.219971f, -0.0119629f, 0.180176f,
--0.0336914f, 0.155273f, -0.0820312f, 0.154297f, -0.0820312f, 0.154297f, -0.0693359f,
-0.153564f, -0.0556641f, 0.152832f, -0.0419922f, 0.1521f, -0.0302734f, 0.151367f,
--0.0185547f, 0.150635f, -0.0102539f, 0.149902f, -0.00195312f, 0.149414f, 0, 0.0644531f,
-0, 0.0649414f, -0.00439453f, 0.0654297f, -0.0148926f, 0.065918f, -0.0253906f, 0.0664062f,
--0.0400391f, 0.0668945f, -0.0546875f, 0.0671387f, -0.0722656f, 0.0673828f, -0.0898438f,
-0.0673828f, -0.108887f, 0.0673828f, -0.724609f, 0.155273f, -0.724609f, 0.155273f,
--0.518066f, 0.155273f, -0.503418f, 0.155029f, -0.48999f, 0.154785f, -0.476562f, 0.154297f,
--0.466309f, 0.153809f, -0.454102f, 0.15332f, -0.443359f, 0.155273f, -0.443359f, 0.179688f,
--0.494141f, 0.219971f, -0.516113f, 0.260254f, -0.538086f, 0.319824f, -0.538086f,
-0.419922f, -0.538086f, 0.467041f, -0.470703f, 0.51416f, -0.40332f, 0.51416f, -0.266602f,
-0.421875f, -0.263672f, 0.421875f, -0.318359f, 0.415039f, -0.357422f, 0.408203f, -0.396484f,
-0.393066f, -0.421631f, 0.37793f, -0.446777f, 0.354492f, -0.458496f, 0.331055f, -0.470215f,
-0.297363f, -0.470215f, 0.262695f, -0.470215f, 0.236084f, -0.458984f, 0.209473f, -0.447754f,
-0.19165f, -0.422852f, 0.173828f, -0.397949f, 0.164551f, -0.357422f, 0.155273f, -0.316895f,
-0.155273f, -0.258301f, 0.155273f, -0.20166f, 0.164551f, -0.163086f, 0.173828f, -0.124512f,
-0.19165f, -0.100342f, 0.209473f, -0.0761719f, 0.23584f, -0.0656738f, 0.262207f, -0.0551758f,
-0.296387f, -0.0551758f, 0.328613f, -0.0551758f, 0.352051f, -0.0664062f, 0.375488f,
--0.0776367f, 0.391113f, -0.102539f, 0.406738f, -0.127441f, 0.414307f, -0.167236f,
-0.421875f, -0.207031f, 0.421875f, -0.263672f, 0.134277f, -0.266602f, 0.134277f, -0.221191f,
-0.140869f, -0.183105f, 0.147461f, -0.14502f, 0.163086f, -0.117432f, 0.178711f, -0.0898438f,
-0.204346f, -0.074707f, 0.22998f, -0.0595703f, 0.267578f, -0.0595703f, 0.314453f,
--0.0595703f, 0.345947f, -0.0849609f, 0.377441f, -0.110352f, 0.384766f, -0.163086f,
-0.473633f, -0.157227f, 0.469238f, -0.124512f, 0.45459f, -0.0942383f, 0.439941f, -0.0639648f,
-0.414795f, -0.0410156f, 0.389648f, -0.0180664f, 0.353516f, -0.00415039f, 0.317383f,
-0.00976562f, 0.27002f, 0.00976562f, 0.208008f, 0.00976562f, 0.164551f, -0.0112305f,
-0.121094f, -0.0322266f, 0.0939941f, -0.0690918f, 0.0668945f, -0.105957f, 0.0546875f,
--0.156006f, 0.0424805f, -0.206055f, 0.0424805f, -0.264648f, 0.0424805f, -0.317871f,
-0.0512695f, -0.358643f, 0.0600586f, -0.399414f, 0.0759277f, -0.429932f, 0.0917969f,
--0.460449f, 0.113281f, -0.481201f, 0.134766f, -0.501953f, 0.159912f, -0.514404f,
-0.185059f, -0.526855f, 0.212891f, -0.532471f, 0.240723f, -0.538086f, 0.269043f, -0.538086f,
-0.313477f, -0.538086f, 0.348145f, -0.525879f, 0.382812f, -0.513672f, 0.407959f, -0.492432f,
-0.433105f, -0.471191f, 0.44873f, -0.442383f, 0.464355f, -0.413574f, 0.470703f, -0.380371f,
-0.380371f, -0.373535f, 0.373535f, -0.41748f, 0.345703f, -0.443359f, 0.317871f, -0.469238f,
-0.266602f, -0.469238f, 0.229004f, -0.469238f, 0.203857f, -0.456787f, 0.178711f, -0.444336f,
-0.163086f, -0.419189f, 0.147461f, -0.394043f, 0.140869f, -0.355957f, 0.134277f, -0.317871f,
-0.134277f, -0.266602f, 0.400879f, -0.0849609f, 0.376465f, -0.0341797f, 0.336182f,
--0.012207f, 0.295898f, 0.00976562f, 0.236328f, 0.00976562f, 0.13623f, 0.00976562f,
-0.0891113f, -0.0576172f, 0.0419922f, -0.125f, 0.0419922f, -0.261719f, 0.0419922f,
--0.538086f, 0.236328f, -0.538086f, 0.296387f, -0.538086f, 0.336426f, -0.516113f,
-0.376465f, -0.494141f, 0.400879f, -0.446289f, 0.401855f, -0.446289f, 0.401855f, -0.451172f,
-0.401611f, -0.46167f, 0.401367f, -0.472168f, 0.401123f, -0.483643f, 0.400879f, -0.495117f,
-0.400879f, -0.505371f, 0.400879f, -0.515625f, 0.400879f, -0.52002f, 0.400879f, -0.724609f,
-0.48877f, -0.724609f, 0.48877f, -0.108887f, 0.48877f, -0.0898438f, 0.489014f, -0.0722656f,
-0.489258f, -0.0546875f, 0.489746f, -0.0400391f, 0.490234f, -0.0253906f, 0.490723f,
--0.0148926f, 0.491211f, -0.00439453f, 0.491699f, 0, 0.407715f, 0, 0.406738f, -0.00488281f,
-0.406006f, -0.013916f, 0.405273f, -0.0229492f, 0.404541f, -0.034668f, 0.403809f,
--0.0463867f, 0.40332f, -0.0593262f, 0.402832f, -0.0722656f, 0.402832f, -0.0849609f,
-0.134277f, -0.264648f, 0.134277f, -0.209961f, 0.141113f, -0.170898f, 0.147949f, -0.131836f,
-0.163086f, -0.106689f, 0.178223f, -0.081543f, 0.20166f, -0.0698242f, 0.225098f, -0.0581055f,
-0.258789f, -0.0581055f, 0.293457f, -0.0581055f, 0.320068f, -0.0693359f, 0.34668f,
--0.0805664f, 0.364502f, -0.105713f, 0.382324f, -0.130859f, 0.391602f, -0.171387f,
-0.400879f, -0.211914f, 0.400879f, -0.270508f, 0.400879f, -0.32666f, 0.391602f, -0.365479f,
-0.382324f, -0.404297f, 0.364258f, -0.428223f, 0.346191f, -0.452148f, 0.320068f, -0.462646f,
-0.293945f, -0.473145f, 0.259766f, -0.473145f, 0.227539f, -0.473145f, 0.204102f, -0.461914f,
-0.180664f, -0.450684f, 0.165039f, -0.425781f, 0.149414f, -0.400879f, 0.141846f, -0.361084f,
-0.134277f, -0.321289f, 0.134277f, -0.264648f, 0.134766f, -0.245605f, 0.134766f, -0.204102f,
-0.143311f, -0.169189f, 0.151855f, -0.134277f, 0.169678f, -0.109131f, 0.1875f, -0.0839844f,
-0.215332f, -0.0700684f, 0.243164f, -0.0561523f, 0.282227f, -0.0561523f, 0.339355f,
--0.0561523f, 0.373779f, -0.0791016f, 0.408203f, -0.102051f, 0.42041f, -0.137207f,
-0.497559f, -0.115234f, 0.489258f, -0.0932617f, 0.474365f, -0.0710449f, 0.459473f,
--0.0488281f, 0.43457f, -0.0310059f, 0.409668f, -0.0131836f, 0.372314f, -0.00170898f,
-0.334961f, 0.00976562f, 0.282227f, 0.00976562f, 0.165039f, 0.00976562f, 0.10376f,
--0.0600586f, 0.0424805f, -0.129883f, 0.0424805f, -0.267578f, 0.0424805f, -0.341797f,
-0.0610352f, -0.393311f, 0.0795898f, -0.444824f, 0.111816f, -0.477051f, 0.144043f,
--0.509277f, 0.187012f, -0.523682f, 0.22998f, -0.538086f, 0.278809f, -0.538086f, 0.345215f,
--0.538086f, 0.389893f, -0.516602f, 0.43457f, -0.495117f, 0.46167f, -0.457275f, 0.48877f,
--0.419434f, 0.500244f, -0.368164f, 0.511719f, -0.316895f, 0.511719f, -0.257324f,
-0.511719f, -0.245605f, 0.420898f, -0.312988f, 0.413574f, -0.396484f, 0.378418f, -0.434814f,
-0.343262f, -0.473145f, 0.277344f, -0.473145f, 0.255371f, -0.473145f, 0.231201f, -0.466064f,
-0.207031f, -0.458984f, 0.186523f, -0.440918f, 0.166016f, -0.422852f, 0.151855f, -0.391846f,
-0.137695f, -0.36084f, 0.135742f, -0.312988f, 0.17627f, -0.464355f, 0.17627f, 0, 0.0883789f,
-0, 0.0883789f, -0.464355f, 0.0141602f, -0.464355f, 0.0141602f, -0.52832f, 0.0883789f,
--0.52832f, 0.0883789f, -0.587891f, 0.0883789f, -0.616699f, 0.09375f, -0.641357f,
-0.0991211f, -0.666016f, 0.113525f, -0.684326f, 0.12793f, -0.702637f, 0.152832f, -0.713135f,
-0.177734f, -0.723633f, 0.217285f, -0.723633f, 0.23291f, -0.723633f, 0.249756f, -0.722168f,
-0.266602f, -0.720703f, 0.279297f, -0.717773f, 0.279297f, -0.650879f, 0.270996f, -0.652344f,
-0.26001f, -0.653564f, 0.249023f, -0.654785f, 0.240234f, -0.654785f, 0.220703f, -0.654785f,
-0.208252f, -0.649414f, 0.195801f, -0.644043f, 0.188721f, -0.634033f, 0.181641f, -0.624023f,
-0.178955f, -0.609375f, 0.17627f, -0.594727f, 0.17627f, -0.575684f, 0.17627f, -0.52832f,
-0.279297f, -0.52832f, 0.279297f, -0.464355f, 0.267578f, 0.20752f, 0.222168f, 0.20752f,
-0.187012f, 0.198242f, 0.151855f, 0.188965f, 0.126953f, 0.171631f, 0.102051f, 0.154297f,
-0.0864258f, 0.130371f, 0.0708008f, 0.106445f, 0.0639648f, 0.0771484f, 0.152344f,
-0.0644531f, 0.161133f, 0.101074f, 0.191162f, 0.12085f, 0.221191f, 0.140625f, 0.27002f,
-0.140625f, 0.299805f, 0.140625f, 0.324219f, 0.132324f, 0.348633f, 0.124023f, 0.365723f,
-0.105713f, 0.382812f, 0.0874023f, 0.39209f, 0.0581055f, 0.401367f, 0.0288086f, 0.401367f,
--0.0131836f, 0.401367f, -0.0981445f, 0.400391f, -0.0981445f, 0.390625f, -0.078125f,
-0.376221f, -0.0598145f, 0.361816f, -0.0415039f, 0.341064f, -0.0273438f, 0.320312f,
--0.0131836f, 0.292969f, -0.00463867f, 0.265625f, 0.00390625f, 0.230469f, 0.00390625f,
-0.180176f, 0.00390625f, 0.144287f, -0.0129395f, 0.108398f, -0.0297852f, 0.0856934f,
--0.0634766f, 0.0629883f, -0.097168f, 0.0524902f, -0.147217f, 0.0419922f, -0.197266f,
-0.0419922f, -0.263184f, 0.0419922f, -0.32666f, 0.0524902f, -0.377441f, 0.0629883f,
--0.428223f, 0.0866699f, -0.463623f, 0.110352f, -0.499023f, 0.148193f, -0.517822f,
-0.186035f, -0.536621f, 0.240234f, -0.536621f, 0.296387f, -0.536621f, 0.337646f, -0.510986f,
-0.378906f, -0.485352f, 0.401367f, -0.437988f, 0.402344f, -0.437988f, 0.402344f, -0.450195f,
-0.403076f, -0.465332f, 0.403809f, -0.480469f, 0.404541f, -0.493896f, 0.405273f, -0.507324f,
-0.40625f, -0.51709f, 0.407227f, -0.526855f, 0.408203f, -0.52832f, 0.491699f, -0.52832f,
-0.491211f, -0.523926f, 0.490723f, -0.513428f, 0.490234f, -0.50293f, 0.489746f, -0.488281f,
-0.489258f, -0.473633f, 0.489014f, -0.455811f, 0.48877f, -0.437988f, 0.48877f, -0.418945f,
-0.48877f, -0.0151367f, 0.48877f, 0.0957031f, 0.434326f, 0.151611f, 0.379883f, 0.20752f,
-0.267578f, 0.20752f, 0.401367f, -0.26416f, 0.401367f, -0.319336f, 0.389404f, -0.358643f,
-0.377441f, -0.397949f, 0.35791f, -0.422852f, 0.338379f, -0.447754f, 0.313232f, -0.459473f,
-0.288086f, -0.471191f, 0.261719f, -0.471191f, 0.228027f, -0.471191f, 0.203857f, -0.459473f,
-0.179688f, -0.447754f, 0.163818f, -0.422607f, 0.147949f, -0.397461f, 0.140381f, -0.358154f,
-0.132812f, -0.318848f, 0.132812f, -0.26416f, 0.132812f, -0.207031f, 0.140381f, -0.168213f,
-0.147949f, -0.129395f, 0.163574f, -0.105469f, 0.179199f, -0.081543f, 0.203125f, -0.0712891f,
-0.227051f, -0.0610352f, 0.260254f, -0.0610352f, 0.286621f, -0.0610352f, 0.311768f,
--0.0722656f, 0.336914f, -0.0834961f, 0.356934f, -0.10791f, 0.376953f, -0.132324f,
-0.38916f, -0.170898f, 0.401367f, -0.209473f, 0.401367f, -0.26416f, 0.0668945f, -0.640625f,
-0.0668945f, -0.724609f, 0.154785f, -0.724609f, 0.154785f, -0.640625f, 0.0668945f,
-0, 0.0668945f, -0.52832f, 0.154785f, -0.52832f, 0.154785f, 0, 0.0673828f, 0, 0.0673828f,
--0.724609f, 0.155273f, -0.724609f, 0.155273f, 0, 0.375f, 0, 0.375f, -0.334961f, 0.375f,
--0.373535f, 0.370117f, -0.399414f, 0.365234f, -0.425293f, 0.35376f, -0.441162f, 0.342285f,
--0.457031f, 0.32373f, -0.463623f, 0.305176f, -0.470215f, 0.27832f, -0.470215f, 0.250488f,
--0.470215f, 0.228027f, -0.459229f, 0.205566f, -0.448242f, 0.189697f, -0.42749f, 0.173828f,
--0.406738f, 0.165283f, -0.376221f, 0.156738f, -0.345703f, 0.156738f, -0.306152f,
-0.156738f, 0, 0.0693359f, 0, 0.0693359f, -0.415527f, 0.0693359f, -0.432129f, 0.0690918f,
--0.450439f, 0.0688477f, -0.46875f, 0.0683594f, -0.485107f, 0.0678711f, -0.501465f,
-0.0673828f, -0.513184f, 0.0668945f, -0.524902f, 0.0664062f, -0.52832f, 0.149414f,
--0.52832f, 0.149902f, -0.525879f, 0.150391f, -0.515137f, 0.150879f, -0.504395f, 0.151611f,
--0.490479f, 0.152344f, -0.476562f, 0.152832f, -0.462158f, 0.15332f, -0.447754f, 0.15332f,
--0.437988f, 0.154785f, -0.437988f, 0.166504f, -0.460938f, 0.180176f, -0.479492f,
-0.193848f, -0.498047f, 0.212158f, -0.510986f, 0.230469f, -0.523926f, 0.25415f, -0.531006f,
-0.277832f, -0.538086f, 0.309082f, -0.538086f, 0.369141f, -0.538086f, 0.404053f, -0.51416f,
-0.438965f, -0.490234f, 0.452637f, -0.437988f, 0.454102f, -0.437988f, 0.46582f, -0.460938f,
-0.480469f, -0.479492f, 0.495117f, -0.498047f, 0.514648f, -0.510986f, 0.53418f, -0.523926f,
-0.558594f, -0.531006f, 0.583008f, -0.538086f, 0.614258f, -0.538086f, 0.654297f, -0.538086f,
-0.68335f, -0.527344f, 0.712402f, -0.516602f, 0.730957f, -0.494141f, 0.749512f, -0.47168f,
-0.758301f, -0.436279f, 0.76709f, -0.400879f, 0.76709f, -0.352051f, 0.76709f, 0, 0.680176f,
-0, 0.680176f, -0.334961f, 0.680176f, -0.373535f, 0.675293f, -0.399414f, 0.67041f,
--0.425293f, 0.658936f, -0.441162f, 0.647461f, -0.457031f, 0.628906f, -0.463623f,
-0.610352f, -0.470215f, 0.583496f, -0.470215f, 0.555664f, -0.470215f, 0.533203f, -0.459717f,
-0.510742f, -0.449219f, 0.494873f, -0.428711f, 0.479004f, -0.408203f, 0.470459f, -0.377441f,
-0.461914f, -0.34668f, 0.461914f, -0.306152f, 0.461914f, 0, 0.402832f, 0, 0.402832f,
--0.334961f, 0.402832f, -0.373535f, 0.397217f, -0.399414f, 0.391602f, -0.425293f,
-0.378906f, -0.441162f, 0.366211f, -0.457031f, 0.345459f, -0.463623f, 0.324707f, -0.470215f,
-0.293945f, -0.470215f, 0.262695f, -0.470215f, 0.237549f, -0.459229f, 0.212402f, -0.448242f,
-0.19458f, -0.42749f, 0.176758f, -0.406738f, 0.166992f, -0.376221f, 0.157227f, -0.345703f,
-0.157227f, -0.306152f, 0.157227f, 0, 0.0693359f, 0, 0.0693359f, -0.415527f, 0.0693359f,
--0.432129f, 0.0690918f, -0.450439f, 0.0688477f, -0.46875f, 0.0683594f, -0.485107f,
-0.0678711f, -0.501465f, 0.0673828f, -0.513184f, 0.0668945f, -0.524902f, 0.0664062f,
--0.52832f, 0.149414f, -0.52832f, 0.149902f, -0.525879f, 0.150391f, -0.515137f, 0.150879f,
--0.504395f, 0.151611f, -0.490479f, 0.152344f, -0.476562f, 0.152832f, -0.462158f,
-0.15332f, -0.447754f, 0.15332f, -0.437988f, 0.154785f, -0.437988f, 0.16748f, -0.460938f,
-0.182617f, -0.479492f, 0.197754f, -0.498047f, 0.217773f, -0.510986f, 0.237793f, -0.523926f,
-0.263672f, -0.531006f, 0.289551f, -0.538086f, 0.32373f, -0.538086f, 0.367676f, -0.538086f,
-0.399414f, -0.527344f, 0.431152f, -0.516602f, 0.45166f, -0.494141f, 0.472168f, -0.47168f,
-0.481689f, -0.436279f, 0.491211f, -0.400879f, 0.491211f, -0.352051f, 0.491211f, 0,
-0.51416f, -0.264648f, 0.51416f, -0.125977f, 0.453125f, -0.0581055f, 0.39209f, 0.00976562f,
-0.275879f, 0.00976562f, 0.220703f, 0.00976562f, 0.177246f, -0.00683594f, 0.133789f,
--0.0234375f, 0.10376f, -0.0576172f, 0.0737305f, -0.0917969f, 0.0578613f, -0.143311f,
-0.0419922f, -0.194824f, 0.0419922f, -0.264648f, 0.0419922f, -0.538086f, 0.278809f,
--0.538086f, 0.340332f, -0.538086f, 0.38501f, -0.520996f, 0.429688f, -0.503906f, 0.458252f,
--0.469727f, 0.486816f, -0.435547f, 0.500488f, -0.384277f, 0.51416f, -0.333008f, 0.51416f,
--0.264648f, 0.421875f, -0.264648f, 0.421875f, -0.326172f, 0.412354f, -0.366211f,
-0.402832f, -0.40625f, 0.384521f, -0.430176f, 0.366211f, -0.454102f, 0.339844f, -0.463623f,
-0.313477f, -0.473145f, 0.280273f, -0.473145f, 0.246582f, -0.473145f, 0.219482f, -0.463135f,
-0.192383f, -0.453125f, 0.17334f, -0.428955f, 0.154297f, -0.404785f, 0.144287f, -0.364746f,
-0.134277f, -0.324707f, 0.134277f, -0.264648f, 0.134277f, -0.203125f, 0.14502f, -0.162842f,
-0.155762f, -0.122559f, 0.174561f, -0.0986328f, 0.193359f, -0.074707f, 0.218994f,
--0.0649414f, 0.244629f, -0.0551758f, 0.274902f, -0.0551758f, 0.308594f, -0.0551758f,
-0.335938f, -0.0646973f, 0.363281f, -0.0742188f, 0.382324f, -0.0981445f, 0.401367f,
--0.12207f, 0.411621f, -0.162598f, 0.421875f, -0.203125f, 0.421875f, -0.264648f, 0.51416f,
--0.266602f, 0.51416f, -0.206543f, 0.504395f, -0.155762f, 0.494629f, -0.10498f, 0.471924f,
--0.0683594f, 0.449219f, -0.0317383f, 0.411865f, -0.0109863f, 0.374512f, 0.00976562f,
-0.319824f, 0.00976562f, 0.263184f, 0.00976562f, 0.220703f, -0.0117188f, 0.178223f,
--0.0332031f, 0.155762f, -0.0820312f, 0.15332f, -0.0820312f, 0.153809f, -0.0810547f,
-0.154053f, -0.0732422f, 0.154297f, -0.0654297f, 0.154541f, -0.0537109f, 0.154785f,
--0.0419922f, 0.155029f, -0.0275879f, 0.155273f, -0.0131836f, 0.155273f, 0.000976562f,
-0.155273f, 0.20752f, 0.0673828f, 0.20752f, 0.0673828f, -0.42041f, 0.0673828f, -0.439453f,
-0.0671387f, -0.457031f, 0.0668945f, -0.474609f, 0.0664062f, -0.489014f, 0.065918f,
--0.503418f, 0.0654297f, -0.513672f, 0.0649414f, -0.523926f, 0.0644531f, -0.52832f,
-0.149414f, -0.52832f, 0.149902f, -0.526855f, 0.150635f, -0.518066f, 0.151367f, -0.509277f,
-0.1521f, -0.496826f, 0.152832f, -0.484375f, 0.153564f, -0.470215f, 0.154297f, -0.456055f,
-0.154297f, -0.443359f, 0.15625f, -0.443359f, 0.168457f, -0.46875f, 0.184082f, -0.486572f,
-0.199707f, -0.504395f, 0.219727f, -0.515869f, 0.239746f, -0.527344f, 0.264404f, -0.532471f,
-0.289062f, -0.537598f, 0.319824f, -0.537598f, 0.374512f, -0.537598f, 0.411865f, -0.518066f,
-0.449219f, -0.498535f, 0.471924f, -0.463135f, 0.494629f, -0.427734f, 0.504395f, -0.377686f,
-0.51416f, -0.327637f, 0.51416f, -0.266602f, 0.421875f, -0.264648f, 0.421875f, -0.313477f,
-0.416016f, -0.351562f, 0.410156f, -0.389648f, 0.395752f, -0.416016f, 0.381348f, -0.442383f,
-0.357422f, -0.456055f, 0.333496f, -0.469727f, 0.297363f, -0.469727f, 0.268066f, -0.469727f,
-0.242188f, -0.461426f, 0.216309f, -0.453125f, 0.197021f, -0.429688f, 0.177734f, -0.40625f,
-0.166504f, -0.36499f, 0.155273f, -0.32373f, 0.155273f, -0.257812f, 0.155273f, -0.20166f,
-0.164551f, -0.162842f, 0.173828f, -0.124023f, 0.19165f, -0.100098f, 0.209473f, -0.0761719f,
-0.23584f, -0.0656738f, 0.262207f, -0.0551758f, 0.296387f, -0.0551758f, 0.333008f,
--0.0551758f, 0.357178f, -0.0693359f, 0.381348f, -0.0834961f, 0.395752f, -0.110352f,
-0.410156f, -0.137207f, 0.416016f, -0.176025f, 0.421875f, -0.214844f, 0.421875f, -0.264648f,
-0.236328f, 0.00976562f, 0.135742f, 0.00976562f, 0.0888672f, -0.0581055f, 0.0419922f,
--0.125977f, 0.0419922f, -0.261719f, 0.0419922f, -0.399414f, 0.0900879f, -0.46875f,
-0.138184f, -0.538086f, 0.236328f, -0.538086f, 0.269043f, -0.538086f, 0.294189f, -0.532227f,
-0.319336f, -0.526367f, 0.339111f, -0.514893f, 0.358887f, -0.503418f, 0.373779f, -0.486328f,
-0.388672f, -0.469238f, 0.400879f, -0.446289f, 0.401855f, -0.446289f, 0.401855f, -0.458496f,
-0.402588f, -0.473389f, 0.40332f, -0.488281f, 0.404053f, -0.501465f, 0.404785f, -0.514648f,
-0.405762f, -0.52417f, 0.406738f, -0.533691f, 0.407715f, -0.535156f, 0.492188f, -0.535156f,
-0.491211f, -0.526855f, 0.48999f, -0.491699f, 0.48877f, -0.456543f, 0.48877f, -0.391113f,
-0.48877f, 0.20752f, 0.400879f, 0.20752f, 0.400879f, -0.00683594f, 0.400879f, -0.0195312f,
-0.401123f, -0.0332031f, 0.401367f, -0.046875f, 0.401855f, -0.059082f, 0.402344f,
--0.0727539f, 0.402832f, -0.0869141f, 0.401855f, -0.0869141f, 0.38916f, -0.0620117f,
-0.373779f, -0.0437012f, 0.358398f, -0.0253906f, 0.338379f, -0.0134277f, 0.318359f,
--0.00146484f, 0.293213f, 0.00415039f, 0.268066f, 0.00976562f, 0.236328f, 0.00976562f,
-0.400879f, -0.270508f, 0.400879f, -0.328125f, 0.390869f, -0.367188f, 0.380859f, -0.40625f,
-0.362549f, -0.429688f, 0.344238f, -0.453125f, 0.318115f, -0.463135f, 0.291992f, -0.473145f,
-0.259766f, -0.473145f, 0.226074f, -0.473145f, 0.202148f, -0.460693f, 0.178223f, -0.448242f,
-0.16333f, -0.422607f, 0.148438f, -0.396973f, 0.141357f, -0.357666f, 0.134277f, -0.318359f,
-0.134277f, -0.264648f, 0.134277f, -0.211914f, 0.140869f, -0.172852f, 0.147461f, -0.133789f,
-0.162354f, -0.108398f, 0.177246f, -0.0830078f, 0.200928f, -0.0705566f, 0.224609f,
--0.0581055f, 0.258789f, -0.0581055f, 0.288086f, -0.0581055f, 0.313965f, -0.0671387f,
-0.339844f, -0.0761719f, 0.359131f, -0.0998535f, 0.378418f, -0.123535f, 0.389648f,
--0.164795f, 0.400879f, -0.206055f, 0.400879f, -0.270508f, 0.0693359f, 0, 0.0693359f,
--0.405273f, 0.0693359f, -0.421875f, 0.0690918f, -0.439209f, 0.0688477f, -0.456543f,
-0.0683594f, -0.472656f, 0.0678711f, -0.48877f, 0.0673828f, -0.50293f, 0.0668945f,
--0.51709f, 0.0664062f, -0.52832f, 0.149414f, -0.52832f, 0.149902f, -0.51709f, 0.150635f,
--0.502686f, 0.151367f, -0.488281f, 0.1521f, -0.473145f, 0.152832f, -0.458008f, 0.153076f,
--0.444092f, 0.15332f, -0.430176f, 0.15332f, -0.42041f, 0.155273f, -0.42041f, 0.164551f,
--0.450684f, 0.175049f, -0.4729f, 0.185547f, -0.495117f, 0.199707f, -0.509521f, 0.213867f,
--0.523926f, 0.233398f, -0.531006f, 0.25293f, -0.538086f, 0.280762f, -0.538086f, 0.291504f,
--0.538086f, 0.30127f, -0.536377f, 0.311035f, -0.534668f, 0.316406f, -0.533203f, 0.316406f,
--0.452637f, 0.307617f, -0.455078f, 0.295898f, -0.456299f, 0.28418f, -0.45752f, 0.269531f,
--0.45752f, 0.239258f, -0.45752f, 0.218018f, -0.443848f, 0.196777f, -0.430176f, 0.18335f,
--0.406006f, 0.169922f, -0.381836f, 0.163574f, -0.348389f, 0.157227f, -0.314941f,
-0.157227f, -0.275391f, 0.157227f, 0, 0.463867f, -0.145996f, 0.463867f, -0.108887f,
-0.449463f, -0.079834f, 0.435059f, -0.0507812f, 0.407715f, -0.0310059f, 0.380371f,
--0.0112305f, 0.340576f, -0.000732422f, 0.300781f, 0.00976562f, 0.249512f, 0.00976562f,
-0.203613f, 0.00976562f, 0.166748f, 0.00268555f, 0.129883f, -0.00439453f, 0.102051f,
--0.0200195f, 0.0742188f, -0.0356445f, 0.0554199f, -0.0612793f, 0.0366211f, -0.0869141f,
-0.027832f, -0.124023f, 0.105469f, -0.13916f, 0.116699f, -0.0966797f, 0.151855f, -0.0769043f,
-0.187012f, -0.0571289f, 0.249512f, -0.0571289f, 0.277832f, -0.0571289f, 0.301514f,
--0.0610352f, 0.325195f, -0.0649414f, 0.342285f, -0.0744629f, 0.359375f, -0.0839844f,
-0.368896f, -0.0998535f, 0.378418f, -0.115723f, 0.378418f, -0.13916f, 0.378418f, -0.163086f,
-0.367188f, -0.178467f, 0.355957f, -0.193848f, 0.335938f, -0.204102f, 0.315918f, -0.214355f,
-0.287354f, -0.221924f, 0.258789f, -0.229492f, 0.224609f, -0.23877f, 0.192871f, -0.24707f,
-0.161621f, -0.257324f, 0.130371f, -0.267578f, 0.105225f, -0.284424f, 0.0800781f,
--0.30127f, 0.0644531f, -0.326172f, 0.0488281f, -0.351074f, 0.0488281f, -0.388672f,
-0.0488281f, -0.460938f, 0.100342f, -0.498779f, 0.151855f, -0.536621f, 0.250488f,
--0.536621f, 0.337891f, -0.536621f, 0.389404f, -0.505859f, 0.440918f, -0.475098f,
-0.45459f, -0.407227f, 0.375488f, -0.397461f, 0.371094f, -0.417969f, 0.359375f, -0.431885f,
-0.347656f, -0.445801f, 0.331055f, -0.454346f, 0.314453f, -0.462891f, 0.293701f, -0.466553f,
-0.272949f, -0.470215f, 0.250488f, -0.470215f, 0.190918f, -0.470215f, 0.162598f, -0.452148f,
-0.134277f, -0.434082f, 0.134277f, -0.397461f, 0.134277f, -0.375977f, 0.144775f, -0.362061f,
-0.155273f, -0.348145f, 0.174072f, -0.338623f, 0.192871f, -0.329102f, 0.219238f, -0.322021f,
-0.245605f, -0.314941f, 0.277344f, -0.307129f, 0.29834f, -0.301758f, 0.320312f, -0.295654f,
-0.342285f, -0.289551f, 0.363037f, -0.281006f, 0.383789f, -0.272461f, 0.4021f, -0.260986f,
-0.42041f, -0.249512f, 0.434082f, -0.233398f, 0.447754f, -0.217285f, 0.455811f, -0.195801f,
-0.463867f, -0.174316f, 0.463867f, -0.145996f, 0.270508f, -0.00390625f, 0.250488f,
-0.00146484f, 0.229736f, 0.00463867f, 0.208984f, 0.0078125f, 0.181641f, 0.0078125f,
-0.0761719f, 0.0078125f, 0.0761719f, -0.111816f, 0.0761719f, -0.464355f, 0.0151367f,
--0.464355f, 0.0151367f, -0.52832f, 0.0795898f, -0.52832f, 0.105469f, -0.646484f,
-0.164062f, -0.646484f, 0.164062f, -0.52832f, 0.261719f, -0.52832f, 0.261719f, -0.464355f,
-0.164062f, -0.464355f, 0.164062f, -0.130859f, 0.164062f, -0.0927734f, 0.176514f,
--0.0773926f, 0.188965f, -0.0620117f, 0.219727f, -0.0620117f, 0.232422f, -0.0620117f,
-0.244385f, -0.0639648f, 0.256348f, -0.065918f, 0.270508f, -0.0688477f, 0.15332f,
--0.52832f, 0.15332f, -0.193359f, 0.15332f, -0.154785f, 0.158936f, -0.128906f, 0.164551f,
--0.103027f, 0.177246f, -0.0871582f, 0.189941f, -0.0712891f, 0.210693f, -0.0646973f,
-0.231445f, -0.0581055f, 0.262207f, -0.0581055f, 0.293457f, -0.0581055f, 0.318604f,
--0.0690918f, 0.34375f, -0.0800781f, 0.361572f, -0.10083f, 0.379395f, -0.121582f,
-0.38916f, -0.1521f, 0.398926f, -0.182617f, 0.398926f, -0.222168f, 0.398926f, -0.52832f,
-0.486816f, -0.52832f, 0.486816f, -0.112793f, 0.486816f, -0.0961914f, 0.487061f, -0.0778809f,
-0.487305f, -0.0595703f, 0.487793f, -0.0432129f, 0.488281f, -0.0268555f, 0.48877f,
--0.0151367f, 0.489258f, -0.00341797f, 0.489746f, 0, 0.406738f, 0, 0.40625f, -0.00244141f,
-0.405762f, -0.0131836f, 0.405273f, -0.0239258f, 0.404541f, -0.0378418f, 0.403809f,
--0.0517578f, 0.40332f, -0.0661621f, 0.402832f, -0.0805664f, 0.402832f, -0.090332f,
-0.401367f, -0.090332f, 0.388672f, -0.0673828f, 0.373535f, -0.0488281f, 0.358398f,
--0.0302734f, 0.338379f, -0.017334f, 0.318359f, -0.00439453f, 0.29248f, 0.00268555f,
-0.266602f, 0.00976562f, 0.232422f, 0.00976562f, 0.188477f, 0.00976562f, 0.156738f,
--0.000976562f, 0.125f, -0.0117188f, 0.104492f, -0.0341797f, 0.0839844f, -0.0566406f,
-0.0744629f, -0.0917969f, 0.0649414f, -0.126953f, 0.0649414f, -0.17627f, 0.0649414f,
--0.52832f, 0.299316f, 0, 0.195312f, 0, 0.00341797f, -0.52832f, 0.097168f, -0.52832f,
-0.213379f, -0.18457f, 0.216797f, -0.173828f, 0.221436f, -0.158447f, 0.226074f, -0.143066f,
-0.230957f, -0.126465f, 0.23584f, -0.109863f, 0.23999f, -0.0944824f, 0.244141f, -0.0791016f,
-0.24707f, -0.0688477f, 0.25f, -0.0791016f, 0.254639f, -0.0944824f, 0.259277f, -0.109863f,
-0.26416f, -0.125977f, 0.269043f, -0.14209f, 0.27417f, -0.157471f, 0.279297f, -0.172852f,
-0.283203f, -0.183594f, 0.40332f, -0.52832f, 0.496582f, -0.52832f, 0.573242f, 0, 0.471191f,
-0, 0.386719f, -0.34082f, 0.382812f, -0.354004f, 0.378662f, -0.373535f, 0.374512f,
--0.393066f, 0.370605f, -0.411621f, 0.365723f, -0.433105f, 0.361328f, -0.456055f,
-0.356934f, -0.434082f, 0.352051f, -0.412598f, 0.348145f, -0.394043f, 0.343506f, -0.374023f,
-0.338867f, -0.354004f, 0.334961f, -0.338867f, 0.248047f, 0, 0.146484f, 0, -0.00146484f,
--0.52832f, 0.0854492f, -0.52832f, 0.174805f, -0.169434f, 0.178223f, -0.158203f, 0.181641f,
--0.141846f, 0.185059f, -0.125488f, 0.188477f, -0.109863f, 0.191895f, -0.0917969f,
-0.195801f, -0.0727539f, 0.199707f, -0.0913086f, 0.204102f, -0.108887f, 0.208008f,
--0.124023f, 0.211914f, -0.139648f, 0.21582f, -0.155273f, 0.21875f, -0.165527f, 0.314453f,
--0.52832f, 0.408691f, -0.52832f, 0.500977f, -0.165527f, 0.504395f, -0.152832f, 0.508301f,
--0.136719f, 0.512207f, -0.120605f, 0.515625f, -0.106445f, 0.519531f, -0.0898438f,
-0.523438f, -0.0727539f, 0.527344f, -0.0913086f, 0.53125f, -0.108887f, 0.534668f,
--0.124023f, 0.53833f, -0.140381f, 0.541992f, -0.156738f, 0.54541f, -0.169434f, 0.638672f,
--0.52832f, 0.724609f, -0.52832f, 0.391113f, 0, 0.249023f, -0.216797f, 0.105957f,
-0, 0.0112305f, 0, 0.199219f, -0.271484f, 0.0200195f, -0.52832f, 0.117188f, -0.52832f,
-0.249023f, -0.322754f, 0.379883f, -0.52832f, 0.478027f, -0.52832f, 0.298828f, -0.272461f,
-0.489258f, 0, 0.294922f, 0, 0.276367f, 0.0478516f, 0.25708f, 0.0861816f, 0.237793f,
-0.124512f, 0.213867f, 0.151611f, 0.189941f, 0.178711f, 0.160645f, 0.193115f, 0.131348f,
-0.20752f, 0.0932617f, 0.20752f, 0.0766602f, 0.20752f, 0.0625f, 0.206543f, 0.0483398f,
-0.205566f, 0.0327148f, 0.202148f, 0.0327148f, 0.13623f, 0.0419922f, 0.137695f, 0.0537109f,
-0.138428f, 0.0654297f, 0.13916f, 0.0737305f, 0.13916f, 0.112305f, 0.13916f, 0.145508f,
-0.110352f, 0.178711f, 0.081543f, 0.203613f, 0.0185547f, 0.211914f, -0.00244141f,
-0.00244141f, -0.52832f, 0.0961914f, -0.52832f, 0.20752f, -0.236328f, 0.212402f, -0.223145f,
-0.219971f, -0.201172f, 0.227539f, -0.179199f, 0.235107f, -0.157227f, 0.242676f, -0.135254f,
-0.248535f, -0.117676f, 0.254395f, -0.100098f, 0.255371f, -0.0957031f, 0.256836f,
--0.101074f, 0.262451f, -0.116943f, 0.268066f, -0.132812f, 0.275146f, -0.152344f,
-0.282227f, -0.171875f, 0.289551f, -0.191895f, 0.296875f, -0.211914f, 0.301758f, -0.226562f,
-0.405273f, -0.52832f, 0.498047f, -0.52832f, 0.0239258f, 0, 0.0239258f, -0.0668945f,
-0.34668f, -0.460449f, 0.043457f, -0.460449f, 0.043457f, -0.52832f, 0.445801f, -0.52832f,
-0.445801f, -0.461426f, 0.122559f, -0.0678711f, 0.463867f, -0.0678711f, 0.463867f,
-0
-};
-
-const unsigned char LiberationSanskNormalVerbs[] = {
-6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 2, 2, 1, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5,
-6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6,
-0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
-5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 0, 1,
-1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1,
-1, 1, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 1, 1, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,
-1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1,
-5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1,
-1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2,
-5, 0, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1,
-2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1,
-1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2,
-1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
-1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2,
-2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2,
-2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 5, 6
-};
-
-const unsigned LiberationSanskNormalCharCodes[] = {
-32, 33, 35, 37, 38, 39, 41, 42, 43, 45, 46, 47, 49, 50,
-52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 72, 73,
-74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 92, 93, 94,
-96, 97, 98, 99, 100, 101, 102, 103, 105, 108, 109, 110, 111, 112, 113, 114, 115,
-116, 117, 118, 119, 120, 121, 122
-};
-
-const SkFixed LiberationSanskNormalWidths[] = {
-0x00004720, 0x00004720, 0x00008e60, 0x0000e3a0, 0x0000aac0, 0x000030e0, 0x00005540,
-0x000063a0, 0x00009580, 0x00005540, 0x00004720, 0x00004720, 0x00008e60, 0x00008e60,
-0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00004720, 0x00004720,
-0x00009580, 0x00009580, 0x00009580, 0x00008e60, 0x000103e0, 0x0000aac0, 0x0000aac0,
-0x0000b8e0, 0x0000b8e0, 0x0000aac0, 0x00009c60, 0x0000b8e0, 0x00004720, 0x00008000,
-0x0000aac0, 0x00008e60, 0x0000d540, 0x0000b8e0, 0x0000c720, 0x0000aac0, 0x0000c720,
-0x0000b8e0, 0x0000aac0, 0x00009c60, 0x0000aac0, 0x0000f1a0, 0x0000aac0, 0x0000aac0,
-0x00009c60, 0x00004720, 0x00004720, 0x00004720, 0x00007820, 0x00005540, 0x00008e60,
-0x00008e60, 0x00008000, 0x00008e60, 0x00008e60, 0x00004720, 0x00008e60, 0x000038e0,
-0x000038e0, 0x0000d540, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00005540,
-0x00008000, 0x00004720, 0x00008e60, 0x00008000, 0x0000b8e0, 0x00008000, 0x00008000,
-0x00008000
-};
-
-const int LiberationSanskNormalCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSanskNormalCharCodes);
-
-const SkPaint::FontMetrics LiberationSanskNormalMetrics = {
-0x00000003, -0.910156f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.25342f, 0,
--0.203125f, 1.05029f, 0.538086f, 0, 0.0732422f, 0.105957f
-};
-
-const SkScalar LiberationSanskBoldPoints[] = {
-0.222168f, -0.208008f, 0.109863f, -0.208008f, 0.0942383f, -0.687988f, 0.237793f, -0.687988f,
-0.0942383f, 0, 0.0942383f, -0.131836f, 0.234863f, -0.131836f, 0.234863f, 0, 0.394043f,
--0.438477f, 0.287109f, -0.438477f, 0.273926f, -0.687988f, 0.408203f, -0.687988f,
-0.186035f, -0.438477f, 0.0791016f, -0.438477f, 0.065918f, -0.687988f, 0.199219f,
--0.687988f, 0.443848f, -0.420898f, 0.410156f, -0.258789f, 0.515137f, -0.258789f,
-0.515137f, -0.186035f, 0.39502f, -0.186035f, 0.35498f, 0, 0.278809f, 0, 0.317871f,
--0.186035f, 0.167969f, -0.186035f, 0.128906f, 0, 0.0541992f, 0, 0.0927734f, -0.186035f,
-0.0170898f, -0.186035f, 0.0170898f, -0.258789f, 0.108887f, -0.258789f, 0.143066f,
--0.420898f, 0.0419922f, -0.420898f, 0.0419922f, -0.493164f, 0.158203f, -0.493164f,
-0.199219f, -0.681152f, 0.273926f, -0.681152f, 0.233887f, -0.493164f, 0.383789f, -0.493164f,
-0.424805f, -0.681152f, 0.500977f, -0.681152f, 0.459961f, -0.493164f, 0.540039f, -0.493164f,
-0.540039f, -0.420898f, 0.219238f, -0.420898f, 0.184082f, -0.258789f, 0.334961f, -0.258789f,
-0.369141f, -0.420898f, 0.541992f, -0.201172f, 0.541992f, -0.159668f, 0.52832f, -0.125732f,
-0.514648f, -0.0917969f, 0.486084f, -0.0671387f, 0.45752f, -0.0424805f, 0.413086f,
--0.0280762f, 0.368652f, -0.0136719f, 0.307129f, -0.0112305f, 0.307129f, 0.0742188f,
-0.253906f, 0.0742188f, 0.253906f, -0.00976562f, 0.198242f, -0.0117188f, 0.156982f,
--0.0249023f, 0.115723f, -0.0380859f, 0.0866699f, -0.0620117f, 0.0576172f, -0.0859375f,
-0.0397949f, -0.120361f, 0.0219727f, -0.154785f, 0.0131836f, -0.199219f, 0.138184f,
--0.222168f, 0.14209f, -0.19873f, 0.149658f, -0.179443f, 0.157227f, -0.160156f, 0.17041f,
--0.145996f, 0.183594f, -0.131836f, 0.203857f, -0.122803f, 0.224121f, -0.11377f, 0.253906f,
--0.11084f, 0.253906f, -0.301758f, 0.252441f, -0.302734f, 0.246582f, -0.303955f, 0.240723f,
--0.305176f, 0.23877f, -0.305176f, 0.200684f, -0.313965f, 0.164062f, -0.326904f, 0.127441f,
--0.339844f, 0.098877f, -0.362061f, 0.0703125f, -0.384277f, 0.0527344f, -0.418213f,
-0.0351562f, -0.452148f, 0.0351562f, -0.50293f, 0.0351562f, -0.547363f, 0.0512695f,
--0.579346f, 0.0673828f, -0.611328f, 0.0964355f, -0.632324f, 0.125488f, -0.65332f,
-0.165771f, -0.664062f, 0.206055f, -0.674805f, 0.253906f, -0.676758f, 0.253906f, -0.742188f,
-0.307129f, -0.742188f, 0.307129f, -0.676758f, 0.359375f, -0.674805f, 0.395996f, -0.663086f,
-0.432617f, -0.651367f, 0.458008f, -0.630127f, 0.483398f, -0.608887f, 0.499023f, -0.577881f,
-0.514648f, -0.546875f, 0.524902f, -0.505859f, 0.395996f, -0.486816f, 0.388672f, -0.529297f,
-0.367432f, -0.55249f, 0.346191f, -0.575684f, 0.307129f, -0.581055f, 0.307129f, -0.40918f,
-0.30957f, -0.408203f, 0.312256f, -0.408203f, 0.314941f, -0.408203f, 0.317871f, -0.407227f,
-0.359863f, -0.397461f, 0.400146f, -0.384277f, 0.44043f, -0.371094f, 0.471924f, -0.348633f,
-0.503418f, -0.326172f, 0.522705f, -0.290771f, 0.541992f, -0.255371f, 0.541992f, -0.201172f,
-0.253906f, -0.583008f, 0.228027f, -0.581055f, 0.210693f, -0.574219f, 0.193359f, -0.567383f,
-0.182617f, -0.556885f, 0.171875f, -0.546387f, 0.16748f, -0.532959f, 0.163086f, -0.519531f,
-0.163086f, -0.504883f, 0.163086f, -0.483887f, 0.169922f, -0.470459f, 0.176758f, -0.457031f,
-0.188965f, -0.448242f, 0.201172f, -0.439453f, 0.217773f, -0.43335f, 0.234375f, -0.427246f,
-0.253906f, -0.420898f, 0.415039f, -0.199219f, 0.415039f, -0.223145f, 0.406738f, -0.238037f,
-0.398438f, -0.25293f, 0.383789f, -0.262207f, 0.369141f, -0.271484f, 0.349365f, -0.277588f,
-0.32959f, -0.283691f, 0.307129f, -0.290039f, 0.307129f, -0.11084f, 0.358887f, -0.114258f,
-0.386963f, -0.135254f, 0.415039f, -0.15625f, 0.415039f, -0.199219f, 0.862793f, -0.210938f,
-0.862793f, -0.149902f, 0.849121f, -0.10791f, 0.835449f, -0.065918f, 0.812012f, -0.0402832f,
-0.788574f, -0.0146484f, 0.75708f, -0.00341797f, 0.725586f, 0.0078125f, 0.689941f,
-0.0078125f, 0.65332f, 0.0078125f, 0.621826f, -0.00341797f, 0.590332f, -0.0146484f,
-0.567139f, -0.0402832f, 0.543945f, -0.065918f, 0.530518f, -0.10791f, 0.51709f, -0.149902f,
-0.51709f, -0.210938f, 0.51709f, -0.275391f, 0.530518f, -0.317627f, 0.543945f, -0.359863f,
-0.567383f, -0.38501f, 0.59082f, -0.410156f, 0.622803f, -0.420166f, 0.654785f, -0.430176f,
-0.691895f, -0.430176f, 0.727051f, -0.430176f, 0.758301f, -0.420166f, 0.789551f, -0.410156f,
-0.812744f, -0.38501f, 0.835938f, -0.359863f, 0.849365f, -0.317627f, 0.862793f, -0.275391f,
-0.862793f, -0.210938f, 0.269531f, 0, 0.168945f, 0, 0.618164f, -0.687988f, 0.720215f,
--0.687988f, 0.199219f, -0.695801f, 0.234375f, -0.695801f, 0.265625f, -0.685791f,
-0.296875f, -0.675781f, 0.320312f, -0.650879f, 0.34375f, -0.625977f, 0.357422f, -0.58374f,
-0.371094f, -0.541504f, 0.371094f, -0.477051f, 0.371094f, -0.416016f, 0.357422f, -0.374023f,
-0.34375f, -0.332031f, 0.320068f, -0.306152f, 0.296387f, -0.280273f, 0.264648f, -0.269043f,
-0.23291f, -0.257812f, 0.196777f, -0.257812f, 0.161133f, -0.257812f, 0.129639f, -0.269043f,
-0.0981445f, -0.280273f, 0.0749512f, -0.305908f, 0.0517578f, -0.331543f, 0.0383301f,
--0.373535f, 0.0249023f, -0.415527f, 0.0249023f, -0.477051f, 0.0249023f, -0.541504f,
-0.0380859f, -0.58374f, 0.0512695f, -0.625977f, 0.074707f, -0.650879f, 0.0981445f,
--0.675781f, 0.130127f, -0.685791f, 0.162109f, -0.695801f, 0.199219f, -0.695801f,
-0.757812f, -0.210938f, 0.757812f, -0.253418f, 0.753662f, -0.28125f, 0.749512f, -0.309082f,
-0.741211f, -0.325439f, 0.73291f, -0.341797f, 0.720703f, -0.348389f, 0.708496f, -0.35498f,
-0.691895f, -0.35498f, 0.673828f, -0.35498f, 0.660889f, -0.348389f, 0.647949f, -0.341797f,
-0.639648f, -0.325195f, 0.631348f, -0.308594f, 0.627197f, -0.280762f, 0.623047f, -0.25293f,
-0.623047f, -0.210938f, 0.623047f, -0.169922f, 0.626953f, -0.142822f, 0.630859f, -0.115723f,
-0.639404f, -0.0991211f, 0.647949f, -0.0825195f, 0.660645f, -0.0756836f, 0.67334f,
--0.0688477f, 0.690918f, -0.0688477f, 0.707031f, -0.0688477f, 0.719482f, -0.0756836f,
-0.731934f, -0.0825195f, 0.740479f, -0.098877f, 0.749023f, -0.115234f, 0.753418f,
--0.142578f, 0.757812f, -0.169922f, 0.757812f, -0.210938f, 0.265137f, -0.477051f,
-0.265137f, -0.519043f, 0.260986f, -0.546631f, 0.256836f, -0.574219f, 0.248535f, -0.590576f,
-0.240234f, -0.606934f, 0.228027f, -0.613525f, 0.21582f, -0.620117f, 0.199219f, -0.620117f,
-0.181152f, -0.620117f, 0.167969f, -0.613281f, 0.154785f, -0.606445f, 0.146484f, -0.590088f,
-0.138184f, -0.57373f, 0.134033f, -0.546143f, 0.129883f, -0.518555f, 0.129883f, -0.477051f,
-0.129883f, -0.436035f, 0.134033f, -0.408691f, 0.138184f, -0.381348f, 0.146729f, -0.364746f,
-0.155273f, -0.348145f, 0.167969f, -0.341064f, 0.180664f, -0.333984f, 0.198242f, -0.333984f,
-0.214844f, -0.333984f, 0.227295f, -0.34082f, 0.239746f, -0.347656f, 0.248291f, -0.364258f,
-0.256836f, -0.380859f, 0.260986f, -0.408447f, 0.265137f, -0.436035f, 0.265137f, -0.477051f,
-0.0439453f, -0.187988f, 0.0439453f, -0.226562f, 0.0563965f, -0.257812f, 0.0688477f,
--0.289062f, 0.0908203f, -0.314453f, 0.112793f, -0.339844f, 0.143066f, -0.360107f,
-0.17334f, -0.380371f, 0.208984f, -0.396973f, 0.193359f, -0.428711f, 0.183105f, -0.464844f,
-0.172852f, -0.500977f, 0.172852f, -0.533203f, 0.172852f, -0.56543f, 0.182617f, -0.594238f,
-0.192383f, -0.623047f, 0.214355f, -0.644775f, 0.236328f, -0.666504f, 0.271484f, -0.679199f,
-0.306641f, -0.691895f, 0.356934f, -0.691895f, 0.396484f, -0.691895f, 0.428955f, -0.682373f,
-0.461426f, -0.672852f, 0.484863f, -0.654297f, 0.508301f, -0.635742f, 0.52124f, -0.608887f,
-0.53418f, -0.582031f, 0.53418f, -0.546875f, 0.53418f, -0.51123f, 0.518066f, -0.483643f,
-0.501953f, -0.456055f, 0.475342f, -0.433838f, 0.44873f, -0.411621f, 0.414062f, -0.393311f,
-0.379395f, -0.375f, 0.342773f, -0.35791f, 0.367676f, -0.313965f, 0.397461f, -0.273193f,
-0.427246f, -0.232422f, 0.461914f, -0.193848f, 0.489258f, -0.235352f, 0.507812f, -0.279053f,
-0.526367f, -0.322754f, 0.539062f, -0.371094f, 0.641113f, -0.336914f, 0.624512f, -0.279785f,
-0.601562f, -0.229492f, 0.578613f, -0.179199f, 0.546875f, -0.131836f, 0.568848f, -0.113281f,
-0.59082f, -0.104736f, 0.612793f, -0.0961914f, 0.633789f, -0.0961914f, 0.649414f,
--0.0961914f, 0.663818f, -0.0981445f, 0.678223f, -0.100098f, 0.690918f, -0.104004f,
-0.690918f, -0.00488281f, 0.664062f, 0.00585938f, 0.626953f, 0.00585938f, 0.602051f,
-0.00585938f, 0.579102f, 0.000976562f, 0.556152f, -0.00390625f, 0.535645f, -0.0119629f,
-0.515137f, -0.0200195f, 0.497559f, -0.0307617f, 0.47998f, -0.0415039f, 0.46582f,
--0.0532227f, 0.449707f, -0.0410156f, 0.429932f, -0.029541f, 0.410156f, -0.0180664f,
-0.386963f, -0.00927734f, 0.36377f, -0.000488281f, 0.337158f, 0.00463867f, 0.310547f,
-0.00976562f, 0.280762f, 0.00976562f, 0.219238f, 0.00976562f, 0.174316f, -0.00537109f,
-0.129395f, -0.0205078f, 0.100586f, -0.046875f, 0.0717773f, -0.0732422f, 0.0578613f,
--0.109375f, 0.0439453f, -0.145508f, 0.0439453f, -0.187988f, 0.424805f, -0.545898f,
-0.424805f, -0.57373f, 0.40625f, -0.591309f, 0.387695f, -0.608887f, 0.355957f, -0.608887f,
-0.318359f, -0.608887f, 0.298584f, -0.587891f, 0.278809f, -0.566895f, 0.278809f, -0.532227f,
-0.278809f, -0.508789f, 0.286377f, -0.484375f, 0.293945f, -0.459961f, 0.305176f, -0.437988f,
-0.330078f, -0.44873f, 0.352051f, -0.459717f, 0.374023f, -0.470703f, 0.390137f, -0.483643f,
-0.40625f, -0.496582f, 0.415527f, -0.511719f, 0.424805f, -0.526855f, 0.424805f, -0.545898f,
-0.384766f, -0.120117f, 0.347168f, -0.162109f, 0.313477f, -0.208008f, 0.279785f, -0.253906f,
-0.251953f, -0.304199f, 0.211426f, -0.285156f, 0.189697f, -0.257324f, 0.167969f, -0.229492f,
-0.167969f, -0.189941f, 0.167969f, -0.16748f, 0.175537f, -0.147949f, 0.183105f, -0.128418f,
-0.197754f, -0.114014f, 0.212402f, -0.0996094f, 0.234619f, -0.0913086f, 0.256836f,
--0.0830078f, 0.286133f, -0.0830078f, 0.317871f, -0.0830078f, 0.343506f, -0.0947266f,
-0.369141f, -0.106445f, 0.384766f, -0.120117f, 0.172852f, -0.438477f, 0.065918f, -0.438477f,
-0.0532227f, -0.687988f, 0.186035f, -0.687988f, 0.194824f, 0.20752f, 0.157227f, 0.15332f,
-0.129883f, 0.0996094f, 0.102539f, 0.0458984f, 0.0847168f, -0.0107422f, 0.0668945f,
--0.0673828f, 0.0583496f, -0.128662f, 0.0498047f, -0.189941f, 0.0498047f, -0.259277f,
-0.0498047f, -0.329102f, 0.0583496f, -0.389893f, 0.0668945f, -0.450684f, 0.0847168f,
--0.50708f, 0.102539f, -0.563477f, 0.129883f, -0.616943f, 0.157227f, -0.67041f, 0.194824f,
--0.724609f, 0.332031f, -0.724609f, 0.292969f, -0.667969f, 0.265137f, -0.612793f,
-0.237305f, -0.557617f, 0.219482f, -0.500977f, 0.20166f, -0.444336f, 0.193359f, -0.384521f,
-0.185059f, -0.324707f, 0.185059f, -0.258789f, 0.185059f, -0.192383f, 0.193359f, -0.132568f,
-0.20166f, -0.0727539f, 0.219482f, -0.0161133f, 0.237305f, 0.0405273f, 0.265137f,
-0.095459f, 0.292969f, 0.150391f, 0.332031f, 0.20752f, 0.000976562f, 0.20752f, 0.0400391f,
-0.150391f, 0.0678711f, 0.095459f, 0.0957031f, 0.0405273f, 0.113525f, -0.0161133f,
-0.131348f, -0.0727539f, 0.139648f, -0.132568f, 0.147949f, -0.192383f, 0.147949f,
--0.258789f, 0.147949f, -0.324707f, 0.139648f, -0.384521f, 0.131348f, -0.444336f,
-0.113525f, -0.500977f, 0.0957031f, -0.557617f, 0.0678711f, -0.612793f, 0.0400391f,
--0.667969f, 0.000976562f, -0.724609f, 0.138184f, -0.724609f, 0.175781f, -0.67041f,
-0.203125f, -0.616943f, 0.230469f, -0.563477f, 0.248291f, -0.50708f, 0.266113f, -0.450684f,
-0.274658f, -0.389893f, 0.283203f, -0.329102f, 0.283203f, -0.259277f, 0.283203f, -0.189941f,
-0.274658f, -0.128662f, 0.266113f, -0.0673828f, 0.248291f, -0.0107422f, 0.230469f,
-0.0458984f, 0.203125f, 0.0996094f, 0.175781f, 0.15332f, 0.138184f, 0.20752f, 0.240234f,
--0.554199f, 0.35498f, -0.60498f, 0.388184f, -0.508789f, 0.266113f, -0.479004f, 0.356934f,
--0.375f, 0.26709f, -0.315918f, 0.195801f, -0.438965f, 0.123047f, -0.315918f, 0.0322266f,
--0.375977f, 0.125f, -0.479004f, 0.00292969f, -0.508789f, 0.0361328f, -0.60498f, 0.152832f,
--0.554199f, 0.144043f, -0.687988f, 0.249023f, -0.687988f, 0.347168f, -0.277832f,
-0.347168f, -0.0786133f, 0.236816f, -0.0786133f, 0.236816f, -0.277832f, 0.0419922f,
--0.277832f, 0.0419922f, -0.387207f, 0.236816f, -0.387207f, 0.236816f, -0.586426f,
-0.347168f, -0.586426f, 0.347168f, -0.387207f, 0.543457f, -0.387207f, 0.543457f, -0.277832f,
-0.0390625f, -0.199707f, 0.0390625f, -0.318848f, 0.292969f, -0.318848f, 0.292969f,
--0.199707f, 0.0678711f, 0, 0.0678711f, -0.148926f, 0.208984f, -0.148926f, 0.208984f,
-0, 0.00976562f, 0.0200195f, 0.151855f, -0.724609f, 0.268066f, -0.724609f, 0.128418f,
-0.0200195f, 0.515137f, -0.344238f, 0.515137f, -0.245605f, 0.49707f, -0.177979f, 0.479004f,
--0.110352f, 0.447021f, -0.0686035f, 0.415039f, -0.0268555f, 0.371338f, -0.00854492f,
-0.327637f, 0.00976562f, 0.275879f, 0.00976562f, 0.224121f, 0.00976562f, 0.180664f,
--0.00830078f, 0.137207f, -0.0263672f, 0.105957f, -0.0681152f, 0.074707f, -0.109863f,
-0.0571289f, -0.17749f, 0.0395508f, -0.245117f, 0.0395508f, -0.344238f, 0.0395508f,
--0.448242f, 0.0568848f, -0.516357f, 0.0742188f, -0.584473f, 0.105957f, -0.625f, 0.137695f,
--0.665527f, 0.181885f, -0.681885f, 0.226074f, -0.698242f, 0.279785f, -0.698242f,
-0.330078f, -0.698242f, 0.373291f, -0.681885f, 0.416504f, -0.665527f, 0.447998f, -0.625f,
-0.479492f, -0.584473f, 0.497314f, -0.516357f, 0.515137f, -0.448242f, 0.515137f, -0.344238f,
-0.377441f, -0.344238f, 0.377441f, -0.416992f, 0.37207f, -0.4646f, 0.366699f, -0.512207f,
-0.35498f, -0.540283f, 0.343262f, -0.568359f, 0.324463f, -0.57959f, 0.305664f, -0.59082f,
-0.278809f, -0.59082f, 0.25f, -0.59082f, 0.230469f, -0.579346f, 0.210938f, -0.567871f,
-0.198975f, -0.539551f, 0.187012f, -0.51123f, 0.181885f, -0.463623f, 0.176758f, -0.416016f,
-0.176758f, -0.344238f, 0.176758f, -0.273438f, 0.182129f, -0.226074f, 0.1875f, -0.178711f,
-0.199219f, -0.150146f, 0.210938f, -0.121582f, 0.22998f, -0.109863f, 0.249023f, -0.0981445f,
-0.276855f, -0.0981445f, 0.303711f, -0.0981445f, 0.322754f, -0.109863f, 0.341797f,
--0.121582f, 0.354004f, -0.150146f, 0.366211f, -0.178711f, 0.371826f, -0.226074f,
-0.377441f, -0.273438f, 0.377441f, -0.344238f, 0.0629883f, 0, 0.0629883f, -0.102051f,
-0.233398f, -0.102051f, 0.233398f, -0.571289f, 0.0683594f, -0.468262f, 0.0683594f,
--0.576172f, 0.240723f, -0.687988f, 0.370605f, -0.687988f, 0.370605f, -0.102051f,
-0.52832f, -0.102051f, 0.52832f, 0, 0.034668f, 0, 0.034668f, -0.0952148f, 0.0581055f,
--0.146484f, 0.0917969f, -0.187744f, 0.125488f, -0.229004f, 0.162354f, -0.263428f,
-0.199219f, -0.297852f, 0.235596f, -0.327393f, 0.271973f, -0.356934f, 0.301025f, -0.384521f,
-0.330078f, -0.412109f, 0.348145f, -0.439941f, 0.366211f, -0.467773f, 0.366211f, -0.499023f,
-0.366211f, -0.544922f, 0.343262f, -0.566895f, 0.320312f, -0.588867f, 0.275879f, -0.588867f,
-0.231934f, -0.588867f, 0.20874f, -0.565186f, 0.185547f, -0.541504f, 0.178711f, -0.494141f,
-0.0405273f, -0.501953f, 0.0454102f, -0.54248f, 0.0605469f, -0.578125f, 0.0756836f,
--0.61377f, 0.10376f, -0.640625f, 0.131836f, -0.66748f, 0.174072f, -0.682861f, 0.216309f,
--0.698242f, 0.274902f, -0.698242f, 0.330566f, -0.698242f, 0.373535f, -0.685303f,
-0.416504f, -0.672363f, 0.445801f, -0.647461f, 0.475098f, -0.622559f, 0.490234f, -0.58667f,
-0.505371f, -0.550781f, 0.505371f, -0.504883f, 0.505371f, -0.456543f, 0.486328f, -0.41748f,
-0.467285f, -0.378418f, 0.4375f, -0.345459f, 0.407715f, -0.3125f, 0.371338f, -0.283691f,
-0.334961f, -0.254883f, 0.300781f, -0.227539f, 0.266602f, -0.200195f, 0.238525f, -0.172363f,
-0.210449f, -0.144531f, 0.196777f, -0.112793f, 0.516113f, -0.112793f, 0.516113f, 0,
-0.52002f, -0.190918f, 0.52002f, -0.144043f, 0.504639f, -0.106689f, 0.489258f, -0.0693359f,
-0.458496f, -0.0429688f, 0.427734f, -0.0166016f, 0.38208f, -0.00268555f, 0.336426f,
-0.0112305f, 0.275879f, 0.0112305f, 0.208496f, 0.0112305f, 0.162354f, -0.00585938f,
-0.116211f, -0.0229492f, 0.0866699f, -0.0510254f, 0.0571289f, -0.0791016f, 0.0422363f,
--0.114746f, 0.0273438f, -0.150391f, 0.0229492f, -0.187012f, 0.162598f, -0.199219f,
-0.165527f, -0.177246f, 0.173584f, -0.158936f, 0.181641f, -0.140625f, 0.195312f, -0.127441f,
-0.208984f, -0.114258f, 0.22876f, -0.107178f, 0.248535f, -0.100098f, 0.275391f, -0.100098f,
-0.324707f, -0.100098f, 0.352051f, -0.124512f, 0.379395f, -0.148926f, 0.379395f, -0.199219f,
-0.379395f, -0.22998f, 0.366455f, -0.248535f, 0.353516f, -0.26709f, 0.33374f, -0.2771f,
-0.313965f, -0.287109f, 0.291016f, -0.290527f, 0.268066f, -0.293945f, 0.247559f, -0.293945f,
-0.199707f, -0.293945f, 0.199707f, -0.404785f, 0.244629f, -0.404785f, 0.265137f, -0.404785f,
-0.286377f, -0.408691f, 0.307617f, -0.412598f, 0.324707f, -0.422852f, 0.341797f, -0.433105f,
-0.352539f, -0.451416f, 0.363281f, -0.469727f, 0.363281f, -0.498047f, 0.363281f, -0.540527f,
-0.3396f, -0.564697f, 0.315918f, -0.588867f, 0.270508f, -0.588867f, 0.228027f, -0.588867f,
-0.201904f, -0.56543f, 0.175781f, -0.541992f, 0.171875f, -0.499023f, 0.034668f, -0.508789f,
-0.0405273f, -0.557129f, 0.0612793f, -0.592773f, 0.0820312f, -0.628418f, 0.113525f,
--0.651855f, 0.14502f, -0.675293f, 0.186035f, -0.686768f, 0.227051f, -0.698242f, 0.272949f,
--0.698242f, 0.333496f, -0.698242f, 0.376953f, -0.683594f, 0.42041f, -0.668945f, 0.448242f,
--0.644043f, 0.476074f, -0.619141f, 0.489258f, -0.585938f, 0.502441f, -0.552734f,
-0.502441f, -0.515137f, 0.502441f, -0.484863f, 0.493652f, -0.45874f, 0.484863f, -0.432617f,
-0.467041f, -0.411865f, 0.449219f, -0.391113f, 0.421387f, -0.376221f, 0.393555f, -0.361328f,
-0.355469f, -0.354004f, 0.355469f, -0.352051f, 0.397949f, -0.347168f, 0.429199f, -0.332764f,
-0.460449f, -0.318359f, 0.480469f, -0.296875f, 0.500488f, -0.275391f, 0.510254f, -0.248291f,
-0.52002f, -0.221191f, 0.52002f, -0.190918f, 0.52832f, -0.229004f, 0.52832f, -0.177246f,
-0.511963f, -0.133545f, 0.495605f, -0.0898438f, 0.463379f, -0.0578613f, 0.431152f,
--0.0258789f, 0.383545f, -0.00805664f, 0.335938f, 0.00976562f, 0.273438f, 0.00976562f,
-0.21582f, 0.00976562f, 0.172852f, -0.00415039f, 0.129883f, -0.0180664f, 0.100342f,
--0.0427246f, 0.0708008f, -0.0673828f, 0.0539551f, -0.100586f, 0.0371094f, -0.133789f,
-0.0307617f, -0.171875f, 0.167969f, -0.183105f, 0.171875f, -0.166992f, 0.178955f,
--0.151855f, 0.186035f, -0.136719f, 0.19873f, -0.125f, 0.211426f, -0.113281f, 0.22998f,
--0.106201f, 0.248535f, -0.0991211f, 0.274902f, -0.0991211f, 0.326172f, -0.0991211f,
-0.356689f, -0.131836f, 0.387207f, -0.164551f, 0.387207f, -0.226074f, 0.387207f, -0.253418f,
-0.379639f, -0.275391f, 0.37207f, -0.297363f, 0.358154f, -0.312988f, 0.344238f, -0.328613f,
-0.323975f, -0.336914f, 0.303711f, -0.345215f, 0.277832f, -0.345215f, 0.243652f, -0.345215f,
-0.22168f, -0.332275f, 0.199707f, -0.319336f, 0.18457f, -0.300781f, 0.0507812f, -0.300781f,
-0.074707f, -0.687988f, 0.488281f, -0.687988f, 0.488281f, -0.585938f, 0.199219f, -0.585938f,
-0.187988f, -0.412109f, 0.208496f, -0.430176f, 0.239746f, -0.443115f, 0.270996f, -0.456055f,
-0.3125f, -0.456055f, 0.363281f, -0.456055f, 0.40332f, -0.439453f, 0.443359f, -0.422852f,
-0.471191f, -0.393066f, 0.499023f, -0.363281f, 0.513672f, -0.321533f, 0.52832f, -0.279785f,
-0.52832f, -0.229004f, 0.52002f, -0.225098f, 0.52002f, -0.17334f, 0.505371f, -0.130127f,
-0.490723f, -0.0869141f, 0.46167f, -0.0559082f, 0.432617f, -0.0249023f, 0.38916f,
--0.00756836f, 0.345703f, 0.00976562f, 0.288574f, 0.00976562f, 0.166992f, 0.00976562f,
-0.101807f, -0.0754395f, 0.0366211f, -0.160645f, 0.0366211f, -0.328125f, 0.0366211f,
--0.512207f, 0.102783f, -0.605225f, 0.168945f, -0.698242f, 0.291992f, -0.698242f,
-0.333008f, -0.698242f, 0.366699f, -0.689697f, 0.400391f, -0.681152f, 0.426758f, -0.662109f,
-0.453125f, -0.643066f, 0.47168f, -0.613037f, 0.490234f, -0.583008f, 0.501465f, -0.540039f,
-0.37207f, -0.521973f, 0.362305f, -0.558105f, 0.340332f, -0.573975f, 0.318359f, -0.589844f,
-0.289062f, -0.589844f, 0.233887f, -0.589844f, 0.202393f, -0.534668f, 0.170898f, -0.479492f,
-0.170898f, -0.367188f, 0.192871f, -0.403809f, 0.231934f, -0.42334f, 0.270996f, -0.442871f,
-0.320312f, -0.442871f, 0.365723f, -0.442871f, 0.402588f, -0.427979f, 0.439453f, -0.413086f,
-0.465576f, -0.38501f, 0.491699f, -0.356934f, 0.505859f, -0.316406f, 0.52002f, -0.275879f,
-0.52002f, -0.225098f, 0.382324f, -0.221191f, 0.382324f, -0.249023f, 0.375977f, -0.27124f,
-0.369629f, -0.293457f, 0.356689f, -0.309082f, 0.34375f, -0.324707f, 0.324707f, -0.333252f,
-0.305664f, -0.341797f, 0.280762f, -0.341797f, 0.262695f, -0.341797f, 0.244629f, -0.335938f,
-0.226562f, -0.330078f, 0.212402f, -0.317139f, 0.198242f, -0.304199f, 0.189453f, -0.28418f,
-0.180664f, -0.26416f, 0.180664f, -0.23584f, 0.180664f, -0.206543f, 0.187988f, -0.181152f,
-0.195312f, -0.155762f, 0.20874f, -0.136963f, 0.222168f, -0.118164f, 0.241211f, -0.107666f,
-0.260254f, -0.097168f, 0.28418f, -0.097168f, 0.330566f, -0.097168f, 0.356445f, -0.130127f,
-0.382324f, -0.163086f, 0.382324f, -0.221191f, 0.512207f, -0.579102f, 0.46582f, -0.505859f,
-0.424561f, -0.437012f, 0.383301f, -0.368164f, 0.352539f, -0.298584f, 0.321777f, -0.229004f,
-0.303955f, -0.155518f, 0.286133f, -0.0820312f, 0.286133f, 0, 0.143066f, 0, 0.143066f,
--0.081543f, 0.162354f, -0.155029f, 0.181641f, -0.228516f, 0.214844f, -0.29834f, 0.248047f,
--0.368164f, 0.291992f, -0.436279f, 0.335938f, -0.504395f, 0.384766f, -0.575195f,
-0.0429688f, -0.575195f, 0.0429688f, -0.687988f, 0.512207f, -0.687988f, 0.525391f,
--0.193848f, 0.525391f, -0.149414f, 0.510742f, -0.112061f, 0.496094f, -0.074707f,
-0.46582f, -0.0476074f, 0.435547f, -0.0205078f, 0.38916f, -0.00537109f, 0.342773f,
-0.00976562f, 0.278809f, 0.00976562f, 0.215332f, 0.00976562f, 0.168701f, -0.00537109f,
-0.12207f, -0.0205078f, 0.0915527f, -0.0476074f, 0.0610352f, -0.074707f, 0.0463867f,
--0.111816f, 0.0317383f, -0.148926f, 0.0317383f, -0.192871f, 0.0317383f, -0.230469f,
-0.043457f, -0.259521f, 0.0551758f, -0.288574f, 0.074707f, -0.30957f, 0.0942383f,
--0.330566f, 0.119629f, -0.343018f, 0.14502f, -0.355469f, 0.171875f, -0.359863f, 0.171875f,
--0.361816f, 0.143066f, -0.368164f, 0.120117f, -0.382812f, 0.097168f, -0.397461f,
-0.0810547f, -0.417969f, 0.0649414f, -0.438477f, 0.0563965f, -0.463623f, 0.0478516f,
--0.48877f, 0.0478516f, -0.516113f, 0.0478516f, -0.557129f, 0.0627441f, -0.59082f,
-0.0776367f, -0.624512f, 0.106445f, -0.648438f, 0.135254f, -0.672363f, 0.177979f,
--0.685303f, 0.220703f, -0.698242f, 0.276855f, -0.698242f, 0.336914f, -0.698242f,
-0.380615f, -0.684814f, 0.424316f, -0.671387f, 0.452637f, -0.647217f, 0.480957f, -0.623047f,
-0.494629f, -0.589355f, 0.508301f, -0.555664f, 0.508301f, -0.515137f, 0.508301f, -0.488281f,
-0.499756f, -0.463135f, 0.491211f, -0.437988f, 0.475098f, -0.41748f, 0.458984f, -0.396973f,
-0.435791f, -0.382812f, 0.412598f, -0.368652f, 0.383301f, -0.362793f, 0.383301f, -0.36084f,
-0.413574f, -0.355957f, 0.439697f, -0.343018f, 0.46582f, -0.330078f, 0.484863f, -0.309326f,
-0.503906f, -0.288574f, 0.514648f, -0.259521f, 0.525391f, -0.230469f, 0.525391f, -0.193848f,
-0.367188f, -0.507812f, 0.367188f, -0.52832f, 0.362793f, -0.545654f, 0.358398f, -0.562988f,
-0.348145f, -0.575439f, 0.337891f, -0.587891f, 0.320557f, -0.594971f, 0.303223f, -0.602051f,
-0.276855f, -0.602051f, 0.251465f, -0.602051f, 0.234375f, -0.594971f, 0.217285f, -0.587891f,
-0.207031f, -0.575439f, 0.196777f, -0.562988f, 0.192383f, -0.545654f, 0.187988f, -0.52832f,
-0.187988f, -0.507812f, 0.187988f, -0.489746f, 0.19165f, -0.472168f, 0.195312f, -0.45459f,
-0.205078f, -0.440674f, 0.214844f, -0.426758f, 0.232422f, -0.417969f, 0.25f, -0.40918f,
-0.277832f, -0.40918f, 0.307129f, -0.40918f, 0.324951f, -0.417969f, 0.342773f, -0.426758f,
-0.352051f, -0.440918f, 0.361328f, -0.455078f, 0.364258f, -0.472656f, 0.367188f, -0.490234f,
-0.367188f, -0.507812f, 0.383301f, -0.205078f, 0.383301f, -0.226074f, 0.378662f, -0.245605f,
-0.374023f, -0.265137f, 0.362061f, -0.280029f, 0.350098f, -0.294922f, 0.329102f, -0.303955f,
-0.308105f, -0.312988f, 0.275879f, -0.312988f, 0.246582f, -0.312988f, 0.226807f, -0.303955f,
-0.207031f, -0.294922f, 0.195068f, -0.279785f, 0.183105f, -0.264648f, 0.177979f, -0.244873f,
-0.172852f, -0.225098f, 0.172852f, -0.203125f, 0.172852f, -0.177246f, 0.177979f, -0.155762f,
-0.183105f, -0.134277f, 0.195557f, -0.118896f, 0.208008f, -0.103516f, 0.228516f, -0.0952148f,
-0.249023f, -0.0869141f, 0.279785f, -0.0869141f, 0.310547f, -0.0869141f, 0.330566f,
--0.095459f, 0.350586f, -0.104004f, 0.362305f, -0.119629f, 0.374023f, -0.135254f,
-0.378662f, -0.156982f, 0.383301f, -0.178711f, 0.383301f, -0.205078f, 0.519043f, -0.35498f,
-0.519043f, -0.171875f, 0.452148f, -0.0810547f, 0.385254f, 0.00976562f, 0.262207f,
-0.00976562f, 0.217773f, 0.00976562f, 0.182373f, 0.000488281f, 0.146973f, -0.00878906f,
-0.120605f, -0.0283203f, 0.0942383f, -0.0478516f, 0.0759277f, -0.0786133f, 0.0576172f,
--0.109375f, 0.046875f, -0.151855f, 0.175781f, -0.169922f, 0.185547f, -0.133301f,
-0.207764f, -0.115723f, 0.22998f, -0.0981445f, 0.263672f, -0.0981445f, 0.291504f,
--0.0981445f, 0.313477f, -0.111328f, 0.335449f, -0.124512f, 0.351074f, -0.151367f,
-0.366699f, -0.178223f, 0.375244f, -0.219482f, 0.383789f, -0.260742f, 0.384277f, -0.316895f,
-0.374512f, -0.297852f, 0.358398f, -0.283203f, 0.342285f, -0.268555f, 0.322021f, -0.258789f,
-0.301758f, -0.249023f, 0.278809f, -0.243896f, 0.255859f, -0.23877f, 0.232422f, -0.23877f,
-0.1875f, -0.23877f, 0.150879f, -0.254639f, 0.114258f, -0.270508f, 0.0883789f, -0.300293f,
-0.0625f, -0.330078f, 0.048584f, -0.372314f, 0.034668f, -0.414551f, 0.034668f, -0.467773f,
-0.034668f, -0.522461f, 0.0510254f, -0.56543f, 0.0673828f, -0.608398f, 0.0981445f,
--0.637939f, 0.128906f, -0.66748f, 0.173584f, -0.682861f, 0.218262f, -0.698242f, 0.274902f,
--0.698242f, 0.334473f, -0.698242f, 0.380127f, -0.677979f, 0.425781f, -0.657715f,
-0.456543f, -0.615479f, 0.487305f, -0.573242f, 0.503174f, -0.508545f, 0.519043f, -0.443848f,
-0.519043f, -0.35498f, 0.374023f, -0.451172f, 0.374023f, -0.480469f, 0.367432f, -0.506104f,
-0.36084f, -0.531738f, 0.347656f, -0.550537f, 0.334473f, -0.569336f, 0.31543f, -0.580078f,
-0.296387f, -0.59082f, 0.271484f, -0.59082f, 0.248535f, -0.59082f, 0.230469f, -0.582275f,
-0.212402f, -0.57373f, 0.199707f, -0.557617f, 0.187012f, -0.541504f, 0.18042f, -0.518555f,
-0.173828f, -0.495605f, 0.173828f, -0.466797f, 0.173828f, -0.439941f, 0.180176f, -0.416748f,
-0.186523f, -0.393555f, 0.19873f, -0.376709f, 0.210938f, -0.359863f, 0.229492f, -0.350342f,
-0.248047f, -0.34082f, 0.271973f, -0.34082f, 0.291016f, -0.34082f, 0.309326f, -0.347656f,
-0.327637f, -0.354492f, 0.342041f, -0.368164f, 0.356445f, -0.381836f, 0.365234f, -0.402588f,
-0.374023f, -0.42334f, 0.374023f, -0.451172f, 0.0961914f, -0.367188f, 0.0961914f,
--0.504883f, 0.236816f, -0.504883f, 0.236816f, -0.367188f, 0.0961914f, 0, 0.0961914f,
--0.137207f, 0.236816f, -0.137207f, 0.236816f, 0, 0.097168f, -0.367188f, 0.097168f,
--0.504883f, 0.237793f, -0.504883f, 0.237793f, -0.367188f, 0.237793f, -0.0322266f,
-0.237793f, 0.000488281f, 0.234131f, 0.0273438f, 0.230469f, 0.0541992f, 0.223633f,
-0.0769043f, 0.216797f, 0.0996094f, 0.207031f, 0.118652f, 0.197266f, 0.137695f, 0.185059f,
-0.154785f, 0.0952148f, 0.154785f, 0.108887f, 0.137695f, 0.12085f, 0.118652f, 0.132812f,
-0.0996094f, 0.141602f, 0.0795898f, 0.150391f, 0.0595703f, 0.155273f, 0.0395508f,
-0.160156f, 0.0195312f, 0.160156f, 0, 0.097168f, 0, 0.097168f, -0.137207f, 0.237793f,
--0.137207f, 0.0415039f, -0.411133f, 0.0415039f, -0.52002f, 0.542969f, -0.52002f,
-0.542969f, -0.411133f, 0.0415039f, -0.14209f, 0.0415039f, -0.25f, 0.542969f, -0.25f,
-0.542969f, -0.14209f, 0.0419922f, -0.0610352f, 0.0419922f, -0.171875f, 0.448242f,
--0.330078f, 0.0419922f, -0.48877f, 0.0419922f, -0.600098f, 0.543457f, -0.40918f,
-0.543457f, -0.251953f, 0.553223f, -0.500977f, 0.553223f, -0.46875f, 0.544678f, -0.444336f,
-0.536133f, -0.419922f, 0.521973f, -0.400635f, 0.507812f, -0.381348f, 0.489746f, -0.365967f,
-0.47168f, -0.350586f, 0.452637f, -0.336914f, 0.433594f, -0.323242f, 0.415283f, -0.310059f,
-0.396973f, -0.296875f, 0.382324f, -0.281982f, 0.367676f, -0.26709f, 0.358398f, -0.249268f,
-0.349121f, -0.231445f, 0.348145f, -0.208008f, 0.217773f, -0.208008f, 0.220215f, -0.249512f,
-0.235596f, -0.279053f, 0.250977f, -0.308594f, 0.272949f, -0.330566f, 0.294922f, -0.352539f,
-0.319824f, -0.369873f, 0.344727f, -0.387207f, 0.365967f, -0.405273f, 0.387207f, -0.42334f,
-0.401123f, -0.44458f, 0.415039f, -0.46582f, 0.415039f, -0.495117f, 0.415039f, -0.538086f,
-0.386963f, -0.562988f, 0.358887f, -0.587891f, 0.307129f, -0.587891f, 0.282227f, -0.587891f,
-0.26123f, -0.580322f, 0.240234f, -0.572754f, 0.224365f, -0.559082f, 0.208496f, -0.54541f,
-0.198242f, -0.525879f, 0.187988f, -0.506348f, 0.185059f, -0.48291f, 0.0458984f, -0.48877f,
-0.0517578f, -0.532227f, 0.0700684f, -0.570312f, 0.0883789f, -0.608398f, 0.120117f,
--0.636719f, 0.151855f, -0.665039f, 0.197998f, -0.681641f, 0.244141f, -0.698242f,
-0.305176f, -0.698242f, 0.36377f, -0.698242f, 0.409668f, -0.68457f, 0.455566f, -0.670898f,
-0.487549f, -0.645264f, 0.519531f, -0.619629f, 0.536377f, -0.583008f, 0.553223f, -0.546387f,
-0.553223f, -0.500977f, 0.213867f, 0, 0.213867f, -0.131836f, 0.35498f, -0.131836f,
-0.35498f, 0, 0.553223f, 0, 0.492188f, -0.175781f, 0.22998f, -0.175781f, 0.168945f,
-0, 0.0249023f, 0, 0.275879f, -0.687988f, 0.445801f, -0.687988f, 0.695801f, 0, 0.39209f,
--0.481934f, 0.38623f, -0.499023f, 0.380615f, -0.516357f, 0.375f, -0.533691f, 0.37085f,
--0.548096f, 0.366699f, -0.5625f, 0.364014f, -0.571777f, 0.361328f, -0.581055f, 0.36084f,
--0.582031f, 0.360352f, -0.580566f, 0.35791f, -0.571289f, 0.355469f, -0.562012f, 0.351318f,
--0.547852f, 0.347168f, -0.533691f, 0.341553f, -0.516357f, 0.335938f, -0.499023f,
-0.330078f, -0.481934f, 0.262207f, -0.28418f, 0.459961f, -0.28418f, 0.676758f, -0.196289f,
-0.676758f, -0.144043f, 0.655762f, -0.106689f, 0.634766f, -0.0693359f, 0.598389f,
--0.0456543f, 0.562012f, -0.0219727f, 0.513672f, -0.0109863f, 0.465332f, 0, 0.411133f,
-0, 0.0668945f, 0, 0.0668945f, -0.687988f, 0.381836f, -0.687988f, 0.442871f, -0.687988f,
-0.490479f, -0.67749f, 0.538086f, -0.666992f, 0.570801f, -0.645508f, 0.603516f, -0.624023f,
-0.620361f, -0.591553f, 0.637207f, -0.559082f, 0.637207f, -0.515137f, 0.637207f, -0.456543f,
-0.604736f, -0.41626f, 0.572266f, -0.375977f, 0.505859f, -0.361816f, 0.589355f, -0.352051f,
-0.633057f, -0.309326f, 0.676758f, -0.266602f, 0.676758f, -0.196289f, 0.492188f, -0.495605f,
-0.492188f, -0.541992f, 0.462646f, -0.561523f, 0.433105f, -0.581055f, 0.375f, -0.581055f,
-0.210938f, -0.581055f, 0.210938f, -0.410645f, 0.375977f, -0.410645f, 0.437012f, -0.410645f,
-0.4646f, -0.431885f, 0.492188f, -0.453125f, 0.492188f, -0.495605f, 0.532227f, -0.20752f,
-0.532227f, -0.234863f, 0.521484f, -0.253418f, 0.510742f, -0.271973f, 0.491943f, -0.283203f,
-0.473145f, -0.294434f, 0.447998f, -0.299316f, 0.422852f, -0.304199f, 0.393555f, -0.304199f,
-0.210938f, -0.304199f, 0.210938f, -0.106934f, 0.398926f, -0.106934f, 0.427246f, -0.106934f,
-0.45166f, -0.111572f, 0.476074f, -0.116211f, 0.493896f, -0.127686f, 0.511719f, -0.13916f,
-0.521973f, -0.158691f, 0.532227f, -0.178223f, 0.532227f, -0.20752f, 0.388184f, -0.103516f,
-0.428711f, -0.103516f, 0.458252f, -0.11499f, 0.487793f, -0.126465f, 0.509521f, -0.14502f,
-0.53125f, -0.163574f, 0.545654f, -0.187012f, 0.560059f, -0.210449f, 0.569336f, -0.234375f,
-0.694824f, -0.187012f, 0.679688f, -0.149902f, 0.655273f, -0.114258f, 0.630859f, -0.0786133f,
-0.594238f, -0.0512695f, 0.557617f, -0.0239258f, 0.50708f, -0.00708008f, 0.456543f,
-0.00976562f, 0.388184f, 0.00976562f, 0.298828f, 0.00976562f, 0.233398f, -0.0168457f,
-0.167969f, -0.043457f, 0.125244f, -0.0910645f, 0.0825195f, -0.138672f, 0.0617676f,
--0.204102f, 0.0410156f, -0.269531f, 0.0410156f, -0.347168f, 0.0410156f, -0.427734f,
-0.0617676f, -0.492676f, 0.0825195f, -0.557617f, 0.124512f, -0.603271f, 0.166504f,
--0.648926f, 0.230713f, -0.673584f, 0.294922f, -0.698242f, 0.381836f, -0.698242f,
-0.449219f, -0.698242f, 0.499756f, -0.684082f, 0.550293f, -0.669922f, 0.587158f, -0.644287f,
-0.624023f, -0.618652f, 0.648193f, -0.58374f, 0.672363f, -0.548828f, 0.686035f, -0.506836f,
-0.559082f, -0.472168f, 0.552246f, -0.494141f, 0.538086f, -0.514404f, 0.523926f, -0.534668f,
-0.502197f, -0.550293f, 0.480469f, -0.565918f, 0.451172f, -0.575439f, 0.421875f, -0.584961f,
-0.384766f, -0.584961f, 0.33252f, -0.584961f, 0.294922f, -0.568115f, 0.257324f, -0.55127f,
-0.233154f, -0.52002f, 0.208984f, -0.48877f, 0.19751f, -0.445068f, 0.186035f, -0.401367f,
-0.186035f, -0.347168f, 0.186035f, -0.293457f, 0.19751f, -0.248779f, 0.208984f, -0.204102f,
-0.233398f, -0.171875f, 0.257812f, -0.139648f, 0.296143f, -0.121582f, 0.334473f, -0.103516f,
-0.388184f, -0.103516f, 0.680176f, -0.349121f, 0.680176f, -0.263184f, 0.654297f, -0.197998f,
-0.628418f, -0.132812f, 0.583496f, -0.0888672f, 0.538574f, -0.0449219f, 0.477295f,
--0.0224609f, 0.416016f, 0, 0.345215f, 0, 0.0668945f, 0, 0.0668945f, -0.687988f, 0.315918f,
--0.687988f, 0.395996f, -0.687988f, 0.462891f, -0.667969f, 0.529785f, -0.647949f,
-0.578125f, -0.606445f, 0.626465f, -0.564941f, 0.65332f, -0.500977f, 0.680176f, -0.437012f,
-0.680176f, -0.349121f, 0.535156f, -0.349121f, 0.535156f, -0.40918f, 0.518799f, -0.452148f,
-0.502441f, -0.495117f, 0.473145f, -0.522705f, 0.443848f, -0.550293f, 0.403076f, -0.563477f,
-0.362305f, -0.57666f, 0.312988f, -0.57666f, 0.210938f, -0.57666f, 0.210938f, -0.111328f,
-0.333008f, -0.111328f, 0.376465f, -0.111328f, 0.41333f, -0.126465f, 0.450195f, -0.141602f,
-0.477295f, -0.171631f, 0.504395f, -0.20166f, 0.519775f, -0.246094f, 0.535156f, -0.290527f,
-0.535156f, -0.349121f, 0.0668945f, 0, 0.0668945f, -0.687988f, 0.60791f, -0.687988f,
-0.60791f, -0.57666f, 0.210938f, -0.57666f, 0.210938f, -0.403809f, 0.578125f, -0.403809f,
-0.578125f, -0.29248f, 0.210938f, -0.29248f, 0.210938f, -0.111328f, 0.62793f, -0.111328f,
-0.62793f, 0, 0.210938f, -0.57666f, 0.210938f, -0.36377f, 0.562988f, -0.36377f, 0.562988f,
--0.252441f, 0.210938f, -0.252441f, 0.210938f, 0, 0.0668945f, 0, 0.0668945f, -0.687988f,
-0.574219f, -0.687988f, 0.574219f, -0.57666f, 0.393555f, -0.103027f, 0.424805f, -0.103027f,
-0.453613f, -0.10791f, 0.482422f, -0.112793f, 0.50708f, -0.12085f, 0.531738f, -0.128906f,
-0.551514f, -0.139404f, 0.571289f, -0.149902f, 0.583984f, -0.161133f, 0.583984f, -0.256348f,
-0.416016f, -0.256348f, 0.416016f, -0.362793f, 0.71582f, -0.362793f, 0.71582f, -0.109863f,
-0.692383f, -0.0859375f, 0.65918f, -0.064209f, 0.625977f, -0.0424805f, 0.584473f,
--0.026123f, 0.542969f, -0.00976562f, 0.493896f, 0, 0.444824f, 0.00976562f, 0.389648f,
-0.00976562f, 0.29834f, 0.00976562f, 0.232422f, -0.0168457f, 0.166504f, -0.043457f,
-0.124023f, -0.0910645f, 0.081543f, -0.138672f, 0.0612793f, -0.204102f, 0.0410156f,
--0.269531f, 0.0410156f, -0.347168f, 0.0410156f, -0.427734f, 0.0625f, -0.492676f,
-0.0839844f, -0.557617f, 0.127686f, -0.603271f, 0.171387f, -0.648926f, 0.237549f,
--0.673584f, 0.303711f, -0.698242f, 0.393066f, -0.698242f, 0.458008f, -0.698242f,
-0.508545f, -0.685547f, 0.559082f, -0.672852f, 0.596924f, -0.649414f, 0.634766f, -0.625977f,
-0.6604f, -0.593018f, 0.686035f, -0.560059f, 0.701172f, -0.519043f, 0.568359f, -0.479004f,
-0.55957f, -0.500488f, 0.544922f, -0.519775f, 0.530273f, -0.539062f, 0.508545f, -0.553467f,
-0.486816f, -0.567871f, 0.458252f, -0.576416f, 0.429688f, -0.584961f, 0.393066f, -0.584961f,
-0.339355f, -0.584961f, 0.300293f, -0.568115f, 0.26123f, -0.55127f, 0.23584f, -0.52002f,
-0.210449f, -0.48877f, 0.198242f, -0.445068f, 0.186035f, -0.401367f, 0.186035f, -0.347168f,
-0.186035f, -0.293457f, 0.198486f, -0.248535f, 0.210938f, -0.203613f, 0.236572f, -0.171387f,
-0.262207f, -0.13916f, 0.30127f, -0.121094f, 0.340332f, -0.103027f, 0.393555f, -0.103027f,
-0.510742f, 0, 0.510742f, -0.294922f, 0.210938f, -0.294922f, 0.210938f, 0, 0.0668945f,
-0, 0.0668945f, -0.687988f, 0.210938f, -0.687988f, 0.210938f, -0.414062f, 0.510742f,
--0.414062f, 0.510742f, -0.687988f, 0.654785f, -0.687988f, 0.654785f, 0, 0.0668945f,
-0, 0.0668945f, -0.687988f, 0.210938f, -0.687988f, 0.210938f, 0, 0.255859f, 0.00976562f,
-0.204102f, 0.00976562f, 0.163574f, -0.000976562f, 0.123047f, -0.0117188f, 0.0932617f,
--0.0351562f, 0.0634766f, -0.0585938f, 0.0441895f, -0.0959473f, 0.0249023f, -0.133301f,
-0.0151367f, -0.186523f, 0.158203f, -0.20752f, 0.163086f, -0.178711f, 0.171875f, -0.158936f,
-0.180664f, -0.13916f, 0.193115f, -0.126709f, 0.205566f, -0.114258f, 0.22168f, -0.108643f,
-0.237793f, -0.103027f, 0.256836f, -0.103027f, 0.299805f, -0.103027f, 0.322021f, -0.131836f,
-0.344238f, -0.160645f, 0.344238f, -0.214355f, 0.344238f, -0.575195f, 0.207031f, -0.575195f,
-0.207031f, -0.687988f, 0.487793f, -0.687988f, 0.487793f, -0.217773f, 0.487793f, -0.165527f,
-0.472656f, -0.123291f, 0.45752f, -0.0810547f, 0.427979f, -0.0515137f, 0.398438f,
--0.0219727f, 0.355225f, -0.00610352f, 0.312012f, 0.00976562f, 0.255859f, 0.00976562f,
-0.0668945f, 0, 0.0668945f, -0.687988f, 0.210938f, -0.687988f, 0.210938f, -0.111328f,
-0.580078f, -0.111328f, 0.580078f, 0, 0.638184f, 0, 0.638184f, -0.416992f, 0.638184f,
--0.441895f, 0.638916f, -0.468262f, 0.639648f, -0.494629f, 0.640625f, -0.516602f,
-0.64209f, -0.54248f, 0.643066f, -0.566895f, 0.632812f, -0.52832f, 0.623535f, -0.493652f,
-0.619629f, -0.479004f, 0.615234f, -0.463379f, 0.61084f, -0.447754f, 0.606689f, -0.433105f,
-0.602539f, -0.418457f, 0.598633f, -0.405762f, 0.594727f, -0.393066f, 0.591797f, -0.383789f,
-0.467773f, 0, 0.365234f, 0, 0.241211f, -0.383789f, 0.238281f, -0.393066f, 0.234619f,
--0.405762f, 0.230957f, -0.418457f, 0.226807f, -0.433105f, 0.222656f, -0.447754f,
-0.218262f, -0.463379f, 0.213867f, -0.479004f, 0.209473f, -0.493652f, 0.199707f, -0.52832f,
-0.188965f, -0.566895f, 0.19043f, -0.538574f, 0.191895f, -0.51123f, 0.192871f, -0.487793f,
-0.193848f, -0.461914f, 0.194824f, -0.436035f, 0.194824f, -0.416992f, 0.194824f, 0,
-0.0668945f, 0, 0.0668945f, -0.687988f, 0.259766f, -0.687988f, 0.382812f, -0.303223f,
-0.387695f, -0.288086f, 0.393311f, -0.266113f, 0.398926f, -0.244141f, 0.404297f, -0.223633f,
-0.410156f, -0.199707f, 0.416992f, -0.173828f, 0.423828f, -0.199219f, 0.430176f, -0.222656f,
-0.433105f, -0.23291f, 0.436035f, -0.243652f, 0.438965f, -0.254395f, 0.441895f, -0.264648f,
-0.444824f, -0.274902f, 0.447754f, -0.28418f, 0.450684f, -0.293457f, 0.453125f, -0.300781f,
-0.574219f, -0.687988f, 0.766113f, -0.687988f, 0.766113f, 0, 0.73584f, -0.347168f,
-0.73584f, -0.266602f, 0.711914f, -0.200684f, 0.687988f, -0.134766f, 0.643066f, -0.0878906f,
-0.598145f, -0.0410156f, 0.533447f, -0.015625f, 0.46875f, 0.00976562f, 0.387207f,
-0.00976562f, 0.300781f, 0.00976562f, 0.236084f, -0.0168457f, 0.171387f, -0.043457f,
-0.12793f, -0.0910645f, 0.0844727f, -0.138672f, 0.0627441f, -0.204102f, 0.0410156f,
--0.269531f, 0.0410156f, -0.347168f, 0.0410156f, -0.427734f, 0.0637207f, -0.492676f,
-0.0864258f, -0.557617f, 0.130615f, -0.603271f, 0.174805f, -0.648926f, 0.239502f,
--0.673584f, 0.304199f, -0.698242f, 0.388184f, -0.698242f, 0.472168f, -0.698242f,
-0.536865f, -0.67334f, 0.601562f, -0.648438f, 0.645752f, -0.602539f, 0.689941f, -0.556641f,
-0.712891f, -0.491943f, 0.73584f, -0.427246f, 0.73584f, -0.347168f, 0.588867f, -0.347168f,
-0.588867f, -0.401367f, 0.575928f, -0.445068f, 0.562988f, -0.48877f, 0.537598f, -0.52002f,
-0.512207f, -0.55127f, 0.474854f, -0.568115f, 0.4375f, -0.584961f, 0.388184f, -0.584961f,
-0.337891f, -0.584961f, 0.300049f, -0.568115f, 0.262207f, -0.55127f, 0.236816f, -0.52002f,
-0.211426f, -0.48877f, 0.19873f, -0.445068f, 0.186035f, -0.401367f, 0.186035f, -0.347168f,
-0.186035f, -0.293457f, 0.198975f, -0.248779f, 0.211914f, -0.204102f, 0.237305f, -0.171875f,
-0.262695f, -0.139648f, 0.300293f, -0.121582f, 0.337891f, -0.103516f, 0.387207f, -0.103516f,
-0.439941f, -0.103516f, 0.478027f, -0.121826f, 0.516113f, -0.140137f, 0.540771f, -0.172607f,
-0.56543f, -0.205078f, 0.577148f, -0.249756f, 0.588867f, -0.294434f, 0.588867f, -0.347168f,
-0.539551f, 0, 0.379883f, -0.26123f, 0.210938f, -0.26123f, 0.210938f, 0, 0.0668945f,
-0, 0.0668945f, -0.687988f, 0.410645f, -0.687988f, 0.475098f, -0.687988f, 0.523193f,
--0.673584f, 0.571289f, -0.65918f, 0.603516f, -0.632568f, 0.635742f, -0.605957f, 0.651611f,
--0.568115f, 0.66748f, -0.530273f, 0.66748f, -0.48291f, 0.66748f, -0.444336f, 0.656006f,
--0.412354f, 0.644531f, -0.380371f, 0.624268f, -0.355469f, 0.604004f, -0.330566f,
-0.576172f, -0.313721f, 0.54834f, -0.296875f, 0.515625f, -0.289062f, 0.70166f, 0,
-0.522461f, -0.477051f, 0.522461f, -0.527344f, 0.489502f, -0.551758f, 0.456543f, -0.576172f,
-0.395508f, -0.576172f, 0.210938f, -0.576172f, 0.210938f, -0.373047f, 0.399414f, -0.373047f,
-0.431641f, -0.373047f, 0.454834f, -0.380615f, 0.478027f, -0.388184f, 0.49292f, -0.4021f,
-0.507812f, -0.416016f, 0.515137f, -0.435059f, 0.522461f, -0.454102f, 0.522461f, -0.477051f,
-0.62793f, -0.198242f, 0.62793f, -0.151367f, 0.61084f, -0.113037f, 0.59375f, -0.074707f,
-0.557861f, -0.0473633f, 0.521973f, -0.0200195f, 0.466064f, -0.00512695f, 0.410156f,
-0.00976562f, 0.333008f, 0.00976562f, 0.264648f, 0.00976562f, 0.212402f, -0.00244141f,
-0.160156f, -0.0146484f, 0.122803f, -0.0385742f, 0.0854492f, -0.0625f, 0.0622559f,
--0.0979004f, 0.0390625f, -0.133301f, 0.0288086f, -0.179199f, 0.167969f, -0.202148f,
-0.173828f, -0.179199f, 0.185059f, -0.160156f, 0.196289f, -0.141113f, 0.216064f, -0.127197f,
-0.23584f, -0.113281f, 0.265381f, -0.105713f, 0.294922f, -0.0981445f, 0.336914f, -0.0981445f,
-0.410156f, -0.0981445f, 0.448975f, -0.120361f, 0.487793f, -0.142578f, 0.487793f,
--0.189941f, 0.487793f, -0.218262f, 0.472168f, -0.236328f, 0.456543f, -0.254395f,
-0.430664f, -0.266113f, 0.404785f, -0.277832f, 0.371094f, -0.285645f, 0.337402f, -0.293457f,
-0.300781f, -0.300781f, 0.271484f, -0.307617f, 0.242188f, -0.314941f, 0.212891f, -0.322266f,
-0.186279f, -0.33252f, 0.159668f, -0.342773f, 0.136719f, -0.356934f, 0.11377f, -0.371094f,
-0.0969238f, -0.391846f, 0.0800781f, -0.412598f, 0.0705566f, -0.44043f, 0.0610352f,
--0.468262f, 0.0610352f, -0.505859f, 0.0610352f, -0.557129f, 0.081543f, -0.59375f,
-0.102051f, -0.630371f, 0.138428f, -0.653564f, 0.174805f, -0.676758f, 0.225098f, -0.6875f,
-0.275391f, -0.698242f, 0.334961f, -0.698242f, 0.402344f, -0.698242f, 0.450439f, -0.687744f,
-0.498535f, -0.677246f, 0.531006f, -0.655762f, 0.563477f, -0.634277f, 0.582275f, -0.601807f,
-0.601074f, -0.569336f, 0.609863f, -0.525879f, 0.470215f, -0.506836f, 0.459473f, -0.55127f,
-0.426514f, -0.57373f, 0.393555f, -0.596191f, 0.332031f, -0.596191f, 0.293945f, -0.596191f,
-0.268799f, -0.5896f, 0.243652f, -0.583008f, 0.22876f, -0.571777f, 0.213867f, -0.560547f,
-0.20752f, -0.545654f, 0.201172f, -0.530762f, 0.201172f, -0.51416f, 0.201172f, -0.48877f,
-0.213379f, -0.472412f, 0.225586f, -0.456055f, 0.247559f, -0.445068f, 0.269531f, -0.434082f,
-0.300049f, -0.426514f, 0.330566f, -0.418945f, 0.367188f, -0.411133f, 0.399414f, -0.404297f,
-0.431152f, -0.396729f, 0.462891f, -0.38916f, 0.491699f, -0.378906f, 0.520508f, -0.368652f,
-0.54541f, -0.354004f, 0.570312f, -0.339355f, 0.588623f, -0.318115f, 0.606934f, -0.296875f,
-0.617432f, -0.267578f, 0.62793f, -0.238281f, 0.62793f, -0.198242f, 0.377441f, -0.57666f,
-0.377441f, 0, 0.233398f, 0, 0.233398f, -0.57666f, 0.0112305f, -0.57666f, 0.0112305f,
--0.687988f, 0.600098f, -0.687988f, 0.600098f, -0.57666f, 0.353027f, 0.00976562f,
-0.288574f, 0.00976562f, 0.234863f, -0.00561523f, 0.181152f, -0.0209961f, 0.142334f,
--0.0534668f, 0.103516f, -0.0859375f, 0.0817871f, -0.136719f, 0.0600586f, -0.1875f,
-0.0600586f, -0.257812f, 0.0600586f, -0.687988f, 0.204102f, -0.687988f, 0.204102f,
--0.269043f, 0.204102f, -0.225586f, 0.214844f, -0.194092f, 0.225586f, -0.162598f,
-0.245605f, -0.142334f, 0.265625f, -0.12207f, 0.293945f, -0.112549f, 0.322266f, -0.103027f,
-0.356934f, -0.103027f, 0.39209f, -0.103027f, 0.421631f, -0.113037f, 0.451172f, -0.123047f,
-0.472412f, -0.144043f, 0.493652f, -0.165039f, 0.505371f, -0.197266f, 0.51709f, -0.229492f,
-0.51709f, -0.273926f, 0.51709f, -0.687988f, 0.661133f, -0.687988f, 0.661133f, -0.265137f,
-0.661133f, -0.194336f, 0.638184f, -0.142578f, 0.615234f, -0.0908203f, 0.574219f,
--0.0568848f, 0.533203f, -0.0229492f, 0.476807f, -0.0065918f, 0.42041f, 0.00976562f,
-0.353027f, 0.00976562f, 0.407227f, 0, 0.26123f, 0, 0.00683594f, -0.687988f, 0.157227f,
--0.687988f, 0.298828f, -0.246094f, 0.305664f, -0.224121f, 0.312012f, -0.201172f,
-0.318359f, -0.178223f, 0.32373f, -0.15918f, 0.32959f, -0.136719f, 0.334961f, -0.116211f,
-0.339844f, -0.13623f, 0.345215f, -0.158203f, 0.350098f, -0.176758f, 0.356689f, -0.199951f,
-0.363281f, -0.223145f, 0.370117f, -0.246094f, 0.51123f, -0.687988f, 0.660156f, -0.687988f,
-0.765137f, 0, 0.594238f, 0, 0.500977f, -0.397949f, 0.496582f, -0.416016f, 0.491455f,
--0.440918f, 0.486328f, -0.46582f, 0.481934f, -0.489258f, 0.476562f, -0.516113f, 0.472168f,
--0.544922f, 0.466797f, -0.516113f, 0.461426f, -0.48877f, 0.458984f, -0.477051f, 0.456543f,
--0.4646f, 0.454102f, -0.452148f, 0.451416f, -0.440186f, 0.44873f, -0.428223f, 0.446533f,
--0.41748f, 0.444336f, -0.406738f, 0.441895f, -0.397949f, 0.349121f, 0, 0.178223f,
-0, 0.000976562f, -0.687988f, 0.146973f, -0.687988f, 0.23291f, -0.305176f, 0.240234f,
--0.273926f, 0.246582f, -0.243652f, 0.25293f, -0.213379f, 0.258301f, -0.189453f, 0.26416f,
--0.161621f, 0.269043f, -0.13623f, 0.276367f, -0.172363f, 0.283203f, -0.206543f, 0.286133f,
--0.221191f, 0.289551f, -0.236816f, 0.292969f, -0.252441f, 0.296143f, -0.267578f,
-0.299316f, -0.282715f, 0.30249f, -0.296631f, 0.305664f, -0.310547f, 0.308105f, -0.321777f,
-0.393066f, -0.687988f, 0.554199f, -0.687988f, 0.641113f, -0.321777f, 0.644043f, -0.310059f,
-0.646973f, -0.295654f, 0.649902f, -0.28125f, 0.652832f, -0.265869f, 0.655762f, -0.250488f,
-0.658691f, -0.235107f, 0.661621f, -0.219727f, 0.664062f, -0.205078f, 0.669922f, -0.170898f,
-0.675781f, -0.13623f, 0.681641f, -0.163574f, 0.687988f, -0.192871f, 0.693359f, -0.217773f,
-0.700195f, -0.247559f, 0.707031f, -0.277344f, 0.713867f, -0.305176f, 0.796875f, -0.687988f,
-0.942871f, -0.687988f, 0.506836f, 0, 0.333984f, -0.273926f, 0.161133f, 0, 0.00878906f,
-0, 0.24707f, -0.361816f, 0.0288086f, -0.687988f, 0.181152f, -0.687988f, 0.333984f,
--0.444824f, 0.486816f, -0.687988f, 0.638184f, -0.687988f, 0.429199f, -0.361816f,
-0.658203f, 0, 0.405762f, -0.282227f, 0.405762f, 0, 0.262207f, 0, 0.262207f, -0.282227f,
-0.0170898f, -0.687988f, 0.167969f, -0.687988f, 0.333008f, -0.396973f, 0.5f, -0.687988f,
-0.650879f, -0.687988f, 0.582031f, 0, 0.0297852f, 0, 0.0297852f, -0.102051f, 0.401855f,
--0.575195f, 0.0668945f, -0.575195f, 0.0668945f, -0.687988f, 0.562012f, -0.687988f,
-0.562012f, -0.587891f, 0.189941f, -0.112793f, 0.582031f, -0.112793f, 0.0561523f,
-0.20752f, 0.0561523f, -0.724609f, 0.320801f, -0.724609f, 0.320801f, -0.631836f, 0.186035f,
--0.631836f, 0.186035f, 0.114258f, 0.320801f, 0.114258f, 0.320801f, 0.20752f, 0.012207f,
-0.20752f, 0.012207f, 0.114258f, 0.147949f, 0.114258f, 0.147949f, -0.631836f, 0.012207f,
--0.631836f, 0.012207f, -0.724609f, 0.276855f, -0.724609f, 0.276855f, 0.20752f, 0.450195f,
--0.250977f, 0.291016f, -0.618164f, 0.132812f, -0.250977f, 0.0219727f, -0.250977f,
-0.212891f, -0.687988f, 0.370117f, -0.687988f, 0.562012f, -0.250977f, -0.00976562f,
-0.12207f, -0.00976562f, 0.0839844f, 0.564941f, 0.0839844f, 0.564941f, 0.12207f, 0.191895f,
-0.00976562f, 0.153809f, 0.00976562f, 0.123779f, -0.000732422f, 0.09375f, -0.0112305f,
-0.0727539f, -0.0314941f, 0.0517578f, -0.0517578f, 0.0405273f, -0.081543f, 0.0292969f,
--0.111328f, 0.0292969f, -0.149414f, 0.0292969f, -0.196289f, 0.0456543f, -0.228271f,
-0.0620117f, -0.260254f, 0.090332f, -0.280029f, 0.118652f, -0.299805f, 0.156738f,
--0.308838f, 0.194824f, -0.317871f, 0.237793f, -0.318359f, 0.351562f, -0.320312f,
-0.351562f, -0.347168f, 0.351562f, -0.375977f, 0.346436f, -0.395264f, 0.341309f, -0.414551f,
-0.331543f, -0.426758f, 0.321777f, -0.438965f, 0.307373f, -0.444092f, 0.292969f, -0.449219f,
-0.274414f, -0.449219f, 0.257324f, -0.449219f, 0.243896f, -0.445801f, 0.230469f, -0.442383f,
-0.220703f, -0.433838f, 0.210938f, -0.425293f, 0.204834f, -0.410889f, 0.19873f, -0.396484f,
-0.196289f, -0.374512f, 0.0532227f, -0.381348f, 0.059082f, -0.416016f, 0.074707f,
--0.44458f, 0.090332f, -0.473145f, 0.11792f, -0.494141f, 0.145508f, -0.515137f, 0.185791f,
--0.526611f, 0.226074f, -0.538086f, 0.280273f, -0.538086f, 0.32959f, -0.538086f, 0.368164f,
--0.525879f, 0.406738f, -0.513672f, 0.433594f, -0.489502f, 0.460449f, -0.465332f,
-0.474609f, -0.430176f, 0.48877f, -0.39502f, 0.48877f, -0.348633f, 0.48877f, -0.15625f,
-0.48877f, -0.137695f, 0.490479f, -0.123047f, 0.492188f, -0.108398f, 0.496826f, -0.0983887f,
-0.501465f, -0.0883789f, 0.51001f, -0.083252f, 0.518555f, -0.078125f, 0.532227f, -0.078125f,
-0.547852f, -0.078125f, 0.5625f, -0.0810547f, 0.5625f, -0.00683594f, 0.550293f, -0.00390625f,
-0.540527f, -0.00146484f, 0.530762f, 0.000976562f, 0.520996f, 0.00244141f, 0.51123f,
-0.00390625f, 0.500244f, 0.00488281f, 0.489258f, 0.00585938f, 0.474609f, 0.00585938f,
-0.422852f, 0.00585938f, 0.398193f, -0.0195312f, 0.373535f, -0.0449219f, 0.368652f,
--0.0942383f, 0.365723f, -0.0942383f, 0.338379f, -0.0449219f, 0.295654f, -0.0175781f,
-0.25293f, 0.00976562f, 0.191895f, 0.00976562f, 0.351562f, -0.244629f, 0.28125f, -0.243652f,
-0.259277f, -0.242676f, 0.239502f, -0.23999f, 0.219727f, -0.237305f, 0.204834f, -0.22876f,
-0.189941f, -0.220215f, 0.181152f, -0.204102f, 0.172363f, -0.187988f, 0.172363f, -0.160156f,
-0.172363f, -0.122559f, 0.189697f, -0.104248f, 0.207031f, -0.0859375f, 0.23584f, -0.0859375f,
-0.262207f, -0.0859375f, 0.283691f, -0.097168f, 0.305176f, -0.108398f, 0.320068f,
--0.126709f, 0.334961f, -0.14502f, 0.343262f, -0.168945f, 0.351562f, -0.192871f, 0.351562f,
--0.217773f, 0.569824f, -0.266113f, 0.569824f, -0.206055f, 0.557861f, -0.155518f,
-0.545898f, -0.10498f, 0.520996f, -0.0681152f, 0.496094f, -0.03125f, 0.457764f, -0.0107422f,
-0.419434f, 0.00976562f, 0.367188f, 0.00976562f, 0.34375f, 0.00976562f, 0.320312f,
-0.00488281f, 0.296875f, 0, 0.275879f, -0.0112305f, 0.254883f, -0.0224609f, 0.237305f,
--0.0405273f, 0.219727f, -0.0585938f, 0.207031f, -0.0849609f, 0.206055f, -0.0849609f,
-0.206055f, -0.074707f, 0.205322f, -0.0615234f, 0.20459f, -0.0483398f, 0.203613f,
--0.0358887f, 0.202637f, -0.0234375f, 0.201416f, -0.0136719f, 0.200195f, -0.00390625f,
-0.199219f, 0, 0.065918f, 0, 0.0673828f, -0.0170898f, 0.0686035f, -0.048584f, 0.0698242f,
--0.0800781f, 0.0698242f, -0.120605f, 0.0698242f, -0.724609f, 0.207031f, -0.724609f,
-0.207031f, -0.522461f, 0.207031f, -0.506836f, 0.206787f, -0.491943f, 0.206543f, -0.477051f,
-0.206055f, -0.464355f, 0.205566f, -0.449707f, 0.205078f, -0.436523f, 0.207031f, -0.436523f,
-0.231934f, -0.491211f, 0.275391f, -0.514648f, 0.318848f, -0.538086f, 0.375977f, -0.538086f,
-0.426758f, -0.538086f, 0.463379f, -0.517822f, 0.5f, -0.497559f, 0.523682f, -0.461182f,
-0.547363f, -0.424805f, 0.558594f, -0.375f, 0.569824f, -0.325195f, 0.569824f, -0.266113f,
-0.426758f, -0.266113f, 0.426758f, -0.355957f, 0.400391f, -0.399414f, 0.374023f, -0.442871f,
-0.318848f, -0.442871f, 0.297852f, -0.442871f, 0.277344f, -0.43457f, 0.256836f, -0.42627f,
-0.240723f, -0.405518f, 0.224609f, -0.384766f, 0.214844f, -0.349854f, 0.205078f, -0.314941f,
-0.205078f, -0.261719f, 0.205078f, -0.209961f, 0.214844f, -0.175781f, 0.224609f, -0.141602f,
-0.240234f, -0.121094f, 0.255859f, -0.100586f, 0.276367f, -0.0922852f, 0.296875f,
--0.0839844f, 0.317871f, -0.0839844f, 0.370117f, -0.0839844f, 0.398438f, -0.127197f,
-0.426758f, -0.17041f, 0.426758f, -0.266113f, 0.412109f, 0, 0.411133f, -0.00390625f,
-0.409912f, -0.013916f, 0.408691f, -0.0239258f, 0.407471f, -0.0366211f, 0.40625f,
--0.0493164f, 0.405518f, -0.0625f, 0.404785f, -0.0756836f, 0.404785f, -0.0859375f,
-0.402832f, -0.0859375f, 0.378906f, -0.034668f, 0.336182f, -0.0124512f, 0.293457f,
-0.00976562f, 0.233887f, 0.00976562f, 0.184082f, 0.00976562f, 0.147705f, -0.0107422f,
-0.111328f, -0.03125f, 0.0876465f, -0.0678711f, 0.0639648f, -0.104492f, 0.0524902f,
--0.154541f, 0.0410156f, -0.20459f, 0.0410156f, -0.263672f, 0.0410156f, -0.32373f,
-0.0529785f, -0.374023f, 0.0649414f, -0.424316f, 0.0898438f, -0.460693f, 0.114746f,
--0.49707f, 0.153076f, -0.517578f, 0.191406f, -0.538086f, 0.244141f, -0.538086f, 0.27002f,
--0.538086f, 0.293945f, -0.532715f, 0.317871f, -0.527344f, 0.338379f, -0.516113f,
-0.358887f, -0.504883f, 0.375488f, -0.487305f, 0.39209f, -0.469727f, 0.403809f, -0.444824f,
-0.404785f, -0.444824f, 0.404785f, -0.449707f, 0.404541f, -0.459229f, 0.404297f, -0.46875f,
-0.404297f, -0.480957f, 0.404297f, -0.493164f, 0.404053f, -0.506348f, 0.403809f, -0.519531f,
-0.403809f, -0.531738f, 0.403809f, -0.724609f, 0.541016f, -0.724609f, 0.541016f, -0.115234f,
-0.541016f, -0.0766602f, 0.54248f, -0.0466309f, 0.543945f, -0.0166016f, 0.544922f,
-0, 0.405762f, -0.26709f, 0.405762f, -0.319336f, 0.395996f, -0.35376f, 0.38623f, -0.388184f,
-0.370361f, -0.408447f, 0.354492f, -0.428711f, 0.334229f, -0.436768f, 0.313965f, -0.444824f,
-0.292969f, -0.444824f, 0.266602f, -0.444824f, 0.246338f, -0.43457f, 0.226074f, -0.424316f,
-0.212158f, -0.402344f, 0.198242f, -0.380371f, 0.191162f, -0.346191f, 0.184082f, -0.312012f,
-0.184082f, -0.263672f, 0.184082f, -0.0839844f, 0.291992f, -0.0839844f, 0.3125f, -0.0839844f,
-0.333008f, -0.0927734f, 0.353516f, -0.101562f, 0.369629f, -0.122559f, 0.385742f,
--0.143555f, 0.395752f, -0.178955f, 0.405762f, -0.214355f, 0.405762f, -0.26709f, 0.286133f,
-0.00976562f, 0.229004f, 0.00976562f, 0.18335f, -0.00708008f, 0.137695f, -0.0239258f,
-0.105469f, -0.0583496f, 0.0732422f, -0.0927734f, 0.0561523f, -0.144775f, 0.0390625f,
--0.196777f, 0.0390625f, -0.266602f, 0.0390625f, -0.342285f, 0.0593262f, -0.394043f,
-0.0795898f, -0.445801f, 0.114014f, -0.477783f, 0.148438f, -0.509766f, 0.193359f,
--0.523926f, 0.238281f, -0.538086f, 0.288086f, -0.538086f, 0.350586f, -0.538086f,
-0.394775f, -0.516357f, 0.438965f, -0.494629f, 0.467285f, -0.455566f, 0.495605f, -0.416504f,
-0.508789f, -0.362061f, 0.521973f, -0.307617f, 0.521973f, -0.241699f, 0.521973f, -0.237793f,
-0.183105f, -0.237793f, 0.183105f, -0.20459f, 0.188965f, -0.176025f, 0.194824f, -0.147461f,
-0.208008f, -0.126709f, 0.221191f, -0.105957f, 0.242188f, -0.0939941f, 0.263184f,
--0.0820312f, 0.292969f, -0.0820312f, 0.329102f, -0.0820312f, 0.352051f, -0.0974121f,
-0.375f, -0.112793f, 0.384766f, -0.14502f, 0.51416f, -0.133789f, 0.505371f, -0.111328f,
-0.489502f, -0.0859375f, 0.473633f, -0.0605469f, 0.447266f, -0.0393066f, 0.420898f,
--0.0180664f, 0.381592f, -0.00415039f, 0.342285f, 0.00976562f, 0.286133f, 0.00976562f,
-0.286133f, -0.45166f, 0.265137f, -0.45166f, 0.246826f, -0.44458f, 0.228516f, -0.4375f,
-0.215088f, -0.422119f, 0.20166f, -0.406738f, 0.193359f, -0.382324f, 0.185059f, -0.35791f,
-0.184082f, -0.32373f, 0.38916f, -0.32373f, 0.385254f, -0.387695f, 0.358398f, -0.419678f,
-0.331543f, -0.45166f, 0.286133f, -0.45166f, 0.230957f, -0.435547f, 0.230957f, 0,
-0.0942383f, 0, 0.0942383f, -0.435547f, 0.0170898f, -0.435547f, 0.0170898f, -0.52832f,
-0.0942383f, -0.52832f, 0.0942383f, -0.583496f, 0.0942383f, -0.61377f, 0.101562f,
--0.639404f, 0.108887f, -0.665039f, 0.126465f, -0.684082f, 0.144043f, -0.703125f,
-0.173828f, -0.713867f, 0.203613f, -0.724609f, 0.248047f, -0.724609f, 0.271484f, -0.724609f,
-0.294189f, -0.722168f, 0.316895f, -0.719727f, 0.334961f, -0.716797f, 0.334961f, -0.628418f,
-0.326172f, -0.630371f, 0.315186f, -0.631592f, 0.304199f, -0.632812f, 0.294922f, -0.632812f,
-0.275879f, -0.632812f, 0.263428f, -0.628906f, 0.250977f, -0.625f, 0.243896f, -0.617188f,
-0.236816f, -0.609375f, 0.233887f, -0.597412f, 0.230957f, -0.585449f, 0.230957f, -0.569824f,
-0.230957f, -0.52832f, 0.334961f, -0.52832f, 0.334961f, -0.435547f, 0.291016f, 0.211914f,
-0.23877f, 0.211914f, 0.198975f, 0.201416f, 0.15918f, 0.190918f, 0.131104f, 0.172119f,
-0.103027f, 0.15332f, 0.0861816f, 0.127197f, 0.0693359f, 0.101074f, 0.0629883f, 0.0698242f,
-0.200195f, 0.0537109f, 0.20752f, 0.0854492f, 0.231689f, 0.103516f, 0.255859f, 0.121582f,
-0.294922f, 0.121582f, 0.319336f, 0.121582f, 0.3396f, 0.114746f, 0.359863f, 0.10791f,
-0.374268f, 0.0915527f, 0.388672f, 0.0751953f, 0.396729f, 0.0483398f, 0.404785f, 0.0214844f,
-0.404785f, -0.0180664f, 0.404785f, -0.0317383f, 0.404785f, -0.0458984f, 0.404785f,
--0.0600586f, 0.405273f, -0.0717773f, 0.405762f, -0.0854492f, 0.405762f, -0.0981445f,
-0.404785f, -0.0981445f, 0.380859f, -0.046875f, 0.337646f, -0.0239258f, 0.294434f,
--0.000976562f, 0.234863f, -0.000976562f, 0.18457f, -0.000976562f, 0.148193f, -0.020752f,
-0.111816f, -0.0405273f, 0.0878906f, -0.0759277f, 0.0639648f, -0.111328f, 0.0524902f,
--0.1604f, 0.0410156f, -0.209473f, 0.0410156f, -0.268555f, 0.0410156f, -0.32959f,
-0.0532227f, -0.37915f, 0.0654297f, -0.428711f, 0.0905762f, -0.464355f, 0.115723f,
--0.5f, 0.154053f, -0.519287f, 0.192383f, -0.538574f, 0.245117f, -0.538574f, 0.297852f,
--0.538574f, 0.3396f, -0.516113f, 0.381348f, -0.493652f, 0.404785f, -0.443359f, 0.407227f,
--0.443359f, 0.407227f, -0.453613f, 0.407959f, -0.467041f, 0.408691f, -0.480469f,
-0.409668f, -0.49292f, 0.410645f, -0.505371f, 0.411865f, -0.515137f, 0.413086f, -0.524902f,
-0.414062f, -0.52832f, 0.543945f, -0.52832f, 0.542969f, -0.510742f, 0.541992f, -0.479004f,
-0.541016f, -0.447266f, 0.541016f, -0.40625f, 0.541016f, -0.0161133f, 0.541016f, 0.0415039f,
-0.524414f, 0.0842285f, 0.507812f, 0.126953f, 0.47583f, 0.155273f, 0.443848f, 0.183594f,
-0.397217f, 0.197754f, 0.350586f, 0.211914f, 0.291016f, 0.211914f, 0.405762f, -0.271484f,
-0.405762f, -0.321289f, 0.395996f, -0.354492f, 0.38623f, -0.387695f, 0.370605f, -0.407715f,
-0.35498f, -0.427734f, 0.334717f, -0.436035f, 0.314453f, -0.444336f, 0.293945f, -0.444336f,
-0.267578f, -0.444336f, 0.247314f, -0.434082f, 0.227051f, -0.423828f, 0.212891f, -0.402344f,
-0.19873f, -0.380859f, 0.191406f, -0.347656f, 0.184082f, -0.314453f, 0.184082f, -0.268555f,
-0.184082f, -0.183105f, 0.211426f, -0.139648f, 0.23877f, -0.0961914f, 0.292969f, -0.0961914f,
-0.313477f, -0.0961914f, 0.33374f, -0.104248f, 0.354004f, -0.112305f, 0.370117f, -0.132568f,
-0.38623f, -0.152832f, 0.395996f, -0.186523f, 0.405762f, -0.220215f, 0.405762f, -0.271484f,
-0.205078f, -0.422852f, 0.23291f, -0.483398f, 0.274902f, -0.510742f, 0.316895f, -0.538086f,
-0.375f, -0.538086f, 0.422852f, -0.538086f, 0.455811f, -0.522461f, 0.48877f, -0.506836f,
-0.509521f, -0.479492f, 0.530273f, -0.452148f, 0.539551f, -0.415039f, 0.548828f, -0.37793f,
-0.548828f, -0.334961f, 0.548828f, 0, 0.412109f, 0, 0.412109f, -0.295898f, 0.412109f,
--0.32666f, 0.407227f, -0.352295f, 0.402344f, -0.37793f, 0.391113f, -0.39624f, 0.379883f,
--0.414551f, 0.361816f, -0.424805f, 0.34375f, -0.435059f, 0.317871f, -0.435059f, 0.292969f,
--0.435059f, 0.272705f, -0.424072f, 0.252441f, -0.413086f, 0.237793f, -0.392822f,
-0.223145f, -0.372559f, 0.215088f, -0.344482f, 0.207031f, -0.316406f, 0.207031f, -0.282715f,
-0.207031f, 0, 0.0698242f, 0, 0.0698242f, -0.724609f, 0.207031f, -0.724609f, 0.207031f,
--0.526855f, 0.207031f, -0.51123f, 0.206543f, -0.495361f, 0.206055f, -0.479492f, 0.205322f,
--0.465576f, 0.20459f, -0.45166f, 0.204102f, -0.44043f, 0.203613f, -0.429199f, 0.203125f,
--0.422852f, 0.0698242f, -0.623535f, 0.0698242f, -0.724609f, 0.207031f, -0.724609f,
-0.207031f, -0.623535f, 0.0698242f, 0, 0.0698242f, -0.52832f, 0.207031f, -0.52832f,
-0.207031f, 0, 0.0703125f, -0.623535f, 0.0703125f, -0.724609f, 0.20752f, -0.724609f,
-0.20752f, -0.623535f, 0.0673828f, 0.20752f, 0.0400391f, 0.20752f, 0.0197754f, 0.206299f,
--0.000488281f, 0.205078f, -0.015625f, 0.203125f, -0.015625f, 0.106445f, -0.00927734f,
-0.107422f, -0.00292969f, 0.10791f, 0.00341797f, 0.108398f, 0.00927734f, 0.108398f,
-0.0283203f, 0.108398f, 0.0400391f, 0.104492f, 0.0517578f, 0.100586f, 0.0585938f,
-0.0913086f, 0.0654297f, 0.0820312f, 0.0678711f, 0.0668945f, 0.0703125f, 0.0517578f,
-0.0703125f, 0.0292969f, 0.0703125f, -0.52832f, 0.20752f, -0.52832f, 0.20752f, 0.0625f,
-0.20752f, 0.0942383f, 0.199707f, 0.120605f, 0.191895f, 0.146973f, 0.175049f, 0.166504f,
-0.158203f, 0.186035f, 0.131592f, 0.196777f, 0.10498f, 0.20752f, 0.0673828f, 0.20752f,
-0.407227f, 0, 0.266113f, -0.239258f, 0.207031f, -0.198242f, 0.207031f, 0, 0.0698242f,
-0, 0.0698242f, -0.724609f, 0.207031f, -0.724609f, 0.207031f, -0.30957f, 0.395508f,
--0.52832f, 0.542969f, -0.52832f, 0.357422f, -0.322266f, 0.557129f, 0, 0.0698242f,
-0, 0.0698242f, -0.724609f, 0.207031f, -0.724609f, 0.207031f, 0, 0.380859f, 0, 0.380859f,
--0.296387f, 0.380859f, -0.327148f, 0.376709f, -0.352783f, 0.372559f, -0.378418f,
-0.363037f, -0.396729f, 0.353516f, -0.415039f, 0.338135f, -0.425293f, 0.322754f, -0.435547f,
-0.300781f, -0.435547f, 0.279785f, -0.435547f, 0.262695f, -0.424561f, 0.245605f, -0.413574f,
-0.233154f, -0.393311f, 0.220703f, -0.373047f, 0.213867f, -0.344971f, 0.207031f, -0.316895f,
-0.207031f, -0.283203f, 0.207031f, 0, 0.0698242f, 0, 0.0698242f, -0.410156f, 0.0698242f,
--0.427246f, 0.0695801f, -0.445312f, 0.0693359f, -0.463379f, 0.0686035f, -0.479736f,
-0.0678711f, -0.496094f, 0.0673828f, -0.509033f, 0.0668945f, -0.521973f, 0.065918f,
--0.52832f, 0.196777f, -0.52832f, 0.197754f, -0.522461f, 0.19873f, -0.509521f, 0.199707f,
--0.496582f, 0.200684f, -0.480957f, 0.20166f, -0.465332f, 0.202393f, -0.449707f, 0.203125f,
--0.434082f, 0.203125f, -0.42334f, 0.205078f, -0.42334f, 0.230469f, -0.483887f, 0.268311f,
--0.51123f, 0.306152f, -0.538574f, 0.358887f, -0.538574f, 0.419434f, -0.538574f, 0.456299f,
--0.509033f, 0.493164f, -0.479492f, 0.505859f, -0.42334f, 0.508789f, -0.42334f, 0.522949f,
--0.456055f, 0.539307f, -0.478027f, 0.555664f, -0.5f, 0.575439f, -0.513428f, 0.595215f,
--0.526855f, 0.618408f, -0.532715f, 0.641602f, -0.538574f, 0.668945f, -0.538574f,
-0.712402f, -0.538574f, 0.742432f, -0.522949f, 0.772461f, -0.507324f, 0.79126f, -0.47998f,
-0.810059f, -0.452637f, 0.818604f, -0.415527f, 0.827148f, -0.378418f, 0.827148f, -0.335449f,
-0.827148f, 0, 0.690918f, 0, 0.690918f, -0.296387f, 0.690918f, -0.327148f, 0.686768f,
--0.352783f, 0.682617f, -0.378418f, 0.673096f, -0.396729f, 0.663574f, -0.415039f,
-0.648193f, -0.425293f, 0.632812f, -0.435547f, 0.61084f, -0.435547f, 0.590332f, -0.435547f,
-0.573486f, -0.425049f, 0.556641f, -0.414551f, 0.544189f, -0.395264f, 0.531738f, -0.375977f,
-0.524902f, -0.349121f, 0.518066f, -0.322266f, 0.51709f, -0.289551f, 0.51709f, 0,
-0.412109f, 0, 0.412109f, -0.296387f, 0.412109f, -0.327148f, 0.407227f, -0.352783f,
-0.402344f, -0.378418f, 0.391113f, -0.396729f, 0.379883f, -0.415039f, 0.361816f, -0.425293f,
-0.34375f, -0.435547f, 0.317871f, -0.435547f, 0.292969f, -0.435547f, 0.272705f, -0.424561f,
-0.252441f, -0.413574f, 0.237793f, -0.393311f, 0.223145f, -0.373047f, 0.215088f, -0.344971f,
-0.207031f, -0.316895f, 0.207031f, -0.283203f, 0.207031f, 0, 0.0698242f, 0, 0.0698242f,
--0.410156f, 0.0698242f, -0.427246f, 0.0695801f, -0.445312f, 0.0693359f, -0.463379f,
-0.0686035f, -0.479736f, 0.0678711f, -0.496094f, 0.0673828f, -0.509033f, 0.0668945f,
--0.521973f, 0.065918f, -0.52832f, 0.196777f, -0.52832f, 0.197754f, -0.522461f, 0.19873f,
--0.509521f, 0.199707f, -0.496582f, 0.200684f, -0.480957f, 0.20166f, -0.465332f, 0.202393f,
--0.449707f, 0.203125f, -0.434082f, 0.203125f, -0.42334f, 0.205078f, -0.42334f, 0.23291f,
--0.483887f, 0.274902f, -0.51123f, 0.316895f, -0.538574f, 0.375f, -0.538574f, 0.422852f,
--0.538574f, 0.455811f, -0.522949f, 0.48877f, -0.507324f, 0.509521f, -0.47998f, 0.530273f,
--0.452637f, 0.539551f, -0.415527f, 0.548828f, -0.378418f, 0.548828f, -0.335449f,
-0.548828f, 0, 0.571777f, -0.264648f, 0.571777f, -0.204102f, 0.554932f, -0.153809f,
-0.538086f, -0.103516f, 0.504395f, -0.0671387f, 0.470703f, -0.0307617f, 0.42041f,
--0.010498f, 0.370117f, 0.00976562f, 0.303223f, 0.00976562f, 0.23877f, 0.00976562f,
-0.189453f, -0.0102539f, 0.140137f, -0.0302734f, 0.106689f, -0.0664062f, 0.0732422f,
--0.102539f, 0.0561523f, -0.153076f, 0.0390625f, -0.203613f, 0.0390625f, -0.264648f,
-0.0390625f, -0.32373f, 0.0554199f, -0.373779f, 0.0717773f, -0.423828f, 0.10498f,
--0.460449f, 0.138184f, -0.49707f, 0.188477f, -0.517578f, 0.23877f, -0.538086f, 0.306152f,
--0.538086f, 0.377441f, -0.538086f, 0.427734f, -0.517578f, 0.478027f, -0.49707f, 0.51001f,
--0.460693f, 0.541992f, -0.424316f, 0.556885f, -0.374268f, 0.571777f, -0.324219f,
-0.571777f, -0.264648f, 0.428223f, -0.264648f, 0.428223f, -0.358887f, 0.397461f, -0.401367f,
-0.366699f, -0.443848f, 0.308105f, -0.443848f, 0.247559f, -0.443848f, 0.215332f, -0.400879f,
-0.183105f, -0.35791f, 0.183105f, -0.264648f, 0.183105f, -0.217285f, 0.19165f, -0.183105f,
-0.200195f, -0.148926f, 0.21582f, -0.126953f, 0.231445f, -0.10498f, 0.253418f, -0.0944824f,
-0.275391f, -0.0839844f, 0.301758f, -0.0839844f, 0.332031f, -0.0839844f, 0.355713f,
--0.0944824f, 0.379395f, -0.10498f, 0.395508f, -0.126953f, 0.411621f, -0.148926f,
-0.419922f, -0.183105f, 0.428223f, -0.217285f, 0.428223f, -0.264648f, 0.569824f, -0.266602f,
-0.569824f, -0.206543f, 0.557861f, -0.155762f, 0.545898f, -0.10498f, 0.520996f, -0.0683594f,
-0.496094f, -0.0317383f, 0.457764f, -0.0109863f, 0.419434f, 0.00976562f, 0.367188f,
-0.00976562f, 0.34375f, 0.00976562f, 0.320557f, 0.00488281f, 0.297363f, 0, 0.276367f,
--0.0109863f, 0.255371f, -0.0219727f, 0.237549f, -0.0397949f, 0.219727f, -0.0576172f,
-0.207031f, -0.0839844f, 0.204102f, -0.0839844f, 0.20459f, -0.081543f, 0.205078f,
--0.0717773f, 0.205566f, -0.0620117f, 0.206055f, -0.0490723f, 0.206543f, -0.0361328f,
-0.206787f, -0.0217285f, 0.207031f, -0.00732422f, 0.207031f, 0.00488281f, 0.207031f,
-0.20752f, 0.0698242f, 0.20752f, 0.0698242f, -0.406738f, 0.0698242f, -0.447266f, 0.0686035f,
--0.479004f, 0.0673828f, -0.510742f, 0.065918f, -0.52832f, 0.199219f, -0.52832f, 0.200195f,
--0.524902f, 0.201416f, -0.515137f, 0.202637f, -0.505371f, 0.203369f, -0.492676f,
-0.204102f, -0.47998f, 0.20459f, -0.466309f, 0.205078f, -0.452637f, 0.205078f, -0.442383f,
-0.207031f, -0.442383f, 0.231934f, -0.494629f, 0.275391f, -0.51709f, 0.318848f, -0.539551f,
-0.375977f, -0.539551f, 0.42627f, -0.539551f, 0.462891f, -0.519043f, 0.499512f, -0.498535f,
-0.523193f, -0.462402f, 0.546875f, -0.42627f, 0.55835f, -0.376221f, 0.569824f, -0.326172f,
-0.569824f, -0.266602f, 0.426758f, -0.266602f, 0.426758f, -0.356934f, 0.399414f, -0.400635f,
-0.37207f, -0.444336f, 0.317871f, -0.444336f, 0.297363f, -0.444336f, 0.2771f, -0.435791f,
-0.256836f, -0.427246f, 0.240967f, -0.406494f, 0.225098f, -0.385742f, 0.215088f, -0.35083f,
-0.205078f, -0.315918f, 0.205078f, -0.262695f, 0.205078f, -0.210938f, 0.214844f, -0.176514f,
-0.224609f, -0.14209f, 0.240479f, -0.121582f, 0.256348f, -0.101074f, 0.276367f, -0.0925293f,
-0.296387f, -0.0839844f, 0.316895f, -0.0839844f, 0.343262f, -0.0839844f, 0.36377f,
--0.0944824f, 0.384277f, -0.10498f, 0.398193f, -0.127197f, 0.412109f, -0.149414f,
-0.419434f, -0.184082f, 0.426758f, -0.21875f, 0.426758f, -0.266602f, 0.0410156f, -0.263672f,
-0.0410156f, -0.32373f, 0.0532227f, -0.374268f, 0.0654297f, -0.424805f, 0.0905762f,
--0.461182f, 0.115723f, -0.497559f, 0.154053f, -0.518066f, 0.192383f, -0.538574f,
-0.245117f, -0.538574f, 0.297852f, -0.538574f, 0.3396f, -0.516113f, 0.381348f, -0.493652f,
-0.404785f, -0.443359f, 0.404785f, -0.453613f, 0.405518f, -0.467041f, 0.40625f, -0.480469f,
-0.407471f, -0.49292f, 0.408691f, -0.505371f, 0.409912f, -0.515137f, 0.411133f, -0.524902f,
-0.412109f, -0.52832f, 0.543945f, -0.52832f, 0.542969f, -0.510742f, 0.541992f, -0.479004f,
-0.541016f, -0.447266f, 0.541016f, -0.406738f, 0.541016f, 0.20752f, 0.404785f, 0.20752f,
-0.404785f, -0.012207f, 0.404785f, -0.0258789f, 0.405273f, -0.0390625f, 0.405762f,
--0.0522461f, 0.40625f, -0.0634766f, 0.406738f, -0.0761719f, 0.407227f, -0.0878906f,
-0.40625f, -0.0878906f, 0.382324f, -0.0366211f, 0.337891f, -0.0134277f, 0.293457f,
-0.00976562f, 0.233887f, 0.00976562f, 0.184082f, 0.00976562f, 0.147705f, -0.0107422f,
-0.111328f, -0.03125f, 0.0876465f, -0.0678711f, 0.0639648f, -0.104492f, 0.0524902f,
--0.154541f, 0.0410156f, -0.20459f, 0.0410156f, -0.263672f, 0.405762f, -0.266602f,
-0.405762f, -0.319336f, 0.395996f, -0.353516f, 0.38623f, -0.387695f, 0.370605f, -0.407959f,
-0.35498f, -0.428223f, 0.334717f, -0.436279f, 0.314453f, -0.444336f, 0.293945f, -0.444336f,
-0.267578f, -0.444336f, 0.247314f, -0.434082f, 0.227051f, -0.423828f, 0.212891f, -0.401855f,
-0.19873f, -0.379883f, 0.191406f, -0.345703f, 0.184082f, -0.311523f, 0.184082f, -0.263672f,
-0.184082f, -0.0839844f, 0.292969f, -0.0839844f, 0.313477f, -0.0839844f, 0.33374f,
--0.0927734f, 0.354004f, -0.101562f, 0.370117f, -0.122559f, 0.38623f, -0.143555f,
-0.395996f, -0.178711f, 0.405762f, -0.213867f, 0.405762f, -0.266602f, 0.0698242f,
-0, 0.0698242f, -0.404297f, 0.0698242f, -0.421387f, 0.0695801f, -0.44043f, 0.0693359f,
--0.459473f, 0.0686035f, -0.476807f, 0.0678711f, -0.494141f, 0.0673828f, -0.508057f,
-0.0668945f, -0.521973f, 0.065918f, -0.52832f, 0.196777f, -0.52832f, 0.197754f, -0.522461f,
-0.19873f, -0.508057f, 0.199707f, -0.493652f, 0.200684f, -0.476562f, 0.20166f, -0.459473f,
-0.202393f, -0.442627f, 0.203125f, -0.425781f, 0.203125f, -0.415527f, 0.205078f, -0.415527f,
-0.215332f, -0.444336f, 0.225586f, -0.467041f, 0.23584f, -0.489746f, 0.249756f, -0.505615f,
-0.263672f, -0.521484f, 0.283203f, -0.530029f, 0.302734f, -0.538574f, 0.331543f, -0.538574f,
-0.34375f, -0.538574f, 0.355713f, -0.536377f, 0.367676f, -0.53418f, 0.374023f, -0.53125f,
-0.374023f, -0.416504f, 0.36084f, -0.419434f, 0.347412f, -0.421631f, 0.333984f, -0.423828f,
-0.31543f, -0.423828f, 0.26416f, -0.423828f, 0.235596f, -0.382324f, 0.207031f, -0.34082f,
-0.207031f, -0.259277f, 0.207031f, 0, 0.515137f, -0.154297f, 0.515137f, -0.116211f,
-0.499268f, -0.0859375f, 0.483398f, -0.0556641f, 0.453125f, -0.0344238f, 0.422852f,
--0.0131836f, 0.378906f, -0.00170898f, 0.334961f, 0.00976562f, 0.278809f, 0.00976562f,
-0.228516f, 0.00976562f, 0.187988f, 0.00244141f, 0.147461f, -0.00488281f, 0.116943f,
--0.0217285f, 0.0864258f, -0.0385742f, 0.065918f, -0.0654297f, 0.0454102f, -0.0922852f,
-0.0351562f, -0.131836f, 0.155762f, -0.149902f, 0.161621f, -0.12793f, 0.171875f, -0.114258f,
-0.182129f, -0.100586f, 0.197266f, -0.0932617f, 0.212402f, -0.0859375f, 0.232666f,
--0.0834961f, 0.25293f, -0.0810547f, 0.278809f, -0.0810547f, 0.302246f, -0.0810547f,
-0.32251f, -0.0837402f, 0.342773f, -0.0864258f, 0.357666f, -0.0930176f, 0.372559f,
--0.0996094f, 0.380859f, -0.111572f, 0.38916f, -0.123535f, 0.38916f, -0.141602f, 0.38916f,
--0.162109f, 0.377197f, -0.174072f, 0.365234f, -0.186035f, 0.344482f, -0.193604f,
-0.32373f, -0.201172f, 0.295654f, -0.206787f, 0.267578f, -0.212402f, 0.23584f, -0.219727f,
-0.202637f, -0.227051f, 0.17041f, -0.237305f, 0.138184f, -0.247559f, 0.112793f, -0.265137f,
-0.0874023f, -0.282715f, 0.0717773f, -0.309814f, 0.0561523f, -0.336914f, 0.0561523f,
--0.378418f, 0.0561523f, -0.416016f, 0.0708008f, -0.445557f, 0.0854492f, -0.475098f,
-0.11377f, -0.49585f, 0.14209f, -0.516602f, 0.183838f, -0.527588f, 0.225586f, -0.538574f,
-0.279785f, -0.538574f, 0.322754f, -0.538574f, 0.359863f, -0.530518f, 0.396973f, -0.522461f,
-0.42627f, -0.505127f, 0.455566f, -0.487793f, 0.475342f, -0.460938f, 0.495117f, -0.434082f,
-0.50293f, -0.395996f, 0.381348f, -0.383301f, 0.37793f, -0.402344f, 0.369141f, -0.414795f,
-0.360352f, -0.427246f, 0.347412f, -0.43457f, 0.334473f, -0.441895f, 0.317383f, -0.44458f,
-0.300293f, -0.447266f, 0.279785f, -0.447266f, 0.230957f, -0.447266f, 0.206543f, -0.434814f,
-0.182129f, -0.422363f, 0.182129f, -0.393066f, 0.182129f, -0.375f, 0.192139f, -0.364258f,
-0.202148f, -0.353516f, 0.220459f, -0.346436f, 0.23877f, -0.339355f, 0.263916f, -0.334229f,
-0.289062f, -0.329102f, 0.318848f, -0.321777f, 0.355469f, -0.313965f, 0.390869f, -0.303467f,
-0.42627f, -0.292969f, 0.453857f, -0.274658f, 0.481445f, -0.256348f, 0.498291f, -0.227539f,
-0.515137f, -0.19873f, 0.515137f, -0.154297f, 0.199219f, -0.52832f, 0.199219f, -0.231934f,
-0.199219f, -0.201172f, 0.204102f, -0.175537f, 0.208984f, -0.149902f, 0.220215f, -0.131592f,
-0.231445f, -0.113281f, 0.249268f, -0.103027f, 0.26709f, -0.0927734f, 0.292969f, -0.0927734f,
-0.317871f, -0.0927734f, 0.338135f, -0.10376f, 0.358398f, -0.114746f, 0.373047f, -0.13501f,
-0.387695f, -0.155273f, 0.395752f, -0.18335f, 0.403809f, -0.211426f, 0.403809f, -0.245117f,
-0.403809f, -0.52832f, 0.541016f, -0.52832f, 0.541016f, -0.118164f, 0.541016f, -0.101562f,
-0.54126f, -0.083252f, 0.541504f, -0.0649414f, 0.542236f, -0.048584f, 0.542969f, -0.0322266f,
-0.543701f, -0.0192871f, 0.544434f, -0.00634766f, 0.544922f, 0, 0.414062f, 0, 0.413574f,
--0.00585938f, 0.412354f, -0.0187988f, 0.411133f, -0.0317383f, 0.4104f, -0.0473633f,
-0.409668f, -0.0629883f, 0.408936f, -0.0786133f, 0.408203f, -0.0942383f, 0.408203f,
--0.10498f, 0.405762f, -0.10498f, 0.378418f, -0.0449219f, 0.336182f, -0.0175781f,
-0.293945f, 0.00976562f, 0.23584f, 0.00976562f, 0.188477f, 0.00976562f, 0.155273f,
--0.00585938f, 0.12207f, -0.0214844f, 0.101318f, -0.048584f, 0.0805664f, -0.0756836f,
-0.0712891f, -0.112793f, 0.0620117f, -0.149902f, 0.0620117f, -0.192871f, 0.0620117f,
--0.52832f, 0.275879f, -0.11084f, 0.408203f, -0.52832f, 0.551758f, -0.52832f, 0.356934f,
-0, 0.192871f, 0, 0.00390625f, -0.52832f, 0.148926f, -0.52832f, 0.212891f, -0.124512f,
-0.314941f, -0.52832f, 0.461914f, -0.52832f, 0.562988f, -0.124512f, 0.652832f, -0.52832f,
-0.779785f, -0.52832f, 0.641113f, 0, 0.496094f, 0, 0.38916f, -0.430664f, 0.278809f,
-0, 0.133789f, 0, -0.00292969f, -0.52832f, 0.125977f, -0.52832f, 0.399902f, 0, 0.276855f,
--0.191406f, 0.152832f, 0, 0.00683594f, 0, 0.200195f, -0.272949f, 0.0161133f, -0.52832f,
-0.164062f, -0.52832f, 0.276855f, -0.355469f, 0.38916f, -0.52832f, 0.538086f, -0.52832f,
-0.354004f, -0.274414f, 0.548828f, 0, 0.285156f, -0.117676f, 0.407227f, -0.52832f,
-0.550781f, -0.52832f, 0.341797f, 0.027832f, 0.302246f, 0.124023f, 0.259766f, 0.164062f,
-0.213379f, 0.20752f, 0.138184f, 0.20752f, 0.0888672f, 0.20752f, 0.0517578f, 0.201172f,
-0.0517578f, 0.103516f, 0.0776367f, 0.107422f, 0.0983887f, 0.107422f, 0.119141f, 0.107422f,
-0.134766f, 0.103027f, 0.150391f, 0.0986328f, 0.163086f, 0.0883789f, 0.187988f, 0.0678711f,
-0.208008f, 0.0180664f, 0.216797f, -0.00537109f, 0.0078125f, -0.52832f, 0.152832f,
--0.52832f, 0.0332031f, 0, 0.0332031f, -0.097168f, 0.296875f, -0.429199f, 0.0532227f,
--0.429199f, 0.0532227f, -0.52832f, 0.448242f, -0.52832f, 0.448242f, -0.430176f, 0.186035f,
--0.100098f, 0.472168f, -0.100098f, 0.472168f, 0
-};
-
-const unsigned char LiberationSanskBoldVerbs[] = {
-6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1,
-1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 1, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1,
-1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1,
-1, 5, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5,
-6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 1, 1, 1, 2, 2, 5, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2,
-5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 0, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 5, 0, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5,
-6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
-1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 1, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1,
-5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2,
-2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5,
-6, 0, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 5, 6
-};
-
-const unsigned LiberationSanskBoldCharCodes[] = {
-32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 50, 51,
-53, 54, 55, 56, 57, 58, 59, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-76, 77, 79, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 100, 101,
-102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 117, 118,
-119, 120, 121, 122
-};
-
-const SkFixed LiberationSanskBoldWidths[] = {
-0x00004720, 0x00005540, 0x00007960, 0x00008e60, 0x00008e60, 0x0000e3a0, 0x0000b8e0,
-0x00003ce0, 0x00005540, 0x00005540, 0x000063a0, 0x00009580, 0x00005540, 0x00004720,
-0x00004720, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60,
-0x00008e60, 0x00008e60, 0x00008e60, 0x00005540, 0x00005540, 0x00009580, 0x00009580,
-0x00009c60, 0x0000b8e0, 0x0000b8e0, 0x0000b8e0, 0x0000b8e0, 0x0000aac0, 0x00009c60,
-0x0000c720, 0x0000b8e0, 0x00004720, 0x00008e60, 0x00009c60, 0x0000d540, 0x0000c720,
-0x0000b8e0, 0x0000aac0, 0x00009c60, 0x0000b8e0, 0x0000aac0, 0x0000f1a0, 0x0000aac0,
-0x0000aac0, 0x00009c60, 0x00005540, 0x00005540, 0x00009580, 0x00008e60, 0x00008e60,
-0x00009c60, 0x00009c60, 0x00008e60, 0x00005540, 0x00009c60, 0x00009c60, 0x00004720,
-0x00004720, 0x00008e60, 0x00004720, 0x0000e3a0, 0x00009c60, 0x00009c60, 0x00009c60,
-0x00009c60, 0x000063a0, 0x00008e60, 0x00009c60, 0x00008e60, 0x0000c720, 0x00008e60,
-0x00008e60, 0x00008000
-};
-
-const int LiberationSanskBoldCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSanskBoldCharCodes);
-
-const SkPaint::FontMetrics LiberationSanskBoldMetrics = {
-0x2c663933, -1.0332f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.24609f, 4.07409e-11f,
--0.184082f, 1.06201f, 0.538086f, 6.66449e-1f, 0.10498f, 0.105957f
-};
-
-const SkScalar LiberationSanskItalicPoints[] = {
-0.518066f, 0, 0.481445f, -0.201172f, 0.169434f, -0.201172f, 0.0522461f, 0, -0.0493164f,
-0, 0.364746f, -0.687988f, 0.470703f, -0.687988f, 0.613281f, 0, 0.425293f, -0.504883f,
-0.421387f, -0.524902f, 0.417725f, -0.543945f, 0.414062f, -0.562988f, 0.411621f, -0.578857f,
-0.40918f, -0.594727f, 0.407471f, -0.605225f, 0.405762f, -0.615723f, 0.405273f, -0.617676f,
-0.404297f, -0.615723f, 0.398682f, -0.60498f, 0.393066f, -0.594238f, 0.384277f, -0.578369f,
-0.375488f, -0.5625f, 0.364746f, -0.543213f, 0.354004f, -0.523926f, 0.342285f, -0.504395f,
-0.210449f, -0.273926f, 0.467773f, -0.273926f, 0.498535f, 0, 0.560547f, -0.318848f,
-0.186035f, -0.318848f, 0.124023f, 0, 0.0307617f, 0, 0.164551f, -0.687988f, 0.257812f,
--0.687988f, 0.201172f, -0.396973f, 0.575684f, -0.396973f, 0.632324f, -0.687988f,
-0.723145f, -0.687988f, 0.589355f, 0, 0.418945f, -0.611816f, 0.299805f, 0, 0.207031f,
-0, 0.326172f, -0.611816f, 0.0898438f, -0.611816f, 0.104492f, -0.687988f, 0.669922f,
--0.687988f, 0.655273f, -0.611816f, 0.686523f, 0, 0.577637f, 0, 0.542969f, -0.437012f,
-0.54248f, -0.446289f, 0.541748f, -0.458008f, 0.541016f, -0.469727f, 0.540283f, -0.482666f,
-0.539551f, -0.495605f, 0.538818f, -0.509033f, 0.538086f, -0.522461f, 0.537598f, -0.534668f,
-0.536133f, -0.563965f, 0.535156f, -0.595215f, 0.523438f, -0.564453f, 0.51123f, -0.534668f,
-0.500977f, -0.509277f, 0.489502f, -0.482422f, 0.478027f, -0.455566f, 0.469238f, -0.437012f,
-0.264648f, 0, 0.155762f, 0, 0.0864258f, -0.687988f, 0.182617f, -0.687988f, 0.221191f,
--0.250977f, 0.223633f, -0.220215f, 0.225098f, -0.190186f, 0.226562f, -0.160156f,
-0.227539f, -0.135742f, 0.228516f, -0.107422f, 0.229004f, -0.0820312f, 0.243164f,
--0.115723f, 0.257324f, -0.148438f, 0.263184f, -0.162598f, 0.269775f, -0.17749f, 0.276367f,
--0.192383f, 0.282715f, -0.207031f, 0.289062f, -0.22168f, 0.295166f, -0.235107f, 0.30127f,
--0.248535f, 0.306641f, -0.259766f, 0.509277f, -0.687988f, 0.598633f, -0.687988f,
-0.635254f, -0.259766f, 0.63623f, -0.249023f, 0.637207f, -0.235352f, 0.638184f, -0.22168f,
-0.638916f, -0.207275f, 0.639648f, -0.192871f, 0.640381f, -0.177979f, 0.641113f, -0.163086f,
-0.641602f, -0.148926f, 0.643066f, -0.116211f, 0.643555f, -0.0820312f, 0.644043f,
--0.0820312f, 0.651123f, -0.098877f, 0.658203f, -0.115723f, 0.668945f, -0.141113f,
-0.679688f, -0.166504f, 0.692627f, -0.196045f, 0.705566f, -0.225586f, 0.717773f, -0.250977f,
-0.924316f, -0.687988f, 1.02246f, -0.687988f, 0.383301f, -0.285156f, 0.328125f, 0,
-0.235352f, 0, 0.291504f, -0.285156f, 0.104004f, -0.687988f, 0.199707f, -0.687988f,
-0.349121f, -0.358887f, 0.622559f, -0.687988f, 0.727051f, -0.687988f, 0.515137f, -0.00292969f,
-0.500977f, 0.000488281f, 0.484619f, 0.00268555f, 0.468262f, 0.00488281f, 0.452637f,
-0.00488281f, 0.407227f, 0.00488281f, 0.386475f, -0.013916f, 0.365723f, -0.0327148f,
-0.365723f, -0.0698242f, 0.365723f, -0.0771484f, 0.366699f, -0.0856934f, 0.367676f,
--0.0942383f, 0.368164f, -0.101074f, 0.365234f, -0.101074f, 0.348145f, -0.0751953f,
-0.329834f, -0.0546875f, 0.311523f, -0.0341797f, 0.289307f, -0.0197754f, 0.26709f,
--0.00537109f, 0.239746f, 0.00219727f, 0.212402f, 0.00976562f, 0.17627f, 0.00976562f,
-0.138184f, 0.00976562f, 0.109619f, -0.00244141f, 0.0810547f, -0.0146484f, 0.0615234f,
--0.0349121f, 0.0419922f, -0.0551758f, 0.0322266f, -0.081543f, 0.0224609f, -0.10791f,
-0.0224609f, -0.135742f, 0.0224609f, -0.175293f, 0.0339355f, -0.204102f, 0.0454102f,
--0.23291f, 0.0651855f, -0.253418f, 0.0849609f, -0.273926f, 0.111572f, -0.286865f,
-0.138184f, -0.299805f, 0.168213f, -0.307129f, 0.198242f, -0.314453f, 0.230469f, -0.317383f,
-0.262695f, -0.320312f, 0.293457f, -0.320801f, 0.406738f, -0.322266f, 0.410156f, -0.339844f,
-0.412598f, -0.352051f, 0.414307f, -0.363281f, 0.416016f, -0.374512f, 0.416016f, -0.384277f,
-0.416016f, -0.428711f, 0.390137f, -0.449951f, 0.364258f, -0.471191f, 0.318359f, -0.471191f,
-0.294434f, -0.471191f, 0.273682f, -0.467529f, 0.25293f, -0.463867f, 0.236572f, -0.454346f,
-0.220215f, -0.444824f, 0.207764f, -0.428467f, 0.195312f, -0.412109f, 0.1875f, -0.387207f,
-0.100586f, -0.401367f, 0.109863f, -0.431641f, 0.125977f, -0.456787f, 0.14209f, -0.481934f,
-0.168457f, -0.5f, 0.194824f, -0.518066f, 0.232666f, -0.528076f, 0.270508f, -0.538086f,
-0.323242f, -0.538086f, 0.366699f, -0.538086f, 0.400391f, -0.527344f, 0.434082f, -0.516602f,
-0.457031f, -0.497559f, 0.47998f, -0.478516f, 0.491943f, -0.452148f, 0.503906f, -0.425781f,
-0.503906f, -0.394043f, 0.503906f, -0.378906f, 0.501221f, -0.357666f, 0.498535f, -0.336426f,
-0.494629f, -0.317383f, 0.458496f, -0.132812f, 0.456055f, -0.12207f, 0.45459f, -0.11084f,
-0.453125f, -0.0996094f, 0.453125f, -0.0898438f, 0.453125f, -0.0717773f, 0.462646f,
--0.0629883f, 0.472168f, -0.0541992f, 0.492676f, -0.0541992f, 0.5f, -0.0541992f, 0.507568f,
--0.0551758f, 0.515137f, -0.0561523f, 0.521973f, -0.0576172f, 0.39502f, -0.261719f,
-0.297852f, -0.259766f, 0.27832f, -0.259277f, 0.257324f, -0.257812f, 0.236328f, -0.256348f,
-0.216064f, -0.251709f, 0.195801f, -0.24707f, 0.17749f, -0.239258f, 0.15918f, -0.231445f,
-0.145508f, -0.218018f, 0.131836f, -0.20459f, 0.123779f, -0.185547f, 0.115723f, -0.166504f,
-0.115723f, -0.139648f, 0.115723f, -0.124023f, 0.12085f, -0.109131f, 0.125977f, -0.0942383f,
-0.136719f, -0.0827637f, 0.147461f, -0.0712891f, 0.16333f, -0.064209f, 0.179199f,
--0.0571289f, 0.200684f, -0.0571289f, 0.243164f, -0.0571289f, 0.274902f, -0.0717773f,
-0.306641f, -0.0864258f, 0.329102f, -0.10791f, 0.351562f, -0.129395f, 0.364502f, -0.154541f,
-0.377441f, -0.179688f, 0.381836f, -0.200684f, 0.363281f, -0.538086f, 0.402344f, -0.538086f,
-0.432617f, -0.525879f, 0.462891f, -0.513672f, 0.483398f, -0.491211f, 0.503906f, -0.46875f,
-0.514648f, -0.436768f, 0.525391f, -0.404785f, 0.525391f, -0.365234f, 0.525391f, -0.34082f,
-0.523193f, -0.311768f, 0.520996f, -0.282715f, 0.515137f, -0.251953f, 0.501953f, -0.182617f,
-0.480469f, -0.133057f, 0.458984f, -0.0834961f, 0.428711f, -0.0517578f, 0.398438f,
--0.0200195f, 0.359375f, -0.00512695f, 0.320312f, 0.00976562f, 0.271973f, 0.00976562f,
-0.211914f, 0.00976562f, 0.174316f, -0.015625f, 0.136719f, -0.0410156f, 0.121094f,
--0.0869141f, 0.119629f, -0.0869141f, 0.117188f, -0.0742188f, 0.11377f, -0.0598145f,
-0.110352f, -0.0454102f, 0.107178f, -0.0327148f, 0.104004f, -0.0200195f, 0.101807f,
--0.0109863f, 0.0996094f, -0.00195312f, 0.0986328f, 0, 0.0141602f, 0, 0.015625f, -0.00439453f,
-0.0180664f, -0.0148926f, 0.0205078f, -0.0253906f, 0.0236816f, -0.0400391f, 0.0268555f,
--0.0546875f, 0.0307617f, -0.0722656f, 0.034668f, -0.0898438f, 0.0380859f, -0.108887f,
-0.157715f, -0.724609f, 0.245605f, -0.724609f, 0.205078f, -0.518066f, 0.202637f, -0.503906f,
-0.199463f, -0.491211f, 0.196289f, -0.478516f, 0.193848f, -0.469238f, 0.190918f, -0.458496f,
-0.188477f, -0.449707f, 0.19043f, -0.449707f, 0.208008f, -0.472656f, 0.226318f, -0.489258f,
-0.244629f, -0.505859f, 0.265381f, -0.516846f, 0.286133f, -0.527832f, 0.310059f, -0.532959f,
-0.333984f, -0.538086f, 0.363281f, -0.538086f, 0.337891f, -0.470215f, 0.306641f, -0.470215f,
-0.278564f, -0.460938f, 0.250488f, -0.45166f, 0.226562f, -0.428955f, 0.202637f, -0.40625f,
-0.184326f, -0.367676f, 0.166016f, -0.329102f, 0.154785f, -0.270508f, 0.145508f, -0.222656f,
-0.145508f, -0.184082f, 0.145508f, -0.152832f, 0.153809f, -0.128662f, 0.162109f, -0.104492f,
-0.17749f, -0.0881348f, 0.192871f, -0.0717773f, 0.2146f, -0.0634766f, 0.236328f, -0.0551758f,
-0.262695f, -0.0551758f, 0.292969f, -0.0551758f, 0.317383f, -0.064209f, 0.341797f,
--0.0732422f, 0.361572f, -0.095459f, 0.381348f, -0.117676f, 0.396484f, -0.155029f,
-0.411621f, -0.192383f, 0.422363f, -0.249023f, 0.433594f, -0.308105f, 0.433594f, -0.349609f,
-0.433594f, -0.409668f, 0.410645f, -0.439941f, 0.387695f, -0.470215f, 0.337891f, -0.470215f,
-0.125f, -0.245605f, 0.122559f, -0.231934f, 0.121826f, -0.218018f, 0.121094f, -0.204102f,
-0.120605f, -0.19043f, 0.120605f, -0.125488f, 0.153076f, -0.0908203f, 0.185547f, -0.0561523f,
-0.250977f, -0.0561523f, 0.27832f, -0.0561523f, 0.300781f, -0.0632324f, 0.323242f,
--0.0703125f, 0.341553f, -0.0822754f, 0.359863f, -0.0942383f, 0.373779f, -0.110107f,
-0.387695f, -0.125977f, 0.396973f, -0.143555f, 0.464355f, -0.112793f, 0.452148f, -0.0908203f,
-0.43457f, -0.0690918f, 0.416992f, -0.0473633f, 0.390869f, -0.0297852f, 0.364746f,
--0.012207f, 0.328125f, -0.0012207f, 0.291504f, 0.00976562f, 0.240723f, 0.00976562f,
-0.191895f, 0.00976562f, 0.15332f, -0.00415039f, 0.114746f, -0.0180664f, 0.0881348f,
--0.0446777f, 0.0615234f, -0.0712891f, 0.0476074f, -0.109863f, 0.0336914f, -0.148438f,
-0.0336914f, -0.197754f, 0.0336914f, -0.274902f, 0.0544434f, -0.337891f, 0.0751953f,
--0.400879f, 0.112061f, -0.445312f, 0.148926f, -0.489746f, 0.198975f, -0.513916f,
-0.249023f, -0.538086f, 0.307617f, -0.538086f, 0.361328f, -0.538086f, 0.400879f, -0.523926f,
-0.44043f, -0.509766f, 0.466797f, -0.484375f, 0.493164f, -0.458984f, 0.506104f, -0.423584f,
-0.519043f, -0.388184f, 0.519043f, -0.345703f, 0.519043f, -0.335449f, 0.518311f, -0.323242f,
-0.517578f, -0.311035f, 0.516113f, -0.297852f, 0.514648f, -0.284668f, 0.512451f, -0.27124f,
-0.510254f, -0.257812f, 0.507324f, -0.245605f, 0.429688f, -0.312988f, 0.430664f, -0.322754f,
-0.431152f, -0.331299f, 0.431641f, -0.339844f, 0.431641f, -0.348145f, 0.431641f, -0.380371f,
-0.422852f, -0.404053f, 0.414062f, -0.427734f, 0.397949f, -0.443115f, 0.381836f, -0.458496f,
-0.359375f, -0.46582f, 0.336914f, -0.473145f, 0.30957f, -0.473145f, 0.286133f, -0.473145f,
-0.260254f, -0.466064f, 0.234375f, -0.458984f, 0.210693f, -0.440918f, 0.187012f, -0.422852f,
-0.16748f, -0.391846f, 0.147949f, -0.36084f, 0.136719f, -0.312988f, 0.211914f, -0.464355f,
-0.121582f, 0, 0.0336914f, 0, 0.124023f, -0.464355f, 0.0498047f, -0.464355f, 0.0625f,
--0.52832f, 0.136719f, -0.52832f, 0.147949f, -0.587891f, 0.153809f, -0.616699f, 0.163086f,
--0.641602f, 0.172363f, -0.666504f, 0.189697f, -0.685059f, 0.207031f, -0.703613f,
-0.234375f, -0.714111f, 0.261719f, -0.724609f, 0.303711f, -0.724609f, 0.319336f, -0.724609f,
-0.335693f, -0.723145f, 0.352051f, -0.72168f, 0.364258f, -0.71875f, 0.351562f, -0.651855f,
-0.347168f, -0.652832f, 0.341553f, -0.65332f, 0.335938f, -0.653809f, 0.32959f, -0.654541f,
-0.323242f, -0.655273f, 0.317383f, -0.655518f, 0.311523f, -0.655762f, 0.307129f, -0.655762f,
-0.288574f, -0.655762f, 0.276123f, -0.650391f, 0.263672f, -0.64502f, 0.255615f, -0.634766f,
-0.247559f, -0.624512f, 0.242676f, -0.609619f, 0.237793f, -0.594727f, 0.233887f, -0.575684f,
-0.224609f, -0.52832f, 0.327637f, -0.52832f, 0.314941f, -0.464355f, 0.193848f, 0.20752f,
-0.148438f, 0.20752f, 0.114746f, 0.198486f, 0.0810547f, 0.189453f, 0.0578613f, 0.17334f,
-0.034668f, 0.157227f, 0.0212402f, 0.134521f, 0.0078125f, 0.111816f, 0.00195312f,
-0.0844727f, 0.081543f, 0.0639648f, 0.0898438f, 0.101074f, 0.118408f, 0.12085f, 0.146973f,
-0.140625f, 0.195801f, 0.140625f, 0.230957f, 0.140625f, 0.257812f, 0.131592f, 0.284668f,
-0.122559f, 0.303955f, 0.104004f, 0.323242f, 0.0854492f, 0.336182f, 0.0563965f, 0.349121f,
-0.0273438f, 0.356934f, -0.0131836f, 0.359375f, -0.0258789f, 0.362305f, -0.0405273f,
-0.365234f, -0.0551758f, 0.367676f, -0.0678711f, 0.370605f, -0.0830078f, 0.373535f,
--0.0981445f, 0.372559f, -0.0981445f, 0.358887f, -0.0786133f, 0.343506f, -0.0600586f,
-0.328125f, -0.0415039f, 0.308105f, -0.0273438f, 0.288086f, -0.0131836f, 0.261719f,
--0.00463867f, 0.235352f, 0.00390625f, 0.200195f, 0.00390625f, 0.161621f, 0.00390625f,
-0.130859f, -0.00952148f, 0.100098f, -0.0229492f, 0.0786133f, -0.0466309f, 0.0571289f,
--0.0703125f, 0.0456543f, -0.103271f, 0.0341797f, -0.13623f, 0.0341797f, -0.175293f,
-0.0341797f, -0.199219f, 0.0368652f, -0.22583f, 0.0395508f, -0.252441f, 0.0454102f,
--0.283203f, 0.0698242f, -0.410645f, 0.128174f, -0.474121f, 0.186523f, -0.537598f,
-0.287109f, -0.537598f, 0.314941f, -0.537598f, 0.339844f, -0.531006f, 0.364746f, -0.524414f,
-0.384521f, -0.511475f, 0.404297f, -0.498535f, 0.418701f, -0.47998f, 0.433105f, -0.461426f,
-0.439453f, -0.437988f, 0.44043f, -0.437988f, 0.442871f, -0.450195f, 0.446533f, -0.465332f,
-0.450195f, -0.480469f, 0.453613f, -0.493896f, 0.457031f, -0.507324f, 0.459961f, -0.51709f,
-0.462891f, -0.526855f, 0.463867f, -0.52832f, 0.547363f, -0.52832f, 0.546387f, -0.523926f,
-0.543945f, -0.513428f, 0.541504f, -0.50293f, 0.538086f, -0.488281f, 0.534668f, -0.473633f,
-0.531006f, -0.455811f, 0.527344f, -0.437988f, 0.523438f, -0.418945f, 0.444824f, -0.0151367f,
-0.43457f, 0.0371094f, 0.416504f, 0.0783691f, 0.398438f, 0.119629f, 0.368652f, 0.148438f,
-0.338867f, 0.177246f, 0.296143f, 0.192383f, 0.253418f, 0.20752f, 0.193848f, 0.20752f,
-0.126465f, -0.182129f, 0.126465f, -0.123047f, 0.1521f, -0.092041f, 0.177734f, -0.0610352f,
-0.227539f, -0.0610352f, 0.253906f, -0.0610352f, 0.281006f, -0.0722656f, 0.308105f,
--0.0834961f, 0.332275f, -0.10791f, 0.356445f, -0.132324f, 0.375732f, -0.170898f,
-0.39502f, -0.209473f, 0.405762f, -0.26416f, 0.409668f, -0.284668f, 0.411621f, -0.306396f,
-0.413574f, -0.328125f, 0.413574f, -0.34375f, 0.413574f, -0.376465f, 0.404785f, -0.400635f,
-0.395996f, -0.424805f, 0.380127f, -0.440918f, 0.364258f, -0.457031f, 0.342773f, -0.464844f,
-0.321289f, -0.472656f, 0.296387f, -0.472656f, 0.266113f, -0.472656f, 0.241455f, -0.463623f,
-0.216797f, -0.45459f, 0.197266f, -0.432861f, 0.177734f, -0.411133f, 0.163086f, -0.374756f,
-0.148438f, -0.338379f, 0.137695f, -0.283203f, 0.132324f, -0.254395f, 0.129395f, -0.228027f,
-0.126465f, -0.20166f, 0.126465f, -0.182129f, 0.322266f, 0, 0.382812f, -0.30957f,
-0.384766f, -0.319336f, 0.386963f, -0.331055f, 0.38916f, -0.342773f, 0.390869f, -0.354492f,
-0.392578f, -0.366211f, 0.393799f, -0.376709f, 0.39502f, -0.387207f, 0.39502f, -0.394531f,
-0.39502f, -0.431152f, 0.376465f, -0.450439f, 0.35791f, -0.469727f, 0.315918f, -0.469727f,
-0.288086f, -0.469727f, 0.262939f, -0.457275f, 0.237793f, -0.444824f, 0.217773f, -0.422119f,
-0.197754f, -0.399414f, 0.183105f, -0.366943f, 0.168457f, -0.334473f, 0.161621f, -0.294922f,
-0.104004f, 0, 0.0166016f, 0, 0.0976562f, -0.415527f, 0.101074f, -0.432129f, 0.104248f,
--0.450439f, 0.107422f, -0.46875f, 0.110107f, -0.485107f, 0.112793f, -0.501465f, 0.114502f,
--0.513184f, 0.116211f, -0.524902f, 0.116699f, -0.52832f, 0.199707f, -0.52832f, 0.199707f,
--0.525879f, 0.198242f, -0.515137f, 0.196777f, -0.504395f, 0.19458f, -0.490479f, 0.192383f,
--0.476562f, 0.190186f, -0.462158f, 0.187988f, -0.447754f, 0.186035f, -0.437988f,
-0.1875f, -0.437988f, 0.202148f, -0.460938f, 0.217773f, -0.479492f, 0.233398f, -0.498047f,
-0.251953f, -0.510986f, 0.270508f, -0.523926f, 0.293213f, -0.530762f, 0.315918f, -0.537598f,
-0.344727f, -0.537598f, 0.403809f, -0.537598f, 0.438477f, -0.508545f, 0.473145f, -0.479492f,
-0.47998f, -0.424316f, 0.495605f, -0.44873f, 0.512207f, -0.469238f, 0.528809f, -0.489746f,
-0.549072f, -0.505127f, 0.569336f, -0.520508f, 0.593994f, -0.529053f, 0.618652f, -0.537598f,
-0.649902f, -0.537598f, 0.71582f, -0.537598f, 0.751221f, -0.501953f, 0.786621f, -0.466309f,
-0.786621f, -0.398926f, 0.786621f, -0.381348f, 0.783447f, -0.359375f, 0.780273f, -0.337402f,
-0.776367f, -0.318848f, 0.714355f, 0, 0.627441f, 0, 0.687988f, -0.30957f, 0.689941f,
--0.319336f, 0.692139f, -0.331055f, 0.694336f, -0.342773f, 0.696045f, -0.354492f,
-0.697754f, -0.366211f, 0.698975f, -0.376709f, 0.700195f, -0.387207f, 0.700195f, -0.394531f,
-0.700195f, -0.431152f, 0.681641f, -0.450439f, 0.663086f, -0.469727f, 0.621094f, -0.469727f,
-0.593262f, -0.469727f, 0.568115f, -0.45752f, 0.542969f, -0.445312f, 0.522949f, -0.422852f,
-0.50293f, -0.400391f, 0.488281f, -0.368164f, 0.473633f, -0.335938f, 0.466797f, -0.296387f,
-0.40918f, 0, 0.350098f, 0, 0.411621f, -0.314941f, 0.415527f, -0.333984f, 0.417969f,
--0.35376f, 0.42041f, -0.373535f, 0.42041f, -0.388184f, 0.42041f, -0.426758f, 0.399902f,
--0.448242f, 0.379395f, -0.469727f, 0.333008f, -0.469727f, 0.301758f, -0.469727f,
-0.27417f, -0.457275f, 0.246582f, -0.444824f, 0.224121f, -0.422119f, 0.20166f, -0.399414f,
-0.185791f, -0.367432f, 0.169922f, -0.335449f, 0.162109f, -0.295898f, 0.104492f, 0,
-0.0166016f, 0, 0.0976562f, -0.415527f, 0.101074f, -0.432129f, 0.104248f, -0.450439f,
-0.107422f, -0.46875f, 0.110107f, -0.485107f, 0.112793f, -0.501465f, 0.114502f, -0.513184f,
-0.116211f, -0.524902f, 0.116699f, -0.52832f, 0.199707f, -0.52832f, 0.199707f, -0.525879f,
-0.198242f, -0.515137f, 0.196777f, -0.504395f, 0.19458f, -0.490479f, 0.192383f, -0.476562f,
-0.190186f, -0.462158f, 0.187988f, -0.447754f, 0.186035f, -0.437988f, 0.1875f, -0.437988f,
-0.204102f, -0.460938f, 0.22168f, -0.479492f, 0.239258f, -0.498047f, 0.260498f, -0.510986f,
-0.281738f, -0.523926f, 0.307373f, -0.530762f, 0.333008f, -0.537598f, 0.365723f, -0.537598f,
-0.437988f, -0.537598f, 0.474365f, -0.501953f, 0.510742f, -0.466309f, 0.510742f, -0.398926f,
-0.510742f, -0.381348f, 0.507568f, -0.359375f, 0.504395f, -0.337402f, 0.500488f, -0.318848f,
-0.438477f, 0, 0.524414f, -0.333496f, 0.524414f, -0.308105f, 0.521484f, -0.282471f,
-0.518555f, -0.256836f, 0.511719f, -0.228027f, 0.49707f, -0.163574f, 0.470947f, -0.118164f,
-0.444824f, -0.0727539f, 0.409668f, -0.0444336f, 0.374512f, -0.0161133f, 0.331543f,
--0.00317383f, 0.288574f, 0.00976562f, 0.239746f, 0.00976562f, 0.192871f, 0.00976562f,
-0.154785f, -0.00463867f, 0.116699f, -0.019043f, 0.0895996f, -0.0466309f, 0.0625f,
--0.0742188f, 0.0476074f, -0.114014f, 0.0327148f, -0.153809f, 0.0327148f, -0.20459f,
-0.0332031f, -0.227539f, 0.0354004f, -0.251953f, 0.0375977f, -0.276367f, 0.043457f,
--0.302734f, 0.0576172f, -0.364258f, 0.0825195f, -0.408447f, 0.107422f, -0.452637f,
-0.141602f, -0.481445f, 0.175781f, -0.510254f, 0.218994f, -0.523926f, 0.262207f, -0.537598f,
-0.313477f, -0.537598f, 0.365234f, -0.537598f, 0.404541f, -0.523926f, 0.443848f, -0.510254f,
-0.470459f, -0.483887f, 0.49707f, -0.45752f, 0.510742f, -0.419678f, 0.524414f, -0.381836f,
-0.524414f, -0.333496f, 0.433594f, -0.333496f, 0.433594f, -0.371094f, 0.425293f, -0.397461f,
-0.416992f, -0.423828f, 0.401123f, -0.440674f, 0.385254f, -0.45752f, 0.362793f, -0.465332f,
-0.340332f, -0.473145f, 0.3125f, -0.473145f, 0.286621f, -0.473145f, 0.260498f, -0.467041f,
-0.234375f, -0.460938f, 0.210693f, -0.442383f, 0.187012f, -0.423828f, 0.16748f, -0.389648f,
-0.147949f, -0.355469f, 0.134766f, -0.298828f, 0.128418f, -0.271973f, 0.125732f, -0.247803f,
-0.123047f, -0.223633f, 0.123047f, -0.203125f, 0.123047f, -0.163086f, 0.132324f, -0.134766f,
-0.141602f, -0.106445f, 0.157959f, -0.0888672f, 0.174316f, -0.0712891f, 0.196533f,
--0.0632324f, 0.21875f, -0.0551758f, 0.245117f, -0.0551758f, 0.271484f, -0.0551758f,
-0.297119f, -0.0610352f, 0.322754f, -0.0668945f, 0.345703f, -0.0856934f, 0.368652f,
--0.104492f, 0.387939f, -0.13916f, 0.407227f, -0.173828f, 0.42041f, -0.230957f, 0.427246f,
--0.260254f, 0.429932f, -0.284668f, 0.432617f, -0.309082f, 0.433594f, -0.333496f,
-0.270508f, 0.00976562f, 0.210449f, 0.00976562f, 0.172607f, -0.015625f, 0.134766f,
--0.0410156f, 0.119141f, -0.0869141f, 0.116699f, -0.0869141f, 0.116699f, -0.0859375f,
-0.115723f, -0.0773926f, 0.114746f, -0.0688477f, 0.112793f, -0.0561523f, 0.11084f,
--0.043457f, 0.108154f, -0.0283203f, 0.105469f, -0.0131836f, 0.102539f, 0.000976562f,
-0.0625f, 0.20752f, -0.0249023f, 0.20752f, 0.0966797f, -0.42041f, 0.100586f, -0.439453f,
-0.103516f, -0.457031f, 0.106445f, -0.474609f, 0.108643f, -0.489014f, 0.11084f, -0.503418f,
-0.112061f, -0.513672f, 0.113281f, -0.523926f, 0.11377f, -0.52832f, 0.195312f, -0.52832f,
-0.195312f, -0.524414f, 0.194824f, -0.515625f, 0.194336f, -0.506836f, 0.193115f, -0.49585f,
-0.191895f, -0.484863f, 0.19043f, -0.472656f, 0.188965f, -0.460449f, 0.187012f, -0.449707f,
-0.188965f, -0.449707f, 0.206543f, -0.472656f, 0.224854f, -0.489258f, 0.243164f, -0.505859f,
-0.263916f, -0.516846f, 0.284668f, -0.527832f, 0.308594f, -0.532959f, 0.33252f, -0.538086f,
-0.361816f, -0.538086f, 0.400879f, -0.538086f, 0.431152f, -0.525879f, 0.461426f, -0.513672f,
-0.481934f, -0.491211f, 0.502441f, -0.46875f, 0.513184f, -0.436768f, 0.523926f, -0.404785f,
-0.523926f, -0.365234f, 0.523926f, -0.34082f, 0.521729f, -0.311768f, 0.519531f, -0.282715f,
-0.513672f, -0.251953f, 0.500488f, -0.182617f, 0.479004f, -0.133057f, 0.45752f, -0.0834961f,
-0.427246f, -0.0517578f, 0.396973f, -0.0200195f, 0.35791f, -0.00512695f, 0.318848f,
-0.00976562f, 0.270508f, 0.00976562f, 0.336426f, -0.470215f, 0.305176f, -0.470215f,
-0.2771f, -0.460938f, 0.249023f, -0.45166f, 0.225098f, -0.428955f, 0.201172f, -0.40625f,
-0.182861f, -0.367676f, 0.164551f, -0.329102f, 0.15332f, -0.270508f, 0.144043f, -0.222656f,
-0.144043f, -0.184082f, 0.144043f, -0.152832f, 0.152344f, -0.128662f, 0.160645f, -0.104492f,
-0.176025f, -0.0881348f, 0.191406f, -0.0717773f, 0.213135f, -0.0634766f, 0.234863f,
--0.0551758f, 0.26123f, -0.0551758f, 0.291504f, -0.0551758f, 0.315918f, -0.064209f,
-0.340332f, -0.0732422f, 0.360107f, -0.095459f, 0.379883f, -0.117676f, 0.39502f, -0.155029f,
-0.410156f, -0.192383f, 0.420898f, -0.249023f, 0.432129f, -0.308105f, 0.432129f, -0.349609f,
-0.432129f, -0.409668f, 0.40918f, -0.439941f, 0.38623f, -0.470215f, 0.336426f, -0.470215f,
-0.350586f, -0.458008f, 0.342285f, -0.460449f, 0.330811f, -0.462402f, 0.319336f, -0.464355f,
-0.306641f, -0.464355f, 0.275391f, -0.464355f, 0.250488f, -0.446289f, 0.225586f, -0.428223f,
-0.206787f, -0.400391f, 0.187988f, -0.372559f, 0.175781f, -0.339111f, 0.163574f, -0.305664f,
-0.158203f, -0.275391f, 0.104492f, 0, 0.0166016f, 0, 0.0957031f, -0.405273f, 0.0991211f,
--0.422363f, 0.102051f, -0.439453f, 0.10498f, -0.456543f, 0.107666f, -0.472656f, 0.110352f,
--0.48877f, 0.112793f, -0.503174f, 0.115234f, -0.517578f, 0.116699f, -0.52832f, 0.199707f,
--0.52832f, 0.198242f, -0.517578f, 0.196045f, -0.50293f, 0.193848f, -0.488281f, 0.191406f,
--0.473145f, 0.188965f, -0.458008f, 0.186768f, -0.444092f, 0.18457f, -0.430176f, 0.182617f,
--0.42041f, 0.18457f, -0.42041f, 0.199707f, -0.450684f, 0.2146f, -0.4729f, 0.229492f,
--0.495117f, 0.245605f, -0.509521f, 0.261719f, -0.523926f, 0.280029f, -0.531006f,
-0.29834f, -0.538086f, 0.320312f, -0.538086f, 0.325684f, -0.538086f, 0.332031f, -0.537354f,
-0.338379f, -0.536621f, 0.344971f, -0.535645f, 0.351562f, -0.534668f, 0.357422f, -0.533447f,
-0.363281f, -0.532227f, 0.366699f, -0.53125f, 0.442871f, -0.154785f, 0.442871f, -0.113281f,
-0.42627f, -0.0822754f, 0.409668f, -0.0512695f, 0.37915f, -0.0307617f, 0.348633f,
--0.0102539f, 0.305176f, -0.000244141f, 0.261719f, 0.00976562f, 0.20752f, 0.00976562f,
-0.162109f, 0.00976562f, 0.12793f, 0.00195312f, 0.09375f, -0.00585938f, 0.0690918f,
--0.020752f, 0.0444336f, -0.0356445f, 0.0280762f, -0.0578613f, 0.0117188f, -0.0800781f,
-0.00244141f, -0.108887f, 0.0742188f, -0.13623f, 0.081543f, -0.116699f, 0.0930176f,
--0.101318f, 0.104492f, -0.0859375f, 0.121338f, -0.0754395f, 0.138184f, -0.0649414f,
-0.161377f, -0.0595703f, 0.18457f, -0.0541992f, 0.215332f, -0.0541992f, 0.246582f,
--0.0541992f, 0.272705f, -0.0593262f, 0.298828f, -0.0644531f, 0.317627f, -0.0756836f,
-0.336426f, -0.0869141f, 0.346924f, -0.104492f, 0.357422f, -0.12207f, 0.357422f, -0.146973f,
-0.357422f, -0.166504f, 0.348145f, -0.18042f, 0.338867f, -0.194336f, 0.322021f, -0.204834f,
-0.305176f, -0.215332f, 0.281006f, -0.224365f, 0.256836f, -0.233398f, 0.227051f, -0.242676f,
-0.195312f, -0.25293f, 0.166748f, -0.265137f, 0.138184f, -0.277344f, 0.116455f, -0.294434f,
-0.0947266f, -0.311523f, 0.0817871f, -0.334717f, 0.0688477f, -0.35791f, 0.0688477f,
--0.38916f, 0.0688477f, -0.429199f, 0.0861816f, -0.457275f, 0.103516f, -0.485352f,
-0.133057f, -0.50293f, 0.162598f, -0.520508f, 0.201904f, -0.528564f, 0.241211f, -0.536621f,
-0.285156f, -0.536621f, 0.325195f, -0.536621f, 0.358398f, -0.529785f, 0.391602f, -0.522949f,
-0.416504f, -0.508057f, 0.441406f, -0.493164f, 0.45752f, -0.469482f, 0.473633f, -0.445801f,
-0.479492f, -0.412109f, 0.399902f, -0.399902f, 0.38916f, -0.438477f, 0.359375f, -0.455566f,
-0.32959f, -0.472656f, 0.279297f, -0.472656f, 0.253418f, -0.472656f, 0.230713f, -0.46875f,
-0.208008f, -0.464844f, 0.190918f, -0.456055f, 0.173828f, -0.447266f, 0.163818f, -0.433105f,
-0.153809f, -0.418945f, 0.153809f, -0.398926f, 0.153809f, -0.378906f, 0.163086f, -0.365479f,
-0.172363f, -0.352051f, 0.189209f, -0.341797f, 0.206055f, -0.331543f, 0.229736f, -0.323486f,
-0.253418f, -0.31543f, 0.282715f, -0.306152f, 0.310547f, -0.297363f, 0.339111f, -0.285645f,
-0.367676f, -0.273926f, 0.390625f, -0.256592f, 0.413574f, -0.239258f, 0.428223f, -0.2146f,
-0.442871f, -0.189941f, 0.442871f, -0.154785f, 0.202637f, -0.52832f, 0.141113f, -0.213379f,
-0.137207f, -0.194336f, 0.134766f, -0.174561f, 0.132324f, -0.154785f, 0.132324f, -0.140137f,
-0.132324f, -0.101562f, 0.152832f, -0.0800781f, 0.17334f, -0.0585938f, 0.219727f,
--0.0585938f, 0.250977f, -0.0585938f, 0.278564f, -0.0710449f, 0.306152f, -0.0834961f,
-0.328613f, -0.106201f, 0.351074f, -0.128906f, 0.366943f, -0.160889f, 0.382812f, -0.192871f,
-0.390625f, -0.232422f, 0.448242f, -0.52832f, 0.536133f, -0.52832f, 0.455078f, -0.112793f,
-0.45166f, -0.0961914f, 0.448486f, -0.0778809f, 0.445312f, -0.0595703f, 0.442627f,
--0.0432129f, 0.439941f, -0.0268555f, 0.438232f, -0.0151367f, 0.436523f, -0.00341797f,
-0.436035f, 0, 0.353027f, 0, 0.353027f, -0.00244141f, 0.354492f, -0.0131836f, 0.355957f,
--0.0239258f, 0.358154f, -0.0378418f, 0.360352f, -0.0517578f, 0.362549f, -0.0661621f,
-0.364746f, -0.0805664f, 0.366699f, -0.090332f, 0.365234f, -0.090332f, 0.348633f,
--0.0673828f, 0.331055f, -0.0488281f, 0.313477f, -0.0302734f, 0.292236f, -0.017334f,
-0.270996f, -0.00439453f, 0.245361f, 0.00244141f, 0.219727f, 0.00927734f, 0.187012f,
-0.00927734f, 0.114746f, 0.00927734f, 0.0783691f, -0.0263672f, 0.0419922f, -0.0620117f,
-0.0419922f, -0.129395f, 0.0419922f, -0.146973f, 0.045166f, -0.168945f, 0.0483398f,
--0.190918f, 0.0522461f, -0.209473f, 0.114258f, -0.52832f, 0.244629f, 0, 0.217773f,
-0.0463867f, 0.192871f, 0.0844727f, 0.167969f, 0.122559f, 0.140625f, 0.149902f, 0.113281f,
-0.177246f, 0.0812988f, 0.192383f, 0.0493164f, 0.20752f, 0.0078125f, 0.20752f, -0.00830078f,
-0.20752f, -0.0251465f, 0.205811f, -0.0419922f, 0.204102f, -0.0566406f, 0.200684f,
--0.0415039f, 0.135254f, -0.0332031f, 0.136719f, -0.0227051f, 0.137939f, -0.012207f,
-0.13916f, -0.00390625f, 0.13916f, 0.0424805f, 0.13916f, 0.0778809f, 0.10791f, 0.113281f,
-0.0766602f, 0.147461f, 0.0170898f, 0.160645f, -0.00585938f, 0.0546875f, -0.52832f,
-0.144043f, -0.52832f, 0.19873f, -0.236328f, 0.20166f, -0.220703f, 0.205078f, -0.200195f,
-0.208496f, -0.179688f, 0.211426f, -0.159424f, 0.214355f, -0.13916f, 0.216553f, -0.121826f,
-0.21875f, -0.104492f, 0.219238f, -0.0957031f, 0.224121f, -0.106445f, 0.231934f, -0.121826f,
-0.239746f, -0.137207f, 0.249268f, -0.154541f, 0.258789f, -0.171875f, 0.268799f, -0.190186f,
-0.278809f, -0.208496f, 0.288086f, -0.225586f, 0.453125f, -0.52832f, 0.550293f, -0.52832f
-};
-
-const unsigned char LiberationSanskItalicVerbs[] = {
-6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1,
-1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6
-};
-
-const unsigned LiberationSanskItalicCharCodes[] = {
-32, 65, 72, 84, 87, 89, 97,
-98, 101, 102, 103, 109, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed LiberationSanskItalicWidths[] = {
-0x00004720, 0x0000aac0, 0x0000b8e0, 0x00009c60, 0x0000f1a0, 0x0000aac0, 0x00008e60,
-0x00008e60, 0x00008e60, 0x00004720, 0x00008e60, 0x0000d540, 0x00008e60, 0x00008e60,
-0x00008e60, 0x00005540, 0x00008000, 0x00008e60, 0x00008000
-};
-
-const int LiberationSanskItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSanskItalicCharCodes);
-
-const SkPaint::FontMetrics LiberationSanskItalicMetrics = {
-0x00000003, -1.01416f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.33447f, 0,
--0.271973f, 1.0625f, 0.537598f, 0, 0.0732422f, 0.105957f
-};
-
-const SkScalar LiberationSanskBoldItalicPoints[] = {
-0.206543f, -0.208008f, 0.0942383f, -0.208008f, 0.172363f, -0.687988f, 0.315918f, -0.687988f,
-0.0385742f, 0, 0.0639648f, -0.131836f, 0.20459f, -0.131836f, 0.179199f, 0, 0.169434f,
--0.0322266f, 0.163086f, 0.000488281f, 0.154297f, 0.0273438f, 0.145508f, 0.0541992f,
-0.134277f, 0.0769043f, 0.123047f, 0.0996094f, 0.109619f, 0.118652f, 0.0961914f, 0.137695f,
-0.0805664f, 0.154785f, -0.00976562f, 0.154785f, 0.00732422f, 0.137695f, 0.0229492f,
-0.118652f, 0.0385742f, 0.0996094f, 0.0512695f, 0.0795898f, 0.0639648f, 0.0595703f,
-0.0727539f, 0.0395508f, 0.081543f, 0.0195312f, 0.0854492f, 0, 0.0224609f, 0, 0.0512695f,
--0.148926f, 0.192383f, -0.148926f, 0.0273438f, -0.199707f, 0.050293f, -0.318848f,
-0.304199f, -0.318848f, 0.28125f, -0.199707f, 0.0224609f, 0, 0.0512695f, -0.148926f,
-0.192383f, -0.148926f, 0.163574f, 0, -0.0371094f, 0.0200195f, 0.249512f, -0.724609f,
-0.365723f, -0.724609f, 0.0810547f, 0.0200195f, 0.353516f, -0.698242f, 0.394043f,
--0.698242f, 0.429199f, -0.687256f, 0.464355f, -0.67627f, 0.490234f, -0.649902f, 0.516113f,
--0.623535f, 0.53125f, -0.579834f, 0.546387f, -0.536133f, 0.546387f, -0.470703f, 0.546387f,
--0.439941f, 0.541748f, -0.404785f, 0.537109f, -0.369629f, 0.527832f, -0.324707f,
-0.51416f, -0.259766f, 0.495605f, -0.209473f, 0.477051f, -0.15918f, 0.454346f, -0.12207f,
-0.431641f, -0.0849609f, 0.405762f, -0.0598145f, 0.379883f, -0.034668f, 0.351562f,
--0.019043f, 0.323242f, -0.00341797f, 0.293457f, 0.00317383f, 0.263672f, 0.00976562f,
-0.233398f, 0.00976562f, 0.1875f, 0.00976562f, 0.151855f, -0.00317383f, 0.116211f,
--0.0161133f, 0.0915527f, -0.0441895f, 0.0668945f, -0.0722656f, 0.0541992f, -0.116211f,
-0.0415039f, -0.160156f, 0.0415039f, -0.22168f, 0.0415039f, -0.251465f, 0.0456543f,
--0.285645f, 0.0498047f, -0.319824f, 0.0581055f, -0.364258f, 0.0712891f, -0.433105f,
-0.090332f, -0.484863f, 0.109375f, -0.536621f, 0.132568f, -0.57373f, 0.155762f, -0.61084f,
-0.182373f, -0.63501f, 0.208984f, -0.65918f, 0.237305f, -0.673096f, 0.265625f, -0.687012f,
-0.295166f, -0.692627f, 0.324707f, -0.698242f, 0.353516f, -0.698242f, 0.242676f, -0.0981445f,
-0.269531f, -0.0981445f, 0.291748f, -0.109619f, 0.313965f, -0.121094f, 0.33252f, -0.148438f,
-0.351074f, -0.175781f, 0.366211f, -0.221191f, 0.381348f, -0.266602f, 0.393555f, -0.334473f,
-0.401855f, -0.380371f, 0.407471f, -0.414307f, 0.413086f, -0.448242f, 0.413086f, -0.477051f,
-0.413086f, -0.530762f, 0.395264f, -0.560791f, 0.377441f, -0.59082f, 0.338867f, -0.59082f,
-0.30957f, -0.59082f, 0.287598f, -0.579346f, 0.265625f, -0.567871f, 0.248535f, -0.540771f,
-0.231445f, -0.513672f, 0.218262f, -0.468262f, 0.205078f, -0.422852f, 0.193359f, -0.354492f,
-0.186035f, -0.312012f, 0.18042f, -0.271729f, 0.174805f, -0.231445f, 0.174805f, -0.202637f,
-0.174805f, -0.180664f, 0.177979f, -0.161377f, 0.181152f, -0.14209f, 0.188965f, -0.128174f,
-0.196777f, -0.114258f, 0.209961f, -0.106201f, 0.223145f, -0.0981445f, 0.242676f,
--0.0981445f, 0.0161133f, 0, 0.0371094f, -0.112793f, 0.20752f, -0.112793f, 0.294922f,
--0.5625f, 0.108887f, -0.458008f, 0.131836f, -0.576172f, 0.325195f, -0.687988f, 0.457031f,
--0.687988f, 0.344727f, -0.112793f, 0.502441f, -0.112793f, 0.480957f, 0, -0.015625f,
-0, 0.00244141f, -0.0952148f, 0.0258789f, -0.135742f, 0.0556641f, -0.169189f, 0.0854492f,
--0.202637f, 0.118164f, -0.230957f, 0.150879f, -0.259277f, 0.184814f, -0.283691f,
-0.21875f, -0.308105f, 0.250732f, -0.330566f, 0.282715f, -0.353027f, 0.310791f, -0.374268f,
-0.338867f, -0.395508f, 0.359619f, -0.418213f, 0.380371f, -0.440918f, 0.392578f, -0.465576f,
-0.404785f, -0.490234f, 0.404785f, -0.519043f, 0.404785f, -0.538574f, 0.398926f, -0.552002f,
-0.393066f, -0.56543f, 0.382568f, -0.573486f, 0.37207f, -0.581543f, 0.357422f, -0.585205f,
-0.342773f, -0.588867f, 0.325684f, -0.588867f, 0.306641f, -0.588867f, 0.290039f, -0.584473f,
-0.273438f, -0.580078f, 0.259521f, -0.569824f, 0.245605f, -0.55957f, 0.234863f, -0.542236f,
-0.224121f, -0.524902f, 0.216797f, -0.499023f, 0.0869141f, -0.527832f, 0.0986328f,
--0.567383f, 0.118652f, -0.598877f, 0.138672f, -0.630371f, 0.168945f, -0.652344f,
-0.199219f, -0.674316f, 0.240479f, -0.686279f, 0.281738f, -0.698242f, 0.335449f, -0.698242f,
-0.390625f, -0.698242f, 0.430176f, -0.686279f, 0.469727f, -0.674316f, 0.495605f, -0.652344f,
-0.521484f, -0.630371f, 0.533691f, -0.599121f, 0.545898f, -0.567871f, 0.545898f, -0.528809f,
-0.545898f, -0.490723f, 0.533691f, -0.458496f, 0.521484f, -0.42627f, 0.500488f, -0.398438f,
-0.479492f, -0.370605f, 0.451904f, -0.346191f, 0.424316f, -0.321777f, 0.393311f, -0.299316f,
-0.362305f, -0.276855f, 0.330078f, -0.255127f, 0.297852f, -0.233398f, 0.267822f, -0.210938f,
-0.237793f, -0.188477f, 0.211914f, -0.164307f, 0.186035f, -0.140137f, 0.16748f, -0.112793f,
-0.486816f, -0.112793f, 0.465332f, 0, 0.26123f, -0.404785f, 0.28418f, -0.404785f,
-0.309814f, -0.408691f, 0.335449f, -0.412598f, 0.356689f, -0.424316f, 0.37793f, -0.436035f,
-0.391846f, -0.457275f, 0.405762f, -0.478516f, 0.405762f, -0.513184f, 0.405762f, -0.54834f,
-0.386963f, -0.568604f, 0.368164f, -0.588867f, 0.329102f, -0.588867f, 0.284668f, -0.588867f,
-0.255371f, -0.566895f, 0.226074f, -0.544922f, 0.213379f, -0.499023f, 0.0830078f,
--0.524414f, 0.0961914f, -0.570312f, 0.119141f, -0.603271f, 0.14209f, -0.63623f, 0.173828f,
--0.657227f, 0.205566f, -0.678223f, 0.24585f, -0.688232f, 0.286133f, -0.698242f, 0.334473f,
--0.698242f, 0.384277f, -0.698242f, 0.42334f, -0.686768f, 0.462402f, -0.675293f, 0.489502f,
--0.653564f, 0.516602f, -0.631836f, 0.530762f, -0.60083f, 0.544922f, -0.569824f, 0.544922f,
--0.530273f, 0.544922f, -0.493164f, 0.533203f, -0.462402f, 0.521484f, -0.431641f,
-0.498779f, -0.408936f, 0.476074f, -0.38623f, 0.443359f, -0.37207f, 0.410645f, -0.35791f,
-0.368652f, -0.354004f, 0.368164f, -0.352051f, 0.398926f, -0.347168f, 0.423828f, -0.335693f,
-0.44873f, -0.324219f, 0.466309f, -0.305664f, 0.483887f, -0.287109f, 0.493408f, -0.261719f,
-0.50293f, -0.236328f, 0.50293f, -0.204102f, 0.50293f, -0.161621f, 0.486328f, -0.122803f,
-0.469727f, -0.0839844f, 0.437744f, -0.0544434f, 0.405762f, -0.0249023f, 0.358398f,
--0.00756836f, 0.311035f, 0.00976562f, 0.249512f, 0.00976562f, 0.188965f, 0.00976562f,
-0.144775f, -0.00341797f, 0.100586f, -0.0166016f, 0.0712891f, -0.0402832f, 0.0419922f,
--0.0639648f, 0.0266113f, -0.0964355f, 0.0112305f, -0.128906f, 0.0078125f, -0.16748f,
-0.145508f, -0.186035f, 0.148438f, -0.161621f, 0.156982f, -0.145264f, 0.165527f, -0.128906f,
-0.179443f, -0.118896f, 0.193359f, -0.108887f, 0.212646f, -0.104736f, 0.231934f, -0.100586f,
-0.255859f, -0.100586f, 0.283203f, -0.100586f, 0.303467f, -0.108398f, 0.32373f, -0.116211f,
-0.337158f, -0.129883f, 0.350586f, -0.143555f, 0.357178f, -0.162354f, 0.36377f, -0.181152f,
-0.36377f, -0.203125f, 0.36377f, -0.248535f, 0.337402f, -0.27124f, 0.311035f, -0.293945f,
-0.256348f, -0.293945f, 0.204102f, -0.293945f, 0.225586f, -0.404785f, 0.426758f, -0.139648f,
-0.400391f, 0, 0.269531f, 0, 0.295898f, -0.139648f, -0.0166016f, -0.139648f, 0.00341797f,
--0.240723f, 0.353516f, -0.687988f, 0.53418f, -0.687988f, 0.447266f, -0.242188f, 0.539062f,
--0.242188f, 0.518555f, -0.139648f, 0.366211f, -0.498047f, 0.367676f, -0.505371f,
-0.370605f, -0.517578f, 0.373535f, -0.529785f, 0.377197f, -0.543213f, 0.380859f, -0.556641f,
-0.384521f, -0.569092f, 0.388184f, -0.581543f, 0.390625f, -0.588867f, 0.387207f, -0.583008f,
-0.380371f, -0.57251f, 0.373535f, -0.562012f, 0.365479f, -0.550049f, 0.357422f, -0.538086f,
-0.348877f, -0.526367f, 0.340332f, -0.514648f, 0.333496f, -0.505859f, 0.126465f, -0.242188f,
-0.316406f, -0.242188f, 0.154297f, -0.687988f, 0.567871f, -0.687988f, 0.546875f, -0.575195f,
-0.256836f, -0.575195f, 0.214355f, -0.412109f, 0.223145f, -0.419922f, 0.235107f, -0.427734f,
-0.24707f, -0.435547f, 0.262207f, -0.441895f, 0.277344f, -0.448242f, 0.296387f, -0.452148f,
-0.31543f, -0.456055f, 0.338867f, -0.456055f, 0.376953f, -0.456055f, 0.409912f, -0.442871f,
-0.442871f, -0.429688f, 0.467285f, -0.403809f, 0.491699f, -0.37793f, 0.505615f, -0.340088f,
-0.519531f, -0.302246f, 0.519531f, -0.25293f, 0.519531f, -0.194824f, 0.500488f, -0.146484f,
-0.481445f, -0.0981445f, 0.445312f, -0.0634766f, 0.40918f, -0.0288086f, 0.356689f,
--0.00952148f, 0.304199f, 0.00976562f, 0.237305f, 0.00976562f, 0.182617f, 0.00976562f,
-0.142578f, -0.00317383f, 0.102539f, -0.0161133f, 0.0749512f, -0.0388184f, 0.0473633f,
--0.0615234f, 0.0314941f, -0.0927734f, 0.015625f, -0.124023f, 0.00976562f, -0.160645f,
-0.147949f, -0.182617f, 0.151855f, -0.162109f, 0.158691f, -0.146729f, 0.165527f, -0.131348f,
-0.177246f, -0.121094f, 0.188965f, -0.11084f, 0.206543f, -0.105713f, 0.224121f, -0.100586f,
-0.249023f, -0.100586f, 0.281738f, -0.100586f, 0.306396f, -0.111328f, 0.331055f, -0.12207f,
-0.347412f, -0.140869f, 0.36377f, -0.159668f, 0.371826f, -0.18457f, 0.379883f, -0.209473f,
-0.379883f, -0.237305f, 0.379883f, -0.265625f, 0.372803f, -0.286133f, 0.365723f, -0.306641f,
-0.353271f, -0.319824f, 0.34082f, -0.333008f, 0.323975f, -0.339111f, 0.307129f, -0.345215f,
-0.287598f, -0.345215f, 0.255859f, -0.345215f, 0.231934f, -0.333984f, 0.208008f, -0.322754f,
-0.188965f, -0.300781f, 0.0551758f, -0.300781f, 0.260254f, 0.00976562f, 0.208008f,
-0.00976562f, 0.168213f, -0.00708008f, 0.128418f, -0.0239258f, 0.101318f, -0.0559082f,
-0.0742188f, -0.0878906f, 0.0603027f, -0.133789f, 0.0463867f, -0.179688f, 0.0463867f,
--0.237793f, 0.0463867f, -0.337402f, 0.0695801f, -0.421631f, 0.0927734f, -0.505859f,
-0.134521f, -0.567383f, 0.17627f, -0.628906f, 0.234863f, -0.663574f, 0.293457f, -0.698242f,
-0.36377f, -0.698242f, 0.397461f, -0.698242f, 0.430664f, -0.690918f, 0.463867f, -0.683594f,
-0.491211f, -0.665527f, 0.518555f, -0.647461f, 0.537354f, -0.616943f, 0.556152f, -0.586426f,
-0.561523f, -0.540039f, 0.431641f, -0.52002f, 0.424805f, -0.555664f, 0.406738f, -0.572754f,
-0.388672f, -0.589844f, 0.356445f, -0.589844f, 0.300293f, -0.589844f, 0.258789f, -0.533691f,
-0.217285f, -0.477539f, 0.198242f, -0.364258f, 0.224121f, -0.399414f, 0.263916f, -0.421143f,
-0.303711f, -0.442871f, 0.354004f, -0.442871f, 0.392578f, -0.442871f, 0.424316f, -0.430908f,
-0.456055f, -0.418945f, 0.47876f, -0.395752f, 0.501465f, -0.372559f, 0.513916f, -0.338623f,
-0.526367f, -0.304688f, 0.526367f, -0.260254f, 0.526367f, -0.206055f, 0.507568f, -0.157227f,
-0.48877f, -0.108398f, 0.454102f, -0.0712891f, 0.419434f, -0.0341797f, 0.370361f,
--0.012207f, 0.321289f, 0.00976562f, 0.260254f, 0.00976562f, 0.180176f, -0.209473f,
-0.180176f, -0.158203f, 0.204102f, -0.12793f, 0.228027f, -0.0976562f, 0.272461f, -0.0976562f,
-0.297363f, -0.0976562f, 0.318359f, -0.107422f, 0.339355f, -0.117188f, 0.354492f,
--0.135986f, 0.369629f, -0.154785f, 0.378174f, -0.181885f, 0.386719f, -0.208984f,
-0.386719f, -0.243652f, 0.386719f, -0.269043f, 0.380127f, -0.287598f, 0.373535f, -0.306152f,
-0.361816f, -0.318115f, 0.350098f, -0.330078f, 0.334229f, -0.335938f, 0.318359f, -0.341797f,
-0.299805f, -0.341797f, 0.277832f, -0.341797f, 0.256348f, -0.333496f, 0.234863f, -0.325195f,
-0.218018f, -0.308838f, 0.201172f, -0.29248f, 0.190674f, -0.267578f, 0.180176f, -0.242676f,
-0.180176f, -0.209473f, 0.345215f, -0.697754f, 0.394531f, -0.697754f, 0.43335f, -0.686035f,
-0.472168f, -0.674316f, 0.499023f, -0.652832f, 0.525879f, -0.631348f, 0.540283f, -0.60083f,
-0.554688f, -0.570312f, 0.554688f, -0.532715f, 0.554688f, -0.5f, 0.544189f, -0.470947f,
-0.533691f, -0.441895f, 0.513916f, -0.419678f, 0.494141f, -0.397461f, 0.465332f, -0.382568f,
-0.436523f, -0.367676f, 0.400391f, -0.362793f, 0.399902f, -0.36084f, 0.424805f, -0.353516f,
-0.445557f, -0.340332f, 0.466309f, -0.327148f, 0.480957f, -0.30835f, 0.495605f, -0.289551f,
-0.503906f, -0.265137f, 0.512207f, -0.240723f, 0.512207f, -0.210938f, 0.512207f, -0.163574f,
-0.495117f, -0.123291f, 0.478027f, -0.0830078f, 0.444092f, -0.0534668f, 0.410156f,
--0.0239258f, 0.359375f, -0.00708008f, 0.308594f, 0.00976562f, 0.240723f, 0.00976562f,
-0.182617f, 0.00976562f, 0.139648f, -0.00415039f, 0.0966797f, -0.0180664f, 0.0686035f,
--0.0429688f, 0.0405273f, -0.0678711f, 0.0268555f, -0.101807f, 0.0131836f, -0.135742f,
-0.0131836f, -0.175781f, 0.0131836f, -0.221191f, 0.029541f, -0.253174f, 0.0458984f,
--0.285156f, 0.0715332f, -0.306885f, 0.097168f, -0.328613f, 0.128174f, -0.341309f,
-0.15918f, -0.354004f, 0.188477f, -0.359863f, 0.188477f, -0.361816f, 0.143555f, -0.381836f,
-0.120361f, -0.421143f, 0.097168f, -0.460449f, 0.097168f, -0.513672f, 0.097168f, -0.556152f,
-0.114014f, -0.590332f, 0.130859f, -0.624512f, 0.162842f, -0.648193f, 0.194824f, -0.671875f,
-0.240967f, -0.684814f, 0.287109f, -0.697754f, 0.345215f, -0.697754f, 0.316406f, -0.410156f,
-0.345703f, -0.410156f, 0.364746f, -0.420654f, 0.383789f, -0.431152f, 0.395264f, -0.447266f,
-0.406738f, -0.463379f, 0.411133f, -0.482666f, 0.415527f, -0.501953f, 0.415527f, -0.519531f,
-0.415527f, -0.558594f, 0.39502f, -0.580078f, 0.374512f, -0.601562f, 0.331543f, -0.601562f,
-0.310547f, -0.601562f, 0.29248f, -0.595459f, 0.274414f, -0.589355f, 0.260986f, -0.57666f,
-0.247559f, -0.563965f, 0.23999f, -0.544434f, 0.232422f, -0.524902f, 0.232422f, -0.498047f,
-0.232422f, -0.482422f, 0.236328f, -0.466553f, 0.240234f, -0.450684f, 0.249756f, -0.438232f,
-0.259277f, -0.425781f, 0.275391f, -0.417969f, 0.291504f, -0.410156f, 0.316406f, -0.410156f,
-0.273926f, -0.3125f, 0.244629f, -0.3125f, 0.222412f, -0.303223f, 0.200195f, -0.293945f,
-0.185303f, -0.2771f, 0.17041f, -0.260254f, 0.162598f, -0.236572f, 0.154785f, -0.212891f,
-0.154785f, -0.184082f, 0.154785f, -0.163086f, 0.160645f, -0.145264f, 0.166504f, -0.127441f,
-0.178711f, -0.114502f, 0.190918f, -0.101562f, 0.209717f, -0.0942383f, 0.228516f,
--0.0869141f, 0.253906f, -0.0869141f, 0.27832f, -0.0869141f, 0.299561f, -0.0952148f,
-0.320801f, -0.103516f, 0.33667f, -0.119873f, 0.352539f, -0.13623f, 0.361816f, -0.1604f,
-0.371094f, -0.18457f, 0.371094f, -0.216797f, 0.371094f, -0.234863f, 0.366455f, -0.251953f,
-0.361816f, -0.269043f, 0.350342f, -0.282471f, 0.338867f, -0.295898f, 0.320312f, -0.304199f,
-0.301758f, -0.3125f, 0.273926f, -0.3125f, 0.398926f, -0.318848f, 0.383789f, -0.300781f,
-0.367432f, -0.287109f, 0.351074f, -0.273438f, 0.33252f, -0.26416f, 0.313965f, -0.254883f,
-0.292236f, -0.250244f, 0.270508f, -0.245605f, 0.244141f, -0.245605f, 0.204102f, -0.245605f,
-0.172119f, -0.259521f, 0.140137f, -0.273438f, 0.11792f, -0.298584f, 0.0957031f, -0.32373f,
-0.0837402f, -0.358887f, 0.0717773f, -0.394043f, 0.0717773f, -0.436035f, 0.0717773f,
--0.491211f, 0.0915527f, -0.539062f, 0.111328f, -0.586914f, 0.146484f, -0.622314f,
-0.181641f, -0.657715f, 0.230469f, -0.677979f, 0.279297f, -0.698242f, 0.337891f, -0.698242f,
-0.384277f, -0.698242f, 0.42334f, -0.683105f, 0.462402f, -0.667969f, 0.490967f, -0.638428f,
-0.519531f, -0.608887f, 0.535645f, -0.565918f, 0.551758f, -0.522949f, 0.551758f, -0.467285f,
-0.551758f, -0.454102f, 0.550781f, -0.4375f, 0.549805f, -0.420898f, 0.548096f, -0.403076f,
-0.546387f, -0.385254f, 0.543701f, -0.366699f, 0.541016f, -0.348145f, 0.537598f, -0.331543f,
-0.519043f, -0.239746f, 0.487793f, -0.174805f, 0.456543f, -0.109863f, 0.416748f, -0.0688477f,
-0.376953f, -0.027832f, 0.330322f, -0.0090332f, 0.283691f, 0.00976562f, 0.233887f,
-0.00976562f, 0.192383f, 0.00976562f, 0.156738f, 0, 0.121094f, -0.00976562f, 0.09375f,
--0.0300293f, 0.0664062f, -0.050293f, 0.0483398f, -0.0805664f, 0.0302734f, -0.11084f,
-0.0234375f, -0.151855f, 0.157227f, -0.175293f, 0.164062f, -0.138672f, 0.18457f, -0.118652f,
-0.205078f, -0.0986328f, 0.243164f, -0.0986328f, 0.264648f, -0.0986328f, 0.286865f,
--0.108154f, 0.309082f, -0.117676f, 0.329834f, -0.142334f, 0.350586f, -0.166992f,
-0.368408f, -0.209717f, 0.38623f, -0.252441f, 0.398926f, -0.318848f, 0.41748f, -0.492676f,
-0.41748f, -0.513184f, 0.411377f, -0.531006f, 0.405273f, -0.548828f, 0.393799f, -0.562256f,
-0.382324f, -0.575684f, 0.366455f, -0.583252f, 0.350586f, -0.59082f, 0.331055f, -0.59082f,
-0.304688f, -0.59082f, 0.282715f, -0.581055f, 0.260742f, -0.571289f, 0.244873f, -0.552002f,
-0.229004f, -0.532715f, 0.219971f, -0.504395f, 0.210938f, -0.476074f, 0.210938f, -0.439453f,
-0.210938f, -0.41748f, 0.217529f, -0.400146f, 0.224121f, -0.382812f, 0.235596f, -0.37085f,
-0.24707f, -0.358887f, 0.263184f, -0.352783f, 0.279297f, -0.34668f, 0.29834f, -0.34668f,
-0.316895f, -0.34668f, 0.335205f, -0.351807f, 0.353516f, -0.356934f, 0.369141f, -0.369141f,
-0.384766f, -0.381348f, 0.396484f, -0.400879f, 0.408203f, -0.42041f, 0.413574f, -0.449219f,
-0.415527f, -0.460938f, 0.416504f, -0.47168f, 0.41748f, -0.482422f, 0.41748f, -0.492676f,
-0.114746f, -0.367188f, 0.141602f, -0.504883f, 0.282227f, -0.504883f, 0.255371f, -0.367188f,
-0.043457f, 0, 0.0703125f, -0.137207f, 0.210938f, -0.137207f, 0.184082f, 0, 0.507324f,
-0, 0.480469f, -0.175781f, 0.218262f, -0.175781f, 0.123047f, 0, -0.0205078f, 0, 0.36377f,
--0.687988f, 0.533691f, -0.687988f, 0.649902f, 0, 0.436523f, -0.504883f, 0.435547f,
--0.512207f, 0.434082f, -0.523193f, 0.432617f, -0.53418f, 0.431152f, -0.545654f, 0.429688f,
--0.557129f, 0.428711f, -0.567139f, 0.427734f, -0.577148f, 0.427734f, -0.582031f,
-0.425781f, -0.576172f, 0.420654f, -0.564209f, 0.415527f, -0.552246f, 0.408936f, -0.537598f,
-0.402344f, -0.522949f, 0.394531f, -0.507324f, 0.386719f, -0.491699f, 0.379883f, -0.478516f,
-0.276367f, -0.28418f, 0.469238f, -0.28418f, 0.151367f, -0.687988f, 0.436523f, -0.687988f,
-0.500488f, -0.687988f, 0.547119f, -0.677246f, 0.59375f, -0.666504f, 0.624512f, -0.645996f,
-0.655273f, -0.625488f, 0.670166f, -0.595947f, 0.685059f, -0.566406f, 0.685059f, -0.528809f,
-0.685059f, -0.493164f, 0.673828f, -0.465088f, 0.662598f, -0.437012f, 0.641846f, -0.41626f,
-0.621094f, -0.395508f, 0.591797f, -0.381592f, 0.5625f, -0.367676f, 0.526855f, -0.360352f,
-0.561523f, -0.354492f, 0.587891f, -0.34082f, 0.614258f, -0.327148f, 0.63208f, -0.307373f,
-0.649902f, -0.287598f, 0.658936f, -0.262939f, 0.667969f, -0.238281f, 0.667969f, -0.210449f,
-0.667969f, -0.149414f, 0.643311f, -0.108887f, 0.618652f, -0.0683594f, 0.576904f,
--0.0441895f, 0.535156f, -0.0200195f, 0.479492f, -0.0100098f, 0.423828f, 0, 0.361816f,
-0, 0.0175781f, 0, 0.241211f, -0.410645f, 0.384766f, -0.410645f, 0.427246f, -0.410645f,
-0.457275f, -0.416016f, 0.487305f, -0.421387f, 0.506104f, -0.433105f, 0.524902f, -0.444824f,
-0.533447f, -0.463135f, 0.541992f, -0.481445f, 0.541992f, -0.506836f, 0.541992f, -0.52832f,
-0.533936f, -0.542725f, 0.525879f, -0.557129f, 0.510498f, -0.565674f, 0.495117f, -0.574219f,
-0.472412f, -0.577637f, 0.449707f, -0.581055f, 0.420898f, -0.581055f, 0.273926f, -0.581055f,
-0.182129f, -0.106934f, 0.342285f, -0.106934f, 0.388672f, -0.106934f, 0.422852f, -0.111816f,
-0.457031f, -0.116699f, 0.479248f, -0.128906f, 0.501465f, -0.141113f, 0.512451f, -0.161621f,
-0.523438f, -0.182129f, 0.523438f, -0.213379f, 0.523438f, -0.257324f, 0.490234f, -0.280762f,
-0.457031f, -0.304199f, 0.381836f, -0.304199f, 0.220703f, -0.304199f, 0.195801f, -0.279785f,
-0.195801f, -0.23877f, 0.206055f, -0.206055f, 0.216309f, -0.17334f, 0.236572f, -0.150391f,
-0.256836f, -0.127441f, 0.286865f, -0.115234f, 0.316895f, -0.103027f, 0.356934f, -0.103027f,
-0.39502f, -0.103027f, 0.42627f, -0.113281f, 0.45752f, -0.123535f, 0.482666f, -0.141113f,
-0.507812f, -0.158691f, 0.5271f, -0.181396f, 0.546387f, -0.204102f, 0.561035f, -0.229004f,
-0.671875f, -0.171875f, 0.650879f, -0.134766f, 0.621582f, -0.101562f, 0.592285f, -0.0683594f,
-0.552734f, -0.0437012f, 0.513184f, -0.019043f, 0.462402f, -0.00463867f, 0.411621f,
-0.00976562f, 0.347168f, 0.00976562f, 0.270508f, 0.00976562f, 0.214111f, -0.0126953f,
-0.157715f, -0.0351562f, 0.121094f, -0.0739746f, 0.0844727f, -0.112793f, 0.0666504f,
--0.165283f, 0.0488281f, -0.217773f, 0.0488281f, -0.277832f, 0.0488281f, -0.338379f,
-0.0615234f, -0.393066f, 0.0742188f, -0.447754f, 0.0983887f, -0.494385f, 0.122559f,
--0.541016f, 0.157715f, -0.578857f, 0.192871f, -0.616699f, 0.237793f, -0.643066f,
-0.282715f, -0.669434f, 0.33667f, -0.683838f, 0.390625f, -0.698242f, 0.452637f, -0.698242f,
-0.519531f, -0.698242f, 0.568115f, -0.682617f, 0.616699f, -0.666992f, 0.650391f, -0.640625f,
-0.684082f, -0.614258f, 0.704102f, -0.57959f, 0.724121f, -0.544922f, 0.733887f, -0.506836f,
-0.600098f, -0.472168f, 0.594238f, -0.493652f, 0.582275f, -0.513916f, 0.570312f, -0.53418f,
-0.551758f, -0.550049f, 0.533203f, -0.565918f, 0.507324f, -0.575439f, 0.481445f, -0.584961f,
-0.448242f, -0.584961f, 0.386719f, -0.584961f, 0.3396f, -0.562744f, 0.29248f, -0.540527f,
-0.260498f, -0.500244f, 0.228516f, -0.459961f, 0.212158f, -0.403809f, 0.195801f, -0.347656f,
-0.195801f, -0.279785f, 0.358398f, -0.687988f, 0.437988f, -0.687988f, 0.500244f, -0.669434f,
-0.5625f, -0.650879f, 0.605469f, -0.614014f, 0.648438f, -0.577148f, 0.671143f, -0.522217f,
-0.693848f, -0.467285f, 0.693848f, -0.394043f, 0.693848f, -0.329102f, 0.678955f, -0.274658f,
-0.664062f, -0.220215f, 0.637451f, -0.176514f, 0.61084f, -0.132812f, 0.573975f, -0.0998535f,
-0.537109f, -0.0668945f, 0.493408f, -0.0446777f, 0.449707f, -0.0224609f, 0.400391f,
--0.0112305f, 0.351074f, 0, 0.299805f, 0, 0.0175781f, 0, 0.151367f, -0.687988f, 0.183105f,
--0.111328f, 0.29541f, -0.111328f, 0.352051f, -0.111328f, 0.400391f, -0.129395f, 0.44873f,
--0.147461f, 0.483887f, -0.182373f, 0.519043f, -0.217285f, 0.539062f, -0.268799f,
-0.559082f, -0.320312f, 0.559082f, -0.387695f, 0.559082f, -0.435547f, 0.54541f, -0.470947f,
-0.531738f, -0.506348f, 0.506104f, -0.529785f, 0.480469f, -0.553223f, 0.443359f, -0.564941f,
-0.40625f, -0.57666f, 0.359375f, -0.57666f, 0.273438f, -0.57666f, 0.0175781f, 0, 0.150879f,
--0.687988f, 0.691895f, -0.687988f, 0.67041f, -0.57666f, 0.273438f, -0.57666f, 0.239746f,
--0.403809f, 0.606934f, -0.403809f, 0.585449f, -0.29248f, 0.218262f, -0.29248f, 0.183105f,
--0.111328f, 0.600098f, -0.111328f, 0.578125f, 0, 0.273438f, -0.57666f, 0.231934f,
--0.36377f, 0.558105f, -0.36377f, 0.536621f, -0.252441f, 0.210449f, -0.252441f, 0.161133f,
-0, 0.0175781f, 0, 0.150879f, -0.687988f, 0.632324f, -0.687988f, 0.61084f, -0.57666f,
-0.683594f, -0.0854492f, 0.650879f, -0.0629883f, 0.616455f, -0.045166f, 0.582031f,
--0.0273438f, 0.542969f, -0.0153809f, 0.503906f, -0.00341797f, 0.459229f, 0.00292969f,
-0.414551f, 0.00927734f, 0.361328f, 0.00927734f, 0.282227f, 0.00927734f, 0.223389f,
--0.0129395f, 0.164551f, -0.0351562f, 0.125732f, -0.0742188f, 0.0869141f, -0.113281f,
-0.0678711f, -0.167236f, 0.0488281f, -0.221191f, 0.0488281f, -0.284668f, 0.0488281f,
--0.376465f, 0.0776367f, -0.452637f, 0.106445f, -0.528809f, 0.159912f, -0.583496f,
-0.213379f, -0.638184f, 0.289551f, -0.668213f, 0.365723f, -0.698242f, 0.459961f, -0.698242f,
-0.523926f, -0.698242f, 0.572754f, -0.682617f, 0.621582f, -0.666992f, 0.656738f, -0.640625f,
-0.691895f, -0.614258f, 0.714111f, -0.579834f, 0.736328f, -0.54541f, 0.74707f, -0.507324f,
-0.609375f, -0.469238f, 0.603516f, -0.491699f, 0.591553f, -0.512695f, 0.57959f, -0.533691f,
-0.560547f, -0.549805f, 0.541504f, -0.565918f, 0.514648f, -0.575439f, 0.487793f, -0.584961f,
-0.452148f, -0.584961f, 0.390137f, -0.584961f, 0.342041f, -0.5625f, 0.293945f, -0.540039f,
-0.26123f, -0.500488f, 0.228516f, -0.460938f, 0.21167f, -0.406738f, 0.194824f, -0.352539f,
-0.194824f, -0.289062f, 0.194824f, -0.251465f, 0.204834f, -0.217773f, 0.214844f, -0.184082f,
-0.236328f, -0.158447f, 0.257812f, -0.132812f, 0.291748f, -0.11792f, 0.325684f, -0.103027f,
-0.373047f, -0.103027f, 0.40332f, -0.103027f, 0.430664f, -0.106934f, 0.458008f, -0.11084f,
-0.481934f, -0.117432f, 0.505859f, -0.124023f, 0.525635f, -0.132324f, 0.54541f, -0.140625f,
-0.560547f, -0.149902f, 0.583008f, -0.26123f, 0.416016f, -0.26123f, 0.435059f, -0.362793f,
-0.734863f, -0.362793f, 0.466797f, 0, 0.524414f, -0.294922f, 0.21875f, -0.294922f,
-0.161133f, 0, 0.0175781f, 0, 0.150879f, -0.687988f, 0.294922f, -0.687988f, 0.241699f,
--0.414062f, 0.547363f, -0.414062f, 0.600586f, -0.687988f, 0.739258f, -0.687988f,
-0.605469f, 0, 0.0175781f, 0, 0.150879f, -0.687988f, 0.294922f, -0.687988f, 0.161133f,
-0, 0.48584f, 0, 0.3125f, -0.3125f, 0.209473f, -0.252441f, 0.160156f, 0, 0.0175781f,
-0, 0.150879f, -0.687988f, 0.294922f, -0.687988f, 0.231445f, -0.375977f, 0.602539f,
--0.687988f, 0.782715f, -0.687988f, 0.417969f, -0.387207f, 0.64502f, 0, 0.0175781f,
-0, 0.150879f, -0.687988f, 0.294922f, -0.687988f, 0.183105f, -0.111328f, 0.552246f,
--0.111328f, 0.530273f, 0, 0.588867f, 0, 0.672852f, -0.431641f, 0.678223f, -0.458496f,
-0.68457f, -0.486084f, 0.690918f, -0.513672f, 0.696289f, -0.536621f, 0.702637f, -0.563477f,
-0.708984f, -0.588867f, 0.691406f, -0.550781f, 0.675293f, -0.515137f, 0.668457f, -0.5f,
-0.660889f, -0.483887f, 0.65332f, -0.467773f, 0.645996f, -0.452393f, 0.638672f, -0.437012f,
-0.63208f, -0.423096f, 0.625488f, -0.40918f, 0.619629f, -0.398438f, 0.418457f, 0,
-0.315918f, 0, 0.27002f, -0.399902f, 0.269043f, -0.40918f, 0.267578f, -0.422119f,
-0.266113f, -0.435059f, 0.264404f, -0.450195f, 0.262695f, -0.465332f, 0.260986f, -0.481445f,
-0.259277f, -0.497559f, 0.257812f, -0.512695f, 0.254395f, -0.548828f, 0.250488f, -0.588867f,
-0.24707f, -0.559082f, 0.243652f, -0.530273f, 0.242188f, -0.518066f, 0.240479f, -0.504883f,
-0.23877f, -0.491699f, 0.237061f, -0.479004f, 0.235352f, -0.466309f, 0.233398f, -0.45459f,
-0.231445f, -0.442871f, 0.229492f, -0.433105f, 0.145508f, 0, 0.0175781f, 0, 0.151367f,
--0.687988f, 0.344238f, -0.687988f, 0.387207f, -0.303223f, 0.38916f, -0.288086f, 0.391113f,
--0.265381f, 0.393066f, -0.242676f, 0.39502f, -0.220703f, 0.396973f, -0.195312f, 0.399414f,
--0.168457f, 0.411621f, -0.195312f, 0.42334f, -0.220215f, 0.433105f, -0.241699f, 0.444092f,
--0.263916f, 0.455078f, -0.286133f, 0.462402f, -0.300781f, 0.658691f, -0.687988f,
-0.850586f, -0.687988f, 0.716797f, 0, 0.431641f, 0, 0.249023f, -0.552246f, 0.246094f,
--0.53125f, 0.243164f, -0.510742f, 0.240723f, -0.493164f, 0.237305f, -0.4729f, 0.233887f,
--0.452637f, 0.230469f, -0.435547f, 0.145508f, 0, 0.0175781f, 0, 0.151367f, -0.687988f,
-0.322266f, -0.687988f, 0.506348f, -0.130859f, 0.509277f, -0.149902f, 0.512207f, -0.170898f,
-0.514648f, -0.188965f, 0.518311f, -0.211182f, 0.521973f, -0.233398f, 0.526367f, -0.255859f,
-0.611328f, -0.687988f, 0.739258f, -0.687988f, 0.605469f, 0, 0.453125f, -0.698242f,
-0.525391f, -0.698242f, 0.58252f, -0.678467f, 0.639648f, -0.658691f, 0.679443f, -0.621826f,
-0.719238f, -0.584961f, 0.740234f, -0.532715f, 0.76123f, -0.480469f, 0.76123f, -0.415527f,
-0.76123f, -0.391602f, 0.758789f, -0.365967f, 0.756348f, -0.340332f, 0.751465f, -0.316895f,
-0.736328f, -0.241699f, 0.701904f, -0.181396f, 0.66748f, -0.121094f, 0.616699f, -0.0786133f,
-0.565918f, -0.0361328f, 0.499756f, -0.0131836f, 0.433594f, 0.00976562f, 0.35498f,
-0.00976562f, 0.280273f, 0.00976562f, 0.223145f, -0.0114746f, 0.166016f, -0.0327148f,
-0.127197f, -0.0710449f, 0.0883789f, -0.109375f, 0.0686035f, -0.162598f, 0.0488281f,
--0.21582f, 0.0488281f, -0.279785f, 0.0488281f, -0.302246f, 0.0510254f, -0.325684f,
-0.0532227f, -0.349121f, 0.0581055f, -0.373047f, 0.0732422f, -0.446289f, 0.106934f,
--0.506348f, 0.140625f, -0.566406f, 0.190918f, -0.609131f, 0.241211f, -0.651855f,
-0.307373f, -0.675049f, 0.373535f, -0.698242f, 0.453125f, -0.698242f, 0.446289f, -0.584473f,
-0.394043f, -0.584473f, 0.353027f, -0.568848f, 0.312012f, -0.553223f, 0.281982f, -0.523926f,
-0.251953f, -0.494629f, 0.231934f, -0.451904f, 0.211914f, -0.40918f, 0.20166f, -0.35498f,
-0.198242f, -0.336914f, 0.196777f, -0.318604f, 0.195312f, -0.300293f, 0.195312f, -0.283691f,
-0.195312f, -0.193848f, 0.239258f, -0.148682f, 0.283203f, -0.103516f, 0.361816f, -0.103516f,
-0.414551f, -0.103516f, 0.455566f, -0.119385f, 0.496582f, -0.135254f, 0.526855f, -0.165039f,
-0.557129f, -0.194824f, 0.576904f, -0.237061f, 0.59668f, -0.279297f, 0.606934f, -0.332031f,
-0.610352f, -0.349609f, 0.611572f, -0.369629f, 0.612793f, -0.389648f, 0.612793f, -0.403809f,
-0.612793f, -0.449219f, 0.601074f, -0.48291f, 0.589355f, -0.516602f, 0.567871f, -0.539307f,
-0.546387f, -0.562012f, 0.515381f, -0.573242f, 0.484375f, -0.584473f, 0.446289f, -0.584473f,
-0.415039f, -0.687988f, 0.475586f, -0.687988f, 0.522705f, -0.673828f, 0.569824f, -0.659668f,
-0.602295f, -0.632812f, 0.634766f, -0.605957f, 0.651611f, -0.567871f, 0.668457f, -0.529785f,
-0.668457f, -0.481934f, 0.668457f, -0.42627f, 0.648682f, -0.381836f, 0.628906f, -0.337402f,
-0.592773f, -0.306396f, 0.556641f, -0.275391f, 0.505859f, -0.258789f, 0.455078f, -0.242188f,
-0.393066f, -0.242188f, 0.208984f, -0.242188f, 0.161133f, 0, 0.0175781f, 0, 0.150879f,
--0.687988f, 0.22998f, -0.353027f, 0.371094f, -0.353027f, 0.446777f, -0.353027f, 0.484619f,
--0.381348f, 0.522461f, -0.409668f, 0.522461f, -0.474121f, 0.522461f, -0.500977f,
-0.513672f, -0.520264f, 0.504883f, -0.539551f, 0.48877f, -0.552002f, 0.472656f, -0.564453f,
-0.450439f, -0.570312f, 0.428223f, -0.576172f, 0.401367f, -0.576172f, 0.273438f, -0.576172f,
-0.453125f, -0.698242f, 0.525391f, -0.698242f, 0.58252f, -0.678467f, 0.639648f, -0.658691f,
-0.679443f, -0.621826f, 0.719238f, -0.584961f, 0.740234f, -0.532715f, 0.76123f, -0.480469f,
-0.76123f, -0.415527f, 0.76123f, -0.391602f, 0.758789f, -0.365967f, 0.756348f, -0.340332f,
-0.751465f, -0.316895f, 0.738281f, -0.250977f, 0.710205f, -0.196533f, 0.682129f, -0.14209f,
-0.641113f, -0.10083f, 0.600098f, -0.0595703f, 0.547119f, -0.032959f, 0.494141f, -0.00634766f,
-0.430664f, 0.00390625f, 0.439941f, 0.0517578f, 0.462158f, 0.0732422f, 0.484375f,
-0.0947266f, 0.527832f, 0.0947266f, 0.536133f, 0.0947266f, 0.545898f, 0.0942383f,
-0.555664f, 0.09375f, 0.56543f, 0.0927734f, 0.575195f, 0.0917969f, 0.584473f, 0.0905762f,
-0.59375f, 0.0893555f, 0.601074f, 0.0878906f, 0.579102f, 0.183105f, 0.564941f, 0.187988f,
-0.542725f, 0.19165f, 0.520508f, 0.195312f, 0.496582f, 0.195312f, 0.442383f, 0.195312f,
-0.404297f, 0.181641f, 0.366211f, 0.167969f, 0.341309f, 0.142822f, 0.316406f, 0.117676f,
-0.303223f, 0.0825195f, 0.290039f, 0.0473633f, 0.285156f, 0.00439453f, 0.227539f,
--0.00488281f, 0.18335f, -0.029541f, 0.13916f, -0.0541992f, 0.109131f, -0.0910645f,
-0.0791016f, -0.12793f, 0.0639648f, -0.175781f, 0.0488281f, -0.223633f, 0.0488281f,
--0.279785f, 0.0488281f, -0.302246f, 0.0510254f, -0.325684f, 0.0532227f, -0.349121f,
-0.0581055f, -0.373047f, 0.0732422f, -0.446289f, 0.106934f, -0.506348f, 0.140625f,
--0.566406f, 0.190918f, -0.609131f, 0.241211f, -0.651855f, 0.307373f, -0.675049f,
-0.373535f, -0.698242f, 0.453125f, -0.698242f, 0.446289f, -0.584473f, 0.394043f, -0.584473f,
-0.353027f, -0.568848f, 0.312012f, -0.553223f, 0.281982f, -0.523926f, 0.251953f, -0.494629f,
-0.231934f, -0.451904f, 0.211914f, -0.40918f, 0.20166f, -0.35498f, 0.198242f, -0.336914f,
-0.196777f, -0.318604f, 0.195312f, -0.300293f, 0.195312f, -0.283691f, 0.195312f, -0.193848f,
-0.239258f, -0.148682f, 0.283203f, -0.103516f, 0.361816f, -0.103516f, 0.414551f, -0.103516f,
-0.455566f, -0.119385f, 0.496582f, -0.135254f, 0.526855f, -0.165039f, 0.557129f, -0.194824f,
-0.576904f, -0.237061f, 0.59668f, -0.279297f, 0.606934f, -0.332031f, 0.610352f, -0.349609f,
-0.611572f, -0.369629f, 0.612793f, -0.389648f, 0.612793f, -0.403809f, 0.612793f, -0.449219f,
-0.601074f, -0.48291f, 0.589355f, -0.516602f, 0.567871f, -0.539307f, 0.546387f, -0.562012f,
-0.515381f, -0.573242f, 0.484375f, -0.584473f, 0.446289f, -0.584473f, 0.493164f, 0,
-0.380859f, -0.260742f, 0.211914f, -0.260742f, 0.161621f, 0, 0.0175781f, 0, 0.151367f,
--0.687988f, 0.469238f, -0.687988f, 0.535156f, -0.687988f, 0.582031f, -0.671875f,
-0.628906f, -0.655762f, 0.658447f, -0.628662f, 0.687988f, -0.601562f, 0.70166f, -0.565918f,
-0.715332f, -0.530273f, 0.715332f, -0.491211f, 0.715332f, -0.445312f, 0.698975f, -0.409424f,
-0.682617f, -0.373535f, 0.655518f, -0.347656f, 0.628418f, -0.321777f, 0.592773f, -0.306152f,
-0.557129f, -0.290527f, 0.518555f, -0.284668f, 0.652344f, 0, 0.425781f, -0.373047f,
-0.458496f, -0.373047f, 0.484863f, -0.379395f, 0.51123f, -0.385742f, 0.530029f, -0.399414f,
-0.548828f, -0.413086f, 0.559082f, -0.433838f, 0.569336f, -0.45459f, 0.569336f, -0.48291f,
-0.569336f, -0.508301f, 0.560059f, -0.526123f, 0.550781f, -0.543945f, 0.534668f, -0.554932f,
-0.518555f, -0.565918f, 0.49707f, -0.571045f, 0.475586f, -0.576172f, 0.451172f, -0.576172f,
-0.273438f, -0.576172f, 0.233887f, -0.373047f, 0.292969f, 0.00976562f, 0.227051f,
-0.00976562f, 0.177246f, -0.00195312f, 0.127441f, -0.0136719f, 0.0930176f, -0.0373535f,
-0.0585938f, -0.0610352f, 0.0388184f, -0.0961914f, 0.019043f, -0.131348f, 0.012207f,
--0.178223f, 0.15332f, -0.202148f, 0.158203f, -0.175781f, 0.168945f, -0.15625f, 0.179688f,
--0.136719f, 0.197754f, -0.123779f, 0.21582f, -0.11084f, 0.241699f, -0.104492f, 0.267578f,
--0.0981445f, 0.302734f, -0.0981445f, 0.339844f, -0.0981445f, 0.37085f, -0.103027f,
-0.401855f, -0.10791f, 0.424072f, -0.119385f, 0.446289f, -0.130859f, 0.45874f, -0.149414f,
-0.471191f, -0.167969f, 0.471191f, -0.195312f, 0.471191f, -0.218262f, 0.461914f, -0.234375f,
-0.452637f, -0.250488f, 0.434326f, -0.262207f, 0.416016f, -0.273926f, 0.388916f, -0.283203f,
-0.361816f, -0.29248f, 0.325684f, -0.301758f, 0.279785f, -0.313965f, 0.239502f, -0.329102f,
-0.199219f, -0.344238f, 0.169189f, -0.367432f, 0.13916f, -0.390625f, 0.121582f, -0.424072f,
-0.104004f, -0.45752f, 0.104004f, -0.506348f, 0.104004f, -0.552734f, 0.125977f, -0.588623f,
-0.147949f, -0.624512f, 0.185791f, -0.648926f, 0.223633f, -0.67334f, 0.274658f, -0.685791f,
-0.325684f, -0.698242f, 0.383789f, -0.698242f, 0.446777f, -0.698242f, 0.494385f, -0.686279f,
-0.541992f, -0.674316f, 0.575684f, -0.652588f, 0.609375f, -0.630859f, 0.629395f, -0.600342f,
-0.649414f, -0.569824f, 0.656738f, -0.532715f, 0.516113f, -0.5f, 0.505371f, -0.543945f,
-0.469482f, -0.570068f, 0.433594f, -0.596191f, 0.375977f, -0.596191f, 0.34375f, -0.596191f,
-0.31958f, -0.589844f, 0.29541f, -0.583496f, 0.279053f, -0.572266f, 0.262695f, -0.561035f,
-0.254395f, -0.54541f, 0.246094f, -0.529785f, 0.246094f, -0.51123f, 0.246094f, -0.489258f,
-0.25708f, -0.474365f, 0.268066f, -0.459473f, 0.287354f, -0.44873f, 0.306641f, -0.437988f,
-0.333496f, -0.429688f, 0.360352f, -0.421387f, 0.392578f, -0.412598f, 0.41748f, -0.405762f,
-0.443604f, -0.397705f, 0.469727f, -0.389648f, 0.494141f, -0.378662f, 0.518555f, -0.367676f,
-0.540039f, -0.352783f, 0.561523f, -0.337891f, 0.577637f, -0.317139f, 0.59375f, -0.296387f,
-0.603027f, -0.269287f, 0.612305f, -0.242188f, 0.612305f, -0.206543f, 0.612305f, -0.155273f,
-0.592773f, -0.115234f, 0.573242f, -0.0751953f, 0.533691f, -0.0473633f, 0.494141f,
--0.0195312f, 0.434082f, -0.00488281f, 0.374023f, 0.00976562f, 0.292969f, 0.00976562f,
-0.437012f, -0.57666f, 0.324707f, 0, 0.180664f, 0, 0.292969f, -0.57666f, 0.0708008f,
--0.57666f, 0.0922852f, -0.687988f, 0.681152f, -0.687988f, 0.659668f, -0.57666f, 0.335938f,
--0.103027f, 0.374512f, -0.103027f, 0.404297f, -0.111328f, 0.434082f, -0.119629f,
-0.456299f, -0.138672f, 0.478516f, -0.157715f, 0.493164f, -0.188477f, 0.507812f, -0.219238f,
-0.516602f, -0.26416f, 0.598633f, -0.687988f, 0.742676f, -0.687988f, 0.65918f, -0.258789f,
-0.645508f, -0.189453f, 0.618652f, -0.138916f, 0.591797f, -0.0883789f, 0.551025f,
--0.0554199f, 0.510254f, -0.0224609f, 0.454834f, -0.00634766f, 0.399414f, 0.00976562f,
-0.328125f, 0.00976562f, 0.265137f, 0.00976562f, 0.214844f, -0.00463867f, 0.164551f,
--0.019043f, 0.129883f, -0.046875f, 0.0952148f, -0.074707f, 0.0766602f, -0.115967f,
-0.0581055f, -0.157227f, 0.0581055f, -0.210449f, 0.0581055f, -0.220703f, 0.059082f,
--0.234131f, 0.0600586f, -0.247559f, 0.0617676f, -0.26123f, 0.0634766f, -0.274902f,
-0.0654297f, -0.287842f, 0.0673828f, -0.300781f, 0.0693359f, -0.310059f, 0.141602f,
--0.687988f, 0.285645f, -0.687988f, 0.210938f, -0.29248f, 0.20752f, -0.275879f, 0.204834f,
--0.252686f, 0.202148f, -0.229492f, 0.202148f, -0.208496f, 0.202148f, -0.182129f,
-0.211914f, -0.162354f, 0.22168f, -0.142578f, 0.239502f, -0.129395f, 0.257324f, -0.116211f,
-0.281982f, -0.109619f, 0.306641f, -0.103027f, 0.335938f, -0.103027f, 0.703613f, 0,
-0.532715f, 0, 0.519531f, -0.396484f, 0.519531f, -0.401855f, 0.519043f, -0.419189f,
-0.518555f, -0.436523f, 0.518066f, -0.458496f, 0.517578f, -0.480469f, 0.517334f, -0.503906f,
-0.51709f, -0.527344f, 0.51709f, -0.544922f, 0.506348f, -0.516113f, 0.496094f, -0.48877f,
-0.491699f, -0.477051f, 0.486816f, -0.4646f, 0.481934f, -0.452148f, 0.477295f, -0.440186f,
-0.472656f, -0.428223f, 0.468262f, -0.41748f, 0.463867f, -0.406738f, 0.459961f, -0.397949f,
-0.290039f, 0, 0.116699f, 0, 0.0732422f, -0.687988f, 0.209961f, -0.687988f, 0.227539f,
--0.290039f, 0.228516f, -0.266602f, 0.229248f, -0.237549f, 0.22998f, -0.208496f, 0.230469f,
--0.182129f, 0.230957f, -0.151855f, 0.230957f, -0.121094f, 0.245117f, -0.157227f,
-0.258789f, -0.191406f, 0.264648f, -0.206055f, 0.270996f, -0.22168f, 0.277344f, -0.237305f,
-0.283691f, -0.252441f, 0.290039f, -0.267578f, 0.295654f, -0.281494f, 0.30127f, -0.29541f,
-0.306152f, -0.306641f, 0.469238f, -0.687988f, 0.623535f, -0.687988f, 0.63916f, -0.250977f,
-0.640137f, -0.230469f, 0.640869f, -0.208008f, 0.641602f, -0.185547f, 0.642578f, -0.166016f,
-0.643555f, -0.143066f, 0.644043f, -0.121094f, 0.654297f, -0.148926f, 0.665527f, -0.178223f,
-0.675293f, -0.203125f, 0.687012f, -0.23291f, 0.69873f, -0.262695f, 0.709961f, -0.290527f,
-0.873047f, -0.687988f, 1.01514f, -0.687988f, 0.107422f, -0.687988f, 0.258301f, -0.687988f,
-0.367676f, -0.458008f, 0.563965f, -0.687988f, 0.716797f, -0.687988f, 0.423828f, -0.357422f,
-0.603027f, 0, 0.453125f, 0, 0.32959f, -0.259766f, 0.107422f, 0, -0.0458984f, 0, 0.272461f,
--0.359375f, 0.408203f, -0.282227f, 0.353516f, 0, 0.209961f, 0, 0.264648f, -0.282227f,
-0.0839844f, -0.687988f, 0.226562f, -0.687988f, 0.353027f, -0.392578f, 0.584473f,
--0.687988f, 0.742188f, -0.687988f, 0.52832f, 0, -0.0234375f, 0, -0.00390625f, -0.102051f,
-0.44873f, -0.575195f, 0.125f, -0.575195f, 0.146973f, -0.687988f, 0.64209f, -0.687988f,
-0.622559f, -0.587891f, 0.168457f, -0.112793f, 0.550293f, -0.112793f, -0.0263672f,
-0.20752f, 0.154297f, -0.724609f, 0.418945f, -0.724609f, 0.400879f, -0.631836f, 0.266113f,
--0.631836f, 0.121094f, 0.114258f, 0.255859f, 0.114258f, 0.237793f, 0.20752f, 0.141113f,
-0.0200195f, 0.0541992f, -0.725098f, 0.17041f, -0.725098f, 0.259766f, 0.0200195f,
--0.0849609f, 0.20752f, -0.0668945f, 0.114258f, 0.0683594f, 0.114258f, 0.213379f,
--0.631836f, 0.0776367f, -0.631836f, 0.0957031f, -0.724609f, 0.360352f, -0.724609f,
-0.179199f, 0.20752f, -0.0585938f, 0.12207f, -0.0585938f, 0.0839844f, 0.516113f, 0.0839844f,
-0.516113f, 0.12207f, 0.52002f, -0.00585938f, 0.499512f, 0.00195312f, 0.478516f, 0.00341797f,
-0.45752f, 0.00488281f, 0.435547f, 0.00488281f, 0.386719f, 0.00488281f, 0.360352f,
--0.015625f, 0.333984f, -0.0361328f, 0.333984f, -0.0698242f, 0.333984f, -0.0771484f,
-0.334473f, -0.0852051f, 0.334961f, -0.0932617f, 0.336426f, -0.101074f, 0.333496f,
--0.101074f, 0.316895f, -0.0751953f, 0.299805f, -0.0546875f, 0.282715f, -0.0341797f,
-0.261963f, -0.0197754f, 0.241211f, -0.00537109f, 0.215332f, 0.00219727f, 0.189453f,
-0.00976562f, 0.154785f, 0.00976562f, 0.116699f, 0.00976562f, 0.088623f, -0.00244141f,
-0.0605469f, -0.0146484f, 0.0419922f, -0.0349121f, 0.0234375f, -0.0551758f, 0.0141602f,
--0.081543f, 0.00488281f, -0.10791f, 0.00488281f, -0.135742f, 0.00488281f, -0.175293f,
-0.0158691f, -0.204102f, 0.0268555f, -0.23291f, 0.0458984f, -0.253418f, 0.0649414f,
--0.273926f, 0.0905762f, -0.286865f, 0.116211f, -0.299805f, 0.145508f, -0.307129f,
-0.174805f, -0.314453f, 0.206543f, -0.317383f, 0.238281f, -0.320312f, 0.269043f, -0.320801f,
-0.362305f, -0.322266f, 0.366211f, -0.339844f, 0.369629f, -0.354492f, 0.371094f, -0.365479f,
-0.372559f, -0.376465f, 0.372559f, -0.38623f, 0.372559f, -0.418457f, 0.355957f, -0.433594f,
-0.339355f, -0.44873f, 0.310547f, -0.44873f, 0.296387f, -0.44873f, 0.28125f, -0.446777f,
-0.266113f, -0.444824f, 0.252686f, -0.437744f, 0.239258f, -0.430664f, 0.228271f, -0.416748f,
-0.217285f, -0.402832f, 0.211426f, -0.379395f, 0.0830078f, -0.394531f, 0.0908203f,
--0.427246f, 0.108398f, -0.453613f, 0.125977f, -0.47998f, 0.154297f, -0.498779f, 0.182617f,
--0.517578f, 0.221924f, -0.527832f, 0.26123f, -0.538086f, 0.312988f, -0.538086f, 0.414062f,
--0.538086f, 0.461182f, -0.502441f, 0.508301f, -0.466797f, 0.508301f, -0.394043f,
-0.508301f, -0.378906f, 0.504395f, -0.35791f, 0.500488f, -0.336914f, 0.496582f, -0.317383f,
-0.461914f, -0.14502f, 0.460449f, -0.136719f, 0.459229f, -0.127197f, 0.458008f, -0.117676f,
-0.458008f, -0.109863f, 0.458008f, -0.0981445f, 0.462891f, -0.0917969f, 0.467773f,
--0.0854492f, 0.474121f, -0.0825195f, 0.480469f, -0.0795898f, 0.486816f, -0.0788574f,
-0.493164f, -0.078125f, 0.496582f, -0.078125f, 0.503418f, -0.078125f, 0.509521f, -0.0786133f,
-0.515625f, -0.0791016f, 0.526855f, -0.081543f, 0.347168f, -0.245605f, 0.268066f,
--0.245605f, 0.210938f, -0.244629f, 0.177979f, -0.222168f, 0.14502f, -0.199707f, 0.14502f,
--0.158691f, 0.14502f, -0.139648f, 0.150879f, -0.125732f, 0.156738f, -0.111816f, 0.166504f,
--0.103027f, 0.17627f, -0.0942383f, 0.189209f, -0.0900879f, 0.202148f, -0.0859375f,
-0.216309f, -0.0859375f, 0.230469f, -0.0859375f, 0.247803f, -0.0915527f, 0.265137f,
--0.097168f, 0.281982f, -0.110352f, 0.298828f, -0.123535f, 0.313477f, -0.145752f,
-0.328125f, -0.167969f, 0.336426f, -0.200684f, 0.41748f, -0.538086f, 0.457031f, -0.538086f,
-0.487793f, -0.525879f, 0.518555f, -0.513672f, 0.539307f, -0.491211f, 0.560059f, -0.46875f,
-0.571045f, -0.436768f, 0.582031f, -0.404785f, 0.582031f, -0.365234f, 0.582031f, -0.358398f,
-0.582031f, -0.334961f, 0.57959f, -0.307617f, 0.577148f, -0.280273f, 0.571777f, -0.251953f,
-0.558105f, -0.182617f, 0.536621f, -0.133057f, 0.515137f, -0.0834961f, 0.484619f,
--0.0517578f, 0.454102f, -0.0200195f, 0.414795f, -0.00512695f, 0.375488f, 0.00976562f,
-0.32666f, 0.00976562f, 0.265625f, 0.00976562f, 0.227539f, -0.015625f, 0.189453f,
--0.0410156f, 0.173828f, -0.0869141f, 0.172852f, -0.0869141f, 0.169922f, -0.0742188f,
-0.16626f, -0.0598145f, 0.162598f, -0.0454102f, 0.158936f, -0.0327148f, 0.155273f,
--0.0200195f, 0.152832f, -0.0109863f, 0.150391f, -0.00195312f, 0.149414f, 0, 0.0170898f,
-0, 0.0185547f, -0.00439453f, 0.0209961f, -0.0148926f, 0.0234375f, -0.0253906f, 0.0266113f,
--0.0400391f, 0.0297852f, -0.0546875f, 0.0336914f, -0.0722656f, 0.0375977f, -0.0898438f,
-0.0410156f, -0.108887f, 0.161133f, -0.724609f, 0.29834f, -0.724609f, 0.257324f, -0.516113f,
-0.250977f, -0.483887f, 0.246582f, -0.464844f, 0.242188f, -0.445801f, 0.241699f, -0.445801f,
-0.243652f, -0.445801f, 0.270996f, -0.486816f, 0.314697f, -0.512451f, 0.358398f, -0.538086f,
-0.41748f, -0.538086f, 0.358887f, -0.442871f, 0.333496f, -0.442871f, 0.310059f, -0.434814f,
-0.286621f, -0.426758f, 0.26709f, -0.407227f, 0.247559f, -0.387695f, 0.232178f, -0.354492f,
-0.216797f, -0.321289f, 0.207031f, -0.270508f, 0.203125f, -0.249023f, 0.200928f, -0.230469f,
-0.19873f, -0.211914f, 0.19873f, -0.195801f, 0.19873f, -0.168457f, 0.205811f, -0.147705f,
-0.212891f, -0.126953f, 0.22583f, -0.112793f, 0.23877f, -0.0986328f, 0.256836f, -0.0915527f,
-0.274902f, -0.0844727f, 0.296875f, -0.0844727f, 0.321777f, -0.0844727f, 0.341553f,
--0.092041f, 0.361328f, -0.0996094f, 0.377197f, -0.118408f, 0.393066f, -0.137207f,
-0.405518f, -0.169678f, 0.417969f, -0.202148f, 0.428223f, -0.251953f, 0.433594f, -0.276855f,
-0.436279f, -0.298584f, 0.438965f, -0.320312f, 0.438965f, -0.338867f, 0.438965f, -0.390137f,
-0.421631f, -0.416504f, 0.404297f, -0.442871f, 0.358887f, -0.442871f, 0.261719f, -0.0844727f,
-0.302246f, -0.0844727f, 0.328613f, -0.110107f, 0.35498f, -0.135742f, 0.370605f, -0.186035f,
-0.50293f, -0.161621f, 0.491211f, -0.123047f, 0.470947f, -0.0913086f, 0.450684f, -0.0595703f,
-0.420654f, -0.0371094f, 0.390625f, -0.0146484f, 0.349365f, -0.00244141f, 0.308105f,
-0.00976562f, 0.253906f, 0.00976562f, 0.197266f, 0.00976562f, 0.155273f, -0.00537109f,
-0.113281f, -0.0205078f, 0.0856934f, -0.0480957f, 0.0581055f, -0.0756836f, 0.0444336f,
--0.11377f, 0.0307617f, -0.151855f, 0.0307617f, -0.197754f, 0.0307617f, -0.217285f,
-0.0324707f, -0.240234f, 0.0341797f, -0.263184f, 0.0395508f, -0.285156f, 0.0517578f,
--0.339355f, 0.0705566f, -0.37915f, 0.0893555f, -0.418945f, 0.112549f, -0.447021f,
-0.135742f, -0.475098f, 0.162598f, -0.49292f, 0.189453f, -0.510742f, 0.217773f, -0.520752f,
-0.246094f, -0.530762f, 0.275146f, -0.534424f, 0.304199f, -0.538086f, 0.332031f, -0.538086f,
-0.384277f, -0.538086f, 0.422363f, -0.523926f, 0.460449f, -0.509766f, 0.486084f, -0.485596f,
-0.511719f, -0.461426f, 0.525146f, -0.429443f, 0.538574f, -0.397461f, 0.541504f, -0.361816f,
-0.402832f, -0.350586f, 0.400391f, -0.394531f, 0.380615f, -0.419189f, 0.36084f, -0.443848f,
-0.321289f, -0.443848f, 0.293945f, -0.443848f, 0.273682f, -0.434814f, 0.253418f, -0.425781f,
-0.237793f, -0.406006f, 0.222168f, -0.38623f, 0.209717f, -0.355225f, 0.197266f, -0.324219f,
-0.186035f, -0.280762f, 0.184082f, -0.270996f, 0.182129f, -0.26001f, 0.180176f, -0.249023f,
-0.178467f, -0.238037f, 0.176758f, -0.227051f, 0.175781f, -0.217041f, 0.174805f, -0.207031f,
-0.174805f, -0.19873f, 0.174805f, -0.139648f, 0.196777f, -0.112061f, 0.21875f, -0.0844727f,
-0.261719f, -0.0844727f, 0.365723f, -0.078125f, 0.348145f, -0.0551758f, 0.32959f,
--0.0385742f, 0.311035f, -0.0219727f, 0.290283f, -0.0109863f, 0.269531f, 0, 0.245117f,
-0.00512695f, 0.220703f, 0.0102539f, 0.191406f, 0.0102539f, 0.152344f, 0.0102539f,
-0.121826f, -0.00341797f, 0.0913086f, -0.0170898f, 0.0705566f, -0.0415039f, 0.0498047f,
--0.065918f, 0.0390625f, -0.0996094f, 0.0283203f, -0.133301f, 0.0283203f, -0.172852f,
-0.0283203f, -0.194824f, 0.0305176f, -0.220215f, 0.0327148f, -0.245605f, 0.0385742f,
--0.276367f, 0.0522461f, -0.345703f, 0.0759277f, -0.395264f, 0.0996094f, -0.444824f,
-0.131104f, -0.476562f, 0.162598f, -0.508301f, 0.201172f, -0.523193f, 0.239746f, -0.538086f,
-0.283203f, -0.538086f, 0.318848f, -0.538086f, 0.344971f, -0.530518f, 0.371094f, -0.522949f,
-0.389404f, -0.509766f, 0.407715f, -0.496582f, 0.419189f, -0.479004f, 0.430664f, -0.461426f,
-0.436523f, -0.441406f, 0.438965f, -0.441406f, 0.439941f, -0.451172f, 0.442871f, -0.470703f,
-0.445801f, -0.490234f, 0.45166f, -0.520508f, 0.492676f, -0.724609f, 0.62793f, -0.724609f,
-0.511719f, -0.112793f, 0.506348f, -0.0830078f, 0.50293f, -0.0546875f, 0.499512f,
--0.0263672f, 0.497559f, 0, 0.360352f, 0, 0.360352f, -0.00390625f, 0.360596f, -0.0117188f,
-0.36084f, -0.0195312f, 0.361816f, -0.0302734f, 0.362793f, -0.0410156f, 0.364258f,
--0.0532227f, 0.365723f, -0.0654297f, 0.367676f, -0.078125f, 0.251465f, -0.0839844f,
-0.277344f, -0.0839844f, 0.300537f, -0.092041f, 0.32373f, -0.100098f, 0.343262f, -0.119873f,
-0.362793f, -0.139648f, 0.37793f, -0.173096f, 0.393066f, -0.206543f, 0.402832f, -0.257324f,
-0.406738f, -0.278809f, 0.408936f, -0.297607f, 0.411133f, -0.316406f, 0.411133f, -0.33252f,
-0.411133f, -0.391113f, 0.388184f, -0.417725f, 0.365234f, -0.444336f, 0.319336f, -0.444336f,
-0.296387f, -0.444336f, 0.275391f, -0.436523f, 0.254395f, -0.428711f, 0.236816f, -0.409424f,
-0.219238f, -0.390137f, 0.205078f, -0.357666f, 0.190918f, -0.325195f, 0.182129f, -0.275879f,
-0.177734f, -0.250977f, 0.175537f, -0.230713f, 0.17334f, -0.210449f, 0.17334f, -0.191895f,
-0.17334f, -0.140137f, 0.191895f, -0.112061f, 0.210449f, -0.0839844f, 0.251465f, -0.0839844f,
-0.174805f, -0.232422f, 0.172852f, -0.22168f, 0.172119f, -0.210938f, 0.171387f, -0.200195f,
-0.171387f, -0.188965f, 0.171387f, -0.137207f, 0.194092f, -0.109619f, 0.216797f, -0.0820312f,
-0.26123f, -0.0820312f, 0.281738f, -0.0820312f, 0.297852f, -0.0883789f, 0.313965f,
--0.0947266f, 0.32666f, -0.105713f, 0.339355f, -0.116699f, 0.348877f, -0.131836f,
-0.358398f, -0.146973f, 0.365234f, -0.164551f, 0.484863f, -0.128418f, 0.470215f, -0.097168f,
-0.45166f, -0.0715332f, 0.433105f, -0.0458984f, 0.40625f, -0.027832f, 0.379395f, -0.00976562f,
-0.341797f, 0, 0.304199f, 0.00976562f, 0.251953f, 0.00976562f, 0.198242f, 0.00976562f,
-0.156982f, -0.00537109f, 0.115723f, -0.0205078f, 0.0876465f, -0.0483398f, 0.0595703f,
--0.0761719f, 0.045166f, -0.115723f, 0.0307617f, -0.155273f, 0.0307617f, -0.204102f,
-0.0307617f, -0.28418f, 0.052002f, -0.346191f, 0.0732422f, -0.408203f, 0.111084f,
--0.450928f, 0.148926f, -0.493652f, 0.201172f, -0.515869f, 0.253418f, -0.538086f,
-0.31543f, -0.538086f, 0.370117f, -0.538086f, 0.410156f, -0.523438f, 0.450195f, -0.508789f,
-0.476562f, -0.482178f, 0.50293f, -0.455566f, 0.515625f, -0.418701f, 0.52832f, -0.381836f,
-0.52832f, -0.337402f, 0.52832f, -0.31543f, 0.525146f, -0.286865f, 0.521973f, -0.258301f,
-0.516602f, -0.232422f, 0.401367f, -0.32373f, 0.402344f, -0.331543f, 0.402588f, -0.337891f,
-0.402832f, -0.344238f, 0.402832f, -0.351074f, 0.402832f, -0.40332f, 0.378662f, -0.427246f,
-0.354492f, -0.451172f, 0.31543f, -0.451172f, 0.298828f, -0.451172f, 0.280273f, -0.445801f,
-0.261719f, -0.44043f, 0.244385f, -0.426025f, 0.227051f, -0.411621f, 0.213135f, -0.386963f,
-0.199219f, -0.362305f, 0.190918f, -0.32373f, 0.257812f, -0.435547f, 0.172852f, 0,
-0.0361328f, 0, 0.121094f, -0.435547f, 0.0439453f, -0.435547f, 0.0620117f, -0.52832f,
-0.13916f, -0.52832f, 0.149902f, -0.583496f, 0.15625f, -0.616699f, 0.169189f, -0.643066f,
-0.182129f, -0.669434f, 0.204834f, -0.6875f, 0.227539f, -0.705566f, 0.260742f, -0.715088f,
-0.293945f, -0.724609f, 0.34082f, -0.724609f, 0.362793f, -0.724609f, 0.382568f, -0.721924f,
-0.402344f, -0.719238f, 0.416504f, -0.716309f, 0.398926f, -0.62793f, 0.394531f, -0.628906f,
-0.388428f, -0.629639f, 0.382324f, -0.630371f, 0.375732f, -0.631104f, 0.369141f, -0.631836f,
-0.362793f, -0.632324f, 0.356445f, -0.632812f, 0.352051f, -0.632812f, 0.319336f, -0.632812f,
-0.304688f, -0.617188f, 0.290039f, -0.601562f, 0.283691f, -0.569824f, 0.275879f, -0.52832f,
-0.379883f, -0.52832f, 0.361816f, -0.435547f, 0.210449f, 0.20752f, 0.15918f, 0.20752f,
-0.121582f, 0.198486f, 0.0839844f, 0.189453f, 0.0581055f, 0.171875f, 0.0322266f, 0.154297f,
-0.017334f, 0.128662f, 0.00244141f, 0.103027f, -0.00341797f, 0.0693359f, 0.134766f,
-0.0546875f, 0.141602f, 0.0869141f, 0.164551f, 0.101807f, 0.1875f, 0.116699f, 0.226562f,
-0.116699f, 0.254883f, 0.116699f, 0.275879f, 0.109131f, 0.296875f, 0.101562f, 0.312256f,
-0.0856934f, 0.327637f, 0.0698242f, 0.338135f, 0.045166f, 0.348633f, 0.0205078f, 0.356445f,
--0.0131836f, 0.359375f, -0.0273438f, 0.362061f, -0.0422363f, 0.364746f, -0.0571289f,
-0.367188f, -0.0698242f, 0.369629f, -0.0844727f, 0.371582f, -0.0981445f, 0.370605f,
--0.0981445f, 0.356934f, -0.0786133f, 0.341553f, -0.0600586f, 0.326172f, -0.0415039f,
-0.305908f, -0.0273438f, 0.285645f, -0.0131836f, 0.259277f, -0.00463867f, 0.23291f,
-0.00390625f, 0.197754f, 0.00390625f, 0.15918f, 0.00390625f, 0.128174f, -0.00927734f,
-0.097168f, -0.0224609f, 0.0759277f, -0.0458984f, 0.0546875f, -0.0693359f, 0.0432129f,
--0.102051f, 0.0317383f, -0.134766f, 0.0317383f, -0.173828f, 0.0317383f, -0.197754f,
-0.0339355f, -0.225098f, 0.0361328f, -0.252441f, 0.0419922f, -0.283203f, 0.0668945f,
--0.410645f, 0.125732f, -0.474121f, 0.18457f, -0.537598f, 0.286133f, -0.537598f, 0.313965f,
--0.537598f, 0.339111f, -0.530762f, 0.364258f, -0.523926f, 0.384277f, -0.510986f,
-0.404297f, -0.498047f, 0.418701f, -0.479248f, 0.433105f, -0.460449f, 0.439941f, -0.436035f,
-0.440918f, -0.436035f, 0.443359f, -0.44873f, 0.447021f, -0.463867f, 0.450684f, -0.479004f,
-0.454102f, -0.49292f, 0.45752f, -0.506836f, 0.460449f, -0.516846f, 0.463379f, -0.526855f,
-0.464355f, -0.52832f, 0.59375f, -0.52832f, 0.592773f, -0.523926f, 0.590332f, -0.513184f,
-0.587891f, -0.502441f, 0.584473f, -0.487549f, 0.581055f, -0.472656f, 0.577393f, -0.454346f,
-0.57373f, -0.436035f, 0.569824f, -0.416504f, 0.489258f, -0.00488281f, 0.478516f,
-0.0478516f, 0.458496f, 0.0876465f, 0.438477f, 0.127441f, 0.405518f, 0.154053f, 0.372559f,
-0.180664f, 0.324707f, 0.194092f, 0.276855f, 0.20752f, 0.210449f, 0.20752f, 0.406738f,
--0.267578f, 0.410156f, -0.284668f, 0.411621f, -0.303223f, 0.413086f, -0.321777f,
-0.413086f, -0.334961f, 0.413086f, -0.362793f, 0.405762f, -0.383057f, 0.398438f, -0.40332f,
-0.385498f, -0.416992f, 0.372559f, -0.430664f, 0.354736f, -0.437256f, 0.336914f, -0.443848f,
-0.316406f, -0.443848f, 0.291504f, -0.443848f, 0.27124f, -0.436279f, 0.250977f, -0.428711f,
-0.235107f, -0.4104f, 0.219238f, -0.39209f, 0.207031f, -0.361084f, 0.194824f, -0.330078f,
-0.186035f, -0.283691f, 0.181641f, -0.259277f, 0.178467f, -0.235352f, 0.175293f, -0.211426f,
-0.175293f, -0.193359f, 0.175293f, -0.143066f, 0.197021f, -0.119629f, 0.21875f, -0.0961914f,
-0.259766f, -0.0961914f, 0.28125f, -0.0961914f, 0.303711f, -0.105713f, 0.326172f,
--0.115234f, 0.346191f, -0.135986f, 0.366211f, -0.156738f, 0.38208f, -0.189209f, 0.397949f,
--0.22168f, 0.406738f, -0.267578f, 0.293457f, -0.724609f, 0.254883f, -0.526855f, 0.25293f,
--0.516602f, 0.250488f, -0.504639f, 0.248047f, -0.492676f, 0.245361f, -0.480957f,
-0.242676f, -0.469238f, 0.240234f, -0.458008f, 0.237793f, -0.446777f, 0.23584f, -0.437988f,
-0.237305f, -0.437988f, 0.251953f, -0.458496f, 0.269775f, -0.476562f, 0.287598f, -0.494629f,
-0.30957f, -0.508301f, 0.331543f, -0.521973f, 0.358643f, -0.529785f, 0.385742f, -0.537598f,
-0.419434f, -0.537598f, 0.493652f, -0.537598f, 0.53125f, -0.501953f, 0.568848f, -0.466309f,
-0.568848f, -0.398926f, 0.568848f, -0.390137f, 0.567627f, -0.378906f, 0.566406f, -0.367676f,
-0.564941f, -0.356689f, 0.563477f, -0.345703f, 0.561768f, -0.335693f, 0.560059f, -0.325684f,
-0.558594f, -0.318848f, 0.496582f, 0, 0.360352f, 0, 0.417969f, -0.290527f, 0.419922f,
--0.299805f, 0.422119f, -0.311035f, 0.424316f, -0.322266f, 0.42627f, -0.333496f, 0.428223f,
--0.344727f, 0.429443f, -0.354736f, 0.430664f, -0.364746f, 0.430664f, -0.371094f,
-0.430664f, -0.401855f, 0.411865f, -0.417969f, 0.393066f, -0.434082f, 0.356445f, -0.434082f,
-0.333496f, -0.434082f, 0.310547f, -0.424316f, 0.287598f, -0.414551f, 0.267822f, -0.396484f,
-0.248047f, -0.378418f, 0.233154f, -0.352783f, 0.218262f, -0.327148f, 0.212402f, -0.295898f,
-0.154785f, 0, 0.0170898f, 0, 0.156738f, -0.724609f, 0.137695f, -0.623535f, 0.157715f,
--0.724609f, 0.294922f, -0.724609f, 0.274902f, -0.623535f, 0.0170898f, 0, 0.119629f,
--0.52832f, 0.256836f, -0.52832f, 0.153809f, 0, 0.138184f, -0.623535f, 0.157715f,
--0.724609f, 0.294922f, -0.724609f, 0.275391f, -0.623535f, -0.0263672f, 0.20752f,
--0.0507812f, 0.20752f, -0.0717773f, 0.204834f, -0.0927734f, 0.202148f, -0.107422f,
-0.198242f, -0.0898438f, 0.106445f, -0.0834961f, 0.107422f, -0.0754395f, 0.10791f,
--0.0673828f, 0.108398f, -0.0615234f, 0.108398f, -0.0449219f, 0.108398f, -0.0332031f,
-0.104492f, -0.0214844f, 0.100586f, -0.0131836f, 0.0913086f, -0.00488281f, 0.0820312f,
-0.000732422f, 0.0668945f, 0.00634766f, 0.0517578f, 0.0107422f, 0.0292969f, 0.119629f,
--0.52832f, 0.256836f, -0.52832f, 0.141602f, 0.0625f, 0.135254f, 0.0942383f, 0.122314f,
-0.120605f, 0.109375f, 0.146973f, 0.0888672f, 0.166504f, 0.0683594f, 0.186035f, 0.0397949f,
-0.196777f, 0.0112305f, 0.20752f, -0.0263672f, 0.20752f, 0.355469f, 0, 0.263672f,
--0.242676f, 0.195312f, -0.206055f, 0.153809f, 0, 0.0170898f, 0, 0.157715f, -0.724609f,
-0.294922f, -0.724609f, 0.213379f, -0.30957f, 0.44043f, -0.52832f, 0.597656f, -0.52832f,
-0.366699f, -0.322266f, 0.500977f, 0, 0.0170898f, 0, 0.157715f, -0.724609f, 0.294922f,
--0.724609f, 0.153809f, 0, 0.645508f, -0.435547f, 0.623535f, -0.435547f, 0.60376f,
--0.425781f, 0.583984f, -0.416016f, 0.568115f, -0.397705f, 0.552246f, -0.379395f,
-0.540771f, -0.35376f, 0.529297f, -0.328125f, 0.522949f, -0.296387f, 0.464844f, 0,
-0.328613f, 0, 0.388672f, -0.310059f, 0.390137f, -0.317871f, 0.391602f, -0.326904f,
-0.393066f, -0.335938f, 0.394287f, -0.345215f, 0.395508f, -0.354492f, 0.39624f, -0.362549f,
-0.396973f, -0.370605f, 0.396973f, -0.376465f, 0.396973f, -0.435547f, 0.335449f, -0.435547f,
-0.312988f, -0.435547f, 0.293457f, -0.425537f, 0.273926f, -0.415527f, 0.257812f, -0.397217f,
-0.241699f, -0.378906f, 0.230225f, -0.352783f, 0.21875f, -0.32666f, 0.212402f, -0.294922f,
-0.154785f, 0, 0.0170898f, 0, 0.0981445f, -0.415527f, 0.101562f, -0.432129f, 0.104736f,
--0.450439f, 0.10791f, -0.46875f, 0.110596f, -0.485107f, 0.113281f, -0.501465f, 0.11499f,
--0.513184f, 0.116699f, -0.524902f, 0.117188f, -0.52832f, 0.25f, -0.52832f, 0.25f,
--0.525879f, 0.248535f, -0.515137f, 0.24707f, -0.504395f, 0.244873f, -0.490479f, 0.242676f,
--0.476562f, 0.240479f, -0.462158f, 0.238281f, -0.447754f, 0.236328f, -0.437988f,
-0.237793f, -0.437988f, 0.25293f, -0.460938f, 0.268799f, -0.479492f, 0.284668f, -0.498047f,
-0.303467f, -0.510986f, 0.322266f, -0.523926f, 0.345459f, -0.530762f, 0.368652f, -0.537598f,
-0.397949f, -0.537598f, 0.458496f, -0.537598f, 0.493652f, -0.508545f, 0.528809f, -0.479492f,
-0.535645f, -0.424316f, 0.55127f, -0.44873f, 0.568359f, -0.469238f, 0.585449f, -0.489746f,
-0.605957f, -0.505127f, 0.626465f, -0.520508f, 0.651611f, -0.529053f, 0.676758f, -0.537598f,
-0.708496f, -0.537598f, 0.775879f, -0.537598f, 0.811768f, -0.501953f, 0.847656f, -0.466309f,
-0.847656f, -0.398926f, 0.847656f, -0.381348f, 0.844482f, -0.359375f, 0.841309f, -0.337402f,
-0.837402f, -0.318848f, 0.774902f, 0, 0.638672f, 0, 0.698242f, -0.306152f, 0.699707f,
--0.313477f, 0.701172f, -0.32251f, 0.702637f, -0.331543f, 0.704102f, -0.340576f, 0.705566f,
--0.349609f, 0.706299f, -0.358398f, 0.707031f, -0.367188f, 0.707031f, -0.374023f,
-0.707031f, -0.376465f, 0.705566f, -0.435547f, 0.645508f, -0.435547f, 0.360352f, 0,
-0.417969f, -0.290527f, 0.419922f, -0.299805f, 0.422119f, -0.311035f, 0.424316f, -0.322266f,
-0.42627f, -0.333496f, 0.428223f, -0.344727f, 0.429443f, -0.354736f, 0.430664f, -0.364746f,
-0.430664f, -0.371094f, 0.430664f, -0.401855f, 0.412109f, -0.417969f, 0.393555f, -0.434082f,
-0.356445f, -0.434082f, 0.333496f, -0.434082f, 0.310547f, -0.424316f, 0.287598f, -0.414551f,
-0.267822f, -0.396484f, 0.248047f, -0.378418f, 0.233154f, -0.352783f, 0.218262f, -0.327148f,
-0.212402f, -0.295898f, 0.154785f, 0, 0.0170898f, 0, 0.0981445f, -0.415527f, 0.101562f,
--0.432129f, 0.104736f, -0.450439f, 0.10791f, -0.46875f, 0.110352f, -0.485107f, 0.112793f,
--0.501465f, 0.114502f, -0.513184f, 0.116211f, -0.524902f, 0.116699f, -0.52832f, 0.247559f,
--0.52832f, 0.247559f, -0.525879f, 0.246338f, -0.515137f, 0.245117f, -0.504395f, 0.243408f,
--0.490479f, 0.241699f, -0.476562f, 0.239746f, -0.462158f, 0.237793f, -0.447754f,
-0.23584f, -0.437988f, 0.237305f, -0.437988f, 0.251953f, -0.458496f, 0.269775f, -0.476562f,
-0.287598f, -0.494629f, 0.30957f, -0.508301f, 0.331543f, -0.521973f, 0.358643f, -0.529785f,
-0.385742f, -0.537598f, 0.419434f, -0.537598f, 0.493652f, -0.537598f, 0.53125f, -0.501953f,
-0.568848f, -0.466309f, 0.568848f, -0.398926f, 0.568848f, -0.390137f, 0.567627f, -0.378906f,
-0.566406f, -0.367676f, 0.564941f, -0.356689f, 0.563477f, -0.345703f, 0.561768f, -0.335693f,
-0.560059f, -0.325684f, 0.558594f, -0.318848f, 0.496582f, 0, 0.578613f, -0.333496f,
-0.578613f, -0.253906f, 0.554688f, -0.190186f, 0.530762f, -0.126465f, 0.488281f, -0.0820312f,
-0.445801f, -0.0375977f, 0.387695f, -0.013916f, 0.32959f, 0.00976562f, 0.26123f, 0.00976562f,
-0.208984f, 0.00976562f, 0.166504f, -0.00463867f, 0.124023f, -0.019043f, 0.09375f,
--0.0466309f, 0.0634766f, -0.0742188f, 0.0471191f, -0.114014f, 0.0307617f, -0.153809f,
-0.0307617f, -0.20459f, 0.0307617f, -0.280273f, 0.0534668f, -0.341797f, 0.0761719f,
--0.40332f, 0.117676f, -0.446777f, 0.15918f, -0.490234f, 0.216797f, -0.513916f, 0.274414f,
--0.537598f, 0.34375f, -0.537598f, 0.401367f, -0.537598f, 0.445312f, -0.523926f, 0.489258f,
--0.510254f, 0.518799f, -0.483887f, 0.54834f, -0.45752f, 0.563477f, -0.419678f, 0.578613f,
--0.381836f, 0.578613f, -0.333496f, 0.435059f, -0.323242f, 0.435059f, -0.355469f,
-0.427979f, -0.378418f, 0.420898f, -0.401367f, 0.407715f, -0.415771f, 0.394531f, -0.430176f,
-0.375732f, -0.437012f, 0.356934f, -0.443848f, 0.333496f, -0.443848f, 0.312012f, -0.443848f,
-0.290039f, -0.438721f, 0.268066f, -0.433594f, 0.248291f, -0.41748f, 0.228516f, -0.401367f,
-0.212158f, -0.371582f, 0.195801f, -0.341797f, 0.18457f, -0.292969f, 0.179199f, -0.269531f,
-0.177002f, -0.248779f, 0.174805f, -0.228027f, 0.174805f, -0.210449f, 0.174805f, -0.175293f,
-0.182373f, -0.151367f, 0.189941f, -0.127441f, 0.203613f, -0.112305f, 0.217285f, -0.097168f,
-0.23584f, -0.0905762f, 0.254395f, -0.0839844f, 0.276367f, -0.0839844f, 0.29834f,
--0.0839844f, 0.319824f, -0.0888672f, 0.341309f, -0.09375f, 0.36084f, -0.109619f,
-0.380371f, -0.125488f, 0.396484f, -0.155029f, 0.412598f, -0.18457f, 0.423828f, -0.234375f,
-0.429199f, -0.259766f, 0.431641f, -0.281006f, 0.434082f, -0.302246f, 0.435059f, -0.323242f,
-0.355469f, -0.442871f, 0.330078f, -0.442871f, 0.306641f, -0.434814f, 0.283203f, -0.426758f,
-0.263672f, -0.407227f, 0.244141f, -0.387695f, 0.22876f, -0.354492f, 0.213379f, -0.321289f,
-0.203613f, -0.270508f, 0.199707f, -0.249023f, 0.19751f, -0.230469f, 0.195312f, -0.211914f,
-0.195312f, -0.195801f, 0.195312f, -0.168457f, 0.202393f, -0.147705f, 0.209473f, -0.126953f,
-0.222412f, -0.112793f, 0.235352f, -0.0986328f, 0.253418f, -0.0915527f, 0.271484f,
--0.0844727f, 0.293457f, -0.0844727f, 0.318359f, -0.0844727f, 0.338623f, -0.0922852f,
-0.358887f, -0.100098f, 0.375f, -0.119141f, 0.391113f, -0.138184f, 0.403564f, -0.170654f,
-0.416016f, -0.203125f, 0.424805f, -0.251953f, 0.429199f, -0.276855f, 0.431641f, -0.298584f,
-0.434082f, -0.320312f, 0.434082f, -0.338867f, 0.434082f, -0.390625f, 0.415283f, -0.416748f,
-0.396484f, -0.442871f, 0.355469f, -0.442871f, 0.240723f, -0.445801f, 0.257812f, -0.469727f,
-0.275879f, -0.487061f, 0.293945f, -0.504395f, 0.314941f, -0.515869f, 0.335938f, -0.527344f,
-0.360352f, -0.532715f, 0.384766f, -0.538086f, 0.414062f, -0.538086f, 0.453613f, -0.538086f,
-0.484375f, -0.525879f, 0.515137f, -0.513672f, 0.535889f, -0.491211f, 0.556641f, -0.46875f,
-0.567627f, -0.436768f, 0.578613f, -0.404785f, 0.578613f, -0.365234f, 0.578613f, -0.336426f,
-0.576172f, -0.30835f, 0.57373f, -0.280273f, 0.568359f, -0.251953f, 0.554688f, -0.182617f,
-0.533203f, -0.133057f, 0.511719f, -0.0834961f, 0.481201f, -0.0517578f, 0.450684f,
--0.0200195f, 0.411377f, -0.00512695f, 0.37207f, 0.00976562f, 0.323242f, 0.00976562f,
-0.262207f, 0.00976562f, 0.224121f, -0.015625f, 0.186035f, -0.0410156f, 0.17041f,
--0.0869141f, 0.169434f, -0.0869141f, 0.166992f, -0.0664062f, 0.162598f, -0.0419922f,
-0.158203f, -0.0175781f, 0.153809f, 0.00488281f, 0.114746f, 0.20752f, -0.0219727f,
-0.20752f, 0.0966797f, -0.406738f, 0.100098f, -0.423828f, 0.102295f, -0.435791f, 0.104492f,
--0.447754f, 0.106201f, -0.460205f, 0.10791f, -0.472656f, 0.110107f, -0.488281f, 0.112305f,
--0.503906f, 0.115723f, -0.52832f, 0.25f, -0.52832f, 0.25f, -0.525391f, 0.249023f,
--0.515625f, 0.248047f, -0.505859f, 0.246582f, -0.493408f, 0.245117f, -0.480957f,
-0.243164f, -0.468018f, 0.241211f, -0.455078f, 0.23877f, -0.445801f, 0.438477f, -0.440918f,
-0.440918f, -0.453125f, 0.444092f, -0.466553f, 0.447266f, -0.47998f, 0.450439f, -0.491943f,
-0.453613f, -0.503906f, 0.456543f, -0.513672f, 0.459473f, -0.523438f, 0.461426f, -0.52832f,
-0.593262f, -0.52832f, 0.59082f, -0.52002f, 0.583252f, -0.485352f, 0.575684f, -0.450684f,
-0.563477f, -0.388184f, 0.448242f, 0.20752f, 0.311035f, 0.20752f, 0.352539f, -0.00341797f,
-0.355957f, -0.0195312f, 0.360352f, -0.0385742f, 0.364746f, -0.0576172f, 0.370117f,
--0.0795898f, 0.368164f, -0.0795898f, 0.350586f, -0.0566406f, 0.332031f, -0.0397949f,
-0.313477f, -0.0229492f, 0.292236f, -0.0117188f, 0.270996f, -0.000488281f, 0.246338f,
-0.00488281f, 0.22168f, 0.0102539f, 0.192383f, 0.0102539f, 0.152832f, 0.0102539f,
-0.122559f, -0.00317383f, 0.0922852f, -0.0166016f, 0.0712891f, -0.0402832f, 0.050293f,
--0.0639648f, 0.0395508f, -0.097168f, 0.0288086f, -0.130371f, 0.0288086f, -0.169922f,
-0.0288086f, -0.191895f, 0.0310059f, -0.218506f, 0.0332031f, -0.245117f, 0.0390625f,
--0.275879f, 0.0527344f, -0.345703f, 0.0766602f, -0.395508f, 0.100586f, -0.445312f,
-0.132324f, -0.477051f, 0.164062f, -0.508789f, 0.202393f, -0.523438f, 0.240723f, -0.538086f,
-0.283203f, -0.538086f, 0.31543f, -0.538086f, 0.3396f, -0.532715f, 0.36377f, -0.527344f,
-0.381836f, -0.515625f, 0.399902f, -0.503906f, 0.413086f, -0.485352f, 0.42627f, -0.466797f,
-0.436035f, -0.440918f, 0.25293f, -0.0839844f, 0.278809f, -0.0839844f, 0.302002f,
--0.092041f, 0.325195f, -0.100098f, 0.344727f, -0.119873f, 0.364258f, -0.139648f,
-0.379395f, -0.173096f, 0.394531f, -0.206543f, 0.403809f, -0.257324f, 0.407715f, -0.278809f,
-0.409668f, -0.297363f, 0.411621f, -0.315918f, 0.411621f, -0.332031f, 0.411621f, -0.386719f,
-0.391357f, -0.415527f, 0.371094f, -0.444336f, 0.32666f, -0.444336f, 0.300781f, -0.444336f,
-0.278564f, -0.436768f, 0.256348f, -0.429199f, 0.238037f, -0.410156f, 0.219727f, -0.391113f,
-0.205811f, -0.358643f, 0.191895f, -0.326172f, 0.182617f, -0.275879f, 0.177734f, -0.250488f,
-0.175781f, -0.22876f, 0.173828f, -0.207031f, 0.173828f, -0.188477f, 0.173828f, -0.164551f,
-0.178467f, -0.145264f, 0.183105f, -0.125977f, 0.192627f, -0.112305f, 0.202148f, -0.0986328f,
-0.217041f, -0.0913086f, 0.231934f, -0.0839844f, 0.25293f, -0.0839844f, 0.412109f,
--0.416504f, 0.400879f, -0.418945f, 0.388184f, -0.421387f, 0.375488f, -0.423828f,
-0.356445f, -0.423828f, 0.296387f, -0.423828f, 0.258545f, -0.381348f, 0.220703f, -0.338867f,
-0.203613f, -0.250977f, 0.154297f, 0, 0.0170898f, 0, 0.0957031f, -0.405273f, 0.0991211f,
--0.422363f, 0.102051f, -0.439453f, 0.10498f, -0.456543f, 0.107666f, -0.472656f, 0.110352f,
--0.48877f, 0.112549f, -0.503174f, 0.114746f, -0.517578f, 0.116211f, -0.52832f, 0.24707f,
--0.52832f, 0.245605f, -0.517578f, 0.243896f, -0.50293f, 0.242188f, -0.488281f, 0.240234f,
--0.473145f, 0.238281f, -0.458008f, 0.236084f, -0.444092f, 0.233887f, -0.430176f,
-0.232422f, -0.42041f, 0.234375f, -0.42041f, 0.250977f, -0.450684f, 0.267334f, -0.4729f,
-0.283691f, -0.495117f, 0.301514f, -0.509521f, 0.319336f, -0.523926f, 0.3396f, -0.531006f,
-0.359863f, -0.538086f, 0.384277f, -0.538086f, 0.390137f, -0.538086f, 0.397217f, -0.537354f,
-0.404297f, -0.536621f, 0.411377f, -0.535645f, 0.418457f, -0.534668f, 0.424561f, -0.533447f,
-0.430664f, -0.532227f, 0.43457f, -0.53125f, 0.488281f, -0.163086f, 0.488281f, -0.119629f,
-0.471924f, -0.0871582f, 0.455566f, -0.0546875f, 0.424072f, -0.0332031f, 0.392578f,
--0.0117188f, 0.346924f, -0.000976562f, 0.30127f, 0.00976562f, 0.242676f, 0.00976562f,
-0.144531f, 0.00976562f, 0.0878906f, -0.0249023f, 0.03125f, -0.0595703f, 0.0112305f,
--0.132324f, 0.133789f, -0.149902f, 0.138672f, -0.132324f, 0.147461f, -0.119385f,
-0.15625f, -0.106445f, 0.17041f, -0.0979004f, 0.18457f, -0.0893555f, 0.204834f, -0.0852051f,
-0.225098f, -0.0810547f, 0.252441f, -0.0810547f, 0.276367f, -0.0810547f, 0.296143f,
--0.0847168f, 0.315918f, -0.0883789f, 0.330322f, -0.0964355f, 0.344727f, -0.104492f,
-0.352783f, -0.117188f, 0.36084f, -0.129883f, 0.36084f, -0.147461f, 0.36084f, -0.163086f,
-0.354248f, -0.173096f, 0.347656f, -0.183105f, 0.334229f, -0.190186f, 0.320801f, -0.197266f,
-0.300049f, -0.202881f, 0.279297f, -0.208496f, 0.251465f, -0.214355f, 0.212891f, -0.223145f,
-0.18042f, -0.235352f, 0.147949f, -0.247559f, 0.124512f, -0.266357f, 0.101074f, -0.285156f,
-0.0878906f, -0.311768f, 0.074707f, -0.338379f, 0.074707f, -0.375488f, 0.074707f,
--0.419434f, 0.0930176f, -0.449951f, 0.111328f, -0.480469f, 0.143311f, -0.499756f,
-0.175293f, -0.519043f, 0.218262f, -0.527832f, 0.26123f, -0.536621f, 0.311035f, -0.536621f,
-0.356445f, -0.536621f, 0.392822f, -0.529541f, 0.429199f, -0.522461f, 0.455566f, -0.505859f,
-0.481934f, -0.489258f, 0.498779f, -0.462402f, 0.515625f, -0.435547f, 0.521973f, -0.395996f,
-0.399414f, -0.381836f, 0.391113f, -0.415527f, 0.367188f, -0.430664f, 0.343262f, -0.445801f,
-0.301758f, -0.445801f, 0.280762f, -0.445801f, 0.262451f, -0.443115f, 0.244141f, -0.44043f,
-0.230713f, -0.433594f, 0.217285f, -0.426758f, 0.209473f, -0.415527f, 0.20166f, -0.404297f,
-0.20166f, -0.387207f, 0.20166f, -0.371582f, 0.210938f, -0.361084f, 0.220215f, -0.350586f,
-0.236816f, -0.343018f, 0.253418f, -0.335449f, 0.276367f, -0.329834f, 0.299316f, -0.324219f,
-0.326172f, -0.317871f, 0.360352f, -0.310059f, 0.389893f, -0.298828f, 0.419434f, -0.287598f,
-0.441406f, -0.269775f, 0.463379f, -0.251953f, 0.47583f, -0.226074f, 0.488281f, -0.200195f,
-0.488281f, -0.163086f, 0.273438f, -0.00390625f, 0.255371f, 0.00146484f, 0.232422f,
-0.00463867f, 0.209473f, 0.0078125f, 0.183594f, 0.0078125f, 0.154785f, 0.0078125f,
-0.131348f, 0.000976562f, 0.10791f, -0.00585938f, 0.0913086f, -0.0195312f, 0.074707f,
--0.0332031f, 0.0656738f, -0.0539551f, 0.0566406f, -0.074707f, 0.0566406f, -0.102051f,
-0.0566406f, -0.124023f, 0.0593262f, -0.144775f, 0.0620117f, -0.165527f, 0.0644531f,
--0.178711f, 0.114258f, -0.435547f, 0.0419922f, -0.435547f, 0.0600586f, -0.52832f,
-0.13916f, -0.52832f, 0.206055f, -0.652344f, 0.291992f, -0.652344f, 0.268555f, -0.52832f,
-0.367188f, -0.52832f, 0.350098f, -0.435547f, 0.25f, -0.435547f, 0.199219f, -0.174316f,
-0.197266f, -0.164551f, 0.195312f, -0.150635f, 0.193359f, -0.136719f, 0.193848f, -0.126953f,
-0.194824f, -0.106445f, 0.206299f, -0.0964355f, 0.217773f, -0.0864258f, 0.236328f,
--0.0864258f, 0.248047f, -0.0864258f, 0.26001f, -0.0881348f, 0.271973f, -0.0898438f,
-0.289062f, -0.0927734f, 0.25f, -0.52832f, 0.192383f, -0.237793f, 0.19043f, -0.228516f,
-0.188232f, -0.217285f, 0.186035f, -0.206055f, 0.184082f, -0.194824f, 0.182129f, -0.183594f,
-0.180908f, -0.173828f, 0.179688f, -0.164062f, 0.179688f, -0.157227f, 0.179688f, -0.126465f,
-0.198242f, -0.110352f, 0.216797f, -0.0942383f, 0.253906f, -0.0942383f, 0.276855f,
--0.0942383f, 0.300049f, -0.104004f, 0.323242f, -0.11377f, 0.343018f, -0.131836f,
-0.362793f, -0.149902f, 0.377441f, -0.175537f, 0.39209f, -0.201172f, 0.397949f, -0.232422f,
-0.455566f, -0.52832f, 0.593262f, -0.52832f, 0.512207f, -0.112793f, 0.508789f, -0.0961914f,
-0.505615f, -0.0778809f, 0.502441f, -0.0595703f, 0.5f, -0.0432129f, 0.497559f, -0.0268555f,
-0.49585f, -0.0151367f, 0.494141f, -0.00341797f, 0.493652f, 0, 0.362793f, 0, 0.362793f,
--0.00244141f, 0.364014f, -0.0131836f, 0.365234f, -0.0239258f, 0.366943f, -0.0378418f,
-0.368652f, -0.0517578f, 0.370605f, -0.0661621f, 0.372559f, -0.0805664f, 0.374512f,
--0.090332f, 0.373047f, -0.090332f, 0.358398f, -0.0698242f, 0.34082f, -0.0517578f,
-0.323242f, -0.0336914f, 0.30127f, -0.0200195f, 0.279297f, -0.00634766f, 0.251953f,
-0.00146484f, 0.224609f, 0.00927734f, 0.190918f, 0.00927734f, 0.116699f, 0.00927734f,
-0.0791016f, -0.0263672f, 0.0415039f, -0.0620117f, 0.0415039f, -0.129395f, 0.0415039f,
--0.138184f, 0.0427246f, -0.149414f, 0.0439453f, -0.160645f, 0.0454102f, -0.171631f,
-0.046875f, -0.182617f, 0.048584f, -0.192871f, 0.050293f, -0.203125f, 0.0517578f,
--0.209473f, 0.11377f, -0.52832f, 0.303711f, 0, 0.139648f, 0, 0.0537109f, -0.52832f,
-0.194824f, -0.52832f, 0.229492f, -0.23291f, 0.231445f, -0.218262f, 0.23291f, -0.200684f,
-0.234375f, -0.183105f, 0.23584f, -0.165527f, 0.237305f, -0.147949f, 0.238525f, -0.131348f,
-0.239746f, -0.114746f, 0.240234f, -0.101562f, 0.245605f, -0.114258f, 0.252686f, -0.130859f,
-0.259766f, -0.147461f, 0.267822f, -0.165039f, 0.275879f, -0.182617f, 0.28418f, -0.199707f,
-0.29248f, -0.216797f, 0.299805f, -0.231445f, 0.454102f, -0.52832f, 0.601562f, -0.52832f,
-0.589355f, 0, 0.444336f, 0, 0.42334f, -0.322266f, 0.422363f, -0.337402f, 0.422119f,
--0.356934f, 0.421875f, -0.376465f, 0.421387f, -0.393555f, 0.420898f, -0.413574f,
-0.420898f, -0.43457f, 0.413086f, -0.413574f, 0.404785f, -0.393555f, 0.397949f, -0.376465f,
-0.389893f, -0.356689f, 0.381836f, -0.336914f, 0.374512f, -0.321289f, 0.227051f, 0,
-0.0820312f, 0, 0.0483398f, -0.52832f, 0.174316f, -0.52832f, 0.180664f, -0.217773f,
-0.181152f, -0.20459f, 0.181152f, -0.188232f, 0.181152f, -0.171875f, 0.181152f, -0.157715f,
-0.181152f, -0.124512f, 0.1875f, -0.141113f, 0.194336f, -0.157715f, 0.200195f, -0.171875f,
-0.206787f, -0.188232f, 0.213379f, -0.20459f, 0.219727f, -0.217773f, 0.363281f, -0.52832f,
-0.510254f, -0.52832f, 0.530762f, -0.217773f, 0.531738f, -0.205078f, 0.531982f, -0.188965f,
-0.532227f, -0.172852f, 0.532715f, -0.158691f, 0.533203f, -0.14209f, 0.533203f, -0.124512f,
-0.540039f, -0.14209f, 0.546875f, -0.158691f, 0.552734f, -0.172852f, 0.559082f, -0.188965f,
-0.56543f, -0.205078f, 0.570801f, -0.217773f, 0.701172f, -0.52832f, 0.831055f, -0.52832f,
-0.353516f, 0, 0.262695f, -0.187012f, 0.103027f, 0, -0.0439453f, 0, 0.204102f, -0.274414f,
-0.0678711f, -0.52832f, 0.210449f, -0.52832f, 0.294922f, -0.358887f, 0.439453f, -0.52832f,
-0.589844f, -0.52832f, 0.354004f, -0.271973f, 0.497559f, 0, 0.27832f, 0.027832f, 0.250977f,
-0.0703125f, 0.226318f, 0.103516f, 0.20166f, 0.136719f, 0.174561f, 0.159912f, 0.147461f,
-0.183105f, 0.115723f, 0.195312f, 0.0839844f, 0.20752f, 0.0429688f, 0.20752f, 0.0175781f,
-0.20752f, -0.00268555f, 0.205322f, -0.0229492f, 0.203125f, -0.0415039f, 0.19873f,
--0.0229492f, 0.103027f, -0.0141602f, 0.10498f, -0.00219727f, 0.106201f, 0.00976562f,
-0.107422f, 0.0195312f, 0.107422f, 0.0380859f, 0.107422f, 0.0539551f, 0.102539f, 0.0698242f,
-0.0976562f, 0.0849609f, 0.0864258f, 0.100098f, 0.0751953f, 0.114746f, 0.0568848f,
-0.129395f, 0.0385742f, 0.144531f, 0.0117188f, 0.158203f, -0.0117188f, 0.0546875f,
--0.52832f, 0.196777f, -0.52832f, 0.231445f, -0.285645f, 0.232422f, -0.280273f, 0.234131f,
--0.267578f, 0.23584f, -0.254883f, 0.237549f, -0.238525f, 0.239258f, -0.222168f, 0.241211f,
--0.204102f, 0.243164f, -0.186035f, 0.244629f, -0.169678f, 0.246094f, -0.15332f, 0.247314f,
--0.140625f, 0.248535f, -0.12793f, 0.248535f, -0.122559f, 0.250977f, -0.12793f, 0.256592f,
--0.140381f, 0.262207f, -0.152832f, 0.269775f, -0.168701f, 0.277344f, -0.18457f, 0.285645f,
--0.202148f, 0.293945f, -0.219727f, 0.301514f, -0.23584f, 0.309082f, -0.251953f, 0.31543f,
--0.264893f, 0.321777f, -0.277832f, 0.324707f, -0.283691f, 0.451172f, -0.52832f, 0.597656f,
--0.52832f, -0.0170898f, 0, 0.00146484f, -0.097168f, 0.320312f, -0.429199f, 0.0859375f,
--0.429199f, 0.105469f, -0.52832f, 0.500488f, -0.52832f, 0.481445f, -0.430176f, 0.164062f,
--0.100098f, 0.440918f, -0.100098f, 0.421387f, 0
-};
-
-const unsigned char LiberationSanskBoldItalicVerbs[] = {
-6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6,
-0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 0, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1,
-1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 1,
-1, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 5, 0, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5,
-6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6,
-0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 1, 1,
-1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1,
-1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0,
-1, 1, 1, 5, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5,
-6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
-2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6
-};
-
-const unsigned LiberationSanskBoldItalicCharCodes[] = {
-32, 33,
-44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 65, 66, 67, 68, 69, 70,
-71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 91, 92,
-93, 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
-112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122
-};
-
-const SkFixed LiberationSanskBoldItalicWidths[] = {
-0x00004720, 0x00005540, 0x00004720, 0x00005540, 0x00004720, 0x00004720, 0x00008e60,
-0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60, 0x00008e60,
-0x00008e60, 0x00005540, 0x0000b8e0, 0x0000b8e0, 0x0000b8e0, 0x0000b8e0, 0x0000aac0,
-0x00009c60, 0x0000c720, 0x0000b8e0, 0x00004720, 0x0000b8e0, 0x00009c60, 0x0000d540,
-0x0000b8e0, 0x0000c720, 0x0000aac0, 0x0000c720, 0x0000b8e0, 0x0000aac0, 0x00009c60,
-0x0000b8e0, 0x0000f1a0, 0x0000aac0, 0x0000aac0, 0x00009c60, 0x00005540, 0x00004720,
-0x00005540, 0x00008e60, 0x00008e60, 0x00009c60, 0x00008e60, 0x00009c60, 0x00008e60,
-0x00005540, 0x00009c60, 0x00009c60, 0x00004720, 0x00004720, 0x00008e60, 0x00004720,
-0x0000e3a0, 0x00009c60, 0x00009c60, 0x00009c60, 0x00009c60, 0x000063a0, 0x00008e60,
-0x00005540, 0x00009c60, 0x00008e60, 0x0000c720, 0x00008e60, 0x00008e60, 0x00008000
-};
-
-const int LiberationSanskBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(LiberationSanskBoldItalicCharCodes);
-
-const SkPaint::FontMetrics LiberationSanskBoldItalicMetrics = {
-0x00000003, -1.02979f, -0.905273f, 0.211914f, 0.303223f, 0.0327148f, 1.3374f, 0, -0.208984f,
-1.12842f, 0.537598f, 0, 0.10498f, 0.105957f
-};
-
-const SkScalar HiraginoMaruGothicProkNormalPoints[] = {
-0.109f, -0.22f, 0.109f, -0.197f, 0.128f, -0.186f, 0.149f, -0.186f, 0.169f, -0.186f,
-0.188f, -0.197f, 0.189f, -0.22f, 0.203f, -0.732f, 0.204f, -0.76f, 0.182f, -0.778f,
-0.15f, -0.778f, 0.117f, -0.778f, 0.095f, -0.76f, 0.095f, -0.732f, 0.149f, -0.125f,
-0.11f, -0.125f, 0.08f, -0.098f, 0.08f, -0.056f, 0.08f, -0.014f, 0.11f, 0.013f, 0.149f,
-0.013f, 0.186f, 0.013f, 0.218f, -0.014f, 0.218f, -0.056f, 0.218f, -0.098f, 0.186f,
--0.125f, 0.149f, -0.125f, 0.291f, -0.684f, 0.291f, -0.028f, 0.291f, -0.001f, 0.312f,
-0.013f, 0.339f, 0.013f, 0.366f, 0.013f, 0.387f, -0.001f, 0.387f, -0.028f, 0.387f,
--0.684f, 0.614f, -0.684f, 0.637f, -0.684f, 0.652f, -0.704f, 0.652f, -0.727f, 0.652f,
--0.751f, 0.638f, -0.772f, 0.614f, -0.772f, 0.063f, -0.772f, 0.039f, -0.772f, 0.025f,
--0.751f, 0.025f, -0.727f, 0.025f, -0.704f, 0.039f, -0.684f, 0.064f, -0.684f, 0.409f,
--0.347f, 0.302f, -0.345f, 0.25f, -0.339f, 0.195f, -0.324f, 0.1f, -0.298f, 0.044f,
--0.238f, 0.044f, -0.144f, 0.044f, -0.041f, 0.111f, 0.021f, 0.221f, 0.021f, 0.32f,
-0.021f, 0.373f, -0.018f, 0.411f, -0.061f, 0.412f, -0.041f, 0.414f, -0.023f, 0.417f,
--0.011f, 0.421f, 0.007f, 0.439f, 0.013f, 0.459f, 0.013f, 0.462f, 0.013f, 0.465f,
-0.013f, 0.468f, 0.013f, 0.493f, 0.011f, 0.508f, -0.003f, 0.508f, -0.019f, 0.508f,
--0.022f, 0.507f, -0.026f, 0.506f, -0.029f, 0.5f, -0.048f, 0.495f, -0.082f, 0.495f,
--0.117f, 0.495f, -0.39f, 0.495f, -0.508f, 0.429f, -0.561f, 0.295f, -0.561f, 0.214f,
--0.561f, 0.169f, -0.544f, 0.134f, -0.517f, 0.111f, -0.499f, 0.085f, -0.47f, 0.075f,
--0.439f, 0.074f, -0.435f, 0.073f, -0.431f, 0.073f, -0.427f, 0.073f, -0.409f, 0.087f,
--0.395f, 0.106f, -0.389f, 0.113f, -0.386f, 0.121f, -0.385f, 0.129f, -0.385f, 0.146f,
--0.385f, 0.161f, -0.392f, 0.168f, -0.411f, 0.185f, -0.457f, 0.221f, -0.485f, 0.294f,
--0.485f, 0.373f, -0.485f, 0.409f, -0.456f, 0.409f, -0.39f, 0.409f, -0.208f, 0.409f,
--0.17f, 0.402f, -0.151f, 0.383f, -0.127f, 0.351f, -0.087f, 0.299f, -0.056f, 0.236f,
--0.056f, 0.176f, -0.056f, 0.136f, -0.091f, 0.136f, -0.143f, 0.136f, -0.191f, 0.157f,
--0.222f, 0.197f, -0.242f, 0.237f, -0.262f, 0.292f, -0.272f, 0.409f, -0.275f, 0.045f,
--0.268f, 0.045f, -0.096f, 0.136f, 0.023f, 0.298f, 0.023f, 0.434f, 0.023f, 0.487f,
--0.049f, 0.514f, -0.118f, 0.517f, -0.125f, 0.518f, -0.13f, 0.518f, -0.136f, 0.518f,
--0.154f, 0.504f, -0.166f, 0.486f, -0.17f, 0.479f, -0.173f, 0.472f, -0.174f, 0.465f,
--0.174f, 0.449f, -0.174f, 0.435f, -0.166f, 0.428f, -0.147f, 0.409f, -0.093f, 0.378f,
--0.055f, 0.3f, -0.055f, 0.194f, -0.055f, 0.138f, -0.138f, 0.138f, -0.269f, 0.138f,
--0.396f, 0.195f, -0.484f, 0.299f, -0.484f, 0.375f, -0.484f, 0.405f, -0.445f, 0.424f,
--0.394f, 0.431f, -0.377f, 0.444f, -0.371f, 0.459f, -0.371f, 0.466f, -0.371f, 0.474f,
--0.372f, 0.481f, -0.374f, 0.496f, -0.38f, 0.511f, -0.392f, 0.511f, -0.411f, 0.511f,
--0.415f, 0.51f, -0.421f, 0.508f, -0.426f, 0.483f, -0.489f, 0.429f, -0.562f, 0.297f,
--0.562f, 0.133f, -0.562f, 0.045f, -0.439f, 0.045f, -0.268f, 0.486f, -0.253f, 0.517f,
--0.253f, 0.536f, -0.272f, 0.536f, -0.308f, 0.536f, -0.311f, 0.536f, -0.313f, 0.536f,
--0.316f, 0.526f, -0.447f, 0.444f, -0.561f, 0.298f, -0.561f, 0.135f, -0.561f, 0.045f,
--0.44f, 0.045f, -0.267f, 0.045f, -0.094f, 0.14f, 0.022f, 0.304f, 0.022f, 0.434f,
-0.022f, 0.492f, -0.044f, 0.524f, -0.11f, 0.528f, -0.116f, 0.529f, -0.122f, 0.529f,
--0.128f, 0.529f, -0.146f, 0.515f, -0.158f, 0.498f, -0.163f, 0.491f, -0.165f, 0.484f,
--0.167f, 0.477f, -0.167f, 0.463f, -0.167f, 0.45f, -0.16f, 0.441f, -0.142f, 0.417f,
--0.089f, 0.377f, -0.053f, 0.305f, -0.053f, 0.197f, -0.053f, 0.136f, -0.13f, 0.134f,
--0.253f, 0.137f, -0.326f, 0.15f, -0.424f, 0.202f, -0.488f, 0.298f, -0.488f, 0.39f,
--0.488f, 0.433f, -0.415f, 0.445f, -0.344f, 0.445f, -0.342f, 0.445f, -0.34f, 0.445f,
--0.339f, 0.445f, -0.33f, 0.441f, -0.326f, 0.43f, -0.326f, 0.138f, -0.547f, 0.053f,
--0.547f, 0.028f, -0.547f, 0.017f, -0.529f, 0.017f, -0.506f, 0.017f, -0.483f, 0.029f,
--0.468f, 0.053f, -0.468f, 0.138f, -0.468f, 0.138f, -0.027f, 0.138f, 0, 0.156f, 0.013f,
-0.183f, 0.013f, 0.209f, 0.013f, 0.228f, 0, 0.228f, -0.027f, 0.228f, -0.468f, 0.348f,
--0.468f, 0.372f, -0.468f, 0.385f, -0.483f, 0.385f, -0.506f, 0.385f, -0.53f, 0.373f,
--0.547f, 0.348f, -0.547f, 0.228f, -0.547f, 0.228f, -0.608f, 0.228f, -0.68f, 0.256f,
--0.7f, 0.293f, -0.7f, 0.314f, -0.7f, 0.331f, -0.697f, 0.348f, -0.69f, 0.354f, -0.688f,
-0.359f, -0.687f, 0.364f, -0.687f, 0.382f, -0.687f, 0.396f, -0.7f, 0.402f, -0.717f,
-0.405f, -0.723f, 0.406f, -0.729f, 0.406f, -0.736f, 0.406f, -0.751f, 0.398f, -0.766f,
-0.379f, -0.772f, 0.351f, -0.781f, 0.326f, -0.783f, 0.293f, -0.783f, 0.217f, -0.783f,
-0.138f, -0.748f, 0.138f, -0.619f, 0.531f, -0.366f, 0.531f, -0.489f, 0.467f, -0.561f,
-0.348f, -0.561f, 0.253f, -0.561f, 0.193f, -0.516f, 0.158f, -0.445f, 0.159f, -0.464f,
-0.162f, -0.474f, 0.162f, -0.487f, 0.162f, -0.514f, 0.162f, -0.54f, 0.144f, -0.553f,
-0.118f, -0.553f, 0.09f, -0.553f, 0.071f, -0.54f, 0.071f, -0.514f, 0.071f, -0.027f,
-0.071f, 0, 0.089f, 0.013f, 0.117f, 0.013f, 0.143f, 0.013f, 0.162f, 0, 0.162f, -0.027f,
-0.162f, -0.307f, 0.162f, -0.346f, 0.172f, -0.375f, 0.197f, -0.409f, 0.231f, -0.456f,
-0.276f, -0.48f, 0.33f, -0.48f, 0.405f, -0.48f, 0.439f, -0.432f, 0.439f, -0.347f,
-0.439f, -0.027f, 0.439f, 0, 0.458f, 0.013f, 0.485f, 0.013f, 0.511f, 0.013f, 0.531f,
-0, 0.531f, -0.027f, 0.16f, -0.036f, 0.16f, -0.054f, 0.159f, -0.075f, 0.155f, -0.094f,
-0.189f, -0.024f, 0.246f, 0.022f, 0.339f, 0.022f, 0.488f, 0.022f, 0.578f, -0.096f,
-0.578f, -0.274f, 0.578f, -0.452f, 0.493f, -0.561f, 0.343f, -0.561f, 0.246f, -0.561f,
-0.191f, -0.514f, 0.156f, -0.443f, 0.159f, -0.46f, 0.16f, -0.484f, 0.16f, -0.498f,
-0.16f, -0.516f, 0.16f, -0.541f, 0.141f, -0.553f, 0.116f, -0.553f, 0.088f, -0.553f,
-0.071f, -0.54f, 0.071f, -0.514f, 0.071f, 0.184f, 0.071f, 0.209f, 0.088f, 0.223f,
-0.116f, 0.223f, 0.143f, 0.223f, 0.16f, 0.209f, 0.16f, 0.184f, 0.33f, -0.483f, 0.431f,
--0.483f, 0.486f, -0.402f, 0.486f, -0.272f, 0.486f, -0.143f, 0.429f, -0.057f, 0.328f,
--0.057f, 0.223f, -0.057f, 0.158f, -0.147f, 0.158f, -0.271f, 0.158f, -0.394f, 0.22f,
--0.483f, 0.33f, -0.483f, 0.085f, -0.027f, 0.085f, 0, 0.104f, 0.013f, 0.132f, 0.013f,
-0.157f, 0.013f, 0.177f, 0, 0.177f, -0.027f, 0.177f, -0.303f, 0.178f, -0.345f, 0.193f,
--0.382f, 0.219f, -0.414f, 0.244f, -0.446f, 0.277f, -0.468f, 0.32f, -0.469f, 0.341f,
--0.469f, 0.354f, -0.466f, 0.368f, -0.463f, 0.371f, -0.462f, 0.374f, -0.462f, 0.377f,
--0.462f, 0.398f, -0.462f, 0.412f, -0.48f, 0.416f, -0.501f, 0.417f, -0.507f, 0.418f,
--0.513f, 0.418f, -0.518f, 0.418f, -0.537f, 0.409f, -0.551f, 0.386f, -0.554f, 0.372f,
--0.557f, 0.361f, -0.559f, 0.346f, -0.559f, 0.339f, -0.559f, 0.332f, -0.559f, 0.324f,
--0.558f, 0.238f, -0.555f, 0.187f, -0.493f, 0.171f, -0.445f, 0.173f, -0.461f, 0.177f,
--0.478f, 0.177f, -0.492f, 0.177f, -0.514f, 0.177f, -0.54f, 0.157f, -0.553f, 0.132f,
--0.553f, 0.104f, -0.553f, 0.085f, -0.54f, 0.085f, -0.514f, 0.286f, -0.236f, 0.377f,
--0.218f, 0.403f, -0.191f, 0.403f, -0.142f, 0.403f, -0.091f, 0.351f, -0.056f, 0.271f,
--0.056f, 0.192f, -0.056f, 0.151f, -0.085f, 0.133f, -0.143f, 0.127f, -0.162f, 0.109f,
--0.17f, 0.09f, -0.17f, 0.086f, -0.17f, 0.081f, -0.169f, 0.076f, -0.168f, 0.057f,
--0.164f, 0.04f, -0.15f, 0.04f, -0.13f, 0.04f, -0.126f, 0.041f, -0.122f, 0.042f, -0.117f,
-0.068f, -0.028f, 0.143f, 0.023f, 0.271f, 0.023f, 0.411f, 0.023f, 0.493f, -0.048f,
-0.493f, -0.144f, 0.493f, -0.249f, 0.441f, -0.287f, 0.311f, -0.314f, 0.249f, -0.327f,
-0.165f, -0.345f, 0.146f, -0.365f, 0.146f, -0.411f, 0.146f, -0.453f, 0.184f, -0.486f,
-0.265f, -0.486f, 0.322f, -0.486f, 0.366f, -0.463f, 0.379f, -0.418f, 0.384f, -0.399f,
-0.402f, -0.391f, 0.42f, -0.391f, 0.425f, -0.391f, 0.431f, -0.392f, 0.436f, -0.393f,
-0.454f, -0.398f, 0.471f, -0.411f, 0.471f, -0.43f, 0.471f, -0.434f, 0.47f, -0.438f,
-0.469f, -0.442f, 0.444f, -0.515f, 0.373f, -0.562f, 0.262f, -0.562f, 0.133f, -0.562f,
-0.055f, -0.5f, 0.055f, -0.409f, 0.055f, -0.314f, 0.106f, -0.271f, 0.229f, -0.247f,
-0.068f, -0.174f, 0.068f, -0.052f, 0.133f, 0.022f, 0.251f, 0.022f, 0.351f, 0.022f,
-0.409f, -0.029f, 0.44f, -0.099f, 0.437f, -0.083f, 0.434f, -0.063f, 0.434f, -0.052f,
-0.434f, -0.024f, 0.434f, 0.001f, 0.453f, 0.013f, 0.48f, 0.013f, 0.506f, 0.013f, 0.524f,
-0, 0.524f, -0.027f, 0.524f, -0.513f, 0.524f, -0.54f, 0.505f, -0.553f, 0.479f, -0.553f,
-0.452f, -0.553f, 0.433f, -0.54f, 0.433f, -0.513f, 0.433f, -0.235f, 0.433f, -0.196f,
-0.423f, -0.165f, 0.399f, -0.131f, 0.365f, -0.084f, 0.322f, -0.059f, 0.269f, -0.059f,
-0.195f, -0.059f, 0.16f, -0.107f, 0.16f, -0.193f, 0.16f, -0.513f, 0.16f, -0.54f, 0.141f,
--0.553f, 0.114f, -0.553f, 0.087f, -0.553f, 0.068f, -0.54f, 0.068f, -0.513f, 0.307f,
--0.194f, 0.296f, -0.165f, 0.282f, -0.127f, 0.274f, -0.096f, 0.265f, -0.127f, 0.256f,
--0.164f, 0.244f, -0.196f, 0.118f, -0.528f, 0.111f, -0.546f, 0.096f, -0.553f, 0.08f,
--0.553f, 0.073f, -0.553f, 0.066f, -0.552f, 0.059f, -0.55f, 0.041f, -0.544f, 0.026f,
--0.529f, 0.026f, -0.511f, 0.026f, -0.506f, 0.027f, -0.5f, 0.029f, -0.495f, 0.231f,
--0.005f, 0.203f, 0.065f, 0.185f, 0.111f, 0.164f, 0.149f, 0.121f, 0.149f, 0.103f,
-0.149f, 0.085f, 0.142f, 0.071f, 0.136f, 0.064f, 0.133f, 0.058f, 0.132f, 0.052f, 0.132f,
-0.035f, 0.132f, 0.022f, 0.143f, 0.015f, 0.16f, 0.012f, 0.168f, 0.01f, 0.175f, 0.01f,
-0.183f, 0.01f, 0.198f, 0.018f, 0.212f, 0.038f, 0.219f, 0.061f, 0.228f, 0.085f, 0.232f,
-0.11f, 0.232f, 0.208f, 0.232f, 0.249f, 0.175f, 0.284f, 0.089f, 0.52f, -0.496f, 0.522f,
--0.502f, 0.523f, -0.508f, 0.523f, -0.513f, 0.523f, -0.531f, 0.509f, -0.545f, 0.49f,
--0.55f, 0.484f, -0.551f, 0.478f, -0.552f, 0.472f, -0.552f, 0.455f, -0.552f, 0.44f,
--0.545f, 0.433f, -0.526f, 0.88f, -0.329f, 0.905f, -0.329f, 0.919f, -0.345f, 0.919f,
--0.372f, 0.919f, -0.398f, 0.905f, -0.417f, 0.879f, -0.417f, 0.12f, -0.417f, 0.094f,
--0.417f, 0.08f, -0.398f, 0.08f, -0.372f, 0.08f, -0.345f, 0.094f, -0.329f, 0.119f,
--0.329f
-};
-
-const unsigned char HiraginoMaruGothicProkNormalVerbs[] = {
-6, 0, 4, 4, 1, 4, 4, 5, 0, 4, 4, 4, 4, 5, 6, 0, 1, 4, 4, 1, 1, 4, 4, 1, 4, 4, 5,
-6, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 0, 4, 4, 4,
-4, 4, 5, 6, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 0, 4, 4, 4,
-4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 0, 4, 4, 4, 4, 5, 6, 0, 1, 4, 4, 1, 1, 4, 4, 1, 1,
-4, 4, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 0, 4, 4, 4, 1, 4, 4, 1, 4, 4, 1, 4, 4,
-4, 1, 4, 4, 5, 6, 0, 4, 4, 4, 4, 4, 4, 1, 4, 4, 1, 4, 4, 5, 0, 4, 4, 4, 4, 5, 6,
-0, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 5, 6, 0, 4, 4, 4, 4, 4, 4,
-4, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 6, 0, 4, 4, 4, 1, 4, 4, 1, 4, 4,
-1, 4, 4, 4, 1, 4, 4, 5, 6, 0, 4, 4, 1, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4,
-1, 4, 4, 4, 4, 5, 6, 0, 4, 4, 1, 4, 4, 5, 6
-};
-
-const unsigned HiraginoMaruGothicProkNormalCharCodes[] = {
-32, 33, 84, 97, 99, 101, 102, 110, 112,
-114, 115, 117, 121, 12540
-};
-
-const SkFixed HiraginoMaruGothicProkNormalWidths[] = {
-0x0000553f, 0x00004d4f, 0x0000ad0e, 0x000092b0, 0x00008dd2, 0x000092f1, 0x00006666,
-0x00009999, 0x00009fbe, 0x00006e97, 0x000088f5, 0x000098d4, 0x00008d0e, 0x00010000
-};
-
-const int HiraginoMaruGothicProkNormalCharCodesCount = (int) SK_ARRAY_COUNT(HiraginoMaruGothicProkNormalCharCodes);
-
-const SkPaint::FontMetrics HiraginoMaruGothicProkNormalMetrics = {
-0x00004f0f, -1.273f, -0.880002f, 0.12f, 0.4f, 0.500001f, 1.673f, 7.89174e-34f, -0.393f,
-1.28f, 0.576f, 5.17319e-29f, 0.077f, 0.06f
-};
-
-const SkScalar PapyruskNormalPoints[] = {
-0.172852f, -0.257812f, 0.166016f, -0.250977f, 0.155762f, -0.228027f, 0.152344f, -0.221191f,
-0.13623f, -0.210938f, 0.126953f, -0.21582f, 0.103027f, -0.213867f, 0.0952148f, -0.219238f,
-0.0859375f, -0.223145f, 0.0859375f, -0.230957f, 0.0869141f, -0.234863f, 0.105957f,
--0.26416f, 0.11084f, -0.312988f, 0.11377f, -0.332031f, 0.125f, -0.332031f, 0.128906f,
--0.338379f, 0.128906f, -0.344238f, 0.128906f, -0.349609f, 0.124023f, -0.356934f,
-0.11084f, -0.354004f, 0.10791f, -0.395996f, 0.119141f, -0.428223f, 0.115234f, -0.440918f,
-0.11084f, -0.449219f, 0.108887f, -0.506836f, 0.10791f, -0.52002f, 0.103027f, -0.520996f,
-0.103027f, -0.530762f, 0.118164f, -0.529785f, 0.12207f, -0.535156f, 0.116211f, -0.544434f,
-0.103027f, -0.546875f, 0.103027f, -0.551758f, 0.104004f, -0.583008f, 0.0991211f,
--0.61084f, 0.101074f, -0.623047f, 0.0888672f, -0.631836f, 0.0834961f, -0.639648f,
-0.078125f, -0.647461f, 0.078125f, -0.657227f, 0.078125f, -0.675781f, 0.100586f, -0.691895f,
-0.123047f, -0.708008f, 0.146973f, -0.708008f, 0.155762f, -0.707031f, 0.161133f, -0.713867f,
-0.171387f, -0.708008f, 0.172852f, -0.703125f, 0.169922f, -0.688965f, 0.167969f, -0.666016f,
-0.163086f, -0.654785f, 0.167969f, -0.626953f, 0.160156f, -0.625f, 0.163086f, -0.601074f,
-0.166992f, -0.596191f, 0.166992f, -0.584961f, 0.168945f, -0.570801f, 0.166016f, -0.546875f,
-0.167969f, -0.535156f, 0.160156f, -0.509766f, 0.161133f, -0.503906f, 0.164062f, -0.500977f,
-0.163086f, -0.490234f, 0.15918f, -0.421875f, 0.154785f, -0.404785f, 0.155762f, -0.391113f,
-0.165039f, -0.374023f, 0.164062f, -0.355957f, 0.163086f, -0.333008f, 0.161621f, -0.330566f,
-0.154785f, -0.324219f, 0.167969f, -0.294922f, 0.170898f, -0.268066f, 0.194824f, -0.0390625f,
-0.190918f, -0.0322266f, 0.183105f, -0.0170898f, 0.152832f, 0.00390625f, 0.14502f,
-0.0141602f, 0.129883f, 0.00683594f, 0.117188f, -0.00976562f, 0.0981445f, -0.0268555f,
-0.0878906f, -0.0439453f, 0.0854492f, -0.0454102f, 0.0771484f, -0.046875f, 0.0668945f,
--0.0498047f, 0.0683594f, -0.059082f, 0.0742188f, -0.0620117f, 0.10498f, -0.0810547f,
-0.12207f, -0.097168f, 0.12793f, -0.100098f, 0.132812f, -0.101074f, 0.145996f, -0.0888672f,
-0.181152f, -0.0639648f, 0.192383f, -0.0566406f, 0.194824f, -0.0390625f, 0.698242f,
--0.0458984f, 0.672852f, -0.0239258f, 0.665039f, -0.0078125f, 0.658203f, -0.012207f,
-0.651855f, -0.00878906f, 0.645996f, 0.00195312f, 0.619141f, 0.0141602f, 0.617188f,
-0.012207f, 0.605957f, 0.00878906f, 0.60498f, -0.00390625f, 0.606934f, -0.0161133f,
-0.616211f, -0.0332031f, 0.612793f, -0.0478516f, 0.615234f, -0.0600586f, 0.620117f,
--0.0888672f, 0.626953f, -0.11377f, 0.623047f, -0.145996f, 0.62207f, -0.155762f, 0.634766f,
--0.165039f, 0.635254f, -0.169922f, 0.635254f, -0.177246f, 0.635254f, -0.191406f,
-0.62793f, -0.208008f, 0.63623f, -0.233887f, 0.625977f, -0.243164f, 0.631836f, -0.269043f,
-0.626953f, -0.271973f, 0.629883f, -0.354004f, 0.624023f, -0.358887f, 0.619141f, -0.378906f,
-0.615234f, -0.375f, 0.606445f, -0.375f, 0.603271f, -0.373535f, 0.600098f, -0.37207f,
-0.594238f, -0.365234f, 0.582031f, -0.352051f, 0.562988f, -0.359863f, 0.543457f, -0.354004f,
-0.540039f, -0.354004f, 0.540527f, -0.354004f, 0.527832f, -0.355957f, 0.514648f, -0.366211f,
-0.504883f, -0.366211f, 0.503418f, -0.366211f, 0.502686f, -0.365967f, 0.501953f, -0.365723f,
-0.500977f, -0.365234f, 0.450195f, -0.36084f, 0.398926f, -0.367188f, 0.356934f, -0.36377f,
-0.335938f, -0.369141f, 0.304199f, -0.359863f, 0.254883f, -0.365234f, 0.242188f, -0.36377f,
-0.227051f, -0.375f, 0.222168f, -0.362793f, 0.162109f, -0.36377f, 0.149902f, -0.352051f,
-0.149902f, -0.341797f, 0.155762f, -0.303223f, 0.157227f, -0.297852f, 0.157227f, -0.287109f,
-0.157227f, -0.277344f, 0.151855f, -0.268066f, 0.154785f, -0.237793f, 0.147949f, -0.233398f,
-0.146484f, -0.229248f, 0.14502f, -0.225098f, 0.14502f, -0.216797f, 0.148926f, -0.210449f,
-0.15918f, -0.208008f, 0.160156f, -0.187012f, 0.160156f, -0.123047f, 0.160156f, -0.120117f,
-0.161133f, -0.10791f, 0.161133f, -0.103516f, 0.154785f, -0.0991211f, 0.155762f, -0.0888672f,
-0.163086f, -0.059082f, 0.164062f, -0.0488281f, 0.164062f, -0.0273438f, 0.144043f,
--0.0170898f, 0.119141f, -0.00488281f, 0.097168f, 0.0078125f, 0.0839844f, 0.0141602f,
-0.0810547f, 0.00976562f, 0.0761719f, 0.00976562f, 0.0708008f, -0.000976562f, 0.0708008f,
--0.00976562f, 0.0708008f, -0.0200195f, 0.0732422f, -0.0239258f, 0.0839844f, -0.0488281f,
-0.0888672f, -0.065918f, 0.0961914f, -0.0688477f, 0.097168f, -0.0849609f, 0.0888672f,
--0.0927734f, 0.0961914f, -0.106445f, 0.0961914f, -0.108887f, 0.0961914f, -0.111328f,
-0.0888672f, -0.124023f, 0.0878906f, -0.132812f, 0.0917969f, -0.213867f, 0.0869141f,
--0.23584f, 0.0869141f, -0.24707f, 0.0952148f, -0.25293f, 0.102051f, -0.258789f, 0.104492f,
--0.26123f, 0.105957f, -0.27002f, 0.0908203f, -0.275391f, 0.0908203f, -0.288086f,
-0.0908203f, -0.290039f, 0.0942383f, -0.327148f, 0.0878906f, -0.342773f, 0.0878906f,
--0.398926f, 0.0859375f, -0.426758f, 0.0869141f, -0.441895f, 0.0791016f, -0.440918f,
-0.0771484f, -0.438965f, 0.0732422f, -0.452148f, 0.0771484f, -0.448242f, 0.0791016f,
--0.466797f, 0.097168f, -0.477051f, 0.097168f, -0.487793f, 0.097168f, -0.50293f, 0.0771484f,
--0.505859f, 0.0698242f, -0.540039f, 0.0698242f, -0.547852f, 0.0668945f, -0.586914f,
-0.0668945f, -0.618164f, 0.0791016f, -0.623047f, 0.0952148f, -0.634766f, 0.121094f,
--0.646973f, 0.140137f, -0.654785f, 0.154785f, -0.648926f, 0.154785f, -0.639648f,
-0.161133f, -0.628906f, 0.153809f, -0.621094f, 0.152588f, -0.616211f, 0.151367f, -0.611328f,
-0.149902f, -0.591797f, 0.148926f, -0.580078f, 0.158203f, -0.545898f, 0.160156f, -0.525879f,
-0.155762f, -0.525879f, 0.146973f, -0.50293f, 0.153809f, -0.495117f, 0.151855f, -0.484863f,
-0.146973f, -0.476074f, 0.14209f, -0.46582f, 0.144043f, -0.455078f, 0.147949f, -0.446777f,
-0.151855f, -0.438965f, 0.151855f, -0.415039f, 0.163086f, -0.412109f, 0.25f, -0.407227f,
-0.263184f, -0.397949f, 0.295898f, -0.394043f, 0.306152f, -0.39502f, 0.309082f, -0.399902f,
-0.342773f, -0.397949f, 0.347168f, -0.396973f, 0.354004f, -0.402832f, 0.36084f, -0.402832f,
-0.371094f, -0.401855f, 0.371094f, -0.397949f, 0.376953f, -0.394043f, 0.388184f, -0.39502f,
-0.441895f, -0.395996f, 0.461914f, -0.397949f, 0.47998f, -0.39209f, 0.48877f, -0.404785f,
-0.500977f, -0.404785f, 0.50293f, -0.404785f, 0.527832f, -0.402832f, 0.575195f, -0.407227f,
-0.603027f, -0.405762f, 0.612793f, -0.408203f, 0.616211f, -0.418945f, 0.625f, -0.440918f,
-0.623047f, -0.49707f, 0.625f, -0.508789f, 0.618164f, -0.52002f, 0.605957f, -0.532227f,
-0.605957f, -0.553223f, 0.603027f, -0.575195f, 0.608887f, -0.585938f, 0.603027f, -0.605957f,
-0.603027f, -0.617188f, 0.603027f, -0.626465f, 0.608887f, -0.62793f, 0.62207f, -0.629883f,
-0.637207f, -0.641113f, 0.648926f, -0.641113f, 0.65625f, -0.643066f, 0.667969f, -0.654785f,
-0.682129f, -0.647949f, 0.687012f, -0.625f, 0.690918f, -0.611816f, 0.676758f, -0.560059f,
-0.680176f, -0.533203f, 0.678223f, -0.521973f, 0.672852f, -0.521973f, 0.666016f, -0.521973f,
-0.666016f, -0.512207f, 0.668457f, -0.506348f, 0.675781f, -0.50293f, 0.685059f, -0.498047f,
-0.687988f, -0.484863f, 0.690918f, -0.464844f, 0.689941f, -0.458984f, 0.682129f, -0.443848f,
-0.684082f, -0.35498f, 0.682129f, -0.278809f, 0.689941f, -0.26709f, 0.686035f, -0.249512f,
-0.686035f, -0.240234f, 0.686035f, -0.23877f, 0.686035f, -0.236816f, 0.686035f, -0.230957f,
-0.686035f, -0.219238f, 0.675781f, -0.208496f, 0.675781f, -0.204102f, 0.675781f, -0.202148f,
-0.676758f, -0.202148f, 0.689941f, -0.179199f, 0.687012f, -0.112793f, 0.688965f, -0.632812f,
-0.680176f, -0.625977f, 0.667969f, -0.60498f, 0.628906f, -0.589844f, 0.61084f, -0.578125f,
-0.60498f, -0.575195f, 0.599121f, -0.575195f, 0.598145f, -0.575195f, 0.569824f, -0.580078f,
-0.503906f, -0.582031f, 0.458008f, -0.586914f, 0.414062f, -0.583984f, 0.396973f, -0.586914f,
-0.390137f, -0.585938f, 0.384766f, -0.562988f, 0.387207f, -0.550781f, 0.388184f, -0.535156f,
-0.388184f, -0.530762f, 0.382812f, -0.507812f, 0.383789f, -0.490234f, 0.381836f, -0.475098f,
-0.384766f, -0.463867f, 0.373047f, -0.462891f, 0.369873f, -0.459961f, 0.366699f, -0.457031f,
-0.366211f, -0.445801f, 0.382324f, -0.443359f, 0.383789f, -0.437012f, 0.381836f, -0.401855f,
-0.381836f, -0.378906f, 0.381836f, -0.364258f, 0.362793f, -0.347168f, 0.365234f, -0.342773f,
-0.367188f, -0.340088f, 0.369141f, -0.337402f, 0.373291f, -0.335938f, 0.377441f, -0.334473f,
-0.381836f, -0.333984f, 0.384766f, -0.328125f, 0.378418f, -0.324219f, 0.376221f, -0.320312f,
-0.374023f, -0.316406f, 0.373047f, -0.307129f, 0.384766f, -0.293945f, 0.384766f, -0.27002f,
-0.384766f, -0.249023f, 0.384766f, -0.241211f, 0.37793f, -0.233887f, 0.382812f, -0.222168f,
-0.380859f, -0.208984f, 0.384766f, -0.190918f, 0.382812f, -0.176758f, 0.383789f, -0.165039f,
-0.384766f, -0.14502f, 0.366211f, -0.137207f, 0.366211f, -0.123047f, 0.366211f, -0.111328f,
-0.383789f, -0.102051f, 0.391113f, -0.0200195f, 0.383789f, -0.0141602f, 0.375f, -0.00976562f,
-0.349121f, 0.012207f, 0.339844f, 0.0131836f, 0.333008f, 0.0131836f, 0.327148f, 0.0200195f,
-0.321289f, 0.0161133f, 0.317871f, 0.0161133f, 0.317871f, 0.0161133f, 0.312012f, 0.0180664f,
-0.306152f, 0.00488281f, 0.307129f, 0.00195312f, 0.307373f, 0.000244141f, 0.307617f,
--0.00146484f, 0.308105f, -0.00292969f, 0.312012f, -0.0249023f, 0.308105f, -0.0507812f,
-0.312012f, -0.0888672f, 0.314941f, -0.14502f, 0.319824f, -0.187012f, 0.319824f, -0.198242f,
-0.329102f, -0.209961f, 0.316895f, -0.254883f, 0.321777f, -0.286133f, 0.318848f, -0.327148f,
-0.316895f, -0.35498f, 0.315918f, -0.355957f, 0.315918f, -0.36377f, 0.325195f, -0.390137f,
-0.321777f, -0.400879f, 0.311035f, -0.427734f, 0.311035f, -0.437988f, 0.311035f, -0.438965f,
-0.312012f, -0.453125f, 0.306152f, -0.478027f, 0.307129f, -0.492188f, 0.300781f, -0.527832f,
-0.298828f, -0.540039f, 0.313965f, -0.569824f, 0.324219f, -0.575684f, 0.324219f, -0.581055f,
-0.324219f, -0.585938f, 0.323242f, -0.588867f, 0.295898f, -0.594238f, 0.287109f, -0.594238f,
-0.276855f, -0.595215f, 0.254883f, -0.604004f, 0.210938f, -0.600098f, 0.144043f, -0.606934f,
-0.0717773f, -0.603027f, 0.0600586f, -0.60498f, 0.0478516f, -0.59082f, 0.0380859f,
--0.59082f, 0.0351562f, -0.59082f, 0.0209961f, -0.592773f, 0.00683594f, -0.595215f,
-0.00732422f, -0.609863f, 0.010498f, -0.615967f, 0.0136719f, -0.62207f, 0.0219727f,
--0.628906f, 0.0581055f, -0.657227f, 0.0732422f, -0.664062f, 0.100586f, -0.664062f,
-0.11377f, -0.664062f, 0.119629f, -0.649902f, 0.129883f, -0.649902f, 0.139648f, -0.649902f,
-0.152832f, -0.661133f, 0.174805f, -0.65918f, 0.217773f, -0.64502f, 0.253906f, -0.646973f,
-0.282227f, -0.640137f, 0.338867f, -0.637207f, 0.362793f, -0.624023f, 0.374023f, -0.623047f,
-0.375f, -0.626953f, 0.387207f, -0.625977f, 0.417969f, -0.623535f, 0.425537f, -0.62207f,
-0.433105f, -0.620605f, 0.440918f, -0.61377f, 0.458008f, -0.609863f, 0.466797f, -0.616211f,
-0.48291f, -0.617188f, 0.503906f, -0.625977f, 0.540039f, -0.625f, 0.563965f, -0.629883f,
-0.579102f, -0.625f, 0.588867f, -0.625f, 0.63623f, -0.625f, 0.680176f, -0.646973f,
-0.686035f, -0.644043f, 0.48877f, -0.0332031f, 0.483887f, -0.0239258f, 0.476074f,
--0.012207f, 0.461914f, -0.00683594f, 0.441895f, 0.00390625f, 0.422852f, 0.00976562f,
-0.404785f, 0.0170898f, 0.401855f, 0.0170898f, 0.398438f, 0.0170898f, 0.395264f, 0.0134277f,
-0.39209f, 0.00976562f, 0.39209f, 0.00683594f, 0.39209f, 0.00195312f, 0.396973f, -0.0151367f,
-0.399414f, -0.0200195f, 0.400879f, -0.0322266f, 0.391113f, -0.0258789f, 0.347168f,
--0.0112305f, 0.333984f, -0.00488281f, 0.320801f, -0.00488281f, 0.319824f, -0.00488281f,
-0.300781f, -0.00488281f, 0.277832f, 0.00585938f, 0.262207f, 0.0078125f, 0.216797f,
-0.0170898f, 0.198242f, 0.0141602f, 0.185059f, 0.019043f, 0.175781f, 0.0209961f, 0.161133f,
-0.0200195f, 0.128906f, 0.0131836f, 0.106934f, 0.0112305f, 0.0844727f, 0.00830078f,
-0.0681152f, -0.00415039f, 0.0517578f, -0.0166016f, 0.0439453f, -0.0361328f, 0.0307617f,
--0.0410156f, 0.027832f, -0.0532227f, 0.0268555f, -0.0620117f, 0.0200195f, -0.0849609f,
-0.0380859f, -0.121094f, 0.0439453f, -0.137207f, 0.046875f, -0.143555f, 0.0620117f,
--0.155762f, 0.100098f, -0.187012f, 0.116211f, -0.192871f, 0.143066f, -0.204102f,
-0.143555f, -0.204102f, 0.14502f, -0.203857f, 0.146484f, -0.203613f, 0.147949f, -0.203125f,
-0.157715f, -0.224121f, 0.185059f, -0.224121f, 0.187988f, -0.227051f, 0.198242f, -0.227051f,
-0.20459f, -0.234863f, 0.210938f, -0.237793f, 0.217285f, -0.240723f, 0.234863f, -0.244141f,
-0.295898f, -0.254883f, 0.313965f, -0.25293f, 0.336914f, -0.257812f, 0.37793f, -0.262207f,
-0.398926f, -0.26709f, 0.398926f, -0.282227f, 0.398926f, -0.28418f, 0.397949f, -0.285156f,
-0.393066f, -0.307129f, 0.396973f, -0.338867f, 0.395508f, -0.349121f, 0.389648f, -0.35376f,
-0.383789f, -0.358398f, 0.37207f, -0.359863f, 0.365234f, -0.371094f, 0.354492f, -0.388672f,
-0.347656f, -0.393799f, 0.34082f, -0.398926f, 0.321777f, -0.402832f, 0.293945f, -0.40918f,
-0.26709f, -0.410156f, 0.253906f, -0.408203f, 0.249512f, -0.410156f, 0.24707f, -0.413086f,
-0.244629f, -0.416016f, 0.243164f, -0.421875f, 0.22998f, -0.416016f, 0.214844f, -0.401855f,
-0.166992f, -0.37793f, 0.151855f, -0.369629f, 0.146973f, -0.361816f, 0.140137f, -0.352051f,
-0.135254f, -0.344238f, 0.126953f, -0.344238f, 0.117188f, -0.346191f, 0.103027f, -0.353027f,
-0.0878906f, -0.355957f, 0.0805664f, -0.358398f, 0.0732422f, -0.364258f, 0.065918f,
--0.370117f, 0.065918f, -0.375f, 0.065918f, -0.37793f, 0.0668945f, -0.37793f, 0.0751953f,
--0.383789f, 0.0908203f, -0.395996f, 0.10791f, -0.398926f, 0.133789f, -0.412109f,
-0.166016f, -0.422852f, 0.174805f, -0.424805f, 0.195801f, -0.436035f, 0.212891f, -0.433105f,
-0.271973f, -0.445801f, 0.296875f, -0.444824f, 0.315918f, -0.444824f, 0.335938f, -0.437988f,
-0.394043f, -0.426758f, 0.402832f, -0.421875f, 0.402832f, -0.415039f, 0.395996f, -0.411133f,
-0.398926f, -0.394043f, 0.408203f, -0.394043f, 0.40918f, -0.394531f, 0.409668f, -0.394775f,
-0.410156f, -0.39502f, 0.411133f, -0.39502f, 0.424805f, -0.400879f, 0.426758f, -0.400879f,
-0.431641f, -0.400879f, 0.433105f, -0.395996f, 0.442871f, -0.37793f, 0.453125f, -0.370117f,
-0.453125f, -0.358887f, 0.451172f, -0.333984f, 0.451172f, -0.317871f, 0.466797f, -0.306152f,
-0.473145f, -0.233887f, 0.459961f, -0.21582f, 0.475098f, -0.198242f, 0.476074f, -0.191895f,
-0.473145f, -0.145996f, 0.477051f, -0.11084f, 0.477051f, -0.103027f, 0.477051f, -0.0917969f,
-0.470215f, -0.0898438f, 0.471191f, -0.0776367f, 0.47168f, -0.0742188f, 0.472168f,
--0.0708008f, 0.475098f, -0.064209f, 0.478027f, -0.0576172f, 0.481934f, -0.0488281f,
-0.411133f, -0.118164f, 0.403809f, -0.124512f, 0.401855f, -0.128906f, 0.403809f, -0.148926f,
-0.399902f, -0.193848f, 0.405762f, -0.207031f, 0.390137f, -0.21582f, 0.381836f, -0.213867f,
-0.336914f, -0.216797f, 0.315918f, -0.21582f, 0.299805f, -0.227051f, 0.290039f, -0.221191f,
-0.263184f, -0.220215f, 0.244141f, -0.212891f, 0.23291f, -0.219238f, 0.219238f, -0.210938f,
-0.145996f, -0.175781f, 0.129883f, -0.164062f, 0.117188f, -0.14502f, 0.100098f, -0.134766f,
-0.0961914f, -0.130859f, 0.0961914f, -0.125977f, 0.0961914f, -0.125977f, 0.0964355f,
--0.125488f, 0.0966797f, -0.125f, 0.097168f, -0.124023f, 0.101074f, -0.118164f, 0.100098f,
--0.11377f, 0.11084f, -0.0698242f, 0.100098f, -0.0419922f, 0.10791f, -0.0322266f,
-0.121094f, -0.0478516f, 0.12793f, -0.0419922f, 0.133789f, -0.0380859f, 0.139648f,
--0.0341797f, 0.147949f, -0.0314941f, 0.15625f, -0.0288086f, 0.168945f, -0.0258789f,
-0.179199f, -0.012207f, 0.212891f, -0.00878906f, 0.222168f, -0.0180664f, 0.231934f,
--0.0131836f, 0.23877f, -0.0170898f, 0.244141f, -0.0200195f, 0.255859f, -0.0161133f,
-0.257812f, -0.0161133f, 0.272461f, -0.0161133f, 0.295898f, -0.0297852f, 0.297363f,
--0.0307617f, 0.299805f, -0.0319824f, 0.302246f, -0.0332031f, 0.307129f, -0.0361328f,
-0.351074f, -0.0361328f, 0.365234f, -0.0541992f, 0.375f, -0.0668945f, 0.398926f, -0.0869141f,
-0.399902f, -0.0927734f, 0.398926f, -0.0991211f, 0.40625f, -0.101562f, 0.408203f,
--0.10498f, 0.410156f, -0.108398f, 0.411133f, -0.118164f, 0.484863f, -0.0927734f,
-0.484863f, -0.0898438f, 0.483887f, -0.0878906f, 0.478027f, -0.0629883f, 0.478027f,
--0.0625f, 0.478271f, -0.0615234f, 0.478516f, -0.0605469f, 0.479004f, -0.059082f,
-0.458008f, -0.0332031f, 0.445801f, -0.0297852f, 0.426758f, -0.0170898f, 0.418945f,
--0.0151367f, 0.396973f, -0.00390625f, 0.39502f, -0.00390625f, 0.36377f, -0.00488281f,
-0.355469f, -0.00488281f, 0.34082f, 0.00195312f, 0.315918f, 0.0161133f, 0.276855f,
-0.019043f, 0.237793f, 0.0161133f, 0.229004f, 0.00878906f, 0.200195f, 0.00488281f,
-0.167969f, -0.00390625f, 0.123047f, -0.0141602f, 0.102051f, -0.0322266f, 0.0830078f,
--0.0517578f, 0.0888672f, -0.0688477f, 0.0795898f, -0.0649414f, 0.0717773f, -0.0649414f,
-0.0678711f, -0.0649414f, 0.059082f, -0.0751953f, 0.046875f, -0.0961914f, 0.0400391f,
--0.10498f, 0.0371094f, -0.132812f, 0.0410156f, -0.146973f, 0.0371094f, -0.154785f,
-0.0268555f, -0.166016f, 0.0332031f, -0.190918f, 0.0307617f, -0.23584f, 0.0478516f,
--0.265137f, 0.0688477f, -0.308105f, 0.0961914f, -0.331055f, 0.14502f, -0.37793f,
-0.15918f, -0.388184f, 0.178223f, -0.401855f, 0.187012f, -0.404785f, 0.207031f, -0.419922f,
-0.27002f, -0.439941f, 0.285156f, -0.443848f, 0.286133f, -0.443848f, 0.286865f, -0.443604f,
-0.287598f, -0.443359f, 0.288086f, -0.442871f, 0.312988f, -0.432129f, 0.337891f, -0.438965f,
-0.384766f, -0.431152f, 0.424805f, -0.437012f, 0.432129f, -0.435059f, 0.440918f, -0.431152f,
-0.437012f, -0.415527f, 0.432373f, -0.4104f, 0.427734f, -0.405273f, 0.413086f, -0.398926f,
-0.412109f, -0.388184f, 0.39209f, -0.375977f, 0.37793f, -0.369141f, 0.375977f, -0.369141f,
-0.362793f, -0.371094f, 0.346191f, -0.369141f, 0.270996f, -0.380859f, 0.26709f, -0.381836f,
-0.259766f, -0.381836f, 0.25293f, -0.381836f, 0.25f, -0.380859f, 0.208984f, -0.373047f,
-0.195801f, -0.373047f, 0.179199f, -0.370117f, 0.163086f, -0.347168f, 0.14209f, -0.339844f,
-0.132812f, -0.319824f, 0.116211f, -0.316895f, 0.118164f, -0.312988f, 0.118164f, -0.310059f,
-0.0981445f, -0.270996f, 0.0961914f, -0.253906f, 0.097168f, -0.224121f, 0.0976562f,
--0.202637f, 0.100586f, -0.188477f, 0.103516f, -0.174316f, 0.11084f, -0.160156f, 0.106934f,
--0.148926f, 0.102051f, -0.140625f, 0.102051f, -0.138184f, 0.102051f, -0.135254f,
-0.10498f, -0.130859f, 0.119629f, -0.126953f, 0.119141f, -0.126953f, 0.123535f, -0.123535f,
-0.133789f, -0.108887f, 0.146973f, -0.0908203f, 0.147949f, -0.0888672f, 0.148926f,
--0.0864258f, 0.149902f, -0.0839844f, 0.151855f, -0.0800781f, 0.163086f, -0.0800781f,
-0.168945f, -0.0717773f, 0.201172f, -0.0488281f, 0.214844f, -0.0371094f, 0.230957f,
--0.0322266f, 0.245117f, -0.0268555f, 0.26709f, -0.0258789f, 0.323242f, -0.0200195f,
-0.324219f, -0.0195312f, 0.324707f, -0.0192871f, 0.325195f, -0.019043f, 0.325195f,
--0.019043f, 0.333496f, -0.019043f, 0.359863f, -0.0332031f, 0.369141f, -0.0297852f,
-0.402832f, -0.0532227f, 0.416016f, -0.0551758f, 0.428711f, -0.0639648f, 0.441406f,
--0.0727539f, 0.462891f, -0.0952148f, 0.469238f, -0.103027f, 0.475098f, -0.103027f,
-0.479004f, -0.103027f, 0.481934f, -0.100098f, 0.484863f, -0.097168f, 0.484863f, -0.0927734f,
-0.51123f, -0.100098f, 0.51123f, -0.09375f, 0.508789f, -0.0888672f, 0.499023f, -0.0717773f,
-0.476074f, -0.0322266f, 0.455078f, -0.0307617f, 0.441895f, -0.0200195f, 0.4375f,
--0.015625f, 0.426758f, -0.0141602f, 0.338867f, 0.00292969f, 0.325195f, 0.0078125f,
-0.293945f, 0.00488281f, 0.249023f, 0.00878906f, 0.198242f, 0.00585938f, 0.184082f,
-0.00585938f, 0.17334f, -0.00244141f, 0.170898f, -0.00390625f, 0.123047f, -0.0209961f,
-0.106934f, -0.0361328f, 0.0751953f, -0.0581055f, 0.0498047f, -0.0917969f, 0.0400391f,
--0.100098f, 0.0458984f, -0.111816f, 0.0458984f, -0.121094f, 0.0458984f, -0.125f,
-0.0439453f, -0.126953f, 0.0307617f, -0.147949f, 0.027832f, -0.175781f, 0.0268555f,
--0.198242f, 0.0268555f, -0.209473f, 0.0322266f, -0.228027f, 0.0405273f, -0.257324f,
-0.0458984f, -0.263184f, 0.0639648f, -0.286133f, 0.0732422f, -0.307129f, 0.0961914f,
--0.329102f, 0.121094f, -0.361816f, 0.143066f, -0.374023f, 0.174805f, -0.395996f,
-0.195801f, -0.410156f, 0.203125f, -0.415039f, 0.217773f, -0.417969f, 0.262207f, -0.432129f,
-0.296875f, -0.436035f, 0.317871f, -0.444824f, 0.328125f, -0.445801f, 0.353027f, -0.445801f,
-0.370117f, -0.418945f, 0.379395f, -0.419922f, 0.383789f, -0.429199f, 0.396973f, -0.417969f,
-0.415039f, -0.408203f, 0.456055f, -0.368164f, 0.463867f, -0.358398f, 0.468018f, -0.351318f,
-0.472168f, -0.344238f, 0.476318f, -0.336426f, 0.480469f, -0.328613f, 0.483643f, -0.319336f,
-0.486816f, -0.310059f, 0.493164f, -0.291016f, 0.49707f, -0.278809f, 0.492188f, -0.276855f,
-0.473145f, -0.280762f, 0.452148f, -0.273926f, 0.436035f, -0.276855f, 0.417969f, -0.271973f,
-0.383789f, -0.275879f, 0.351074f, -0.273926f, 0.316895f, -0.279785f, 0.26123f, -0.278809f,
-0.233887f, -0.279785f, 0.167969f, -0.270996f, 0.144043f, -0.271973f, 0.11084f, -0.262207f,
-0.0991211f, -0.259766f, 0.097168f, -0.248047f, 0.0961914f, -0.23584f, 0.09375f, -0.231445f,
-0.0913086f, -0.227051f, 0.0830078f, -0.221191f, 0.0839844f, -0.211914f, 0.100098f,
--0.199707f, 0.101074f, -0.196777f, 0.11377f, -0.146973f, 0.120117f, -0.134766f, 0.115234f,
--0.129883f, 0.115234f, -0.125977f, 0.115234f, -0.125977f, 0.115479f, -0.125488f,
-0.115723f, -0.125f, 0.116211f, -0.124023f, 0.134766f, -0.118164f, 0.13916f, -0.105957f,
-0.144043f, -0.0888672f, 0.151855f, -0.0849609f, 0.178223f, -0.0742188f, 0.187012f,
--0.0551758f, 0.193848f, -0.0517578f, 0.208984f, -0.0498047f, 0.21582f, -0.0371094f,
-0.230957f, -0.0351562f, 0.272949f, -0.0200195f, 0.308105f, -0.0268555f, 0.400879f,
--0.0419922f, 0.420898f, -0.0541992f, 0.452148f, -0.0732422f, 0.478027f, -0.106934f,
-0.484863f, -0.115234f, 0.494141f, -0.115234f, 0.51123f, -0.115234f, 0.51123f, -0.100098f,
-0.395996f, -0.330078f, 0.395996f, -0.337891f, 0.37793f, -0.362793f, 0.344238f, -0.387207f,
-0.333008f, -0.398926f, 0.316895f, -0.399902f, 0.279785f, -0.402832f, 0.270996f, -0.400879f,
-0.25f, -0.38916f, 0.223145f, -0.382812f, 0.188965f, -0.370117f, 0.175781f, -0.365234f,
-0.160156f, -0.341797f, 0.145508f, -0.331543f, 0.144043f, -0.329102f, 0.14209f, -0.323242f,
-0.202148f, -0.318848f, 0.208984f, -0.319824f, 0.220215f, -0.323242f, 0.230957f, -0.320801f,
-0.259766f, -0.314941f, 0.26123f, -0.314941f, 0.293945f, -0.320801f, 0.304199f, -0.323242f,
-0.312012f, -0.312012f, 0.323242f, -0.312012f, 0.366211f, -0.320801f, 0.383789f, -0.318848f,
-0.395996f, -0.320312f, 0.395996f, -0.330078f, 0.433105f, -0.911133f, 0.428223f, -0.899902f,
-0.413086f, -0.883789f, 0.401855f, -0.870117f, 0.38916f, -0.861816f, 0.375977f, -0.85498f,
-0.333984f, -0.875977f, 0.310547f, -0.888184f, 0.296875f, -0.888184f, 0.28418f, -0.888184f,
-0.254883f, -0.875977f, 0.224121f, -0.864746f, 0.210938f, -0.829102f, 0.196777f, -0.790039f,
-0.186035f, -0.76709f, 0.179199f, -0.734863f, 0.170898f, -0.724121f, 0.173828f, -0.709961f,
-0.179199f, -0.707031f, 0.176758f, -0.604004f, 0.166992f, -0.591797f, 0.166992f, -0.578125f,
-0.166016f, -0.566895f, 0.178223f, -0.538086f, 0.173828f, -0.518066f, 0.178223f, -0.470215f,
-0.178223f, -0.467773f, 0.178223f, -0.456543f, 0.162109f, -0.443848f, 0.164062f, -0.434082f,
-0.180664f, -0.42627f, 0.182129f, -0.421875f, 0.185059f, -0.402832f, 0.185059f, -0.395996f,
-0.196777f, -0.395996f, 0.211914f, -0.39502f, 0.265137f, -0.39209f, 0.304199f, -0.397949f,
-0.346191f, -0.401855f, 0.368164f, -0.408203f, 0.379883f, -0.40918f, 0.398926f, -0.40918f,
-0.411133f, -0.38916f, 0.399902f, -0.381836f, 0.36377f, -0.358887f, 0.345215f, -0.342773f,
-0.295898f, -0.350098f, 0.245117f, -0.345215f, 0.234863f, -0.345215f, 0.226074f, -0.348145f,
-0.201172f, -0.35498f, 0.195801f, -0.35498f, 0.188965f, -0.35498f, 0.183594f, -0.347168f,
-0.178223f, -0.339355f, 0.178223f, -0.331055f, 0.178223f, -0.328125f, 0.186035f, -0.254883f,
-0.186035f, -0.253906f, 0.186035f, -0.249023f, 0.173828f, -0.243164f, 0.171875f, -0.232422f,
-0.171875f, -0.233887f, 0.171875f, -0.226562f, 0.182129f, -0.214844f, 0.185059f, -0.201172f,
-0.187988f, -0.144043f, 0.191895f, -0.124023f, 0.186035f, -0.118164f, 0.181152f, -0.118164f,
-0.179199f, -0.119141f, 0.171387f, -0.114746f, 0.169922f, -0.105957f, 0.174805f, -0.105957f,
-0.173828f, -0.102051f, 0.187988f, -0.0839844f, 0.187988f, -0.0717773f, 0.186035f,
--0.0581055f, 0.187988f, -0.0458984f, 0.190918f, -0.0341797f, 0.182129f, -0.0297852f,
-0.182129f, -0.0161133f, 0.138184f, 0.00292969f, 0.0991211f, 0.0078125f, 0.0927734f,
-0.00292969f, 0.0927734f, -0.00195312f, 0.0981445f, -0.0131836f, 0.102051f, -0.046875f,
-0.109863f, -0.0678711f, 0.112793f, -0.0898438f, 0.109863f, -0.115234f, 0.123047f,
--0.128906f, 0.123047f, -0.141113f, 0.12207f, -0.147949f, 0.111816f, -0.182129f, 0.111816f,
--0.185059f, 0.112793f, -0.22998f, 0.115234f, -0.315918f, 0.117188f, -0.328125f, 0.140137f,
--0.331055f, 0.140137f, -0.341797f, 0.140137f, -0.348145f, 0.134766f, -0.348145f,
-0.116211f, -0.350098f, 0.100098f, -0.356934f, 0.0771484f, -0.356934f, 0.0610352f,
--0.358887f, 0.0507812f, -0.359863f, 0.0419922f, -0.359863f, 0.0361328f, -0.356934f,
-0.0205078f, -0.352051f, 0.0180664f, -0.352051f, 0.00976562f, -0.352051f, 0.00976562f,
--0.36084f, 0.00976562f, -0.364746f, 0.012207f, -0.367188f, 0.0219727f, -0.380859f,
-0.0400391f, -0.403809f, 0.046875f, -0.410156f, 0.059082f, -0.410156f, 0.0673828f,
--0.410156f, 0.0820312f, -0.405762f, 0.10791f, -0.419922f, 0.106934f, -0.425781f,
-0.111816f, -0.458008f, 0.109863f, -0.509766f, 0.111328f, -0.524414f, 0.121094f, -0.53418f,
-0.10498f, -0.557129f, 0.105957f, -0.567871f, 0.103027f, -0.675781f, 0.103027f, -0.690918f,
-0.11084f, -0.704102f, 0.12793f, -0.73291f, 0.12793f, -0.737305f, 0.117188f, -0.745117f,
-0.12207f, -0.779785f, 0.14917f, -0.81958f, 0.17627f, -0.859375f, 0.208008f, -0.87793f,
-0.269043f, -0.915039f, 0.282227f, -0.923828f, 0.298828f, -0.925781f, 0.331055f, -0.934082f,
-0.347168f, -0.929199f, 0.383789f, -0.930176f, 0.393066f, -0.929688f, 0.400635f, -0.925293f,
-0.408203f, -0.920898f, 0.418945f, -0.910156f, 0.422852f, -0.914062f, 0.425781f, -0.914062f,
-0.428711f, -0.914062f, 0.433105f, -0.911133f, 0.160156f, -0.0869141f, 0.158203f,
--0.0610352f, 0.15918f, -0.0410156f, 0.15918f, -0.0336914f, 0.151855f, -0.0288086f,
-0.154785f, -0.0170898f, 0.144043f, -0.0151367f, 0.111816f, 0.00488281f, 0.0991211f,
-0.00683594f, 0.0839844f, 0.0161133f, 0.0820312f, 0.0161133f, 0.0805664f, 0.0163574f,
-0.0791016f, 0.0166016f, 0.0771484f, 0.0170898f, 0.0678711f, 0.0170898f, 0.0678711f,
-0.0112305f, 0.0678711f, -0.000976562f, 0.0649414f, -0.0229492f, 0.0717773f, -0.0761719f,
-0.0742188f, -0.144043f, 0.0756836f, -0.168945f, 0.0849609f, -0.185059f, 0.0791016f,
--0.200195f, 0.0708008f, -0.215332f, 0.0708008f, -0.217773f, 0.0708008f, -0.225586f,
-0.0830078f, -0.246094f, 0.0878906f, -0.253418f, 0.0878906f, -0.262207f, 0.0878906f,
--0.269043f, 0.0732422f, -0.274902f, 0.0751953f, -0.283203f, 0.0708008f, -0.285156f,
-0.0708008f, -0.291992f, 0.0708008f, -0.299805f, 0.0791016f, -0.333984f, 0.0791016f,
--0.417969f, 0.0888672f, -0.457031f, 0.0888672f, -0.464844f, 0.0771484f, -0.474121f,
-0.0771484f, -0.49707f, 0.0751953f, -0.584961f, 0.0751953f, -0.594727f, 0.0878906f,
--0.618164f, 0.0952148f, -0.630859f, 0.0771484f, -0.63916f, 0.0771484f, -0.645996f,
-0.0771484f, -0.644043f, 0.0800781f, -0.665039f, 0.0698242f, -0.673828f, 0.0698242f,
--0.692871f, 0.0678711f, -0.71582f, 0.0678711f, -0.720215f, 0.0761719f, -0.745117f,
-0.0678711f, -0.779785f, 0.0698242f, -0.796875f, 0.0600586f, -0.854004f, 0.0600586f,
--0.858887f, 0.0600586f, -0.861816f, 0.0639648f, -0.87793f, 0.0668945f, -0.897949f,
-0.11084f, -0.921875f, 0.130859f, -0.937012f, 0.13916f, -0.938965f, 0.145996f, -0.928223f,
-0.146973f, -0.907227f, 0.150879f, -0.893066f, 0.151855f, -0.884766f, 0.151855f, -0.873047f,
-0.148926f, -0.836914f, 0.148926f, -0.833984f, 0.149902f, -0.816895f, 0.149902f, -0.808105f,
-0.147949f, -0.804199f, 0.13623f, -0.778809f, 0.134766f, -0.769043f, 0.144531f, -0.768555f,
-0.147217f, -0.765869f, 0.149902f, -0.763184f, 0.149902f, -0.751953f, 0.149902f, -0.741211f,
-0.149902f, -0.731445f, 0.138184f, -0.725098f, 0.138184f, -0.712891f, 0.137207f, -0.703125f,
-0.137207f, -0.699219f, 0.145996f, -0.685059f, 0.14209f, -0.591797f, 0.14209f, -0.524902f,
-0.128906f, -0.499023f, 0.13623f, -0.461914f, 0.125977f, -0.437988f, 0.127441f, -0.433594f,
-0.134766f, -0.426758f, 0.143066f, -0.417969f, 0.146973f, -0.259766f, 0.134766f, -0.246094f,
-0.13623f, -0.236816f, 0.13623f, -0.226074f, 0.13623f, -0.208984f, 0.131836f, -0.193848f,
-0.13623f, -0.183105f, 0.149902f, -0.183105f, 0.149902f, -0.165039f, 0.496094f, -0.0332031f,
-0.491211f, -0.019043f, 0.423828f, 0.0131836f, 0.410156f, -0.00439453f, 0.410156f,
--0.00878906f, 0.410156f, -0.0112305f, 0.421875f, -0.0581055f, 0.422852f, -0.0791016f,
-0.426758f, -0.078125f, 0.435059f, -0.0878906f, 0.431641f, -0.0957031f, 0.428467f,
--0.0981445f, 0.425293f, -0.100586f, 0.416992f, -0.104004f, 0.415039f, -0.111816f,
-0.422852f, -0.203125f, 0.417969f, -0.21582f, 0.418945f, -0.231934f, 0.418945f, -0.269043f,
-0.424805f, -0.287109f, 0.416016f, -0.295898f, 0.416992f, -0.325195f, 0.411621f, -0.341309f,
-0.398926f, -0.355957f, 0.398926f, -0.36084f, 0.398926f, -0.367188f, 0.39502f, -0.370117f,
-0.382812f, -0.371094f, 0.35791f, -0.38623f, 0.317871f, -0.383789f, 0.271973f, -0.387207f,
-0.266113f, -0.384277f, 0.258789f, -0.375f, 0.25f, -0.376953f, 0.211914f, -0.370117f,
-0.198242f, -0.367188f, 0.181152f, -0.354004f, 0.15918f, -0.344238f, 0.143066f, -0.336426f,
-0.141113f, -0.320801f, 0.140137f, -0.272949f, 0.133789f, -0.243164f, 0.144043f, -0.213867f,
-0.144043f, -0.198242f, 0.143066f, -0.140137f, 0.133789f, -0.120117f, 0.132812f, -0.112793f,
-0.132812f, -0.109863f, 0.14209f, -0.0942383f, 0.14502f, -0.0410156f, 0.148926f, -0.0239258f,
-0.148926f, -0.0209961f, 0.145996f, -0.0163574f, 0.143066f, -0.0117188f, 0.138184f,
--0.00976562f, 0.105957f, -0.00195312f, 0.097168f, 0, 0.0893555f, 0.0131836f, 0.0820312f,
-0.0131836f, 0.0771484f, 0.0131836f, 0.0717773f, 0.0078125f, 0.0712891f, 0.00683594f,
-0.0705566f, 0.00585938f, 0.0698242f, 0.00488281f, 0.0688477f, 0.00390625f, 0.0668945f,
-0, 0.0668945f, 0.000976562f, 0.0742188f, -0.0351562f, 0.0732422f, -0.0761719f, 0.078125f,
--0.0927734f, 0.0742188f, -0.120117f, 0.0761719f, -0.149902f, 0.0771484f, -0.212891f,
-0.0771484f, -0.225586f, 0.0942383f, -0.227051f, 0.0927734f, -0.237793f, 0.0891113f,
--0.240479f, 0.0854492f, -0.243164f, 0.0732422f, -0.243164f, 0.0742188f, -0.331055f,
-0.0849609f, -0.337891f, 0.0791016f, -0.348145f, 0.065918f, -0.383789f, 0.0571289f,
--0.39502f, 0.0629883f, -0.405762f, 0.0732422f, -0.417969f, 0.0908203f, -0.425781f,
-0.10791f, -0.438965f, 0.115234f, -0.444824f, 0.125977f, -0.444824f, 0.132324f, -0.444824f,
-0.138184f, -0.441162f, 0.144043f, -0.4375f, 0.14502f, -0.433105f, 0.145996f, -0.387207f,
-0.147949f, -0.37207f, 0.157227f, -0.375f, 0.174805f, -0.396484f, 0.198486f, -0.415283f,
-0.222168f, -0.434082f, 0.233887f, -0.434082f, 0.240234f, -0.434082f, 0.244141f, -0.423828f,
-0.253906f, -0.426758f, 0.26709f, -0.435059f, 0.28125f, -0.442871f, 0.291016f, -0.442871f,
-0.293945f, -0.442871f, 0.333984f, -0.438965f, 0.349121f, -0.443848f, 0.394043f, -0.437988f,
-0.416992f, -0.435059f, 0.430176f, -0.421875f, 0.437012f, -0.422852f, 0.452637f, -0.422852f,
-0.462891f, -0.40918f, 0.470215f, -0.396973f, 0.47998f, -0.380859f, 0.486816f, -0.372559f,
-0.486816f, -0.345215f, 0.486816f, -0.317871f, 0.48877f, -0.306152f, 0.477051f, -0.291016f,
-0.480957f, -0.278809f, 0.486816f, -0.268066f, 0.486816f, -0.256836f, 0.486816f, -0.248047f,
-0.486816f, -0.244141f, 0.48584f, -0.242188f, 0.479004f, -0.228027f, 0.477051f, -0.224121f,
-0.477051f, -0.213867f, 0.486816f, -0.201172f, 0.48584f, -0.187012f, 0.484863f, -0.152832f,
-0.484863f, -0.148926f, 0.492188f, -0.129883f, 0.493164f, -0.0859375f, 0.571777f,
--0.248047f, 0.561035f, -0.25f, 0.562988f, -0.23877f, 0.551758f, -0.230957f, 0.554199f,
--0.222168f, 0.555908f, -0.220215f, 0.557617f, -0.218262f, 0.564941f, -0.213867f,
-0.565918f, -0.204102f, 0.565918f, -0.150879f, 0.524902f, -0.0888672f, 0.515625f,
--0.0751953f, 0.501953f, -0.0600586f, 0.488281f, -0.0449219f, 0.484863f, -0.0400391f,
-0.470215f, -0.0361328f, 0.37793f, 0.00683594f, 0.327148f, 0.00878906f, 0.290039f,
-0.0180664f, 0.246094f, 0.0170898f, 0.230957f, 0.0209961f, 0.187012f, 0.0131836f,
-0.168945f, 0.012207f, 0.15918f, 0.000976562f, 0.131836f, -0.00292969f, 0.119141f,
--0.00976562f, 0.102539f, -0.0224609f, 0.0913086f, -0.0310059f, 0.0800781f, -0.0395508f,
-0.0769043f, -0.0422363f, 0.0737305f, -0.0449219f, 0.0717773f, -0.0478516f, 0.0610352f,
--0.0688477f, 0.0458984f, -0.0810547f, 0.0341797f, -0.111816f, 0.0297852f, -0.124023f,
-0.0351562f, -0.12793f, 0.0351562f, -0.134766f, 0.0371094f, -0.137207f, 0.0390625f,
--0.139648f, 0.0458984f, -0.14209f, 0.0429688f, -0.149902f, 0.0268555f, -0.160156f,
-0.0268555f, -0.180176f, 0.0268555f, -0.201172f, 0.0317383f, -0.22168f, 0.0366211f,
--0.242188f, 0.0488281f, -0.269043f, 0.0678711f, -0.312012f, 0.0771484f, -0.317871f,
-0.097168f, -0.331055f, 0.10791f, -0.350098f, 0.11377f, -0.360352f, 0.12207f, -0.36377f,
-0.167969f, -0.388184f, 0.193848f, -0.40918f, 0.225098f, -0.420898f, 0.279785f, -0.439941f,
-0.325195f, -0.443848f, 0.36084f, -0.444824f, 0.391113f, -0.444824f, 0.391113f, -0.428223f,
-0.399414f, -0.420898f, 0.401855f, -0.420898f, 0.40918f, -0.420898f, 0.417969f, -0.435059f,
-0.430176f, -0.432129f, 0.461914f, -0.420898f, 0.475098f, -0.410156f, 0.493164f, -0.398926f,
-0.51123f, -0.371094f, 0.518555f, -0.361816f, 0.540039f, -0.361816f, 0.554199f, -0.344238f,
-0.559082f, -0.327148f, 0.563965f, -0.310059f, 0.569824f, -0.26416f, 0.500977f, -0.23584f,
-0.48291f, -0.291992f, 0.47998f, -0.316895f, 0.475098f, -0.326172f, 0.472168f, -0.326172f,
-0.468262f, -0.326172f, 0.46582f, -0.327637f, 0.463379f, -0.329102f, 0.459961f, -0.333008f,
-0.436035f, -0.362793f, 0.428223f, -0.375f, 0.387207f, -0.394043f, 0.381348f, -0.403809f,
-0.377197f, -0.408447f, 0.373047f, -0.413086f, 0.367188f, -0.413086f, 0.36084f, -0.413086f,
-0.347168f, -0.408203f, 0.333496f, -0.414062f, 0.327148f, -0.414062f, 0.312988f, -0.412109f,
-0.289062f, -0.411133f, 0.255859f, -0.398926f, 0.248047f, -0.405762f, 0.242188f, -0.397949f,
-0.208984f, -0.37793f, 0.147949f, -0.325195f, 0.13623f, -0.314941f, 0.132324f, -0.290039f,
-0.11377f, -0.257812f, 0.106934f, -0.246094f, 0.106934f, -0.242188f, 0.106934f, -0.231445f,
-0.103516f, -0.228027f, 0.100098f, -0.224609f, 0.0898438f, -0.223145f, 0.0878906f,
--0.215332f, 0.0878906f, -0.21582f, 0.0883789f, -0.214844f, 0.088623f, -0.214111f,
-0.0888672f, -0.213379f, 0.0888672f, -0.212891f, 0.104004f, -0.195801f, 0.105957f,
--0.185059f, 0.0908203f, -0.172363f, 0.0908203f, -0.167969f, 0.0908203f, -0.167969f,
-0.0927734f, -0.162109f, 0.097168f, -0.166992f, 0.101074f, -0.166992f, 0.105469f,
--0.166992f, 0.106934f, -0.164062f, 0.118164f, -0.12793f, 0.143066f, -0.0869141f,
-0.140137f, -0.0620117f, 0.144043f, -0.0581055f, 0.148926f, -0.0581055f, 0.154785f,
--0.0581055f, 0.161133f, -0.0639648f, 0.170898f, -0.0610352f, 0.22998f, -0.0249023f,
-0.290039f, -0.019043f, 0.324219f, -0.0141602f, 0.362793f, -0.0209961f, 0.388184f,
--0.0268555f, 0.419922f, -0.059082f, 0.442871f, -0.065918f, 0.454102f, -0.078125f,
-0.47998f, -0.131836f, 0.493164f, -0.143066f, 0.5f, -0.149902f, 0.5f, -0.154785f,
-0.5f, -0.157227f, 0.492188f, -0.180176f, 0.587891f, -0.201172f, 0.578125f, -0.174805f,
-0.573242f, -0.163086f, 0.559082f, -0.14502f, 0.548828f, -0.125977f, 0.536133f, -0.112793f,
-0.526855f, -0.101074f, 0.52002f, -0.0991211f, 0.506836f, -0.102051f, 0.501953f, -0.0927734f,
-0.489258f, -0.0698242f, 0.482666f, -0.0639648f, 0.476074f, -0.0581055f, 0.458984f,
--0.0581055f, 0.458008f, -0.0581055f, 0.450195f, -0.059082f, 0.448242f, -0.0424805f,
-0.436279f, -0.0310059f, 0.424316f, -0.0195312f, 0.396973f, -0.00976562f, 0.370117f,
--0.000976562f, 0.348145f, 0.00683594f, 0.304199f, 0.0078125f, 0.291992f, 0.00976562f,
-0.279785f, 0.0180664f, 0.269043f, 0.012207f, 0.26416f, 0.0117188f, 0.259277f, 0.0112305f,
-0.23291f, 0.00878906f, 0.221191f, 0.0078125f, 0.223145f, -0.00390625f, 0.211914f,
--0.00585938f, 0.202148f, 0, 0.193848f, 0.00390625f, 0.180176f, 0.00390625f, 0.158203f,
-0.00390625f, 0.148926f, 0.000976562f, 0.145996f, 0.0131836f, 0.147949f, 0.0859375f,
-0.141113f, 0.119141f, 0.140137f, 0.132812f, 0.147949f, 0.132812f, 0.150879f, 0.223145f,
-0.13916f, 0.225098f, 0.13623f, 0.23291f, 0.138184f, 0.245117f, 0.144043f, 0.270996f,
-0.141113f, 0.282227f, 0.147949f, 0.276855f, 0.152832f, 0.279785f, 0.153809f, 0.312988f,
-0.157227f, 0.345215f, 0.15918f, 0.367188f, 0.15918f, 0.376465f, 0.144043f, 0.37793f,
-0.141113f, 0.384766f, 0.158203f, 0.38916f, 0.157227f, 0.398926f, 0.162109f, 0.422852f,
-0.164062f, 0.438965f, 0.158203f, 0.448242f, 0.145996f, 0.458008f, 0.13623f, 0.474121f,
-0.124023f, 0.478027f, 0.0981445f, 0.490234f, 0.0898438f, 0.491211f, 0.0717773f, 0.490234f,
-0.0708008f, 0.472168f, 0.0717773f, 0.456055f, 0.0751953f, 0.415039f, 0.0742188f,
-0.374023f, 0.074707f, 0.367676f, 0.0766602f, 0.36377f, 0.0786133f, 0.359863f, 0.0849609f,
-0.35498f, 0.0800781f, 0.323242f, 0.0893555f, 0.313965f, 0.0915527f, 0.310059f, 0.09375f,
-0.306152f, 0.0942383f, 0.296875f, 0.0859375f, 0.293945f, 0.083252f, 0.291016f, 0.0805664f,
-0.288086f, 0.0791016f, 0.282227f, 0.0830078f, 0.26416f, 0.0810547f, 0.250977f, 0.0800781f,
-0.199219f, 0.078125f, 0.160156f, 0.0830078f, 0.11377f, 0.0839844f, 0.101074f, 0.0952148f,
-0.090332f, 0.0952148f, 0.0800781f, 0.0952148f, 0.0717773f, 0.0908203f, 0.0541992f,
-0.0800781f, 0.0507812f, 0.0751953f, 0.0341797f, 0.0751953f, 0.0268555f, 0.0810547f,
--0.13623f, 0.0869141f, -0.153809f, 0.0849609f, -0.171875f, 0.0830078f, -0.185059f,
-0.0742188f, -0.187988f, 0.0742188f, -0.201172f, 0.0717773f, -0.272949f, 0.0717773f,
--0.280762f, 0.0751953f, -0.300781f, 0.0698242f, -0.341797f, 0.0698242f, -0.358887f,
-0.067627f, -0.363037f, 0.0654297f, -0.367188f, 0.0532227f, -0.374023f, 0.0546875f,
--0.389648f, 0.059082f, -0.394043f, 0.0688477f, -0.399902f, 0.0917969f, -0.425781f,
-0.112793f, -0.437988f, 0.125f, -0.443848f, 0.134277f, -0.442871f, 0.147949f, -0.431152f,
-0.145996f, -0.421875f, 0.144043f, -0.407227f, 0.14502f, -0.398926f, 0.153809f, -0.397949f,
-0.170898f, -0.407227f, 0.200684f, -0.422363f, 0.2146f, -0.427246f, 0.228516f, -0.432129f,
-0.244141f, -0.432129f, 0.252441f, -0.432129f, 0.25708f, -0.429932f, 0.261719f, -0.427734f,
-0.266113f, -0.422852f, 0.274902f, -0.429199f, 0.279785f, -0.435059f, 0.291992f, -0.437988f,
-0.312012f, -0.441895f, 0.367188f, -0.440918f, 0.414062f, -0.441895f, 0.42334f, -0.441895f,
-0.436035f, -0.426758f, 0.437988f, -0.427246f, 0.439941f, -0.427734f, 0.441895f, -0.428223f,
-0.442871f, -0.428223f, 0.446777f, -0.428223f, 0.459961f, -0.420898f, 0.496094f, -0.402832f,
-0.505859f, -0.398926f, 0.508789f, -0.394043f, 0.51709f, -0.375f, 0.519531f, -0.371094f,
-0.525879f, -0.371094f, 0.531738f, -0.371094f, 0.539062f, -0.374023f, 0.553711f, -0.362793f,
-0.563965f, -0.345215f, 0.570801f, -0.333008f, 0.578857f, -0.301514f, 0.586914f, -0.27002f,
-0.586914f, -0.253906f, 0.586914f, -0.251953f, 0.583984f, -0.23584f, 0.583008f, -0.222168f,
-0.524902f, -0.245117f, 0.506836f, -0.254395f, 0.50293f, -0.26709f, 0.495117f, -0.290039f,
-0.470215f, -0.327148f, 0.467773f, -0.347168f, 0.460938f, -0.354004f, 0.435059f, -0.353027f,
-0.395996f, -0.378906f, 0.368164f, -0.381836f, 0.341797f, -0.391113f, 0.270996f, -0.390137f,
-0.259766f, -0.390137f, 0.246094f, -0.388184f, 0.206055f, -0.376953f, 0.186035f, -0.373047f,
-0.169922f, -0.366211f, 0.158203f, -0.362793f, 0.146973f, -0.358887f, 0.146973f, -0.333984f,
-0.146973f, -0.328125f, 0.132812f, -0.297852f, 0.132812f, -0.294922f, 0.132812f, -0.291992f,
-0.133789f, -0.291016f, 0.13623f, -0.287109f, 0.145996f, -0.283203f, 0.144043f, -0.258789f,
-0.145996f, -0.203125f, 0.145996f, -0.196777f, 0.137207f, -0.181152f, 0.147949f, -0.157227f,
-0.147949f, -0.140137f, 0.145996f, -0.0952148f, 0.14502f, -0.078125f, 0.15918f, -0.0708008f,
-0.184082f, -0.0600586f, 0.204102f, -0.0449219f, 0.209961f, -0.0532227f, 0.223145f,
--0.0478516f, 0.265137f, -0.0449219f, 0.300781f, -0.0307617f, 0.34082f, -0.0371094f,
-0.366211f, -0.0361328f, 0.384766f, -0.0439453f, 0.404785f, -0.0532227f, 0.429199f,
--0.0708008f, 0.448242f, -0.0830078f, 0.46582f, -0.10498f, 0.486816f, -0.120117f,
-0.504883f, -0.131836f, 0.506836f, -0.144043f, 0.508789f, -0.163086f, 0.520996f, -0.187012f,
-0.521484f, -0.187988f, 0.521729f, -0.188721f, 0.521973f, -0.189453f, 0.521973f, -0.189941f,
-0.52002f, -0.229004f, 0.519043f, -0.240234f, 0.405762f, -0.40918f, 0.405762f, -0.406738f,
-0.403809f, -0.404785f, 0.375977f, -0.382812f, 0.36084f, -0.367188f, 0.352051f, -0.36377f,
-0.338867f, -0.37207f, 0.330078f, -0.380859f, 0.300781f, -0.381836f, 0.272949f, -0.393066f,
-0.262207f, -0.395996f, 0.255859f, -0.385254f, 0.249023f, -0.382568f, 0.242188f, -0.379883f,
-0.221191f, -0.379883f, 0.205078f, -0.373047f, 0.192871f, -0.376953f, 0.183105f, -0.369141f,
-0.144043f, -0.338867f, 0.134277f, -0.326172f, 0.132812f, -0.291992f, 0.131836f, -0.254883f,
-0.121094f, -0.248047f, 0.130859f, -0.231445f, 0.130859f, -0.21582f, 0.138184f, -0.21582f,
-0.13916f, -0.202148f, 0.141113f, -0.13916f, 0.14209f, -0.105957f, 0.140137f, -0.0761719f,
-0.125f, -0.0673828f, 0.125f, -0.0620117f, 0.125f, -0.0610352f, 0.128906f, -0.0532227f,
-0.14209f, -0.0561523f, 0.141113f, -0.0517578f, 0.14502f, -0.0322266f, 0.14502f, -0.0297852f,
-0.14502f, -0.0224609f, 0.137207f, -0.0146484f, 0.129395f, -0.00683594f, 0.121094f,
--0.00585938f, 0.102051f, -0.00390625f, 0.0732422f, 0.0112305f, 0.0610352f, 0.00390625f,
-0.0629883f, -0.00585938f, 0.0698242f, -0.0341797f, 0.0668945f, -0.0717773f, 0.0698242f,
--0.0771484f, 0.0800781f, -0.0771484f, 0.0800781f, -0.0830078f, 0.0791016f, -0.0917969f,
-0.0732422f, -0.105957f, 0.0717773f, -0.125977f, 0.0678711f, -0.143066f, 0.0678711f,
--0.144043f, 0.0678711f, -0.157227f, 0.0688477f, -0.172852f, 0.0708008f, -0.175293f,
-0.072998f, -0.177979f, 0.0751953f, -0.180664f, 0.0788574f, -0.186035f, 0.0825195f,
--0.191406f, 0.0869141f, -0.199219f, 0.0917969f, -0.210938f, 0.0908203f, -0.21582f,
-0.0678711f, -0.21582f, 0.0678711f, -0.226074f, 0.0698242f, -0.263184f, 0.0668945f,
--0.299805f, 0.0683594f, -0.304688f, 0.0732422f, -0.309082f, 0.0732422f, -0.323242f,
-0.0668945f, -0.329102f, 0.0649414f, -0.34082f, 0.0639648f, -0.367188f, 0.0532227f,
--0.388184f, 0.0566406f, -0.405762f, 0.0688477f, -0.417969f, 0.0991211f, -0.434082f,
-0.117188f, -0.445801f, 0.130859f, -0.441895f, 0.135986f, -0.436523f, 0.141113f, -0.431152f,
-0.141113f, -0.418945f, 0.141113f, -0.416016f, 0.141113f, -0.402832f, 0.141113f, -0.384766f,
-0.148926f, -0.384766f, 0.150879f, -0.384766f, 0.175781f, -0.397949f, 0.200195f, -0.407227f,
-0.242188f, -0.430176f, 0.255859f, -0.436035f, 0.26709f, -0.433105f, 0.289062f, -0.439941f,
-0.308105f, -0.445801f, 0.317871f, -0.445801f, 0.338867f, -0.443848f, 0.348633f, -0.430176f,
-0.35498f, -0.430176f, 0.355957f, -0.430664f, 0.356445f, -0.430908f, 0.356934f, -0.431152f,
-0.35791f, -0.431152f, 0.369141f, -0.437012f, 0.373047f, -0.438965f, 0.375f, -0.438965f,
-0.387207f, -0.438965f, 0.397949f, -0.425781f, 0.405762f, -0.416504f, 0.405762f, -0.40918f,
-0.440918f, -0.143066f, 0.440918f, -0.123535f, 0.433838f, -0.110352f, 0.426758f, -0.097168f,
-0.416992f, -0.097168f, 0.415039f, -0.097168f, 0.407227f, -0.0991211f, 0.400879f,
--0.0878906f, 0.39209f, -0.0639648f, 0.370117f, -0.0400391f, 0.359863f, -0.0258789f,
-0.346191f, -0.0249023f, 0.300781f, -0.00195312f, 0.279785f, 0.000976562f, 0.244141f,
-0.0131836f, 0.21582f, 0.0078125f, 0.172852f, 0.0180664f, 0.168457f, 0.0180664f, 0.125f,
-0.00878906f, 0.104492f, 0.00439453f, 0.0991211f, 0, 0.0800781f, -0.012207f, 0.0561523f,
--0.0258789f, 0.0410156f, -0.0356445f, 0.0314941f, -0.0510254f, 0.0219727f, -0.0664062f,
-0.0219727f, -0.0791016f, 0.0219727f, -0.0869141f, 0.0385742f, -0.100342f, 0.0551758f,
--0.11377f, 0.0751953f, -0.123047f, 0.0859375f, -0.108887f, 0.0952148f, -0.065918f,
-0.112793f, -0.0551758f, 0.141113f, -0.0332031f, 0.154785f, -0.0288086f, 0.181152f,
--0.0161133f, 0.199219f, -0.0161133f, 0.210938f, -0.0141602f, 0.234863f, -0.0209961f,
-0.274902f, -0.0249023f, 0.294922f, -0.0351562f, 0.313965f, -0.0419922f, 0.332031f,
--0.0527344f, 0.349121f, -0.0861816f, 0.366211f, -0.119629f, 0.366211f, -0.146973f,
-0.366211f, -0.157227f, 0.359863f, -0.165039f, 0.34082f, -0.191895f, 0.335938f, -0.204102f,
-0.324219f, -0.209961f, 0.317871f, -0.202148f, 0.307129f, -0.203125f, 0.280762f, -0.207031f,
-0.25f, -0.207031f, 0.242188f, -0.207031f, 0.229004f, -0.226074f, 0.21875f, -0.214355f,
-0.212402f, -0.211182f, 0.206055f, -0.208008f, 0.187988f, -0.205078f, 0.170898f, -0.202148f,
-0.161133f, -0.207031f, 0.148926f, -0.207031f, 0.13623f, -0.216797f, 0.120117f, -0.213867f,
-0.10498f, -0.221191f, 0.0839844f, -0.228027f, 0.0717773f, -0.231934f, 0.0629883f,
--0.24707f, 0.0541992f, -0.262207f, 0.0541992f, -0.277832f, 0.0541992f, -0.301758f,
-0.0708008f, -0.328613f, 0.0874023f, -0.355469f, 0.117188f, -0.37793f, 0.140137f,
--0.395508f, 0.171875f, -0.412598f, 0.203613f, -0.429688f, 0.231689f, -0.438965f,
-0.259766f, -0.448242f, 0.277832f, -0.448242f, 0.283203f, -0.448242f, 0.314941f, -0.437988f,
-0.329102f, -0.433105f, 0.362305f, -0.438965f, 0.37207f, -0.438965f, 0.385742f, -0.438965f,
-0.393799f, -0.43457f, 0.401855f, -0.430176f, 0.401855f, -0.423828f, 0.401855f, -0.41748f,
-0.387939f, -0.406006f, 0.374023f, -0.394531f, 0.353027f, -0.384766f, 0.337891f, -0.37793f,
-0.325195f, -0.378906f, 0.300781f, -0.379883f, 0.282227f, -0.384766f, 0.273926f, -0.401855f,
-0.26709f, -0.401855f, 0.258789f, -0.393066f, 0.244141f, -0.393066f, 0.22998f, -0.393066f,
-0.209961f, -0.390137f, 0.194824f, -0.394043f, 0.187012f, -0.388184f, 0.155762f, -0.370117f,
-0.123047f, -0.341797f, 0.123047f, -0.318848f, 0.123047f, -0.302734f, 0.132812f, -0.297852f,
-0.165039f, -0.283203f, 0.174805f, -0.277832f, 0.174805f, -0.266113f, 0.189941f, -0.257812f,
-0.206055f, -0.272949f, 0.213867f, -0.271973f, 0.295898f, -0.277832f, 0.334961f, -0.269043f,
-0.353027f, -0.271973f, 0.375977f, -0.256836f, 0.410156f, -0.237793f, 0.42041f, -0.230957f,
-0.428223f, -0.207031f, 0.432129f, -0.193848f, 0.440918f, -0.163086f, 0.440918f, -0.143066f,
-0.504883f, -0.0297852f, 0.501465f, -0.0170898f, 0.490234f, -0.012207f, 0.434082f,
-0.012207f, 0.418945f, 0.00341797f, 0.418945f, -0.0161133f, 0.419922f, -0.0439453f,
-0.411133f, -0.0458984f, 0.378906f, -0.0307617f, 0.333984f, -0.00878906f, 0.315918f,
-0, 0.256836f, 0.0112305f, 0.237793f, 0.0170898f, 0.23291f, 0.0170898f, 0.228027f,
-0.0170898f, 0.226074f, 0.0161133f, 0.208008f, 0.00878906f, 0.186035f, 0.0151367f,
-0.166016f, -0.00195312f, 0.126953f, 0.00390625f, 0.121094f, 0.00146484f, 0.109863f,
--0.00488281f, 0.0986328f, -0.0112305f, 0.0908203f, -0.019043f, 0.0688477f, -0.043457f,
-0.0688477f, -0.0688477f, 0.0688477f, -0.0766602f, 0.0791016f, -0.0849609f, 0.0629883f,
--0.0908203f, 0.0620117f, -0.109863f, 0.0610352f, -0.13623f, 0.0610352f, -0.147949f,
-0.0649414f, -0.155762f, 0.0742188f, -0.172852f, 0.0649414f, -0.200195f, 0.065918f,
--0.229004f, 0.0649414f, -0.262207f, 0.0654297f, -0.265137f, 0.0751953f, -0.295898f,
-0.0751953f, -0.303223f, 0.065918f, -0.298828f, 0.0600586f, -0.305176f, 0.0600586f,
--0.314941f, 0.0610352f, -0.374023f, 0.0610352f, -0.387695f, 0.0581055f, -0.39502f,
-0.0541992f, -0.400879f, 0.0541992f, -0.401855f, 0.0539551f, -0.402588f, 0.0537109f,
--0.40332f, 0.0532227f, -0.403809f, 0.0532227f, -0.412109f, 0.0649414f, -0.418945f,
-0.0708008f, -0.421875f, 0.106934f, -0.437012f, 0.124512f, -0.443848f, 0.130859f,
--0.443848f, 0.138184f, -0.443848f, 0.144043f, -0.430176f, 0.148926f, -0.418945f,
-0.13916f, -0.391602f, 0.13916f, -0.368164f, 0.14209f, -0.339844f, 0.141113f, -0.328125f,
-0.132812f, -0.304199f, 0.132324f, -0.291016f, 0.131836f, -0.285889f, 0.131348f, -0.280762f,
-0.130859f, -0.276855f, 0.130859f, -0.269531f, 0.133789f, -0.262207f, 0.14209f, -0.248047f,
-0.130859f, -0.210938f, 0.134766f, -0.199219f, 0.130859f, -0.178223f, 0.126953f, -0.149902f,
-0.126953f, -0.145996f, 0.12793f, -0.144043f, 0.134766f, -0.131836f, 0.138184f, -0.0800781f,
-0.141113f, -0.065918f, 0.150635f, -0.0600586f, 0.160156f, -0.0541992f, 0.189941f,
--0.0449219f, 0.226074f, -0.0351562f, 0.23584f, -0.0332031f, 0.258789f, -0.0332031f,
-0.275391f, -0.0332031f, 0.283203f, -0.0361328f, 0.311035f, -0.046875f, 0.34082f,
--0.0390625f, 0.348633f, -0.0415039f, 0.351074f, -0.0551758f, 0.367188f, -0.0639648f,
-0.38916f, -0.0942383f, 0.407227f, -0.108887f, 0.414551f, -0.118652f, 0.416016f, -0.13623f,
-0.419922f, -0.186035f, 0.423828f, -0.196777f, 0.413086f, -0.208008f, 0.414062f, -0.226074f,
-0.416016f, -0.303223f, 0.413086f, -0.329102f, 0.408203f, -0.358887f, 0.408203f, -0.366211f,
-0.416992f, -0.375f, 0.415039f, -0.383789f, 0.407227f, -0.384766f, 0.404785f, -0.399902f,
-0.404785f, -0.403809f, 0.40918f, -0.418945f, 0.40918f, -0.429199f, 0.416992f, -0.426758f,
-0.471191f, -0.445801f, 0.47168f, -0.445801f, 0.472168f, -0.446289f, 0.472656f, -0.446777f,
-0.473145f, -0.446777f, 0.478516f, -0.446777f, 0.482178f, -0.437744f, 0.48584f, -0.428711f,
-0.48584f, -0.414062f, 0.481934f, -0.314941f, 0.475098f, -0.23877f, 0.461914f, -0.244141f,
-0.456055f, -0.230469f, 0.456055f, -0.225098f, 0.458984f, -0.214844f, 0.464844f, -0.216797f,
-0.467773f, -0.216797f, 0.472168f, -0.216797f, 0.475098f, -0.214355f, 0.478027f, -0.211914f,
-0.478027f, -0.208008f, 0.473145f, -0.116211f, 0.48291f, -0.0991211f, 0.487793f, -0.0517578f,
-0.490234f, -0.0488281f, 0.494385f, -0.0441895f, 0.498535f, -0.0395508f, 0.504883f,
--0.0297852f, 0.48584f, -0.103027f, 0.469238f, -0.0571289f, 0.469238f, -0.0551758f,
-0.471191f, -0.0478516f, 0.480957f, -0.0361328f, 0.477051f, -0.00976562f, 0.479004f,
-0.027832f, 0.474121f, 0.0400391f, 0.475098f, 0.0917969f, 0.467773f, 0.108887f, 0.462891f,
-0.132812f, 0.455078f, 0.148926f, 0.456055f, 0.173828f, 0.438965f, 0.21582f, 0.435059f,
-0.227051f, 0.420898f, 0.23584f, 0.383789f, 0.283203f, 0.361816f, 0.315918f, 0.349609f,
-0.334961f, 0.336914f, 0.34082f, 0.324219f, 0.348145f, 0.312012f, 0.36084f, 0.296875f,
-0.370117f, 0.288086f, 0.37793f, 0.26709f, 0.383789f, 0.266602f, 0.383789f, 0.23584f,
-0.397949f, 0.205078f, 0.40918f, 0.161133f, 0.421875f, 0.115234f, 0.416992f, 0.0908203f,
-0.414062f, 0.0732422f, 0.412598f, 0.0610352f, 0.405762f, 0.027832f, 0.384766f, 0.0112305f,
-0.380859f, -0.00195312f, 0.362793f, -0.027832f, 0.347168f, -0.0371094f, 0.339355f,
--0.0371094f, 0.319824f, -0.0371094f, 0.299316f, -0.0229492f, 0.280762f, -0.0185547f,
-0.275391f, -0.00390625f, 0.273926f, 0.00195312f, 0.288086f, 0.00683594f, 0.301758f,
-0.0258789f, 0.328125f, 0.0449219f, 0.35791f, 0.0551758f, 0.368164f, 0.0600586f, 0.368164f,
-0.0610352f, 0.368164f, 0.0678711f, 0.367188f, 0.108887f, 0.383789f, 0.143066f, 0.38623f,
-0.149414f, 0.391113f, 0.155762f, 0.391113f, 0.160645f, 0.391113f, 0.168945f, 0.384766f,
-0.180176f, 0.38623f, 0.200684f, 0.38623f, 0.23877f, 0.369141f, 0.272461f, 0.352539f,
-0.279785f, 0.344238f, 0.316895f, 0.306152f, 0.339844f, 0.291992f, 0.352539f, 0.282227f,
-0.36084f, 0.255859f, 0.373047f, 0.21582f, 0.391113f, 0.187988f, 0.388184f, 0.166992f,
-0.396973f, 0.12793f, 0.397949f, 0.0878906f, 0.397949f, 0.0673828f, 0.407227f, 0.046875f,
-0.415039f, 0.0200195f, 0.40918f, -0.00292969f, 0.403809f, -0.0708008f, 0.402832f,
--0.0820312f, 0.402832f, -0.0869141f, 0.411133f, -0.112793f, 0.405762f, -0.120117f,
-0.391113f, -0.112793f, 0.374023f, -0.103027f, 0.359863f, -0.0878906f, 0.312988f,
--0.0581055f, 0.289062f, -0.0351562f, 0.251953f, -0.0078125f, 0.236328f, 0.00292969f,
-0.228027f, 0.00585938f, 0.195801f, 0.0112305f, 0.178223f, 0.0180664f, 0.16748f, 0.0209961f,
-0.162109f, 0.0209961f, 0.143066f, 0.0209961f, 0.111328f, 0.00878906f, 0.0795898f,
--0.00341797f, 0.0678711f, -0.0161133f, 0.0488281f, -0.0351562f, 0.0488281f, -0.0649414f,
-0.0498047f, -0.0751953f, 0.0600586f, -0.0820312f, 0.0600586f, -0.0878906f, 0.0600586f,
--0.0888672f, 0.0598145f, -0.0895996f, 0.0595703f, -0.090332f, 0.059082f, -0.0908203f,
-0.0488281f, -0.10498f, 0.0478516f, -0.119141f, 0.0507812f, -0.131836f, 0.0698242f,
--0.175781f, 0.065918f, -0.192871f, 0.065918f, -0.199219f, 0.065918f, -0.20459f, 0.0698242f,
--0.223145f, 0.0791016f, -0.258789f, 0.0820312f, -0.271484f, 0.0839844f, -0.283203f,
-0.0849609f, -0.320801f, 0.0942383f, -0.358887f, 0.0942383f, -0.365723f, 0.0869141f,
--0.375977f, 0.0732422f, -0.37793f, 0.0717773f, -0.38623f, 0.0898438f, -0.407227f,
-0.101074f, -0.411133f, 0.118164f, -0.416016f, 0.166992f, -0.443848f, 0.169922f, -0.443848f,
-0.177246f, -0.443848f, 0.181641f, -0.437988f, 0.186035f, -0.432129f, 0.186035f, -0.422852f,
-0.186035f, -0.419922f, 0.170898f, -0.382812f, 0.164062f, -0.346191f, 0.151855f, -0.290039f,
-0.148926f, -0.256836f, 0.146484f, -0.249512f, 0.141113f, -0.248047f, 0.125977f, -0.244141f,
-0.118164f, -0.241211f, 0.118164f, -0.23291f, 0.118164f, -0.221191f, 0.138184f, -0.221191f,
-0.124023f, -0.120117f, 0.120117f, -0.0908203f, 0.123047f, -0.0830078f, 0.129883f,
--0.0742188f, 0.144043f, -0.0507812f, 0.171875f, -0.0400391f, 0.185059f, -0.0249023f,
-0.191895f, -0.0219727f, 0.195801f, -0.0219727f, 0.211914f, -0.0332031f, 0.258789f,
--0.0488281f, 0.278809f, -0.0629883f, 0.312988f, -0.0869141f, 0.345215f, -0.118164f,
-0.366211f, -0.130859f, 0.375f, -0.13623f, 0.393066f, -0.183105f, 0.395996f, -0.185059f,
-0.397949f, -0.193848f, 0.408203f, -0.206055f, 0.403809f, -0.23291f, 0.408203f, -0.240234f,
-0.405762f, -0.26123f, 0.40918f, -0.271973f, 0.400879f, -0.314941f, 0.396973f, -0.374023f,
-0.382812f, -0.402832f, 0.381836f, -0.404785f, 0.381836f, -0.40918f, 0.381836f, -0.416992f,
-0.402832f, -0.423828f, 0.417969f, -0.437988f, 0.446777f, -0.441895f, 0.458008f, -0.444824f,
-0.472168f, -0.435059f, 0.472168f, -0.428223f, 0.472168f, -0.425781f, 0.469238f, -0.408203f,
-0.471191f, -0.373047f, 0.466797f, -0.358887f, 0.466797f, -0.346191f, 0.460938f, -0.324219f,
-0.461914f, -0.316895f, 0.469238f, -0.299316f, 0.473145f, -0.290527f, 0.477051f, -0.281738f,
-0.477051f, -0.276855f, 0.477051f, -0.26416f, 0.479004f, -0.23291f, 0.472168f, -0.21582f,
-0.470215f, -0.209961f, 0.470215f, -0.207031f, 0.470215f, -0.193359f, 0.48584f, -0.179199f,
-0.484863f, -0.166992f
-};
-
-const unsigned char PapyruskNormalVerbs[] = {
-6, 0, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 2, 1, 1, 5, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1,
-2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
-1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2,
-2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2,
-2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2,
-1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1,
-2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1,
-5, 6, 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1,
-1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
-1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2,
-2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1,
-2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
-2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 5, 0, 2, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 5, 6, 0, 2, 1, 2, 2, 1, 1, 1, 1,
-1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
-1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 5, 6, 0, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1,
-1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1,
-1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 5, 0, 2, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 0, 1, 1, 1,
-1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1,
-2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2,
-1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2,
-1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 1, 2, 2,
-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2,
-2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 5, 0, 1, 1, 1, 1,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 5, 6, 0, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1,
-1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 5, 0, 2, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 5, 6, 0, 2, 1, 1, 1, 1, 1,
-1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1,
-1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 5,
-6, 0, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 5, 6, 0, 2, 1, 2, 1, 1, 1,
-1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1,
-1, 2, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2,
-2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
-2, 2, 2, 2, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2,
-2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1,
-1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
-1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 5, 6
-};
-
-const unsigned PapyruskNormalCharCodes[] = {
-32, 33, 72, 84, 97,
-99, 101, 102, 108, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed PapyruskNormalWidths[] = {
-0x00003a20, 0x000042e0, 0x0000c3e0, 0x0000b1e0, 0x00008940, 0x00007f80, 0x000087e0,
-0x000064a0, 0x00003860, 0x00008c80, 0x00009920, 0x00009d20, 0x000062e0, 0x000078e0,
-0x00008f20, 0x00008a40
-};
-
-const int PapyruskNormalCharCodesCount = (int) SK_ARRAY_COUNT(PapyruskNormalCharCodes);
-
-const SkPaint::FontMetrics PapyruskNormalMetrics = {
-0x00000003, -0.944824f, -0.939941f, 0.603027f, 0.603027f, 0, 2.51855f, 0, -0.5625f,
-1.95605f, 0.464355f, 0, 0.0673828f, 0.166504f
-};
-
-const SkScalar TimesNewRomankNormalPoints[] = {
-0.175781f, -0.175293f, 0.157227f, -0.175293f, 0.114258f, -0.570801f, 0.111328f, -0.59668f,
-0.111328f, -0.609375f, 0.111328f, -0.640137f, 0.127686f, -0.658691f, 0.144043f, -0.677246f,
-0.166992f, -0.677246f, 0.189941f, -0.677246f, 0.205811f, -0.658691f, 0.22168f, -0.640137f,
-0.22168f, -0.603516f, 0.22168f, -0.591797f, 0.219727f, -0.570801f, 0.166016f, -0.0942383f,
-0.188477f, -0.0942383f, 0.204346f, -0.0783691f, 0.220215f, -0.0625f, 0.220215f, -0.0405273f,
-0.220215f, -0.0180664f, 0.204346f, -0.00219727f, 0.188477f, 0.0136719f, 0.166016f,
-0.0136719f, 0.143555f, 0.0136719f, 0.127686f, -0.00219727f, 0.111816f, -0.0180664f,
-0.111816f, -0.0405273f, 0.111816f, -0.0625f, 0.127686f, -0.0783691f, 0.143555f, -0.0942383f,
-0.166016f, -0.0942383f, 0.28125f, -0.39209f, 0.254883f, -0.534668f, 0.244141f, -0.59375f,
-0.243164f, -0.605957f, 0.243164f, -0.618164f, 0.243164f, -0.648926f, 0.256836f, -0.663086f,
-0.270508f, -0.677246f, 0.292969f, -0.677246f, 0.313965f, -0.677246f, 0.327881f, -0.663086f,
-0.341797f, -0.648926f, 0.341797f, -0.625f, 0.341797f, -0.583496f, 0.33252f, -0.535156f,
-0.304688f, -0.39209f, 0.102539f, -0.39209f, 0.0756836f, -0.536621f, 0.0649414f, -0.596191f,
-0.0649414f, -0.617676f, 0.0649414f, -0.648926f, 0.0778809f, -0.663086f, 0.0908203f,
--0.677246f, 0.112793f, -0.677246f, 0.134277f, -0.677246f, 0.148438f, -0.662842f,
-0.162598f, -0.648438f, 0.162598f, -0.624512f, 0.162598f, -0.605469f, 0.149902f, -0.536133f,
-0.123535f, -0.39209f, 0.0561523f, 0.0136719f, 0.101562f, -0.208496f, 0.0180664f,
--0.208496f, 0.0180664f, -0.248535f, 0.109375f, -0.248535f, 0.143066f, -0.416016f,
-0.0180664f, -0.416016f, 0.0180664f, -0.455078f, 0.152344f, -0.455078f, 0.196777f,
--0.677246f, 0.237305f, -0.677246f, 0.192871f, -0.455078f, 0.357422f, -0.455078f,
-0.404785f, -0.677246f, 0.445312f, -0.677246f, 0.398926f, -0.455078f, 0.481934f, -0.455078f,
-0.481934f, -0.416016f, 0.391602f, -0.416016f, 0.357422f, -0.248535f, 0.481934f, -0.248535f,
-0.481934f, -0.208496f, 0.349121f, -0.208496f, 0.303711f, 0.0136719f, 0.26416f, 0.0136719f,
-0.308594f, -0.208496f, 0.143066f, -0.208496f, 0.0966797f, 0.0136719f, 0.150391f,
--0.248535f, 0.315918f, -0.248535f, 0.351074f, -0.416016f, 0.18457f, -0.416016f, 0.0527344f,
--0.163086f, 0.0742188f, -0.163086f, 0.0795898f, -0.0961914f, 0.116211f, -0.0605469f,
-0.152832f, -0.0249023f, 0.225586f, -0.0180664f, 0.225586f, -0.303223f, 0.115723f,
--0.371094f, 0.0791016f, -0.42334f, 0.0532227f, -0.460449f, 0.0532227f, -0.513672f,
-0.0532227f, -0.57373f, 0.0979004f, -0.618652f, 0.142578f, -0.663574f, 0.225586f,
--0.672852f, 0.225586f, -0.717773f, 0.256836f, -0.717773f, 0.256836f, -0.672852f,
-0.296875f, -0.67041f, 0.324219f, -0.663574f, 0.338379f, -0.660156f, 0.417969f, -0.629883f,
-0.417969f, -0.483887f, 0.398926f, -0.483887f, 0.392578f, -0.561523f, 0.358643f, -0.597412f,
-0.324707f, -0.633301f, 0.256836f, -0.640137f, 0.256836f, -0.39209f, 0.379883f, -0.306152f,
-0.414795f, -0.265381f, 0.449707f, -0.224609f, 0.449707f, -0.164062f, 0.449707f, -0.0966797f,
-0.398682f, -0.0454102f, 0.347656f, 0.00585938f, 0.256836f, 0.0136719f, 0.256836f,
-0.0761719f, 0.225586f, 0.0761719f, 0.225586f, 0.0136719f, 0.179688f, 0.0117188f,
-0.140137f, 0.00317383f, 0.100586f, -0.00537109f, 0.0527344f, -0.0249023f, 0.225586f,
--0.412598f, 0.225586f, -0.639648f, 0.176758f, -0.633789f, 0.153076f, -0.608643f,
-0.129395f, -0.583496f, 0.129395f, -0.54541f, 0.129395f, -0.509766f, 0.150879f, -0.47876f,
-0.172363f, -0.447754f, 0.225586f, -0.412598f, 0.256836f, -0.0180664f, 0.293457f,
--0.0244141f, 0.312988f, -0.0361328f, 0.340332f, -0.0532227f, 0.356201f, -0.0808105f,
-0.37207f, -0.108398f, 0.37207f, -0.139648f, 0.37207f, -0.171875f, 0.352783f, -0.200684f,
-0.333496f, -0.229492f, 0.256836f, -0.282227f, 0.679688f, -0.677246f, 0.197266f, 0.0273438f,
-0.153809f, 0.0273438f, 0.63623f, -0.677246f, 0.177734f, -0.677246f, 0.243652f, -0.677246f,
-0.280029f, -0.622559f, 0.316406f, -0.567871f, 0.316406f, -0.49707f, 0.316406f, -0.412109f,
-0.275391f, -0.365723f, 0.234375f, -0.319336f, 0.176758f, -0.319336f, 0.138184f, -0.319336f,
-0.105957f, -0.340576f, 0.0737305f, -0.361816f, 0.0544434f, -0.403809f, 0.0351562f,
--0.445801f, 0.0351562f, -0.49707f, 0.0351562f, -0.54834f, 0.0546875f, -0.591553f,
-0.0742188f, -0.634766f, 0.108154f, -0.656006f, 0.14209f, -0.677246f, 0.177734f, -0.677246f,
-0.17627f, -0.649902f, 0.151367f, -0.649902f, 0.13208f, -0.620605f, 0.112793f, -0.591309f,
-0.112793f, -0.497559f, 0.112793f, -0.429688f, 0.123535f, -0.394043f, 0.131836f, -0.367188f,
-0.149414f, -0.352539f, 0.159668f, -0.34375f, 0.174805f, -0.34375f, 0.198242f, -0.34375f,
-0.214844f, -0.369141f, 0.239258f, -0.406738f, 0.239258f, -0.494629f, 0.239258f, -0.587402f,
-0.215332f, -0.625f, 0.199707f, -0.649902f, 0.17627f, -0.649902f, 0.657227f, -0.328613f,
-0.691895f, -0.328613f, 0.726318f, -0.306641f, 0.760742f, -0.284668f, 0.779541f, -0.242676f,
-0.79834f, -0.200684f, 0.79834f, -0.150391f, 0.79834f, -0.0639648f, 0.756836f, -0.0183105f,
-0.715332f, 0.0273438f, 0.658691f, 0.0273438f, 0.623047f, 0.0273438f, 0.5896f, 0.00537109f,
-0.556152f, -0.0166016f, 0.536865f, -0.057373f, 0.517578f, -0.0981445f, 0.517578f,
--0.150391f, 0.517578f, -0.20166f, 0.536865f, -0.244141f, 0.556152f, -0.286621f, 0.5896f,
--0.307617f, 0.623047f, -0.328613f, 0.657227f, -0.328613f, 0.657715f, -0.302734f,
-0.634277f, -0.302734f, 0.617188f, -0.276367f, 0.595215f, -0.242188f, 0.595215f, -0.146973f,
-0.595215f, -0.0595703f, 0.617676f, -0.0249023f, 0.634277f, 0, 0.657715f, 0, 0.680176f,
-0, 0.697754f, -0.0268555f, 0.721191f, -0.0625f, 0.721191f, -0.149414f, 0.721191f,
--0.241211f, 0.697754f, -0.277832f, 0.681641f, -0.302734f, 0.657715f, -0.302734f,
-0.510254f, -0.42627f, 0.715332f, -0.42627f, 0.715332f, -0.408203f, 0.672852f, -0.404785f,
-0.652588f, -0.389404f, 0.632324f, -0.374023f, 0.589355f, -0.296387f, 0.546387f, -0.21875f,
-0.492676f, -0.151367f, 0.536133f, -0.100586f, 0.570312f, -0.0803223f, 0.604492f,
--0.0600586f, 0.63916f, -0.0600586f, 0.672852f, -0.0600586f, 0.696289f, -0.0783691f,
-0.719727f, -0.0966797f, 0.729492f, -0.132324f, 0.747559f, -0.119141f, 0.729492f,
--0.050293f, 0.689453f, -0.0175781f, 0.649414f, 0.0151367f, 0.596191f, 0.0151367f,
-0.556152f, 0.0151367f, 0.514893f, -0.0065918f, 0.473633f, -0.0283203f, 0.424805f,
--0.0800781f, 0.364258f, -0.0263672f, 0.315674f, -0.00561523f, 0.26709f, 0.0151367f,
-0.211914f, 0.0151367f, 0.131348f, 0.0151367f, 0.0839844f, -0.027832f, 0.0366211f,
--0.0708008f, 0.0366211f, -0.130371f, 0.0366211f, -0.189453f, 0.0791016f, -0.248291f,
-0.121582f, -0.307129f, 0.23877f, -0.370117f, 0.21582f, -0.420898f, 0.20752f, -0.453369f,
-0.199219f, -0.48584f, 0.199219f, -0.515625f, 0.199219f, -0.599121f, 0.260742f, -0.643066f,
-0.308594f, -0.677246f, 0.369629f, -0.677246f, 0.427734f, -0.677246f, 0.464355f, -0.642822f,
-0.500977f, -0.608398f, 0.500977f, -0.558105f, 0.500977f, -0.506348f, 0.465576f, -0.467285f,
-0.430176f, -0.428223f, 0.340332f, -0.381836f, 0.402344f, -0.271484f, 0.469727f, -0.179688f,
-0.555664f, -0.282227f, 0.555664f, -0.352539f, 0.555664f, -0.375f, 0.541016f, -0.392578f,
-0.530273f, -0.405762f, 0.510254f, -0.408203f, 0.32373f, -0.413574f, 0.384277f, -0.442383f,
-0.414307f, -0.479004f, 0.444336f, -0.515625f, 0.444336f, -0.560547f, 0.444336f, -0.595703f,
-0.422607f, -0.618652f, 0.400879f, -0.641602f, 0.368652f, -0.641602f, 0.326172f, -0.641602f,
-0.304443f, -0.612061f, 0.282715f, -0.58252f, 0.282715f, -0.554199f, 0.282715f, -0.530273f,
-0.291016f, -0.500732f, 0.299316f, -0.471191f, 0.32373f, -0.413574f, 0.399414f, -0.108398f,
-0.334961f, -0.196289f, 0.310059f, -0.236816f, 0.285156f, -0.277344f, 0.255371f, -0.337402f,
-0.196777f, -0.303711f, 0.167236f, -0.263184f, 0.137695f, -0.222656f, 0.137695f, -0.175293f,
-0.137695f, -0.123047f, 0.171387f, -0.0834961f, 0.205078f, -0.0439453f, 0.262207f,
--0.0439453f, 0.292969f, -0.0439453f, 0.321533f, -0.0561523f, 0.350098f, -0.0683594f,
-0.399414f, -0.108398f, 0.0771484f, -0.39209f, 0.0507812f, -0.536621f, 0.0395508f,
--0.59668f, 0.0395508f, -0.617676f, 0.0395508f, -0.648926f, 0.0522461f, -0.663086f,
-0.0649414f, -0.677246f, 0.0869141f, -0.677246f, 0.108887f, -0.677246f, 0.123291f,
--0.662842f, 0.137695f, -0.648438f, 0.137695f, -0.625f, 0.137695f, -0.606934f, 0.125f,
--0.536133f, 0.0986328f, -0.39209f, 0.310547f, 0.195801f, 0.310547f, 0.213867f, 0.236816f,
-0.176758f, 0.1875f, 0.126953f, 0.117188f, 0.0561523f, 0.0791016f, -0.0400391f, 0.0410156f,
--0.13623f, 0.0410156f, -0.239746f, 0.0410156f, -0.391113f, 0.115723f, -0.515869f,
-0.19043f, -0.640625f, 0.310547f, -0.694336f, 0.310547f, -0.673828f, 0.250488f, -0.640625f,
-0.211914f, -0.583008f, 0.17334f, -0.525391f, 0.154297f, -0.437012f, 0.135254f, -0.348633f,
-0.135254f, -0.252441f, 0.135254f, -0.147949f, 0.151367f, -0.0625f, 0.164062f, 0.00488281f,
-0.182129f, 0.0456543f, 0.200195f, 0.0864258f, 0.230713f, 0.124023f, 0.26123f, 0.161621f,
-0.310547f, 0.195801f, 0.0224609f, -0.673828f, 0.0224609f, -0.694336f, 0.0966797f,
--0.657715f, 0.145996f, -0.60791f, 0.21582f, -0.536621f, 0.253906f, -0.440674f, 0.291992f,
--0.344727f, 0.291992f, -0.240723f, 0.291992f, -0.0893555f, 0.217529f, 0.0354004f,
-0.143066f, 0.160156f, 0.0224609f, 0.213867f, 0.0224609f, 0.195801f, 0.0825195f, 0.162109f,
-0.121338f, 0.104736f, 0.160156f, 0.0473633f, 0.178955f, -0.0412598f, 0.197754f, -0.129883f,
-0.197754f, -0.226074f, 0.197754f, -0.330078f, 0.181641f, -0.416016f, 0.169434f, -0.483398f,
-0.151123f, -0.523926f, 0.132812f, -0.564453f, 0.102539f, -0.602051f, 0.0722656f,
--0.639648f, 0.0224609f, -0.673828f, 0.241211f, -0.509766f, 0.239258f, -0.543457f,
-0.227539f, -0.57666f, 0.210938f, -0.624512f, 0.210938f, -0.642578f, 0.210938f, -0.667969f,
-0.2229f, -0.681152f, 0.234863f, -0.694336f, 0.252441f, -0.694336f, 0.267578f, -0.694336f,
-0.278809f, -0.681152f, 0.290039f, -0.667969f, 0.290039f, -0.643555f, 0.290039f, -0.621582f,
-0.2771f, -0.582275f, 0.26416f, -0.542969f, 0.26123f, -0.509766f, 0.288086f, -0.526855f,
-0.30957f, -0.55127f, 0.342773f, -0.589844f, 0.358887f, -0.599121f, 0.375f, -0.608398f,
-0.391602f, -0.608398f, 0.407715f, -0.608398f, 0.418701f, -0.597412f, 0.429688f, -0.586426f,
-0.429688f, -0.571289f, 0.429688f, -0.553223f, 0.413574f, -0.539062f, 0.397461f, -0.524902f,
-0.333008f, -0.510742f, 0.29541f, -0.502441f, 0.270508f, -0.491699f, 0.295898f, -0.478516f,
-0.33252f, -0.47168f, 0.391602f, -0.460938f, 0.409912f, -0.444824f, 0.428223f, -0.428711f,
-0.428223f, -0.409668f, 0.428223f, -0.39502f, 0.417236f, -0.384277f, 0.40625f, -0.373535f,
-0.391602f, -0.373535f, 0.376953f, -0.373535f, 0.359131f, -0.383789f, 0.341309f, -0.394043f,
-0.311035f, -0.429688f, 0.291016f, -0.453613f, 0.26123f, -0.474609f, 0.262207f, -0.446777f,
-0.272461f, -0.414062f, 0.290039f, -0.356445f, 0.290039f, -0.335449f, 0.290039f, -0.315918f,
-0.27832f, -0.30249f, 0.266602f, -0.289062f, 0.253418f, -0.289062f, 0.235352f, -0.289062f,
-0.220703f, -0.303223f, 0.210449f, -0.313477f, 0.210449f, -0.335938f, 0.210449f, -0.359375f,
-0.22168f, -0.392334f, 0.23291f, -0.425293f, 0.23584f, -0.437744f, 0.23877f, -0.450195f,
-0.241211f, -0.474609f, 0.212402f, -0.455566f, 0.190918f, -0.432129f, 0.155273f, -0.39209f,
-0.137207f, -0.381348f, 0.124512f, -0.373535f, 0.11084f, -0.373535f, 0.0942383f, -0.373535f,
-0.0825195f, -0.384766f, 0.0708008f, -0.395996f, 0.0708008f, -0.409668f, 0.0708008f,
--0.421875f, 0.0808105f, -0.435303f, 0.0908203f, -0.44873f, 0.11084f, -0.45752f, 0.124023f,
--0.463379f, 0.170898f, -0.473145f, 0.201172f, -0.479492f, 0.22998f, -0.491699f, 0.203613f,
--0.504883f, 0.166992f, -0.512207f, 0.106934f, -0.524902f, 0.0927734f, -0.535156f,
-0.0708008f, -0.55127f, 0.0708008f, -0.574219f, 0.0708008f, -0.587402f, 0.0817871f,
--0.598389f, 0.0927734f, -0.609375f, 0.107422f, -0.609375f, 0.123535f, -0.609375f,
-0.141602f, -0.599121f, 0.159668f, -0.588867f, 0.186523f, -0.557861f, 0.213379f, -0.526855f,
-0.241211f, -0.509766f, 0.26123f, -0.0688477f, 0.26123f, -0.3125f, 0.0180664f, -0.3125f,
-0.0180664f, -0.352539f, 0.26123f, -0.352539f, 0.26123f, -0.595215f, 0.300293f, -0.595215f,
-0.300293f, -0.352539f, 0.544434f, -0.352539f, 0.544434f, -0.3125f, 0.300293f, -0.3125f,
-0.300293f, -0.0688477f, 0.0537109f, 0.166504f, 0.0537109f, 0.14502f, 0.104004f, 0.128418f,
-0.131592f, 0.0935059f, 0.15918f, 0.0585938f, 0.15918f, 0.0195312f, 0.15918f, 0.0102539f,
-0.154785f, 0.00390625f, 0.151367f, -0.000488281f, 0.147949f, -0.000488281f, 0.142578f,
--0.000488281f, 0.124512f, 0.00927734f, 0.115723f, 0.0136719f, 0.105957f, 0.0136719f,
-0.0820312f, 0.0136719f, 0.0678711f, -0.000488281f, 0.0537109f, -0.0146484f, 0.0537109f,
--0.0395508f, 0.0537109f, -0.0634766f, 0.0720215f, -0.0805664f, 0.090332f, -0.0976562f,
-0.116699f, -0.0976562f, 0.148926f, -0.0976562f, 0.174072f, -0.0695801f, 0.199219f,
--0.0415039f, 0.199219f, 0.00488281f, 0.199219f, 0.0551758f, 0.164307f, 0.0983887f,
-0.129395f, 0.141602f, 0.0537109f, 0.166504f, 0.0405273f, -0.26123f, 0.292969f, -0.26123f,
-0.292969f, -0.1875f, 0.0405273f, -0.1875f, 0.125f, -0.0947266f, 0.147949f, -0.0947266f,
-0.163574f, -0.0788574f, 0.179199f, -0.0629883f, 0.179199f, -0.0405273f, 0.179199f,
--0.0180664f, 0.16333f, -0.00219727f, 0.147461f, 0.0136719f, 0.125f, 0.0136719f, 0.102539f,
-0.0136719f, 0.0866699f, -0.00219727f, 0.0708008f, -0.0180664f, 0.0708008f, -0.0405273f,
-0.0708008f, -0.0634766f, 0.0866699f, -0.0791016f, 0.102539f, -0.0947266f, 0.125f,
--0.0947266f, 0.280273f, -0.694336f, 0.0405273f, 0.0136719f, 0.00146484f, 0.0136719f,
-0.241211f, -0.694336f, 0.117188f, -0.597168f, 0.27832f, -0.675781f, 0.294434f, -0.675781f,
-0.294434f, -0.116699f, 0.294434f, -0.0610352f, 0.299072f, -0.0473633f, 0.303711f,
--0.0336914f, 0.318359f, -0.0263672f, 0.333008f, -0.019043f, 0.37793f, -0.0180664f,
-0.37793f, 0, 0.128906f, 0, 0.128906f, -0.0180664f, 0.175781f, -0.019043f, 0.189453f,
--0.026123f, 0.203125f, -0.0332031f, 0.208496f, -0.045166f, 0.213867f, -0.0571289f,
-0.213867f, -0.116699f, 0.213867f, -0.474121f, 0.213867f, -0.546387f, 0.208984f, -0.566895f,
-0.205566f, -0.58252f, 0.196533f, -0.589844f, 0.1875f, -0.597168f, 0.174805f, -0.597168f,
-0.156738f, -0.597168f, 0.124512f, -0.582031f, 0.458496f, -0.127441f, 0.412109f, 0,
-0.0214844f, 0, 0.0214844f, -0.0180664f, 0.193848f, -0.175293f, 0.26416f, -0.274902f,
-0.334473f, -0.374512f, 0.334473f, -0.457031f, 0.334473f, -0.52002f, 0.295898f, -0.560547f,
-0.257324f, -0.601074f, 0.203613f, -0.601074f, 0.154785f, -0.601074f, 0.115967f, -0.57251f,
-0.0771484f, -0.543945f, 0.0585938f, -0.48877f, 0.0405273f, -0.48877f, 0.0527344f,
--0.579102f, 0.103271f, -0.627441f, 0.153809f, -0.675781f, 0.229492f, -0.675781f,
-0.310059f, -0.675781f, 0.364014f, -0.624023f, 0.417969f, -0.572266f, 0.417969f, -0.501953f,
-0.417969f, -0.45166f, 0.394531f, -0.401367f, 0.358398f, -0.322266f, 0.277344f, -0.233887f,
-0.155762f, -0.101074f, 0.125488f, -0.0737305f, 0.29834f, -0.0737305f, 0.351074f,
--0.0737305f, 0.372314f, -0.0776367f, 0.393555f, -0.081543f, 0.410645f, -0.0935059f,
-0.427734f, -0.105469f, 0.44043f, -0.127441f, 0.0507812f, -0.536133f, 0.0791016f,
--0.603027f, 0.122314f, -0.639404f, 0.165527f, -0.675781f, 0.22998f, -0.675781f, 0.30957f,
--0.675781f, 0.352051f, -0.624023f, 0.384277f, -0.585449f, 0.384277f, -0.541504f,
-0.384277f, -0.469238f, 0.293457f, -0.39209f, 0.354492f, -0.368164f, 0.385742f, -0.32373f,
-0.416992f, -0.279297f, 0.416992f, -0.219238f, 0.416992f, -0.133301f, 0.362305f, -0.0703125f,
-0.291016f, 0.0117188f, 0.155762f, 0.0117188f, 0.0888672f, 0.0117188f, 0.0646973f,
--0.00488281f, 0.0405273f, -0.0214844f, 0.0405273f, -0.0405273f, 0.0405273f, -0.0546875f,
-0.052002f, -0.0654297f, 0.0634766f, -0.0761719f, 0.0795898f, -0.0761719f, 0.0917969f,
--0.0761719f, 0.104492f, -0.0722656f, 0.112793f, -0.0698242f, 0.14209f, -0.0544434f,
-0.171387f, -0.0390625f, 0.182617f, -0.0361328f, 0.200684f, -0.0307617f, 0.221191f,
--0.0307617f, 0.270996f, -0.0307617f, 0.307861f, -0.0693359f, 0.344727f, -0.10791f,
-0.344727f, -0.160645f, 0.344727f, -0.199219f, 0.327637f, -0.23584f, 0.314941f, -0.263184f,
-0.299805f, -0.277344f, 0.278809f, -0.296875f, 0.242188f, -0.312744f, 0.205566f, -0.328613f,
-0.16748f, -0.328613f, 0.151855f, -0.328613f, 0.151855f, -0.343262f, 0.19043f, -0.348145f,
-0.229248f, -0.371094f, 0.268066f, -0.394043f, 0.285645f, -0.42627f, 0.303223f, -0.458496f,
-0.303223f, -0.49707f, 0.303223f, -0.547363f, 0.271729f, -0.578369f, 0.240234f, -0.609375f,
-0.193359f, -0.609375f, 0.117676f, -0.609375f, 0.0668945f, -0.52832f, 0.465332f, -0.244141f,
-0.465332f, -0.174805f, 0.376465f, -0.174805f, 0.376465f, 0, 0.295898f, 0, 0.295898f,
--0.174805f, 0.015625f, -0.174805f, 0.015625f, -0.237305f, 0.322754f, -0.675781f,
-0.376465f, -0.675781f, 0.376465f, -0.244141f, 0.295898f, -0.244141f, 0.295898f, -0.572754f,
-0.0634766f, -0.244141f, 0.434082f, -0.662109f, 0.395996f, -0.579102f, 0.196777f,
--0.579102f, 0.15332f, -0.490234f, 0.282715f, -0.471191f, 0.358398f, -0.394043f, 0.42334f,
--0.327637f, 0.42334f, -0.237793f, 0.42334f, -0.185547f, 0.4021f, -0.141113f, 0.380859f,
--0.0966797f, 0.348633f, -0.0654297f, 0.316406f, -0.0341797f, 0.276855f, -0.0151367f,
-0.220703f, 0.0117188f, 0.161621f, 0.0117188f, 0.102051f, 0.0117188f, 0.0749512f,
--0.00854492f, 0.0478516f, -0.0288086f, 0.0478516f, -0.0532227f, 0.0478516f, -0.0668945f,
-0.059082f, -0.0773926f, 0.0703125f, -0.0878906f, 0.0874023f, -0.0878906f, 0.100098f,
--0.0878906f, 0.109619f, -0.0839844f, 0.119141f, -0.0800781f, 0.14209f, -0.0639648f,
-0.178711f, -0.0385742f, 0.216309f, -0.0385742f, 0.273438f, -0.0385742f, 0.31665f,
--0.0817871f, 0.359863f, -0.125f, 0.359863f, -0.187012f, 0.359863f, -0.24707f, 0.321289f,
--0.299072f, 0.282715f, -0.351074f, 0.214844f, -0.379395f, 0.161621f, -0.401367f,
-0.0698242f, -0.404785f, 0.196777f, -0.662109f, 0.448242f, -0.675781f, 0.448242f,
--0.657715f, 0.383789f, -0.651367f, 0.343018f, -0.63208f, 0.302246f, -0.612793f, 0.262451f,
--0.573242f, 0.222656f, -0.533691f, 0.196533f, -0.485107f, 0.17041f, -0.436523f, 0.152832f,
--0.369629f, 0.223145f, -0.417969f, 0.293945f, -0.417969f, 0.361816f, -0.417969f,
-0.411621f, -0.363281f, 0.461426f, -0.308594f, 0.461426f, -0.222656f, 0.461426f, -0.139648f,
-0.411133f, -0.0712891f, 0.350586f, 0.0117188f, 0.250977f, 0.0117188f, 0.183105f,
-0.0117188f, 0.135742f, -0.0332031f, 0.0429688f, -0.120605f, 0.0429688f, -0.259766f,
-0.0429688f, -0.348633f, 0.0786133f, -0.428711f, 0.114258f, -0.508789f, 0.18042f,
--0.570801f, 0.246582f, -0.632812f, 0.307129f, -0.654297f, 0.367676f, -0.675781f,
-0.419922f, -0.675781f, 0.144531f, -0.333984f, 0.135742f, -0.268066f, 0.135742f, -0.227539f,
-0.135742f, -0.180664f, 0.153076f, -0.125732f, 0.17041f, -0.0708008f, 0.20459f, -0.0385742f,
-0.229492f, -0.015625f, 0.265137f, -0.015625f, 0.307617f, -0.015625f, 0.341064f, -0.0556641f,
-0.374512f, -0.0957031f, 0.374512f, -0.169922f, 0.374512f, -0.253418f, 0.341309f,
--0.314453f, 0.308105f, -0.375488f, 0.24707f, -0.375488f, 0.228516f, -0.375488f, 0.207275f,
--0.367676f, 0.186035f, -0.359863f, 0.144531f, -0.333984f, 0.100586f, -0.662109f,
-0.455566f, -0.662109f, 0.455566f, -0.643555f, 0.234863f, 0.0136719f, 0.180176f, 0.0136719f,
-0.37793f, -0.58252f, 0.195801f, -0.58252f, 0.140625f, -0.58252f, 0.117188f, -0.569336f,
-0.0761719f, -0.546875f, 0.0512695f, -0.5f, 0.0371094f, -0.505371f, 0.191895f, -0.333496f,
-0.113281f, -0.397949f, 0.0905762f, -0.437012f, 0.0678711f, -0.476074f, 0.0678711f,
--0.518066f, 0.0678711f, -0.58252f, 0.117676f, -0.62915f, 0.16748f, -0.675781f, 0.25f,
--0.675781f, 0.330078f, -0.675781f, 0.378906f, -0.632324f, 0.427734f, -0.588867f,
-0.427734f, -0.533203f, 0.427734f, -0.496094f, 0.401367f, -0.45752f, 0.375f, -0.418945f,
-0.291504f, -0.366699f, 0.377441f, -0.300293f, 0.405273f, -0.262207f, 0.442383f, -0.212402f,
-0.442383f, -0.157227f, 0.442383f, -0.0874023f, 0.38916f, -0.0378418f, 0.335938f,
-0.0117188f, 0.249512f, 0.0117188f, 0.155273f, 0.0117188f, 0.102539f, -0.0473633f,
-0.0605469f, -0.0947266f, 0.0605469f, -0.150879f, 0.0605469f, -0.194824f, 0.0900879f,
--0.238037f, 0.119629f, -0.28125f, 0.191895f, -0.333496f, 0.268555f, -0.385742f, 0.327148f,
--0.438477f, 0.342773f, -0.468994f, 0.358398f, -0.499512f, 0.358398f, -0.538086f,
-0.358398f, -0.589355f, 0.32959f, -0.618408f, 0.300781f, -0.647461f, 0.250977f, -0.647461f,
-0.201172f, -0.647461f, 0.169922f, -0.618652f, 0.138672f, -0.589844f, 0.138672f, -0.55127f,
-0.138672f, -0.525879f, 0.151611f, -0.500488f, 0.164551f, -0.475098f, 0.188477f, -0.452148f,
-0.214844f, -0.314941f, 0.174316f, -0.280762f, 0.154785f, -0.240479f, 0.135254f, -0.200195f,
-0.135254f, -0.15332f, 0.135254f, -0.090332f, 0.169678f, -0.0524902f, 0.204102f, -0.0146484f,
-0.257324f, -0.0146484f, 0.310059f, -0.0146484f, 0.341797f, -0.0444336f, 0.373535f,
--0.0742188f, 0.373535f, -0.116699f, 0.373535f, -0.151855f, 0.35498f, -0.179688f,
-0.320312f, -0.231445f, 0.214844f, -0.314941f, 0.0527344f, 0.0136719f, 0.0527344f,
--0.00439453f, 0.116211f, -0.00537109f, 0.170898f, -0.0339355f, 0.225586f, -0.0625f,
-0.276611f, -0.133789f, 0.327637f, -0.205078f, 0.347656f, -0.290527f, 0.270996f, -0.241211f,
-0.208984f, -0.241211f, 0.13916f, -0.241211f, 0.0893555f, -0.295166f, 0.0395508f,
--0.349121f, 0.0395508f, -0.438477f, 0.0395508f, -0.525391f, 0.0893555f, -0.593262f,
-0.149414f, -0.675781f, 0.246094f, -0.675781f, 0.327637f, -0.675781f, 0.385742f, -0.608398f,
-0.457031f, -0.524902f, 0.457031f, -0.402344f, 0.457031f, -0.291992f, 0.402832f, -0.196533f,
-0.348633f, -0.101074f, 0.251953f, -0.0380859f, 0.17334f, 0.0136719f, 0.0805664f,
-0.0136719f, 0.355469f, -0.32666f, 0.364258f, -0.390137f, 0.364258f, -0.428223f, 0.364258f,
--0.475586f, 0.348145f, -0.530518f, 0.332031f, -0.585449f, 0.30249f, -0.614746f, 0.272949f,
--0.644043f, 0.235352f, -0.644043f, 0.191895f, -0.644043f, 0.15918f, -0.60498f, 0.126465f,
--0.565918f, 0.126465f, -0.48877f, 0.126465f, -0.385742f, 0.169922f, -0.327637f, 0.20166f,
--0.285645f, 0.248047f, -0.285645f, 0.270508f, -0.285645f, 0.30127f, -0.296387f, 0.332031f,
--0.307129f, 0.355469f, -0.32666f, 0.137695f, -0.461426f, 0.160156f, -0.461426f, 0.176025f,
--0.445801f, 0.191895f, -0.430176f, 0.191895f, -0.407715f, 0.191895f, -0.385254f,
-0.176025f, -0.369385f, 0.160156f, -0.353516f, 0.137695f, -0.353516f, 0.115234f, -0.353516f,
-0.0993652f, -0.369385f, 0.0834961f, -0.385254f, 0.0834961f, -0.407715f, 0.0834961f,
--0.430176f, 0.0993652f, -0.445801f, 0.115234f, -0.461426f, 0.137695f, -0.461426f,
-0.0693359f, 0.166504f, 0.0693359f, 0.14502f, 0.119629f, 0.128418f, 0.147217f, 0.0935059f,
-0.174805f, 0.0585938f, 0.174805f, 0.0195312f, 0.174805f, 0.0102539f, 0.17041f, 0.00390625f,
-0.166992f, -0.000488281f, 0.163574f, -0.000488281f, 0.158203f, -0.000488281f, 0.140137f,
-0.00927734f, 0.131348f, 0.0136719f, 0.121582f, 0.0136719f, 0.0976562f, 0.0136719f,
-0.0834961f, -0.000488281f, 0.0693359f, -0.0146484f, 0.0693359f, -0.0395508f, 0.0693359f,
--0.0634766f, 0.0876465f, -0.0805664f, 0.105957f, -0.0976562f, 0.132324f, -0.0976562f,
-0.164551f, -0.0976562f, 0.189697f, -0.0695801f, 0.214844f, -0.0415039f, 0.214844f,
-0.00488281f, 0.214844f, 0.0551758f, 0.179932f, 0.0983887f, 0.14502f, 0.141602f, 0.0693359f,
-0.166504f, 0.0180664f, -0.344727f, 0.543457f, -0.572266f, 0.543457f, -0.529785f,
-0.0913086f, -0.333496f, 0.543457f, -0.135254f, 0.543457f, -0.0913086f, 0.0180664f,
--0.320801f, 0.0180664f, -0.431152f, 0.544922f, -0.431152f, 0.544922f, -0.391113f,
-0.0180664f, -0.391113f, 0.0180664f, -0.271973f, 0.544922f, -0.271973f, 0.544922f,
--0.231934f, 0.0180664f, -0.231934f, 0.543457f, -0.318848f, 0.0180664f, -0.0913086f,
-0.0180664f, -0.133301f, 0.470703f, -0.32959f, 0.0180664f, -0.527832f, 0.0180664f,
--0.572266f, 0.543457f, -0.342773f, 0.22168f, -0.15625f, 0.20166f, -0.15625f, 0.205078f,
--0.217773f, 0.217041f, -0.258057f, 0.229004f, -0.29834f, 0.266602f, -0.370117f, 0.295898f,
--0.425293f, 0.304688f, -0.454834f, 0.313477f, -0.484375f, 0.313477f, -0.514648f,
-0.313477f, -0.57666f, 0.280518f, -0.613281f, 0.247559f, -0.649902f, 0.199707f, -0.649902f,
-0.157227f, -0.649902f, 0.132812f, -0.629883f, 0.108398f, -0.609863f, 0.108398f, -0.586426f,
-0.108398f, -0.568359f, 0.123047f, -0.541992f, 0.137695f, -0.515625f, 0.137695f, -0.501953f,
-0.137695f, -0.484375f, 0.126465f, -0.472412f, 0.115234f, -0.460449f, 0.0991211f,
--0.460449f, 0.0786133f, -0.460449f, 0.0617676f, -0.480713f, 0.0449219f, -0.500977f,
-0.0449219f, -0.537109f, 0.0449219f, -0.592285f, 0.0922852f, -0.634766f, 0.139648f,
--0.677246f, 0.220703f, -0.677246f, 0.321289f, -0.677246f, 0.368652f, -0.618652f,
-0.403809f, -0.575684f, 0.403809f, -0.523438f, 0.403809f, -0.487793f, 0.387939f, -0.450195f,
-0.37207f, -0.412598f, 0.327637f, -0.361816f, 0.256836f, -0.281738f, 0.240967f, -0.248291f,
-0.225098f, -0.214844f, 0.22168f, -0.15625f, 0.214844f, -0.0957031f, 0.237793f, -0.0957031f,
-0.253662f, -0.079834f, 0.269531f, -0.0639648f, 0.269531f, -0.0410156f, 0.269531f,
--0.0185547f, 0.253418f, -0.00268555f, 0.237305f, 0.0131836f, 0.214844f, 0.0131836f,
-0.192383f, 0.0131836f, 0.176514f, -0.00268555f, 0.160645f, -0.0185547f, 0.160645f,
--0.0410156f, 0.160645f, -0.0639648f, 0.176514f, -0.079834f, 0.192383f, -0.0957031f,
-0.214844f, -0.0957031f, 0.6875f, -0.467773f, 0.630371f, -0.272949f, 0.598633f, -0.163574f,
-0.591797f, -0.134277f, 0.584961f, -0.10498f, 0.584961f, -0.0874023f, 0.584961f, -0.0717773f,
-0.595459f, -0.0610352f, 0.605957f, -0.050293f, 0.621582f, -0.050293f, 0.657227f,
--0.050293f, 0.707275f, -0.0859375f, 0.757324f, -0.121582f, 0.792969f, -0.20166f,
-0.828613f, -0.281738f, 0.828613f, -0.368652f, 0.828613f, -0.452148f, 0.78833f, -0.522949f,
-0.748047f, -0.59375f, 0.674561f, -0.631592f, 0.601074f, -0.669434f, 0.512207f, -0.669434f,
-0.399414f, -0.669434f, 0.302734f, -0.609619f, 0.206055f, -0.549805f, 0.149658f, -0.4375f,
-0.0932617f, -0.325195f, 0.0932617f, -0.204102f, 0.0932617f, -0.0917969f, 0.142822f,
-0, 0.192383f, 0.0917969f, 0.282227f, 0.138916f, 0.37207f, 0.186035f, 0.475586f, 0.186035f,
-0.604004f, 0.186035f, 0.707764f, 0.117188f, 0.811523f, 0.0483398f, 0.868164f, -0.0839844f,
-0.896484f, -0.0839844f, 0.852539f, 0.0498047f, 0.736816f, 0.132812f, 0.621094f, 0.21582f,
-0.473145f, 0.21582f, 0.356934f, 0.21582f, 0.257324f, 0.160889f, 0.157715f, 0.105957f,
-0.102539f, 0.00512695f, 0.0473633f, -0.0957031f, 0.0473633f, -0.216797f, 0.0473633f,
--0.345703f, 0.10791f, -0.457275f, 0.168457f, -0.568848f, 0.277588f, -0.631592f, 0.386719f,
--0.694336f, 0.509277f, -0.694336f, 0.610352f, -0.694336f, 0.69165f, -0.652588f, 0.772949f,
--0.61084f, 0.81543f, -0.530518f, 0.85791f, -0.450195f, 0.85791f, -0.359863f, 0.85791f,
--0.270508f, 0.818115f, -0.182861f, 0.77832f, -0.0952148f, 0.716797f, -0.0551758f,
-0.655273f, -0.0151367f, 0.588379f, -0.0151367f, 0.55127f, -0.0151367f, 0.532471f,
--0.0327148f, 0.513672f, -0.050293f, 0.513672f, -0.0820312f, 0.513672f, -0.109375f,
-0.522461f, -0.153809f, 0.450195f, -0.0664062f, 0.406738f, -0.0405273f, 0.363281f,
--0.0146484f, 0.330078f, -0.0146484f, 0.29541f, -0.0146484f, 0.268555f, -0.0456543f,
-0.241699f, -0.0766602f, 0.241699f, -0.128418f, 0.241699f, -0.199219f, 0.287842f,
--0.287109f, 0.333984f, -0.375f, 0.410156f, -0.430176f, 0.466309f, -0.470703f, 0.510742f,
--0.470703f, 0.543457f, -0.470703f, 0.565186f, -0.453857f, 0.586914f, -0.437012f,
-0.594727f, -0.40332f, 0.61084f, -0.457031f, 0.516113f, -0.447754f, 0.479492f, -0.447754f,
-0.441895f, -0.40918f, 0.386719f, -0.352539f, 0.347656f, -0.256348f, 0.318848f, -0.186035f,
-0.318848f, -0.143066f, 0.318848f, -0.112305f, 0.336182f, -0.0930176f, 0.353516f,
--0.0737305f, 0.375f, -0.0737305f, 0.40332f, -0.0737305f, 0.43457f, -0.0952148f, 0.46582f,
--0.116699f, 0.5f, -0.161377f, 0.53418f, -0.206055f, 0.549805f, -0.250977f, 0.577148f,
--0.328613f, 0.577148f, -0.377441f, 0.577148f, -0.409668f, 0.559326f, -0.428711f,
-0.541504f, -0.447754f, 0.516113f, -0.447754f, 0.45752f, -0.22168f, 0.201172f, -0.22168f,
-0.15625f, -0.117188f, 0.139648f, -0.0786133f, 0.139648f, -0.0595703f, 0.139648f,
--0.0444336f, 0.154053f, -0.032959f, 0.168457f, -0.0214844f, 0.216309f, -0.0180664f,
-0.216309f, 0, 0.0078125f, 0, 0.0078125f, -0.0180664f, 0.0493164f, -0.0253906f, 0.0615234f,
--0.0371094f, 0.0864258f, -0.0605469f, 0.116699f, -0.132324f, 0.349609f, -0.677246f,
-0.366699f, -0.677246f, 0.597168f, -0.126465f, 0.625f, -0.0600586f, 0.647705f, -0.0402832f,
-0.67041f, -0.0205078f, 0.710938f, -0.0180664f, 0.710938f, 0, 0.449707f, 0, 0.449707f,
--0.0180664f, 0.489258f, -0.0200195f, 0.503174f, -0.03125f, 0.51709f, -0.0424805f,
-0.51709f, -0.0585938f, 0.51709f, -0.0800781f, 0.497559f, -0.126465f, 0.443848f, -0.257812f,
-0.331543f, -0.525391f, 0.216309f, -0.257812f, 0.461914f, -0.337891f, 0.530762f, -0.323242f,
-0.564941f, -0.291016f, 0.612305f, -0.246094f, 0.612305f, -0.181152f, 0.612305f, -0.131836f,
-0.581055f, -0.0866699f, 0.549805f, -0.0415039f, 0.495361f, -0.020752f, 0.440918f,
-0, 0.329102f, 0, 0.0166016f, 0, 0.0166016f, -0.0180664f, 0.0415039f, -0.0180664f,
-0.0830078f, -0.0180664f, 0.101074f, -0.0444336f, 0.112305f, -0.0615234f, 0.112305f,
--0.117188f, 0.112305f, -0.544922f, 0.112305f, -0.606445f, 0.0981445f, -0.622559f,
-0.0791016f, -0.644043f, 0.0415039f, -0.644043f, 0.0166016f, -0.644043f, 0.0166016f,
--0.662109f, 0.302734f, -0.662109f, 0.382812f, -0.662109f, 0.431152f, -0.650391f,
-0.504395f, -0.632812f, 0.542969f, -0.588135f, 0.581543f, -0.543457f, 0.581543f, -0.485352f,
-0.581543f, -0.435547f, 0.55127f, -0.39624f, 0.520996f, -0.356934f, 0.461914f, -0.337891f,
-0.206055f, -0.364258f, 0.224121f, -0.36084f, 0.247314f, -0.359131f, 0.270508f, -0.357422f,
-0.29834f, -0.357422f, 0.369629f, -0.357422f, 0.405518f, -0.372803f, 0.441406f, -0.388184f,
-0.460449f, -0.419922f, 0.479492f, -0.45166f, 0.479492f, -0.489258f, 0.479492f, -0.547363f,
-0.432129f, -0.588379f, 0.384766f, -0.629395f, 0.293945f, -0.629395f, 0.245117f, -0.629395f,
-0.206055f, -0.618652f, 0.206055f, -0.0478516f, 0.262695f, -0.034668f, 0.317871f,
--0.034668f, 0.40625f, -0.034668f, 0.452637f, -0.0744629f, 0.499023f, -0.114258f,
-0.499023f, -0.172852f, 0.499023f, -0.211426f, 0.478027f, -0.24707f, 0.457031f, -0.282715f,
-0.409668f, -0.303223f, 0.362305f, -0.32373f, 0.29248f, -0.32373f, 0.262207f, -0.32373f,
-0.240723f, -0.322754f, 0.219238f, -0.321777f, 0.206055f, -0.319336f, 0.602051f, -0.677246f,
-0.617188f, -0.452148f, 0.602051f, -0.452148f, 0.571777f, -0.553223f, 0.515625f, -0.597656f,
-0.459473f, -0.64209f, 0.380859f, -0.64209f, 0.314941f, -0.64209f, 0.261719f, -0.608643f,
-0.208496f, -0.575195f, 0.177979f, -0.501953f, 0.147461f, -0.428711f, 0.147461f, -0.319824f,
-0.147461f, -0.22998f, 0.17627f, -0.164062f, 0.205078f, -0.0981445f, 0.262939f, -0.0629883f,
-0.320801f, -0.027832f, 0.39502f, -0.027832f, 0.459473f, -0.027832f, 0.508789f, -0.0554199f,
-0.558105f, -0.0830078f, 0.617188f, -0.165039f, 0.632324f, -0.155273f, 0.58252f, -0.0668945f,
-0.516113f, -0.0258789f, 0.449707f, 0.0151367f, 0.358398f, 0.0151367f, 0.193848f,
-0.0151367f, 0.103516f, -0.106934f, 0.0361328f, -0.197754f, 0.0361328f, -0.320801f,
-0.0361328f, -0.419922f, 0.0805664f, -0.50293f, 0.125f, -0.585938f, 0.202881f, -0.631592f,
-0.280762f, -0.677246f, 0.373047f, -0.677246f, 0.444824f, -0.677246f, 0.514648f, -0.64209f,
-0.535156f, -0.631348f, 0.543945f, -0.631348f, 0.557129f, -0.631348f, 0.566895f, -0.640625f,
-0.57959f, -0.653809f, 0.584961f, -0.677246f, 0.0170898f, 0, 0.0170898f, -0.0180664f,
-0.0419922f, -0.0180664f, 0.0839844f, -0.0180664f, 0.101562f, -0.0449219f, 0.112305f,
--0.0610352f, 0.112305f, -0.117188f, 0.112305f, -0.544922f, 0.112305f, -0.606934f,
-0.0986328f, -0.622559f, 0.0795898f, -0.644043f, 0.0419922f, -0.644043f, 0.0170898f,
--0.644043f, 0.0170898f, -0.662109f, 0.286621f, -0.662109f, 0.435059f, -0.662109f,
-0.512451f, -0.628418f, 0.589844f, -0.594727f, 0.636963f, -0.516113f, 0.684082f, -0.4375f,
-0.684082f, -0.334473f, 0.684082f, -0.196289f, 0.600098f, -0.103516f, 0.505859f, 0,
-0.312988f, 0, 0.206055f, -0.0478516f, 0.268066f, -0.0341797f, 0.310059f, -0.0341797f,
-0.42334f, -0.0341797f, 0.498047f, -0.11377f, 0.572754f, -0.193359f, 0.572754f, -0.32959f,
-0.572754f, -0.466797f, 0.498047f, -0.545898f, 0.42334f, -0.625f, 0.306152f, -0.625f,
-0.262207f, -0.625f, 0.206055f, -0.61084f, 0.208984f, -0.625977f, 0.208984f, -0.364258f,
-0.354492f, -0.364258f, 0.411133f, -0.364258f, 0.430176f, -0.381348f, 0.455566f, -0.403809f,
-0.458496f, -0.460449f, 0.476562f, -0.460449f, 0.476562f, -0.22998f, 0.458496f, -0.22998f,
-0.45166f, -0.27832f, 0.444824f, -0.291992f, 0.436035f, -0.309082f, 0.416016f, -0.318848f,
-0.395996f, -0.328613f, 0.354492f, -0.328613f, 0.208984f, -0.328613f, 0.208984f, -0.110352f,
-0.208984f, -0.0664062f, 0.212891f, -0.0568848f, 0.216797f, -0.0473633f, 0.226562f,
--0.041748f, 0.236328f, -0.0361328f, 0.263672f, -0.0361328f, 0.375977f, -0.0361328f,
-0.432129f, -0.0361328f, 0.45752f, -0.0439453f, 0.48291f, -0.0517578f, 0.506348f,
--0.074707f, 0.536621f, -0.10498f, 0.568359f, -0.166016f, 0.587891f, -0.166016f, 0.530762f,
-0, 0.0205078f, 0, 0.0205078f, -0.0180664f, 0.0439453f, -0.0180664f, 0.0673828f, -0.0180664f,
-0.0883789f, -0.0292969f, 0.104004f, -0.0371094f, 0.109619f, -0.0527344f, 0.115234f,
--0.0683594f, 0.115234f, -0.116699f, 0.115234f, -0.546875f, 0.115234f, -0.609863f,
-0.102539f, -0.624512f, 0.0849609f, -0.644043f, 0.0439453f, -0.644043f, 0.0205078f,
--0.644043f, 0.0205078f, -0.662109f, 0.530762f, -0.662109f, 0.538086f, -0.51709f,
-0.519043f, -0.51709f, 0.508789f, -0.569336f, 0.496338f, -0.588867f, 0.483887f, -0.608398f,
-0.459473f, -0.618652f, 0.439941f, -0.625977f, 0.390625f, -0.625977f, 0.20459f, -0.625977f,
-0.20459f, -0.365723f, 0.325195f, -0.365723f, 0.366699f, -0.365723f, 0.385986f, -0.384033f,
-0.405273f, -0.402344f, 0.411621f, -0.456543f, 0.429688f, -0.456543f, 0.429688f, -0.232422f,
-0.411621f, -0.232422f, 0.411133f, -0.270996f, 0.401611f, -0.289062f, 0.39209f, -0.307129f,
-0.375244f, -0.316162f, 0.358398f, -0.325195f, 0.325195f, -0.325195f, 0.20459f, -0.325195f,
-0.20459f, -0.117188f, 0.20459f, -0.0668945f, 0.210938f, -0.0507812f, 0.21582f, -0.0385742f,
-0.231445f, -0.0297852f, 0.25293f, -0.0180664f, 0.276367f, -0.0180664f, 0.300293f,
--0.0180664f, 0.300293f, 0, 0.0161133f, 0, 0.0161133f, -0.0180664f, 0.0395508f, -0.0180664f,
-0.0805664f, -0.0180664f, 0.0991211f, -0.0419922f, 0.11084f, -0.0576172f, 0.11084f,
--0.117188f, 0.11084f, -0.544922f, 0.11084f, -0.595215f, 0.104492f, -0.611328f, 0.0996094f,
--0.623535f, 0.0844727f, -0.632324f, 0.0634766f, -0.644043f, 0.0395508f, -0.644043f,
-0.0161133f, -0.644043f, 0.0161133f, -0.662109f, 0.508789f, -0.662109f, 0.515137f,
--0.516602f, 0.498047f, -0.516602f, 0.485352f, -0.562988f, 0.468506f, -0.584717f,
-0.45166f, -0.606445f, 0.427002f, -0.616211f, 0.402344f, -0.625977f, 0.350586f, -0.625977f,
-0.61377f, -0.677246f, 0.630859f, -0.468262f, 0.61377f, -0.468262f, 0.587891f, -0.546387f,
-0.546875f, -0.585938f, 0.487793f, -0.643066f, 0.39502f, -0.643066f, 0.268555f, -0.643066f,
-0.202637f, -0.542969f, 0.147461f, -0.458496f, 0.147461f, -0.341797f, 0.147461f, -0.24707f,
-0.184082f, -0.168945f, 0.220703f, -0.0908203f, 0.280029f, -0.0544434f, 0.339355f,
--0.0180664f, 0.401855f, -0.0180664f, 0.438477f, -0.0180664f, 0.472656f, -0.0273438f,
-0.506836f, -0.0366211f, 0.538574f, -0.0546875f, 0.538574f, -0.246094f, 0.538574f,
--0.295898f, 0.531006f, -0.311279f, 0.523438f, -0.32666f, 0.507568f, -0.334717f, 0.491699f,
--0.342773f, 0.45166f, -0.342773f, 0.45166f, -0.361328f, 0.708008f, -0.361328f, 0.708008f,
--0.342773f, 0.695801f, -0.342773f, 0.657715f, -0.342773f, 0.643555f, -0.317383f,
-0.633789f, -0.299316f, 0.633789f, -0.246094f, 0.633789f, -0.043457f, 0.577637f, -0.0131836f,
-0.522949f, 0.000976562f, 0.468262f, 0.0151367f, 0.401367f, 0.0151367f, 0.209473f,
-0.0151367f, 0.109863f, -0.10791f, 0.0351562f, -0.200195f, 0.0351562f, -0.320801f,
-0.0351562f, -0.408203f, 0.0771484f, -0.488281f, 0.126953f, -0.583496f, 0.213867f,
--0.634766f, 0.286621f, -0.677246f, 0.385742f, -0.677246f, 0.421875f, -0.677246f,
-0.451416f, -0.671387f, 0.480957f, -0.665527f, 0.535156f, -0.645508f, 0.5625f, -0.635254f,
-0.571777f, -0.635254f, 0.581055f, -0.635254f, 0.587646f, -0.643799f, 0.594238f, -0.652344f,
-0.595703f, -0.677246f, 0.205566f, -0.35498f, 0.513184f, -0.35498f, 0.513184f, -0.544434f,
-0.513184f, -0.595215f, 0.506836f, -0.611328f, 0.501953f, -0.623535f, 0.486328f, -0.632324f,
-0.465332f, -0.644043f, 0.441895f, -0.644043f, 0.418457f, -0.644043f, 0.418457f, -0.662109f,
-0.70166f, -0.662109f, 0.70166f, -0.644043f, 0.678223f, -0.644043f, 0.654785f, -0.644043f,
-0.633789f, -0.632812f, 0.618164f, -0.625f, 0.612549f, -0.609131f, 0.606934f, -0.593262f,
-0.606934f, -0.544434f, 0.606934f, -0.117188f, 0.606934f, -0.0668945f, 0.613281f,
--0.0507812f, 0.618164f, -0.0385742f, 0.633301f, -0.0297852f, 0.654785f, -0.0180664f,
-0.678223f, -0.0180664f, 0.70166f, -0.0180664f, 0.70166f, 0, 0.418457f, 0, 0.418457f,
--0.0180664f, 0.441895f, -0.0180664f, 0.482422f, -0.0180664f, 0.500977f, -0.0419922f,
-0.513184f, -0.0576172f, 0.513184f, -0.117188f, 0.513184f, -0.318848f, 0.205566f,
--0.318848f, 0.205566f, -0.117188f, 0.205566f, -0.0668945f, 0.211914f, -0.0507812f,
-0.216797f, -0.0385742f, 0.232422f, -0.0297852f, 0.253418f, -0.0180664f, 0.276855f,
--0.0180664f, 0.300781f, -0.0180664f, 0.300781f, 0, 0.0170898f, 0, 0.0170898f, -0.0180664f,
-0.0405273f, -0.0180664f, 0.081543f, -0.0180664f, 0.100098f, -0.0419922f, 0.111816f,
--0.0576172f, 0.111816f, -0.117188f, 0.111816f, -0.544434f, 0.111816f, -0.595215f,
-0.105469f, -0.611328f, 0.100586f, -0.623535f, 0.0854492f, -0.632324f, 0.0639648f,
--0.644043f, 0.0405273f, -0.644043f, 0.0170898f, -0.644043f, 0.0170898f, -0.662109f,
-0.300781f, -0.662109f, 0.300781f, -0.644043f, 0.276855f, -0.644043f, 0.253418f, -0.644043f,
-0.232422f, -0.632812f, 0.217285f, -0.625f, 0.211426f, -0.609131f, 0.205566f, -0.593262f,
-0.205566f, -0.544434f, 0.308594f, -0.0180664f, 0.308594f, 0, 0.0249023f, 0, 0.0249023f,
--0.0180664f, 0.0483398f, -0.0180664f, 0.0893555f, -0.0180664f, 0.10791f, -0.0419922f,
-0.119629f, -0.0576172f, 0.119629f, -0.117188f, 0.119629f, -0.544922f, 0.119629f,
--0.595215f, 0.113281f, -0.611328f, 0.108398f, -0.623535f, 0.0932617f, -0.632324f,
-0.0717773f, -0.644043f, 0.0483398f, -0.644043f, 0.0249023f, -0.644043f, 0.0249023f,
--0.662109f, 0.308594f, -0.662109f, 0.308594f, -0.644043f, 0.284668f, -0.644043f,
-0.244141f, -0.644043f, 0.225586f, -0.620117f, 0.213379f, -0.604492f, 0.213379f, -0.544922f,
-0.213379f, -0.117188f, 0.213379f, -0.0668945f, 0.219727f, -0.0507812f, 0.224609f,
--0.0385742f, 0.240234f, -0.0297852f, 0.26123f, -0.0180664f, 0.284668f, -0.0180664f,
-0.0996094f, -0.644043f, 0.0996094f, -0.662109f, 0.383301f, -0.662109f, 0.383301f,
--0.644043f, 0.359375f, -0.644043f, 0.318848f, -0.644043f, 0.300293f, -0.620117f,
-0.288574f, -0.604492f, 0.288574f, -0.544922f, 0.288574f, -0.221191f, 0.288574f, -0.146484f,
-0.272217f, -0.100098f, 0.255859f, -0.0537109f, 0.21582f, -0.0192871f, 0.175781f,
-0.0151367f, 0.119141f, 0.0151367f, 0.0732422f, 0.0151367f, 0.046875f, -0.00756836f,
-0.0205078f, -0.0302734f, 0.0205078f, -0.0595703f, 0.0205078f, -0.0834961f, 0.0327148f,
--0.0957031f, 0.0488281f, -0.11084f, 0.0703125f, -0.11084f, 0.0859375f, -0.11084f,
-0.0983887f, -0.100586f, 0.11084f, -0.090332f, 0.129883f, -0.0458984f, 0.141113f,
--0.0195312f, 0.158691f, -0.0195312f, 0.171875f, -0.0195312f, 0.18335f, -0.0356445f,
-0.194824f, -0.0517578f, 0.194824f, -0.0927734f, 0.194824f, -0.544922f, 0.194824f,
--0.595215f, 0.188477f, -0.611328f, 0.183594f, -0.623535f, 0.167969f, -0.632324f,
-0.146973f, -0.644043f, 0.123535f, -0.644043f, 0.298828f, -0.367188f, 0.542969f, -0.124512f,
-0.603027f, -0.0644531f, 0.645508f, -0.0427246f, 0.687988f, -0.0209961f, 0.730469f,
--0.0180664f, 0.730469f, 0, 0.415527f, 0, 0.415527f, -0.0180664f, 0.443848f, -0.0180664f,
-0.456299f, -0.0275879f, 0.46875f, -0.0371094f, 0.46875f, -0.0488281f, 0.46875f, -0.0605469f,
-0.464111f, -0.0698242f, 0.459473f, -0.0791016f, 0.433594f, -0.104492f, 0.205078f,
--0.330566f, 0.205078f, -0.117188f, 0.205078f, -0.0668945f, 0.211426f, -0.0507812f,
-0.216309f, -0.0385742f, 0.231934f, -0.0297852f, 0.25293f, -0.0180664f, 0.276367f,
--0.0180664f, 0.298828f, -0.0180664f, 0.298828f, 0, 0.0166016f, 0, 0.0166016f, -0.0180664f,
-0.0400391f, -0.0180664f, 0.0810547f, -0.0180664f, 0.0996094f, -0.0419922f, 0.111328f,
--0.0576172f, 0.111328f, -0.117188f, 0.111328f, -0.544922f, 0.111328f, -0.595215f,
-0.10498f, -0.611816f, 0.100098f, -0.623535f, 0.0849609f, -0.632324f, 0.0634766f,
--0.644043f, 0.0400391f, -0.644043f, 0.0166016f, -0.644043f, 0.0166016f, -0.662109f,
-0.298828f, -0.662109f, 0.298828f, -0.644043f, 0.276367f, -0.644043f, 0.253418f, -0.644043f,
-0.231934f, -0.632812f, 0.216797f, -0.625f, 0.210938f, -0.609375f, 0.205078f, -0.59375f,
-0.205078f, -0.544922f, 0.205078f, -0.342285f, 0.214844f, -0.351562f, 0.271973f, -0.404297f,
-0.416992f, -0.537109f, 0.447266f, -0.581543f, 0.460449f, -0.601074f, 0.460449f, -0.615723f,
-0.460449f, -0.626953f, 0.450195f, -0.635498f, 0.439941f, -0.644043f, 0.415527f, -0.644043f,
-0.400391f, -0.644043f, 0.400391f, -0.662109f, 0.643555f, -0.662109f, 0.643555f, -0.644043f,
-0.62207f, -0.643555f, 0.604492f, -0.638184f, 0.586914f, -0.632812f, 0.561523f, -0.617432f,
-0.536133f, -0.602051f, 0.499023f, -0.567871f, 0.488281f, -0.558105f, 0.399902f, -0.467773f,
-0.573242f, -0.183105f, 0.589355f, -0.179688f, 0.532715f, 0, 0.0200195f, 0, 0.0200195f,
--0.0180664f, 0.0449219f, -0.0180664f, 0.0869141f, -0.0180664f, 0.10498f, -0.0454102f,
-0.115234f, -0.0610352f, 0.115234f, -0.117676f, 0.115234f, -0.544922f, 0.115234f,
--0.606934f, 0.101562f, -0.622559f, 0.0825195f, -0.644043f, 0.0449219f, -0.644043f,
-0.0200195f, -0.644043f, 0.0200195f, -0.662109f, 0.319824f, -0.662109f, 0.319824f,
--0.644043f, 0.26709f, -0.644531f, 0.24585f, -0.634277f, 0.224609f, -0.624023f, 0.216797f,
--0.608398f, 0.208984f, -0.592773f, 0.208984f, -0.533691f, 0.208984f, -0.117676f,
-0.208984f, -0.0771484f, 0.216797f, -0.0620117f, 0.222656f, -0.0517578f, 0.234863f,
--0.046875f, 0.24707f, -0.0419922f, 0.311035f, -0.0419922f, 0.359375f, -0.0419922f,
-0.435547f, -0.0419922f, 0.466309f, -0.0532227f, 0.49707f, -0.0644531f, 0.522461f,
--0.0930176f, 0.547852f, -0.121582f, 0.573242f, -0.183105f, 0.40918f, 0, 0.15332f,
--0.557129f, 0.15332f, -0.114746f, 0.15332f, -0.0537109f, 0.166504f, -0.0385742f,
-0.18457f, -0.0180664f, 0.223633f, -0.0180664f, 0.24707f, -0.0180664f, 0.24707f, 0,
-0.0166016f, 0, 0.0166016f, -0.0180664f, 0.0400391f, -0.0180664f, 0.0820312f, -0.0180664f,
-0.0996094f, -0.043457f, 0.110352f, -0.059082f, 0.110352f, -0.114746f, 0.110352f,
--0.547363f, 0.110352f, -0.591309f, 0.100586f, -0.61084f, 0.09375f, -0.625f, 0.0754395f,
--0.634521f, 0.0571289f, -0.644043f, 0.0166016f, -0.644043f, 0.0166016f, -0.662109f,
-0.204102f, -0.662109f, 0.444336f, -0.144043f, 0.680664f, -0.662109f, 0.868164f, -0.662109f,
-0.868164f, -0.644043f, 0.845215f, -0.644043f, 0.802734f, -0.644043f, 0.785156f, -0.618652f,
-0.774414f, -0.603027f, 0.774414f, -0.547363f, 0.774414f, -0.114746f, 0.774414f, -0.0537109f,
-0.788086f, -0.0385742f, 0.806152f, -0.0180664f, 0.845215f, -0.0180664f, 0.868164f,
--0.0180664f, 0.868164f, 0, 0.586914f, 0, 0.586914f, -0.0180664f, 0.610352f, -0.0180664f,
-0.652832f, -0.0180664f, 0.669922f, -0.043457f, 0.680664f, -0.059082f, 0.680664f,
--0.114746f, 0.680664f, -0.557129f, 0.425293f, 0, -0.0131836f, -0.662109f, 0.166504f,
--0.662109f, 0.571289f, -0.165527f, 0.571289f, -0.547363f, 0.571289f, -0.608398f,
-0.557617f, -0.623535f, 0.539551f, -0.644043f, 0.500488f, -0.644043f, 0.477539f, -0.644043f,
-0.477539f, -0.662109f, 0.708008f, -0.662109f, 0.708008f, -0.644043f, 0.68457f, -0.644043f,
-0.642578f, -0.644043f, 0.625f, -0.618652f, 0.614258f, -0.603027f, 0.614258f, -0.547363f,
-0.614258f, 0.0107422f, 0.59668f, 0.0107422f, 0.160156f, -0.522461f, 0.160156f, -0.114746f,
-0.160156f, -0.0537109f, 0.17334f, -0.0385742f, 0.191895f, -0.0180664f, 0.230469f,
--0.0180664f, 0.253906f, -0.0180664f, 0.253906f, 0, 0.0234375f, 0, 0.0234375f, -0.0180664f,
-0.0463867f, -0.0180664f, 0.0888672f, -0.0180664f, 0.106445f, -0.043457f, 0.117188f,
--0.059082f, 0.117188f, -0.114746f, 0.117188f, -0.575195f, 0.0883789f, -0.608887f,
-0.0734863f, -0.619629f, 0.0585938f, -0.630371f, 0.0297852f, -0.639648f, 0.015625f,
--0.644043f, -0.0131836f, -0.644043f, 0.205078f, -0.310059f, 0.205078f, -0.117188f,
-0.205078f, -0.0546875f, 0.21875f, -0.0395508f, 0.237305f, -0.0180664f, 0.274902f,
--0.0180664f, 0.300293f, -0.0180664f, 0.300293f, 0, 0.0166016f, 0, 0.0166016f, -0.0180664f,
-0.0415039f, -0.0180664f, 0.0834961f, -0.0180664f, 0.101562f, -0.0454102f, 0.111328f,
--0.0605469f, 0.111328f, -0.117188f, 0.111328f, -0.544922f, 0.111328f, -0.607422f,
-0.0981445f, -0.622559f, 0.0791016f, -0.644043f, 0.0415039f, -0.644043f, 0.0166016f,
--0.644043f, 0.0166016f, -0.662109f, 0.259277f, -0.662109f, 0.348145f, -0.662109f,
-0.399414f, -0.643799f, 0.450684f, -0.625488f, 0.48584f, -0.582031f, 0.520996f, -0.538574f,
-0.520996f, -0.479004f, 0.520996f, -0.397949f, 0.467529f, -0.347168f, 0.414062f, -0.296387f,
-0.316406f, -0.296387f, 0.29248f, -0.296387f, 0.264648f, -0.299805f, 0.236816f, -0.303223f,
-0.205078f, -0.310059f, 0.205078f, -0.337891f, 0.230957f, -0.333008f, 0.250977f, -0.330566f,
-0.270996f, -0.328125f, 0.285156f, -0.328125f, 0.335938f, -0.328125f, 0.372803f, -0.367432f,
-0.409668f, -0.406738f, 0.409668f, -0.469238f, 0.409668f, -0.512207f, 0.39209f, -0.549072f,
-0.374512f, -0.585938f, 0.342285f, -0.604248f, 0.310059f, -0.622559f, 0.269043f, -0.622559f,
-0.244141f, -0.622559f, 0.205078f, -0.613281f, 0.44043f, 0.00732422f, 0.490234f, 0.0932617f,
-0.548096f, 0.133789f, 0.605957f, 0.174316f, 0.679688f, 0.180176f, 0.679688f, 0.195801f,
-0.612305f, 0.193359f, 0.535645f, 0.168701f, 0.458984f, 0.144043f, 0.390381f, 0.100342f,
-0.321777f, 0.0566406f, 0.271973f, 0.00732422f, 0.20166f, -0.0209961f, 0.160645f,
--0.0527344f, 0.101074f, -0.100098f, 0.0681152f, -0.169189f, 0.0351562f, -0.238281f,
-0.0351562f, -0.33252f, 0.0351562f, -0.480957f, 0.131348f, -0.579102f, 0.227539f,
--0.677246f, 0.364258f, -0.677246f, 0.494141f, -0.677246f, 0.589111f, -0.578857f,
-0.684082f, -0.480469f, 0.684082f, -0.330566f, 0.684082f, -0.208984f, 0.616455f, -0.117188f,
-0.548828f, -0.0253906f, 0.44043f, 0.00732422f, 0.358398f, -0.639648f, 0.269531f,
--0.639648f, 0.215332f, -0.576172f, 0.146973f, -0.496582f, 0.146973f, -0.33252f, 0.146973f,
--0.171875f, 0.216309f, -0.0849609f, 0.27002f, -0.0180664f, 0.358398f, -0.0180664f,
-0.450195f, -0.0180664f, 0.506348f, -0.0849609f, 0.572266f, -0.164062f, 0.572266f,
--0.318359f, 0.572266f, -0.437012f, 0.536133f, -0.518066f, 0.508301f, -0.580566f,
-0.462158f, -0.610107f, 0.416016f, -0.639648f, 0.358398f, -0.639648f, 0.675781f, 0,
-0.499023f, 0, 0.274902f, -0.30957f, 0.25f, -0.308594f, 0.234375f, -0.308594f, 0.228027f,
--0.308594f, 0.220703f, -0.308838f, 0.213379f, -0.309082f, 0.205566f, -0.30957f, 0.205566f,
--0.117188f, 0.205566f, -0.0546875f, 0.219238f, -0.0395508f, 0.237793f, -0.0180664f,
-0.274902f, -0.0180664f, 0.300781f, -0.0180664f, 0.300781f, 0, 0.0170898f, 0, 0.0170898f,
--0.0180664f, 0.0419922f, -0.0180664f, 0.0839844f, -0.0180664f, 0.102051f, -0.0454102f,
-0.112305f, -0.0605469f, 0.112305f, -0.117188f, 0.112305f, -0.544922f, 0.112305f,
--0.607422f, 0.0986328f, -0.622559f, 0.0795898f, -0.644043f, 0.0419922f, -0.644043f,
-0.0170898f, -0.644043f, 0.0170898f, -0.662109f, 0.258301f, -0.662109f, 0.36377f,
--0.662109f, 0.413818f, -0.646729f, 0.463867f, -0.631348f, 0.498779f, -0.590088f,
-0.533691f, -0.548828f, 0.533691f, -0.491699f, 0.533691f, -0.430664f, 0.493896f, -0.385742f,
-0.454102f, -0.34082f, 0.370605f, -0.322266f, 0.507324f, -0.132324f, 0.554199f, -0.0668945f,
-0.587891f, -0.0454102f, 0.621582f, -0.0239258f, 0.675781f, -0.0180664f, 0.205566f,
--0.340332f, 0.214844f, -0.340332f, 0.22168f, -0.340088f, 0.228516f, -0.339844f, 0.23291f,
--0.339844f, 0.327637f, -0.339844f, 0.375732f, -0.380859f, 0.423828f, -0.421875f,
-0.423828f, -0.485352f, 0.423828f, -0.547363f, 0.38501f, -0.586182f, 0.346191f, -0.625f,
-0.282227f, -0.625f, 0.253906f, -0.625f, 0.205566f, -0.615723f, 0.458496f, -0.677246f,
-0.458496f, -0.448242f, 0.44043f, -0.448242f, 0.431641f, -0.51416f, 0.408936f, -0.553223f,
-0.38623f, -0.592285f, 0.344238f, -0.615234f, 0.302246f, -0.638184f, 0.257324f, -0.638184f,
-0.206543f, -0.638184f, 0.17334f, -0.607178f, 0.140137f, -0.576172f, 0.140137f, -0.536621f,
-0.140137f, -0.506348f, 0.161133f, -0.481445f, 0.191406f, -0.444824f, 0.305176f, -0.383789f,
-0.397949f, -0.333984f, 0.431885f, -0.307373f, 0.46582f, -0.280762f, 0.484131f, -0.244629f,
-0.502441f, -0.208496f, 0.502441f, -0.168945f, 0.502441f, -0.09375f, 0.444092f, -0.0393066f,
-0.385742f, 0.0151367f, 0.293945f, 0.0151367f, 0.265137f, 0.0151367f, 0.239746f, 0.0107422f,
-0.224609f, 0.00830078f, 0.177002f, -0.00708008f, 0.129395f, -0.0224609f, 0.116699f,
--0.0224609f, 0.104492f, -0.0224609f, 0.0974121f, -0.0151367f, 0.090332f, -0.0078125f,
-0.0869141f, 0.0151367f, 0.0688477f, 0.0151367f, 0.0688477f, -0.211914f, 0.0869141f,
--0.211914f, 0.0996094f, -0.140625f, 0.121094f, -0.105225f, 0.142578f, -0.0698242f,
-0.186768f, -0.0463867f, 0.230957f, -0.0229492f, 0.283691f, -0.0229492f, 0.344727f,
--0.0229492f, 0.380127f, -0.0551758f, 0.415527f, -0.0874023f, 0.415527f, -0.131348f,
-0.415527f, -0.155762f, 0.4021f, -0.180664f, 0.388672f, -0.205566f, 0.360352f, -0.227051f,
-0.341309f, -0.241699f, 0.256348f, -0.289307f, 0.171387f, -0.336914f, 0.135498f, -0.365234f,
-0.0996094f, -0.393555f, 0.0810547f, -0.427734f, 0.0625f, -0.461914f, 0.0625f, -0.50293f,
-0.0625f, -0.574219f, 0.117188f, -0.625732f, 0.171875f, -0.677246f, 0.256348f, -0.677246f,
-0.309082f, -0.677246f, 0.368164f, -0.651367f, 0.395508f, -0.63916f, 0.406738f, -0.63916f,
-0.419434f, -0.63916f, 0.42749f, -0.646729f, 0.435547f, -0.654297f, 0.44043f, -0.677246f,
-0.578613f, -0.662109f, 0.585938f, -0.506836f, 0.567383f, -0.506836f, 0.562012f, -0.547852f,
-0.552734f, -0.56543f, 0.537598f, -0.59375f, 0.512451f, -0.607178f, 0.487305f, -0.620605f,
-0.446289f, -0.620605f, 0.353027f, -0.620605f, 0.353027f, -0.114746f, 0.353027f, -0.0537109f,
-0.366211f, -0.0385742f, 0.384766f, -0.0180664f, 0.42334f, -0.0180664f, 0.446289f,
--0.0180664f, 0.446289f, 0, 0.165527f, 0, 0.165527f, -0.0180664f, 0.188965f, -0.0180664f,
-0.230957f, -0.0180664f, 0.248535f, -0.043457f, 0.259277f, -0.059082f, 0.259277f,
--0.114746f, 0.259277f, -0.620605f, 0.179688f, -0.620605f, 0.133301f, -0.620605f,
-0.11377f, -0.61377f, 0.0883789f, -0.604492f, 0.0703125f, -0.578125f, 0.0522461f,
--0.551758f, 0.0488281f, -0.506836f, 0.0302734f, -0.506836f, 0.0380859f, -0.662109f,
-0.709961f, -0.662109f, 0.709961f, -0.644043f, 0.674805f, -0.637695f, 0.656738f, -0.621582f,
-0.630859f, -0.597656f, 0.61084f, -0.54834f, 0.379883f, 0.0151367f, 0.361816f, 0.0151367f,
-0.11377f, -0.555664f, 0.0947266f, -0.599609f, 0.0869141f, -0.609375f, 0.074707f,
--0.624512f, 0.0568848f, -0.633057f, 0.0390625f, -0.641602f, 0.00878906f, -0.644043f,
-0.00878906f, -0.662109f, 0.279297f, -0.662109f, 0.279297f, -0.644043f, 0.233398f,
--0.639648f, 0.219727f, -0.628418f, 0.206055f, -0.617188f, 0.206055f, -0.599609f,
-0.206055f, -0.575195f, 0.228516f, -0.523438f, 0.396973f, -0.135254f, 0.553223f, -0.518555f,
-0.576172f, -0.575195f, 0.576172f, -0.597168f, 0.576172f, -0.611328f, 0.562012f, -0.624268f,
-0.547852f, -0.637207f, 0.51416f, -0.642578f, 0.511719f, -0.643066f, 0.505859f, -0.644043f,
-0.505859f, -0.662109f, 0.936035f, -0.662109f, 0.936035f, -0.644043f, 0.910156f, -0.644043f,
-0.894043f, -0.634766f, 0.87793f, -0.625488f, 0.863281f, -0.600098f, 0.853516f, -0.583008f,
-0.83252f, -0.518555f, 0.647949f, 0.0151367f, 0.628418f, 0.0151367f, 0.477539f, -0.408203f,
-0.327637f, 0.0151367f, 0.310059f, 0.0151367f, 0.113281f, -0.534668f, 0.0913086f,
--0.596191f, 0.0854492f, -0.607422f, 0.0756836f, -0.625977f, 0.0588379f, -0.63501f,
-0.0419922f, -0.644043f, 0.0131836f, -0.644043f, 0.0131836f, -0.662109f, 0.258301f,
--0.662109f, 0.258301f, -0.644043f, 0.246582f, -0.644043f, 0.220703f, -0.644043f,
-0.207031f, -0.632324f, 0.193359f, -0.620605f, 0.193359f, -0.604004f, 0.193359f, -0.586914f,
-0.214844f, -0.525391f, 0.345215f, -0.153809f, 0.455078f, -0.469727f, 0.435547f, -0.525391f,
-0.419922f, -0.569824f, 0.409668f, -0.594238f, 0.396973f, -0.612793f, 0.390625f, -0.62207f,
-0.381348f, -0.628418f, 0.369141f, -0.637207f, 0.356934f, -0.641113f, 0.347656f, -0.644043f,
-0.327637f, -0.644043f, 0.327637f, -0.662109f, 0.585449f, -0.662109f, 0.585449f, -0.644043f,
-0.567871f, -0.644043f, 0.540527f, -0.644043f, 0.527832f, -0.632324f, 0.515137f, -0.620605f,
-0.515137f, -0.600586f, 0.515137f, -0.575684f, 0.537109f, -0.513672f, 0.664062f, -0.153809f,
-0.790039f, -0.518555f, 0.811523f, -0.579102f, 0.811523f, -0.602539f, 0.811523f, -0.61377f,
-0.804443f, -0.623535f, 0.797363f, -0.633301f, 0.786621f, -0.637207f, 0.768066f, -0.644043f,
-0.738281f, -0.644043f, 0.738281f, -0.662109f, 0.408203f, -0.366699f, 0.550293f, -0.154785f,
-0.609375f, -0.0668945f, 0.637939f, -0.0437012f, 0.666504f, -0.0205078f, 0.710449f,
--0.0180664f, 0.710449f, 0, 0.42627f, 0, 0.42627f, -0.0180664f, 0.45459f, -0.0185547f,
-0.468262f, -0.0239258f, 0.478516f, -0.0283203f, 0.485107f, -0.0373535f, 0.491699f,
--0.0463867f, 0.491699f, -0.0556641f, 0.491699f, -0.0668945f, 0.487305f, -0.078125f,
-0.483887f, -0.0864258f, 0.460449f, -0.121094f, 0.348145f, -0.291016f, 0.209473f,
--0.113281f, 0.1875f, -0.0849609f, 0.183105f, -0.0754395f, 0.178711f, -0.065918f,
-0.178711f, -0.0556641f, 0.178711f, -0.0400391f, 0.191895f, -0.0297852f, 0.205078f,
--0.0195312f, 0.242188f, -0.0180664f, 0.242188f, 0, 0.00732422f, 0, 0.00732422f, -0.0180664f,
-0.0322266f, -0.0205078f, 0.050293f, -0.0283203f, 0.0805664f, -0.0410156f, 0.10791f,
--0.0625f, 0.135254f, -0.0839844f, 0.17041f, -0.128418f, 0.32666f, -0.325684f, 0.196289f,
--0.516602f, 0.143066f, -0.594238f, 0.105957f, -0.618408f, 0.0688477f, -0.642578f,
-0.0205078f, -0.644043f, 0.0205078f, -0.662109f, 0.32666f, -0.662109f, 0.32666f, -0.644043f,
-0.287598f, -0.642578f, 0.273193f, -0.631348f, 0.258789f, -0.620117f, 0.258789f, -0.606445f,
-0.258789f, -0.588379f, 0.282227f, -0.553711f, 0.383789f, -0.401855f, 0.501465f, -0.550781f,
-0.521973f, -0.577148f, 0.526611f, -0.586914f, 0.53125f, -0.59668f, 0.53125f, -0.606934f,
-0.53125f, -0.617188f, 0.525391f, -0.625f, 0.518066f, -0.635254f, 0.506836f, -0.639404f,
-0.495605f, -0.643555f, 0.460449f, -0.644043f, 0.460449f, -0.662109f, 0.695312f, -0.662109f,
-0.695312f, -0.644043f, 0.66748f, -0.642578f, 0.649902f, -0.635254f, 0.623535f, -0.624023f,
-0.601562f, -0.60498f, 0.57959f, -0.585938f, 0.539551f, -0.534668f, 0.476562f, -0.662109f,
-0.70752f, -0.662109f, 0.70752f, -0.644043f, 0.694824f, -0.644043f, 0.682129f, -0.644043f,
-0.657715f, -0.632812f, 0.633301f, -0.621582f, 0.613281f, -0.600586f, 0.593262f, -0.57959f,
-0.563965f, -0.532227f, 0.404297f, -0.280762f, 0.404297f, -0.114746f, 0.404297f, -0.0537109f,
-0.417969f, -0.0385742f, 0.436523f, -0.0180664f, 0.476562f, -0.0180664f, 0.498047f,
--0.0180664f, 0.498047f, 0, 0.216797f, 0, 0.216797f, -0.0180664f, 0.240234f, -0.0180664f,
-0.282227f, -0.0180664f, 0.299805f, -0.043457f, 0.310547f, -0.059082f, 0.310547f,
--0.114746f, 0.310547f, -0.271484f, 0.128906f, -0.548828f, 0.0966797f, -0.597656f,
-0.0852051f, -0.609863f, 0.0737305f, -0.62207f, 0.0375977f, -0.63916f, 0.027832f,
--0.644043f, 0.00927734f, -0.644043f, 0.00927734f, -0.662109f, 0.29248f, -0.662109f,
-0.29248f, -0.644043f, 0.277832f, -0.644043f, 0.254883f, -0.644043f, 0.235596f, -0.633301f,
-0.216309f, -0.622559f, 0.216309f, -0.601074f, 0.216309f, -0.583496f, 0.246094f, -0.537598f,
-0.384277f, -0.324219f, 0.51416f, -0.52832f, 0.543457f, -0.574219f, 0.543457f, -0.59668f,
-0.543457f, -0.610352f, 0.536377f, -0.621094f, 0.529297f, -0.631836f, 0.516113f, -0.637939f,
-0.50293f, -0.644043f, 0.476562f, -0.644043f, 0.575195f, -0.662109f, 0.140137f, -0.0400391f,
-0.411621f, -0.0400391f, 0.474121f, -0.0400391f, 0.507568f, -0.0673828f, 0.541016f,
--0.0947266f, 0.566895f, -0.178223f, 0.583008f, -0.175293f, 0.551758f, 0, 0.0126953f,
-0, 0.0126953f, -0.0180664f, 0.4375f, -0.622559f, 0.225586f, -0.622559f, 0.172852f,
--0.622559f, 0.14917f, -0.611084f, 0.125488f, -0.599609f, 0.113037f, -0.577881f, 0.100586f,
--0.556152f, 0.090332f, -0.496582f, 0.0717773f, -0.496582f, 0.0854492f, -0.662109f,
-0.296875f, 0.198242f, 0.0820312f, 0.198242f, 0.0820312f, -0.677246f, 0.296875f, -0.677246f,
-0.296875f, -0.638672f, 0.155273f, -0.638672f, 0.155273f, 0.160156f, 0.296875f, 0.160156f,
-0.0405273f, -0.694336f, 0.279785f, 0.0136719f, 0.240723f, 0.0136719f, 0.00146484f,
--0.694336f, 0.0366211f, -0.677246f, 0.251465f, -0.677246f, 0.251465f, 0.19873f, 0.0366211f,
-0.19873f, 0.0366211f, 0.160156f, 0.178223f, 0.160156f, 0.178223f, -0.638672f, 0.0366211f,
--0.638672f, 0.243164f, -0.675781f, 0.450684f, -0.325684f, 0.405762f, -0.325684f,
-0.234863f, -0.611816f, 0.0639648f, -0.325684f, 0.0180664f, -0.325684f, 0.228516f,
--0.675781f, 0.508789f, 0.21582f, -0.00830078f, 0.21582f, -0.00830078f, 0.174805f,
-0.508789f, 0.174805f, 0.0576172f, -0.678711f, 0.166504f, -0.678711f, 0.218262f, -0.510254f,
-0.201172f, -0.510254f, 0.284668f, -0.0644531f, 0.21582f, -0.0112305f, 0.198242f,
--0.00292969f, 0.171875f, 0.00927734f, 0.14209f, 0.00927734f, 0.0957031f, 0.00927734f,
-0.0656738f, -0.0224609f, 0.0356445f, -0.0541992f, 0.0356445f, -0.105957f, 0.0356445f,
--0.138672f, 0.050293f, -0.162598f, 0.0703125f, -0.195801f, 0.119873f, -0.225098f,
-0.169434f, -0.254395f, 0.284668f, -0.296387f, 0.284668f, -0.313965f, 0.284668f, -0.380859f,
-0.263428f, -0.405762f, 0.242188f, -0.430664f, 0.20166f, -0.430664f, 0.170898f, -0.430664f,
-0.152832f, -0.414062f, 0.134277f, -0.397461f, 0.134277f, -0.375977f, 0.135254f, -0.347656f,
-0.135254f, -0.325195f, 0.123779f, -0.312988f, 0.112305f, -0.300781f, 0.09375f, -0.300781f,
-0.0756836f, -0.300781f, 0.064209f, -0.313477f, 0.0527344f, -0.326172f, 0.0527344f,
--0.348145f, 0.0527344f, -0.390137f, 0.0957031f, -0.425293f, 0.138672f, -0.460449f,
-0.216309f, -0.460449f, 0.275879f, -0.460449f, 0.313965f, -0.44043f, 0.342773f, -0.425293f,
-0.356445f, -0.393066f, 0.365234f, -0.37207f, 0.365234f, -0.307129f, 0.365234f, -0.155273f,
-0.365234f, -0.0913086f, 0.367676f, -0.0769043f, 0.370117f, -0.0625f, 0.375732f, -0.0576172f,
-0.381348f, -0.0527344f, 0.388672f, -0.0527344f, 0.396484f, -0.0527344f, 0.402344f,
--0.0561523f, 0.412598f, -0.0625f, 0.441895f, -0.0917969f, 0.441895f, -0.0644531f,
-0.387207f, 0.00878906f, 0.337402f, 0.00878906f, 0.313477f, 0.00878906f, 0.299316f,
--0.0078125f, 0.285156f, -0.0244141f, 0.284668f, -0.0644531f, 0.284668f, -0.0961914f,
-0.284668f, -0.266602f, 0.210938f, -0.237305f, 0.189453f, -0.225098f, 0.150879f, -0.203613f,
-0.134277f, -0.180176f, 0.117676f, -0.156738f, 0.117676f, -0.128906f, 0.117676f, -0.09375f,
-0.138672f, -0.0705566f, 0.159668f, -0.0473633f, 0.187012f, -0.0473633f, 0.224121f,
--0.0473633f, 0.284668f, -0.0961914f, 0.153809f, -0.370117f, 0.21875f, -0.460449f,
-0.293945f, -0.460449f, 0.362793f, -0.460449f, 0.414062f, -0.401611f, 0.465332f, -0.342773f,
-0.465332f, -0.240723f, 0.465332f, -0.121582f, 0.38623f, -0.0488281f, 0.318359f, 0.0136719f,
-0.234863f, 0.0136719f, 0.195801f, 0.0136719f, 0.155518f, -0.000488281f, 0.115234f,
--0.0146484f, 0.0732422f, -0.0429688f, 0.0732422f, -0.506348f, 0.0732422f, -0.58252f,
-0.0695801f, -0.600098f, 0.065918f, -0.617676f, 0.0581055f, -0.624023f, 0.050293f,
--0.630371f, 0.0385742f, -0.630371f, 0.0249023f, -0.630371f, 0.00439453f, -0.622559f,
--0.00244141f, -0.639648f, 0.131836f, -0.694336f, 0.153809f, -0.694336f, 0.153809f,
--0.338867f, 0.153809f, -0.0712891f, 0.178711f, -0.046875f, 0.205322f, -0.0344238f,
-0.231934f, -0.0219727f, 0.259766f, -0.0219727f, 0.304199f, -0.0219727f, 0.342529f,
--0.0708008f, 0.380859f, -0.119629f, 0.380859f, -0.212891f, 0.380859f, -0.298828f,
-0.342529f, -0.344971f, 0.304199f, -0.391113f, 0.255371f, -0.391113f, 0.229492f, -0.391113f,
-0.203613f, -0.37793f, 0.184082f, -0.368164f, 0.153809f, -0.338867f, 0.411133f, -0.169922f,
-0.393066f, -0.081543f, 0.340332f, -0.0339355f, 0.287598f, 0.0136719f, 0.223633f,
-0.0136719f, 0.147461f, 0.0136719f, 0.0908203f, -0.050293f, 0.0341797f, -0.114258f,
-0.0341797f, -0.223145f, 0.0341797f, -0.328613f, 0.0969238f, -0.394531f, 0.159668f,
--0.460449f, 0.247559f, -0.460449f, 0.313477f, -0.460449f, 0.355957f, -0.425537f,
-0.398438f, -0.390625f, 0.398438f, -0.353027f, 0.398438f, -0.334473f, 0.386475f, -0.322998f,
-0.374512f, -0.311523f, 0.353027f, -0.311523f, 0.324219f, -0.311523f, 0.30957f, -0.330078f,
-0.30127f, -0.340332f, 0.298584f, -0.369141f, 0.295898f, -0.397949f, 0.278809f, -0.413086f,
-0.261719f, -0.427734f, 0.231445f, -0.427734f, 0.182617f, -0.427734f, 0.152832f, -0.391602f,
-0.113281f, -0.34375f, 0.113281f, -0.265137f, 0.113281f, -0.185059f, 0.152588f, -0.123779f,
-0.191895f, -0.0625f, 0.258789f, -0.0625f, 0.306641f, -0.0625f, 0.344727f, -0.0952148f,
-0.371582f, -0.117676f, 0.396973f, -0.176758f, 0.347168f, -0.050293f, 0.314453f, -0.0161133f,
-0.283203f, -0.0012207f, 0.251953f, 0.0136719f, 0.21582f, 0.0136719f, 0.142578f, 0.0136719f,
-0.0878906f, -0.0476074f, 0.0332031f, -0.108887f, 0.0332031f, -0.205078f, 0.0332031f,
--0.30127f, 0.09375f, -0.381104f, 0.154297f, -0.460938f, 0.249512f, -0.460938f, 0.308594f,
--0.460938f, 0.347168f, -0.42334f, 0.347168f, -0.505859f, 0.347168f, -0.58252f, 0.343506f,
--0.600098f, 0.339844f, -0.617676f, 0.332031f, -0.624023f, 0.324219f, -0.630371f,
-0.3125f, -0.630371f, 0.299805f, -0.630371f, 0.278809f, -0.622559f, 0.272461f, -0.639648f,
-0.405762f, -0.694336f, 0.427734f, -0.694336f, 0.427734f, -0.177246f, 0.427734f, -0.0986328f,
-0.431396f, -0.0812988f, 0.435059f, -0.0639648f, 0.443115f, -0.0571289f, 0.451172f,
--0.050293f, 0.461914f, -0.050293f, 0.475098f, -0.050293f, 0.49707f, -0.0585938f,
-0.502441f, -0.0415039f, 0.369629f, 0.0136719f, 0.347168f, 0.0136719f, 0.347168f,
--0.0844727f, 0.347168f, -0.314941f, 0.344238f, -0.348145f, 0.32959f, -0.375488f,
-0.314941f, -0.402832f, 0.290771f, -0.416748f, 0.266602f, -0.430664f, 0.243652f, -0.430664f,
-0.200684f, -0.430664f, 0.166992f, -0.39209f, 0.122559f, -0.341309f, 0.122559f, -0.243652f,
-0.122559f, -0.14502f, 0.165527f, -0.0925293f, 0.208496f, -0.0400391f, 0.26123f, -0.0400391f,
-0.305664f, -0.0400391f, 0.347168f, -0.0844727f, 0.106445f, -0.278809f, 0.105957f,
--0.179199f, 0.154785f, -0.122559f, 0.203613f, -0.065918f, 0.269531f, -0.065918f,
-0.313477f, -0.065918f, 0.345947f, -0.0900879f, 0.378418f, -0.114258f, 0.400391f,
--0.172852f, 0.415527f, -0.163086f, 0.405273f, -0.0961914f, 0.355957f, -0.0412598f,
-0.306641f, 0.0136719f, 0.232422f, 0.0136719f, 0.151855f, 0.0136719f, 0.0944824f,
--0.0490723f, 0.0371094f, -0.111816f, 0.0371094f, -0.217773f, 0.0371094f, -0.33252f,
-0.0959473f, -0.396729f, 0.154785f, -0.460938f, 0.243652f, -0.460938f, 0.318848f,
--0.460938f, 0.367188f, -0.411377f, 0.415527f, -0.361816f, 0.415527f, -0.278809f,
-0.106445f, -0.307129f, 0.313477f, -0.307129f, 0.311035f, -0.350098f, 0.303223f, -0.367676f,
-0.291016f, -0.39502f, 0.266846f, -0.410645f, 0.242676f, -0.42627f, 0.216309f, -0.42627f,
-0.175781f, -0.42627f, 0.143799f, -0.394775f, 0.111816f, -0.363281f, 0.106445f, -0.307129f,
-0.206055f, -0.412109f, 0.206055f, -0.118164f, 0.206055f, -0.0556641f, 0.219727f,
--0.0390625f, 0.237793f, -0.0175781f, 0.268066f, -0.0175781f, 0.308594f, -0.0175781f,
-0.308594f, 0, 0.0415039f, 0, 0.0415039f, -0.0175781f, 0.0615234f, -0.0175781f, 0.0810547f,
--0.0175781f, 0.097168f, -0.0273438f, 0.113281f, -0.0371094f, 0.119385f, -0.0537109f,
-0.125488f, -0.0703125f, 0.125488f, -0.118164f, 0.125488f, -0.412109f, 0.0385742f,
--0.412109f, 0.0385742f, -0.447266f, 0.125488f, -0.447266f, 0.125488f, -0.476562f,
-0.125488f, -0.543457f, 0.146973f, -0.589844f, 0.168457f, -0.63623f, 0.212646f, -0.664795f,
-0.256836f, -0.693359f, 0.312012f, -0.693359f, 0.363281f, -0.693359f, 0.40625f, -0.660156f,
-0.43457f, -0.638184f, 0.43457f, -0.61084f, 0.43457f, -0.596191f, 0.421875f, -0.583252f,
-0.40918f, -0.570312f, 0.394531f, -0.570312f, 0.383301f, -0.570312f, 0.37085f, -0.578369f,
-0.358398f, -0.586426f, 0.340332f, -0.613037f, 0.322266f, -0.639648f, 0.307129f, -0.648926f,
-0.291992f, -0.658203f, 0.273438f, -0.658203f, 0.250977f, -0.658203f, 0.235352f, -0.64624f,
-0.219727f, -0.634277f, 0.212891f, -0.609131f, 0.206055f, -0.583984f, 0.206055f, -0.479492f,
-0.206055f, -0.447266f, 0.321289f, -0.447266f, 0.321289f, -0.412109f, 0.150879f, -0.163086f,
-0.109863f, -0.183105f, 0.0878906f, -0.218994f, 0.065918f, -0.254883f, 0.065918f,
--0.29834f, 0.065918f, -0.364746f, 0.115967f, -0.412598f, 0.166016f, -0.460449f, 0.244141f,
--0.460449f, 0.308105f, -0.460449f, 0.35498f, -0.429199f, 0.449707f, -0.429199f, 0.470703f,
--0.429199f, 0.474121f, -0.427979f, 0.477539f, -0.426758f, 0.479004f, -0.423828f,
-0.481934f, -0.419434f, 0.481934f, -0.408203f, 0.481934f, -0.395508f, 0.479492f, -0.390625f,
-0.478027f, -0.388184f, 0.474365f, -0.386719f, 0.470703f, -0.385254f, 0.449707f, -0.385254f,
-0.391602f, -0.385254f, 0.418945f, -0.350098f, 0.418945f, -0.29541f, 0.418945f, -0.23291f,
-0.371094f, -0.188477f, 0.323242f, -0.144043f, 0.242676f, -0.144043f, 0.209473f, -0.144043f,
-0.174805f, -0.153809f, 0.15332f, -0.135254f, 0.145752f, -0.121338f, 0.138184f, -0.107422f,
-0.138184f, -0.0976562f, 0.138184f, -0.0893555f, 0.14624f, -0.081543f, 0.154297f,
--0.0737305f, 0.177734f, -0.0703125f, 0.191406f, -0.0683594f, 0.246094f, -0.0668945f,
-0.34668f, -0.0644531f, 0.376465f, -0.0600586f, 0.421875f, -0.0537109f, 0.448975f,
--0.0263672f, 0.476074f, 0.000976562f, 0.476074f, 0.0410156f, 0.476074f, 0.0961914f,
-0.424316f, 0.144531f, 0.348145f, 0.21582f, 0.225586f, 0.21582f, 0.131348f, 0.21582f,
-0.0664062f, 0.17334f, 0.0297852f, 0.148926f, 0.0297852f, 0.122559f, 0.0297852f, 0.11084f,
-0.0351562f, 0.0991211f, 0.043457f, 0.0810547f, 0.0693359f, 0.0488281f, 0.0727539f,
-0.0444336f, 0.119141f, -0.00390625f, 0.09375f, -0.019043f, 0.083252f, -0.0310059f,
-0.0727539f, -0.0429688f, 0.0727539f, -0.0581055f, 0.0727539f, -0.0751953f, 0.0866699f,
--0.0981445f, 0.100586f, -0.121094f, 0.150879f, -0.163086f, 0.23584f, -0.437012f,
-0.199707f, -0.437012f, 0.175293f, -0.408203f, 0.150879f, -0.379395f, 0.150879f, -0.319824f,
-0.150879f, -0.242676f, 0.184082f, -0.200195f, 0.209473f, -0.167969f, 0.248535f, -0.167969f,
-0.285645f, -0.167969f, 0.30957f, -0.195801f, 0.333496f, -0.223633f, 0.333496f, -0.283203f,
-0.333496f, -0.36084f, 0.299805f, -0.404785f, 0.274902f, -0.437012f, 0.23584f, -0.437012f,
-0.145996f, 0, 0.123047f, 0.0249023f, 0.111328f, 0.0463867f, 0.0996094f, 0.0678711f,
-0.0996094f, 0.0859375f, 0.0996094f, 0.109375f, 0.12793f, 0.126953f, 0.176758f, 0.157227f,
-0.269043f, 0.157227f, 0.356934f, 0.157227f, 0.398682f, 0.126221f, 0.44043f, 0.0952148f,
-0.44043f, 0.0600586f, 0.44043f, 0.034668f, 0.415527f, 0.0239258f, 0.390137f, 0.0131836f,
-0.314941f, 0.0112305f, 0.205078f, 0.00830078f, 0.145996f, 0, 0.14502f, -0.694336f,
-0.165527f, -0.694336f, 0.179932f, -0.679932f, 0.194336f, -0.665527f, 0.194336f, -0.64502f,
-0.194336f, -0.624512f, 0.179932f, -0.609863f, 0.165527f, -0.595215f, 0.14502f, -0.595215f,
-0.124512f, -0.595215f, 0.109863f, -0.609863f, 0.0952148f, -0.624512f, 0.0952148f,
--0.64502f, 0.0952148f, -0.665527f, 0.109619f, -0.679932f, 0.124023f, -0.694336f,
-0.14502f, -0.694336f, 0.185547f, -0.460449f, 0.185547f, -0.101074f, 0.185547f, -0.059082f,
-0.19165f, -0.045166f, 0.197754f, -0.03125f, 0.209717f, -0.0244141f, 0.22168f, -0.0175781f,
-0.253418f, -0.0175781f, 0.253418f, 0, 0.0361328f, 0, 0.0361328f, -0.0175781f, 0.0688477f,
--0.0175781f, 0.0800781f, -0.0239258f, 0.0913086f, -0.0302734f, 0.0979004f, -0.0449219f,
-0.104492f, -0.0595703f, 0.104492f, -0.101074f, 0.104492f, -0.273438f, 0.104492f,
--0.346191f, 0.100098f, -0.367676f, 0.0966797f, -0.383301f, 0.0893555f, -0.389404f,
-0.0820312f, -0.395508f, 0.0693359f, -0.395508f, 0.0556641f, -0.395508f, 0.0361328f,
--0.388184f, 0.0292969f, -0.405762f, 0.164062f, -0.460449f, 0.144531f, -0.694824f,
-0.165527f, -0.694824f, 0.180176f, -0.680176f, 0.194824f, -0.665527f, 0.194824f, -0.644531f,
-0.194824f, -0.624023f, 0.180176f, -0.609375f, 0.165527f, -0.594727f, 0.144531f, -0.594727f,
-0.124023f, -0.594727f, 0.109375f, -0.609375f, 0.0947266f, -0.624023f, 0.0947266f,
--0.644531f, 0.0947266f, -0.665527f, 0.109375f, -0.680176f, 0.124023f, -0.694824f,
-0.144531f, -0.694824f, 0.186523f, -0.460449f, 0.186523f, -0.0102539f, 0.186523f,
-0.104492f, 0.137695f, 0.160156f, 0.0888672f, 0.21582f, 0.0107422f, 0.21582f, -0.0336914f,
-0.21582f, -0.0551758f, 0.199707f, -0.0766602f, 0.183594f, -0.0766602f, 0.166504f,
--0.0766602f, 0.149414f, -0.0646973f, 0.137207f, -0.0527344f, 0.125f, -0.0366211f,
-0.125f, -0.0239258f, 0.125f, -0.0107422f, 0.131348f, -0.00244141f, 0.134766f, 0.0212402f,
-0.156006f, 0.0449219f, 0.177246f, 0.0610352f, 0.177246f, 0.0727539f, 0.177246f, 0.0839844f,
-0.168213f, 0.0952148f, 0.15918f, 0.100586f, 0.137939f, 0.105957f, 0.116699f, 0.105957f,
-0.0458984f, 0.105957f, -0.272461f, 0.105957f, -0.346191f, 0.101562f, -0.367188f,
-0.0981445f, -0.383301f, 0.0908203f, -0.389404f, 0.0834961f, -0.395508f, 0.0708008f,
--0.395508f, 0.0571289f, -0.395508f, 0.0375977f, -0.388184f, 0.0307617f, -0.405762f,
-0.165527f, -0.460449f, 0.163574f, -0.694336f, 0.163574f, -0.249023f, 0.277344f, -0.353027f,
-0.313477f, -0.38623f, 0.319336f, -0.39502f, 0.323242f, -0.400879f, 0.323242f, -0.406738f,
-0.323242f, -0.416504f, 0.315186f, -0.423584f, 0.307129f, -0.430664f, 0.288574f, -0.431641f,
-0.288574f, -0.447266f, 0.48291f, -0.447266f, 0.48291f, -0.431641f, 0.442871f, -0.430664f,
-0.41626f, -0.419434f, 0.389648f, -0.408203f, 0.35791f, -0.379395f, 0.243164f, -0.273438f,
-0.35791f, -0.128418f, 0.405762f, -0.0683594f, 0.422363f, -0.0522461f, 0.445801f,
--0.0292969f, 0.463379f, -0.0224609f, 0.475586f, -0.0175781f, 0.505859f, -0.0175781f,
-0.505859f, 0, 0.288574f, 0, 0.288574f, -0.0175781f, 0.307129f, -0.0180664f, 0.313721f,
--0.0231934f, 0.320312f, -0.0283203f, 0.320312f, -0.0375977f, 0.320312f, -0.0488281f,
-0.300781f, -0.0737305f, 0.163574f, -0.249023f, 0.163574f, -0.100586f, 0.163574f,
--0.0571289f, 0.169678f, -0.043457f, 0.175781f, -0.0297852f, 0.187012f, -0.0239258f,
-0.198242f, -0.0180664f, 0.23584f, -0.0175781f, 0.23584f, 0, 0.00830078f, 0, 0.00830078f,
--0.0175781f, 0.0424805f, -0.0175781f, 0.0595703f, -0.0258789f, 0.0698242f, -0.03125f,
-0.0751953f, -0.0424805f, 0.0825195f, -0.0585938f, 0.0825195f, -0.0981445f, 0.0825195f,
--0.505371f, 0.0825195f, -0.583008f, 0.0791016f, -0.600342f, 0.0756836f, -0.617676f,
-0.0678711f, -0.624268f, 0.0600586f, -0.630859f, 0.0473633f, -0.630859f, 0.0371094f,
--0.630859f, 0.0166016f, -0.622559f, 0.00830078f, -0.639648f, 0.141113f, -0.694336f,
-0.185059f, -0.694336f, 0.185059f, -0.101074f, 0.185059f, -0.059082f, 0.191162f, -0.0454102f,
-0.197266f, -0.0317383f, 0.209961f, -0.0246582f, 0.222656f, -0.0175781f, 0.257324f,
--0.0175781f, 0.257324f, 0, 0.0380859f, 0, 0.0380859f, -0.0175781f, 0.0688477f, -0.0175781f,
-0.0800781f, -0.0239258f, 0.0913086f, -0.0302734f, 0.0976562f, -0.0449219f, 0.104004f,
--0.0595703f, 0.104004f, -0.101074f, 0.104004f, -0.507324f, 0.104004f, -0.583008f,
-0.100586f, -0.600342f, 0.097168f, -0.617676f, 0.0895996f, -0.624023f, 0.0820312f,
--0.630371f, 0.0703125f, -0.630371f, 0.0576172f, -0.630371f, 0.0380859f, -0.622559f,
-0.0297852f, -0.639648f, 0.163086f, -0.694336f, 0.164062f, -0.365234f, 0.212891f,
--0.414062f, 0.22168f, -0.421387f, 0.243652f, -0.439941f, 0.269043f, -0.450195f, 0.294434f,
--0.460449f, 0.319336f, -0.460449f, 0.361328f, -0.460449f, 0.391602f, -0.436035f,
-0.421875f, -0.411621f, 0.432129f, -0.365234f, 0.482422f, -0.423828f, 0.51709f, -0.442139f,
-0.551758f, -0.460449f, 0.588379f, -0.460449f, 0.624023f, -0.460449f, 0.651611f, -0.442139f,
-0.679199f, -0.423828f, 0.695312f, -0.382324f, 0.706055f, -0.354004f, 0.706055f, -0.293457f,
-0.706055f, -0.101074f, 0.706055f, -0.059082f, 0.712402f, -0.043457f, 0.717285f, -0.0327148f,
-0.730469f, -0.0251465f, 0.743652f, -0.0175781f, 0.773438f, -0.0175781f, 0.773438f,
-0, 0.552734f, 0, 0.552734f, -0.0175781f, 0.562012f, -0.0175781f, 0.59082f, -0.0175781f,
-0.606934f, -0.0288086f, 0.618164f, -0.0366211f, 0.623047f, -0.0537109f, 0.625f, -0.0620117f,
-0.625f, -0.101074f, 0.625f, -0.293457f, 0.625f, -0.348145f, 0.611816f, -0.370605f,
-0.592773f, -0.401855f, 0.550781f, -0.401855f, 0.524902f, -0.401855f, 0.498779f, -0.388916f,
-0.472656f, -0.375977f, 0.435547f, -0.34082f, 0.43457f, -0.335449f, 0.435547f, -0.314453f,
-0.435547f, -0.101074f, 0.435547f, -0.0551758f, 0.440674f, -0.0439453f, 0.445801f,
--0.0327148f, 0.459961f, -0.0251465f, 0.474121f, -0.0175781f, 0.508301f, -0.0175781f,
-0.508301f, 0, 0.282227f, 0, 0.282227f, -0.0175781f, 0.319336f, -0.0175781f, 0.333252f,
--0.0263672f, 0.347168f, -0.0351562f, 0.352539f, -0.0527344f, 0.35498f, -0.0610352f,
-0.35498f, -0.101074f, 0.35498f, -0.293457f, 0.35498f, -0.348145f, 0.338867f, -0.37207f,
-0.317383f, -0.40332f, 0.278809f, -0.40332f, 0.252441f, -0.40332f, 0.226562f, -0.38916f,
-0.186035f, -0.367676f, 0.164062f, -0.34082f, 0.164062f, -0.101074f, 0.164062f, -0.0571289f,
-0.170166f, -0.0439453f, 0.17627f, -0.0307617f, 0.188232f, -0.0241699f, 0.200195f,
--0.0175781f, 0.236816f, -0.0175781f, 0.236816f, 0, 0.015625f, 0, 0.015625f, -0.0175781f,
-0.0463867f, -0.0175781f, 0.0585938f, -0.0241699f, 0.0708008f, -0.0307617f, 0.0771484f,
--0.045166f, 0.0834961f, -0.0595703f, 0.0834961f, -0.101074f, 0.0834961f, -0.271973f,
-0.0834961f, -0.345703f, 0.0791016f, -0.367188f, 0.0756836f, -0.383301f, 0.0683594f,
--0.389404f, 0.0610352f, -0.395508f, 0.0483398f, -0.395508f, 0.034668f, -0.395508f,
-0.015625f, -0.388184f, 0.00830078f, -0.405762f, 0.143066f, -0.460449f, 0.164062f,
--0.460449f, 0.161621f, -0.365723f, 0.240234f, -0.460449f, 0.311523f, -0.460449f,
-0.348145f, -0.460449f, 0.374512f, -0.442139f, 0.400879f, -0.423828f, 0.416504f, -0.381836f,
-0.427246f, -0.352539f, 0.427246f, -0.291992f, 0.427246f, -0.101074f, 0.427246f, -0.0585938f,
-0.434082f, -0.043457f, 0.439453f, -0.03125f, 0.451416f, -0.0244141f, 0.463379f, -0.0175781f,
-0.495605f, -0.0175781f, 0.495605f, 0, 0.274414f, 0, 0.274414f, -0.0175781f, 0.283691f,
--0.0175781f, 0.314941f, -0.0175781f, 0.327393f, -0.0270996f, 0.339844f, -0.0366211f,
-0.344727f, -0.0551758f, 0.34668f, -0.0625f, 0.34668f, -0.101074f, 0.34668f, -0.28418f,
-0.34668f, -0.345215f, 0.330811f, -0.372803f, 0.314941f, -0.400391f, 0.277344f, -0.400391f,
-0.219238f, -0.400391f, 0.161621f, -0.336914f, 0.161621f, -0.101074f, 0.161621f, -0.0556641f,
-0.166992f, -0.0449219f, 0.173828f, -0.0307617f, 0.185791f, -0.0241699f, 0.197754f,
--0.0175781f, 0.234375f, -0.0175781f, 0.234375f, 0, 0.0131836f, 0, 0.0131836f, -0.0175781f,
-0.0229492f, -0.0175781f, 0.0571289f, -0.0175781f, 0.0690918f, -0.0349121f, 0.0810547f,
--0.0522461f, 0.0810547f, -0.101074f, 0.0810547f, -0.26709f, 0.0810547f, -0.347656f,
-0.0773926f, -0.365234f, 0.0737305f, -0.382812f, 0.0661621f, -0.38916f, 0.0585938f,
--0.395508f, 0.0458984f, -0.395508f, 0.0322266f, -0.395508f, 0.0131836f, -0.388184f,
-0.00585938f, -0.405762f, 0.140625f, -0.460449f, 0.161621f, -0.460449f, 0.25f, -0.460449f,
-0.351562f, -0.460449f, 0.413086f, -0.383301f, 0.465332f, -0.317383f, 0.465332f, -0.231934f,
-0.465332f, -0.171875f, 0.436523f, -0.110352f, 0.407715f, -0.0488281f, 0.357178f,
--0.0175781f, 0.306641f, 0.0136719f, 0.244629f, 0.0136719f, 0.143555f, 0.0136719f,
-0.0839844f, -0.0668945f, 0.0336914f, -0.134766f, 0.0336914f, -0.219238f, 0.0336914f,
--0.280762f, 0.064209f, -0.341553f, 0.0947266f, -0.402344f, 0.144531f, -0.431396f,
-0.194336f, -0.460449f, 0.25f, -0.460449f, 0.234863f, -0.428711f, 0.208984f, -0.428711f,
-0.182861f, -0.41333f, 0.156738f, -0.397949f, 0.140625f, -0.359375f, 0.124512f, -0.320801f,
-0.124512f, -0.260254f, 0.124512f, -0.162598f, 0.16333f, -0.0917969f, 0.202148f, -0.0209961f,
-0.265625f, -0.0209961f, 0.312988f, -0.0209961f, 0.34375f, -0.0600586f, 0.374512f,
--0.0991211f, 0.374512f, -0.194336f, 0.374512f, -0.313477f, 0.323242f, -0.381836f,
-0.288574f, -0.428711f, 0.234863f, -0.428711f, -0.000976562f, -0.402832f, 0.136719f,
--0.458496f, 0.155273f, -0.458496f, 0.155273f, -0.354004f, 0.189941f, -0.413086f,
-0.224854f, -0.436768f, 0.259766f, -0.460449f, 0.29834f, -0.460449f, 0.365723f, -0.460449f,
-0.410645f, -0.407715f, 0.46582f, -0.343262f, 0.46582f, -0.239746f, 0.46582f, -0.124023f,
-0.399414f, -0.0483398f, 0.344727f, 0.0136719f, 0.261719f, 0.0136719f, 0.225586f,
-0.0136719f, 0.199219f, 0.00341797f, 0.179688f, -0.00390625f, 0.155273f, -0.0258789f,
-0.155273f, 0.110352f, 0.155273f, 0.15625f, 0.160889f, 0.168701f, 0.166504f, 0.181152f,
-0.18042f, 0.188477f, 0.194336f, 0.195801f, 0.230957f, 0.195801f, 0.230957f, 0.213867f,
--0.00341797f, 0.213867f, -0.00341797f, 0.195801f, 0.00878906f, 0.195801f, 0.0356445f,
-0.196289f, 0.0546875f, 0.185547f, 0.0639648f, 0.180176f, 0.0690918f, 0.168213f, 0.0742188f,
-0.15625f, 0.0742188f, 0.107422f, 0.0742188f, -0.31543f, 0.0742188f, -0.358887f, 0.0703125f,
--0.370605f, 0.0664062f, -0.382324f, 0.0578613f, -0.388184f, 0.0493164f, -0.394043f,
-0.034668f, -0.394043f, 0.0229492f, -0.394043f, 0.00488281f, -0.387207f, 0.155273f,
--0.325195f, 0.155273f, -0.158203f, 0.155273f, -0.104004f, 0.159668f, -0.0869141f,
-0.166504f, -0.0585938f, 0.193115f, -0.0371094f, 0.219727f, -0.015625f, 0.260254f,
--0.015625f, 0.309082f, -0.015625f, 0.339355f, -0.0537109f, 0.378906f, -0.103516f,
-0.378906f, -0.193848f, 0.378906f, -0.296387f, 0.333984f, -0.351562f, 0.302734f, -0.389648f,
-0.259766f, -0.389648f, 0.236328f, -0.389648f, 0.213379f, -0.37793f, 0.195801f, -0.369141f,
-0.155273f, -0.325195f, 0.427246f, -0.460449f, 0.427246f, 0.114746f, 0.427246f, 0.157715f,
-0.433105f, 0.169922f, 0.438965f, 0.182129f, 0.451416f, 0.188965f, 0.463867f, 0.195801f,
-0.5f, 0.195801f, 0.5f, 0.213867f, 0.274414f, 0.213867f, 0.274414f, 0.195801f, 0.283691f,
-0.195801f, 0.311035f, 0.195801f, 0.325195f, 0.187988f, 0.334961f, 0.182617f, 0.34082f,
-0.168701f, 0.34668f, 0.154785f, 0.34668f, 0.114746f, 0.34668f, -0.0776367f, 0.302246f,
--0.0249023f, 0.269043f, -0.00561523f, 0.23584f, 0.0136719f, 0.200195f, 0.0136719f,
-0.135254f, 0.0136719f, 0.0842285f, -0.0454102f, 0.0332031f, -0.104492f, 0.0332031f,
--0.203613f, 0.0332031f, -0.317383f, 0.100586f, -0.388916f, 0.167969f, -0.460449f,
-0.263184f, -0.460449f, 0.291016f, -0.460449f, 0.314453f, -0.452637f, 0.337891f, -0.444824f,
-0.356445f, -0.429199f, 0.384766f, -0.442871f, 0.410645f, -0.460449f, 0.34668f, -0.108398f,
-0.34668f, -0.318359f, 0.34668f, -0.35498f, 0.337158f, -0.375977f, 0.327637f, -0.396973f,
-0.303223f, -0.411621f, 0.278809f, -0.42627f, 0.248047f, -0.42627f, 0.193359f, -0.42627f,
-0.154297f, -0.379883f, 0.115234f, -0.333496f, 0.115234f, -0.239258f, 0.115234f, -0.148926f,
-0.155029f, -0.102051f, 0.194824f, -0.0551758f, 0.250977f, -0.0551758f, 0.279785f,
--0.0551758f, 0.302246f, -0.067627f, 0.324707f, -0.0800781f, 0.34668f, -0.108398f,
-0.162109f, -0.460449f, 0.162109f, -0.359863f, 0.218262f, -0.460449f, 0.277344f, -0.460449f,
-0.304199f, -0.460449f, 0.321777f, -0.444092f, 0.339355f, -0.427734f, 0.339355f, -0.40625f,
-0.339355f, -0.387207f, 0.32666f, -0.374023f, 0.313965f, -0.36084f, 0.296387f, -0.36084f,
-0.279297f, -0.36084f, 0.258057f, -0.377686f, 0.236816f, -0.394531f, 0.226562f, -0.394531f,
-0.217773f, -0.394531f, 0.20752f, -0.384766f, 0.185547f, -0.364746f, 0.162109f, -0.318848f,
-0.162109f, -0.104492f, 0.162109f, -0.0673828f, 0.171387f, -0.0483398f, 0.177734f,
--0.0351562f, 0.193848f, -0.0263672f, 0.209961f, -0.0175781f, 0.240234f, -0.0175781f,
-0.240234f, 0, 0.0112305f, 0, 0.0112305f, -0.0175781f, 0.0454102f, -0.0175781f, 0.0620117f,
--0.0283203f, 0.0742188f, -0.0361328f, 0.0791016f, -0.0532227f, 0.081543f, -0.0615234f,
-0.081543f, -0.100586f, 0.081543f, -0.273926f, 0.081543f, -0.352051f, 0.0783691f,
--0.366943f, 0.0751953f, -0.381836f, 0.0666504f, -0.388672f, 0.0581055f, -0.395508f,
-0.0454102f, -0.395508f, 0.0302734f, -0.395508f, 0.0112305f, -0.388184f, 0.00634766f,
--0.405762f, 0.141602f, -0.460449f, 0.320312f, -0.460449f, 0.320312f, -0.308105f,
-0.304199f, -0.308105f, 0.285645f, -0.379883f, 0.256592f, -0.405762f, 0.227539f, -0.431641f,
-0.182617f, -0.431641f, 0.148438f, -0.431641f, 0.127441f, -0.413574f, 0.106445f, -0.395508f,
-0.106445f, -0.373535f, 0.106445f, -0.346191f, 0.12207f, -0.32666f, 0.137207f, -0.306641f,
-0.183594f, -0.28418f, 0.254883f, -0.249512f, 0.354004f, -0.201172f, 0.354004f, -0.12207f,
-0.354004f, -0.0610352f, 0.307861f, -0.0236816f, 0.261719f, 0.0136719f, 0.20459f,
-0.0136719f, 0.163574f, 0.0136719f, 0.11084f, -0.000976562f, 0.0947266f, -0.00585938f,
-0.0844727f, -0.00585938f, 0.0732422f, -0.00585938f, 0.0668945f, 0.00683594f, 0.0507812f,
-0.00683594f, 0.0507812f, -0.152832f, 0.0668945f, -0.152832f, 0.0805664f, -0.0844727f,
-0.119141f, -0.0498047f, 0.157715f, -0.0151367f, 0.205566f, -0.0151367f, 0.239258f,
--0.0151367f, 0.260498f, -0.0349121f, 0.281738f, -0.0546875f, 0.281738f, -0.0825195f,
-0.281738f, -0.116211f, 0.258057f, -0.13916f, 0.234375f, -0.162109f, 0.163574f, -0.197266f,
-0.0927734f, -0.232422f, 0.0708008f, -0.260742f, 0.0488281f, -0.288574f, 0.0488281f,
--0.331055f, 0.0488281f, -0.38623f, 0.0866699f, -0.42334f, 0.124512f, -0.460449f,
-0.18457f, -0.460449f, 0.210938f, -0.460449f, 0.248535f, -0.449219f, 0.273438f, -0.441895f,
-0.281738f, -0.441895f, 0.289551f, -0.441895f, 0.293945f, -0.445312f, 0.29834f, -0.44873f,
-0.304199f, -0.460449f, 0.161133f, -0.594238f, 0.161133f, -0.447266f, 0.265625f, -0.447266f,
-0.265625f, -0.413086f, 0.161133f, -0.413086f, 0.161133f, -0.123047f, 0.161133f, -0.0795898f,
-0.173584f, -0.0644531f, 0.186035f, -0.0493164f, 0.205566f, -0.0493164f, 0.22168f,
--0.0493164f, 0.236816f, -0.0593262f, 0.251953f, -0.0693359f, 0.260254f, -0.0888672f,
-0.279297f, -0.0888672f, 0.262207f, -0.0410156f, 0.230957f, -0.0168457f, 0.199707f,
-0.00732422f, 0.166504f, 0.00732422f, 0.144043f, 0.00732422f, 0.122559f, -0.00512695f,
-0.101074f, -0.0175781f, 0.0908203f, -0.0407715f, 0.0805664f, -0.0639648f, 0.0805664f,
--0.112305f, 0.0805664f, -0.413086f, 0.00976562f, -0.413086f, 0.00976562f, -0.429199f,
-0.0366211f, -0.439941f, 0.0646973f, -0.465576f, 0.0927734f, -0.491211f, 0.114746f,
--0.526367f, 0.125977f, -0.544922f, 0.145996f, -0.594238f, 0.42334f, -0.447266f, 0.42334f,
--0.17627f, 0.42334f, -0.0986328f, 0.427002f, -0.0812988f, 0.430664f, -0.0639648f,
-0.438721f, -0.0571289f, 0.446777f, -0.050293f, 0.45752f, -0.050293f, 0.472656f, -0.050293f,
-0.491699f, -0.0585938f, 0.498535f, -0.0415039f, 0.364746f, 0.0136719f, 0.342773f,
-0.0136719f, 0.342773f, -0.0810547f, 0.285156f, -0.0185547f, 0.254883f, -0.00244141f,
-0.224609f, 0.0136719f, 0.190918f, 0.0136719f, 0.15332f, 0.0136719f, 0.125732f, -0.00805664f,
-0.0981445f, -0.0297852f, 0.0874023f, -0.0639648f, 0.0766602f, -0.0981445f, 0.0766602f,
--0.160645f, 0.0766602f, -0.360352f, 0.0766602f, -0.39209f, 0.0698242f, -0.404297f,
-0.0629883f, -0.416504f, 0.0495605f, -0.423096f, 0.0361328f, -0.429688f, 0.000976562f,
--0.429199f, 0.000976562f, -0.447266f, 0.157715f, -0.447266f, 0.157715f, -0.147949f,
-0.157715f, -0.0854492f, 0.179443f, -0.065918f, 0.201172f, -0.0463867f, 0.231934f,
--0.0463867f, 0.25293f, -0.0463867f, 0.279541f, -0.0595703f, 0.306152f, -0.0727539f,
-0.342773f, -0.109863f, 0.342773f, -0.363281f, 0.342773f, -0.401367f, 0.328857f, -0.414795f,
-0.314941f, -0.428223f, 0.270996f, -0.429199f, 0.270996f, -0.447266f, 0.00830078f,
--0.447266f, 0.21875f, -0.447266f, 0.21875f, -0.429199f, 0.205078f, -0.429199f, 0.186035f,
--0.429199f, 0.176025f, -0.419922f, 0.166016f, -0.410645f, 0.166016f, -0.39502f, 0.166016f,
--0.37793f, 0.17627f, -0.354492f, 0.280273f, -0.107422f, 0.384766f, -0.36377f, 0.395996f,
--0.391113f, 0.395996f, -0.405273f, 0.395996f, -0.412109f, 0.39209f, -0.416504f, 0.386719f,
--0.423828f, 0.378418f, -0.426514f, 0.370117f, -0.429199f, 0.344727f, -0.429199f,
-0.344727f, -0.447266f, 0.490723f, -0.447266f, 0.490723f, -0.429199f, 0.465332f, -0.427246f,
-0.455566f, -0.418945f, 0.438477f, -0.404297f, 0.424805f, -0.370117f, 0.266113f, 0.0136719f,
-0.246094f, 0.0136719f, 0.0864258f, -0.36377f, 0.0756836f, -0.390137f, 0.065918f,
--0.401611f, 0.0561523f, -0.413086f, 0.0410156f, -0.420898f, 0.0327148f, -0.425293f,
-0.00830078f, -0.429199f, 0.00634766f, -0.447266f, 0.193848f, -0.447266f, 0.193848f,
--0.429199f, 0.167969f, -0.427246f, 0.159912f, -0.419922f, 0.151855f, -0.412598f,
-0.151855f, -0.398926f, 0.151855f, -0.383789f, 0.160156f, -0.362305f, 0.255859f, -0.10498f,
-0.352051f, -0.314453f, 0.32666f, -0.380371f, 0.314941f, -0.409668f, 0.295898f, -0.420898f,
-0.285156f, -0.427734f, 0.255859f, -0.429199f, 0.255859f, -0.447266f, 0.46875f, -0.447266f,
-0.46875f, -0.429199f, 0.433594f, -0.427734f, 0.418945f, -0.416504f, 0.40918f, -0.408691f,
-0.40918f, -0.391602f, 0.40918f, -0.381836f, 0.413086f, -0.371582f, 0.514648f, -0.114746f,
-0.608887f, -0.362305f, 0.618652f, -0.388672f, 0.618652f, -0.404297f, 0.618652f, -0.413574f,
-0.609131f, -0.420898f, 0.599609f, -0.428223f, 0.571777f, -0.429199f, 0.571777f, -0.447266f,
-0.712891f, -0.447266f, 0.712891f, -0.429199f, 0.67041f, -0.422852f, 0.650391f, -0.371582f,
-0.500977f, 0.0136719f, 0.480957f, 0.0136719f, 0.369141f, -0.271973f, 0.23877f, 0.0136719f,
-0.220703f, 0.0136719f, 0.0771484f, -0.362305f, 0.0629883f, -0.397949f, 0.0493164f,
--0.4104f, 0.0356445f, -0.422852f, 0.00634766f, -0.429199f, 0.0131836f, -0.447266f,
-0.223633f, -0.447266f, 0.223633f, -0.429199f, 0.203613f, -0.429199f, 0.195557f, -0.422363f,
-0.1875f, -0.415527f, 0.1875f, -0.404297f, 0.1875f, -0.392578f, 0.20459f, -0.368164f,
-0.209961f, -0.360352f, 0.220703f, -0.34375f, 0.252441f, -0.292969f, 0.289062f, -0.34375f,
-0.324219f, -0.39209f, 0.324219f, -0.404785f, 0.324219f, -0.415039f, 0.315918f, -0.422119f,
-0.307617f, -0.429199f, 0.289062f, -0.429199f, 0.289062f, -0.447266f, 0.44043f, -0.447266f,
-0.44043f, -0.429199f, 0.416504f, -0.427734f, 0.398926f, -0.416016f, 0.375f, -0.399414f,
-0.333496f, -0.34375f, 0.272461f, -0.262207f, 0.383789f, -0.102051f, 0.424805f, -0.0429688f,
-0.442383f, -0.0310059f, 0.459961f, -0.019043f, 0.487793f, -0.0175781f, 0.487793f,
-0, 0.276855f, 0, 0.276855f, -0.0175781f, 0.298828f, -0.0175781f, 0.311035f, -0.0273438f,
-0.320312f, -0.0341797f, 0.320312f, -0.0454102f, 0.320312f, -0.0566406f, 0.289062f,
--0.102051f, 0.223633f, -0.197754f, 0.151855f, -0.102051f, 0.118652f, -0.0576172f,
-0.118652f, -0.0493164f, 0.118652f, -0.0375977f, 0.129639f, -0.0280762f, 0.140625f,
--0.0185547f, 0.162598f, -0.0175781f, 0.162598f, 0, 0.0166016f, 0, 0.0166016f, -0.0175781f,
-0.0341797f, -0.0200195f, 0.0473633f, -0.0297852f, 0.065918f, -0.0439453f, 0.109863f,
--0.102051f, 0.203613f, -0.226562f, 0.118652f, -0.349609f, 0.0825195f, -0.402344f,
-0.0627441f, -0.415771f, 0.0429688f, -0.429199f, 0.0131836f, -0.429199f, 0.00585938f,
--0.447266f, 0.214355f, -0.447266f, 0.214355f, -0.429199f, 0.204102f, -0.429199f,
-0.182129f, -0.429199f, 0.171143f, -0.419678f, 0.160156f, -0.410156f, 0.160156f, -0.395996f,
-0.160156f, -0.376953f, 0.17627f, -0.343262f, 0.285156f, -0.117676f, 0.385254f, -0.364746f,
-0.393555f, -0.384766f, 0.393555f, -0.404297f, 0.393555f, -0.413086f, 0.390137f, -0.41748f,
-0.38623f, -0.422852f, 0.37793f, -0.426025f, 0.369629f, -0.429199f, 0.348633f, -0.429199f,
-0.348633f, -0.447266f, 0.494141f, -0.447266f, 0.494141f, -0.429199f, 0.476074f, -0.427246f,
-0.466309f, -0.421387f, 0.456543f, -0.415527f, 0.444824f, -0.399414f, 0.44043f, -0.392578f,
-0.428223f, -0.361816f, 0.246094f, 0.0844727f, 0.219727f, 0.149414f, 0.177002f, 0.182617f,
-0.134277f, 0.21582f, 0.0947266f, 0.21582f, 0.065918f, 0.21582f, 0.0473633f, 0.199219f,
-0.0288086f, 0.182617f, 0.0288086f, 0.161133f, 0.0288086f, 0.140625f, 0.0422363f,
-0.128174f, 0.0556641f, 0.115723f, 0.0791016f, 0.115723f, 0.0952148f, 0.115723f, 0.123047f,
-0.126465f, 0.142578f, 0.133789f, 0.147461f, 0.133789f, 0.162109f, 0.133789f, 0.179443f,
-0.118652f, 0.196777f, 0.103516f, 0.214355f, 0.0600586f, 0.246094f, -0.0175781f, 0.0854492f,
--0.35498f, 0.078125f, -0.370117f, 0.0620117f, -0.392578f, 0.0498047f, -0.409668f,
-0.0419922f, -0.415527f, 0.0307617f, -0.42334f, 0.00585938f, -0.429199f, 0.419922f,
--0.137207f, 0.414551f, 0, 0.0200195f, 0, 0.0200195f, -0.0175781f, 0.316895f, -0.413086f,
-0.17041f, -0.413086f, 0.123047f, -0.413086f, 0.108398f, -0.406982f, 0.09375f, -0.400879f,
-0.0844727f, -0.383789f, 0.0712891f, -0.359375f, 0.0693359f, -0.323242f, 0.0498047f,
--0.323242f, 0.0527344f, -0.447266f, 0.427734f, -0.447266f, 0.427734f, -0.429199f,
-0.12793f, -0.0327148f, 0.291016f, -0.0327148f, 0.342285f, -0.0327148f, 0.360596f,
--0.0412598f, 0.378906f, -0.0498047f, 0.390137f, -0.0712891f, 0.397949f, -0.0869141f,
-0.40332f, -0.137207f
-};
-
-const unsigned char TimesNewRomankNormalVerbs[] = {
-6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2,
-2, 2, 2, 2, 1, 5, 0, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1,
-2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 5,
-0, 1, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1,
-2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1,
-1, 5, 6, 0, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1,
-1, 2, 2, 1, 1, 1, 2, 2, 2, 5, 0, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1,
-1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 1, 1, 1, 2,
-2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2,
-2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1,
-1, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2,
-1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-2, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2,
-2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2,
-2, 5, 6, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2,
-2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2,
-2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 1,
-1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2,
-2, 2, 2, 2, 1, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2,
-2, 1, 1, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2,
-1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1,
-1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1,
-1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2,
-2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2,
-1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 5, 6,
-0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5,
-6, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0,
-1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 5, 0, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2,
-2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1,
-1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1,
-1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1,
-2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2,
-1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2,
-2, 2, 2, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2,
-2, 1, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1,
-1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2,
-2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1,
-1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 5, 6, 0, 1, 1, 2,
-2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2,
-2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1,
-1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1,
-1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 5, 6
-};
-
-const unsigned TimesNewRomankNormalCharCodes[] = {
-32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
-42, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63,
-64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84,
-86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 105,
-106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
-122
-};
-
-const SkFixed TimesNewRomankNormalWidths[] = {
-0x00004000, 0x00005540, 0x00006880, 0x00008000, 0x00008000, 0x0000d540, 0x0000c720,
-0x00002e20, 0x00005540, 0x00005540, 0x00008000, 0x00009060, 0x00004000, 0x00005540,
-0x00004000, 0x00004720, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000,
-0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00004720, 0x00009060, 0x00009060,
-0x00009060, 0x000071a0, 0x0000ebc0, 0x0000b8e0, 0x0000aac0, 0x0000aac0, 0x0000b8e0,
-0x00009c60, 0x00008e60, 0x0000b8e0, 0x0000b8e0, 0x00005540, 0x000063a0, 0x0000b8e0,
-0x00009c60, 0x0000e3a0, 0x0000b8e0, 0x00008e60, 0x0000b8e0, 0x0000aac0, 0x00008e60,
-0x00009c60, 0x0000b8e0, 0x0000f1a0, 0x0000b8e0, 0x0000b8e0, 0x00009c60, 0x00005540,
-0x00004720, 0x00005540, 0x00007820, 0x00008000, 0x00005540, 0x000071a0, 0x00008000,
-0x000071a0, 0x00008000, 0x000071a0, 0x00005540, 0x00008000, 0x00004720, 0x00004720,
-0x00008000, 0x00004720, 0x0000c720, 0x00008000, 0x00008000, 0x00008000, 0x00008000,
-0x00005540, 0x000063a0, 0x00004720, 0x00008000, 0x00008000, 0x0000b8e0, 0x00008000,
-0x00008000, 0x000071a0
-};
-
-const int TimesNewRomankNormalCharCodesCount = (int) SK_ARRAY_COUNT(TimesNewRomankNormalCharCodes);
-
-const SkPaint::FontMetrics TimesNewRomankNormalMetrics = {
-0x2d202c67, -1.00684f, -0.891113f, 0.216309f, 0.306641f, 0.0424805f, 2.56836f, 4.1423e-11f,
--0.568359f, 2, 0.460449f, 1.01859e-11f, 0.0488281f, 0.108887f
-};
-
-const SkScalar TimesNewRomankBoldPoints[] = {
-0.177734f, -0.215332f, 0.15625f, -0.215332f, 0.152832f, -0.270996f, 0.133789f, -0.350098f,
-0.108398f, -0.456543f, 0.0854492f, -0.552246f, 0.0854492f, -0.59375f, 0.0854492f,
--0.631348f, 0.10791f, -0.654297f, 0.130371f, -0.677246f, 0.166504f, -0.677246f, 0.20166f,
--0.677246f, 0.224854f, -0.654053f, 0.248047f, -0.630859f, 0.248047f, -0.595215f,
-0.248047f, -0.558105f, 0.223633f, -0.456543f, 0.197754f, -0.350098f, 0.184082f, -0.293457f,
-0.177734f, -0.215332f, 0.16748f, -0.145508f, 0.200195f, -0.145508f, 0.223389f, -0.122314f,
-0.246582f, -0.0991211f, 0.246582f, -0.065918f, 0.246582f, -0.0332031f, 0.223389f,
--0.0100098f, 0.200195f, 0.0131836f, 0.16748f, 0.0131836f, 0.134766f, 0.0131836f,
-0.111572f, -0.0100098f, 0.0883789f, -0.0332031f, 0.0883789f, -0.065918f, 0.0883789f,
--0.0986328f, 0.111328f, -0.12207f, 0.134277f, -0.145508f, 0.16748f, -0.145508f, 0.17041f,
--0.352051f, 0.146484f, -0.352051f, 0.0957031f, -0.540039f, 0.0859375f, -0.57666f,
-0.0859375f, -0.604492f, 0.0859375f, -0.634766f, 0.107178f, -0.656006f, 0.128418f,
--0.677246f, 0.158203f, -0.677246f, 0.192383f, -0.677246f, 0.211426f, -0.655029f,
-0.230469f, -0.632812f, 0.230469f, -0.606934f, 0.230469f, -0.584961f, 0.21875f, -0.539062f,
-0.40625f, -0.352051f, 0.381836f, -0.352051f, 0.33252f, -0.539551f, 0.320801f, -0.58252f,
-0.320801f, -0.605957f, 0.320801f, -0.634277f, 0.342529f, -0.655762f, 0.364258f, -0.677246f,
-0.394531f, -0.677246f, 0.429199f, -0.677246f, 0.44751f, -0.654297f, 0.46582f, -0.631348f,
-0.46582f, -0.607422f, 0.46582f, -0.590332f, 0.453125f, -0.539551f, 0.0439453f, 0.0136719f,
-0.0859375f, -0.193359f, 0.0195312f, -0.193359f, 0.0195312f, -0.258301f, 0.0986328f,
--0.258301f, 0.127441f, -0.400879f, 0.0195312f, -0.400879f, 0.0195312f, -0.464355f,
-0.140137f, -0.464355f, 0.182617f, -0.675781f, 0.24707f, -0.675781f, 0.204102f, -0.464355f,
-0.348145f, -0.464355f, 0.390137f, -0.675781f, 0.45459f, -0.675781f, 0.411621f, -0.464355f,
-0.47998f, -0.464355f, 0.47998f, -0.400879f, 0.399414f, -0.400879f, 0.370117f, -0.258301f,
-0.47998f, -0.258301f, 0.47998f, -0.193359f, 0.35791f, -0.193359f, 0.315918f, 0.0136719f,
-0.250977f, 0.0136719f, 0.292969f, -0.193359f, 0.150879f, -0.193359f, 0.106934f, 0.0136719f,
-0.163574f, -0.258301f, 0.307129f, -0.258301f, 0.335449f, -0.400879f, 0.191895f, -0.400879f,
-0.276367f, -0.407715f, 0.393066f, -0.333984f, 0.425293f, -0.296387f, 0.468262f, -0.245605f,
-0.468262f, -0.176758f, 0.468262f, -0.101562f, 0.41748f, -0.0495605f, 0.366699f, 0.00244141f,
-0.276367f, 0.0102539f, 0.276367f, 0.0673828f, 0.233887f, 0.0673828f, 0.233887f, 0.0136719f,
-0.182129f, 0.0126953f, 0.14209f, 0.00512695f, 0.102051f, -0.00244141f, 0.050293f,
--0.0224609f, 0.050293f, -0.180176f, 0.0708008f, -0.180176f, 0.0805664f, -0.126465f,
-0.101562f, -0.0932617f, 0.122559f, -0.0600586f, 0.154541f, -0.0432129f, 0.186523f,
--0.0263672f, 0.233887f, -0.0224609f, 0.233887f, -0.263672f, 0.116211f, -0.337402f,
-0.0773926f, -0.381592f, 0.0385742f, -0.425781f, 0.0385742f, -0.484375f, 0.0385742f,
--0.547852f, 0.0874023f, -0.596436f, 0.13623f, -0.64502f, 0.233887f, -0.657227f, 0.233887f,
--0.680176f, 0.276367f, -0.680176f, 0.276367f, -0.657227f, 0.359375f, -0.651367f,
-0.443359f, -0.605957f, 0.443359f, -0.464844f, 0.424316f, -0.464844f, 0.410156f, -0.512695f,
-0.390381f, -0.543457f, 0.370605f, -0.574219f, 0.339355f, -0.596191f, 0.31543f, -0.612305f,
-0.276367f, -0.623047f, 0.233887f, -0.624512f, 0.198242f, -0.621582f, 0.176758f, -0.60498f,
-0.142578f, -0.579102f, 0.142578f, -0.54248f, 0.142578f, -0.52002f, 0.158447f, -0.49707f,
-0.174316f, -0.474121f, 0.233887f, -0.43457f, 0.276367f, -0.0224609f, 0.318359f, -0.0322266f,
-0.337891f, -0.0559082f, 0.357422f, -0.0795898f, 0.357422f, -0.115234f, 0.357422f,
--0.145996f, 0.340088f, -0.172852f, 0.322754f, -0.199707f, 0.276367f, -0.233887f,
-0.768066f, -0.677246f, 0.297852f, 0.027832f, 0.232422f, 0.027832f, 0.702148f, -0.677246f,
-0.233398f, -0.677246f, 0.302734f, -0.677246f, 0.350342f, -0.628174f, 0.397949f, -0.579102f,
-0.397949f, -0.501465f, 0.397949f, -0.421875f, 0.350098f, -0.372314f, 0.302246f, -0.322754f,
-0.231445f, -0.322754f, 0.161621f, -0.322754f, 0.115479f, -0.370605f, 0.0693359f,
--0.418457f, 0.0693359f, -0.496582f, 0.0693359f, -0.577148f, 0.116699f, -0.627197f,
-0.164062f, -0.677246f, 0.233398f, -0.677246f, 0.233398f, -0.651367f, 0.222656f, -0.651367f,
-0.21582f, -0.64502f, 0.203613f, -0.633789f, 0.19751f, -0.606201f, 0.191406f, -0.578613f,
-0.191406f, -0.492188f, 0.191406f, -0.42334f, 0.199707f, -0.385742f, 0.20459f, -0.364258f,
-0.216309f, -0.353516f, 0.223633f, -0.347168f, 0.233398f, -0.347168f, 0.244141f, -0.347168f,
-0.250488f, -0.353027f, 0.261719f, -0.363281f, 0.26709f, -0.38623f, 0.275391f, -0.42334f,
-0.275391f, -0.490234f, 0.275391f, -0.572266f, 0.267578f, -0.608887f, 0.262207f, -0.634277f,
-0.25f, -0.645996f, 0.244141f, -0.651367f, 0.233398f, -0.651367f, 0.764648f, -0.327637f,
-0.835449f, -0.327637f, 0.883057f, -0.279053f, 0.930664f, -0.230469f, 0.930664f, -0.151855f,
-0.930664f, -0.0722656f, 0.882324f, -0.0224609f, 0.833984f, 0.0273438f, 0.765625f,
-0.0273438f, 0.697754f, 0.0273438f, 0.650146f, -0.0224609f, 0.602539f, -0.0722656f,
-0.602539f, -0.150391f, 0.602539f, -0.229004f, 0.648926f, -0.27832f, 0.695312f, -0.327637f,
-0.764648f, -0.327637f, 0.766113f, -0.302246f, 0.756348f, -0.302246f, 0.749512f, -0.296387f,
-0.737793f, -0.285645f, 0.731445f, -0.259033f, 0.725098f, -0.232422f, 0.725098f, -0.157227f,
-0.725098f, -0.0771484f, 0.732422f, -0.0419922f, 0.737793f, -0.0170898f, 0.750488f,
--0.00585938f, 0.756836f, 0, 0.76709f, 0, 0.776367f, 0, 0.782227f, -0.00537109f, 0.794434f,
--0.0166016f, 0.800293f, -0.0419922f, 0.808594f, -0.0776367f, 0.808594f, -0.149902f,
-0.808594f, -0.226074f, 0.800781f, -0.26123f, 0.794922f, -0.286621f, 0.783203f, -0.296875f,
-0.777344f, -0.302246f, 0.766113f, -0.302246f, 0.569336f, -0.395996f, 0.772461f, -0.395996f,
-0.772461f, -0.376953f, 0.738281f, -0.37207f, 0.71875f, -0.356689f, 0.699219f, -0.341309f,
-0.667969f, -0.285156f, 0.636719f, -0.229004f, 0.580078f, -0.159668f, 0.629883f, -0.114746f,
-0.661133f, -0.097168f, 0.683105f, -0.0849609f, 0.704102f, -0.0849609f, 0.740234f,
--0.0849609f, 0.769531f, -0.132324f, 0.789551f, -0.121582f, 0.749512f, -0.0429688f,
-0.704102f, -0.00976562f, 0.669434f, 0.0151367f, 0.625f, 0.0151367f, 0.586914f, 0.0151367f,
-0.55249f, -0.0012207f, 0.518066f, -0.0175781f, 0.46875f, -0.0625f, 0.407715f, -0.0214844f,
-0.354004f, -0.00317383f, 0.300293f, 0.0151367f, 0.242188f, 0.0151367f, 0.149414f,
-0.0151367f, 0.0947266f, -0.0351562f, 0.0400391f, -0.0854492f, 0.0400391f, -0.15332f,
-0.0400391f, -0.226562f, 0.0922852f, -0.280762f, 0.144531f, -0.334961f, 0.244141f,
--0.374512f, 0.231445f, -0.40625f, 0.225098f, -0.436523f, 0.21875f, -0.466797f, 0.21875f,
--0.495117f, 0.21875f, -0.573242f, 0.273682f, -0.625244f, 0.328613f, -0.677246f, 0.414062f,
--0.677246f, 0.48291f, -0.677246f, 0.523193f, -0.642822f, 0.563477f, -0.608398f, 0.563477f,
--0.5625f, 0.563477f, -0.507324f, 0.522217f, -0.468018f, 0.480957f, -0.428711f, 0.391602f,
--0.395996f, 0.446777f, -0.298828f, 0.553223f, -0.186523f, 0.625f, -0.26709f, 0.625f,
--0.324707f, 0.625f, -0.345215f, 0.61084f, -0.359619f, 0.59668f, -0.374023f, 0.569336f,
--0.376953f, 0.375f, -0.425293f, 0.42627f, -0.444336f, 0.443848f, -0.466064f, 0.461426f,
--0.487793f, 0.461426f, -0.518555f, 0.461426f, -0.573242f, 0.432617f, -0.61084f, 0.413574f,
--0.635742f, 0.385742f, -0.635742f, 0.362793f, -0.635742f, 0.346436f, -0.617676f,
-0.330078f, -0.599609f, 0.330078f, -0.568848f, 0.330078f, -0.544922f, 0.337891f, -0.517578f,
-0.345703f, -0.490234f, 0.375f, -0.425293f, 0.257812f, -0.343262f, 0.21875f, -0.32666f,
-0.202637f, -0.308105f, 0.179688f, -0.280762f, 0.179688f, -0.24707f, 0.179688f, -0.201172f,
-0.206299f, -0.155762f, 0.23291f, -0.110352f, 0.270508f, -0.0854492f, 0.308105f, -0.0605469f,
-0.345703f, -0.0605469f, 0.364258f, -0.0605469f, 0.387451f, -0.0686035f, 0.410645f,
--0.0766602f, 0.437988f, -0.0927734f, 0.320312f, -0.213379f, 0.257812f, -0.343262f,
-0.152832f, -0.352539f, 0.129395f, -0.352539f, 0.078125f, -0.539062f, 0.0683594f,
--0.57373f, 0.0683594f, -0.603027f, 0.0683594f, -0.634766f, 0.0891113f, -0.656006f,
-0.109863f, -0.677246f, 0.140137f, -0.677246f, 0.174805f, -0.677246f, 0.193604f, -0.654785f,
-0.212402f, -0.632324f, 0.212402f, -0.605957f, 0.212402f, -0.583984f, 0.201172f, -0.539551f,
-0.321289f, -0.677246f, 0.321289f, -0.654785f, 0.270508f, -0.621582f, 0.246582f, -0.589844f,
-0.213379f, -0.545898f, 0.194824f, -0.477051f, 0.171387f, -0.391602f, 0.171387f, -0.238281f,
-0.171387f, -0.09375f, 0.192627f, -0.0136719f, 0.213867f, 0.0664062f, 0.250488f, 0.115723f,
-0.275879f, 0.149902f, 0.321289f, 0.175781f, 0.321289f, 0.200195f, 0.203613f, 0.160645f,
-0.121826f, 0.0388184f, 0.0400391f, -0.0830078f, 0.0400391f, -0.241211f, 0.0400391f,
--0.397461f, 0.121582f, -0.517822f, 0.203125f, -0.638184f, 0.321289f, -0.677246f,
-0.012207f, 0.200195f, 0.012207f, 0.177734f, 0.0629883f, 0.144043f, 0.0869141f, 0.112305f,
-0.119629f, 0.0683594f, 0.138672f, 0, 0.162109f, -0.0859375f, 0.162109f, -0.239258f,
-0.162109f, -0.383789f, 0.140869f, -0.463623f, 0.119629f, -0.543457f, 0.0830078f,
--0.592773f, 0.0576172f, -0.626953f, 0.012207f, -0.652832f, 0.012207f, -0.677246f,
-0.129883f, -0.637695f, 0.21167f, -0.515869f, 0.293457f, -0.394043f, 0.293457f, -0.23584f,
-0.293457f, -0.0800781f, 0.21167f, 0.0402832f, 0.129883f, 0.160645f, 0.012207f, 0.200195f,
-0.240723f, -0.484375f, 0.239258f, -0.512695f, 0.235107f, -0.527344f, 0.230957f, -0.541992f,
-0.215088f, -0.572754f, 0.199219f, -0.603516f, 0.199219f, -0.620605f, 0.199219f, -0.643066f,
-0.215088f, -0.660156f, 0.230957f, -0.677246f, 0.25f, -0.677246f, 0.270996f, -0.677246f,
-0.286377f, -0.661377f, 0.301758f, -0.645508f, 0.301758f, -0.620117f, 0.301758f, -0.600098f,
-0.286621f, -0.571777f, 0.271484f, -0.543457f, 0.267334f, -0.528564f, 0.263184f, -0.513672f,
-0.260742f, -0.484375f, 0.288086f, -0.495605f, 0.299805f, -0.503906f, 0.311523f, -0.512207f,
-0.334473f, -0.536621f, 0.365234f, -0.569336f, 0.393555f, -0.569336f, 0.415039f, -0.569336f,
-0.429688f, -0.555176f, 0.444336f, -0.541016f, 0.444336f, -0.521484f, 0.444336f, -0.500488f,
-0.42627f, -0.484375f, 0.408203f, -0.468262f, 0.379395f, -0.468262f, 0.369629f, -0.468262f,
-0.344727f, -0.469727f, 0.333008f, -0.470215f, 0.319336f, -0.470215f, 0.30127f, -0.470215f,
-0.264648f, -0.468262f, 0.285645f, -0.444336f, 0.297363f, -0.435303f, 0.309082f, -0.42627f,
-0.337891f, -0.411621f, 0.366699f, -0.396973f, 0.379395f, -0.380371f, 0.388672f, -0.368164f,
-0.388672f, -0.349121f, 0.388672f, -0.328125f, 0.374512f, -0.313721f, 0.360352f, -0.299316f,
-0.340332f, -0.299316f, 0.319336f, -0.299316f, 0.30249f, -0.31665f, 0.285645f, -0.333984f,
-0.279297f, -0.378418f, 0.275391f, -0.407227f, 0.270752f, -0.42041f, 0.266113f, -0.433594f,
-0.250977f, -0.458984f, 0.234863f, -0.433105f, 0.229492f, -0.418945f, 0.224121f, -0.404785f,
-0.220215f, -0.378418f, 0.213867f, -0.333984f, 0.197754f, -0.317383f, 0.181641f, -0.300781f,
-0.160156f, -0.300781f, 0.140137f, -0.300781f, 0.125732f, -0.314453f, 0.111328f, -0.328125f,
-0.111328f, -0.347168f, 0.111328f, -0.366699f, 0.122314f, -0.38208f, 0.133301f, -0.397461f,
-0.162842f, -0.413818f, 0.192383f, -0.430176f, 0.203613f, -0.438477f, 0.214844f, -0.446777f,
-0.236328f, -0.468262f, 0.184082f, -0.470215f, 0.17041f, -0.470215f, 0.158203f, -0.469727f,
-0.129395f, -0.467773f, 0.118652f, -0.467773f, 0.0908203f, -0.467773f, 0.0732422f,
--0.483398f, 0.0556641f, -0.499023f, 0.0556641f, -0.520508f, 0.0556641f, -0.540527f,
-0.0700684f, -0.554932f, 0.0844727f, -0.569336f, 0.106445f, -0.569336f, 0.137207f,
--0.569336f, 0.165527f, -0.540039f, 0.193848f, -0.510742f, 0.202148f, -0.504395f,
-0.213867f, -0.496094f, 0.240723f, -0.484375f, 0.0195312f, -0.363281f, 0.254395f,
--0.363281f, 0.254395f, -0.597656f, 0.318359f, -0.597656f, 0.318359f, -0.363281f,
-0.553223f, -0.363281f, 0.553223f, -0.298828f, 0.318359f, -0.298828f, 0.318359f, -0.0664062f,
-0.254395f, -0.0664062f, 0.254395f, -0.298828f, 0.0195312f, -0.298828f, 0.0498047f,
-0.175293f, 0.0498047f, 0.153809f, 0.106445f, 0.129395f, 0.13208f, 0.0905762f, 0.157715f,
-0.0517578f, 0.157715f, 0.0112305f, 0.157715f, 0.00292969f, 0.154297f, -0.00146484f,
-0.150879f, -0.00537109f, 0.147461f, -0.00537109f, 0.144531f, -0.00537109f, 0.138672f,
--0.00195312f, 0.124512f, 0.00634766f, 0.103516f, 0.00634766f, 0.074707f, 0.00634766f,
-0.0534668f, -0.0161133f, 0.0322266f, -0.0385742f, 0.0322266f, -0.0688477f, 0.0322266f,
--0.101074f, 0.0566406f, -0.125488f, 0.0810547f, -0.149902f, 0.115723f, -0.149902f,
-0.157715f, -0.149902f, 0.1875f, -0.117432f, 0.217285f, -0.0849609f, 0.217285f, -0.0283203f,
-0.217285f, 0.0415039f, 0.175049f, 0.0957031f, 0.132812f, 0.149902f, 0.0498047f, 0.175293f,
-0.309082f, -0.179199f, 0.0244141f, -0.179199f, 0.0244141f, -0.280273f, 0.309082f,
--0.280273f, 0.125f, -0.150391f, 0.15918f, -0.150391f, 0.182861f, -0.126465f, 0.206543f,
--0.102539f, 0.206543f, -0.0688477f, 0.206543f, -0.0351562f, 0.182617f, -0.0114746f,
-0.158691f, 0.012207f, 0.125f, 0.012207f, 0.0913086f, 0.012207f, 0.067627f, -0.0114746f,
-0.0439453f, -0.0351562f, 0.0439453f, -0.0688477f, 0.0439453f, -0.102539f, 0.067627f,
--0.126465f, 0.0913086f, -0.150391f, 0.125f, -0.150391f, 0.280762f, -0.677246f, 0.0634766f,
-0.0151367f, 0.000976562f, 0.0151367f, 0.219238f, -0.677246f, 0.463379f, -0.331055f,
-0.463379f, -0.231934f, 0.435547f, -0.145996f, 0.418945f, -0.0932617f, 0.390869f,
--0.0595703f, 0.362793f, -0.0258789f, 0.327148f, -0.00610352f, 0.291504f, 0.0136719f,
-0.249512f, 0.0136719f, 0.20166f, 0.0136719f, 0.163086f, -0.0107422f, 0.124512f, -0.0351562f,
-0.0947266f, -0.0805664f, 0.0732422f, -0.11377f, 0.0571289f, -0.168945f, 0.0361328f,
--0.243652f, 0.0361328f, -0.323242f, 0.0361328f, -0.431152f, 0.0664062f, -0.521484f,
-0.0913086f, -0.596191f, 0.14209f, -0.635986f, 0.192871f, -0.675781f, 0.249512f, -0.675781f,
-0.307129f, -0.675781f, 0.357178f, -0.636475f, 0.407227f, -0.597168f, 0.430664f, -0.530762f,
-0.463379f, -0.439453f, 0.463379f, -0.331055f, 0.312988f, -0.332031f, 0.312988f, -0.505859f,
-0.311035f, -0.534668f, 0.306152f, -0.602539f, 0.287598f, -0.626465f, 0.275391f, -0.64209f,
-0.248047f, -0.64209f, 0.227051f, -0.64209f, 0.214844f, -0.630371f, 0.196777f, -0.613281f,
-0.19043f, -0.570068f, 0.184082f, -0.526855f, 0.184082f, -0.268555f, 0.184082f, -0.12793f,
-0.193848f, -0.0800781f, 0.201172f, -0.0454102f, 0.214844f, -0.0336914f, 0.228516f,
--0.0219727f, 0.250977f, -0.0219727f, 0.275391f, -0.0219727f, 0.287598f, -0.0375977f,
-0.308105f, -0.0649414f, 0.311035f, -0.12207f, 0.325684f, -0.675781f, 0.325684f, -0.134277f,
-0.325684f, -0.0732422f, 0.331055f, -0.0563965f, 0.336426f, -0.0395508f, 0.353516f,
--0.0288086f, 0.370605f, -0.0180664f, 0.408203f, -0.0180664f, 0.42334f, -0.0180664f,
-0.42334f, 0, 0.074707f, 0, 0.074707f, -0.0180664f, 0.0922852f, -0.0180664f, 0.134766f,
--0.0180664f, 0.152832f, -0.027832f, 0.170898f, -0.0375977f, 0.177246f, -0.0546875f,
-0.183594f, -0.0717773f, 0.183594f, -0.134277f, 0.183594f, -0.477539f, 0.183594f,
--0.523438f, 0.179199f, -0.534912f, 0.174805f, -0.546387f, 0.162842f, -0.554443f,
-0.150879f, -0.5625f, 0.135254f, -0.5625f, 0.110352f, -0.5625f, 0.074707f, -0.546875f,
-0.065918f, -0.564453f, 0.30957f, -0.675781f, 0.414062f, 0, 0.0244141f, 0, 0.0244141f,
--0.0107422f, 0.203613f, -0.224121f, 0.241943f, -0.297852f, 0.280273f, -0.371582f,
-0.280273f, -0.441895f, 0.280273f, -0.493164f, 0.248535f, -0.5271f, 0.216797f, -0.561035f,
-0.170898f, -0.561035f, 0.0957031f, -0.561035f, 0.0541992f, -0.48584f, 0.0361328f,
--0.492188f, 0.0625f, -0.585938f, 0.116211f, -0.630859f, 0.169922f, -0.675781f, 0.240234f,
--0.675781f, 0.290527f, -0.675781f, 0.332031f, -0.652344f, 0.373535f, -0.628906f,
-0.396973f, -0.588135f, 0.42041f, -0.547363f, 0.42041f, -0.511719f, 0.42041f, -0.446777f,
-0.384277f, -0.379883f, 0.334961f, -0.289551f, 0.168945f, -0.12793f, 0.312012f, -0.12793f,
-0.364746f, -0.12793f, 0.380615f, -0.132324f, 0.396484f, -0.136719f, 0.406738f, -0.147217f,
-0.416992f, -0.157715f, 0.433594f, -0.191406f, 0.451172f, -0.191406f, 0.147949f, -0.332031f,
-0.147949f, -0.349121f, 0.203613f, -0.365234f, 0.225098f, -0.37915f, 0.246582f, -0.393066f,
-0.262207f, -0.421631f, 0.277832f, -0.450195f, 0.277832f, -0.479492f, 0.277832f, -0.52002f,
-0.248291f, -0.549072f, 0.21875f, -0.578125f, 0.174805f, -0.578125f, 0.106445f, -0.578125f,
-0.0585938f, -0.505859f, 0.0405273f, -0.512207f, 0.0756836f, -0.59375f, 0.130615f,
--0.634766f, 0.185547f, -0.675781f, 0.25293f, -0.675781f, 0.321777f, -0.675781f, 0.366455f,
--0.633789f, 0.411133f, -0.591797f, 0.411133f, -0.535645f, 0.411133f, -0.499023f,
-0.390381f, -0.465088f, 0.369629f, -0.431152f, 0.325195f, -0.405273f, 0.382324f, -0.377441f,
-0.412354f, -0.33667f, 0.442383f, -0.295898f, 0.442383f, -0.234375f, 0.442383f, -0.130859f,
-0.367432f, -0.0583496f, 0.29248f, 0.0141602f, 0.166504f, 0.0141602f, 0.0825195f,
-0.0141602f, 0.0439453f, -0.0136719f, 0.0161133f, -0.0332031f, 0.0161133f, -0.0639648f,
-0.0161133f, -0.0864258f, 0.0322266f, -0.102295f, 0.0483398f, -0.118164f, 0.0693359f,
--0.118164f, 0.0854492f, -0.118164f, 0.0996094f, -0.111328f, 0.107422f, -0.107422f,
-0.155029f, -0.0686035f, 0.202637f, -0.0297852f, 0.244141f, -0.0297852f, 0.280273f,
--0.0297852f, 0.306152f, -0.0583496f, 0.332031f, -0.0869141f, 0.332031f, -0.130859f,
-0.332031f, -0.197754f, 0.285156f, -0.25415f, 0.238281f, -0.310547f, 0.147949f, -0.332031f,
-0.0249023f, -0.249512f, 0.339355f, -0.675781f, 0.398926f, -0.675781f, 0.398926f,
--0.249512f, 0.459473f, -0.249512f, 0.459473f, -0.148438f, 0.398926f, -0.148438f,
-0.398926f, 0, 0.264648f, 0, 0.264648f, -0.148438f, 0.0249023f, -0.148438f, 0.0722656f,
--0.249512f, 0.264648f, -0.249512f, 0.264648f, -0.510742f, 0.152344f, -0.662109f,
-0.462402f, -0.662109f, 0.413086f, -0.536133f, 0.152344f, -0.536133f, 0.127441f, -0.470215f,
-0.295898f, -0.463867f, 0.386719f, -0.38623f, 0.461426f, -0.322266f, 0.461426f, -0.227051f,
-0.461426f, -0.166016f, 0.426758f, -0.107666f, 0.39209f, -0.0493164f, 0.329102f, -0.0178223f,
-0.266113f, 0.0136719f, 0.190918f, 0.0136719f, 0.109863f, 0.0136719f, 0.0664062f,
--0.0166016f, 0.0361328f, -0.0380859f, 0.0361328f, -0.0654297f, 0.0361328f, -0.0864258f,
-0.052002f, -0.102539f, 0.0678711f, -0.118652f, 0.0888672f, -0.118652f, 0.10791f,
--0.118652f, 0.127441f, -0.11084f, 0.146973f, -0.103027f, 0.194336f, -0.0698242f,
-0.224121f, -0.0493164f, 0.245605f, -0.0415039f, 0.260742f, -0.0356445f, 0.279785f,
--0.0356445f, 0.319824f, -0.0356445f, 0.3479f, -0.0649414f, 0.375977f, -0.0942383f,
-0.375977f, -0.135254f, 0.375977f, -0.221191f, 0.290039f, -0.274902f, 0.204102f, -0.328613f,
-0.0732422f, -0.328613f, 0.0600586f, -0.328613f, 0.0336914f, -0.328125f, 0.469727f,
--0.675781f, 0.469727f, -0.662109f, 0.381348f, -0.639648f, 0.327881f, -0.604248f,
-0.274414f, -0.568848f, 0.243408f, -0.518311f, 0.212402f, -0.467773f, 0.195312f, -0.393066f,
-0.216797f, -0.407715f, 0.230957f, -0.412109f, 0.262695f, -0.421875f, 0.294922f, -0.421875f,
-0.369141f, -0.421875f, 0.418701f, -0.36792f, 0.468262f, -0.313965f, 0.468262f, -0.220703f,
-0.468262f, -0.155273f, 0.441406f, -0.100586f, 0.414551f, -0.0458984f, 0.365234f,
--0.0161133f, 0.315918f, 0.0136719f, 0.259766f, 0.0136719f, 0.19873f, 0.0136719f,
-0.146973f, -0.0197754f, 0.0952148f, -0.0532227f, 0.0661621f, -0.117676f, 0.0371094f,
--0.182129f, 0.0371094f, -0.257812f, 0.0371094f, -0.369141f, 0.0905762f, -0.465088f,
-0.144043f, -0.561035f, 0.242432f, -0.61792f, 0.34082f, -0.674805f, 0.469727f, -0.675781f,
-0.188965f, -0.353516f, 0.185059f, -0.286133f, 0.185059f, -0.254883f, 0.185059f, -0.1875f,
-0.197998f, -0.124512f, 0.210938f, -0.0615234f, 0.233398f, -0.0361328f, 0.249512f,
--0.0180664f, 0.271484f, -0.0180664f, 0.293945f, -0.0180664f, 0.311523f, -0.0441895f,
-0.329102f, -0.0703125f, 0.329102f, -0.150391f, 0.329102f, -0.285156f, 0.296387f,
--0.336426f, 0.275391f, -0.369629f, 0.239746f, -0.369629f, 0.220215f, -0.369629f,
-0.188965f, -0.353516f, 0.177246f, 0.0136719f, 0.357422f, -0.532715f, 0.220215f, -0.532715f,
-0.139648f, -0.532715f, 0.0991211f, -0.511719f, 0.0708008f, -0.49707f, 0.0522461f,
--0.456543f, 0.0336914f, -0.456543f, 0.081543f, -0.662109f, 0.476074f, -0.662109f,
-0.253906f, 0.0136719f, 0.34082f, -0.374023f, 0.410645f, -0.322754f, 0.437744f, -0.278564f,
-0.464844f, -0.234375f, 0.464844f, -0.177246f, 0.464844f, -0.097168f, 0.404541f, -0.041748f,
-0.344238f, 0.0136719f, 0.240723f, 0.0136719f, 0.142578f, 0.0136719f, 0.0888672f,
--0.034668f, 0.0351562f, -0.0830078f, 0.0351562f, -0.152832f, 0.0351562f, -0.206055f,
-0.0661621f, -0.246094f, 0.097168f, -0.286133f, 0.169434f, -0.319336f, 0.0908203f,
--0.379395f, 0.0686035f, -0.41748f, 0.0463867f, -0.455566f, 0.0463867f, -0.505859f,
-0.0463867f, -0.572266f, 0.102783f, -0.622803f, 0.15918f, -0.67334f, 0.257324f, -0.67334f,
-0.352051f, -0.67334f, 0.403076f, -0.628662f, 0.454102f, -0.583984f, 0.454102f, -0.521484f,
-0.454102f, -0.474609f, 0.426514f, -0.438721f, 0.398926f, -0.402832f, 0.34082f, -0.374023f,
-0.303711f, -0.398926f, 0.321777f, -0.42334f, 0.330566f, -0.453613f, 0.339355f, -0.483887f,
-0.339355f, -0.52002f, 0.339355f, -0.583496f, 0.312012f, -0.617188f, 0.291504f, -0.643066f,
-0.255371f, -0.643066f, 0.222656f, -0.643066f, 0.199707f, -0.619385f, 0.176758f, -0.595703f,
-0.176758f, -0.560547f, 0.176758f, -0.524902f, 0.202393f, -0.486572f, 0.228027f, -0.448242f,
-0.303711f, -0.398926f, 0.206055f, -0.295898f, 0.190918f, -0.282227f, 0.18457f, -0.270996f,
-0.174805f, -0.253906f, 0.166992f, -0.221191f, 0.15918f, -0.188477f, 0.15918f, -0.152832f,
-0.15918f, -0.106934f, 0.170898f, -0.0759277f, 0.182617f, -0.0449219f, 0.204346f,
--0.03125f, 0.226074f, -0.0175781f, 0.249023f, -0.0175781f, 0.284668f, -0.0175781f,
-0.309082f, -0.0437012f, 0.333496f, -0.0698242f, 0.333496f, -0.115234f, 0.333496f,
--0.209961f, 0.206055f, -0.295898f, 0.0307617f, 0.0136719f, 0.0307617f, 0, 0.111816f,
--0.0185547f, 0.168213f, -0.0546875f, 0.224609f, -0.0908203f, 0.257568f, -0.144043f,
-0.290527f, -0.197266f, 0.303711f, -0.266602f, 0.273438f, -0.250977f, 0.252197f, -0.244873f,
-0.230957f, -0.23877f, 0.20752f, -0.23877f, 0.132324f, -0.23877f, 0.0822754f, -0.292969f,
-0.0322266f, -0.347168f, 0.0322266f, -0.441406f, 0.0322266f, -0.506836f, 0.0593262f,
--0.561279f, 0.0864258f, -0.615723f, 0.136719f, -0.645752f, 0.187012f, -0.675781f,
-0.241211f, -0.675781f, 0.299316f, -0.675781f, 0.351074f, -0.642578f, 0.402832f, -0.609375f,
-0.433594f, -0.546387f, 0.464355f, -0.483398f, 0.464355f, -0.402832f, 0.464355f, -0.29834f,
-0.414307f, -0.202637f, 0.364258f, -0.106934f, 0.265137f, -0.0490723f, 0.166016f,
-0.00878906f, 0.0307617f, 0.0136719f, 0.311035f, -0.307617f, 0.315918f, -0.362305f,
-0.315918f, -0.403809f, 0.315918f, -0.492676f, 0.29541f, -0.569336f, 0.283691f, -0.611816f,
-0.260742f, -0.631836f, 0.248535f, -0.642578f, 0.229004f, -0.642578f, 0.20459f, -0.642578f,
-0.190918f, -0.621582f, 0.171875f, -0.592773f, 0.171875f, -0.511719f, 0.171875f, -0.376465f,
-0.204102f, -0.325195f, 0.225098f, -0.291992f, 0.260742f, -0.291992f, 0.279785f, -0.291992f,
-0.311035f, -0.307617f, 0.166992f, -0.469727f, 0.200684f, -0.469727f, 0.224365f, -0.446045f,
-0.248047f, -0.422363f, 0.248047f, -0.388672f, 0.248047f, -0.35498f, 0.224365f, -0.331299f,
-0.200684f, -0.307617f, 0.166992f, -0.307617f, 0.133301f, -0.307617f, 0.109619f, -0.331299f,
-0.0859375f, -0.35498f, 0.0859375f, -0.388672f, 0.0859375f, -0.422363f, 0.109619f,
--0.446045f, 0.133301f, -0.469727f, 0.166992f, -0.469727f, 0.166504f, -0.150391f,
-0.200684f, -0.150391f, 0.224365f, -0.126465f, 0.248047f, -0.102539f, 0.248047f, -0.0688477f,
-0.248047f, -0.0351562f, 0.224121f, -0.0114746f, 0.200195f, 0.012207f, 0.166504f,
-0.012207f, 0.132812f, 0.012207f, 0.109131f, -0.0114746f, 0.0854492f, -0.0351562f,
-0.0854492f, -0.0688477f, 0.0854492f, -0.102539f, 0.109131f, -0.126465f, 0.132812f,
--0.150391f, 0.166504f, -0.150391f, 0.166504f, -0.469727f, 0.200195f, -0.469727f,
-0.223633f, -0.446289f, 0.24707f, -0.422852f, 0.24707f, -0.38916f, 0.24707f, -0.355469f,
-0.223389f, -0.331787f, 0.199707f, -0.308105f, 0.166504f, -0.308105f, 0.132812f, -0.308105f,
-0.109131f, -0.331787f, 0.0854492f, -0.355469f, 0.0854492f, -0.38916f, 0.0854492f,
--0.422852f, 0.108887f, -0.446289f, 0.132324f, -0.469727f, 0.166504f, -0.469727f,
-0.0917969f, 0.175293f, 0.0917969f, 0.153809f, 0.148438f, 0.129395f, 0.174072f, 0.0905762f,
-0.199707f, 0.0517578f, 0.199707f, 0.0112305f, 0.199707f, 0.00292969f, 0.196289f,
--0.00146484f, 0.192871f, -0.00537109f, 0.189453f, -0.00537109f, 0.186523f, -0.00537109f,
-0.180664f, -0.00195312f, 0.166504f, 0.00634766f, 0.145508f, 0.00634766f, 0.116699f,
-0.00634766f, 0.095459f, -0.0161133f, 0.0742188f, -0.0385742f, 0.0742188f, -0.0688477f,
-0.0742188f, -0.101074f, 0.0986328f, -0.125488f, 0.123047f, -0.149902f, 0.157715f,
--0.149902f, 0.199707f, -0.149902f, 0.229492f, -0.117432f, 0.259277f, -0.0849609f,
-0.259277f, -0.0283203f, 0.259277f, 0.0415039f, 0.217041f, 0.0957031f, 0.174805f,
-0.149902f, 0.0917969f, 0.175293f, 0.553223f, -0.090332f, 0.0200195f, -0.308105f,
-0.0200195f, -0.347656f, 0.553223f, -0.567871f, 0.553223f, -0.500488f, 0.140625f,
--0.328125f, 0.553223f, -0.158691f, 0.0195312f, -0.441406f, 0.553711f, -0.441406f,
-0.553711f, -0.37793f, 0.0195312f, -0.37793f, 0.0195312f, -0.281738f, 0.553711f, -0.281738f,
-0.553711f, -0.218262f, 0.0195312f, -0.218262f, 0.0200195f, -0.567871f, 0.553223f,
--0.350586f, 0.553223f, -0.310547f, 0.0200195f, -0.090332f, 0.0200195f, -0.158203f,
-0.432617f, -0.330078f, 0.0200195f, -0.499512f, 0.237305f, -0.21582f, 0.217285f, -0.21582f,
-0.216309f, -0.27002f, 0.222412f, -0.296875f, 0.228516f, -0.32373f, 0.25415f, -0.37085f,
-0.279785f, -0.417969f, 0.287842f, -0.446533f, 0.295898f, -0.475098f, 0.295898f, -0.51709f,
-0.295898f, -0.582031f, 0.270508f, -0.612793f, 0.245117f, -0.643555f, 0.210449f, -0.643555f,
-0.184082f, -0.643555f, 0.166016f, -0.629395f, 0.152344f, -0.618652f, 0.152344f, -0.606934f,
-0.152344f, -0.599121f, 0.161621f, -0.58252f, 0.182617f, -0.544922f, 0.182617f, -0.518555f,
-0.182617f, -0.494629f, 0.16626f, -0.478516f, 0.149902f, -0.462402f, 0.125488f, -0.462402f,
-0.0981445f, -0.462402f, 0.0795898f, -0.481689f, 0.0610352f, -0.500977f, 0.0610352f,
--0.532715f, 0.0610352f, -0.590332f, 0.11084f, -0.633789f, 0.160645f, -0.677246f,
-0.25f, -0.677246f, 0.344727f, -0.677246f, 0.394287f, -0.63208f, 0.443848f, -0.586914f,
-0.443848f, -0.522949f, 0.443848f, -0.476562f, 0.418457f, -0.437256f, 0.393066f, -0.397949f,
-0.320312f, -0.350098f, 0.271484f, -0.317871f, 0.256104f, -0.292725f, 0.240723f, -0.267578f,
-0.237305f, -0.21582f, 0.231934f, -0.144531f, 0.264648f, -0.144531f, 0.287598f, -0.121582f,
-0.310547f, -0.0986328f, 0.310547f, -0.065918f, 0.310547f, -0.0332031f, 0.287598f,
--0.0100098f, 0.264648f, 0.0131836f, 0.231934f, 0.0131836f, 0.199219f, 0.0131836f,
-0.17627f, -0.0100098f, 0.15332f, -0.0332031f, 0.15332f, -0.065918f, 0.15332f, -0.0986328f,
-0.17627f, -0.121582f, 0.199219f, -0.144531f, 0.231934f, -0.144531f, 0.575684f, -0.45166f,
-0.694824f, -0.456543f, 0.605469f, -0.149902f, 0.590332f, -0.0991211f, 0.590332f,
--0.0737305f, 0.590332f, -0.0581055f, 0.601807f, -0.0466309f, 0.613281f, -0.0351562f,
-0.629883f, -0.0351562f, 0.663574f, -0.0351562f, 0.717041f, -0.0739746f, 0.770508f,
--0.112793f, 0.80542f, -0.184814f, 0.840332f, -0.256836f, 0.840332f, -0.338379f, 0.840332f,
--0.473145f, 0.753662f, -0.559814f, 0.666992f, -0.646484f, 0.527832f, -0.646484f,
-0.407715f, -0.646484f, 0.30957f, -0.590088f, 0.211426f, -0.533691f, 0.153809f, -0.42627f,
-0.0961914f, -0.318848f, 0.0961914f, -0.195801f, 0.0961914f, -0.0268555f, 0.203857f,
-0.0808105f, 0.311523f, 0.188477f, 0.478027f, 0.188477f, 0.615234f, 0.188477f, 0.724121f,
-0.114746f, 0.833008f, 0.0410156f, 0.878418f, -0.0805664f, 0.908203f, -0.0805664f,
-0.849609f, 0.0629883f, 0.737549f, 0.139404f, 0.625488f, 0.21582f, 0.477051f, 0.21582f,
-0.289062f, 0.21582f, 0.166992f, 0.0944824f, 0.0449219f, -0.0268555f, 0.0449219f,
--0.212891f, 0.0449219f, -0.34082f, 0.105469f, -0.449951f, 0.166016f, -0.559082f,
-0.275391f, -0.618164f, 0.384766f, -0.677246f, 0.517578f, -0.677246f, 0.625488f, -0.677246f,
-0.706299f, -0.634033f, 0.787109f, -0.59082f, 0.827637f, -0.512695f, 0.868164f, -0.43457f,
-0.868164f, -0.347656f, 0.868164f, -0.246582f, 0.824463f, -0.163086f, 0.780762f, -0.0795898f,
-0.715576f, -0.0397949f, 0.650391f, 0, 0.575195f, 0, 0.526855f, 0, 0.501465f, -0.0239258f,
-0.476074f, -0.0478516f, 0.476074f, -0.0854492f, 0.476074f, -0.111816f, 0.487793f,
--0.154297f, 0.447266f, -0.0869141f, 0.424805f, -0.0610352f, 0.394043f, -0.0263672f,
-0.36377f, -0.0102539f, 0.344238f, 0, 0.319336f, 0, 0.284668f, 0, 0.260986f, -0.0275879f,
-0.237305f, -0.0551758f, 0.237305f, -0.108398f, 0.237305f, -0.163086f, 0.253174f,
--0.215576f, 0.269043f, -0.268066f, 0.296387f, -0.314209f, 0.32373f, -0.360352f, 0.359619f,
--0.396973f, 0.395508f, -0.433594f, 0.44043f, -0.45752f, 0.463379f, -0.470215f, 0.489746f,
--0.470215f, 0.51709f, -0.470215f, 0.534912f, -0.453125f, 0.552734f, -0.436035f, 0.559082f,
--0.393555f, 0.501953f, -0.435059f, 0.483398f, -0.435059f, 0.465332f, -0.414551f,
-0.440918f, -0.386719f, 0.413086f, -0.321777f, 0.363281f, -0.205078f, 0.363281f, -0.134277f,
-0.363281f, -0.112793f, 0.372314f, -0.101074f, 0.381348f, -0.0893555f, 0.39209f, -0.0893555f,
-0.401367f, -0.0893555f, 0.418945f, -0.103027f, 0.443848f, -0.12207f, 0.472168f, -0.16748f,
-0.500488f, -0.212891f, 0.518555f, -0.268311f, 0.536621f, -0.32373f, 0.536621f, -0.370605f,
-0.536621f, -0.404297f, 0.523926f, -0.421875f, 0.514648f, -0.435059f, 0.501953f, -0.435059f,
-0.416016f, -0.188477f, 0.182129f, -0.188477f, 0.154297f, -0.124023f, 0.140625f, -0.0917969f,
-0.140625f, -0.0708008f, 0.140625f, -0.0429688f, 0.163086f, -0.0297852f, 0.17627f,
--0.0219727f, 0.228027f, -0.0180664f, 0.228027f, 0, 0.0078125f, 0, 0.0078125f, -0.0180664f,
-0.043457f, -0.0234375f, 0.0664062f, -0.0476074f, 0.0893555f, -0.0717773f, 0.123047f,
--0.147461f, 0.359863f, -0.675781f, 0.369141f, -0.675781f, 0.60791f, -0.132812f, 0.64209f,
--0.0556641f, 0.664062f, -0.0356445f, 0.680664f, -0.0205078f, 0.710938f, -0.0180664f,
-0.710938f, 0, 0.390625f, 0, 0.390625f, -0.0180664f, 0.403809f, -0.0180664f, 0.442383f,
--0.0180664f, 0.458008f, -0.0288086f, 0.46875f, -0.0366211f, 0.46875f, -0.0512695f,
-0.46875f, -0.0600586f, 0.46582f, -0.0693359f, 0.464844f, -0.0737305f, 0.451172f,
--0.105957f, 0.399414f, -0.224609f, 0.300781f, -0.452637f, 0.199219f, -0.224609f,
-0.444824f, -0.351074f, 0.539062f, -0.329102f, 0.577148f, -0.297852f, 0.631836f, -0.253418f,
-0.631836f, -0.182617f, 0.631836f, -0.10791f, 0.571777f, -0.059082f, 0.498047f, 0,
-0.357422f, 0, 0.0209961f, 0, 0.0209961f, -0.0180664f, 0.0668945f, -0.0180664f, 0.083252f,
--0.0266113f, 0.0996094f, -0.0351562f, 0.106201f, -0.0488281f, 0.112793f, -0.0625f,
-0.112793f, -0.116211f, 0.112793f, -0.545898f, 0.112793f, -0.599609f, 0.106201f, -0.613525f,
-0.0996094f, -0.627441f, 0.0830078f, -0.635742f, 0.0664062f, -0.644043f, 0.0209961f,
--0.644043f, 0.0209961f, -0.662109f, 0.338379f, -0.662109f, 0.452148f, -0.662109f,
-0.499512f, -0.641846f, 0.546875f, -0.621582f, 0.574219f, -0.581299f, 0.601562f, -0.541016f,
-0.601562f, -0.495605f, 0.601562f, -0.447754f, 0.566895f, -0.4104f, 0.532227f, -0.373047f,
-0.444824f, -0.351074f, 0.26709f, -0.364258f, 0.336426f, -0.364258f, 0.369385f, -0.379883f,
-0.402344f, -0.395508f, 0.419922f, -0.423828f, 0.4375f, -0.452148f, 0.4375f, -0.496094f,
-0.4375f, -0.540039f, 0.420166f, -0.568115f, 0.402832f, -0.596191f, 0.370605f, -0.61084f,
-0.338379f, -0.625488f, 0.26709f, -0.625f, 0.26709f, -0.326172f, 0.26709f, -0.11377f,
-0.266602f, -0.0893555f, 0.266602f, -0.0629883f, 0.280029f, -0.0495605f, 0.293457f,
--0.0361328f, 0.319824f, -0.0361328f, 0.358887f, -0.0361328f, 0.391846f, -0.0534668f,
-0.424805f, -0.0708008f, 0.442383f, -0.10376f, 0.459961f, -0.136719f, 0.459961f, -0.177246f,
-0.459961f, -0.223633f, 0.438477f, -0.260498f, 0.416992f, -0.297363f, 0.379395f, -0.312012f,
-0.341797f, -0.32666f, 0.26709f, -0.326172f, 0.66748f, -0.677246f, 0.66748f, -0.447754f,
-0.648438f, -0.447754f, 0.626953f, -0.537598f, 0.568359f, -0.585449f, 0.509766f, -0.633301f,
-0.435547f, -0.633301f, 0.373535f, -0.633301f, 0.321777f, -0.597656f, 0.27002f, -0.562012f,
-0.246094f, -0.504395f, 0.215332f, -0.430664f, 0.215332f, -0.340332f, 0.215332f, -0.251465f,
-0.237793f, -0.178467f, 0.260254f, -0.105469f, 0.308105f, -0.0681152f, 0.355957f,
--0.0307617f, 0.432129f, -0.0307617f, 0.494629f, -0.0307617f, 0.546631f, -0.0581055f,
-0.598633f, -0.0854492f, 0.65625f, -0.152344f, 0.65625f, -0.0952148f, 0.600586f, -0.0371094f,
-0.540283f, -0.0109863f, 0.47998f, 0.0151367f, 0.399414f, 0.0151367f, 0.293457f, 0.0151367f,
-0.211182f, -0.0273438f, 0.128906f, -0.0698242f, 0.0842285f, -0.149414f, 0.0395508f,
--0.229004f, 0.0395508f, -0.318848f, 0.0395508f, -0.413574f, 0.0891113f, -0.498535f,
-0.138672f, -0.583496f, 0.2229f, -0.630371f, 0.307129f, -0.677246f, 0.401855f, -0.677246f,
-0.47168f, -0.677246f, 0.549316f, -0.646973f, 0.594238f, -0.629395f, 0.606445f, -0.629395f,
-0.62207f, -0.629395f, 0.633545f, -0.640869f, 0.64502f, -0.652344f, 0.648438f, -0.677246f,
-0.0131836f, 0, 0.0131836f, -0.0180664f, 0.0351562f, -0.0180664f, 0.0639648f, -0.0180664f,
-0.0793457f, -0.0270996f, 0.0947266f, -0.0361328f, 0.102051f, -0.0517578f, 0.106445f,
--0.0620117f, 0.106445f, -0.113281f, 0.106445f, -0.548828f, 0.106445f, -0.599609f,
-0.101074f, -0.612305f, 0.0957031f, -0.625f, 0.0793457f, -0.634521f, 0.0629883f, -0.644043f,
-0.0351562f, -0.644043f, 0.0131836f, -0.644043f, 0.0131836f, -0.662109f, 0.30957f,
--0.662109f, 0.428223f, -0.662109f, 0.500488f, -0.629883f, 0.588867f, -0.590332f,
-0.634521f, -0.510254f, 0.680176f, -0.430176f, 0.680176f, -0.329102f, 0.680176f, -0.259277f,
-0.657715f, -0.200439f, 0.635254f, -0.141602f, 0.599609f, -0.103271f, 0.563965f, -0.0649414f,
-0.517334f, -0.041748f, 0.470703f, -0.0185547f, 0.40332f, -0.00585938f, 0.373535f,
-0, 0.30957f, 0, 0.265625f, -0.624512f, 0.265625f, -0.10791f, 0.265625f, -0.0668945f,
-0.269531f, -0.0576172f, 0.273438f, -0.0483398f, 0.282715f, -0.043457f, 0.295898f,
--0.0361328f, 0.320801f, -0.0361328f, 0.402344f, -0.0361328f, 0.445312f, -0.0917969f,
-0.503906f, -0.166992f, 0.503906f, -0.325195f, 0.503906f, -0.452637f, 0.463867f, -0.528809f,
-0.432129f, -0.588379f, 0.382324f, -0.609863f, 0.347168f, -0.625f, 0.265625f, -0.624512f,
-0.272461f, -0.624023f, 0.272461f, -0.354492f, 0.285645f, -0.354492f, 0.348633f, -0.354492f,
-0.376953f, -0.394043f, 0.405273f, -0.433594f, 0.413086f, -0.510742f, 0.431641f, -0.510742f,
-0.431641f, -0.164062f, 0.413086f, -0.164062f, 0.407227f, -0.220703f, 0.388428f, -0.256836f,
-0.369629f, -0.292969f, 0.344727f, -0.30542f, 0.319824f, -0.317871f, 0.272461f, -0.317871f,
-0.272461f, -0.131348f, 0.272461f, -0.0766602f, 0.2771f, -0.0644531f, 0.281738f, -0.0522461f,
-0.294434f, -0.0444336f, 0.307129f, -0.0366211f, 0.335449f, -0.0366211f, 0.375f, -0.0366211f,
-0.467773f, -0.0366211f, 0.523682f, -0.0795898f, 0.57959f, -0.122559f, 0.604004f,
--0.210449f, 0.62207f, -0.210449f, 0.592285f, 0, 0.0200195f, 0, 0.0200195f, -0.0180664f,
-0.0419922f, -0.0180664f, 0.0708008f, -0.0180664f, 0.0883789f, -0.0283203f, 0.101074f,
--0.0351562f, 0.10791f, -0.0517578f, 0.113281f, -0.0634766f, 0.113281f, -0.113281f,
-0.113281f, -0.548828f, 0.113281f, -0.59375f, 0.11084f, -0.604004f, 0.105957f, -0.621094f,
-0.0927734f, -0.630371f, 0.0742188f, -0.644043f, 0.0419922f, -0.644043f, 0.0200195f,
--0.644043f, 0.0200195f, -0.662109f, 0.574219f, -0.662109f, 0.574219f, -0.466309f,
-0.555664f, -0.466309f, 0.541504f, -0.538086f, 0.515869f, -0.569336f, 0.490234f, -0.600586f,
-0.443359f, -0.615234f, 0.416016f, -0.624023f, 0.34082f, -0.624023f, 0.274902f, -0.624023f,
-0.274902f, -0.352051f, 0.293945f, -0.352051f, 0.337891f, -0.352051f, 0.365723f, -0.365234f,
-0.393555f, -0.378418f, 0.412842f, -0.409668f, 0.432129f, -0.440918f, 0.437988f, -0.494141f,
-0.455078f, -0.494141f, 0.455078f, -0.161621f, 0.437988f, -0.161621f, 0.428711f, -0.255859f,
-0.387451f, -0.285889f, 0.346191f, -0.315918f, 0.293945f, -0.315918f, 0.274902f, -0.315918f,
-0.274902f, -0.113281f, 0.274902f, -0.0625f, 0.280518f, -0.0498047f, 0.286133f, -0.0371094f,
-0.30249f, -0.0275879f, 0.318848f, -0.0180664f, 0.34668f, -0.0180664f, 0.368652f,
--0.0180664f, 0.368652f, 0, 0.0224609f, 0, 0.0224609f, -0.0180664f, 0.0444336f, -0.0180664f,
-0.0732422f, -0.0180664f, 0.0908203f, -0.0283203f, 0.103516f, -0.0351562f, 0.110352f,
--0.0517578f, 0.115723f, -0.0634766f, 0.115723f, -0.113281f, 0.115723f, -0.548828f,
-0.115723f, -0.599609f, 0.110352f, -0.612305f, 0.10498f, -0.625f, 0.088623f, -0.634521f,
-0.0722656f, -0.644043f, 0.0444336f, -0.644043f, 0.0224609f, -0.644043f, 0.0224609f,
--0.662109f, 0.581055f, -0.662109f, 0.581055f, -0.472168f, 0.561035f, -0.472168f,
-0.554199f, -0.539062f, 0.526123f, -0.571289f, 0.498047f, -0.603516f, 0.444824f, -0.616699f,
-0.415527f, -0.624023f, 0.336426f, -0.624023f, 0.689941f, -0.677246f, 0.689941f, -0.443848f,
-0.671875f, -0.443848f, 0.63916f, -0.539551f, 0.57373f, -0.589355f, 0.508301f, -0.63916f,
-0.430664f, -0.63916f, 0.356445f, -0.63916f, 0.307129f, -0.597412f, 0.257812f, -0.555664f,
-0.237305f, -0.480957f, 0.216797f, -0.40625f, 0.216797f, -0.327637f, 0.216797f, -0.232422f,
-0.239258f, -0.160645f, 0.261719f, -0.0888672f, 0.311768f, -0.0551758f, 0.361816f,
--0.0214844f, 0.430664f, -0.0214844f, 0.45459f, -0.0214844f, 0.479736f, -0.0266113f,
-0.504883f, -0.0317383f, 0.53125f, -0.0415039f, 0.53125f, -0.179199f, 0.53125f, -0.218262f,
-0.525879f, -0.229736f, 0.520508f, -0.241211f, 0.503662f, -0.250488f, 0.486816f, -0.259766f,
-0.462891f, -0.259766f, 0.445801f, -0.259766f, 0.445801f, -0.277832f, 0.767578f, -0.277832f,
-0.767578f, -0.259766f, 0.730957f, -0.257324f, 0.716553f, -0.249756f, 0.702148f, -0.242188f,
-0.694336f, -0.224609f, 0.689941f, -0.215332f, 0.689941f, -0.179199f, 0.689941f, -0.0415039f,
-0.626465f, -0.0131836f, 0.557861f, 0.0012207f, 0.489258f, 0.015625f, 0.415527f, 0.015625f,
-0.321289f, 0.015625f, 0.259033f, -0.0100098f, 0.196777f, -0.0356445f, 0.14917f, -0.0773926f,
-0.101562f, -0.119141f, 0.074707f, -0.171387f, 0.0405273f, -0.23877f, 0.0405273f,
--0.322266f, 0.0405273f, -0.47168f, 0.145508f, -0.574707f, 0.250488f, -0.677734f,
-0.409668f, -0.677734f, 0.458984f, -0.677734f, 0.498535f, -0.669922f, 0.52002f, -0.666016f,
-0.568115f, -0.647705f, 0.616211f, -0.629395f, 0.625f, -0.629395f, 0.638672f, -0.629395f,
-0.650391f, -0.639404f, 0.662109f, -0.649414f, 0.671875f, -0.677246f, 0.273438f, -0.318359f,
-0.273438f, -0.113281f, 0.273438f, -0.0625f, 0.279053f, -0.0498047f, 0.284668f, -0.0371094f,
-0.301025f, -0.0275879f, 0.317383f, -0.0180664f, 0.345215f, -0.0180664f, 0.367188f,
--0.0180664f, 0.367188f, 0, 0.0209961f, 0, 0.0209961f, -0.0180664f, 0.0429688f, -0.0180664f,
-0.0717773f, -0.0180664f, 0.0893555f, -0.0283203f, 0.102051f, -0.0351562f, 0.108887f,
--0.0517578f, 0.114258f, -0.0634766f, 0.114258f, -0.113281f, 0.114258f, -0.548828f,
-0.114258f, -0.599609f, 0.108887f, -0.612305f, 0.103516f, -0.625f, 0.0871582f, -0.634521f,
-0.0708008f, -0.644043f, 0.0429688f, -0.644043f, 0.0209961f, -0.644043f, 0.0209961f,
--0.662109f, 0.367188f, -0.662109f, 0.367188f, -0.644043f, 0.345215f, -0.644043f,
-0.316406f, -0.644043f, 0.298828f, -0.633789f, 0.286133f, -0.626953f, 0.278809f, -0.610352f,
-0.273438f, -0.598633f, 0.273438f, -0.548828f, 0.273438f, -0.361328f, 0.507324f, -0.361328f,
-0.507324f, -0.548828f, 0.507324f, -0.599609f, 0.501953f, -0.612305f, 0.496582f, -0.625f,
-0.47998f, -0.634521f, 0.463379f, -0.644043f, 0.435547f, -0.644043f, 0.414062f, -0.644043f,
-0.414062f, -0.662109f, 0.759766f, -0.662109f, 0.759766f, -0.644043f, 0.738281f, -0.644043f,
-0.708984f, -0.644043f, 0.691895f, -0.633789f, 0.679199f, -0.626953f, 0.671875f, -0.610352f,
-0.666504f, -0.598633f, 0.666504f, -0.548828f, 0.666504f, -0.113281f, 0.666504f, -0.0625f,
-0.671875f, -0.0498047f, 0.677246f, -0.0371094f, 0.693848f, -0.0275879f, 0.710449f,
--0.0180664f, 0.738281f, -0.0180664f, 0.759766f, -0.0180664f, 0.759766f, 0, 0.414062f,
-0, 0.414062f, -0.0180664f, 0.435547f, -0.0180664f, 0.464844f, -0.0180664f, 0.481934f,
--0.0283203f, 0.494629f, -0.0351562f, 0.501953f, -0.0517578f, 0.507324f, -0.0634766f,
-0.507324f, -0.113281f, 0.507324f, -0.318359f, 0.366211f, -0.0180664f, 0.366211f,
-0, 0.0200195f, 0, 0.0200195f, -0.0180664f, 0.0419922f, -0.0180664f, 0.0708008f, -0.0180664f,
-0.0883789f, -0.0283203f, 0.101074f, -0.0351562f, 0.10791f, -0.0517578f, 0.113281f,
--0.0634766f, 0.113281f, -0.113281f, 0.113281f, -0.548828f, 0.113281f, -0.599609f,
-0.10791f, -0.612305f, 0.102539f, -0.625f, 0.0861816f, -0.634521f, 0.0698242f, -0.644043f,
-0.0419922f, -0.644043f, 0.0200195f, -0.644043f, 0.0200195f, -0.662109f, 0.366211f,
--0.662109f, 0.366211f, -0.644043f, 0.344238f, -0.644043f, 0.31543f, -0.644043f, 0.297852f,
--0.633789f, 0.285156f, -0.626953f, 0.277832f, -0.610352f, 0.272461f, -0.598633f,
-0.272461f, -0.548828f, 0.272461f, -0.113281f, 0.272461f, -0.0625f, 0.278076f, -0.0498047f,
-0.283691f, -0.0371094f, 0.300049f, -0.0275879f, 0.316406f, -0.0180664f, 0.344238f,
--0.0180664f, 0.14209f, -0.644043f, 0.14209f, -0.662109f, 0.494141f, -0.662109f, 0.494141f,
--0.644043f, 0.472656f, -0.644043f, 0.443359f, -0.644043f, 0.425781f, -0.633789f,
-0.413574f, -0.626953f, 0.40625f, -0.610352f, 0.400879f, -0.598633f, 0.400879f, -0.548828f,
-0.400879f, -0.224609f, 0.400879f, -0.129395f, 0.381836f, -0.0861816f, 0.362793f,
--0.0429688f, 0.314209f, -0.013916f, 0.265625f, 0.0151367f, 0.197266f, 0.0151367f,
-0.11377f, 0.0151367f, 0.0622559f, -0.0288086f, 0.0107422f, -0.0727539f, 0.0107422f,
--0.125977f, 0.0107422f, -0.160156f, 0.0317383f, -0.181396f, 0.0527344f, -0.202637f,
-0.0830078f, -0.202637f, 0.112793f, -0.202637f, 0.133057f, -0.183594f, 0.15332f, -0.164551f,
-0.15332f, -0.136719f, 0.15332f, -0.123047f, 0.149902f, -0.112793f, 0.147949f, -0.10791f,
-0.134521f, -0.0881348f, 0.121094f, -0.0683594f, 0.121094f, -0.0600586f, 0.121094f,
--0.0473633f, 0.133789f, -0.0380859f, 0.152344f, -0.0244141f, 0.182129f, -0.0244141f,
-0.203125f, -0.0244141f, 0.216797f, -0.0351562f, 0.230469f, -0.0458984f, 0.236084f,
--0.0686035f, 0.241699f, -0.0913086f, 0.241699f, -0.194824f, 0.241699f, -0.548828f,
-0.241699f, -0.599609f, 0.236084f, -0.612305f, 0.230469f, -0.625f, 0.214111f, -0.634521f,
-0.197754f, -0.644043f, 0.169922f, -0.644043f, 0.416504f, -0.408691f, 0.649414f, -0.117188f,
-0.69873f, -0.0556641f, 0.734375f, -0.0336914f, 0.760254f, -0.0180664f, 0.789062f,
--0.0180664f, 0.789062f, 0, 0.444336f, 0, 0.444336f, -0.0180664f, 0.477051f, -0.0209961f,
-0.486572f, -0.0283203f, 0.496094f, -0.0356445f, 0.496094f, -0.0463867f, 0.496094f,
--0.0668945f, 0.451172f, -0.123535f, 0.299316f, -0.314453f, 0.274902f, -0.293945f,
-0.274902f, -0.113281f, 0.274902f, -0.0615234f, 0.280762f, -0.0488281f, 0.286621f,
--0.0361328f, 0.303223f, -0.0270996f, 0.319824f, -0.0180664f, 0.356445f, -0.0180664f,
-0.356445f, 0, 0.0224609f, 0, 0.0224609f, -0.0180664f, 0.0444336f, -0.0180664f, 0.0732422f,
--0.0180664f, 0.0908203f, -0.0283203f, 0.103516f, -0.0351562f, 0.110352f, -0.0517578f,
-0.115723f, -0.0634766f, 0.115723f, -0.113281f, 0.115723f, -0.548828f, 0.115723f,
--0.599609f, 0.110352f, -0.612305f, 0.10498f, -0.625f, 0.088623f, -0.634521f, 0.0722656f,
--0.644043f, 0.0444336f, -0.644043f, 0.0224609f, -0.644043f, 0.0224609f, -0.662109f,
-0.352051f, -0.662109f, 0.352051f, -0.644043f, 0.318359f, -0.644043f, 0.300781f, -0.634277f,
-0.288086f, -0.627441f, 0.280762f, -0.611328f, 0.274902f, -0.599121f, 0.274902f, -0.548828f,
-0.274902f, -0.342773f, 0.520508f, -0.541504f, 0.571777f, -0.583008f, 0.571777f, -0.60791f,
-0.571777f, -0.626465f, 0.550781f, -0.637207f, 0.540039f, -0.642578f, 0.497559f, -0.644043f,
-0.497559f, -0.662109f, 0.755859f, -0.662109f, 0.755859f, -0.644043f, 0.721191f, -0.641602f,
-0.701416f, -0.631592f, 0.681641f, -0.621582f, 0.610352f, -0.563965f, 0.631348f, -0.232422f,
-0.606445f, 0, 0.0185547f, 0, 0.0185547f, -0.0180664f, 0.0405273f, -0.0180664f, 0.0693359f,
--0.0180664f, 0.0869141f, -0.0283203f, 0.0996094f, -0.0351562f, 0.106445f, -0.0517578f,
-0.111816f, -0.0634766f, 0.111816f, -0.113281f, 0.111816f, -0.548828f, 0.111816f,
--0.599609f, 0.106445f, -0.612305f, 0.101074f, -0.625f, 0.0847168f, -0.634521f, 0.0683594f,
--0.644043f, 0.0405273f, -0.644043f, 0.0185547f, -0.644043f, 0.0185547f, -0.662109f,
-0.371582f, -0.662109f, 0.371582f, -0.644043f, 0.342773f, -0.644043f, 0.313965f, -0.644043f,
-0.296387f, -0.633789f, 0.283691f, -0.626953f, 0.276367f, -0.610352f, 0.270996f, -0.598633f,
-0.270996f, -0.548828f, 0.270996f, -0.126953f, 0.270996f, -0.0761719f, 0.276855f,
--0.0622559f, 0.282715f, -0.0483398f, 0.299805f, -0.0415039f, 0.312012f, -0.0371094f,
-0.358887f, -0.0371094f, 0.414062f, -0.0371094f, 0.466797f, -0.0371094f, 0.501953f,
--0.0556641f, 0.537109f, -0.0742188f, 0.562744f, -0.114258f, 0.588379f, -0.154297f,
-0.611328f, -0.232422f, 0.476562f, -0.225586f, 0.65625f, -0.662109f, 0.925781f, -0.662109f,
-0.925781f, -0.644043f, 0.904297f, -0.644043f, 0.875f, -0.644043f, 0.857422f, -0.633789f,
-0.845215f, -0.626953f, 0.837891f, -0.61084f, 0.83252f, -0.599121f, 0.83252f, -0.549805f,
-0.83252f, -0.113281f, 0.83252f, -0.0625f, 0.837891f, -0.0498047f, 0.843262f, -0.0371094f,
-0.859863f, -0.0275879f, 0.876465f, -0.0180664f, 0.904297f, -0.0180664f, 0.925781f,
--0.0180664f, 0.925781f, 0, 0.580078f, 0, 0.580078f, -0.0180664f, 0.601562f, -0.0180664f,
-0.630859f, -0.0180664f, 0.648438f, -0.0283203f, 0.660645f, -0.0351562f, 0.667969f,
--0.0517578f, 0.67334f, -0.0634766f, 0.67334f, -0.113281f, 0.67334f, -0.604004f, 0.419434f,
-0, 0.407715f, 0, 0.149902f, -0.599609f, 0.149902f, -0.133301f, 0.149902f, -0.0844727f,
-0.152344f, -0.0732422f, 0.158691f, -0.0488281f, 0.179932f, -0.0334473f, 0.201172f,
--0.0180664f, 0.246582f, -0.0180664f, 0.246582f, 0, 0.0200195f, 0, 0.0200195f, -0.0180664f,
-0.0268555f, -0.0180664f, 0.0488281f, -0.0175781f, 0.0678711f, -0.0251465f, 0.0869141f,
--0.0327148f, 0.0966797f, -0.0454102f, 0.106445f, -0.0581055f, 0.111816f, -0.0810547f,
-0.112793f, -0.0864258f, 0.112793f, -0.130859f, 0.112793f, -0.549805f, 0.112793f,
--0.600098f, 0.107422f, -0.612549f, 0.102051f, -0.625f, 0.0854492f, -0.634521f, 0.0688477f,
--0.644043f, 0.0410156f, -0.644043f, 0.0200195f, -0.644043f, 0.0200195f, -0.662109f,
-0.290527f, -0.662109f, 0.249023f, -0.662109f, 0.575684f, -0.251465f, 0.575684f, -0.536133f,
-0.575684f, -0.595703f, 0.558594f, -0.616699f, 0.535156f, -0.64502f, 0.47998f, -0.644043f,
-0.47998f, -0.662109f, 0.69873f, -0.662109f, 0.69873f, -0.644043f, 0.656738f, -0.638672f,
-0.642334f, -0.630127f, 0.62793f, -0.621582f, 0.619873f, -0.602295f, 0.611816f, -0.583008f,
-0.611816f, -0.536133f, 0.611816f, 0.0151367f, 0.595215f, 0.0151367f, 0.147461f, -0.536133f,
-0.147461f, -0.115234f, 0.147461f, -0.0581055f, 0.173584f, -0.0380859f, 0.199707f,
--0.0180664f, 0.233398f, -0.0180664f, 0.249023f, -0.0180664f, 0.249023f, 0, 0.0141602f,
-0, 0.0141602f, -0.0180664f, 0.0688477f, -0.0185547f, 0.090332f, -0.0405273f, 0.111816f,
--0.0625f, 0.111816f, -0.115234f, 0.111816f, -0.58252f, 0.0976562f, -0.600098f, 0.0766602f,
--0.626465f, 0.0605469f, -0.634766f, 0.0444336f, -0.643066f, 0.0141602f, -0.644043f,
-0.0141602f, -0.662109f, 0.38623f, -0.671387f, 0.544434f, -0.677246f, 0.643311f, -0.579102f,
-0.742188f, -0.480957f, 0.742188f, -0.333496f, 0.742188f, -0.20752f, 0.668457f, -0.111816f,
-0.570801f, 0.0151367f, 0.392578f, 0.0151367f, 0.213867f, 0.0151367f, 0.116211f, -0.105957f,
-0.0390625f, -0.20166f, 0.0390625f, -0.333008f, 0.0390625f, -0.480469f, 0.139404f,
--0.578857f, 0.239746f, -0.677246f, 0.38623f, -0.671387f, 0.39209f, -0.640137f, 0.30127f,
--0.640137f, 0.253906f, -0.547363f, 0.215332f, -0.471191f, 0.215332f, -0.328613f,
-0.215332f, -0.15918f, 0.274902f, -0.078125f, 0.316406f, -0.0214844f, 0.391113f, -0.0214844f,
-0.441406f, -0.0214844f, 0.475098f, -0.0458984f, 0.518066f, -0.0771484f, 0.541992f,
--0.145752f, 0.565918f, -0.214355f, 0.565918f, -0.324707f, 0.565918f, -0.456055f,
-0.541504f, -0.52124f, 0.51709f, -0.586426f, 0.479248f, -0.613281f, 0.441406f, -0.640137f,
-0.39209f, -0.640137f, 0.27002f, -0.299805f, 0.27002f, -0.116211f, 0.27002f, -0.0625f,
-0.276611f, -0.048584f, 0.283203f, -0.034668f, 0.300049f, -0.0263672f, 0.316895f,
--0.0180664f, 0.361816f, -0.0180664f, 0.361816f, 0, 0.0253906f, 0, 0.0253906f, -0.0180664f,
-0.0712891f, -0.0180664f, 0.0876465f, -0.0266113f, 0.104004f, -0.0351562f, 0.110596f,
--0.0488281f, 0.117188f, -0.0625f, 0.117188f, -0.116211f, 0.117188f, -0.545898f, 0.117188f,
--0.599609f, 0.110596f, -0.613525f, 0.104004f, -0.627441f, 0.0874023f, -0.635742f,
-0.0708008f, -0.644043f, 0.0253906f, -0.644043f, 0.0253906f, -0.662109f, 0.313965f,
--0.662109f, 0.456543f, -0.662109f, 0.518555f, -0.611328f, 0.580566f, -0.560547f,
-0.580566f, -0.484375f, 0.580566f, -0.419922f, 0.540527f, -0.374023f, 0.500488f, -0.328125f,
-0.430176f, -0.311523f, 0.382812f, -0.299805f, 0.27002f, -0.299805f, 0.27002f, -0.624023f,
-0.27002f, -0.337891f, 0.286133f, -0.336914f, 0.294434f, -0.336914f, 0.354004f, -0.336914f,
-0.38623f, -0.372314f, 0.418457f, -0.407715f, 0.418457f, -0.481934f, 0.418457f, -0.555664f,
-0.38623f, -0.589844f, 0.354004f, -0.624023f, 0.290039f, -0.624023f, 0.478027f, 0.00585938f,
-0.500488f, 0.0708008f, 0.547852f, 0.103516f, 0.595215f, 0.13623f, 0.666504f, 0.13623f,
-0.686035f, 0.13623f, 0.708008f, 0.132324f, 0.708008f, 0.162109f, 0.634277f, 0.180664f,
-0.576172f, 0.180664f, 0.485352f, 0.180664f, 0.413818f, 0.13623f, 0.342285f, 0.0917969f,
-0.306152f, 0.00585938f, 0.186035f, -0.0195312f, 0.112549f, -0.111816f, 0.0390625f,
--0.204102f, 0.0390625f, -0.332031f, 0.0390625f, -0.480469f, 0.138672f, -0.578857f,
-0.238281f, -0.677246f, 0.391602f, -0.677246f, 0.544434f, -0.677246f, 0.643555f, -0.578613f,
-0.742676f, -0.47998f, 0.742676f, -0.332031f, 0.742676f, -0.203125f, 0.665039f, -0.10791f,
-0.587402f, -0.0126953f, 0.478027f, 0.00585938f, 0.391113f, -0.640137f, 0.303223f,
--0.640137f, 0.255371f, -0.548828f, 0.215332f, -0.472168f, 0.215332f, -0.330566f,
-0.215332f, -0.160645f, 0.275391f, -0.0786133f, 0.317383f, -0.0214844f, 0.391113f,
--0.0214844f, 0.465332f, -0.0214844f, 0.506836f, -0.0776367f, 0.566895f, -0.158203f,
-0.566895f, -0.319824f, 0.566895f, -0.479004f, 0.529297f, -0.550293f, 0.482422f, -0.640137f,
-0.391113f, -0.640137f, 0.265625f, -0.301758f, 0.265625f, -0.116211f, 0.265625f, -0.0625f,
-0.272217f, -0.048584f, 0.278809f, -0.034668f, 0.29541f, -0.0263672f, 0.312012f, -0.0180664f,
-0.357422f, -0.0180664f, 0.357422f, 0, 0.0185547f, 0, 0.0185547f, -0.0180664f, 0.0644531f,
--0.0180664f, 0.0808105f, -0.0266113f, 0.097168f, -0.0351562f, 0.10376f, -0.0488281f,
-0.110352f, -0.0625f, 0.110352f, -0.116211f, 0.110352f, -0.545898f, 0.110352f, -0.599609f,
-0.10376f, -0.613525f, 0.097168f, -0.627441f, 0.0805664f, -0.635742f, 0.0639648f,
--0.644043f, 0.0185547f, -0.644043f, 0.0185547f, -0.662109f, 0.326172f, -0.662109f,
-0.446289f, -0.662109f, 0.501953f, -0.645508f, 0.557617f, -0.628906f, 0.592773f, -0.584229f,
-0.62793f, -0.539551f, 0.62793f, -0.479492f, 0.62793f, -0.40625f, 0.575195f, -0.358398f,
-0.541504f, -0.328125f, 0.480957f, -0.312988f, 0.640137f, -0.0888672f, 0.671387f,
--0.0454102f, 0.68457f, -0.034668f, 0.70459f, -0.0195312f, 0.730957f, -0.0180664f,
-0.730957f, 0, 0.522461f, 0, 0.309082f, -0.301758f, 0.265625f, -0.626465f, 0.265625f,
--0.336426f, 0.293457f, -0.336426f, 0.361328f, -0.336426f, 0.39502f, -0.348877f, 0.428711f,
--0.361328f, 0.447998f, -0.393799f, 0.467285f, -0.42627f, 0.467285f, -0.478516f, 0.467285f,
--0.554199f, 0.431885f, -0.590332f, 0.396484f, -0.626465f, 0.317871f, -0.626465f,
-0.469727f, -0.677246f, 0.475098f, -0.456543f, 0.455078f, -0.456543f, 0.440918f, -0.539551f,
-0.385498f, -0.590088f, 0.330078f, -0.640625f, 0.265625f, -0.640625f, 0.21582f, -0.640625f,
-0.186768f, -0.614014f, 0.157715f, -0.587402f, 0.157715f, -0.552734f, 0.157715f, -0.530762f,
-0.167969f, -0.513672f, 0.182129f, -0.490723f, 0.213379f, -0.468262f, 0.236328f, -0.452148f,
-0.319336f, -0.411133f, 0.435547f, -0.354004f, 0.476074f, -0.303223f, 0.516113f, -0.252441f,
-0.516113f, -0.187012f, 0.516113f, -0.104004f, 0.451416f, -0.0441895f, 0.386719f,
-0.015625f, 0.287109f, 0.015625f, 0.255859f, 0.015625f, 0.228027f, 0.00927734f, 0.200195f,
-0.00292969f, 0.158203f, -0.0146484f, 0.134766f, -0.0244141f, 0.119629f, -0.0244141f,
-0.106934f, -0.0244141f, 0.0927734f, -0.0146484f, 0.0786133f, -0.00488281f, 0.0698242f,
-0.0151367f, 0.0517578f, 0.0151367f, 0.0517578f, -0.234863f, 0.0698242f, -0.234863f,
-0.0913086f, -0.129395f, 0.152588f, -0.0739746f, 0.213867f, -0.0185547f, 0.284668f,
--0.0185547f, 0.339355f, -0.0185547f, 0.371826f, -0.0483398f, 0.404297f, -0.078125f,
-0.404297f, -0.117676f, 0.404297f, -0.141113f, 0.391846f, -0.163086f, 0.379395f, -0.185059f,
-0.354004f, -0.204834f, 0.328613f, -0.224609f, 0.26416f, -0.256348f, 0.173828f, -0.300781f,
-0.134277f, -0.332031f, 0.0947266f, -0.363281f, 0.0734863f, -0.401855f, 0.0522461f,
--0.44043f, 0.0522461f, -0.486816f, 0.0522461f, -0.565918f, 0.110352f, -0.621582f,
-0.168457f, -0.677246f, 0.256836f, -0.677246f, 0.289062f, -0.677246f, 0.319336f, -0.669434f,
-0.342285f, -0.663574f, 0.375244f, -0.647705f, 0.408203f, -0.631836f, 0.421387f, -0.631836f,
-0.434082f, -0.631836f, 0.441406f, -0.639648f, 0.44873f, -0.647461f, 0.455078f, -0.677246f,
-0.630859f, -0.662109f, 0.630859f, -0.48291f, 0.613281f, -0.48291f, 0.597656f, -0.544922f,
-0.578613f, -0.572021f, 0.55957f, -0.599121f, 0.526367f, -0.615234f, 0.507812f, -0.624023f,
-0.461426f, -0.624023f, 0.412109f, -0.624023f, 0.412109f, -0.113281f, 0.412109f, -0.0625f,
-0.417725f, -0.0498047f, 0.42334f, -0.0371094f, 0.439697f, -0.0275879f, 0.456055f,
--0.0180664f, 0.484375f, -0.0180664f, 0.506348f, -0.0180664f, 0.506348f, 0, 0.159668f,
-0, 0.159668f, -0.0180664f, 0.181641f, -0.0180664f, 0.210449f, -0.0180664f, 0.228027f,
--0.0283203f, 0.240723f, -0.0351562f, 0.248047f, -0.0517578f, 0.253418f, -0.0634766f,
-0.253418f, -0.113281f, 0.253418f, -0.624023f, 0.205566f, -0.624023f, 0.138672f, -0.624023f,
-0.108398f, -0.595703f, 0.065918f, -0.556152f, 0.0546875f, -0.48291f, 0.0361328f,
--0.48291f, 0.0361328f, -0.662109f, 0.0234375f, -0.662109f, 0.365234f, -0.662109f,
-0.365234f, -0.644043f, 0.348145f, -0.644043f, 0.30957f, -0.644043f, 0.295166f, -0.635986f,
-0.280762f, -0.62793f, 0.274658f, -0.61377f, 0.268555f, -0.599609f, 0.268555f, -0.542969f,
-0.268555f, -0.21875f, 0.268555f, -0.129883f, 0.281982f, -0.101074f, 0.29541f, -0.0722656f,
-0.326172f, -0.0532227f, 0.356934f, -0.0341797f, 0.403809f, -0.0341797f, 0.45752f,
--0.0341797f, 0.495361f, -0.0583496f, 0.533203f, -0.0825195f, 0.552002f, -0.125f,
-0.570801f, -0.16748f, 0.570801f, -0.272949f, 0.570801f, -0.542969f, 0.570801f, -0.587402f,
-0.561523f, -0.606445f, 0.552246f, -0.625488f, 0.538086f, -0.632812f, 0.516113f, -0.644043f,
-0.476074f, -0.644043f, 0.476074f, -0.662109f, 0.705078f, -0.662109f, 0.705078f, -0.644043f,
-0.691406f, -0.644043f, 0.663574f, -0.644043f, 0.64502f, -0.632812f, 0.626465f, -0.621582f,
-0.618164f, -0.599121f, 0.611816f, -0.583496f, 0.611816f, -0.542969f, 0.611816f, -0.291504f,
-0.611816f, -0.174805f, 0.596436f, -0.123047f, 0.581055f, -0.0712891f, 0.521484f,
--0.027832f, 0.461914f, 0.015625f, 0.358887f, 0.015625f, 0.272949f, 0.015625f, 0.226074f,
--0.00732422f, 0.162109f, -0.0385742f, 0.135742f, -0.0874023f, 0.109375f, -0.13623f,
-0.109375f, -0.21875f, 0.109375f, -0.542969f, 0.109375f, -0.600098f, 0.103027f, -0.614014f,
-0.0966797f, -0.62793f, 0.0810547f, -0.63623f, 0.0654297f, -0.644531f, 0.0234375f,
--0.644043f, 0.711914f, -0.662109f, 0.711914f, -0.644043f, 0.675781f, -0.638184f,
-0.647461f, -0.605469f, 0.626953f, -0.581055f, 0.586426f, -0.490723f, 0.358398f, 0.0151367f,
-0.342285f, 0.0151367f, 0.115234f, -0.51123f, 0.0742188f, -0.606445f, 0.0603027f,
--0.623047f, 0.0463867f, -0.639648f, 0.0078125f, -0.644043f, 0.0078125f, -0.662109f,
-0.325195f, -0.662109f, 0.325195f, -0.644043f, 0.314453f, -0.644043f, 0.271484f, -0.644043f,
-0.255859f, -0.633301f, 0.244629f, -0.625977f, 0.244629f, -0.611816f, 0.244629f, -0.603027f,
-0.248535f, -0.591064f, 0.252441f, -0.579102f, 0.274902f, -0.526855f, 0.416016f, -0.197266f,
-0.546875f, -0.490723f, 0.570312f, -0.543945f, 0.575684f, -0.562012f, 0.581055f, -0.580078f,
-0.581055f, -0.592773f, 0.581055f, -0.607422f, 0.573242f, -0.618652f, 0.56543f, -0.629883f,
-0.550293f, -0.635742f, 0.529297f, -0.644043f, 0.494629f, -0.644043f, 0.494629f, -0.662109f,
-0.991211f, -0.662109f, 0.991211f, -0.644043f, 0.972656f, -0.642578f, 0.959961f, -0.633789f,
-0.947266f, -0.625f, 0.9375f, -0.606934f, 0.93457f, -0.601074f, 0.906738f, -0.53125f,
-0.699219f, 0.0151367f, 0.680176f, 0.0151367f, 0.516113f, -0.411621f, 0.335449f, 0.0151367f,
-0.317383f, 0.0151367f, 0.0996094f, -0.525391f, 0.0664062f, -0.606934f, 0.0532227f,
--0.624023f, 0.0400391f, -0.641113f, 0.00878906f, -0.644043f, 0.00878906f, -0.662109f,
-0.295898f, -0.662109f, 0.295898f, -0.644043f, 0.26123f, -0.643066f, 0.249756f, -0.633545f,
-0.238281f, -0.624023f, 0.238281f, -0.609863f, 0.238281f, -0.591309f, 0.262207f, -0.53125f,
-0.39209f, -0.209961f, 0.496094f, -0.460938f, 0.46875f, -0.53125f, 0.446289f, -0.588867f,
-0.434082f, -0.608154f, 0.421875f, -0.627441f, 0.406006f, -0.635742f, 0.390137f, -0.644043f,
-0.359375f, -0.644043f, 0.359375f, -0.662109f, 0.680176f, -0.662109f, 0.680176f, -0.644043f,
-0.646484f, -0.643555f, 0.631836f, -0.638672f, 0.621582f, -0.635254f, 0.615723f, -0.627197f,
-0.609863f, -0.619141f, 0.609863f, -0.608887f, 0.609863f, -0.597656f, 0.631836f, -0.540039f,
-0.752441f, -0.226562f, 0.860352f, -0.510254f, 0.877441f, -0.554199f, 0.881348f, -0.570312f,
-0.885254f, -0.586426f, 0.885254f, -0.600098f, 0.885254f, -0.620117f, 0.871582f, -0.631592f,
-0.85791f, -0.643066f, 0.819336f, -0.644043f, 0.819336f, -0.662109f, 0.422363f, -0.388184f,
-0.60498f, -0.117188f, 0.650391f, -0.0498047f, 0.669678f, -0.0354004f, 0.688965f,
--0.0209961f, 0.715332f, -0.0180664f, 0.715332f, 0, 0.392578f, 0, 0.392578f, -0.0180664f,
-0.431152f, -0.0209961f, 0.442383f, -0.0297852f, 0.453613f, -0.0385742f, 0.453613f,
--0.0512695f, 0.453613f, -0.0600586f, 0.450195f, -0.0668945f, 0.443359f, -0.081543f,
-0.416016f, -0.121582f, 0.319336f, -0.264648f, 0.218262f, -0.141113f, 0.172852f, -0.0849609f,
-0.172852f, -0.0649414f, 0.172852f, -0.0507812f, 0.18457f, -0.0385742f, 0.196289f,
--0.0263672f, 0.219238f, -0.0209961f, 0.229492f, -0.0180664f, 0.26123f, -0.0180664f,
-0.26123f, 0, 0.00683594f, 0, 0.00683594f, -0.0180664f, 0.050293f, -0.0244141f, 0.0751953f,
--0.0415039f, 0.10791f, -0.0639648f, 0.166504f, -0.135254f, 0.297852f, -0.29541f,
-0.129395f, -0.542969f, 0.0878906f, -0.604004f, 0.0820312f, -0.61084f, 0.0688477f,
--0.626953f, 0.0561523f, -0.633789f, 0.043457f, -0.640625f, 0.0209961f, -0.644043f,
-0.0209961f, -0.662109f, 0.349609f, -0.662109f, 0.349609f, -0.644043f, 0.333008f,
--0.644043f, 0.304688f, -0.644043f, 0.293457f, -0.63501f, 0.282227f, -0.625977f, 0.282227f,
--0.612305f, 0.282227f, -0.601562f, 0.285645f, -0.59375f, 0.319336f, -0.542969f, 0.401367f,
--0.417969f, 0.471191f, -0.503418f, 0.524902f, -0.569336f, 0.524902f, -0.595703f,
-0.524902f, -0.608887f, 0.517334f, -0.620117f, 0.509766f, -0.631348f, 0.495605f, -0.637695f,
-0.481445f, -0.644043f, 0.45166f, -0.644043f, 0.45166f, -0.662109f, 0.695312f, -0.662109f,
-0.695312f, -0.644043f, 0.666504f, -0.643555f, 0.648926f, -0.636963f, 0.631348f, -0.630371f,
-0.611328f, -0.612305f, 0.598633f, -0.600586f, 0.547852f, -0.539551f, 0.710938f, -0.662109f,
-0.710938f, -0.644043f, 0.678223f, -0.639648f, 0.660645f, -0.625f, 0.63623f, -0.604492f,
-0.583496f, -0.513184f, 0.439941f, -0.273438f, 0.439941f, -0.113281f, 0.439941f, -0.0620117f,
-0.445312f, -0.0495605f, 0.450684f, -0.0371094f, 0.466553f, -0.0275879f, 0.482422f,
--0.0180664f, 0.508789f, -0.0180664f, 0.545898f, -0.0180664f, 0.545898f, 0, 0.174316f,
-0, 0.174316f, -0.0180664f, 0.208984f, -0.0180664f, 0.238281f, -0.0180664f, 0.255371f,
--0.0283203f, 0.268066f, -0.0351562f, 0.275391f, -0.0517578f, 0.280762f, -0.0634766f,
-0.280762f, -0.113281f, 0.280762f, -0.246094f, 0.125f, -0.529785f, 0.0786133f, -0.61377f,
-0.0595703f, -0.628662f, 0.0405273f, -0.643555f, 0.00878906f, -0.644043f, 0.00878906f,
--0.662109f, 0.326172f, -0.662109f, 0.326172f, -0.644043f, 0.312012f, -0.644043f,
-0.283203f, -0.644043f, 0.271729f, -0.635742f, 0.260254f, -0.627441f, 0.260254f, -0.618164f,
-0.260254f, -0.600586f, 0.299316f, -0.529785f, 0.418945f, -0.310547f, 0.538086f, -0.510254f,
-0.58252f, -0.583496f, 0.58252f, -0.607422f, 0.58252f, -0.620605f, 0.569824f, -0.629395f,
-0.553223f, -0.641602f, 0.508789f, -0.644043f, 0.508789f, -0.662109f, 0.610352f, -0.662109f,
-0.221191f, -0.0371094f, 0.347168f, -0.0371094f, 0.436523f, -0.0371094f, 0.472168f,
--0.0483398f, 0.530273f, -0.065918f, 0.572266f, -0.113037f, 0.614258f, -0.160156f,
-0.630371f, -0.239258f, 0.649414f, -0.239258f, 0.622559f, 0, 0.0161133f, 0, 0.405762f,
--0.625977f, 0.307617f, -0.625977f, 0.250488f, -0.625977f, 0.232422f, -0.622559f,
-0.198242f, -0.616211f, 0.168213f, -0.597412f, 0.138184f, -0.578613f, 0.118408f, -0.547363f,
-0.0986328f, -0.516113f, 0.0874023f, -0.468262f, 0.0693359f, -0.468262f, 0.0874023f,
--0.662109f, 0.104492f, 0.182617f, 0.104492f, -0.662109f, 0.300781f, -0.662109f, 0.300781f,
--0.641602f, 0.278809f, -0.641602f, 0.246582f, -0.641602f, 0.235596f, -0.63501f, 0.224609f,
--0.628418f, 0.218994f, -0.615479f, 0.213379f, -0.602539f, 0.213379f, -0.553223f,
-0.213379f, 0.0771484f, 0.213379f, 0.124023f, 0.215332f, 0.130859f, 0.219727f, 0.148438f,
-0.231689f, 0.156738f, 0.243652f, 0.165039f, 0.278809f, 0.165039f, 0.300781f, 0.165039f,
-0.300781f, 0.182617f, 0.000976562f, -0.677246f, 0.0625f, -0.677246f, 0.280762f, 0.0151367f,
-0.217773f, 0.0151367f, 0.229004f, -0.662109f, 0.229004f, 0.182617f, 0.0327148f, 0.182617f,
-0.0327148f, 0.164062f, 0.0546875f, 0.164062f, 0.0869141f, 0.164062f, 0.0979004f,
-0.157715f, 0.108887f, 0.151367f, 0.114502f, 0.138184f, 0.120117f, 0.125f, 0.120117f,
-0.0761719f, 0.120117f, -0.554688f, 0.120117f, -0.601562f, 0.118164f, -0.608398f,
-0.11377f, -0.625488f, 0.101807f, -0.634033f, 0.0898438f, -0.642578f, 0.0546875f,
--0.642578f, 0.0327148f, -0.642578f, 0.0327148f, -0.662109f, 0.0717773f, -0.325195f,
-0.272461f, -0.675781f, 0.3125f, -0.675781f, 0.509766f, -0.325195f, 0.432129f, -0.325195f,
-0.288086f, -0.575195f, 0.146484f, -0.325195f, -0.00927734f, 0.151855f, 0.509277f,
-0.151855f, 0.509277f, 0.21582f, -0.00927734f, 0.21582f, 0.0185547f, -0.68457f, 0.165527f,
--0.68457f, 0.222168f, -0.515137f, 0.180664f, -0.515137f, 0.285645f, -0.0673828f,
-0.202148f, 0.00634766f, 0.135742f, 0.00634766f, 0.0966797f, 0.00634766f, 0.0708008f,
--0.0192871f, 0.0449219f, -0.0449219f, 0.0449219f, -0.0834961f, 0.0449219f, -0.135742f,
-0.0898438f, -0.17749f, 0.134766f, -0.219238f, 0.285645f, -0.288574f, 0.285645f, -0.334473f,
-0.285645f, -0.38623f, 0.280029f, -0.399658f, 0.274414f, -0.413086f, 0.258789f, -0.423096f,
-0.243164f, -0.433105f, 0.223633f, -0.433105f, 0.191895f, -0.433105f, 0.171387f, -0.418945f,
-0.158691f, -0.410156f, 0.158691f, -0.398438f, 0.158691f, -0.388184f, 0.172363f, -0.373047f,
-0.190918f, -0.352051f, 0.190918f, -0.33252f, 0.190918f, -0.308594f, 0.173096f, -0.291748f,
-0.155273f, -0.274902f, 0.126465f, -0.274902f, 0.0957031f, -0.274902f, 0.0749512f,
--0.293457f, 0.0541992f, -0.312012f, 0.0541992f, -0.336914f, 0.0541992f, -0.37207f,
-0.0820312f, -0.404053f, 0.109863f, -0.436035f, 0.159668f, -0.453125f, 0.209473f,
--0.470215f, 0.263184f, -0.470215f, 0.328125f, -0.470215f, 0.365967f, -0.442627f,
-0.403809f, -0.415039f, 0.415039f, -0.382812f, 0.421875f, -0.362305f, 0.421875f, -0.288574f,
-0.421875f, -0.111328f, 0.421875f, -0.0800781f, 0.424316f, -0.0720215f, 0.426758f,
--0.0639648f, 0.431641f, -0.0600586f, 0.436523f, -0.0561523f, 0.442871f, -0.0561523f,
-0.455566f, -0.0561523f, 0.46875f, -0.0742188f, 0.483398f, -0.0625f, 0.458984f, -0.0263672f,
-0.432861f, -0.0100098f, 0.406738f, 0.00634766f, 0.373535f, 0.00634766f, 0.334473f,
-0.00634766f, 0.3125f, -0.0119629f, 0.290527f, -0.0302734f, 0.285645f, -0.0673828f,
-0.285645f, -0.103027f, 0.285645f, -0.255859f, 0.226562f, -0.221191f, 0.197754f, -0.181641f,
-0.178711f, -0.155273f, 0.178711f, -0.128418f, 0.178711f, -0.105957f, 0.194824f, -0.0888672f,
-0.207031f, -0.0756836f, 0.229004f, -0.0756836f, 0.253418f, -0.0756836f, 0.285645f,
--0.103027f, 0.210449f, -0.662109f, 0.210449f, -0.410645f, 0.268066f, -0.470215f,
-0.336426f, -0.470215f, 0.383301f, -0.470215f, 0.424805f, -0.442627f, 0.466309f, -0.415039f,
-0.489746f, -0.364258f, 0.513184f, -0.313477f, 0.513184f, -0.24707f, 0.513184f, -0.172363f,
-0.483398f, -0.111328f, 0.453613f, -0.050293f, 0.403809f, -0.0183105f, 0.354004f,
-0.0136719f, 0.290039f, 0.0136719f, 0.25293f, 0.0136719f, 0.224121f, 0.00195312f,
-0.195312f, -0.00976562f, 0.16748f, -0.0361328f, 0.0917969f, 0.0131836f, 0.0751953f,
-0.0131836f, 0.0751953f, -0.567383f, 0.0751953f, -0.606934f, 0.0717773f, -0.616211f,
-0.0668945f, -0.629883f, 0.0563965f, -0.636475f, 0.0458984f, -0.643066f, 0.0209961f,
--0.644043f, 0.0209961f, -0.662109f, 0.210449f, -0.367188f, 0.210449f, -0.164062f,
-0.210449f, -0.102051f, 0.213379f, -0.0849609f, 0.218262f, -0.0561523f, 0.236816f,
--0.0383301f, 0.255371f, -0.0205078f, 0.28418f, -0.0205078f, 0.309082f, -0.0205078f,
-0.326904f, -0.034668f, 0.344727f, -0.0488281f, 0.356689f, -0.0908203f, 0.368652f,
--0.132812f, 0.368652f, -0.242188f, 0.368652f, -0.347168f, 0.342285f, -0.38623f, 0.323242f,
--0.414551f, 0.291016f, -0.414551f, 0.249023f, -0.414551f, 0.210449f, -0.367188f,
-0.40625f, -0.117676f, 0.421387f, -0.105957f, 0.38916f, -0.0454102f, 0.341064f, -0.0158691f,
-0.292969f, 0.0136719f, 0.23877f, 0.0136719f, 0.147461f, 0.0136719f, 0.0927734f, -0.0551758f,
-0.0380859f, -0.124023f, 0.0380859f, -0.220703f, 0.0380859f, -0.313965f, 0.0878906f,
--0.384766f, 0.147949f, -0.470215f, 0.253418f, -0.470215f, 0.324219f, -0.470215f,
-0.365967f, -0.43457f, 0.407715f, -0.398926f, 0.407715f, -0.35498f, 0.407715f, -0.327148f,
-0.390869f, -0.310547f, 0.374023f, -0.293945f, 0.34668f, -0.293945f, 0.317871f, -0.293945f,
-0.299072f, -0.312988f, 0.280273f, -0.332031f, 0.275879f, -0.380859f, 0.272949f, -0.411621f,
-0.261719f, -0.423828f, 0.250488f, -0.436035f, 0.235352f, -0.436035f, 0.211914f, -0.436035f,
-0.195312f, -0.411133f, 0.169922f, -0.373535f, 0.169922f, -0.295898f, 0.169922f, -0.231445f,
-0.19043f, -0.172607f, 0.210938f, -0.11377f, 0.246582f, -0.0849609f, 0.273438f, -0.0639648f,
-0.310059f, -0.0639648f, 0.333984f, -0.0639648f, 0.355469f, -0.0751953f, 0.376953f,
--0.0864258f, 0.40625f, -0.117676f, 0.477539f, -0.662109f, 0.477539f, -0.136719f,
-0.477539f, -0.0834961f, 0.480469f, -0.0737305f, 0.484375f, -0.0576172f, 0.495361f,
--0.0498047f, 0.506348f, -0.0419922f, 0.533691f, -0.0400391f, 0.533691f, -0.0239258f,
-0.34082f, 0.0136719f, 0.34082f, -0.0585938f, 0.306152f, -0.0166016f, 0.279053f, -0.00146484f,
-0.251953f, 0.0136719f, 0.217773f, 0.0136719f, 0.130371f, 0.0136719f, 0.0795898f,
--0.0644531f, 0.0385742f, -0.12793f, 0.0385742f, -0.220215f, 0.0385742f, -0.293945f,
-0.0639648f, -0.352295f, 0.0893555f, -0.410645f, 0.133545f, -0.44043f, 0.177734f,
--0.470215f, 0.228516f, -0.470215f, 0.26123f, -0.470215f, 0.286621f, -0.45752f, 0.312012f,
--0.444824f, 0.34082f, -0.413086f, 0.34082f, -0.550781f, 0.34082f, -0.603027f, 0.336426f,
--0.61377f, 0.330566f, -0.62793f, 0.318848f, -0.634766f, 0.307129f, -0.641602f, 0.274902f,
--0.641602f, 0.274902f, -0.662109f, 0.34082f, -0.352539f, 0.304688f, -0.421875f, 0.252441f,
--0.421875f, 0.234375f, -0.421875f, 0.222656f, -0.412109f, 0.20459f, -0.396973f, 0.193115f,
--0.358887f, 0.181641f, -0.320801f, 0.181641f, -0.242188f, 0.181641f, -0.155762f,
-0.194336f, -0.114258f, 0.207031f, -0.0727539f, 0.229004f, -0.0541992f, 0.240234f,
--0.0449219f, 0.259766f, -0.0449219f, 0.302734f, -0.0449219f, 0.34082f, -0.112305f,
-0.42041f, -0.244629f, 0.169922f, -0.244629f, 0.174316f, -0.153809f, 0.218262f, -0.101074f,
-0.251953f, -0.0605469f, 0.299316f, -0.0605469f, 0.328613f, -0.0605469f, 0.352539f,
--0.0769043f, 0.376465f, -0.0932617f, 0.403809f, -0.135742f, 0.42041f, -0.125f, 0.383301f,
--0.0493164f, 0.338379f, -0.0178223f, 0.293457f, 0.0136719f, 0.234375f, 0.0136719f,
-0.132812f, 0.0136719f, 0.0805664f, -0.0644531f, 0.0385742f, -0.127441f, 0.0385742f,
--0.220703f, 0.0385742f, -0.334961f, 0.100342f, -0.402588f, 0.162109f, -0.470215f,
-0.245117f, -0.470215f, 0.314453f, -0.470215f, 0.365479f, -0.41333f, 0.416504f, -0.356445f,
-0.42041f, -0.244629f, 0.300293f, -0.277344f, 0.300293f, -0.355957f, 0.291748f, -0.385254f,
-0.283203f, -0.414551f, 0.265137f, -0.429688f, 0.254883f, -0.438477f, 0.237793f, -0.438477f,
-0.212402f, -0.438477f, 0.196289f, -0.413574f, 0.16748f, -0.370117f, 0.16748f, -0.294434f,
-0.16748f, -0.277344f, 0.233887f, -0.408691f, 0.233887f, -0.0917969f, 0.233887f, -0.0458984f,
-0.243652f, -0.0341797f, 0.259277f, -0.0161133f, 0.30127f, -0.0175781f, 0.30127f,
-0, 0.0322266f, 0, 0.0322266f, -0.0175781f, 0.0629883f, -0.0180664f, 0.0759277f, -0.0246582f,
-0.0888672f, -0.03125f, 0.09375f, -0.0429688f, 0.0986328f, -0.0546875f, 0.0986328f,
--0.0917969f, 0.0986328f, -0.408691f, 0.0322266f, -0.408691f, 0.0322266f, -0.456543f,
-0.0986328f, -0.456543f, 0.0986328f, -0.490234f, 0.0981445f, -0.513184f, 0.0981445f,
--0.583496f, 0.149658f, -0.630371f, 0.201172f, -0.677246f, 0.289062f, -0.677246f,
-0.349121f, -0.677246f, 0.378174f, -0.654785f, 0.407227f, -0.632324f, 0.407227f, -0.60498f,
-0.407227f, -0.583008f, 0.38916f, -0.566895f, 0.371094f, -0.550781f, 0.341309f, -0.550781f,
-0.315918f, -0.550781f, 0.301025f, -0.563965f, 0.286133f, -0.577148f, 0.286133f, -0.593262f,
-0.286133f, -0.597656f, 0.289062f, -0.611328f, 0.291016f, -0.619629f, 0.291016f, -0.626953f,
-0.291016f, -0.637207f, 0.285156f, -0.64209f, 0.277344f, -0.649414f, 0.266113f, -0.649414f,
-0.251953f, -0.649414f, 0.242432f, -0.637695f, 0.23291f, -0.625977f, 0.23291f, -0.600098f,
-0.233887f, -0.514648f, 0.233887f, -0.456543f, 0.30127f, -0.456543f, 0.30127f, -0.408691f,
-0.32666f, -0.451172f, 0.480469f, -0.451172f, 0.480469f, -0.397461f, 0.393066f, -0.397461f,
-0.416992f, -0.373535f, 0.42627f, -0.354004f, 0.437988f, -0.327637f, 0.437988f, -0.298828f,
-0.437988f, -0.25f, 0.410889f, -0.214111f, 0.383789f, -0.178223f, 0.337158f, -0.157959f,
-0.290527f, -0.137695f, 0.254395f, -0.137695f, 0.251465f, -0.137695f, 0.195801f, -0.140137f,
-0.173828f, -0.140137f, 0.158936f, -0.125732f, 0.144043f, -0.111328f, 0.144043f, -0.0913086f,
-0.144043f, -0.0737305f, 0.157471f, -0.0625f, 0.170898f, -0.0512695f, 0.201172f, -0.0512695f,
-0.285645f, -0.0522461f, 0.388184f, -0.0522461f, 0.426758f, -0.0297852f, 0.481934f,
-0.00146484f, 0.481934f, 0.0664062f, 0.481934f, 0.10791f, 0.456543f, 0.141846f, 0.431152f,
-0.175781f, 0.389648f, 0.191895f, 0.32666f, 0.21582f, 0.244629f, 0.21582f, 0.183105f,
-0.21582f, 0.132324f, 0.203857f, 0.081543f, 0.191895f, 0.0595703f, 0.170654f, 0.0375977f,
-0.149414f, 0.0375977f, 0.125977f, 0.0375977f, 0.103516f, 0.0544434f, 0.0856934f,
-0.0712891f, 0.0678711f, 0.117188f, 0.0556641f, 0.0537109f, 0.0244141f, 0.0537109f,
--0.03125f, 0.0537109f, -0.0649414f, 0.0795898f, -0.0966797f, 0.105469f, -0.128418f,
-0.161621f, -0.151855f, 0.0961914f, -0.175781f, 0.0668945f, -0.214844f, 0.0375977f,
--0.253906f, 0.0375977f, -0.305176f, 0.0375977f, -0.37207f, 0.0922852f, -0.421143f,
-0.146973f, -0.470215f, 0.23291f, -0.470215f, 0.27832f, -0.470215f, 0.32666f, -0.451172f,
-0.242188f, -0.439941f, 0.213867f, -0.439941f, 0.194336f, -0.411377f, 0.174805f, -0.382812f,
-0.174805f, -0.292969f, 0.174805f, -0.220215f, 0.194092f, -0.193115f, 0.213379f, -0.166016f,
-0.239746f, -0.166016f, 0.269043f, -0.166016f, 0.288574f, -0.192871f, 0.308105f, -0.219727f,
-0.308105f, -0.297363f, 0.308105f, -0.384766f, 0.286133f, -0.416504f, 0.270508f, -0.439941f,
-0.242188f, -0.439941f, 0.213379f, 0.0673828f, 0.163574f, 0.0673828f, 0.147461f, 0.0756836f,
-0.119629f, 0.0908203f, 0.119629f, 0.116699f, 0.119629f, 0.141602f, 0.148438f, 0.161865f,
-0.177246f, 0.182129f, 0.256836f, 0.182129f, 0.324707f, 0.182129f, 0.363525f, 0.164062f,
-0.402344f, 0.145996f, 0.402344f, 0.113281f, 0.402344f, 0.101074f, 0.39502f, 0.0927734f,
-0.381836f, 0.078125f, 0.355225f, 0.0727539f, 0.328613f, 0.0673828f, 0.213379f, 0.0673828f,
-0.220215f, -0.662109f, 0.220215f, -0.397949f, 0.257812f, -0.4375f, 0.289062f, -0.453857f,
-0.320312f, -0.470215f, 0.354004f, -0.470215f, 0.396973f, -0.470215f, 0.42749f, -0.445801f,
-0.458008f, -0.421387f, 0.468018f, -0.388428f, 0.478027f, -0.355469f, 0.478027f, -0.277344f,
-0.478027f, -0.0991211f, 0.478027f, -0.046875f, 0.487793f, -0.0339355f, 0.497559f,
--0.0209961f, 0.527344f, -0.0175781f, 0.527344f, 0, 0.295898f, 0, 0.295898f, -0.0175781f,
-0.320312f, -0.0209961f, 0.33252f, -0.0371094f, 0.341309f, -0.0498047f, 0.341309f,
--0.0991211f, 0.341309f, -0.302734f, 0.341309f, -0.359375f, 0.336914f, -0.373779f,
-0.33252f, -0.388184f, 0.322021f, -0.39624f, 0.311523f, -0.404297f, 0.29834f, -0.404297f,
-0.278809f, -0.404297f, 0.260254f, -0.390869f, 0.241699f, -0.377441f, 0.220215f, -0.34375f,
-0.220215f, -0.0991211f, 0.220215f, -0.050293f, 0.227539f, -0.0380859f, 0.236816f,
--0.0214844f, 0.265625f, -0.0175781f, 0.265625f, 0, 0.0341797f, 0, 0.0341797f, -0.0175781f,
-0.0629883f, -0.0205078f, 0.0751953f, -0.0361328f, 0.0834961f, -0.046875f, 0.0834961f,
--0.0991211f, 0.0834961f, -0.562988f, 0.0834961f, -0.614746f, 0.0739746f, -0.627441f,
-0.0644531f, -0.640137f, 0.0341797f, -0.644043f, 0.0341797f, -0.662109f, 0.143555f,
--0.677734f, 0.175293f, -0.677734f, 0.197266f, -0.655518f, 0.219238f, -0.633301f,
-0.219238f, -0.602051f, 0.219238f, -0.570801f, 0.197021f, -0.548828f, 0.174805f, -0.526855f,
-0.143555f, -0.526855f, 0.112305f, -0.526855f, 0.090332f, -0.548828f, 0.0683594f,
--0.570801f, 0.0683594f, -0.602051f, 0.0683594f, -0.633301f, 0.090332f, -0.655518f,
-0.112305f, -0.677734f, 0.143555f, -0.677734f, 0.211914f, -0.456543f, 0.211914f, -0.0947266f,
-0.211914f, -0.0463867f, 0.223145f, -0.032959f, 0.234375f, -0.0195312f, 0.26709f,
--0.0175781f, 0.26709f, 0, 0.0205078f, 0, 0.0205078f, -0.0175781f, 0.0507812f, -0.0185547f,
-0.0654297f, -0.0351562f, 0.0751953f, -0.0463867f, 0.0751953f, -0.0947266f, 0.0751953f,
--0.361328f, 0.0751953f, -0.409668f, 0.0639648f, -0.423096f, 0.0527344f, -0.436523f,
-0.0205078f, -0.438477f, 0.0205078f, -0.456543f, 0.173828f, -0.677246f, 0.205078f,
--0.677246f, 0.226807f, -0.655518f, 0.248535f, -0.633789f, 0.248535f, -0.603027f,
-0.248535f, -0.571777f, 0.226562f, -0.549805f, 0.20459f, -0.527832f, 0.173828f, -0.527832f,
-0.143066f, -0.527832f, 0.121094f, -0.549805f, 0.0991211f, -0.571777f, 0.0991211f,
--0.603027f, 0.0991211f, -0.633789f, 0.12085f, -0.655518f, 0.142578f, -0.677246f,
-0.173828f, -0.677246f, 0.242188f, -0.456543f, 0.242188f, 0.0161133f, 0.242188f, 0.0825195f,
-0.233887f, 0.114258f, 0.22168f, 0.160156f, 0.185303f, 0.187988f, 0.148926f, 0.21582f,
-0.0893555f, 0.21582f, 0.0292969f, 0.21582f, 0.000732422f, 0.191406f, -0.027832f,
-0.166992f, -0.027832f, 0.132324f, -0.027832f, 0.11084f, -0.0129395f, 0.0949707f,
-0.00195312f, 0.0791016f, 0.0219727f, 0.0791016f, 0.0405273f, 0.0791016f, 0.0512695f,
-0.0900879f, 0.0620117f, 0.101074f, 0.0620117f, 0.123047f, 0.0620117f, 0.128906f,
-0.0615234f, 0.136719f, 0.0605469f, 0.146973f, 0.0605469f, 0.150879f, 0.0605469f,
-0.167969f, 0.0683594f, 0.17627f, 0.0761719f, 0.18457f, 0.0883789f, 0.18457f, 0.0996094f,
-0.18457f, 0.107666f, 0.174805f, 0.115723f, 0.165039f, 0.115723f, 0.146973f, 0.115723f,
-0.137207f, 0.112793f, 0.107422f, 0.10791f, 0.0532227f, 0.107422f, 0.0419922f, 0.105957f,
--0.0737305f, 0.105957f, -0.355957f, 0.106445f, -0.381348f, 0.106445f, -0.412109f,
-0.0959473f, -0.423584f, 0.0854492f, -0.435059f, 0.0517578f, -0.438477f, 0.0517578f,
--0.456543f, 0.219238f, -0.662109f, 0.219238f, -0.226562f, 0.325195f, -0.330566f,
-0.35791f, -0.362305f, 0.365967f, -0.376465f, 0.374023f, -0.390625f, 0.374023f, -0.403809f,
-0.374023f, -0.416992f, 0.363281f, -0.425781f, 0.352539f, -0.43457f, 0.321289f, -0.438477f,
-0.321289f, -0.456543f, 0.525879f, -0.456543f, 0.525879f, -0.438477f, 0.496582f, -0.437012f,
-0.474609f, -0.424561f, 0.452637f, -0.412109f, 0.388672f, -0.349609f, 0.338867f, -0.300781f,
-0.446289f, -0.143555f, 0.51123f, -0.0478516f, 0.523438f, -0.0361328f, 0.540039f,
--0.0195312f, 0.56543f, -0.0175781f, 0.56543f, 0, 0.32959f, 0, 0.32959f, -0.0175781f,
-0.345215f, -0.0175781f, 0.352295f, -0.0234375f, 0.359375f, -0.0292969f, 0.359375f,
--0.0361328f, 0.359375f, -0.0473633f, 0.338867f, -0.0776367f, 0.248535f, -0.209961f,
-0.219238f, -0.181152f, 0.219238f, -0.0991211f, 0.219238f, -0.046875f, 0.229004f,
--0.0339355f, 0.23877f, -0.0209961f, 0.269043f, -0.0175781f, 0.269043f, 0, 0.0332031f,
-0, 0.0332031f, -0.0175781f, 0.0620117f, -0.0205078f, 0.0742188f, -0.0361328f, 0.0825195f,
--0.046875f, 0.0825195f, -0.0991211f, 0.0825195f, -0.562988f, 0.0825195f, -0.614746f,
-0.072998f, -0.627441f, 0.0634766f, -0.640137f, 0.0332031f, -0.644043f, 0.0332031f,
--0.662109f, 0.212402f, -0.662109f, 0.212402f, -0.0947266f, 0.212402f, -0.0463867f,
-0.223633f, -0.032959f, 0.234863f, -0.0195312f, 0.267578f, -0.0175781f, 0.267578f,
-0, 0.0209961f, 0, 0.0209961f, -0.0175781f, 0.0512695f, -0.0185547f, 0.065918f, -0.0351562f,
-0.0756836f, -0.0463867f, 0.0756836f, -0.0947266f, 0.0756836f, -0.567383f, 0.0756836f,
--0.615234f, 0.0644531f, -0.628662f, 0.0532227f, -0.64209f, 0.0209961f, -0.644043f,
-0.0209961f, -0.662109f, 0.223145f, -0.456543f, 0.223145f, -0.396484f, 0.260742f,
--0.4375f, 0.292725f, -0.453857f, 0.324707f, -0.470215f, 0.362793f, -0.470215f, 0.406738f,
--0.470215f, 0.436523f, -0.449707f, 0.466309f, -0.429199f, 0.482422f, -0.387207f,
-0.521484f, -0.431152f, 0.557373f, -0.450684f, 0.593262f, -0.470215f, 0.632324f, -0.470215f,
-0.679688f, -0.470215f, 0.707764f, -0.448486f, 0.73584f, -0.426758f, 0.746826f, -0.393311f,
-0.757812f, -0.359863f, 0.757812f, -0.286621f, 0.757812f, -0.0996094f, 0.757812f,
--0.046875f, 0.767334f, -0.0341797f, 0.776855f, -0.0214844f, 0.807129f, -0.0175781f,
-0.807129f, 0, 0.571289f, 0, 0.571289f, -0.0175781f, 0.599121f, -0.0200195f, 0.612305f,
--0.0390625f, 0.621094f, -0.0522461f, 0.621094f, -0.0996094f, 0.621094f, -0.295898f,
-0.621094f, -0.356934f, 0.616211f, -0.373535f, 0.611328f, -0.390137f, 0.60083f, -0.398193f,
-0.590332f, -0.40625f, 0.576172f, -0.40625f, 0.555176f, -0.40625f, 0.533691f, -0.390869f,
-0.512207f, -0.375488f, 0.490234f, -0.344727f, 0.490234f, -0.0996094f, 0.490234f,
--0.050293f, 0.498535f, -0.0375977f, 0.509766f, -0.0195312f, 0.541504f, -0.0175781f,
-0.541504f, 0, 0.305176f, 0, 0.305176f, -0.0175781f, 0.324219f, -0.0185547f, 0.335205f,
--0.0270996f, 0.346191f, -0.0356445f, 0.349854f, -0.0476074f, 0.353516f, -0.0595703f,
-0.353516f, -0.0996094f, 0.353516f, -0.295898f, 0.353516f, -0.35791f, 0.348633f, -0.373535f,
-0.34375f, -0.38916f, 0.332275f, -0.397949f, 0.320801f, -0.406738f, 0.307617f, -0.406738f,
-0.288086f, -0.406738f, 0.271973f, -0.396484f, 0.249023f, -0.381348f, 0.223145f, -0.344727f,
-0.223145f, -0.0996094f, 0.223145f, -0.0512695f, 0.232666f, -0.0358887f, 0.242188f,
--0.0205078f, 0.272461f, -0.0175781f, 0.272461f, 0, 0.0371094f, 0, 0.0371094f, -0.0175781f,
-0.065918f, -0.0205078f, 0.078125f, -0.0361328f, 0.0864258f, -0.046875f, 0.0864258f,
--0.0996094f, 0.0864258f, -0.357422f, 0.0864258f, -0.40918f, 0.0769043f, -0.421875f,
-0.0673828f, -0.43457f, 0.0371094f, -0.438477f, 0.0371094f, -0.456543f, 0.220215f,
--0.456543f, 0.220215f, -0.397461f, 0.255371f, -0.435547f, 0.287598f, -0.452881f,
-0.319824f, -0.470215f, 0.356934f, -0.470215f, 0.401367f, -0.470215f, 0.430664f, -0.445557f,
-0.459961f, -0.420898f, 0.469727f, -0.384277f, 0.477539f, -0.356445f, 0.477539f, -0.277344f,
-0.477539f, -0.0996094f, 0.477539f, -0.046875f, 0.487061f, -0.0339355f, 0.496582f,
--0.0209961f, 0.526855f, -0.0175781f, 0.526855f, 0, 0.295898f, 0, 0.295898f, -0.0175781f,
-0.321777f, -0.0209961f, 0.333008f, -0.0390625f, 0.34082f, -0.0512695f, 0.34082f,
--0.0996094f, 0.34082f, -0.302734f, 0.34082f, -0.358887f, 0.336426f, -0.373535f, 0.332031f,
--0.388184f, 0.321533f, -0.39624f, 0.311035f, -0.404297f, 0.29834f, -0.404297f, 0.256348f,
--0.404297f, 0.220215f, -0.344238f, 0.220215f, -0.0996094f, 0.220215f, -0.0483398f,
-0.229736f, -0.034668f, 0.239258f, -0.0209961f, 0.265137f, -0.0175781f, 0.265137f,
-0, 0.0341797f, 0, 0.0341797f, -0.0175781f, 0.0629883f, -0.0205078f, 0.0751953f, -0.0361328f,
-0.0834961f, -0.046875f, 0.0834961f, -0.0996094f, 0.0834961f, -0.357422f, 0.0834961f,
--0.40918f, 0.0739746f, -0.421875f, 0.0644531f, -0.43457f, 0.0341797f, -0.438477f,
-0.0341797f, -0.456543f, 0.249023f, -0.470215f, 0.308594f, -0.470215f, 0.359863f,
--0.439453f, 0.411133f, -0.408691f, 0.437744f, -0.352051f, 0.464355f, -0.29541f, 0.464355f,
--0.228027f, 0.464355f, -0.130859f, 0.415039f, -0.0654297f, 0.355469f, 0.0136719f,
-0.250488f, 0.0136719f, 0.147461f, 0.0136719f, 0.0917969f, -0.0585938f, 0.0361328f,
--0.130859f, 0.0361328f, -0.226074f, 0.0361328f, -0.324219f, 0.0930176f, -0.397217f,
-0.149902f, -0.470215f, 0.249023f, -0.470215f, 0.250977f, -0.435547f, 0.226074f, -0.435547f,
-0.208252f, -0.416748f, 0.19043f, -0.397949f, 0.184814f, -0.342529f, 0.179199f, -0.287109f,
-0.179199f, -0.188477f, 0.179199f, -0.13623f, 0.186035f, -0.0908203f, 0.191406f, -0.0561523f,
-0.208984f, -0.0380859f, 0.226562f, -0.0200195f, 0.249023f, -0.0200195f, 0.270996f,
--0.0200195f, 0.285645f, -0.0322266f, 0.304688f, -0.0488281f, 0.311035f, -0.0786133f,
-0.320801f, -0.125f, 0.320801f, -0.266113f, 0.320801f, -0.349121f, 0.311523f, -0.380127f,
-0.302246f, -0.411133f, 0.28418f, -0.425293f, 0.271484f, -0.435547f, 0.250977f, -0.435547f,
-0.210449f, -0.0463867f, 0.210449f, 0.123535f, 0.210449f, 0.158691f, 0.216064f, 0.171387f,
-0.22168f, 0.184082f, 0.233398f, 0.189941f, 0.245117f, 0.195801f, 0.279297f, 0.195801f,
-0.279297f, 0.213867f, 0.019043f, 0.213867f, 0.019043f, 0.195801f, 0.0493164f, 0.194824f,
-0.0639648f, 0.178711f, 0.0737305f, 0.16748f, 0.0737305f, 0.120605f, 0.0737305f, -0.361328f,
-0.0737305f, -0.409668f, 0.0625f, -0.423096f, 0.0512695f, -0.436523f, 0.019043f, -0.438477f,
-0.019043f, -0.456543f, 0.210449f, -0.456543f, 0.210449f, -0.396484f, 0.234375f, -0.431641f,
-0.259277f, -0.447266f, 0.294922f, -0.470215f, 0.336914f, -0.470215f, 0.387207f, -0.470215f,
-0.428467f, -0.438477f, 0.469727f, -0.406738f, 0.491211f, -0.35083f, 0.512695f, -0.294922f,
-0.512695f, -0.230469f, 0.512695f, -0.161133f, 0.490479f, -0.10376f, 0.468262f, -0.0463867f,
-0.426025f, -0.0163574f, 0.383789f, 0.0136719f, 0.332031f, 0.0136719f, 0.294434f,
-0.0136719f, 0.261719f, -0.00292969f, 0.237305f, -0.015625f, 0.210449f, -0.0463867f,
-0.210449f, -0.0957031f, 0.252441f, -0.0361328f, 0.300293f, -0.0361328f, 0.32666f,
--0.0361328f, 0.34375f, -0.0639648f, 0.369141f, -0.10498f, 0.369141f, -0.220215f,
-0.369141f, -0.338379f, 0.341309f, -0.381836f, 0.322754f, -0.410645f, 0.291504f, -0.410645f,
-0.242188f, -0.410645f, 0.210449f, -0.339355f, 0.340332f, -0.0478516f, 0.310547f,
--0.0166016f, 0.284668f, -0.00390625f, 0.250488f, 0.0136719f, 0.213379f, 0.0136719f,
-0.127441f, 0.0136719f, 0.0776367f, -0.0629883f, 0.0380859f, -0.124023f, 0.0380859f,
--0.208984f, 0.0380859f, -0.279785f, 0.0681152f, -0.342041f, 0.0981445f, -0.404297f,
-0.150635f, -0.437256f, 0.203125f, -0.470215f, 0.261719f, -0.470215f, 0.300781f, -0.470215f,
-0.331299f, -0.457031f, 0.361816f, -0.443848f, 0.383789f, -0.416992f, 0.460449f, -0.470215f,
-0.477051f, -0.470215f, 0.477051f, 0.121094f, 0.477051f, 0.166016f, 0.484863f, 0.177246f,
-0.497559f, 0.195312f, 0.536133f, 0.195801f, 0.536133f, 0.213867f, 0.272461f, 0.213867f,
-0.272461f, 0.195801f, 0.302734f, 0.195801f, 0.316406f, 0.188965f, 0.330078f, 0.182129f,
-0.335205f, 0.170898f, 0.340332f, 0.159668f, 0.340332f, 0.125f, 0.340332f, -0.0922852f,
-0.340332f, -0.280273f, 0.340332f, -0.358887f, 0.331787f, -0.384277f, 0.323242f, -0.409668f,
-0.300293f, -0.428223f, 0.288574f, -0.4375f, 0.270508f, -0.4375f, 0.233398f, -0.4375f,
-0.212891f, -0.404785f, 0.180664f, -0.354492f, 0.180664f, -0.217773f, 0.180664f, -0.112793f,
-0.208496f, -0.0703125f, 0.227539f, -0.0415039f, 0.257812f, -0.0415039f, 0.275391f,
--0.0415039f, 0.297607f, -0.0537109f, 0.319824f, -0.065918f, 0.340332f, -0.0922852f,
-0.223145f, -0.456543f, 0.223145f, -0.353027f, 0.268555f, -0.423828f, 0.302734f, -0.447021f,
-0.336914f, -0.470215f, 0.368652f, -0.470215f, 0.395996f, -0.470215f, 0.412354f, -0.453369f,
-0.428711f, -0.436523f, 0.428711f, -0.405762f, 0.428711f, -0.373047f, 0.412842f, -0.35498f,
-0.396973f, -0.336914f, 0.374512f, -0.336914f, 0.348633f, -0.336914f, 0.32959f, -0.353516f,
-0.310547f, -0.370117f, 0.307129f, -0.37207f, 0.302246f, -0.375f, 0.295898f, -0.375f,
-0.281738f, -0.375f, 0.269043f, -0.364258f, 0.249023f, -0.347656f, 0.23877f, -0.316895f,
-0.223145f, -0.269531f, 0.223145f, -0.212402f, 0.223145f, -0.107422f, 0.223633f, -0.0800781f,
-0.223633f, -0.0522461f, 0.227051f, -0.0444336f, 0.23291f, -0.03125f, 0.244385f, -0.0251465f,
-0.255859f, -0.019043f, 0.283203f, -0.0175781f, 0.283203f, 0, 0.0366211f, 0, 0.0366211f,
--0.0175781f, 0.0664062f, -0.0200195f, 0.0769043f, -0.0339355f, 0.0874023f, -0.0478516f,
-0.0874023f, -0.107422f, 0.0874023f, -0.359863f, 0.0874023f, -0.398926f, 0.0834961f,
--0.409668f, 0.0786133f, -0.42334f, 0.0693359f, -0.429688f, 0.0600586f, -0.436035f,
-0.0366211f, -0.438477f, 0.0366211f, -0.456543f, 0.322266f, -0.469238f, 0.32959f,
--0.313477f, 0.312988f, -0.313477f, 0.283203f, -0.382812f, 0.251221f, -0.408203f,
-0.219238f, -0.433594f, 0.1875f, -0.433594f, 0.16748f, -0.433594f, 0.15332f, -0.420166f,
-0.13916f, -0.406738f, 0.13916f, -0.38916f, 0.13916f, -0.375977f, 0.148926f, -0.36377f,
-0.164551f, -0.34375f, 0.236328f, -0.295166f, 0.308105f, -0.246582f, 0.330811f, -0.212646f,
-0.353516f, -0.178711f, 0.353516f, -0.136719f, 0.353516f, -0.0986328f, 0.334473f,
--0.0620117f, 0.31543f, -0.0253906f, 0.280762f, -0.00585938f, 0.246094f, 0.0136719f,
-0.204102f, 0.0136719f, 0.171387f, 0.0136719f, 0.116699f, -0.00683594f, 0.102051f,
--0.012207f, 0.0966797f, -0.012207f, 0.0805664f, -0.012207f, 0.0698242f, 0.012207f,
-0.0537109f, 0.012207f, 0.0458984f, -0.151855f, 0.0625f, -0.151855f, 0.0844727f, -0.0874023f,
-0.122803f, -0.0551758f, 0.161133f, -0.0229492f, 0.195312f, -0.0229492f, 0.21875f,
--0.0229492f, 0.233643f, -0.0373535f, 0.248535f, -0.0517578f, 0.248535f, -0.0722656f,
-0.248535f, -0.0957031f, 0.233887f, -0.112793f, 0.219238f, -0.129883f, 0.168457f,
--0.164551f, 0.09375f, -0.216309f, 0.0717773f, -0.243652f, 0.0395508f, -0.283691f,
-0.0395508f, -0.332031f, 0.0395508f, -0.384766f, 0.0759277f, -0.42749f, 0.112305f,
--0.470215f, 0.181152f, -0.470215f, 0.218262f, -0.470215f, 0.25293f, -0.452148f, 0.266113f,
--0.444824f, 0.274414f, -0.444824f, 0.283203f, -0.444824f, 0.288574f, -0.448486f,
-0.293945f, -0.452148f, 0.305664f, -0.469238f, 0.214844f, -0.623535f, 0.214844f, -0.456543f,
-0.323242f, -0.456543f, 0.323242f, -0.408203f, 0.214844f, -0.408203f, 0.214844f, -0.126465f,
-0.214844f, -0.0869141f, 0.218506f, -0.0754395f, 0.222168f, -0.0639648f, 0.231445f,
--0.0568848f, 0.240723f, -0.0498047f, 0.248535f, -0.0498047f, 0.280273f, -0.0498047f,
-0.308594f, -0.0981445f, 0.323242f, -0.0874023f, 0.283691f, 0.00634766f, 0.194824f,
-0.00634766f, 0.151367f, 0.00634766f, 0.121338f, -0.0178223f, 0.0913086f, -0.0419922f,
-0.0830078f, -0.0717773f, 0.078125f, -0.0883789f, 0.078125f, -0.161621f, 0.078125f,
--0.408203f, 0.0185547f, -0.408203f, 0.0185547f, -0.425293f, 0.0800781f, -0.46875f,
-0.123291f, -0.516602f, 0.166504f, -0.564453f, 0.19873f, -0.623535f, 0.474609f, -0.456543f,
-0.474609f, -0.0991211f, 0.474609f, -0.046875f, 0.484375f, -0.0339355f, 0.494141f,
--0.0209961f, 0.523926f, -0.0175781f, 0.523926f, 0, 0.337891f, 0, 0.337891f, -0.0610352f,
-0.305176f, -0.0219727f, 0.272461f, -0.00415039f, 0.239746f, 0.0136719f, 0.199219f,
-0.0136719f, 0.160645f, 0.0136719f, 0.130615f, -0.0100098f, 0.100586f, -0.0336914f,
-0.090332f, -0.0654297f, 0.0800781f, -0.097168f, 0.0800781f, -0.17627f, 0.0800781f,
--0.357422f, 0.0800781f, -0.40918f, 0.0705566f, -0.421875f, 0.0610352f, -0.43457f,
-0.0307617f, -0.438477f, 0.0307617f, -0.456543f, 0.216797f, -0.456543f, 0.216797f,
--0.144531f, 0.216797f, -0.0957031f, 0.221436f, -0.081543f, 0.226074f, -0.0673828f,
-0.236084f, -0.0600586f, 0.246094f, -0.0527344f, 0.259277f, -0.0527344f, 0.276855f,
--0.0527344f, 0.291016f, -0.0620117f, 0.310547f, -0.074707f, 0.337891f, -0.113281f,
-0.337891f, -0.357422f, 0.337891f, -0.40918f, 0.328369f, -0.421875f, 0.318848f, -0.43457f,
-0.288574f, -0.438477f, 0.288574f, -0.456543f, 0.239746f, 0.0136719f, 0.0859375f,
--0.340332f, 0.0581055f, -0.404297f, 0.0424805f, -0.421387f, 0.03125f, -0.434082f,
-0.00927734f, -0.438477f, 0.00927734f, -0.456543f, 0.251953f, -0.456543f, 0.251953f,
--0.438477f, 0.229004f, -0.438477f, 0.220703f, -0.430176f, 0.208984f, -0.419434f,
-0.208984f, -0.404785f, 0.208984f, -0.386719f, 0.230469f, -0.336914f, 0.305664f, -0.165527f,
-0.365723f, -0.313477f, 0.391602f, -0.376953f, 0.391602f, -0.40332f, 0.391602f, -0.418457f,
-0.380615f, -0.427979f, 0.369629f, -0.4375f, 0.341797f, -0.438477f, 0.341797f, -0.456543f,
-0.491211f, -0.456543f, 0.491211f, -0.438477f, 0.469727f, -0.435547f, 0.456055f, -0.422363f,
-0.442383f, -0.40918f, 0.415039f, -0.344727f, 0.262695f, 0.0136719f, 0.486328f, 0.0136719f,
-0.361328f, -0.321289f, 0.23877f, 0.0136719f, 0.213379f, 0.0136719f, 0.0917969f, -0.317383f,
-0.0644531f, -0.393066f, 0.0454102f, -0.416016f, 0.0332031f, -0.431641f, 0.00830078f,
--0.438477f, 0.00830078f, -0.456543f, 0.23877f, -0.456543f, 0.23877f, -0.438477f,
-0.215332f, -0.438477f, 0.206543f, -0.431641f, 0.197754f, -0.424805f, 0.197754f, -0.416016f,
-0.197754f, -0.407715f, 0.213379f, -0.366211f, 0.280273f, -0.187988f, 0.344727f, -0.366211f,
-0.339844f, -0.37793f, 0.325195f, -0.414551f, 0.314209f, -0.424561f, 0.303223f, -0.43457f,
-0.280273f, -0.438477f, 0.280273f, -0.456543f, 0.51416f, -0.456543f, 0.51416f, -0.438477f,
-0.486816f, -0.437012f, 0.479492f, -0.430908f, 0.472168f, -0.424805f, 0.472168f, -0.413574f,
-0.472168f, -0.402832f, 0.486328f, -0.366211f, 0.550781f, -0.187988f, 0.609375f, -0.352051f,
-0.62207f, -0.387207f, 0.62207f, -0.399902f, 0.62207f, -0.418945f, 0.612793f, -0.427734f,
-0.603516f, -0.436523f, 0.57666f, -0.438477f, 0.57666f, -0.456543f, 0.711914f, -0.456543f,
-0.711914f, -0.438477f, 0.689453f, -0.435547f, 0.67627f, -0.422607f, 0.663086f, -0.409668f,
-0.64209f, -0.349121f, 0.51416f, 0.0136719f, 0.303711f, -0.279785f, 0.382812f, -0.129395f,
-0.423828f, -0.0507812f, 0.447754f, -0.0297852f, 0.460938f, -0.0185547f, 0.483887f,
--0.0175781f, 0.483887f, 0, 0.229492f, 0, 0.229492f, -0.0175781f, 0.259277f, -0.0200195f,
-0.266357f, -0.0253906f, 0.273438f, -0.0307617f, 0.273438f, -0.0400391f, 0.273438f,
--0.0537109f, 0.257812f, -0.0830078f, 0.218262f, -0.157227f, 0.18457f, -0.10791f,
-0.161621f, -0.0742188f, 0.158691f, -0.0678711f, 0.154785f, -0.0585938f, 0.154785f,
--0.0512695f, 0.154785f, -0.0400391f, 0.159424f, -0.0324707f, 0.164062f, -0.0249023f,
-0.172119f, -0.0212402f, 0.180176f, -0.0175781f, 0.20166f, -0.0175781f, 0.20166f,
-0, 0.0229492f, 0, 0.0229492f, -0.0175781f, 0.0561523f, -0.0175781f, 0.0837402f, -0.0358887f,
-0.111328f, -0.0541992f, 0.164062f, -0.131836f, 0.20166f, -0.1875f, 0.123047f, -0.333008f,
-0.0844727f, -0.404297f, 0.0654297f, -0.42041f, 0.0463867f, -0.436523f, 0.0229492f,
--0.438477f, 0.0229492f, -0.456543f, 0.275879f, -0.456543f, 0.275879f, -0.438477f,
-0.262695f, -0.437988f, 0.237305f, -0.429199f, 0.233398f, -0.425781f, 0.233398f, -0.417969f,
-0.233398f, -0.410645f, 0.23584f, -0.402832f, 0.237305f, -0.399414f, 0.249512f, -0.376465f,
-0.285156f, -0.310059f, 0.303711f, -0.336426f, 0.342773f, -0.390137f, 0.342773f, -0.411621f,
-0.342773f, -0.421875f, 0.334229f, -0.428955f, 0.325684f, -0.436035f, 0.303711f, -0.438477f,
-0.303711f, -0.456543f, 0.465332f, -0.456543f, 0.465332f, -0.438477f, 0.435547f, -0.4375f,
-0.409668f, -0.420166f, 0.383789f, -0.402832f, 0.351562f, -0.353027f, 0.243164f, 0.0185547f,
-0.0957031f, -0.319824f, 0.0625f, -0.396484f, 0.0466309f, -0.414062f, 0.0307617f,
--0.431641f, 0.00830078f, -0.438477f, 0.00830078f, -0.456543f, 0.250977f, -0.456543f,
-0.250977f, -0.438477f, 0.227051f, -0.4375f, 0.217285f, -0.429199f, 0.20752f, -0.420898f,
-0.20752f, -0.40918f, 0.20752f, -0.390625f, 0.231934f, -0.335938f, 0.310059f, -0.157227f,
-0.363281f, -0.29541f, 0.39209f, -0.369141f, 0.39209f, -0.397949f, 0.39209f, -0.416016f,
-0.380127f, -0.426758f, 0.368164f, -0.4375f, 0.337891f, -0.438477f, 0.337891f, -0.456543f,
-0.490723f, -0.456543f, 0.490723f, -0.438477f, 0.468262f, -0.436035f, 0.454102f, -0.421143f,
-0.439941f, -0.40625f, 0.406738f, -0.319824f, 0.276367f, 0.0185547f, 0.227051f, 0.145508f,
-0.203125f, 0.174805f, 0.169434f, 0.21582f, 0.118652f, 0.21582f, 0.078125f, 0.21582f,
-0.0529785f, 0.192627f, 0.027832f, 0.169434f, 0.027832f, 0.136719f, 0.027832f, 0.108398f,
-0.045166f, 0.0898438f, 0.0625f, 0.0712891f, 0.0878906f, 0.0712891f, 0.112305f, 0.0712891f,
-0.127197f, 0.0869141f, 0.14209f, 0.102539f, 0.142578f, 0.135254f, 0.143066f, 0.153809f,
-0.146973f, 0.15918f, 0.150879f, 0.164551f, 0.158203f, 0.164551f, 0.169922f, 0.164551f,
-0.183105f, 0.150391f, 0.202637f, 0.129883f, 0.229004f, 0.0566406f, 0.407715f, 0,
-0.0102539f, 0, 0.0102539f, -0.0107422f, 0.26123f, -0.426758f, 0.187988f, -0.426758f,
-0.140625f, -0.426758f, 0.120117f, -0.418213f, 0.0996094f, -0.409668f, 0.0869141f,
--0.390869f, 0.0742188f, -0.37207f, 0.0605469f, -0.32373f, 0.043457f, -0.32373f, 0.043457f,
--0.456543f, 0.427734f, -0.456543f, 0.427734f, -0.443359f, 0.178711f, -0.03125f, 0.209961f,
--0.03125f, 0.303711f, -0.03125f, 0.345215f, -0.0581055f, 0.386719f, -0.0849609f,
-0.407715f, -0.15625f, 0.421387f, -0.15625f
-};
-
-const unsigned char TimesNewRomankBoldVerbs[] = {
-6, 0, 1, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1,
-1, 2, 2, 2, 2, 2, 2, 5, 0, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1, 1, 1, 5, 6,
-0, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 1, 1, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 5, 6,
-0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1,
-1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 5, 6, 0, 1, 2,
-2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 1, 1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 1,
-1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0,
-1, 1, 1, 5, 0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1,
-1, 1, 2, 2, 2, 2, 5, 0, 1, 1, 5, 6, 0, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1,
-1, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 5, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2,
-1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2,
-2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1,
-1, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1,
-1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1,
-1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2,
-1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 1,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 5, 6, 0, 1, 2, 2,
-1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1,
-2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2,
-1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 1,
-2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
-1, 2, 2, 2, 1, 1, 1, 5, 6, 0, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1,
-1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2,
-2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2,
-2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 5, 0, 1, 1, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1,
-1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 5, 6, 0, 1, 2,
-2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2,
-2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2,
-2, 2, 1, 1, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1,
-1, 2, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2,
-1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2,
-2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1,
-5, 6, 0, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 1, 1, 1, 5, 6,
-0, 1, 1, 1, 5, 6, 0, 1, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2,
-5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 5, 0, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1,
-5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-5, 0, 2, 2, 2, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2,
-2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1,
-5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 5, 6,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1,
-1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1,
-1, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2,
-2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1,
-1, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2,
-2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 5, 0, 1, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1,
-2, 2, 1, 2, 2, 2, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
-1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 1, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1,
-2, 2, 2, 1, 1, 1, 2, 2, 1, 5, 6, 0, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1,
-2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 1, 1,
-1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2,
-2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2,
-2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 1, 2,
-2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 5, 6
-};
-
-const unsigned TimesNewRomankBoldCharCodes[] = {
-32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
-43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
-83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
-103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
-119, 120, 121, 122
-};
-
-const SkFixed TimesNewRomankBoldWidths[] = {
-0x00004000, 0x00005540, 0x00008e20, 0x00008000, 0x00008000, 0x00010000, 0x0000d540,
-0x00004720, 0x00005540, 0x00005540, 0x00008000, 0x000091e0, 0x00004000, 0x00005540,
-0x00004000, 0x00004720, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000,
-0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00005540, 0x00005540,
-0x000091e0, 0x000091e0, 0x000091e0, 0x00008000, 0x0000ee20, 0x0000b8e0, 0x0000aac0,
-0x0000b8e0, 0x0000b8e0, 0x0000aac0, 0x00009c60, 0x0000c720, 0x0000c720, 0x000063a0,
-0x00008000, 0x0000c720, 0x0000aac0, 0x0000f1a0, 0x0000b8e0, 0x0000c720, 0x00009c60,
-0x0000c720, 0x0000b8e0, 0x00008e60, 0x0000aac0, 0x0000b8e0, 0x0000b8e0, 0x00010000,
-0x0000b8e0, 0x0000b8e0, 0x0000aac0, 0x00005540, 0x00004720, 0x00005540, 0x000094c0,
-0x00008000, 0x00005540, 0x00008000, 0x00008e60, 0x000071a0, 0x00008e60, 0x000071a0,
-0x00005540, 0x00008000, 0x00008e60, 0x00004720, 0x00005540, 0x00008e60, 0x00004720,
-0x0000d540, 0x00008e60, 0x00008000, 0x00008e60, 0x00008e60, 0x000071a0, 0x000063a0,
-0x00005540, 0x00008e60, 0x00008000, 0x0000b8e0, 0x00008000, 0x00008000, 0x000071a0
-};
-
-const int TimesNewRomankBoldCharCodesCount = (int) SK_ARRAY_COUNT(TimesNewRomankBoldCharCodes);
-
-const SkPaint::FontMetrics TimesNewRomankBoldMetrics = {
-0x08636967, -1.02588f, -0.891113f, 0.216309f, 0.306641f, 0.0424805f, 2.55811f, 2.57616e+24f,
--0.558105f, 2, 0.470215f, 4.25072e-38f, 0.0952148f, 0.108887f
-};
-
-const SkScalar TimesNewRomankItalicPoints[] = {
-0.515137f, -0.677246f, 0.464844f, -0.126465f, 0.460938f, -0.0878906f, 0.460938f, -0.0756836f,
-0.460938f, -0.0561523f, 0.468262f, -0.0458984f, 0.477539f, -0.0317383f, 0.493408f,
--0.0249023f, 0.509277f, -0.0180664f, 0.546875f, -0.0180664f, 0.541504f, 0, 0.280762f,
-0, 0.286133f, -0.0180664f, 0.297363f, -0.0180664f, 0.329102f, -0.0180664f, 0.349121f,
--0.0317383f, 0.363281f, -0.0410156f, 0.371094f, -0.0625f, 0.376465f, -0.0776367f,
-0.381348f, -0.133789f, 0.38916f, -0.217773f, 0.199707f, -0.217773f, 0.132324f, -0.126465f,
-0.109375f, -0.0957031f, 0.103516f, -0.0822754f, 0.0976562f, -0.0688477f, 0.0976562f,
--0.0571289f, 0.0976562f, -0.0415039f, 0.110352f, -0.0302734f, 0.123047f, -0.019043f,
-0.152344f, -0.0180664f, 0.146973f, 0, -0.0488281f, 0, -0.043457f, -0.0180664f, -0.00732422f,
--0.0195312f, 0.0202637f, -0.0422363f, 0.0478516f, -0.0649414f, 0.102539f, -0.13916f,
-0.498047f, -0.677246f, 0.418457f, -0.514648f, 0.226562f, -0.253418f, 0.393066f, -0.253418f,
-0.246582f, -0.366699f, 0.552246f, -0.366699f, 0.600586f, -0.530273f, 0.614258f, -0.578125f,
-0.614258f, -0.604492f, 0.614258f, -0.617188f, 0.608154f, -0.626221f, 0.602051f, -0.635254f,
-0.589355f, -0.639648f, 0.57666f, -0.644043f, 0.539551f, -0.644043f, 0.544434f, -0.662109f,
-0.811035f, -0.662109f, 0.805176f, -0.644043f, 0.771484f, -0.644531f, 0.754883f, -0.637207f,
-0.731445f, -0.626953f, 0.720215f, -0.61084f, 0.704102f, -0.587891f, 0.6875f, -0.530273f,
-0.570801f, -0.130371f, 0.556152f, -0.0805664f, 0.556152f, -0.059082f, 0.556152f,
--0.0405273f, 0.569092f, -0.0310059f, 0.582031f, -0.0214844f, 0.630859f, -0.0180664f,
-0.625488f, 0, 0.367676f, 0, 0.374512f, -0.0180664f, 0.412598f, -0.019043f, 0.425293f,
--0.0249023f, 0.444824f, -0.0336914f, 0.453613f, -0.0473633f, 0.466309f, -0.0664062f,
-0.484863f, -0.130371f, 0.544434f, -0.333008f, 0.237305f, -0.333008f, 0.177246f, -0.130371f,
-0.163086f, -0.081543f, 0.163086f, -0.059082f, 0.163086f, -0.0405273f, 0.175781f,
--0.0310059f, 0.188477f, -0.0214844f, 0.237305f, -0.0180664f, 0.233398f, 0, -0.0263672f,
-0, -0.0200195f, -0.0180664f, 0.0185547f, -0.019043f, 0.03125f, -0.0249023f, 0.0507812f,
--0.0336914f, 0.0600586f, -0.0473633f, 0.0727539f, -0.0673828f, 0.0913086f, -0.130371f,
-0.208496f, -0.530273f, 0.222656f, -0.579102f, 0.222656f, -0.604492f, 0.222656f, -0.617188f,
-0.216553f, -0.626221f, 0.210449f, -0.635254f, 0.19751f, -0.639648f, 0.18457f, -0.644043f,
-0.146973f, -0.644043f, 0.152832f, -0.662109f, 0.414062f, -0.662109f, 0.408691f, -0.644043f,
-0.375977f, -0.644531f, 0.360352f, -0.637207f, 0.337402f, -0.627441f, 0.32666f, -0.611328f,
-0.312012f, -0.589844f, 0.294434f, -0.530273f, 0.146484f, -0.662109f, 0.649414f, -0.662109f,
-0.595215f, -0.486328f, 0.57666f, -0.486328f, 0.585938f, -0.524902f, 0.585938f, -0.555176f,
-0.585938f, -0.59082f, 0.563965f, -0.608887f, 0.547363f, -0.622559f, 0.478516f, -0.622559f,
-0.42627f, -0.622559f, 0.29541f, -0.166504f, 0.270508f, -0.0805664f, 0.270508f, -0.0605469f,
-0.270508f, -0.0419922f, 0.286133f, -0.0300293f, 0.301758f, -0.0180664f, 0.341309f,
--0.0180664f, 0.36377f, -0.0180664f, 0.35791f, 0, 0.0698242f, 0, 0.0751953f, -0.0180664f,
-0.0878906f, -0.0180664f, 0.125977f, -0.0180664f, 0.146484f, -0.0302734f, 0.160645f,
--0.0385742f, 0.172119f, -0.0603027f, 0.183594f, -0.0820312f, 0.204102f, -0.152344f,
-0.341309f, -0.622559f, 0.301758f, -0.622559f, 0.244629f, -0.622559f, 0.209717f, -0.60791f,
-0.174805f, -0.593262f, 0.15332f, -0.56543f, 0.131836f, -0.537598f, 0.118164f, -0.486328f,
-0.100098f, -0.486328f, 0.135254f, 0.0151367f, 0.192383f, -0.536621f, 0.195801f, -0.568359f,
-0.195801f, -0.585449f, 0.195801f, -0.61377f, 0.179688f, -0.628418f, 0.163574f, -0.643066f,
-0.121582f, -0.644043f, 0.126953f, -0.662109f, 0.375f, -0.662109f, 0.369629f, -0.644043f,
-0.319824f, -0.644531f, 0.301514f, -0.626221f, 0.283203f, -0.60791f, 0.276367f, -0.536621f,
-0.239746f, -0.179199f, 0.491211f, -0.567383f, 0.491699f, -0.577148f, 0.491699f, -0.583984f,
-0.491699f, -0.611328f, 0.475586f, -0.625977f, 0.459473f, -0.640625f, 0.40625f, -0.644043f,
-0.410156f, -0.662109f, 0.678223f, -0.662109f, 0.672852f, -0.644043f, 0.626465f, -0.643555f,
-0.610352f, -0.63623f, 0.598633f, -0.630859f, 0.590576f, -0.618896f, 0.58252f, -0.606934f,
-0.577637f, -0.578125f, 0.576172f, -0.569824f, 0.565674f, -0.464844f, 0.555176f, -0.359863f,
-0.53418f, -0.179199f, 0.743652f, -0.497559f, 0.777832f, -0.549805f, 0.786621f, -0.570801f,
-0.79541f, -0.591797f, 0.79541f, -0.606445f, 0.79541f, -0.620117f, 0.783691f, -0.630615f,
-0.771973f, -0.641113f, 0.743652f, -0.644043f, 0.747559f, -0.662109f, 0.943848f, -0.662109f,
-0.938965f, -0.644043f, 0.913086f, -0.64209f, 0.893066f, -0.631348f, 0.873047f, -0.620605f,
-0.845703f, -0.590332f, 0.830078f, -0.572754f, 0.78125f, -0.497559f, 0.44873f, 0.0151367f,
-0.430664f, 0.0151367f, 0.484375f, -0.497559f, 0.151855f, 0.0151367f, 0.349609f, -0.352051f,
-0.475586f, -0.52832f, 0.524414f, -0.597168f, 0.524414f, -0.616211f, 0.524414f, -0.626953f,
-0.513916f, -0.634033f, 0.503418f, -0.641113f, 0.454102f, -0.644043f, 0.458984f, -0.662109f,
-0.666992f, -0.662109f, 0.663086f, -0.644043f, 0.632812f, -0.640137f, 0.621582f, -0.635742f,
-0.604004f, -0.628418f, 0.586914f, -0.612793f, 0.563965f, -0.592285f, 0.520508f, -0.532227f,
-0.358398f, -0.308594f, 0.30957f, -0.14502f, 0.291504f, -0.0834961f, 0.291504f, -0.0600586f,
-0.291504f, -0.0449219f, 0.297119f, -0.0371094f, 0.302734f, -0.0292969f, 0.316895f,
--0.0244141f, 0.335449f, -0.0185547f, 0.373535f, -0.0180664f, 0.368652f, 0, 0.0898438f,
-0, 0.0957031f, -0.0180664f, 0.137207f, -0.019043f, 0.150879f, -0.0249023f, 0.172852f,
--0.0336914f, 0.183594f, -0.0483398f, 0.200195f, -0.0708008f, 0.217773f, -0.128906f,
-0.275879f, -0.322266f, 0.205078f, -0.550781f, 0.186035f, -0.611328f, 0.170166f, -0.625977f,
-0.154297f, -0.640625f, 0.114746f, -0.644043f, 0.119629f, -0.662109f, 0.364258f, -0.662109f,
-0.358398f, -0.644043f, 0.3125f, -0.640625f, 0.306152f, -0.638184f, 0.29541f, -0.634766f,
-0.288574f, -0.624512f, 0.281738f, -0.614258f, 0.281738f, -0.600586f, 0.281738f, -0.580566f,
-0.295898f, -0.532227f, 0.469238f, -0.441895f, 0.374023f, -0.11084f, 0.363281f, -0.0664062f,
-0.361816f, -0.0600586f, 0.361816f, -0.0556641f, 0.361816f, -0.0478516f, 0.366699f,
--0.0419922f, 0.370605f, -0.0375977f, 0.376465f, -0.0375977f, 0.382812f, -0.0375977f,
-0.393066f, -0.0454102f, 0.412109f, -0.0595703f, 0.443848f, -0.104004f, 0.460449f,
--0.0922852f, 0.426758f, -0.0415039f, 0.391113f, -0.0148926f, 0.355469f, 0.0117188f,
-0.325195f, 0.0117188f, 0.304199f, 0.0117188f, 0.293701f, 0.0012207f, 0.283203f, -0.00927734f,
-0.283203f, -0.0292969f, 0.283203f, -0.0532227f, 0.293945f, -0.0922852f, 0.304199f,
--0.128906f, 0.240234f, -0.0454102f, 0.186523f, -0.012207f, 0.147949f, 0.0117188f,
-0.11084f, 0.0117188f, 0.0751953f, 0.0117188f, 0.0493164f, -0.0178223f, 0.0234375f,
--0.0473633f, 0.0234375f, -0.0991211f, 0.0234375f, -0.176758f, 0.0700684f, -0.262939f,
-0.116699f, -0.349121f, 0.188477f, -0.400879f, 0.244629f, -0.441895f, 0.294434f, -0.441895f,
-0.324219f, -0.441895f, 0.343994f, -0.42627f, 0.36377f, -0.410645f, 0.374023f, -0.374512f,
-0.391602f, -0.430176f, 0.29541f, -0.416504f, 0.26416f, -0.416504f, 0.229004f, -0.387207f,
-0.179199f, -0.345703f, 0.140381f, -0.26416f, 0.101562f, -0.182617f, 0.101562f, -0.116699f,
-0.101562f, -0.0834961f, 0.118164f, -0.064209f, 0.134766f, -0.0449219f, 0.15625f,
--0.0449219f, 0.209473f, -0.0449219f, 0.271973f, -0.123535f, 0.355469f, -0.228027f,
-0.355469f, -0.337891f, 0.355469f, -0.379395f, 0.339355f, -0.397949f, 0.323242f, -0.416504f,
-0.29541f, -0.416504f, 0.288574f, -0.694336f, 0.192383f, -0.356934f, 0.239258f, -0.405762f,
-0.27417f, -0.423828f, 0.309082f, -0.441895f, 0.347168f, -0.441895f, 0.400879f, -0.441895f,
-0.435059f, -0.40625f, 0.469238f, -0.370605f, 0.469238f, -0.30957f, 0.469238f, -0.230957f,
-0.424316f, -0.153076f, 0.379395f, -0.0751953f, 0.311523f, -0.0317383f, 0.243652f,
-0.0117188f, 0.177734f, 0.0117188f, 0.104004f, 0.0117188f, 0.0263672f, -0.043457f,
-0.174805f, -0.554688f, 0.191895f, -0.61377f, 0.191895f, -0.624023f, 0.191895f, -0.636719f,
-0.184082f, -0.643066f, 0.172852f, -0.651855f, 0.150879f, -0.651855f, 0.140625f, -0.651855f,
-0.119629f, -0.648438f, 0.119629f, -0.666992f, 0.0996094f, -0.0380859f, 0.148438f,
--0.0112305f, 0.185547f, -0.0112305f, 0.228516f, -0.0112305f, 0.274658f, -0.0427246f,
-0.320801f, -0.0742188f, 0.354736f, -0.148926f, 0.388672f, -0.223633f, 0.388672f,
--0.299805f, 0.388672f, -0.344727f, 0.366455f, -0.370117f, 0.344238f, -0.395508f,
-0.313965f, -0.395508f, 0.268555f, -0.395508f, 0.225098f, -0.359131f, 0.181641f, -0.322754f,
-0.163086f, -0.257812f, 0.119141f, -0.184082f, 0.115723f, -0.159668f, 0.115723f, -0.143555f,
-0.115723f, -0.100098f, 0.146484f, -0.0695801f, 0.177246f, -0.0390625f, 0.221191f,
--0.0390625f, 0.256348f, -0.0390625f, 0.288818f, -0.0534668f, 0.321289f, -0.0678711f,
-0.385254f, -0.117188f, 0.395508f, -0.103027f, 0.279785f, 0.0117188f, 0.174805f, 0.0117188f,
-0.103516f, 0.0117188f, 0.0673828f, -0.0332031f, 0.03125f, -0.078125f, 0.03125f, -0.132324f,
-0.03125f, -0.205078f, 0.0761719f, -0.28125f, 0.121094f, -0.357422f, 0.188965f, -0.399658f,
-0.256836f, -0.441895f, 0.328613f, -0.441895f, 0.380371f, -0.441895f, 0.405273f, -0.420898f,
-0.430176f, -0.399902f, 0.430176f, -0.371094f, 0.430176f, -0.330566f, 0.397949f, -0.293457f,
-0.355469f, -0.245117f, 0.272949f, -0.215332f, 0.218262f, -0.195312f, 0.119141f, -0.184082f,
-0.122559f, -0.208008f, 0.194824f, -0.216309f, 0.240234f, -0.236328f, 0.300293f, -0.263184f,
-0.330322f, -0.300537f, 0.360352f, -0.337891f, 0.360352f, -0.371582f, 0.360352f, -0.39209f,
-0.347412f, -0.404785f, 0.334473f, -0.41748f, 0.310547f, -0.41748f, 0.260742f, -0.41748f,
-0.204834f, -0.364502f, 0.148926f, -0.311523f, 0.122559f, -0.208008f, 0.296387f, -0.430176f,
-0.287598f, -0.397949f, 0.216309f, -0.397949f, 0.162598f, -0.18457f, 0.126953f, -0.043457f,
-0.0908203f, 0.0336914f, 0.0395508f, 0.142578f, -0.0195312f, 0.184082f, -0.0644531f,
-0.21582f, -0.109375f, 0.21582f, -0.138672f, 0.21582f, -0.15918f, 0.198242f, -0.174316f,
-0.186035f, -0.174316f, 0.166504f, -0.174316f, 0.150879f, -0.161865f, 0.139404f, -0.149414f,
-0.12793f, -0.131348f, 0.12793f, -0.118164f, 0.12793f, -0.109131f, 0.13623f, -0.100098f,
-0.144531f, -0.100098f, 0.155273f, -0.100098f, 0.166016f, -0.110352f, 0.175293f, -0.118164f,
-0.182129f, -0.118164f, 0.185547f, -0.118164f, 0.189941f, -0.114746f, 0.192383f, -0.110352f,
-0.195801f, -0.101074f, 0.195801f, -0.0800781f, 0.195801f, -0.0568848f, 0.182617f,
--0.0336914f, 0.169434f, -0.015625f, 0.143311f, 0.00244141f, 0.117188f, 0.0185547f,
-0.0678711f, 0.0253906f, 0.0473633f, 0.0551758f, -0.0673828f, 0.140137f, -0.397949f,
-0.0551758f, -0.397949f, 0.0620117f, -0.430176f, 0.102539f, -0.430176f, 0.118652f,
--0.435791f, 0.134766f, -0.441406f, 0.148193f, -0.457275f, 0.161621f, -0.473145f,
-0.183105f, -0.516602f, 0.211914f, -0.575195f, 0.238281f, -0.607422f, 0.274414f, -0.650879f,
-0.314209f, -0.672607f, 0.354004f, -0.694336f, 0.38916f, -0.694336f, 0.42627f, -0.694336f,
-0.44873f, -0.675537f, 0.471191f, -0.656738f, 0.471191f, -0.634766f, 0.471191f, -0.617676f,
-0.459961f, -0.605957f, 0.44873f, -0.594238f, 0.431152f, -0.594238f, 0.416016f, -0.594238f,
-0.406494f, -0.603027f, 0.396973f, -0.611816f, 0.396973f, -0.624023f, 0.396973f, -0.631836f,
-0.40332f, -0.643311f, 0.409668f, -0.654785f, 0.409668f, -0.658691f, 0.409668f, -0.665527f,
-0.405273f, -0.668945f, 0.398926f, -0.673828f, 0.386719f, -0.673828f, 0.355957f, -0.673828f,
-0.331543f, -0.654297f, 0.298828f, -0.628418f, 0.272949f, -0.573242f, 0.259766f, -0.544434f,
-0.224609f, -0.430176f, 0.520996f, -0.411621f, 0.506836f, -0.36084f, 0.425293f, -0.36084f,
-0.43457f, -0.334473f, 0.43457f, -0.311523f, 0.43457f, -0.24707f, 0.379883f, -0.196777f,
-0.324707f, -0.146484f, 0.228516f, -0.141113f, 0.176758f, -0.125488f, 0.150879f, -0.104004f,
-0.141113f, -0.0961914f, 0.141113f, -0.0878906f, 0.141113f, -0.078125f, 0.149902f,
--0.0700684f, 0.158691f, -0.0620117f, 0.194336f, -0.0537109f, 0.289062f, -0.0317383f,
-0.367676f, -0.0131836f, 0.393066f, 0.012207f, 0.417969f, 0.0380859f, 0.417969f, 0.0717773f,
-0.417969f, 0.111816f, 0.388428f, 0.14502f, 0.358887f, 0.178223f, 0.302002f, 0.197021f,
-0.245117f, 0.21582f, 0.17627f, 0.21582f, 0.115723f, 0.21582f, 0.065918f, 0.201416f,
-0.0161133f, 0.187012f, -0.00537109f, 0.162598f, -0.0268555f, 0.138184f, -0.0268555f,
-0.112305f, -0.0268555f, 0.0913086f, -0.0129395f, 0.0686035f, 0.000976562f, 0.0458984f,
-0.0219727f, 0.03125f, 0.0351562f, 0.0219727f, 0.0966797f, -0.0126953f, 0.0742188f,
--0.0302734f, 0.0742188f, -0.0512695f, 0.0742188f, -0.0708008f, 0.0939941f, -0.0927734f,
-0.11377f, -0.114746f, 0.177734f, -0.141113f, 0.124023f, -0.151367f, 0.0925293f, -0.186035f,
-0.0610352f, -0.220703f, 0.0610352f, -0.263184f, 0.0610352f, -0.33252f, 0.121826f,
--0.387207f, 0.182617f, -0.441895f, 0.283691f, -0.441895f, 0.320312f, -0.441895f,
-0.34375f, -0.43457f, 0.367188f, -0.427246f, 0.38916f, -0.411621f, 0.351562f, -0.334961f,
-0.351562f, -0.374023f, 0.329834f, -0.396484f, 0.308105f, -0.418945f, 0.272949f, -0.418945f,
-0.217773f, -0.418945f, 0.181885f, -0.363525f, 0.145996f, -0.308105f, 0.145996f, -0.248047f,
-0.145996f, -0.210449f, 0.168945f, -0.186523f, 0.191895f, -0.162598f, 0.224609f, -0.162598f,
-0.250488f, -0.162598f, 0.274658f, -0.176758f, 0.298828f, -0.190918f, 0.31543f, -0.21582f,
-0.332031f, -0.240723f, 0.341797f, -0.279297f, 0.351562f, -0.317871f, 0.351562f, -0.334961f,
-0.117676f, 0, 0.078125f, 0.0180664f, 0.0578613f, 0.0463867f, 0.0375977f, 0.074707f,
-0.0375977f, 0.102051f, 0.0375977f, 0.134277f, 0.0668945f, 0.155273f, 0.108887f, 0.185547f,
-0.189941f, 0.185547f, 0.259766f, 0.185547f, 0.309326f, 0.161865f, 0.358887f, 0.138184f,
-0.358887f, 0.100586f, 0.358887f, 0.081543f, 0.340576f, 0.0644531f, 0.322266f, 0.0473633f,
-0.269531f, 0.0366211f, 0.240723f, 0.0307617f, 0.117676f, 0, 0.216797f, -0.441895f,
-0.15332f, -0.22168f, 0.195801f, -0.299316f, 0.225586f, -0.338379f, 0.271973f, -0.398926f,
-0.315918f, -0.42627f, 0.341797f, -0.441895f, 0.370117f, -0.441895f, 0.394531f, -0.441895f,
-0.410645f, -0.42627f, 0.426758f, -0.410645f, 0.426758f, -0.38623f, 0.426758f, -0.362305f,
-0.415527f, -0.32373f, 0.380859f, -0.199707f, 0.460449f, -0.348633f, 0.531738f, -0.408691f,
-0.571289f, -0.441895f, 0.609863f, -0.441895f, 0.632324f, -0.441895f, 0.646729f, -0.426514f,
-0.661133f, -0.411133f, 0.661133f, -0.378906f, 0.661133f, -0.350586f, 0.652344f, -0.318848f,
-0.598633f, -0.128906f, 0.581055f, -0.0668945f, 0.581055f, -0.0600586f, 0.581055f,
--0.0532227f, 0.585449f, -0.0483398f, 0.588379f, -0.0449219f, 0.593262f, -0.0449219f,
-0.598145f, -0.0449219f, 0.610352f, -0.0541992f, 0.638184f, -0.0756836f, 0.662598f,
--0.11084f, 0.678711f, -0.100586f, 0.666504f, -0.0810547f, 0.635498f, -0.046875f,
-0.604492f, -0.0126953f, 0.58252f, -0.000488281f, 0.560547f, 0.0117188f, 0.541992f,
-0.0117188f, 0.524902f, 0.0117188f, 0.513428f, 0, 0.501953f, -0.0117188f, 0.501953f,
--0.0288086f, 0.501953f, -0.0522461f, 0.521973f, -0.123047f, 0.566406f, -0.279785f,
-0.581543f, -0.333984f, 0.58252f, -0.339844f, 0.583984f, -0.349121f, 0.583984f, -0.35791f,
-0.583984f, -0.370117f, 0.578613f, -0.376953f, 0.572754f, -0.383789f, 0.56543f, -0.383789f,
-0.544922f, -0.383789f, 0.521973f, -0.362793f, 0.45459f, -0.300781f, 0.395996f, -0.188965f,
-0.357422f, -0.115234f, 0.32373f, 0, 0.25f, 0, 0.333496f, -0.29541f, 0.347168f, -0.343262f,
-0.347168f, -0.359375f, 0.347168f, -0.372559f, 0.341797f, -0.378906f, 0.336426f, -0.385254f,
-0.328613f, -0.385254f, 0.3125f, -0.385254f, 0.294434f, -0.373535f, 0.265137f, -0.354492f,
-0.218994f, -0.291992f, 0.172852f, -0.229492f, 0.147461f, -0.172363f, 0.135254f, -0.145508f,
-0.0893555f, 0, 0.0170898f, 0, 0.107422f, -0.316406f, 0.119141f, -0.357422f, 0.122559f,
--0.366699f, 0.122559f, -0.371094f, 0.122559f, -0.381836f, 0.112793f, -0.390381f,
-0.103027f, -0.398926f, 0.0878906f, -0.398926f, 0.081543f, -0.398926f, 0.0527344f,
--0.393066f, 0.0483398f, -0.411133f, 0.220703f, -0.441895f, 0.155762f, -0.219727f,
-0.24707f, -0.355957f, 0.295654f, -0.398926f, 0.344238f, -0.441895f, 0.38916f, -0.441895f,
-0.413574f, -0.441895f, 0.429443f, -0.425781f, 0.445312f, -0.409668f, 0.445312f, -0.383789f,
-0.445312f, -0.354492f, 0.431152f, -0.305664f, 0.371582f, -0.100098f, 0.361328f, -0.0644531f,
-0.361328f, -0.0566406f, 0.361328f, -0.0498047f, 0.365234f, -0.045166f, 0.369141f,
--0.0405273f, 0.373535f, -0.0405273f, 0.379395f, -0.0405273f, 0.387695f, -0.046875f,
-0.413574f, -0.0673828f, 0.444336f, -0.109375f, 0.459473f, -0.100098f, 0.414062f,
--0.0351562f, 0.373535f, -0.00732422f, 0.345215f, 0.0117188f, 0.322754f, 0.0117188f,
-0.304688f, 0.0117188f, 0.293945f, 0.000732422f, 0.283203f, -0.0102539f, 0.283203f,
--0.0288086f, 0.283203f, -0.0522461f, 0.299805f, -0.109375f, 0.356445f, -0.305664f,
-0.367188f, -0.342285f, 0.367188f, -0.362793f, 0.367188f, -0.372559f, 0.36084f, -0.378662f,
-0.354492f, -0.384766f, 0.345215f, -0.384766f, 0.331543f, -0.384766f, 0.3125f, -0.373047f,
-0.276367f, -0.351074f, 0.237305f, -0.300537f, 0.198242f, -0.25f, 0.154785f, -0.171387f,
-0.131836f, -0.129883f, 0.116699f, -0.0805664f, 0.0922852f, 0, 0.019043f, 0, 0.10791f,
--0.305664f, 0.123535f, -0.36084f, 0.123535f, -0.37207f, 0.123535f, -0.382812f, 0.11499f,
--0.390869f, 0.106445f, -0.398926f, 0.09375f, -0.398926f, 0.0878906f, -0.398926f,
-0.0732422f, -0.396973f, 0.0546875f, -0.394043f, 0.0517578f, -0.411621f, 0.462402f,
--0.289062f, 0.462402f, -0.21582f, 0.423584f, -0.144043f, 0.384766f, -0.0722656f,
-0.31543f, -0.0302734f, 0.246094f, 0.0117188f, 0.180664f, 0.0117188f, 0.11377f, 0.0117188f,
-0.0715332f, -0.0310059f, 0.0292969f, -0.0737305f, 0.0292969f, -0.141602f, 0.0292969f,
--0.213379f, 0.0705566f, -0.285645f, 0.111816f, -0.35791f, 0.180908f, -0.399902f,
-0.25f, -0.441895f, 0.314453f, -0.441895f, 0.378906f, -0.441895f, 0.420654f, -0.399414f,
-0.462402f, -0.356934f, 0.462402f, -0.289062f, 0.381348f, -0.322754f, 0.381348f, -0.368164f,
-0.359131f, -0.392334f, 0.336914f, -0.416504f, 0.301758f, -0.416504f, 0.22998f, -0.416504f,
-0.169678f, -0.313721f, 0.109375f, -0.210938f, 0.109375f, -0.109375f, 0.109375f, -0.0629883f,
-0.132812f, -0.0378418f, 0.15625f, -0.0126953f, 0.191895f, -0.0126953f, 0.260742f,
--0.0126953f, 0.321045f, -0.11499f, 0.381348f, -0.217285f, 0.381348f, -0.322754f,
-0.221191f, -0.441895f, 0.1875f, -0.32959f, 0.240723f, -0.39209f, 0.282471f, -0.416992f,
-0.324219f, -0.441895f, 0.367676f, -0.441895f, 0.411133f, -0.441895f, 0.441895f, -0.407471f,
-0.472656f, -0.373047f, 0.472656f, -0.317871f, 0.472656f, -0.210449f, 0.385254f, -0.0993652f,
-0.297852f, 0.0117188f, 0.181641f, 0.0117188f, 0.157227f, 0.0117188f, 0.138428f, 0.00634766f,
-0.119629f, 0.000976562f, 0.0961914f, -0.0126953f, 0.0605469f, 0.113281f, 0.0498047f,
-0.150391f, 0.0498047f, 0.161621f, 0.0498047f, 0.172363f, 0.0554199f, 0.179932f, 0.0610352f,
-0.1875f, 0.0737305f, 0.19165f, 0.0864258f, 0.195801f, 0.124023f, 0.195801f, 0.119629f,
-0.213867f, -0.110352f, 0.213867f, -0.105469f, 0.195801f, -0.0600586f, 0.193848f,
--0.0441895f, 0.180176f, -0.0283203f, 0.166504f, -0.0107422f, 0.104492f, 0.112793f,
--0.323242f, 0.124023f, -0.36377f, 0.124023f, -0.373535f, 0.124023f, -0.386719f, 0.116455f,
--0.394043f, 0.108887f, -0.401367f, 0.0932617f, -0.401367f, 0.0791016f, -0.401367f,
-0.0537109f, -0.397949f, 0.0537109f, -0.416992f, 0.107422f, -0.0512695f, 0.137695f,
--0.0151367f, 0.188965f, -0.0151367f, 0.214355f, -0.0151367f, 0.240723f, -0.0292969f,
-0.26709f, -0.043457f, 0.292236f, -0.0712891f, 0.317383f, -0.0991211f, 0.337402f,
--0.135498f, 0.357422f, -0.171875f, 0.373291f, -0.221191f, 0.38916f, -0.270508f, 0.38916f,
--0.318848f, 0.38916f, -0.35791f, 0.371338f, -0.378662f, 0.353516f, -0.399414f, 0.32959f,
--0.399414f, 0.276855f, -0.399414f, 0.225342f, -0.338867f, 0.173828f, -0.27832f, 0.149902f,
--0.197266f, 0.0522461f, -0.414551f, 0.220703f, -0.441895f, 0.150391f, -0.20459f,
-0.23584f, -0.350586f, 0.305664f, -0.408691f, 0.345215f, -0.441895f, 0.370117f, -0.441895f,
-0.38623f, -0.441895f, 0.395508f, -0.432373f, 0.404785f, -0.422852f, 0.404785f, -0.404785f,
-0.404785f, -0.372559f, 0.388184f, -0.343262f, 0.376465f, -0.321289f, 0.354492f, -0.321289f,
-0.343262f, -0.321289f, 0.335205f, -0.328613f, 0.327148f, -0.335938f, 0.325195f, -0.351074f,
-0.324219f, -0.360352f, 0.320801f, -0.363281f, 0.316895f, -0.367188f, 0.311523f, -0.367188f,
-0.303223f, -0.367188f, 0.295898f, -0.363281f, 0.283203f, -0.356445f, 0.257324f, -0.325195f,
-0.216797f, -0.277344f, 0.169434f, -0.201172f, 0.148926f, -0.168945f, 0.134277f, -0.128418f,
-0.11377f, -0.0727539f, 0.11084f, -0.0615234f, 0.0952148f, 0, 0.0205078f, 0, 0.11084f,
--0.303223f, 0.126465f, -0.355957f, 0.126465f, -0.378418f, 0.126465f, -0.387207f,
-0.119141f, -0.393066f, 0.109375f, -0.400879f, 0.0932617f, -0.400879f, 0.0830078f,
--0.400879f, 0.0556641f, -0.396484f, 0.362793f, -0.441895f, 0.333008f, -0.291992f,
-0.314941f, -0.291992f, 0.3125f, -0.357422f, 0.287109f, -0.387207f, 0.261719f, -0.416992f,
-0.224121f, -0.416992f, 0.193848f, -0.416992f, 0.176025f, -0.400391f, 0.158203f, -0.383789f,
-0.158203f, -0.360352f, 0.158203f, -0.344238f, 0.165283f, -0.32959f, 0.172363f, -0.314941f,
-0.196289f, -0.288574f, 0.259766f, -0.219238f, 0.27832f, -0.184082f, 0.296875f, -0.148926f,
-0.296875f, -0.117676f, 0.296875f, -0.0668945f, 0.254639f, -0.0275879f, 0.212402f,
-0.0117188f, 0.147949f, 0.0117188f, 0.112793f, 0.0117188f, 0.0668945f, -0.00488281f,
-0.0507812f, -0.0107422f, 0.0419922f, -0.0107422f, 0.0200195f, -0.0107422f, 0.00878906f,
-0.0117188f, -0.00927734f, 0.0117188f, 0.0205078f, -0.146484f, 0.0385742f, -0.146484f,
-0.0415039f, -0.0722656f, 0.0693359f, -0.0415039f, 0.097168f, -0.0107422f, 0.145508f,
--0.0107422f, 0.182617f, -0.0107422f, 0.204346f, -0.0314941f, 0.226074f, -0.0522461f,
-0.226074f, -0.0825195f, 0.226074f, -0.102051f, 0.218262f, -0.118652f, 0.20459f, -0.147949f,
-0.160889f, -0.199707f, 0.117188f, -0.251465f, 0.104736f, -0.277344f, 0.0922852f,
--0.303223f, 0.0922852f, -0.329102f, 0.0922852f, -0.376465f, 0.126709f, -0.40918f,
-0.161133f, -0.441895f, 0.215332f, -0.441895f, 0.230957f, -0.441895f, 0.243652f, -0.439453f,
-0.250488f, -0.437988f, 0.275635f, -0.428467f, 0.300781f, -0.418945f, 0.309082f, -0.418945f,
-0.330078f, -0.418945f, 0.344238f, -0.441895f, 0.470703f, -0.430176f, 0.385742f, -0.13916f,
-0.366699f, -0.0742188f, 0.366699f, -0.0571289f, 0.366699f, -0.0483398f, 0.369873f,
--0.0441895f, 0.373047f, -0.0400391f, 0.378418f, -0.0400391f, 0.386719f, -0.0400391f,
-0.396729f, -0.0476074f, 0.406738f, -0.0551758f, 0.447266f, -0.10791f, 0.461914f,
--0.0966797f, 0.42334f, -0.0356445f, 0.382812f, -0.00683594f, 0.355957f, 0.0117188f,
-0.331055f, 0.0117188f, 0.312012f, 0.0117188f, 0.30127f, 0.000976562f, 0.290527f,
--0.00976562f, 0.290527f, -0.0268555f, 0.290527f, -0.043457f, 0.296875f, -0.0708008f,
-0.304688f, -0.106934f, 0.341309f, -0.228027f, 0.258301f, -0.0917969f, 0.202393f,
--0.0400391f, 0.146484f, 0.0117188f, 0.0986328f, 0.0117188f, 0.0761719f, 0.0117188f,
-0.0605469f, -0.00390625f, 0.0449219f, -0.0195312f, 0.0449219f, -0.043457f, 0.0449219f,
--0.0800781f, 0.0664062f, -0.155762f, 0.108887f, -0.306641f, 0.124512f, -0.36084f,
-0.124512f, -0.374023f, 0.124512f, -0.379883f, 0.120361f, -0.384033f, 0.116211f, -0.388184f,
-0.111328f, -0.388184f, 0.101074f, -0.388184f, 0.0908203f, -0.380859f, 0.0805664f,
--0.373535f, 0.0444336f, -0.32666f, 0.0292969f, -0.337402f, 0.065918f, -0.394043f,
-0.106934f, -0.420898f, 0.138184f, -0.441895f, 0.164551f, -0.441895f, 0.182617f, -0.441895f,
-0.194092f, -0.43042f, 0.205566f, -0.418945f, 0.205566f, -0.400879f, 0.205566f, -0.374512f,
-0.186035f, -0.306641f, 0.140137f, -0.148926f, 0.121094f, -0.0844727f, 0.121094f,
--0.0673828f, 0.121094f, -0.0581055f, 0.127197f, -0.0524902f, 0.133301f, -0.046875f,
-0.143555f, -0.046875f, 0.159668f, -0.046875f, 0.185547f, -0.0629883f, 0.211426f,
--0.0791016f, 0.254639f, -0.134521f, 0.297852f, -0.189941f, 0.325928f, -0.238525f,
-0.354004f, -0.287109f, 0.385742f, -0.393066f, 0.396484f, -0.430176f, 0.159668f, -0.441895f,
-0.17627f, -0.413574f, 0.182617f, -0.388916f, 0.188965f, -0.364258f, 0.195312f, -0.291992f,
-0.216797f, -0.0517578f, 0.246094f, -0.0869141f, 0.301758f, -0.163086f, 0.328613f,
--0.200195f, 0.368164f, -0.26416f, 0.39209f, -0.303223f, 0.397461f, -0.318848f, 0.400391f,
--0.32666f, 0.400391f, -0.334961f, 0.400391f, -0.340332f, 0.396973f, -0.34375f, 0.393555f,
--0.347168f, 0.37915f, -0.351807f, 0.364746f, -0.356445f, 0.355225f, -0.368896f, 0.345703f,
--0.381348f, 0.345703f, -0.397461f, 0.345703f, -0.41748f, 0.357422f, -0.429688f, 0.369141f,
--0.441895f, 0.386719f, -0.441895f, 0.408203f, -0.441895f, 0.42334f, -0.424072f, 0.438477f,
--0.40625f, 0.438477f, -0.375f, 0.438477f, -0.336426f, 0.412109f, -0.286865f, 0.385742f,
--0.237305f, 0.310547f, -0.134766f, 0.235352f, -0.0322266f, 0.128418f, 0.0888672f,
-0.0546875f, 0.172363f, 0.019043f, 0.194092f, -0.0166016f, 0.21582f, -0.0419922f,
-0.21582f, -0.0571289f, 0.21582f, -0.0686035f, 0.204346f, -0.0800781f, 0.192871f,
--0.0800781f, 0.177734f, -0.0800781f, 0.158691f, -0.064209f, 0.143066f, -0.0483398f,
-0.127441f, -0.0297852f, 0.127441f, -0.0200195f, 0.127441f, -0.0136719f, 0.131836f,
--0.00976562f, 0.134277f, -0.00512695f, 0.145752f, -0.000488281f, 0.157227f, 0.00341797f,
-0.161133f, 0.00585938f, 0.163574f, 0.00927734f, 0.163574f, 0.012207f, 0.163574f,
-0.0195312f, 0.158691f, 0.0463867f, 0.14209f, 0.0820312f, 0.105957f, 0.128906f, 0.0581055f,
-0.151367f, 0.027832f, 0.124023f, -0.281738f, 0.117188f, -0.358398f, 0.103516f, -0.375f,
-0.0898438f, -0.391602f, 0.0576172f, -0.391602f, 0.0473633f, -0.391602f, 0.0209961f,
--0.388672f, 0.0166016f, -0.406738f
-};
-
-const unsigned char TimesNewRomankItalicVerbs[] = {
-6, 0, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1,
-5, 0, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 5, 6,
-0, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 5,
-6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1,
-2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2,
-2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 5, 0, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 5, 0, 2, 2,
-2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-0, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5,
-6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2,
-1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0,
-2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1,
-1, 2, 2, 1, 2, 2, 2, 2, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 5, 6, 0, 1, 1, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
-2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 5, 6, 0, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
-2, 1, 5, 6
-};
-
-const unsigned TimesNewRomankItalicCharCodes[] = {
-32, 65, 72, 84, 87, 89, 97, 98, 101, 102, 103, 109, 110, 111, 112, 114,
-115, 117, 121
-};
-
-const SkFixed TimesNewRomankItalicWidths[] = {
-0x00004000, 0x00009c60, 0x0000b8e0, 0x00008e60, 0x0000d540, 0x00008e60, 0x00008000,
-0x00008000, 0x000071a0, 0x00004720, 0x00008000, 0x0000b8e0, 0x00008000, 0x00008000,
-0x00008000, 0x000063a0, 0x000063a0, 0x00008000, 0x000071a0
-};
-
-const int TimesNewRomankItalicCharCodesCount = (int) SK_ARRAY_COUNT(TimesNewRomankItalicCharCodes);
-
-const SkPaint::FontMetrics TimesNewRomankItalicMetrics = {
-0x00000003, -1.02344f, -0.891113f, 0.216309f, 0.306641f, 0.0424805f, 1.8501f, 0, -0.497559f,
-1.35254f, 0.453613f, 0, 0.0488281f, 0.108887f
-};
-
-const SkScalar TimesNewRomankBoldItalicPoints[] = {
-0.405273f, -0.213379f, 0.200195f, -0.213379f, 0.15918f, -0.162598f, 0.112305f, -0.106445f,
-0.0986328f, -0.0883789f, 0.0922852f, -0.0737305f, 0.0874023f, -0.0625f, 0.0874023f,
--0.0512695f, 0.0874023f, -0.0395508f, 0.0998535f, -0.029541f, 0.112305f, -0.0195312f,
-0.141113f, -0.0180664f, 0.141113f, 0, -0.0566406f, 0, -0.0517578f, -0.0180664f, -0.0253906f,
--0.0224609f, -0.00488281f, -0.0366211f, 0.0224609f, -0.0561523f, 0.0737305f, -0.117188f,
-0.542969f, -0.677246f, 0.564941f, -0.677246f, 0.542969f, -0.135254f, 0.541504f, -0.0927734f,
-0.541504f, -0.0839844f, 0.541504f, -0.0507812f, 0.554932f, -0.0356445f, 0.568359f,
--0.0205078f, 0.599609f, -0.0180664f, 0.594727f, 0, 0.308105f, 0, 0.313477f, -0.0180664f,
-0.355957f, -0.0219727f, 0.362305f, -0.0249023f, 0.375977f, -0.0317383f, 0.387207f,
--0.0534668f, 0.398438f, -0.0751953f, 0.400879f, -0.128906f, 0.405273f, -0.253418f,
-0.417969f, -0.469238f, 0.233887f, -0.253418f, 0.297363f, -0.357422f, 0.539551f, -0.357422f,
-0.593262f, -0.54248f, 0.604004f, -0.580566f, 0.604004f, -0.600586f, 0.604004f, -0.620117f,
-0.59082f, -0.630371f, 0.577637f, -0.640625f, 0.527344f, -0.644043f, 0.532715f, -0.662109f,
-0.861816f, -0.662109f, 0.856445f, -0.644043f, 0.808105f, -0.644043f, 0.783203f, -0.623535f,
-0.758301f, -0.603027f, 0.740723f, -0.54248f, 0.617676f, -0.118652f, 0.605469f, -0.0771484f,
-0.605469f, -0.059082f, 0.605469f, -0.0410156f, 0.618652f, -0.0317383f, 0.635742f,
--0.019043f, 0.680664f, -0.0180664f, 0.675781f, 0, 0.353027f, 0, 0.360352f, -0.0180664f,
-0.407227f, -0.0180664f, 0.429443f, -0.036377f, 0.45166f, -0.0546875f, 0.470215f,
--0.118652f, 0.527344f, -0.315918f, 0.286133f, -0.315918f, 0.229492f, -0.118652f,
-0.217285f, -0.078125f, 0.217285f, -0.0585938f, 0.217285f, -0.0410156f, 0.232178f,
--0.0300293f, 0.24707f, -0.019043f, 0.291016f, -0.0180664f, 0.286133f, 0, -0.0322266f,
-0, -0.0268555f, -0.0180664f, 0.0200195f, -0.0180664f, 0.041748f, -0.036377f, 0.0634766f,
--0.0546875f, 0.0820312f, -0.118652f, 0.205078f, -0.54248f, 0.21582f, -0.579102f,
-0.21582f, -0.600098f, 0.21582f, -0.620117f, 0.202881f, -0.630371f, 0.189941f, -0.640625f,
-0.141113f, -0.644043f, 0.146484f, -0.662109f, 0.470215f, -0.662109f, 0.462891f, -0.644043f,
-0.417969f, -0.644043f, 0.39502f, -0.624756f, 0.37207f, -0.605469f, 0.353027f, -0.54248f,
-0.160156f, -0.662109f, 0.692871f, -0.662109f, 0.642578f, -0.483887f, 0.625f, -0.483887f,
-0.625977f, -0.498047f, 0.625977f, -0.508789f, 0.625977f, -0.55957f, 0.596191f, -0.587646f,
-0.566406f, -0.615723f, 0.495605f, -0.619629f, 0.348145f, -0.121094f, 0.335938f, -0.0795898f,
-0.335938f, -0.0595703f, 0.335938f, -0.0410156f, 0.351074f, -0.0300293f, 0.366211f,
--0.019043f, 0.412598f, -0.0180664f, 0.408203f, 0, 0.0795898f, 0, 0.0854492f, -0.0180664f,
-0.135742f, -0.0180664f, 0.158691f, -0.0368652f, 0.181641f, -0.0556641f, 0.200684f,
--0.121094f, 0.348145f, -0.619629f, 0.271973f, -0.617188f, 0.220703f, -0.586426f,
-0.169434f, -0.555664f, 0.126953f, -0.483887f, 0.10791f, -0.483887f, 0.130371f, 0.0151367f,
-0.175293f, -0.55127f, 0.177246f, -0.576172f, 0.177246f, -0.592285f, 0.177246f, -0.618164f,
-0.165283f, -0.630371f, 0.15332f, -0.642578f, 0.123047f, -0.644043f, 0.130371f, -0.662109f,
-0.397949f, -0.662109f, 0.392578f, -0.644043f, 0.379395f, -0.644043f, 0.353027f, -0.644043f,
-0.33667f, -0.626709f, 0.320312f, -0.609375f, 0.316895f, -0.562012f, 0.291016f, -0.226074f,
-0.490723f, -0.499023f, 0.495605f, -0.562012f, 0.497559f, -0.581543f, 0.497559f, -0.593262f,
-0.497559f, -0.617188f, 0.484619f, -0.629883f, 0.47168f, -0.642578f, 0.441895f, -0.644043f,
-0.446777f, -0.662109f, 0.716309f, -0.662109f, 0.710938f, -0.644043f, 0.675293f, -0.644043f,
-0.658203f, -0.626709f, 0.641113f, -0.609375f, 0.637207f, -0.562012f, 0.611816f, -0.226074f,
-0.804199f, -0.490723f, 0.853516f, -0.558594f, 0.865234f, -0.583008f, 0.873535f, -0.599609f,
-0.873535f, -0.611328f, 0.873535f, -0.622559f, 0.862549f, -0.631592f, 0.851562f, -0.640625f,
-0.820312f, -0.644043f, 0.825195f, -0.662109f, 1.00195f, -0.662109f, 0.997559f, -0.644043f,
-0.973633f, -0.639648f, 0.958008f, -0.627441f, 0.936035f, -0.610352f, 0.900879f, -0.562012f,
-0.480469f, 0.0151367f, 0.45166f, 0.0151367f, 0.485352f, -0.431641f, 0.159668f, 0.0151367f,
-0.264648f, -0.29248f, 0.208984f, -0.533691f, 0.194824f, -0.596191f, 0.174805f, -0.619141f,
-0.159668f, -0.636719f, 0.119629f, -0.644043f, 0.125f, -0.662109f, 0.442871f, -0.662109f,
-0.437012f, -0.644043f, 0.390625f, -0.644043f, 0.369385f, -0.625244f, 0.348145f, -0.606445f,
-0.348145f, -0.580566f, 0.348145f, -0.564453f, 0.356934f, -0.524414f, 0.399902f, -0.328613f,
-0.506836f, -0.476074f, 0.547852f, -0.532715f, 0.558105f, -0.555908f, 0.568359f, -0.579102f,
-0.568359f, -0.59668f, 0.568359f, -0.614258f, 0.555176f, -0.627441f, 0.541992f, -0.640625f,
-0.512695f, -0.644043f, 0.518066f, -0.662109f, 0.716797f, -0.662109f, 0.716797f, -0.644043f,
-0.689941f, -0.641113f, 0.67041f, -0.626465f, 0.650879f, -0.611816f, 0.594238f, -0.533691f,
-0.40625f, -0.274902f, 0.362305f, -0.121582f, 0.348145f, -0.0742188f, 0.348145f, -0.0664062f,
-0.348145f, -0.0454102f, 0.364258f, -0.0317383f, 0.380371f, -0.0180664f, 0.418457f,
--0.0180664f, 0.437012f, -0.0180664f, 0.431641f, 0, 0.0927734f, 0, 0.0976562f, -0.0180664f,
-0.134766f, -0.0175781f, 0.157227f, -0.0280762f, 0.179688f, -0.0385742f, 0.190918f,
--0.0551758f, 0.19873f, -0.0668945f, 0.213867f, -0.117676f, 0.479004f, -0.445801f,
-0.384277f, -0.121094f, 0.374512f, -0.081543f, 0.373047f, -0.0742188f, 0.373047f,
--0.0708008f, 0.373047f, -0.0649414f, 0.377197f, -0.0605469f, 0.381348f, -0.0561523f,
-0.385742f, -0.0561523f, 0.395996f, -0.0561523f, 0.414062f, -0.0717773f, 0.421387f,
--0.078125f, 0.449219f, -0.116699f, 0.466309f, -0.10791f, 0.431641f, -0.0444336f,
-0.392334f, -0.0153809f, 0.353027f, 0.0136719f, 0.307617f, 0.0136719f, 0.279785f,
-0.0136719f, 0.265137f, -0.000732422f, 0.250488f, -0.0151367f, 0.250488f, -0.0371094f,
-0.250488f, -0.0561523f, 0.266113f, -0.10791f, 0.277832f, -0.147461f, 0.221191f, -0.050293f,
-0.168945f, -0.00976562f, 0.138672f, 0.0136719f, 0.104492f, 0.0136719f, 0.0595703f,
-0.0136719f, 0.0395508f, -0.0231934f, 0.0195312f, -0.0600586f, 0.0195312f, -0.106445f,
-0.0195312f, -0.175293f, 0.0615234f, -0.264404f, 0.103516f, -0.353516f, 0.171875f,
--0.407715f, 0.228027f, -0.452637f, 0.277344f, -0.452637f, 0.304688f, -0.452637f,
-0.321289f, -0.436768f, 0.337891f, -0.420898f, 0.345703f, -0.378906f, 0.363281f, -0.438965f,
-0.322754f, -0.353027f, 0.322754f, -0.392578f, 0.310547f, -0.410156f, 0.301758f, -0.422363f,
-0.286621f, -0.422363f, 0.271484f, -0.422363f, 0.255371f, -0.407715f, 0.222656f, -0.377441f,
-0.184814f, -0.284912f, 0.146973f, -0.192383f, 0.146973f, -0.125f, 0.146973f, -0.0991211f,
-0.155518f, -0.0876465f, 0.164062f, -0.0761719f, 0.174316f, -0.0761719f, 0.196289f,
--0.0761719f, 0.21875f, -0.101562f, 0.250977f, -0.137695f, 0.276855f, -0.189941f,
-0.322754f, -0.281738f, 0.322754f, -0.353027f, 0.315918f, -0.677246f, 0.231445f, -0.382812f,
-0.27002f, -0.424805f, 0.295898f, -0.438721f, 0.321777f, -0.452637f, 0.352051f, -0.452637f,
-0.410645f, -0.452637f, 0.439697f, -0.4104f, 0.46875f, -0.368164f, 0.46875f, -0.312988f,
-0.46875f, -0.181152f, 0.373047f, -0.0776367f, 0.288086f, 0.0136719f, 0.179688f, 0.0136719f,
-0.0991211f, 0.0136719f, 0.00927734f, -0.0336914f, 0.158691f, -0.551758f, 0.169434f,
--0.588379f, 0.169434f, -0.602051f, 0.169434f, -0.61377f, 0.159668f, -0.620605f, 0.145996f,
--0.630371f, 0.118164f, -0.628906f, 0.123535f, -0.648438f, 0.286621f, -0.677246f,
-0.128418f, -0.0288086f, 0.151367f, -0.0141602f, 0.169922f, -0.0141602f, 0.195801f,
--0.0141602f, 0.213379f, -0.0244141f, 0.241211f, -0.0410156f, 0.271729f, -0.0844727f,
-0.302246f, -0.12793f, 0.322754f, -0.189453f, 0.343262f, -0.250977f, 0.343262f, -0.312012f,
-0.343262f, -0.34668f, 0.327637f, -0.364746f, 0.312012f, -0.382812f, 0.291504f, -0.382812f,
-0.257324f, -0.382812f, 0.231934f, -0.349609f, 0.214844f, -0.328125f, 0.194824f, -0.258301f,
-0.15625f, -0.183105f, 0.151855f, -0.151367f, 0.151855f, -0.130859f, 0.151855f, -0.0942383f,
-0.173096f, -0.0722656f, 0.194336f, -0.050293f, 0.22998f, -0.050293f, 0.26416f, -0.050293f,
-0.298584f, -0.0668945f, 0.333008f, -0.0834961f, 0.378418f, -0.125f, 0.393066f, -0.111816f,
-0.336914f, -0.0439453f, 0.283691f, -0.0151367f, 0.230469f, 0.0136719f, 0.166016f,
-0.0136719f, 0.0844727f, 0.0136719f, 0.0532227f, -0.0253906f, 0.0219727f, -0.0644531f,
-0.0219727f, -0.115723f, 0.0219727f, -0.195801f, 0.0686035f, -0.275879f, 0.115234f,
--0.355957f, 0.195557f, -0.404297f, 0.275879f, -0.452637f, 0.356934f, -0.452637f,
-0.397949f, -0.452637f, 0.418945f, -0.433105f, 0.439941f, -0.413574f, 0.439941f, -0.383789f,
-0.439941f, -0.348145f, 0.419434f, -0.314453f, 0.391113f, -0.268555f, 0.348145f, -0.240479f,
-0.305176f, -0.212402f, 0.251953f, -0.197754f, 0.216309f, -0.187988f, 0.15625f, -0.183105f,
-0.160645f, -0.208496f, 0.203613f, -0.214844f, 0.227295f, -0.22583f, 0.250977f, -0.236816f,
-0.273682f, -0.260986f, 0.296387f, -0.285156f, 0.312988f, -0.322021f, 0.32959f, -0.358887f,
-0.32959f, -0.391113f, 0.32959f, -0.404785f, 0.322021f, -0.412598f, 0.314453f, -0.42041f,
-0.302734f, -0.42041f, 0.279297f, -0.42041f, 0.25f, -0.387695f, 0.196289f, -0.328125f,
-0.160645f, -0.208496f, 0.261719f, -0.381836f, 0.20459f, -0.15625f, 0.164551f, 0.00341797f,
-0.126465f, 0.0751953f, 0.0883789f, 0.146973f, 0.0373535f, 0.181396f, -0.0136719f,
-0.21582f, -0.0795898f, 0.21582f, -0.121094f, 0.21582f, -0.140625f, 0.199951f, -0.160156f,
-0.184082f, -0.160156f, 0.162598f, -0.160156f, 0.142578f, -0.144043f, 0.12793f, -0.12793f,
-0.113281f, -0.101562f, 0.113281f, -0.0795898f, 0.113281f, -0.0678711f, 0.124512f,
--0.0561523f, 0.135742f, -0.0561523f, 0.152832f, -0.0561523f, 0.168457f, -0.0634766f,
-0.176025f, -0.0708008f, 0.183594f, -0.0708008f, 0.186035f, -0.0683594f, 0.189453f,
--0.0654297f, 0.191895f, -0.0615234f, 0.191895f, -0.046875f, 0.191895f, -0.0366211f,
-0.182617f, -0.0107422f, 0.159668f, 0.00195312f, 0.126953f, 0.0107422f, 0.104492f,
-0.0356445f, 0.00830078f, 0.135254f, -0.381836f, 0.0673828f, -0.381836f, 0.0834961f,
--0.438965f, 0.120117f, -0.438477f, 0.136719f, -0.448242f, 0.15332f, -0.458008f, 0.171875f,
--0.492188f, 0.225586f, -0.591309f, 0.285156f, -0.634277f, 0.344727f, -0.677246f,
-0.417969f, -0.677246f, 0.464844f, -0.677246f, 0.486084f, -0.65918f, 0.507324f, -0.641113f,
-0.507324f, -0.612305f, 0.507324f, -0.586914f, 0.493164f, -0.572021f, 0.479004f, -0.557129f,
-0.458008f, -0.557129f, 0.438477f, -0.557129f, 0.425781f, -0.569336f, 0.413086f, -0.581543f,
-0.413086f, -0.598633f, 0.413086f, -0.61084f, 0.421143f, -0.624512f, 0.429199f, -0.638184f,
-0.429199f, -0.643066f, 0.429199f, -0.648438f, 0.425537f, -0.651855f, 0.421875f, -0.655273f,
-0.416016f, -0.655273f, 0.387207f, -0.655273f, 0.356934f, -0.619629f, 0.307129f, -0.5625f,
-0.276855f, -0.438965f, 0.347656f, -0.438965f, 0.330566f, -0.381836f, 0.386719f, -0.422852f,
-0.516602f, -0.422852f, 0.500977f, -0.369141f, 0.433594f, -0.369141f, 0.449219f, -0.340332f,
-0.449219f, -0.314453f, 0.449219f, -0.27002f, 0.425049f, -0.232422f, 0.400879f, -0.194824f,
-0.35376f, -0.172363f, 0.306641f, -0.149902f, 0.249023f, -0.149902f, 0.233887f, -0.149902f,
-0.215576f, -0.1521f, 0.197266f, -0.154297f, 0.175781f, -0.158203f, 0.143555f, -0.141602f,
-0.135254f, -0.131836f, 0.129395f, -0.125f, 0.129395f, -0.117676f, 0.129395f, -0.108887f,
-0.136719f, -0.102539f, 0.149414f, -0.0913086f, 0.174316f, -0.0859375f, 0.273926f,
--0.0644531f, 0.305664f, -0.0512695f, 0.349121f, -0.0332031f, 0.371338f, -0.00488281f,
-0.393555f, 0.0234375f, 0.393555f, 0.0634766f, 0.393555f, 0.124512f, 0.337402f, 0.170166f,
-0.28125f, 0.21582f, 0.163574f, 0.21582f, 0.0449219f, 0.21582f, -0.0112305f, 0.176758f,
--0.0517578f, 0.148438f, -0.0517578f, 0.109375f, -0.0517578f, 0.0795898f, -0.0251465f,
-0.0541992f, 0.00146484f, 0.0288086f, 0.0888672f, 0.00927734f, 0.059082f, -0.00732422f,
-0.0488281f, -0.0209961f, 0.034668f, -0.0395508f, 0.034668f, -0.0595703f, 0.034668f,
--0.0922852f, 0.060791f, -0.117188f, 0.0869141f, -0.14209f, 0.148438f, -0.166504f,
-0.100586f, -0.185547f, 0.0793457f, -0.215576f, 0.0581055f, -0.245605f, 0.0581055f,
--0.285645f, 0.0581055f, -0.328125f, 0.0837402f, -0.366455f, 0.109375f, -0.404785f,
-0.159424f, -0.428711f, 0.209473f, -0.452637f, 0.274414f, -0.452637f, 0.315918f, -0.452637f,
-0.348145f, -0.443359f, 0.364746f, -0.438477f, 0.386719f, -0.422852f, 0.284668f, -0.428711f,
-0.260742f, -0.428711f, 0.244141f, -0.413086f, 0.217773f, -0.38916f, 0.197998f, -0.333008f,
-0.178223f, -0.276855f, 0.178223f, -0.226562f, 0.178223f, -0.202637f, 0.192139f, -0.188721f,
-0.206055f, -0.174805f, 0.226562f, -0.174805f, 0.246582f, -0.174805f, 0.26123f, -0.188477f,
-0.289062f, -0.215332f, 0.30957f, -0.27417f, 0.330078f, -0.333008f, 0.330078f, -0.380859f,
-0.330078f, -0.402344f, 0.316895f, -0.415527f, 0.303711f, -0.428711f, 0.284668f, -0.428711f,
-0.116211f, 0.0205078f, 0.0698242f, 0.0385742f, 0.0529785f, 0.0595703f, 0.0361328f,
-0.0805664f, 0.0361328f, 0.10498f, 0.0361328f, 0.136719f, 0.0695801f, 0.162354f, 0.103027f,
-0.187988f, 0.17627f, 0.187988f, 0.237305f, 0.187988f, 0.264648f, 0.165771f, 0.291992f,
-0.143555f, 0.291992f, 0.11377f, 0.291992f, 0.0874023f, 0.266846f, 0.0708008f, 0.241699f,
-0.0541992f, 0.17041f, 0.0361328f, 0.137207f, 0.0273438f, 0.116211f, 0.0205078f, 0.265625f,
--0.452637f, 0.203125f, -0.242676f, 0.266113f, -0.339355f, 0.294922f, -0.373047f,
-0.337402f, -0.422363f, 0.36499f, -0.4375f, 0.392578f, -0.452637f, 0.42041f, -0.452637f,
-0.452148f, -0.452637f, 0.466309f, -0.433594f, 0.480469f, -0.414551f, 0.480469f, -0.391602f,
-0.480469f, -0.367676f, 0.467285f, -0.321289f, 0.445312f, -0.242676f, 0.508789f, -0.340332f,
-0.536621f, -0.372559f, 0.57959f, -0.422363f, 0.611328f, -0.439941f, 0.633301f, -0.452637f,
-0.658203f, -0.452637f, 0.684082f, -0.452637f, 0.701416f, -0.435303f, 0.71875f, -0.417969f,
-0.71875f, -0.390137f, 0.71875f, -0.358887f, 0.704102f, -0.309082f, 0.649902f, -0.126953f,
-0.637695f, -0.0864258f, 0.637695f, -0.074707f, 0.637695f, -0.0708008f, 0.640869f,
--0.0673828f, 0.644043f, -0.0639648f, 0.647949f, -0.0639648f, 0.65332f, -0.0639648f,
-0.657227f, -0.0673828f, 0.674805f, -0.081543f, 0.694336f, -0.108887f, 0.69873f, -0.114746f,
-0.70752f, -0.126953f, 0.724121f, -0.116211f, 0.69043f, -0.0532227f, 0.650146f, -0.0239258f,
-0.609863f, 0.00537109f, 0.575684f, 0.00537109f, 0.545898f, 0.00537109f, 0.527832f,
--0.0109863f, 0.509766f, -0.0273438f, 0.509766f, -0.0493164f, 0.509766f, -0.0703125f,
-0.521973f, -0.112793f, 0.577148f, -0.303223f, 0.588379f, -0.342773f, 0.588379f, -0.352539f,
-0.588379f, -0.355957f, 0.584961f, -0.359131f, 0.581543f, -0.362305f, 0.578125f, -0.362305f,
-0.571777f, -0.362305f, 0.56543f, -0.359375f, 0.556152f, -0.354492f, 0.536865f, -0.333984f,
-0.517578f, -0.313477f, 0.481445f, -0.260498f, 0.445312f, -0.20752f, 0.431396f, -0.177734f,
-0.41748f, -0.147949f, 0.403809f, -0.100586f, 0.374023f, 0, 0.250488f, 0, 0.341797f,
--0.318848f, 0.349121f, -0.344727f, 0.349121f, -0.354492f, 0.349121f, -0.35791f, 0.345947f,
--0.36084f, 0.342773f, -0.36377f, 0.339355f, -0.36377f, 0.321289f, -0.36377f, 0.282227f,
--0.316406f, 0.222656f, -0.243164f, 0.173828f, -0.140137f, 0.134277f, 0, 0.00976562f,
-0, 0.101562f, -0.313965f, 0.115234f, -0.360352f, 0.115234f, -0.379883f, 0.115234f,
--0.387695f, 0.111328f, -0.393311f, 0.107422f, -0.398926f, 0.0986328f, -0.4021f, 0.0898438f,
--0.405273f, 0.0649414f, -0.405273f, 0.0698242f, -0.423828f, 0.236328f, -0.452637f,
-0.26709f, -0.452637f, 0.206543f, -0.243164f, 0.267578f, -0.334961f, 0.297852f, -0.368652f,
-0.342285f, -0.41748f, 0.374512f, -0.435059f, 0.406738f, -0.452637f, 0.435059f, -0.452637f,
-0.460449f, -0.452637f, 0.478516f, -0.433838f, 0.496582f, -0.415039f, 0.496582f, -0.384766f,
-0.496582f, -0.357422f, 0.484863f, -0.318359f, 0.422363f, -0.109863f, 0.414551f, -0.0825195f,
-0.414551f, -0.0742188f, 0.414551f, -0.0693359f, 0.418213f, -0.0654297f, 0.421875f,
--0.0615234f, 0.425781f, -0.0615234f, 0.430664f, -0.0615234f, 0.436035f, -0.0654297f,
-0.453125f, -0.0795898f, 0.470703f, -0.105469f, 0.475098f, -0.112305f, 0.484863f,
--0.125977f, 0.503418f, -0.114746f, 0.431641f, 0.00585938f, 0.352539f, 0.00585938f,
-0.322266f, 0.00585938f, 0.305176f, -0.00976562f, 0.288086f, -0.0253906f, 0.288086f,
--0.0488281f, 0.288086f, -0.0693359f, 0.299805f, -0.109863f, 0.36084f, -0.318359f,
-0.367188f, -0.338867f, 0.367188f, -0.348633f, 0.367188f, -0.354004f, 0.362793f, -0.358154f,
-0.358398f, -0.362305f, 0.352539f, -0.362305f, 0.333984f, -0.362305f, 0.307617f, -0.336914f,
-0.240234f, -0.272461f, 0.177246f, -0.14502f, 0.137207f, 0, 0.0126953f, 0, 0.104004f,
--0.313477f, 0.117188f, -0.359863f, 0.117188f, -0.379395f, 0.117188f, -0.387695f,
-0.113281f, -0.393311f, 0.109375f, -0.398926f, 0.100586f, -0.4021f, 0.0917969f, -0.405273f,
-0.0673828f, -0.405273f, 0.0727539f, -0.423828f, 0.237305f, -0.452637f, 0.328613f,
--0.452637f, 0.367188f, -0.452637f, 0.401123f, -0.434814f, 0.435059f, -0.416992f,
-0.452393f, -0.385254f, 0.469727f, -0.353516f, 0.469727f, -0.314941f, 0.469727f, -0.23584f,
-0.425537f, -0.156738f, 0.381348f, -0.0776367f, 0.309082f, -0.0319824f, 0.236816f,
-0.0136719f, 0.163574f, 0.0136719f, 0.097168f, 0.0136719f, 0.060791f, -0.0258789f,
-0.0244141f, -0.0654297f, 0.0244141f, -0.122559f, 0.0244141f, -0.19043f, 0.0515137f,
--0.249756f, 0.0786133f, -0.309082f, 0.120361f, -0.353271f, 0.162109f, -0.397461f,
-0.216309f, -0.425049f, 0.270508f, -0.452637f, 0.328613f, -0.452637f, 0.308594f, -0.426758f,
-0.282715f, -0.426758f, 0.265625f, -0.411621f, 0.231445f, -0.380859f, 0.188477f, -0.267822f,
-0.145508f, -0.154785f, 0.145508f, -0.0639648f, 0.145508f, -0.0415039f, 0.15918f,
--0.0268555f, 0.172852f, -0.012207f, 0.191406f, -0.012207f, 0.210449f, -0.012207f,
-0.225098f, -0.0239258f, 0.246582f, -0.0415039f, 0.277832f, -0.102783f, 0.309082f,
--0.164062f, 0.329102f, -0.238037f, 0.349121f, -0.312012f, 0.349121f, -0.373535f,
-0.349121f, -0.398926f, 0.336914f, -0.412842f, 0.324707f, -0.426758f, 0.308594f, -0.426758f,
-0.0605469f, -0.425293f, 0.222168f, -0.452637f, 0.251465f, -0.452637f, 0.229492f,
--0.373047f, 0.280762f, -0.419922f, 0.313477f, -0.436279f, 0.346191f, -0.452637f,
-0.378418f, -0.452637f, 0.424316f, -0.452637f, 0.449219f, -0.417236f, 0.474121f, -0.381836f,
-0.474121f, -0.330566f, 0.474121f, -0.19043f, 0.376953f, -0.0820312f, 0.291016f, 0.0136719f,
-0.189453f, 0.0136719f, 0.171387f, 0.0136719f, 0.158691f, 0.0102539f, 0.145996f, 0.00683594f,
-0.123047f, -0.00488281f, 0.0976562f, 0.0830078f, 0.0839844f, 0.130859f, 0.0839844f,
-0.155762f, 0.0839844f, 0.171387f, 0.0947266f, 0.18042f, 0.105469f, 0.189453f, 0.14502f,
-0.195801f, 0.140625f, 0.213867f, -0.12207f, 0.213867f, -0.117188f, 0.195801f, -0.0859375f,
-0.194824f, -0.0651855f, 0.175781f, -0.0444336f, 0.156738f, -0.0263672f, 0.09375f,
-0.0927734f, -0.316895f, 0.105957f, -0.362793f, 0.105957f, -0.381836f, 0.105957f,
--0.390137f, 0.102051f, -0.395752f, 0.0981445f, -0.401367f, 0.090332f, -0.403809f,
-0.0825195f, -0.40625f, 0.0551758f, -0.40625f, 0.136719f, -0.050293f, 0.151367f, -0.0263672f,
-0.163086f, -0.0183105f, 0.174805f, -0.0102539f, 0.19043f, -0.0102539f, 0.206055f,
--0.0102539f, 0.220947f, -0.0187988f, 0.23584f, -0.0273438f, 0.257812f, -0.0532227f,
-0.279785f, -0.0791016f, 0.300049f, -0.119629f, 0.320312f, -0.160156f, 0.33252f, -0.21167f,
-0.344727f, -0.263184f, 0.344727f, -0.310059f, 0.344727f, -0.347656f, 0.331299f, -0.364746f,
-0.317871f, -0.381836f, 0.298828f, -0.381836f, 0.281738f, -0.381836f, 0.266602f, -0.373047f,
-0.244629f, -0.360352f, 0.214844f, -0.325684f, 0.236816f, -0.452637f, 0.163086f, -0.178223f,
-0.253906f, -0.378906f, 0.299805f, -0.425293f, 0.32666f, -0.452637f, 0.356445f, -0.452637f,
-0.376953f, -0.452637f, 0.389648f, -0.437744f, 0.402344f, -0.422852f, 0.402344f, -0.395508f,
-0.402344f, -0.348145f, 0.379395f, -0.315918f, 0.364746f, -0.29541f, 0.34668f, -0.29541f,
-0.327148f, -0.29541f, 0.317383f, -0.313477f, 0.307617f, -0.331543f, 0.303711f, -0.334717f,
-0.299805f, -0.337891f, 0.29541f, -0.337891f, 0.290527f, -0.337891f, 0.285156f, -0.334961f,
-0.274414f, -0.329102f, 0.25708f, -0.306396f, 0.239746f, -0.283691f, 0.214355f, -0.230469f,
-0.188965f, -0.177246f, 0.174805f, -0.140381f, 0.160645f, -0.103516f, 0.135254f, 0,
-0.0170898f, 0, 0.0976562f, -0.32373f, 0.106445f, -0.359863f, 0.106445f, -0.371582f,
-0.106445f, -0.384766f, 0.101807f, -0.39209f, 0.097168f, -0.399414f, 0.0891113f, -0.402832f,
-0.0810547f, -0.40625f, 0.0556641f, -0.40625f, 0.0600586f, -0.42041f, 0.20752f, -0.452637f,
-0.37207f, -0.452637f, 0.350586f, -0.301758f, 0.33252f, -0.301758f, 0.328613f, -0.360352f,
-0.296631f, -0.394043f, 0.264648f, -0.427734f, 0.228027f, -0.427734f, 0.205566f, -0.427734f,
-0.190918f, -0.414551f, 0.17627f, -0.401367f, 0.17627f, -0.382812f, 0.17627f, -0.367188f,
-0.182617f, -0.353516f, 0.188965f, -0.339844f, 0.210938f, -0.316406f, 0.288086f, -0.233398f,
-0.304688f, -0.202148f, 0.321289f, -0.170898f, 0.321289f, -0.135254f, 0.321289f, -0.0966797f,
-0.301758f, -0.0622559f, 0.282227f, -0.027832f, 0.243408f, -0.00708008f, 0.20459f,
-0.0136719f, 0.162598f, 0.0136719f, 0.134277f, 0.0136719f, 0.0927734f, 0.00244141f,
-0.0654297f, -0.00537109f, 0.0517578f, -0.00537109f, 0.0395508f, -0.00537109f, 0.0327148f,
--0.00170898f, 0.0258789f, 0.00195312f, 0.0175781f, 0.0136719f, -0.000488281f, 0.0136719f,
-0.0234375f, -0.148926f, 0.0390625f, -0.148926f, 0.0561523f, -0.0898438f, 0.0710449f,
--0.0646973f, 0.0859375f, -0.0395508f, 0.11084f, -0.0246582f, 0.135742f, -0.00976562f,
-0.158691f, -0.00976562f, 0.185547f, -0.00976562f, 0.203125f, -0.0266113f, 0.220703f,
--0.043457f, 0.220703f, -0.0668945f, 0.220703f, -0.0898438f, 0.209229f, -0.111328f,
-0.197754f, -0.132812f, 0.15625f, -0.178223f, 0.0991211f, -0.240234f, 0.0810547f,
--0.273926f, 0.0683594f, -0.29834f, 0.0683594f, -0.32959f, 0.0683594f, -0.382324f,
-0.106689f, -0.41748f, 0.14502f, -0.452637f, 0.214355f, -0.452637f, 0.244629f, -0.452637f,
-0.288574f, -0.441895f, 0.310547f, -0.436523f, 0.32373f, -0.436523f, 0.342773f, -0.436523f,
-0.354492f, -0.452637f, 0.265625f, -0.452637f, 0.170898f, -0.120605f, 0.164062f, -0.0976562f,
-0.164062f, -0.0888672f, 0.164062f, -0.0844727f, 0.16748f, -0.0820312f, 0.171387f,
--0.078125f, 0.176758f, -0.078125f, 0.199219f, -0.078125f, 0.236816f, -0.118164f,
-0.290527f, -0.17627f, 0.349609f, -0.285156f, 0.394043f, -0.43457f, 0.517578f, -0.438965f,
-0.423828f, -0.116699f, 0.412109f, -0.0756836f, 0.412109f, -0.0698242f, 0.412109f,
--0.065918f, 0.415771f, -0.0617676f, 0.419434f, -0.0576172f, 0.42334f, -0.0576172f,
-0.430176f, -0.0576172f, 0.436523f, -0.0634766f, 0.454102f, -0.0776367f, 0.48291f,
--0.120605f, 0.499512f, -0.108887f, 0.431641f, 0.0136719f, 0.350098f, 0.0136719f,
-0.319824f, 0.0136719f, 0.30249f, -0.00170898f, 0.285156f, -0.0170898f, 0.285156f,
--0.0419922f, 0.285156f, -0.0683594f, 0.297363f, -0.108887f, 0.321289f, -0.191406f,
-0.257812f, -0.0991211f, 0.229004f, -0.0668945f, 0.185059f, -0.0185547f, 0.155029f,
--0.00244141f, 0.125f, 0.0136719f, 0.0976562f, 0.0136719f, 0.0717773f, 0.0136719f,
-0.0529785f, -0.00537109f, 0.0341797f, -0.0244141f, 0.0341797f, -0.0537109f, 0.0341797f,
--0.0786133f, 0.0463867f, -0.120605f, 0.101562f, -0.315918f, 0.115234f, -0.36377f,
-0.115234f, -0.380371f, 0.115234f, -0.387695f, 0.111328f, -0.393311f, 0.107422f, -0.398926f,
-0.0983887f, -0.4021f, 0.0893555f, -0.405273f, 0.0649414f, -0.405273f, 0.0698242f,
--0.423828f, 0.236328f, -0.452637f, 0.0253906f, -0.408691f, 0.175781f, -0.452637f,
-0.193848f, -0.430176f, 0.201172f, -0.410156f, 0.214355f, -0.375488f, 0.219727f, -0.314453f,
-0.22998f, -0.194336f, 0.233887f, -0.0581055f, 0.286133f, -0.126953f, 0.353516f, -0.240234f,
-0.374023f, -0.274414f, 0.374023f, -0.304688f, 0.374023f, -0.32373f, 0.350342f, -0.34082f,
-0.32666f, -0.35791f, 0.320801f, -0.367432f, 0.314941f, -0.376953f, 0.314941f, -0.39209f,
-0.314941f, -0.416504f, 0.332764f, -0.43457f, 0.350586f, -0.452637f, 0.375977f, -0.452637f,
-0.402832f, -0.452637f, 0.422607f, -0.432129f, 0.442383f, -0.411621f, 0.442383f, -0.383789f,
-0.442383f, -0.351074f, 0.424072f, -0.307861f, 0.405762f, -0.264648f, 0.338379f, -0.159668f,
-0.251953f, -0.0253906f, 0.168945f, 0.0727539f, 0.115723f, 0.135254f, 0.0830078f,
-0.162842f, 0.050293f, 0.19043f, 0.0151367f, 0.206543f, -0.00585938f, 0.21582f, -0.0263672f,
-0.21582f, -0.0541992f, 0.21582f, -0.0739746f, 0.196289f, -0.09375f, 0.176758f, -0.09375f,
-0.149902f, -0.09375f, 0.123047f, -0.0759277f, 0.104492f, -0.0581055f, 0.0859375f,
--0.0341797f, 0.0859375f, -0.00439453f, 0.0859375f, 0.0205078f, 0.117188f, 0.0371094f,
-0.138184f, 0.0478516f, 0.138184f, 0.059082f, 0.138184f, 0.0698242f, 0.131836f, 0.0844727f,
-0.124023f, 0.11084f, 0.0957031f, 0.11377f, 0.034668f, 0.11377f, 0.00341797f, 0.11377f,
--0.0385742f, 0.109863f, -0.114746f, 0.101562f, -0.300781f, 0.097168f, -0.352051f,
-0.0795898f, -0.374512f, 0.065918f, -0.391113f, 0.0439453f, -0.391113f, 0.0356445f,
--0.391113f, 0.0253906f, -0.389648f
-};
-
-const unsigned char TimesNewRomankBoldItalicVerbs[] = {
-6, 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 5,
-0, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1,
-1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2,
-1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 5, 6, 0, 1, 2, 2, 2, 1, 1, 1, 1, 2, 2, 1,
-1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 5, 6,
-0, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1,
-1, 1, 1, 2, 2, 2, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2,
-2, 2, 1, 2, 2, 2, 1, 1, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 2, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0,
-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 1,
-2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2,
-2, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 1,
-1, 5, 6, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 5, 6, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2,
-2, 2, 2, 5, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6,
-0, 1, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2,
-1, 2, 2, 2, 2, 1, 1, 5, 6, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 5, 6
-};
-
-const unsigned TimesNewRomankBoldItalicCharCodes[] = {
-32, 65, 72, 84, 87, 89, 97, 98,
-101, 102, 103, 109, 110, 111, 112, 114, 115, 117, 121
-};
-
-const SkFixed TimesNewRomankBoldItalicWidths[] = {
-0x00004000, 0x0000aac0, 0x0000c720, 0x00009c60, 0x0000e3a0, 0x00009c60, 0x00008000,
-0x00008000, 0x000071a0, 0x00005540, 0x00008000, 0x0000c720, 0x00008e60, 0x00008000,
-0x00008000, 0x000063a0, 0x000063a0, 0x00008e60, 0x000071a0
-};
-
-const int TimesNewRomankBoldItalicCharCodesCount = (int) SK_ARRAY_COUNT(TimesNewRomankBoldItalicCharCodes);
-
-const SkPaint::FontMetrics TimesNewRomankBoldItalicMetrics = {
-0x3436342f, -1.03223f, -0.891113f, 0.216309f, 0.306641f, 0.0424805f, 1.94824f, 7.98734e-16f,
--0.547363f, 1.40088f, 0.466309f, 9.77694e-15f, 0.0952148f, 0.108887f
-};
-
-static SkTestFontData gTestFonts[] = {
-    {    CourierNewkNormalPoints, CourierNewkNormalVerbs, CourierNewkNormalCharCodes,
-         CourierNewkNormalCharCodesCount, CourierNewkNormalWidths,
-         CourierNewkNormalMetrics, "Courier New", SkTypeface::kNormal, nullptr
-    },
-    {    CourierNewkBoldPoints, CourierNewkBoldVerbs, CourierNewkBoldCharCodes,
-         CourierNewkBoldCharCodesCount, CourierNewkBoldWidths,
-         CourierNewkBoldMetrics, "Courier New", SkTypeface::kBold, nullptr
-    },
-    {    CourierNewkItalicPoints, CourierNewkItalicVerbs, CourierNewkItalicCharCodes,
-         CourierNewkItalicCharCodesCount, CourierNewkItalicWidths,
-         CourierNewkItalicMetrics, "Courier New", SkTypeface::kItalic, nullptr
-    },
-    {    CourierNewkBoldItalicPoints, CourierNewkBoldItalicVerbs, CourierNewkBoldItalicCharCodes,
-         CourierNewkBoldItalicCharCodesCount, CourierNewkBoldItalicWidths,
-         CourierNewkBoldItalicMetrics, "Courier New", SkTypeface::kBoldItalic, nullptr
-    },
-    {    LiberationSanskNormalPoints, LiberationSanskNormalVerbs, LiberationSanskNormalCharCodes,
-         LiberationSanskNormalCharCodesCount, LiberationSanskNormalWidths,
-         LiberationSanskNormalMetrics, "Liberation Sans", SkTypeface::kNormal, nullptr
-    },
-    {    LiberationSanskBoldPoints, LiberationSanskBoldVerbs, LiberationSanskBoldCharCodes,
-         LiberationSanskBoldCharCodesCount, LiberationSanskBoldWidths,
-         LiberationSanskBoldMetrics, "Liberation Sans", SkTypeface::kBold, nullptr
-    },
-    {    LiberationSanskItalicPoints, LiberationSanskItalicVerbs, LiberationSanskItalicCharCodes,
-         LiberationSanskItalicCharCodesCount, LiberationSanskItalicWidths,
-         LiberationSanskItalicMetrics, "Liberation Sans", SkTypeface::kItalic, nullptr
-    },
-    {    LiberationSanskBoldItalicPoints, LiberationSanskBoldItalicVerbs, LiberationSanskBoldItalicCharCodes,
-         LiberationSanskBoldItalicCharCodesCount, LiberationSanskBoldItalicWidths,
-         LiberationSanskBoldItalicMetrics, "Liberation Sans", SkTypeface::kBoldItalic, nullptr
-    },
-    {    HiraginoMaruGothicProkNormalPoints, HiraginoMaruGothicProkNormalVerbs, HiraginoMaruGothicProkNormalCharCodes,
-         HiraginoMaruGothicProkNormalCharCodesCount, HiraginoMaruGothicProkNormalWidths,
-         HiraginoMaruGothicProkNormalMetrics, "Hiragino Maru Gothic Pro", SkTypeface::kNormal, nullptr
-    },
-    {    PapyruskNormalPoints, PapyruskNormalVerbs, PapyruskNormalCharCodes,
-         PapyruskNormalCharCodesCount, PapyruskNormalWidths,
-         PapyruskNormalMetrics, "Papyrus", SkTypeface::kNormal, nullptr
-    },
-    {    TimesNewRomankNormalPoints, TimesNewRomankNormalVerbs, TimesNewRomankNormalCharCodes,
-         TimesNewRomankNormalCharCodesCount, TimesNewRomankNormalWidths,
-         TimesNewRomankNormalMetrics, "Times New Roman", SkTypeface::kNormal, nullptr
-    },
-    {    TimesNewRomankBoldPoints, TimesNewRomankBoldVerbs, TimesNewRomankBoldCharCodes,
-         TimesNewRomankBoldCharCodesCount, TimesNewRomankBoldWidths,
-         TimesNewRomankBoldMetrics, "Times New Roman", SkTypeface::kBold, nullptr
-    },
-    {    TimesNewRomankItalicPoints, TimesNewRomankItalicVerbs, TimesNewRomankItalicCharCodes,
-         TimesNewRomankItalicCharCodesCount, TimesNewRomankItalicWidths,
-         TimesNewRomankItalicMetrics, "Times New Roman", SkTypeface::kItalic, nullptr
-    },
-    {    TimesNewRomankBoldItalicPoints, TimesNewRomankBoldItalicVerbs, TimesNewRomankBoldItalicCharCodes,
-         TimesNewRomankBoldItalicCharCodesCount, TimesNewRomankBoldItalicWidths,
-         TimesNewRomankBoldItalicMetrics, "Times New Roman", SkTypeface::kBoldItalic, nullptr
-    },
-};
-
-const int gTestFontsCount = (int) SK_ARRAY_COUNT(gTestFonts);
-
-struct SubFont {
-    const char* fName;
-    SkTypeface::Style fStyle;
-    SkTestFontData& fFont;
-    const char* fFile;
-};
-
-const SubFont gSubFonts[] = {
-    { "Courier New", SkTypeface::kNormal, gTestFonts[0], "Courier New.ttf"},
-    { "Courier New", SkTypeface::kBold, gTestFonts[1], "Courier New Bold.ttf"},
-    { "Courier New", SkTypeface::kItalic, gTestFonts[2], "Courier New Italic.ttf"},
-    { "Courier New", SkTypeface::kBoldItalic, gTestFonts[3], "Courier New Bold Italic.ttf"},
-    { "Helvetica", SkTypeface::kNormal, gTestFonts[4], "LiberationSans-Regular.ttf"},
-    { "Helvetica", SkTypeface::kBold, gTestFonts[5], "LiberationSans-Bold.ttf"},
-    { "Helvetica", SkTypeface::kItalic, gTestFonts[6], "LiberationSans-Italic.ttf"},
-    { "Helvetica", SkTypeface::kBoldItalic, gTestFonts[7], "LiberationSans-BoldItalic.ttf"},
-    { "Hiragino Maru Gothic Pro", SkTypeface::kNormal, gTestFonts[8], "Pro W4.otf"},
-    { "Liberation Sans", SkTypeface::kNormal, gTestFonts[4], "LiberationSans-Regular.ttf"},
-    { "Liberation Sans", SkTypeface::kBold, gTestFonts[5], "LiberationSans-Bold.ttf"},
-    { "Liberation Sans", SkTypeface::kItalic, gTestFonts[6], "LiberationSans-Italic.ttf"},
-    { "Liberation Sans", SkTypeface::kBoldItalic, gTestFonts[7], "LiberationSans-BoldItalic.ttf"},
-    { "monospace", SkTypeface::kNormal, gTestFonts[0], "Courier New.ttf"},
-    { "monospace", SkTypeface::kBold, gTestFonts[1], "Courier New Bold.ttf"},
-    { "monospace", SkTypeface::kItalic, gTestFonts[2], "Courier New Italic.ttf"},
-    { "monospace", SkTypeface::kBoldItalic, gTestFonts[3], "Courier New Bold Italic.ttf"},
-    { "Papyrus", SkTypeface::kNormal, gTestFonts[9], "Papyrus.ttc"},
-    { "sans-serif", SkTypeface::kNormal, gTestFonts[4], "LiberationSans-Regular.ttf"},
-    { "sans-serif", SkTypeface::kBold, gTestFonts[5], "LiberationSans-Bold.ttf"},
-    { "sans-serif", SkTypeface::kItalic, gTestFonts[6], "LiberationSans-Italic.ttf"},
-    { "sans-serif", SkTypeface::kBoldItalic, gTestFonts[7], "LiberationSans-BoldItalic.ttf"},
-    { "serif", SkTypeface::kNormal, gTestFonts[10], "Times New Roman.ttf"},
-    { "serif", SkTypeface::kBold, gTestFonts[11], "Times New Roman Bold.ttf"},
-    { "serif", SkTypeface::kItalic, gTestFonts[12], "Times New Roman Italic.ttf"},
-    { "serif", SkTypeface::kBoldItalic, gTestFonts[13], "Times New Roman Bold Italic.ttf"},
-    { "Times", SkTypeface::kNormal, gTestFonts[10], "Times New Roman.ttf"},
-    { "Times", SkTypeface::kBold, gTestFonts[11], "Times New Roman Bold.ttf"},
-    { "Times", SkTypeface::kItalic, gTestFonts[12], "Times New Roman Italic.ttf"},
-    { "Times", SkTypeface::kBoldItalic, gTestFonts[13], "Times New Roman Bold Italic.ttf"},
-    { "Times New Roman", SkTypeface::kNormal, gTestFonts[10], "Times New Roman.ttf"},
-    { "Times New Roman", SkTypeface::kBold, gTestFonts[11], "Times New Roman Bold.ttf"},
-    { "Times New Roman", SkTypeface::kItalic, gTestFonts[12], "Times New Roman Italic.ttf"},
-    { "Times New Roman", SkTypeface::kBoldItalic, gTestFonts[13], "Times New Roman Bold Italic.ttf"},
-    { "Times Roman", SkTypeface::kNormal, gTestFonts[4], "LiberationSans-Regular.ttf"},
-};
-
-const int gSubFontsCount = (int) SK_ARRAY_COUNT(gSubFonts);
-
-const int gDefaultFontIndex = 12;
diff --git a/src/third_party/skia/tools/test_font_data_chars.cpp b/src/third_party/skia/tools/test_font_data_chars.cpp
deleted file mode 100644
index ffbfa88..0000000
--- a/src/third_party/skia/tools/test_font_data_chars.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Auto-generated by sk_tool_utils_font.cpp
-
-const char gCourierNew[] =
-    " !/<>ACHMTWYabcdefgilmnoprstuy";
-const char gCourierNew_Bold[] =
-    " AHTWYabefgmnoprsuy";
-const char gCourierNew_Italic[] =
-    " AHTWYabefgmnoprsuy";
-const char gCourierNew_BoldItalic[] =
-    " AHTWYabefgmnoprsuy";
-const char gLiberationSans[] =
-    " !#%&')*+-./1245679:;<=>?@ABCDEFHIJKLMNOPQRSTVWXYZ[\\]^`abcdefgilmnopqrstuvwxyz";
-const char gLiberationSans_Bold[] =
-    " !\"#$%&'()*+-./012356789:;=>?ABCDEFGHIJLMORSTUVWXYZ[]^_abdefghijklmnopqrsuvwxyz";
-const char gLiberationSans_Italic[] =
-    " AHTWYabefgmnoprsuy";
-const char gLiberationSans_BoldItalic[] =
-    " !,-./012345689:ABCDEFGHIKLMNOPQRSTUWXYZ[\\]_abcdefghijklmnopqrstuvwxyz";
-const char gHiraginoMaruGothicPro[] =
-    " !Tacefnprsuy" "\xE3" "\x83" "\xBC";
-const char gPapyrus[] =
-    " !HTaceflnoprsuy";
-const char gTimesNewRoman[] =
-    " !\"#$%&'()*+,-./123456789;<=>?@ABCDEFGHIJKLMNPQRSTVWXYZ[\\]^_`abcdefgijklmnopqrstuvwxyz";
-const char gTimesNewRoman_Bold[] =
-    " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz";
-const char gTimesNewRoman_Italic[] =
-    " AHTWYabefgmnoprsuy";
-const char gTimesNewRoman_BoldItalic[] =
-    " AHTWYabefgmnoprsuy";
diff --git a/src/third_party/skia/tools/test_font_index.inc b/src/third_party/skia/tools/test_font_index.inc
deleted file mode 100644
index b52c004..0000000
--- a/src/third_party/skia/tools/test_font_index.inc
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Auto-generated by create_test_font.cpp
-
-static SkTestFontData gTestFonts[] = {
-    {    LiberationMonoNormalPoints, LiberationMonoNormalVerbs, LiberationMonoNormalCharCodes,
-         LiberationMonoNormalCharCodesCount, LiberationMonoNormalWidths,
-         LiberationMonoNormalMetrics, "Toy Liberation Mono", SkTypeface::kNormal, nullptr
-    },
-    {    LiberationMonoBoldPoints, LiberationMonoBoldVerbs, LiberationMonoBoldCharCodes,
-         LiberationMonoBoldCharCodesCount, LiberationMonoBoldWidths,
-         LiberationMonoBoldMetrics, "Toy Liberation Mono", SkTypeface::kBold, nullptr
-    },
-    {    LiberationMonoItalicPoints, LiberationMonoItalicVerbs, LiberationMonoItalicCharCodes,
-         LiberationMonoItalicCharCodesCount, LiberationMonoItalicWidths,
-         LiberationMonoItalicMetrics, "Toy Liberation Mono", SkTypeface::kItalic, nullptr
-    },
-    {    LiberationMonoBoldItalicPoints, LiberationMonoBoldItalicVerbs, LiberationMonoBoldItalicCharCodes,
-         LiberationMonoBoldItalicCharCodesCount, LiberationMonoBoldItalicWidths,
-         LiberationMonoBoldItalicMetrics, "Toy Liberation Mono", SkTypeface::kBoldItalic, nullptr
-    },
-    {    LiberationSansNormalPoints, LiberationSansNormalVerbs, LiberationSansNormalCharCodes,
-         LiberationSansNormalCharCodesCount, LiberationSansNormalWidths,
-         LiberationSansNormalMetrics, "Toy Liberation Sans", SkTypeface::kNormal, nullptr
-    },
-    {    LiberationSansBoldPoints, LiberationSansBoldVerbs, LiberationSansBoldCharCodes,
-         LiberationSansBoldCharCodesCount, LiberationSansBoldWidths,
-         LiberationSansBoldMetrics, "Toy Liberation Sans", SkTypeface::kBold, nullptr
-    },
-    {    LiberationSansItalicPoints, LiberationSansItalicVerbs, LiberationSansItalicCharCodes,
-         LiberationSansItalicCharCodesCount, LiberationSansItalicWidths,
-         LiberationSansItalicMetrics, "Toy Liberation Sans", SkTypeface::kItalic, nullptr
-    },
-    {    LiberationSansBoldItalicPoints, LiberationSansBoldItalicVerbs, LiberationSansBoldItalicCharCodes,
-         LiberationSansBoldItalicCharCodesCount, LiberationSansBoldItalicWidths,
-         LiberationSansBoldItalicMetrics, "Toy Liberation Sans", SkTypeface::kBoldItalic, nullptr
-    },
-    {    LiberationSerifNormalPoints, LiberationSerifNormalVerbs, LiberationSerifNormalCharCodes,
-         LiberationSerifNormalCharCodesCount, LiberationSerifNormalWidths,
-         LiberationSerifNormalMetrics, "Toy Liberation Serif", SkTypeface::kNormal, nullptr
-    },
-    {    LiberationSerifBoldPoints, LiberationSerifBoldVerbs, LiberationSerifBoldCharCodes,
-         LiberationSerifBoldCharCodesCount, LiberationSerifBoldWidths,
-         LiberationSerifBoldMetrics, "Toy Liberation Serif", SkTypeface::kBold, nullptr
-    },
-    {    LiberationSerifItalicPoints, LiberationSerifItalicVerbs, LiberationSerifItalicCharCodes,
-         LiberationSerifItalicCharCodesCount, LiberationSerifItalicWidths,
-         LiberationSerifItalicMetrics, "Toy Liberation Serif", SkTypeface::kItalic, nullptr
-    },
-    {    LiberationSerifBoldItalicPoints, LiberationSerifBoldItalicVerbs, LiberationSerifBoldItalicCharCodes,
-         LiberationSerifBoldItalicCharCodesCount, LiberationSerifBoldItalicWidths,
-         LiberationSerifBoldItalicMetrics, "Toy Liberation Serif", SkTypeface::kBoldItalic, nullptr
-    },
-};
-
-const int gTestFontsCount = (int) SK_ARRAY_COUNT(gTestFonts);
-
-struct SubFont {
-    const char* fName;
-    SkFontStyle fStyle;
-    SkTestFontData& fFont;
-    const char* fFile;
-};
-
-const SubFont gSubFonts[] = {
-    { "monospace", SkFontStyle(), gTestFonts[0], "LiberationMono-Regular.ttf" },
-    { "monospace", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[1], "LiberationMono-Bold.ttf" },
-    { "monospace", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[2], "LiberationMono-Italic.ttf" },
-    { "monospace", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[3], "LiberationMono-BoldItalic.ttf" },
-    { "sans-serif", SkFontStyle(), gTestFonts[4], "LiberationSans-Regular.ttf" },
-    { "sans-serif", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[5], "LiberationSans-Bold.ttf" },
-    { "sans-serif", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[6], "LiberationSans-Italic.ttf" },
-    { "sans-serif", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[7], "LiberationSans-BoldItalic.ttf" },
-    { "serif", SkFontStyle(), gTestFonts[8], "LiberationSerif-Regular.ttf" },
-    { "serif", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[9], "LiberationSerif-Bold.ttf" },
-    { "serif", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[10], "LiberationSerif-Italic.ttf" },
-    { "serif", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[11], "LiberationSerif-BoldItalic.ttf" },
-    { "Toy Liberation Mono", SkFontStyle(), gTestFonts[0], "LiberationMono-Regular.ttf" },
-    { "Toy Liberation Mono", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[1], "LiberationMono-Bold.ttf" },
-    { "Toy Liberation Mono", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[2], "LiberationMono-Italic.ttf" },
-    { "Toy Liberation Mono", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[3], "LiberationMono-BoldItalic.ttf" },
-    { "Toy Liberation Sans", SkFontStyle(), gTestFonts[4], "LiberationSans-Regular.ttf" },
-    { "Toy Liberation Sans", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[5], "LiberationSans-Bold.ttf" },
-    { "Toy Liberation Sans", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[6], "LiberationSans-Italic.ttf" },
-    { "Toy Liberation Sans", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[7], "LiberationSans-BoldItalic.ttf" },
-    { "Toy Liberation Serif", SkFontStyle(), gTestFonts[8], "LiberationSerif-Regular.ttf" },
-    { "Toy Liberation Serif", SkFontStyle::FromOldStyle(SkTypeface::kBold), gTestFonts[9], "LiberationSerif-Bold.ttf" },
-    { "Toy Liberation Serif", SkFontStyle::FromOldStyle(SkTypeface::kItalic), gTestFonts[10], "LiberationSerif-Italic.ttf" },
-    { "Toy Liberation Serif", SkFontStyle::FromOldStyle(SkTypeface::kBoldItalic), gTestFonts[11], "LiberationSerif-BoldItalic.ttf" },
-};
-
-const int gSubFontsCount = (int) SK_ARRAY_COUNT(gSubFonts);
-
-const int gDefaultFontIndex = 4;
diff --git a/src/third_party/skia/tools/test_gpuveto.py b/src/third_party/skia/tools/test_gpuveto.py
deleted file mode 100755
index fbb29ae..0000000
--- a/src/third_party/skia/tools/test_gpuveto.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2014 Google Inc.
-#
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Script to test out suitableForGpuRasterization (via gpuveto)"""
-
-import argparse
-import glob
-import os
-import re
-import subprocess
-import sys
-
-# Set the PYTHONPATH to include the tools directory.
-sys.path.append(
-    os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
-import find_run_binary
-
-def list_files(dir_or_file):
-    """Returns a list of all the files from the provided argument
-
-    @param dir_or_file: either a directory or skp file
-
-    @returns a list containing the files in the directory or a single file
-    """
-    files = []
-    for globbedpath in glob.iglob(dir_or_file): # useful on win32
-        if os.path.isdir(globbedpath):
-            for filename in os.listdir(globbedpath):
-                newpath = os.path.join(globbedpath, filename)
-                if os.path.isfile(newpath):
-                    files.append(newpath)
-        elif os.path.isfile(globbedpath):
-            files.append(globbedpath)
-    return files
-
-
-def execute_program(args):
-    """Executes a process and waits for it to complete.
-
-    @param args: is passed into subprocess.Popen().
-
-    @returns a tuple of the process output (returncode, output)
-    """
-    proc = subprocess.Popen(args, stdout=subprocess.PIPE, 
-                            stderr=subprocess.STDOUT)
-    output, _ = proc.communicate()
-    errcode = proc.returncode
-    return (errcode, output)
-
-
-class GpuVeto(object):
-
-    def __init__(self):
-        self.bench_pictures = find_run_binary.find_path_to_program(
-            'bench_pictures')
-        sys.stdout.write('Running: %s\n' % (self.bench_pictures))
-        self.gpuveto = find_run_binary.find_path_to_program('gpuveto')
-        assert os.path.isfile(self.bench_pictures)
-        assert os.path.isfile(self.gpuveto)
-        self.indeterminate = 0
-        self.truePositives = 0
-        self.falsePositives = 0
-        self.trueNegatives = 0
-        self.falseNegatives = 0
-
-    def process_skps(self, dir_or_file):
-        for skp in enumerate(dir_or_file):
-            self.process_skp(skp[1])
-
-        sys.stdout.write('TP %d FP %d TN %d FN %d IND %d\n' % (self.truePositives,
-                                                               self.falsePositives,
-                                                               self.trueNegatives,
-                                                               self.falseNegatives,
-                                                               self.indeterminate))
-
-
-    def process_skp(self, skp_file):
-        assert os.path.isfile(skp_file)
-        #print skp_file
-
-        # run gpuveto on the skp
-        args = [self.gpuveto, '-r', skp_file]
-        returncode, output = execute_program(args)
-        if (returncode != 0):
-            return
-
-        if ('unsuitable' in output):
-            suitable = False
-        else:
-            assert 'suitable' in output
-            suitable = True
-
-        # run raster config
-        args = [self.bench_pictures, '-r', skp_file, 
-                                     '--repeat', '20',
-                                     '--timers', 'w',
-                                     '--config', '8888']
-        returncode, output = execute_program(args)
-        if (returncode != 0):
-            return
-
-        matches = re.findall('[\d]+\.[\d]+', output)
-        if len(matches) != 1:
-            return
-
-        rasterTime = float(matches[0])
-
-        # run gpu config
-        args2 = [self.bench_pictures, '-r', skp_file, 
-                                      '--repeat', '20',
-                                      '--timers', 'w',
-                                      '--config', 'gpu']
-        returncode, output = execute_program(args2)
-        if (returncode != 0):
-            return
-
-        matches = re.findall('[\d]+\.[\d]+', output)
-        if len(matches) != 1:
-            return
-
-        gpuTime = float(matches[0])
-
-        # happens if page is too big it will not render
-        if 0 == gpuTime:
-            return
-
-        tolerance = 0.05
-        tol_range = tolerance * gpuTime
-
-
-        if rasterTime > gpuTime - tol_range and rasterTime < gpuTime + tol_range:
-            result = "NONE"
-            self.indeterminate += 1
-        elif suitable:
-            if gpuTime < rasterTime:
-                self.truePositives += 1
-                result = "TP"
-            else:
-                self.falsePositives += 1
-                result = "FP"
-        else:
-            if gpuTime < rasterTime:
-                self.falseNegatives += 1
-                result = "FN"
-            else:
-                self.trueNegatives += 1
-                result = "TN"
-        
-
-        sys.stdout.write('%s: gpuveto: %d raster %.2f gpu: %.2f  Result: %s\n' % (
-            skp_file, suitable, rasterTime, gpuTime, result))
-
-def main(main_argv):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--skp_path',
-                        help='Path to the SKP(s). Can either be a directory ' \
-                        'containing SKPs or a single SKP.',
-                        required=True)
-
-    args = parser.parse_args()
-    GpuVeto().process_skps(list_files(args.skp_path))
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv[1]))
diff --git a/src/third_party/skia/tools/timer/TimeUtils.h b/src/third_party/skia/tools/timer/TimeUtils.h
new file mode 100644
index 0000000..5638f83
--- /dev/null
+++ b/src/third_party/skia/tools/timer/TimeUtils.h
@@ -0,0 +1,62 @@
+// Copyright 2019 Google LLC
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TimeUtils_DEFINED
+#define TimeUtils_DEFINED
+
+#include "include/core/SkTypes.h"
+#include "include/private/SkFloatingPoint.h"
+
+#include <cmath>
+
+namespace TimeUtils {
+    // Returns 0 if the timer is stopped. Behavior is undefined if the timer
+    // has been running longer than SK_MSecMax.
+    static inline SkMSec NanosToMSec(double nanos) {
+        const double msec = nanos * 1e-6;
+        SkASSERT(SK_MSecMax >= msec);
+        return static_cast<SkMSec>(msec);
+    }
+
+    static inline double NanosToSeconds(double nanos) {
+        return nanos * 1e-9;
+    }
+
+    // Return the time scaled by "speed" and (if not zero) mod by period.
+    static inline float Scaled(float time, float speed, float period = 0) {
+        double value = time * speed;
+        if (period) {
+            value = ::fmod(value, (double)(period));
+        }
+        return (float)value;
+    }
+
+    // Transitions from ends->mid->ends linearly over period time. The phase
+    // specifies a phase shift in time units.
+    static inline float PingPong(double time,
+                                 float period,
+                                 float phase,
+                                 float ends,
+                                 float mid) {
+        double value = ::fmod(time + phase, period);
+        double half  = period / 2.0;
+        double diff  = ::fabs(value - half);
+        return (float)(ends + (1.0 - diff / half) * (mid - ends));
+    }
+
+    static inline float SineWave(double time,
+                                 float periodInSecs,
+                                 float phaseInSecs,
+                                 float min,
+                                 float max) {
+        if (periodInSecs < 0.f) {
+            return (min + max) / 2.f;
+        }
+        double t = NanosToSeconds(time) + phaseInSecs;
+        t *= 2 * SK_FloatPI / periodInSecs;
+        float halfAmplitude = (max - min) / 2.f;
+        return halfAmplitude * std::sin(t) + halfAmplitude + min;
+    }
+}  // namespace TimeUtils
+#endif
diff --git a/src/third_party/skia/tools/timer/Timer.cpp b/src/third_party/skia/tools/timer/Timer.cpp
index 28841cd..fe214c4 100644
--- a/src/third_party/skia/tools/timer/Timer.cpp
+++ b/src/third_party/skia/tools/timer/Timer.cpp
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "Timer.h"
+#include "tools/timer/Timer.h"
 
 SkString HumanizeMs(double ms) {
     if (ms > 60e+3)  return SkStringPrintf("%.3gm", ms/60e+3);
diff --git a/src/third_party/skia/tools/timer/Timer.h b/src/third_party/skia/tools/timer/Timer.h
index 446eb25..d461c58 100644
--- a/src/third_party/skia/tools/timer/Timer.h
+++ b/src/third_party/skia/tools/timer/Timer.h
@@ -7,19 +7,7 @@
 #ifndef Timer_DEFINED
 #define Timer_DEFINED
 
-#include "SkString.h"
-#include "SkTime.h"
-#include "SkTypes.h"
-
-class WallTimer {
-public:
-    WallTimer() : fWall(-1) {}
-
-    void start() { fWall = SkTime::GetNSecs(); }
-    void end()   { fWall = (SkTime::GetNSecs() - fWall) * 1e-6; }
-
-    double fWall;  // Milliseconds.
-};
+#include "include/core/SkString.h"
 
 SkString HumanizeMs(double);
 
diff --git a/src/third_party/skia/tools/trace/ChromeTracingTracer.cpp b/src/third_party/skia/tools/trace/ChromeTracingTracer.cpp
new file mode 100644
index 0000000..530c3c3
--- /dev/null
+++ b/src/third_party/skia/tools/trace/ChromeTracingTracer.cpp
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkStream.h"
+#include "include/private/SkThreadID.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkTraceEvent.h"
+#include "src/utils/SkJSONWriter.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/trace/ChromeTracingTracer.h"
+
+#include <chrono>
+
+namespace {
+
+/**
+ * All events have a fixed block of information (TraceEvent), plus variable length payload:
+ * {TraceEvent} {TraceEventArgs} {Inline Payload}
+ */
+struct TraceEventArg {
+    uint8_t     fArgType;
+    const char* fArgName;
+    uint64_t    fArgValue;
+};
+
+// These fields are ordered to minimize size due to alignment. Argument types could be packed
+// better, but very few events have many arguments, so the net loss is pretty small.
+struct TraceEvent {
+    char     fPhase;
+    uint8_t  fNumArgs;
+    uint32_t fSize;
+
+    const char* fName;
+    // TODO: Merge fID and fClockEnd (never used together)
+    uint64_t   fID;
+    uint64_t   fClockBegin;
+    uint64_t   fClockEnd;
+    SkThreadID fThreadID;
+
+    TraceEvent* next() {
+        return reinterpret_cast<TraceEvent*>(reinterpret_cast<char*>(this) + fSize);
+    }
+    TraceEventArg* args() { return reinterpret_cast<TraceEventArg*>(this + 1); }
+    char*          stringTable() { return reinterpret_cast<char*>(this->args() + fNumArgs); }
+};
+
+}  // namespace
+
+ChromeTracingTracer::ChromeTracingTracer(const char* filename) : fFilename(filename) {
+    this->createBlock();
+}
+
+ChromeTracingTracer::~ChromeTracingTracer() { this->flush(); }
+
+void ChromeTracingTracer::createBlock() {
+    fCurBlock.fBlock         = BlockPtr(new uint8_t[kBlockSize]);
+    fCurBlock.fEventsInBlock = 0;
+    fCurBlockUsed            = 0;
+}
+
+SkEventTracer::Handle ChromeTracingTracer::appendEvent(const void* data, size_t size) {
+    SkASSERT(size > 0 && size <= kBlockSize);
+
+    SkAutoSpinlock lock(fMutex);
+    if (fCurBlockUsed + size > kBlockSize) {
+        fBlocks.push_back(std::move(fCurBlock));
+        this->createBlock();
+    }
+    memcpy(fCurBlock.fBlock.get() + fCurBlockUsed, data, size);
+    Handle handle = reinterpret_cast<Handle>(fCurBlock.fBlock.get() + fCurBlockUsed);
+    fCurBlockUsed += size;
+    fCurBlock.fEventsInBlock++;
+    return handle;
+}
+
+SkEventTracer::Handle ChromeTracingTracer::addTraceEvent(char            phase,
+                                                         const uint8_t*  categoryEnabledFlag,
+                                                         const char*     name,
+                                                         uint64_t        id,
+                                                         int             numArgs,
+                                                         const char**    argNames,
+                                                         const uint8_t*  argTypes,
+                                                         const uint64_t* argValues,
+                                                         uint8_t         flags) {
+    // TODO: Respect flags (or assert). INSTANT events encode scope in flags, should be stored
+    // using "s" key in JSON. COPY flag should be supported or rejected.
+
+    // Figure out how much extra storage we need for copied strings
+    int size = static_cast<int>(sizeof(TraceEvent) + numArgs * sizeof(TraceEventArg));
+    for (int i = 0; i < numArgs; ++i) {
+        if (TRACE_VALUE_TYPE_COPY_STRING == argTypes[i]) {
+            skia::tracing_internals::TraceValueUnion value;
+            value.as_uint = argValues[i];
+            size += strlen(value.as_string) + 1;
+        }
+    }
+
+    size = SkAlign8(size);
+
+    SkSTArray<128, uint8_t, true> storage;
+    uint8_t*                      storagePtr = storage.push_back_n(size);
+
+    TraceEvent* traceEvent  = reinterpret_cast<TraceEvent*>(storagePtr);
+    traceEvent->fPhase      = phase;
+    traceEvent->fNumArgs    = numArgs;
+    traceEvent->fSize       = size;
+    traceEvent->fName       = name;
+    traceEvent->fID         = id;
+    traceEvent->fClockBegin = std::chrono::steady_clock::now().time_since_epoch().count();
+    traceEvent->fClockEnd   = 0;
+    traceEvent->fThreadID   = SkGetThreadID();
+
+    TraceEventArg* traceEventArgs  = traceEvent->args();
+    char*          stringTableBase = traceEvent->stringTable();
+    char*          stringTable     = stringTableBase;
+    for (int i = 0; i < numArgs; ++i) {
+        traceEventArgs[i].fArgName = argNames[i];
+        traceEventArgs[i].fArgType = argTypes[i];
+        if (TRACE_VALUE_TYPE_COPY_STRING == argTypes[i]) {
+            // Just write an offset into the arguments array
+            traceEventArgs[i].fArgValue = stringTable - stringTableBase;
+
+            // Copy string into our buffer (and advance)
+            skia::tracing_internals::TraceValueUnion value;
+            value.as_uint = argValues[i];
+            while (*value.as_string) {
+                *stringTable++ = *value.as_string++;
+            }
+            *stringTable++ = 0;
+        } else {
+            traceEventArgs[i].fArgValue = argValues[i];
+        }
+    }
+
+    return this->appendEvent(storagePtr, size);
+}
+
+void ChromeTracingTracer::updateTraceEventDuration(const uint8_t*        categoryEnabledFlag,
+                                                   const char*           name,
+                                                   SkEventTracer::Handle handle) {
+    // We could probably get away with not locking here, but let's be totally safe.
+    SkAutoSpinlock lock(fMutex);
+    TraceEvent*    traceEvent = reinterpret_cast<TraceEvent*>(handle);
+    traceEvent->fClockEnd         = std::chrono::steady_clock::now().time_since_epoch().count();
+}
+
+static void trace_value_to_json(SkJSONWriter* writer,
+                                uint64_t      argValue,
+                                uint8_t       argType,
+                                const char*   stringTableBase) {
+    skia::tracing_internals::TraceValueUnion value;
+    value.as_uint = argValue;
+
+    switch (argType) {
+        case TRACE_VALUE_TYPE_BOOL: writer->appendBool(value.as_bool); break;
+        case TRACE_VALUE_TYPE_UINT: writer->appendU64(value.as_uint); break;
+        case TRACE_VALUE_TYPE_INT: writer->appendS64(value.as_int); break;
+        case TRACE_VALUE_TYPE_DOUBLE: writer->appendDouble(value.as_double); break;
+        case TRACE_VALUE_TYPE_POINTER: writer->appendPointer(value.as_pointer); break;
+        case TRACE_VALUE_TYPE_STRING: writer->appendString(value.as_string); break;
+        case TRACE_VALUE_TYPE_COPY_STRING:
+            writer->appendString(stringTableBase + value.as_uint);
+            break;
+        default: writer->appendString("<unknown type>"); break;
+    }
+}
+
+namespace {
+
+struct TraceEventSerializationState {
+    TraceEventSerializationState(uint64_t clockOffset)
+            : fClockOffset(clockOffset), fNextThreadID(0) {}
+
+    int getShortThreadID(SkThreadID id) {
+        if (int* shortIDPtr = fShortThreadIDMap.find(id)) {
+            return *shortIDPtr;
+        }
+        int shortID = fNextThreadID++;
+        fShortThreadIDMap.set(id, shortID);
+        return shortID;
+    }
+
+    uint64_t                          fClockOffset;
+    SkTHashMap<uint64_t, const char*> fBaseTypeResolver;
+    int                               fNextThreadID;
+    SkTHashMap<SkThreadID, int>       fShortThreadIDMap;
+};
+
+}  // namespace
+
+static void trace_event_to_json(SkJSONWriter*                 writer,
+                                TraceEvent*                   traceEvent,
+                                TraceEventSerializationState* serializationState) {
+    // We track the original (creation time) "name" of each currently live object, so we can
+    // automatically insert "base_name" fields in object snapshot events.
+    auto baseTypeResolver = &(serializationState->fBaseTypeResolver);
+    if (TRACE_EVENT_PHASE_CREATE_OBJECT == traceEvent->fPhase) {
+        SkASSERT(nullptr == baseTypeResolver->find(traceEvent->fID));
+        baseTypeResolver->set(traceEvent->fID, traceEvent->fName);
+    } else if (TRACE_EVENT_PHASE_DELETE_OBJECT == traceEvent->fPhase) {
+        SkASSERT(nullptr != baseTypeResolver->find(traceEvent->fID));
+        baseTypeResolver->remove(traceEvent->fID);
+    }
+
+    writer->beginObject();
+
+    char phaseString[2] = {traceEvent->fPhase, 0};
+    writer->appendString("ph", phaseString);
+    writer->appendString("name", traceEvent->fName);
+    if (0 != traceEvent->fID) {
+        // IDs are (almost) always pointers
+        writer->appendPointer("id", reinterpret_cast<void*>(traceEvent->fID));
+    }
+
+    // Offset timestamps to reduce JSON length, then convert nanoseconds to microseconds
+    // (standard time unit for tracing JSON files).
+    uint64_t relativeTimestamp =
+            static_cast<int64_t>(traceEvent->fClockBegin - serializationState->fClockOffset);
+    writer->appendDouble("ts", static_cast<double>(relativeTimestamp) * 1E-3);
+    if (0 != traceEvent->fClockEnd) {
+        double dur = static_cast<double>(traceEvent->fClockEnd - traceEvent->fClockBegin) * 1E-3;
+        writer->appendDouble("dur", dur);
+    }
+
+    writer->appendS64("tid", serializationState->getShortThreadID(traceEvent->fThreadID));
+    // Trace events *must* include a process ID, but for internal tools this isn't particularly
+    // important (and certainly not worth adding a cross-platform API to get it).
+    writer->appendS32("pid", 0);
+
+    if (traceEvent->fNumArgs) {
+        writer->beginObject("args");
+        const char* stringTable   = traceEvent->stringTable();
+        bool        addedSnapshot = false;
+        if (TRACE_EVENT_PHASE_SNAPSHOT_OBJECT == traceEvent->fPhase &&
+            baseTypeResolver->find(traceEvent->fID) &&
+            0 != strcmp(*baseTypeResolver->find(traceEvent->fID), traceEvent->fName)) {
+            // Special handling for snapshots where the name differs from creation.
+            writer->beginObject("snapshot");
+            writer->appendString("base_type", *baseTypeResolver->find(traceEvent->fID));
+            addedSnapshot = true;
+        }
+
+        for (int i = 0; i < traceEvent->fNumArgs; ++i) {
+            const TraceEventArg* arg = traceEvent->args() + i;
+            // TODO: Skip '#'
+            writer->appendName(arg->fArgName);
+
+            if (arg->fArgName && '#' == arg->fArgName[0]) {
+                writer->beginObject();
+                writer->appendName("id_ref");
+                trace_value_to_json(writer, arg->fArgValue, arg->fArgType, stringTable);
+                writer->endObject();
+            } else {
+                trace_value_to_json(writer, arg->fArgValue, arg->fArgType, stringTable);
+            }
+        }
+
+        if (addedSnapshot) {
+            writer->endObject();
+        }
+
+        writer->endObject();
+    }
+
+    writer->endObject();
+}
+
+void ChromeTracingTracer::flush() {
+    SkAutoSpinlock lock(fMutex);
+
+    SkString dirname = SkOSPath::Dirname(fFilename.c_str());
+    if (!dirname.isEmpty() && !sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) {
+        if (!sk_mkdir(dirname.c_str())) {
+            SkDebugf("Failed to create directory.");
+        }
+    }
+
+    SkFILEWStream fileStream(fFilename.c_str());
+    SkJSONWriter  writer(&fileStream, SkJSONWriter::Mode::kFast);
+    writer.beginArray();
+
+    uint64_t clockOffset = 0;
+    if (fBlocks.count() > 0) {
+        clockOffset = reinterpret_cast<TraceEvent*>(fBlocks[0].fBlock.get())->fClockBegin;
+    } else if (fCurBlock.fEventsInBlock > 0) {
+        clockOffset = reinterpret_cast<TraceEvent*>(fCurBlock.fBlock.get())->fClockBegin;
+    }
+
+    TraceEventSerializationState serializationState(clockOffset);
+
+    auto event_block_to_json = [](SkJSONWriter*                 writer,
+                                  const TraceEventBlock&        block,
+                                  TraceEventSerializationState* serializationState) {
+        TraceEvent* traceEvent = reinterpret_cast<TraceEvent*>(block.fBlock.get());
+        for (int i = 0; i < block.fEventsInBlock; ++i) {
+            trace_event_to_json(writer, traceEvent, serializationState);
+            traceEvent = traceEvent->next();
+        }
+    };
+
+    for (int i = 0; i < fBlocks.count(); ++i) {
+        event_block_to_json(&writer, fBlocks[i], &serializationState);
+    }
+    event_block_to_json(&writer, fCurBlock, &serializationState);
+
+    writer.endArray();
+    writer.flush();
+    fileStream.flush();
+}
diff --git a/src/third_party/skia/tools/trace/ChromeTracingTracer.h b/src/third_party/skia/tools/trace/ChromeTracingTracer.h
new file mode 100644
index 0000000..56eed32
--- /dev/null
+++ b/src/third_party/skia/tools/trace/ChromeTracingTracer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ChromeTracingTracer_DEFINED
+#define ChromeTracingTracer_DEFINED
+
+#include "include/core/SkString.h"
+#include "include/private/SkSpinlock.h"
+#include "include/private/SkTHash.h"
+#include "include/utils/SkEventTracer.h"
+#include "tools/trace/EventTracingPriv.h"
+
+class SkJSONWriter;
+
+/**
+ * A SkEventTracer implementation that logs events to JSON for viewing with chrome://tracing.
+ */
+class ChromeTracingTracer : public SkEventTracer {
+public:
+    ChromeTracingTracer(const char* filename);
+    ~ChromeTracingTracer() override;
+
+    SkEventTracer::Handle addTraceEvent(char            phase,
+                                        const uint8_t*  categoryEnabledFlag,
+                                        const char*     name,
+                                        uint64_t        id,
+                                        int             numArgs,
+                                        const char**    argNames,
+                                        const uint8_t*  argTypes,
+                                        const uint64_t* argValues,
+                                        uint8_t         flags) override;
+
+    void updateTraceEventDuration(const uint8_t*        categoryEnabledFlag,
+                                  const char*           name,
+                                  SkEventTracer::Handle handle) override;
+
+    const uint8_t* getCategoryGroupEnabled(const char* name) override {
+        return fCategories.getCategoryGroupEnabled(name);
+    }
+
+    const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) override {
+        return fCategories.getCategoryGroupName(categoryEnabledFlag);
+    }
+
+private:
+    void flush();
+
+    enum {
+        // Events are variable size, but most commonly 48 bytes, assuming 64-bit pointers and
+        // reasonable packing. This is a first guess at a number that balances memory usage vs.
+        // time overhead of allocating blocks.
+        kBlockSize = 512 * 1024,
+    };
+
+    typedef std::unique_ptr<uint8_t[]> BlockPtr;
+    struct TraceEventBlock {
+        BlockPtr fBlock;
+        int      fEventsInBlock;
+    };
+
+    void createBlock();
+
+    Handle appendEvent(const void* data, size_t size);
+
+    SkString                 fFilename;
+    SkSpinlock               fMutex;
+    SkEventTracingCategories fCategories;
+
+    TraceEventBlock fCurBlock;
+    size_t          fCurBlockUsed;
+
+    SkTArray<TraceEventBlock> fBlocks;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/trace/EventTracingPriv.cpp b/src/third_party/skia/tools/trace/EventTracingPriv.cpp
new file mode 100644
index 0000000..47a7f52
--- /dev/null
+++ b/src/third_party/skia/tools/trace/EventTracingPriv.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/trace/EventTracingPriv.h"
+
+#include "include/utils/SkEventTracer.h"
+#include "src/core/SkATrace.h"
+#include "src/core/SkTraceEvent.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/trace/ChromeTracingTracer.h"
+#include "tools/trace/SkDebugfTracer.h"
+
+static DEFINE_string(trace,
+              "",
+              "Log trace events in one of several modes:\n"
+              "  debugf     : Show events using SkDebugf\n"
+              "  atrace     : Send events to Android ATrace\n"
+              "  <filename> : Any other string is interpreted as a filename. Writes\n"
+              "               trace events to specified file as JSON, for viewing\n"
+              "               with chrome://tracing");
+
+static DEFINE_string(traceMatch,
+              "",
+              "Filter which categories are traced.\n"
+              "Uses same format as --match\n");
+
+void initializeEventTracingForTools(const char* traceFlag) {
+    if (!traceFlag) {
+        if (FLAGS_trace.isEmpty()) {
+            return;
+        }
+        traceFlag = FLAGS_trace[0];
+    }
+
+    SkEventTracer* eventTracer = nullptr;
+    if (0 == strcmp(traceFlag, "atrace")) {
+        eventTracer = new SkATrace();
+    } else if (0 == strcmp(traceFlag, "debugf")) {
+        eventTracer = new SkDebugfTracer();
+    } else {
+        eventTracer = new ChromeTracingTracer(traceFlag);
+    }
+
+    SkAssertResult(SkEventTracer::SetInstance(eventTracer));
+}
+
+uint8_t* SkEventTracingCategories::getCategoryGroupEnabled(const char* name) {
+    static_assert(0 == offsetof(CategoryState, fEnabled), "CategoryState");
+
+    // We ignore the "disabled-by-default-" prefix in our internal tools
+    if (SkStrStartsWith(name, TRACE_CATEGORY_PREFIX)) {
+        name += strlen(TRACE_CATEGORY_PREFIX);
+    }
+
+    // Chrome's implementation of this API does a two-phase lookup (once without a lock, then again
+    // with a lock. But the tracing macros avoid calling these functions more than once per site,
+    // so just do something simple (and easier to reason about):
+    SkAutoMutexExclusive lock(fMutex);
+    for (int i = 0; i < fNumCategories; ++i) {
+        if (0 == strcmp(name, fCategories[i].fName)) {
+            return reinterpret_cast<uint8_t*>(&fCategories[i]);
+        }
+    }
+
+    if (fNumCategories >= kMaxCategories) {
+        SkDEBUGFAIL("Exhausted event tracing categories. Increase kMaxCategories.");
+        return reinterpret_cast<uint8_t*>(&fCategories[0]);
+    }
+
+    fCategories[fNumCategories].fEnabled =
+            CommandLineFlags::ShouldSkip(FLAGS_traceMatch, name)
+                    ? 0
+                    : SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags;
+
+    fCategories[fNumCategories].fName = name;
+    return reinterpret_cast<uint8_t*>(&fCategories[fNumCategories++]);
+}
+
+const char* SkEventTracingCategories::getCategoryGroupName(const uint8_t* categoryEnabledFlag) {
+    if (categoryEnabledFlag) {
+        return reinterpret_cast<const CategoryState*>(categoryEnabledFlag)->fName;
+    }
+    return nullptr;
+}
diff --git a/src/third_party/skia/tools/trace/EventTracingPriv.h b/src/third_party/skia/tools/trace/EventTracingPriv.h
new file mode 100644
index 0000000..44fc9f4
--- /dev/null
+++ b/src/third_party/skia/tools/trace/EventTracingPriv.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef EventTracingPriv_DEFINED
+#define EventTracingPriv_DEFINED
+
+#include "include/private/SkMutex.h"
+
+/**
+ * Construct and install an SkEventTracer, based on the mode,
+ * defaulting to the --trace command line argument.
+ */
+void initializeEventTracingForTools(const char* mode = nullptr);
+
+/**
+ * Helper class used by internal implementations of SkEventTracer to manage categories.
+ */
+class SkEventTracingCategories {
+public:
+    SkEventTracingCategories() : fNumCategories(0) {}
+
+    uint8_t*    getCategoryGroupEnabled(const char* name);
+    const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag);
+
+private:
+    enum { kMaxCategories = 256 };
+
+    struct CategoryState {
+        uint8_t     fEnabled;
+        const char* fName;
+    };
+
+    CategoryState fCategories[kMaxCategories];
+    int           fNumCategories;
+    SkMutex       fMutex;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/trace/SkDebugfTracer.cpp b/src/third_party/skia/tools/trace/SkDebugfTracer.cpp
index 272af78..bd2feea 100644
--- a/src/third_party/skia/tools/trace/SkDebugfTracer.cpp
+++ b/src/third_party/skia/tools/trace/SkDebugfTracer.cpp
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#include "SkDebugfTracer.h"
-#include "SkTraceEvent.h"
+#include "src/core/SkTraceEvent.h"
+#include "tools/trace/SkDebugfTracer.h"
 
 SkEventTracer::Handle SkDebugfTracer::addTraceEvent(char phase,
                                                     const uint8_t* categoryEnabledFlag,
@@ -24,11 +24,11 @@
         } else {
             args.append(" ");
         }
+        skia::tracing_internals::TraceValueUnion value;
+        value.as_uint = argValues[i];
         switch (argTypes[i]) {
             case TRACE_VALUE_TYPE_BOOL:
-                args.appendf("%s=%s",
-                             argNames[i],
-                             (*reinterpret_cast<bool*>(argValues[i]) ? "true" : "false"));
+                args.appendf("%s=%s", argNames[i], value.as_bool ? "true" : "false");
                 break;
             case TRACE_VALUE_TYPE_UINT:
                 args.appendf("%s=%u", argNames[i], static_cast<uint32_t>(argValues[i]));
@@ -37,16 +37,15 @@
                 args.appendf("%s=%d", argNames[i], static_cast<int32_t>(argValues[i]));
                 break;
             case TRACE_VALUE_TYPE_DOUBLE:
-                args.appendf("%s=%g", argNames[i], *SkTCast<const double*>(&argValues[i]));
+                args.appendf("%s=%g", argNames[i], value.as_double);
                 break;
             case TRACE_VALUE_TYPE_POINTER:
-                args.appendf("%s=0x%p", argNames[i], reinterpret_cast<void*>(argValues[i]));
+                args.appendf("%s=0x%p", argNames[i], value.as_pointer);
                 break;
             case TRACE_VALUE_TYPE_STRING:
             case TRACE_VALUE_TYPE_COPY_STRING: {
                 static constexpr size_t kMaxLen = 20;
-                const char* str = reinterpret_cast<const char*>(argValues[i]);
-                SkString string(str);
+                SkString string(value.as_string);
                 size_t truncAt = string.size();
                 size_t newLineAt = SkStrFind(string.c_str(), "\n");
                 if (newLineAt > 0) {
@@ -67,8 +66,9 @@
     }
     bool open = (phase == TRACE_EVENT_PHASE_COMPLETE);
     if (open) {
-        SkDebugf(
-                "[% 2d]%s %s%s #%d {\n", fIndent.size(), fIndent.c_str(), name, args.c_str(), fCnt);
+        const char* category = this->getCategoryGroupName(categoryEnabledFlag);
+        SkDebugf("[% 2d]%s <%s> %s%s #%d {\n", fIndent.size(), fIndent.c_str(), category, name,
+                 args.c_str(), fCnt);
         fIndent.append(" ");
     } else {
         SkDebugf("%s%s #%d\n", name, args.c_str(), fCnt);
@@ -83,8 +83,3 @@
     fIndent.resize(fIndent.size() - 1);
     SkDebugf("[% 2d]%s } %s\n", fIndent.size(), fIndent.c_str(), name);
 }
-
-const uint8_t* SkDebugfTracer::getCategoryGroupEnabled(const char* name) {
-    static uint8_t yes = SkEventTracer::kEnabledForRecording_CategoryGroupEnabledFlags;
-    return &yes;
-}
diff --git a/src/third_party/skia/tools/trace/SkDebugfTracer.h b/src/third_party/skia/tools/trace/SkDebugfTracer.h
index 4350d1a..bd19f51 100644
--- a/src/third_party/skia/tools/trace/SkDebugfTracer.h
+++ b/src/third_party/skia/tools/trace/SkDebugfTracer.h
@@ -8,8 +8,9 @@
 #ifndef SkDebugfTracer_DEFINED
 #define SkDebugfTracer_DEFINED
 
-#include "SkEventTracer.h"
-#include "SkString.h"
+#include "include/core/SkString.h"
+#include "include/utils/SkEventTracer.h"
+#include "tools/trace/EventTracingPriv.h"
 
 /**
  * A SkEventTracer implementation that logs events using SkDebugf.
@@ -32,16 +33,18 @@
                                   const char* name,
                                   SkEventTracer::Handle handle) override;
 
-    const uint8_t* getCategoryGroupEnabled(const char* name) override;
+    const uint8_t* getCategoryGroupEnabled(const char* name) override {
+        return fCategories.getCategoryGroupEnabled(name);
+    }
 
     const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) override {
-        static const char* category = "category?";
-        return category;
+        return fCategories.getCategoryGroupName(categoryEnabledFlag);
     }
 
 private:
     SkString fIndent;
     int fCnt = 0;
+    SkEventTracingCategories fCategories;
 };
 
 #endif
diff --git a/src/third_party/skia/tools/using_skia_and_harfbuzz.cpp b/src/third_party/skia/tools/using_skia_and_harfbuzz.cpp
index d405c71..03fcf30 100644
--- a/src/third_party/skia/tools/using_skia_and_harfbuzz.cpp
+++ b/src/third_party/skia/tools/using_skia_and_harfbuzz.cpp
@@ -16,12 +16,12 @@
 #include <string>
 #include <vector>
 
-#include "SkCanvas.h"
-#include "SkDocument.h"
-#include "SkShaper.h"
-#include "SkStream.h"
-#include "SkTextBlob.h"
-#include "SkTypeface.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkTextBlob.h"
+#include "include/core/SkTypeface.h"
+#include "include/docs/SkPDFDocument.h"
+#include "modules/skshaper/include/SkShaper.h"
 
 // Options /////////////////////////////////////////////////////////////////////
 
@@ -42,8 +42,8 @@
 template <class T>
 struct Option : BaseOption {
     T value;
-    Option(std::string selector, std::string description, T defaultValue)
-        : BaseOption(selector, description), value(defaultValue) {}
+    Option(std::string _selector, std::string _description, T defaultValue)
+        : BaseOption(_selector, _description), value(defaultValue) {}
 };
 
 void BaseOption::Init(const std::vector<BaseOption*> &option_list,
@@ -83,19 +83,19 @@
         stm << value;
         return stm.str();
     }
-    DoubleOption(std::string selector,
-                 std::string description,
+    DoubleOption(std::string _selector,
+                 std::string _description,
                  double defaultValue)
-        : Option<double>(selector, description, defaultValue) {}
+        : Option<double>(_selector, _description, defaultValue) {}
 };
 
 struct StringOption : Option<std::string> {
     virtual void set(std::string _value) { value = _value; }
     virtual std::string valueToString() { return value; }
-    StringOption(std::string selector,
-                 std::string description,
+    StringOption(std::string _selector,
+                 std::string _description,
                  std::string defaultValue)
-        : Option<std::string>(selector, description, defaultValue) {}
+        : Option<std::string>(_selector, _description, defaultValue) {}
 };
 
 // Config //////////////////////////////////////////////////////////////////////
@@ -112,7 +112,7 @@
     DoubleOption font_size = DoubleOption("-z", "Font size", 8.0f);
     DoubleOption left_margin = DoubleOption("-m", "Left margin", 20.0f);
     DoubleOption line_spacing_ratio =
-            DoubleOption("-h", "Line spacing ratio", 1.5f);
+            DoubleOption("-h", "Line spacing ratio", 0.25f);
     StringOption output_file_name =
             StringOption("-o", ".pdf output file name", "out-skiahf.pdf");
 
@@ -132,13 +132,23 @@
         : config(conf), document(doc), pageCanvas(nullptr) {
         white_paint.setColor(SK_ColorWHITE);
         glyph_paint.setColor(SK_ColorBLACK);
-        glyph_paint.setFlags(SkPaint::kAntiAlias_Flag |
-                             SkPaint::kSubpixelText_Flag);
-        glyph_paint.setTextSize(SkDoubleToScalar(config->font_size.value));
+        glyph_paint.setAntiAlias(true);
+        font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+        font.setSubpixel(true);
+        font.setSize(SkDoubleToScalar(config->font_size.value));
     }
 
     void WriteLine(const SkShaper& shaper, const char *text, size_t textBytes) {
-        if (!pageCanvas || current_y > config->page_height.value) {
+        SkTextBlobBuilderRunHandler textBlobBuilder(text, {0, 0});
+        shaper.shape(text, textBytes, font, true,
+                     config->page_width.value - 2*config->left_margin.value, &textBlobBuilder);
+        SkPoint endPoint = textBlobBuilder.endPoint();
+        sk_sp<const SkTextBlob> blob = textBlobBuilder.makeBlob();
+        // If we don't have a page, or if we're not at the start of the page and the blob won't fit
+        if (!pageCanvas ||
+              (current_y > config->line_spacing_ratio.value * config->font_size.value &&
+               current_y + endPoint.y() > config->page_height.value)
+        ) {
             if (pageCanvas) {
                 document->endPage();
             }
@@ -149,14 +159,11 @@
             current_x = config->left_margin.value;
             current_y = config->line_spacing_ratio.value * config->font_size.value;
         }
-        SkTextBlobBuilder textBlobBuilder;
-        shaper.shape(&textBlobBuilder, glyph_paint, text, textBytes, SkPoint{0, 0});
-        sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
         pageCanvas->drawTextBlob(
                 blob.get(), SkDoubleToScalar(current_x),
                 SkDoubleToScalar(current_y), glyph_paint);
         // Advance to the next line.
-        current_y += config->line_spacing_ratio.value * config->font_size.value;
+        current_y += endPoint.y() + config->line_spacing_ratio.value * config->font_size.value;
     }
 
 private:
@@ -165,32 +172,28 @@
     SkCanvas *pageCanvas;
     SkPaint white_paint;
     SkPaint glyph_paint;
+    SkFont font;
     double current_x;
     double current_y;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static sk_sp<SkDocument> MakePDFDocument(const Config &config,
-                                         SkWStream *wStream) {
-    SkDocument::PDFMetadata pdf_info;
+static sk_sp<SkDocument> MakePDFDocument(const Config &config, SkWStream *wStream) {
+    SkPDF::Metadata pdf_info;
     pdf_info.fTitle = config.title.value.c_str();
     pdf_info.fAuthor = config.author.value.c_str();
     pdf_info.fSubject = config.subject.value.c_str();
     pdf_info.fKeywords = config.keywords.value.c_str();
     pdf_info.fCreator = config.creator.value.c_str();
-    bool pdfa = false;
     #if 0
         SkTime::DateTime now;
         SkTime::GetDateTime(&now);
-        pdf_info.fCreation.fEnabled = true;
-        pdf_info.fCreation.fDateTime = now;
-        pdf_info.fModified.fEnabled = true;
-        pdf_info.fModified.fDateTime = now;
-        pdfa = true;
+        pdf_info.fCreation = now;
+        pdf_info.fModified = now;
+        pdf_info.fPDFA = true;
     #endif
-    return SkDocument::MakePDF(wStream, SK_ScalarDefaultRasterDPI, pdf_info,
-                               nullptr, pdfa);
+    return SkPDF::MakeDocument(wStream, pdf_info);
 }
 
 int main(int argc, char **argv) {
@@ -205,12 +208,15 @@
     if (font_file.size() > 0) {
         typeface = SkTypeface::MakeFromFile(font_file.c_str(), 0 /* index */);
     }
-    SkShaper shaper(typeface);
-    assert(shaper.good());
+    std::unique_ptr<SkShaper> shaper = SkShaper::Make();
+    assert(shaper);
+    //SkString line("This is هذا هو الخط a line.");
+    //SkString line("⁧This is a line هذا هو الخط.⁩");
     for (std::string line; std::getline(std::cin, line);) {
-        placement.WriteLine(shaper, line.c_str(), line.size());
+        placement.WriteLine(*shaper, line.c_str(), line.size());
     }
 
     doc->close();
+    wStream.flush();
     return 0;
 }
diff --git a/src/third_party/skia/tools/valgrind.supp b/src/third_party/skia/tools/valgrind.supp
index 064f8ef..20f1a7d 100644
--- a/src/third_party/skia/tools/valgrind.supp
+++ b/src/third_party/skia/tools/valgrind.supp
@@ -6,7 +6,7 @@
    Memcheck:Leak
    match-leak-kinds: possible,definite
    ...
-   fun:_ZN8SkThreadC1EPFvPvES0_
+   fun:start_keepalive
    ...
    fun:main
    ...
@@ -101,6 +101,12 @@
    obj:*/libGLX_nvidia.so*
 }
 {
+   nv_driver_bug_5
+   Memcheck:Leak
+   fun:malloc
+   obj:*/libGLX_nvidia.so*
+}
+{
     #Fixed by FontConfig 2.9.0
     #http://cgit.freedesktop.org/fontconfig/commit/?id=1c475d5c8cb265ac939d6b9e097666e300162511
     font_config_bug_1
@@ -276,3 +282,22 @@
     fun:_ZN12_GLOBAL__N_120ConvolveHorizontallyILb0EEEvPKhRK21SkConvolutionFilter1DPh
     fun:_Z14BGRAConvolve2DPKhibRK21SkConvolutionFilter1DS3_iPhRK18SkConvolutionProcsb
 }
+#Something odd happening in with SkRasterPipeline in GrConvertPixels. Seems bogus after
+#investigation. MSAN/ASAN have no complaints. Complaining about conditional jump or use
+#of var that is "uninitialized" but it definitely is.
+{
+   grconvertpixels_rasterpipeline
+   Memcheck:Cond
+   ...
+   fun:_ZNK16SkRasterPipeline3runEmmmm
+   fun:_Z15GrConvertPixelsRK11GrImageInfoPvmS1_PKvmb
+   ...
+}
+{
+   grconvertpixels_rasterpipeline
+   Memcheck:Value8
+   ...
+   fun:_ZNK16SkRasterPipeline3runEmmmm
+   fun:_Z15GrConvertPixelsRK11GrImageInfoPvmS1_PKvmb
+   ...
+}
diff --git a/src/third_party/skia/tools/viewer/AnimTimer.h b/src/third_party/skia/tools/viewer/AnimTimer.h
new file mode 100644
index 0000000..93d0077
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/AnimTimer.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkScalar.h"
+#include "include/core/SkTime.h"
+
+#ifndef AnimTimer_DEFINED
+#define AnimTimer_DEFINED
+
+/**
+ *  Class to track a "timer". It supports 3 states: stopped, paused, and running.
+ *  Playback speed is variable.
+ *
+ *  The caller must call updateTime() to resync with the clock (typically just before
+ *  using the timer). Forcing the caller to do this ensures that the timer's return values
+ *  are consistent if called repeatedly, as they only reflect the time since the last
+ *  calle to updateTimer().
+ */
+class AnimTimer {
+public:
+    /**
+     *  Class begins in the "stopped" state.
+     */
+    AnimTimer() {}
+
+    enum State { kStopped_State, kPaused_State, kRunning_State };
+
+    State state() const { return fState; }
+
+    double nanos() const { return fElapsedNanos; }
+
+    /**
+     *  Control the rate at which time advances.
+     */
+    float getSpeed() const { return fSpeed; }
+    void  setSpeed(float speed) { fSpeed = speed; }
+
+    /**
+     *  If the timer is paused or stopped, it will resume (or start if it was stopped).
+     */
+    void run() {
+        switch (this->state()) {
+            case kStopped_State:
+                fPreviousNanos = SkTime::GetNSecs();
+                fElapsedNanos  = 0;
+                break;
+            case kPaused_State:  // they want "resume"
+                fPreviousNanos = SkTime::GetNSecs();
+                break;
+            case kRunning_State: break;
+        }
+        fState = kRunning_State;
+    }
+
+    void pause() {
+        if (kRunning_State == this->state()) {
+            fState = kPaused_State;
+        }  // else stay stopped or paused
+    }
+
+    /**
+     *  If the timer is stopped, start running, else it toggles between paused and running.
+     */
+    void togglePauseResume() {
+        if (kRunning_State == this->state()) {
+            this->pause();
+        } else {
+            this->run();
+        }
+    }
+
+    /**
+     *  Call this each time you want to sample the clock for the timer. This is NOT done
+     *  automatically, so that repeated calls to msec() or secs() will always return the
+     *  same value.
+     *
+     *  This may safely be called with the timer in any state.
+     */
+    void updateTime() {
+        if (kRunning_State == this->state()) {
+            double now = SkTime::GetNSecs();
+            fElapsedNanos += (now - fPreviousNanos) * fSpeed;
+            fPreviousNanos = now;
+        }
+    }
+
+private:
+    double fPreviousNanos = 0;
+    double fElapsedNanos = 0;
+    float  fSpeed = 1;
+    State fState = kStopped_State;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/BisectSlide.cpp b/src/third_party/skia/tools/viewer/BisectSlide.cpp
new file mode 100644
index 0000000..fa2bed9
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/BisectSlide.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "tools/viewer/BisectSlide.h"
+
+#include "include/core/SkPicture.h"
+#include "include/core/SkStream.h"
+#include "src/utils/SkOSPath.h"
+
+#include <utility>
+
+#ifdef SK_XML
+#include "experimental/svg/model/SkSVGDOM.h"
+#include "src/xml/SkDOM.h"
+#endif
+
+sk_sp<BisectSlide> BisectSlide::Create(const char filepath[]) {
+    SkFILEStream stream(filepath);
+    if (!stream.isValid()) {
+        SkDebugf("BISECT: invalid input file at \"%s\"\n", filepath);
+        return nullptr;
+    }
+
+    sk_sp<BisectSlide> bisect(new BisectSlide(filepath));
+    if (bisect->fFilePath.endsWith(".svg")) {
+#ifdef SK_XML
+        SkDOM xml;
+        if (!xml.build(stream)) {
+            SkDebugf("BISECT: XML parsing failed: \"%s\"\n", filepath);
+            return nullptr;
+        }
+        sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
+        if (!svg) {
+            SkDebugf("BISECT: couldn't load svg at \"%s\"\n", filepath);
+            return nullptr;
+        }
+        svg->setContainerSize(SkSize::Make(bisect->getDimensions()));
+        svg->render(bisect.get());
+#else
+        return nullptr;
+#endif
+    } else {
+        sk_sp<SkPicture> skp = SkPicture::MakeFromStream(&stream);
+        if (!skp) {
+            SkDebugf("BISECT: couldn't load skp at \"%s\"\n", filepath);
+            return nullptr;
+        }
+        skp->playback(bisect.get());
+    }
+
+    return bisect;
+}
+
+BisectSlide::BisectSlide(const char filepath[])
+        : SkCanvas(4096, 4096, nullptr)
+        , fFilePath(filepath) {
+    const char* basename = strrchr(fFilePath.c_str(), SkOSPath::SEPARATOR);
+    fName.printf("BISECT_%s", basename ? basename + 1 : fFilePath.c_str());
+}
+
+// Called through SkPicture::playback only during creation.
+void BisectSlide::onDrawPath(const SkPath& path, const SkPaint& paint) {
+    SkRect bounds;
+    SkIRect ibounds;
+    this->getTotalMatrix().mapRect(&bounds, path.getBounds());
+    bounds.roundOut(&ibounds);
+    fDrawBounds.join(ibounds);
+    fFoundPaths.push_back() = {path, paint, this->getTotalMatrix()};
+}
+
+bool BisectSlide::onChar(SkUnichar c) {
+    switch (c) {
+        case 'X':
+            if (!fTossedPaths.empty()) {
+                using std::swap;
+                swap(fFoundPaths, fTossedPaths);
+                if ('X' == fTrail.back()) {
+                    fTrail.pop_back();
+                } else {
+                    fTrail.push_back('X');
+                }
+            }
+            return true;
+
+        case 'x':
+            if (fFoundPaths.count() > 1) {
+                int midpt = (fFoundPaths.count() + 1) / 2;
+                fPathHistory.emplace(fFoundPaths, fTossedPaths);
+                fTossedPaths.reset(fFoundPaths.begin() + midpt, fFoundPaths.count() - midpt);
+                fFoundPaths.resize_back(midpt);
+                fTrail.push_back('x');
+            }
+            return true;
+
+        case 'Z': {
+            if (!fPathHistory.empty()) {
+                fFoundPaths = fPathHistory.top().first;
+                fTossedPaths = fPathHistory.top().second;
+                fPathHistory.pop();
+                char ch;
+                do {
+                    ch = fTrail.back();
+                    fTrail.pop_back();
+                } while (ch != 'x');
+            }
+            return true;
+        }
+
+        case 'D':
+            SkDebugf("viewer --bisect %s", fFilePath.c_str());
+            if (!fTrail.empty()) {
+                SkDebugf(" ");
+                for (char ch : fTrail) {
+                    SkDebugf("%c", ch);
+                }
+            }
+            SkDebugf("\n");
+            for (const FoundPath& foundPath : fFoundPaths) {
+                foundPath.fPath.dump();
+            }
+            return true;
+    }
+
+    return false;
+}
+
+void BisectSlide::draw(SkCanvas* canvas) {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->translate(-fDrawBounds.left(), -fDrawBounds.top());
+
+    for (const FoundPath& path : fFoundPaths) {
+        SkAutoCanvasRestore acr(canvas, true);
+        canvas->concat(path.fViewMatrix);
+        canvas->drawPath(path.fPath, path.fPaint);
+    }
+}
diff --git a/src/third_party/skia/tools/viewer/BisectSlide.h b/src/third_party/skia/tools/viewer/BisectSlide.h
new file mode 100644
index 0000000..142209c
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/BisectSlide.h
@@ -0,0 +1,55 @@
+/*
+ * 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 BisectSlide_DEFINED
+#define BisectSlide_DEFINED
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkPath.h"
+#include "tools/viewer/Slide.h"
+
+#include <stack>
+
+/**
+ * This is a simple utility designed to extract the paths from an SKP file and then isolate a single
+ * one of them via bisect. Use the 'x' and 'X' keys to guide a binary search:
+ *
+ *   'x': Throw out half the paths.
+ *   'X': Toggle which half gets tossed and which half is kept.
+ *   'Z': Back up one level.
+ *   'D': Dump the path.
+ */
+class BisectSlide : public Slide, public SkCanvas {
+public:
+    static sk_sp<BisectSlide> Create(const char filepath[]);
+
+    // Slide overrides.
+    SkISize getDimensions() const override { return fDrawBounds.size(); }
+    bool onChar(SkUnichar c) override;
+    void draw(SkCanvas* canvas) override;
+
+private:
+    BisectSlide(const char filepath[]);
+
+    // SkCanvas override called only during creation.
+    void onDrawPath(const SkPath& path, const SkPaint& paint) override;
+
+    struct FoundPath {
+        SkPath fPath;
+        SkPaint fPaint;
+        SkMatrix fViewMatrix;
+    };
+
+    SkString fFilePath;
+    SkIRect fDrawBounds = SkIRect::MakeEmpty();
+    SkTArray<FoundPath> fFoundPaths;
+    SkTArray<FoundPath> fTossedPaths;
+    SkTArray<char> fTrail;
+    std::stack<std::pair<SkTArray<FoundPath>, SkTArray<FoundPath>>> fPathHistory;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/GMSlide.cpp b/src/third_party/skia/tools/viewer/GMSlide.cpp
index 40a9c99..24d8421 100644
--- a/src/third_party/skia/tools/viewer/GMSlide.cpp
+++ b/src/third_party/skia/tools/viewer/GMSlide.cpp
@@ -11,14 +11,14 @@
 * found in the LICENSE file.
 */
 
-#include "GMSlide.h"
-#include "SkCanvas.h"
+#include "include/core/SkCanvas.h"
+#include "tools/viewer/GMSlide.h"
 
-GMSlide::GMSlide(skiagm::GM* gm) : fGM(gm) {
-    fName.printf("GM_%s", gm->getName());
+GMSlide::GMSlide(std::unique_ptr<skiagm::GM> gm) : fGM(std::move(gm)) {
+    fName.printf("GM_%s", fGM->getName());
 }
 
-GMSlide::~GMSlide() { delete fGM; }
+GMSlide::~GMSlide() = default;
 
 void GMSlide::draw(SkCanvas* canvas) {
     // Do we care about timing the draw of the background (once)?
@@ -27,10 +27,15 @@
     fGM->drawContent(canvas);
 }
 
-bool GMSlide::animate(const SkAnimTimer& timer) {
-    return fGM->animate(timer);
+bool GMSlide::animate(double nanos) { return fGM->animate(nanos); }
+
+bool GMSlide::onChar(SkUnichar c) { return fGM->onChar(c); }
+
+bool GMSlide::onGetControls(SkMetaData* controls) {
+    return fGM->getControls(controls);
 }
 
-bool GMSlide::onChar(SkUnichar c) {
-    return fGM->handleKey(c);
+void GMSlide::onSetControls(const SkMetaData& controls) {
+    fGM->setControls(controls);
 }
+
diff --git a/src/third_party/skia/tools/viewer/GMSlide.h b/src/third_party/skia/tools/viewer/GMSlide.h
index 2a3faa9..96d7af9 100644
--- a/src/third_party/skia/tools/viewer/GMSlide.h
+++ b/src/third_party/skia/tools/viewer/GMSlide.h
@@ -8,23 +8,26 @@
 #ifndef GMSlide_DEFINED
 #define GMSlide_DEFINED
 
-#include "Slide.h"
-#include "gm.h"
+#include "gm/gm.h"
+#include "tools/viewer/Slide.h"
 
 class GMSlide : public Slide {
 public:
-    GMSlide(skiagm::GM* gm);
+    GMSlide(std::unique_ptr<skiagm::GM> gm);
     ~GMSlide() override;
 
     SkISize getDimensions() const override { return fGM->getISize(); }
 
     void draw(SkCanvas* canvas) override;
-    bool animate(const SkAnimTimer&) override;
+    bool animate(double nanos) override;
 
     bool onChar(SkUnichar c) override;
 
+    bool onGetControls(SkMetaData*) override;
+    void onSetControls(const SkMetaData&) override;
+
 private:
-    skiagm::GM* fGM;
+    std::unique_ptr<skiagm::GM> fGM;
 };
 
 
diff --git a/src/third_party/skia/tools/viewer/ImGuiLayer.cpp b/src/third_party/skia/tools/viewer/ImGuiLayer.cpp
new file mode 100644
index 0000000..31b3a54
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/ImGuiLayer.cpp
@@ -0,0 +1,202 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "tools/viewer/ImGuiLayer.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkPixmap.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkSwizzle.h"
+#include "include/core/SkTime.h"
+#include "include/core/SkVertices.h"
+
+#include "imgui.h"
+
+#include <stdlib.h>
+#include <map>
+
+using namespace sk_app;
+
+ImGuiLayer::ImGuiLayer() {
+    // ImGui initialization:
+    ImGui::CreateContext();
+    ImGuiIO& io = ImGui::GetIO();
+
+    // Keymap...
+    io.KeyMap[ImGuiKey_Tab]        = (int)skui::Key::kTab;
+    io.KeyMap[ImGuiKey_LeftArrow]  = (int)skui::Key::kLeft;
+    io.KeyMap[ImGuiKey_RightArrow] = (int)skui::Key::kRight;
+    io.KeyMap[ImGuiKey_UpArrow]    = (int)skui::Key::kUp;
+    io.KeyMap[ImGuiKey_DownArrow]  = (int)skui::Key::kDown;
+    io.KeyMap[ImGuiKey_PageUp]     = (int)skui::Key::kPageUp;
+    io.KeyMap[ImGuiKey_PageDown]   = (int)skui::Key::kPageDown;
+    io.KeyMap[ImGuiKey_Home]       = (int)skui::Key::kHome;
+    io.KeyMap[ImGuiKey_End]        = (int)skui::Key::kEnd;
+    io.KeyMap[ImGuiKey_Delete]     = (int)skui::Key::kDelete;
+    io.KeyMap[ImGuiKey_Backspace]  = (int)skui::Key::kBack;
+    io.KeyMap[ImGuiKey_Enter]      = (int)skui::Key::kOK;
+    io.KeyMap[ImGuiKey_Escape]     = (int)skui::Key::kEscape;
+    io.KeyMap[ImGuiKey_A]          = (int)skui::Key::kA;
+    io.KeyMap[ImGuiKey_C]          = (int)skui::Key::kC;
+    io.KeyMap[ImGuiKey_V]          = (int)skui::Key::kV;
+    io.KeyMap[ImGuiKey_X]          = (int)skui::Key::kX;
+    io.KeyMap[ImGuiKey_Y]          = (int)skui::Key::kY;
+    io.KeyMap[ImGuiKey_Z]          = (int)skui::Key::kZ;
+
+    int w, h;
+    unsigned char* pixels;
+    io.Fonts->GetTexDataAsAlpha8(&pixels, &w, &h);
+    SkImageInfo info = SkImageInfo::MakeA8(w, h);
+    SkPixmap pmap(info, pixels, info.minRowBytes());
+    SkMatrix localMatrix = SkMatrix::MakeScale(1.0f / w, 1.0f / h);
+    auto fontImage = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
+    auto fontShader = fontImage->makeShader(&localMatrix);
+    fFontPaint.setShader(fontShader);
+    fFontPaint.setColor(SK_ColorWHITE);
+    fFontPaint.setFilterQuality(kLow_SkFilterQuality);
+    io.Fonts->TexID = &fFontPaint;
+}
+
+ImGuiLayer::~ImGuiLayer() {
+    ImGui::DestroyContext();
+}
+
+void ImGuiLayer::onAttach(Window* window) {
+    fWindow = window;
+}
+
+bool ImGuiLayer::onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) {
+    ImGuiIO& io = ImGui::GetIO();
+    io.MousePos.x = static_cast<float>(x);
+    io.MousePos.y = static_cast<float>(y);
+    if (skui::InputState::kDown == state) {
+        io.MouseDown[0] = true;
+    } else if (skui::InputState::kUp == state) {
+        io.MouseDown[0] = false;
+    }
+    return io.WantCaptureMouse;
+}
+
+bool ImGuiLayer::onMouseWheel(float delta, skui::ModifierKey modifiers) {
+    ImGuiIO& io = ImGui::GetIO();
+    io.MouseWheel += delta;
+    return true;
+}
+
+void ImGuiLayer::skiaWidget(const ImVec2& size, SkiaWidgetFunc func) {
+    intptr_t funcIndex = fSkiaWidgetFuncs.count();
+    fSkiaWidgetFuncs.push_back(func);
+    ImGui::Image((ImTextureID)funcIndex, size);
+}
+
+void ImGuiLayer::onPrePaint() {
+    // Update ImGui input
+    ImGuiIO& io = ImGui::GetIO();
+
+    static double previousTime = 0.0;
+    double currentTime = SkTime::GetSecs();
+    io.DeltaTime = static_cast<float>(currentTime - previousTime);
+    previousTime = currentTime;
+
+    io.DisplaySize.x = static_cast<float>(fWindow->width());
+    io.DisplaySize.y = static_cast<float>(fWindow->height());
+
+    io.KeyAlt = io.KeysDown[static_cast<int>(skui::Key::kOption)];
+    io.KeyCtrl = io.KeysDown[static_cast<int>(skui::Key::kCtrl)];
+    io.KeyShift = io.KeysDown[static_cast<int>(skui::Key::kShift)];
+
+    ImGui::NewFrame();
+}
+
+void ImGuiLayer::onPaint(SkSurface* surface) {
+    // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands
+    // (widgets, etc...) that have been issued
+    ImGui::Render();
+
+    // Then we fetch the most recent data, and convert it so we can render with Skia
+    const ImDrawData* drawData = ImGui::GetDrawData();
+    SkTDArray<SkPoint> pos;
+    SkTDArray<SkPoint> uv;
+    SkTDArray<SkColor> color;
+
+    auto canvas = surface->getCanvas();
+
+    for (int i = 0; i < drawData->CmdListsCount; ++i) {
+        const ImDrawList* drawList = drawData->CmdLists[i];
+
+        // De-interleave all vertex data (sigh), convert to Skia types
+        pos.rewind(); uv.rewind(); color.rewind();
+        for (int j = 0; j < drawList->VtxBuffer.size(); ++j) {
+            const ImDrawVert& vert = drawList->VtxBuffer[j];
+            pos.push_back(SkPoint::Make(vert.pos.x, vert.pos.y));
+            uv.push_back(SkPoint::Make(vert.uv.x, vert.uv.y));
+            color.push_back(vert.col);
+        }
+        // ImGui colors are RGBA
+        SkSwapRB(color.begin(), color.begin(), color.count());
+
+        int indexOffset = 0;
+
+        // Draw everything with canvas.drawVertices...
+        for (int j = 0; j < drawList->CmdBuffer.size(); ++j) {
+            const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j];
+
+            SkAutoCanvasRestore acr(canvas, true);
+
+            // TODO: Find min/max index for each draw, so we know how many vertices (sigh)
+            if (drawCmd->UserCallback) {
+                drawCmd->UserCallback(drawList, drawCmd);
+            } else {
+                intptr_t idIndex = (intptr_t)drawCmd->TextureId;
+                if (idIndex < fSkiaWidgetFuncs.count()) {
+                    // Small image IDs are actually indices into a list of callbacks. We directly
+                    // examing the vertex data to deduce the image rectangle, then reconfigure the
+                    // canvas to be clipped and translated so that the callback code gets to use
+                    // Skia to render a widget in the middle of an ImGui panel.
+                    ImDrawIdx rectIndex = drawList->IdxBuffer[indexOffset];
+                    SkPoint tl = pos[rectIndex], br = pos[rectIndex + 2];
+                    canvas->clipRect(SkRect::MakeLTRB(tl.fX, tl.fY, br.fX, br.fY));
+                    canvas->translate(tl.fX, tl.fY);
+                    fSkiaWidgetFuncs[idIndex](canvas);
+                } else {
+                    SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId);
+                    SkASSERT(paint);
+
+                    canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y,
+                                                      drawCmd->ClipRect.z, drawCmd->ClipRect.w));
+                    auto vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
+                                                         drawList->VtxBuffer.size(),
+                                                         pos.begin(), uv.begin(), color.begin(),
+                                                         drawCmd->ElemCount,
+                                                         drawList->IdxBuffer.begin() + indexOffset);
+                    canvas->drawVertices(vertices, SkBlendMode::kModulate, *paint);
+                }
+                indexOffset += drawCmd->ElemCount;
+            }
+        }
+    }
+
+    fSkiaWidgetFuncs.reset();
+}
+
+bool ImGuiLayer::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) {
+    ImGuiIO& io = ImGui::GetIO();
+    io.KeysDown[static_cast<int>(key)] = (skui::InputState::kDown == state);
+    return io.WantCaptureKeyboard;
+}
+
+bool ImGuiLayer::onChar(SkUnichar c, skui::ModifierKey modifiers) {
+    ImGuiIO& io = ImGui::GetIO();
+    if (io.WantTextInput) {
+        if (c > 0 && c < 0x10000) {
+            io.AddInputCharacter(c);
+        }
+        return true;
+    }
+    return false;
+}
diff --git a/src/third_party/skia/tools/viewer/ImGuiLayer.h b/src/third_party/skia/tools/viewer/ImGuiLayer.h
new file mode 100644
index 0000000..827eec0
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/ImGuiLayer.h
@@ -0,0 +1,137 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef ImGuiLayer_DEFINED
+#define ImGuiLayer_DEFINED
+
+#include "include/core/SkPaint.h"
+#include "include/private/SkTArray.h"
+#include "tools/sk_app/Window.h"
+
+#include "imgui.h"
+
+namespace ImGui {
+
+// Helper object for drawing in a widget region, with draggable points
+struct DragCanvas {
+    DragCanvas(const void* id, SkPoint tl = { 0.0f, 0.0f }, SkPoint br = { 1.0f, 1.0f },
+               float aspect = -1.0f)
+            : fID(0), fDragging(false) {
+        ImGui::PushID(id);
+        fDrawList = ImGui::GetWindowDrawList();
+
+        // Logical size
+        SkScalar w = SkTAbs(br.fX - tl.fX),
+                 h = SkTAbs(br.fY - tl.fY);
+
+        // Determine aspect ratio automatically by default
+        if (aspect < 0) {
+            aspect = h / w;
+        }
+
+        float availWidth = SkTMax(ImGui::GetContentRegionAvailWidth(), 1.0f);
+        fPos = ImGui::GetCursorScreenPos();
+        fSize = ImVec2(availWidth, availWidth * aspect);
+
+        SkPoint local[4] = {
+            { tl.fX, tl.fY },
+            { br.fX, tl.fY },
+            { tl.fX, br.fY },
+            { br.fX, br.fY },
+        };
+        SkPoint screen[4] = {
+            { fPos.x          , fPos.y           },
+            { fPos.x + fSize.x, fPos.y           },
+            { fPos.x          , fPos.y + fSize.y },
+            { fPos.x + fSize.x, fPos.y + fSize.y },
+        };
+        fLocalToScreen.setPolyToPoly(local, screen, 4);
+        fScreenToLocal.setPolyToPoly(screen, local, 4);
+    }
+
+    ~DragCanvas() {
+        ImGui::SetCursorScreenPos(ImVec2(fPos.x, fPos.y + fSize.y));
+        ImGui::Spacing();
+        ImGui::PopID();
+    }
+
+    void fillColor(ImU32 color) {
+        fDrawList->AddRectFilled(fPos, ImVec2(fPos.x + fSize.x, fPos.y + fSize.y), color);
+    }
+
+    void dragPoint(SkPoint* p, bool tooltip = false, ImU32 color = 0xFFFFFFFF) {
+        // Transform points from logical coordinates to screen coordinates
+        SkPoint center = fLocalToScreen.mapXY(p->fX, p->fY);
+
+        // Invisible 10x10 button
+        ImGui::PushID(fID++);
+        ImGui::SetCursorScreenPos(ImVec2(center.fX - 5, center.fY - 5));
+        ImGui::InvisibleButton("", ImVec2(10, 10));
+
+        if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) {
+            // Update screen position to track mouse, clamped to our area
+            ImGuiIO& io = ImGui::GetIO();
+            center.set(SkTPin(io.MousePos.x, fPos.x, fPos.x + fSize.x),
+                       SkTPin(io.MousePos.y, fPos.y, fPos.y + fSize.y));
+
+            // Update local coordinates for the caller
+            *p = fScreenToLocal.mapXY(center.fX, center.fY);
+            fDragging = true;
+        }
+
+        if (tooltip && ImGui::IsItemHovered()) {
+            ImGui::SetTooltip("x: %.3f\ny: %.3f", p->fX, p->fY);
+        }
+
+        ImGui::PopID();
+
+        fScreenPoints.push_back(ImVec2(center.fX, center.fY));
+        fDrawList->AddCircle(fScreenPoints.back(), 5.0f, color);
+    }
+
+    ImDrawList* fDrawList;
+
+    // Location and dimensions (in screen coordinates)
+    ImVec2 fPos;
+    ImVec2 fSize;
+
+    // Screen coordinates of points (for additional user drawing)
+    SkSTArray<4, ImVec2, true> fScreenPoints;
+
+    // To simplify dragPoint
+    SkMatrix fLocalToScreen;
+    SkMatrix fScreenToLocal;
+
+    int fID;
+    bool fDragging;
+};
+
+}
+
+class ImGuiLayer : public sk_app::Window::Layer {
+public:
+    ImGuiLayer();
+    ~ImGuiLayer() override;
+
+    typedef std::function<void(SkCanvas*)> SkiaWidgetFunc;
+    void skiaWidget(const ImVec2& size, SkiaWidgetFunc func);
+
+    void onAttach(sk_app::Window* window) override;
+    void onPrePaint() override;
+    void onPaint(SkSurface*) override;
+    bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) override;
+    bool onMouseWheel(float delta, skui::ModifierKey modifiers) override;
+    bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) override;
+    bool onChar(SkUnichar c, skui::ModifierKey modifiers) override;
+
+private:
+    sk_app::Window* fWindow;
+    SkPaint fFontPaint;
+    SkTArray<SkiaWidgetFunc> fSkiaWidgetFuncs;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/ImageSlide.cpp b/src/third_party/skia/tools/viewer/ImageSlide.cpp
index 8ff7d18..52e5d84 100644
--- a/src/third_party/skia/tools/viewer/ImageSlide.cpp
+++ b/src/third_party/skia/tools/viewer/ImageSlide.cpp
@@ -5,11 +5,11 @@
 * found in the LICENSE file.
 */
 
-#include "ImageSlide.h"
+#include "tools/viewer/ImageSlide.h"
 
-#include "SkCanvas.h"
-#include "SkData.h"
-#include "SkImage.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImage.h"
 
 ImageSlide::ImageSlide(const SkString& name, const SkString& path) : fPath(path) {
     fName = name;
diff --git a/src/third_party/skia/tools/viewer/ImageSlide.h b/src/third_party/skia/tools/viewer/ImageSlide.h
index d9e3f2d..2246408 100644
--- a/src/third_party/skia/tools/viewer/ImageSlide.h
+++ b/src/third_party/skia/tools/viewer/ImageSlide.h
@@ -8,9 +8,9 @@
 #ifndef ImageSlide_DEFINED
 #define ImageSlide_DEFINED
 
-#include "Slide.h"
-#include "SkPicture.h"
-#include "SkImage.h"
+#include "include/core/SkImage.h"
+#include "include/core/SkPicture.h"
+#include "tools/viewer/Slide.h"
 
 class ImageSlide : public Slide {
 public:
diff --git a/src/third_party/skia/tools/viewer/ParticlesSlide.cpp b/src/third_party/skia/tools/viewer/ParticlesSlide.cpp
new file mode 100644
index 0000000..4ea33d1
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/ParticlesSlide.cpp
@@ -0,0 +1,438 @@
+/*
+* Copyright 2019 Google LLC
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "tools/viewer/ParticlesSlide.h"
+
+#include "modules/particles/include/SkParticleEffect.h"
+#include "modules/particles/include/SkParticleSerialization.h"
+#include "modules/particles/include/SkReflected.h"
+#include "src/core/SkOSFile.h"
+#include "src/sksl/SkSLByteCode.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/Resources.h"
+#include "tools/viewer/ImGuiLayer.h"
+
+#include "imgui.h"
+
+using namespace sk_app;
+
+namespace {
+
+static SkScalar kDragSize = 8.0f;
+static SkTArray<SkPoint*> gDragPoints;
+int gDragIndex = -1;
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int InputTextCallback(ImGuiInputTextCallbackData* data) {
+    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
+        SkString* s = (SkString*)data->UserData;
+        SkASSERT(data->Buf == s->writable_str());
+        SkString tmp(data->Buf, data->BufTextLen);
+        s->swap(tmp);
+        data->Buf = s->writable_str();
+    }
+    return 0;
+}
+
+static int count_lines(const SkString& s) {
+    int lines = 1;
+    for (size_t i = 0; i < s.size(); ++i) {
+        if (s[i] == '\n') {
+            ++lines;
+        }
+    }
+    return lines;
+}
+
+class SkGuiVisitor : public SkFieldVisitor {
+public:
+    SkGuiVisitor() {
+        fTreeStack.push_back(true);
+    }
+
+#define IF_OPEN(WIDGET) if (fTreeStack.back()) { WIDGET; }
+
+    void visit(const char* name, float& f) override {
+        IF_OPEN(ImGui::DragFloat(item(name), &f))
+    }
+    void visit(const char* name, int& i) override {
+        IF_OPEN(ImGui::DragInt(item(name), &i))
+    }
+    void visit(const char* name, bool& b) override {
+        IF_OPEN(ImGui::Checkbox(item(name), &b))
+    }
+    void visit(const char* name, SkString& s) override {
+        if (fTreeStack.back()) {
+            int lines = count_lines(s);
+            ImGuiInputTextFlags flags = ImGuiInputTextFlags_CallbackResize;
+            if (lines > 1) {
+                ImGui::LabelText("##Label", "%s", name);
+                ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * (lines + 1));
+                ImGui::InputTextMultiline(item(name), s.writable_str(), s.size() + 1, boxSize,
+                                          flags, InputTextCallback, &s);
+            } else {
+                ImGui::InputText(item(name), s.writable_str(), s.size() + 1, flags,
+                                 InputTextCallback, &s);
+            }
+        }
+    }
+    void visit(const char* name, int& i, const EnumStringMapping* map, int count) override {
+        if (fTreeStack.back()) {
+            const char* curStr = EnumToString(i, map, count);
+            if (ImGui::BeginCombo(item(name), curStr ? curStr : "Unknown")) {
+                for (int j = 0; j < count; ++j) {
+                    if (ImGui::Selectable(map[j].fName, i == map[j].fValue)) {
+                        i = map[j].fValue;
+                    }
+                }
+                ImGui::EndCombo();
+            }
+        }
+    }
+
+    void visit(const char* name, SkPoint& p) override {
+        if (fTreeStack.back()) {
+            ImGui::DragFloat2(item(name), &p.fX);
+            gDragPoints.push_back(&p);
+        }
+    }
+    void visit(const char* name, SkColor4f& c) override {
+        IF_OPEN(ImGui::ColorEdit4(item(name), c.vec()))
+    }
+
+#undef IF_OPEN
+
+    void visit(sk_sp<SkReflected>& e, const SkReflected::Type* baseType) override {
+        if (fTreeStack.back()) {
+            const SkReflected::Type* curType = e ? e->getType() : nullptr;
+            if (ImGui::BeginCombo("Type", curType ? curType->fName : "Null")) {
+                auto visitType = [baseType, curType, &e](const SkReflected::Type* t) {
+                    if (t->fFactory && (t == baseType || t->isDerivedFrom(baseType)) &&
+                        ImGui::Selectable(t->fName, curType == t)) {
+                        e = t->fFactory();
+                    }
+                };
+                SkReflected::VisitTypes(visitType);
+                ImGui::EndCombo();
+            }
+        }
+    }
+
+    void enterObject(const char* name) override {
+        if (fTreeStack.back()) {
+            fTreeStack.push_back(ImGui::TreeNodeEx(item(name),
+                                                   ImGuiTreeNodeFlags_AllowItemOverlap));
+        } else {
+            fTreeStack.push_back(false);
+        }
+    }
+    void exitObject() override {
+        if (fTreeStack.back()) {
+            ImGui::TreePop();
+        }
+        fTreeStack.pop_back();
+    }
+
+    int enterArray(const char* name, int oldCount) override {
+        this->enterObject(item(name));
+        fArrayCounterStack.push_back(0);
+        fArrayEditStack.push_back();
+
+        int count = oldCount;
+        if (fTreeStack.back()) {
+            ImGui::SameLine();
+            if (ImGui::Button("+")) {
+                ++count;
+            }
+        }
+        return count;
+    }
+    ArrayEdit exitArray() override {
+        fArrayCounterStack.pop_back();
+        auto edit = fArrayEditStack.back();
+        fArrayEditStack.pop_back();
+        this->exitObject();
+        return edit;
+    }
+
+private:
+    const char* item(const char* name) {
+        if (name) {
+            return name;
+        }
+
+        // We're in an array. Add extra controls and a dynamic label.
+        int index = fArrayCounterStack.back()++;
+        ArrayEdit& edit(fArrayEditStack.back());
+        fScratchLabel = SkStringPrintf("[%d]", index);
+
+        ImGui::PushID(index);
+
+        if (ImGui::Button("X")) {
+            edit.fVerb = ArrayEdit::Verb::kRemove;
+            edit.fIndex = index;
+        }
+        ImGui::SameLine();
+        if (ImGui::Button("^")) {
+            edit.fVerb = ArrayEdit::Verb::kMoveForward;
+            edit.fIndex = index;
+        }
+        ImGui::SameLine();
+        if (ImGui::Button("v")) {
+            edit.fVerb = ArrayEdit::Verb::kMoveForward;
+            edit.fIndex = index + 1;
+        }
+        ImGui::SameLine();
+
+        ImGui::PopID();
+
+        return fScratchLabel.c_str();
+    }
+
+    SkSTArray<16, bool, true> fTreeStack;
+    SkSTArray<16, int, true>  fArrayCounterStack;
+    SkSTArray<16, ArrayEdit, true> fArrayEditStack;
+    SkString fScratchLabel;
+};
+
+ParticlesSlide::ParticlesSlide() {
+    // Register types for serialization
+    SkParticleEffect::RegisterParticleTypes();
+    fName = "Particles";
+    fPlayPosition.set(200.0f, 200.0f);
+}
+
+void ParticlesSlide::loadEffects(const char* dirname) {
+    fLoaded.reset();
+    fRunning.reset();
+    SkOSFile::Iter iter(dirname, ".json");
+    for (SkString file; iter.next(&file); ) {
+        LoadedEffect effect;
+        effect.fName = SkOSPath::Join(dirname, file.c_str());
+        effect.fParams.reset(new SkParticleEffectParams());
+        if (auto fileData = SkData::MakeFromFileName(effect.fName.c_str())) {
+            skjson::DOM dom(static_cast<const char*>(fileData->data()), fileData->size());
+            SkFromJsonVisitor fromJson(dom.root());
+            effect.fParams->visitFields(&fromJson);
+            fLoaded.push_back(effect);
+        }
+    }
+}
+
+void ParticlesSlide::load(SkScalar winWidth, SkScalar winHeight) {
+    this->loadEffects(GetResourcePath("particles").c_str());
+}
+
+void ParticlesSlide::draw(SkCanvas* canvas) {
+    canvas->clear(SK_ColorGRAY);
+
+    gDragPoints.reset();
+    gDragPoints.push_back(&fPlayPosition);
+
+    // Window to show all loaded effects, and allow playing them
+    if (ImGui::Begin("Library", nullptr, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
+        static bool looped = true;
+        ImGui::Checkbox("Looped", &looped);
+
+        static SkString dirname = GetResourcePath("particles");
+        ImGuiInputTextFlags textFlags = ImGuiInputTextFlags_CallbackResize;
+        ImGui::InputText("Directory", dirname.writable_str(), dirname.size() + 1, textFlags,
+                         InputTextCallback, &dirname);
+
+        if (ImGui::Button("New")) {
+            LoadedEffect effect;
+            effect.fName = SkOSPath::Join(dirname.c_str(), "new.json");
+            effect.fParams.reset(new SkParticleEffectParams());
+            fLoaded.push_back(effect);
+        }
+        ImGui::SameLine();
+
+        if (ImGui::Button("Load")) {
+            this->loadEffects(dirname.c_str());
+        }
+        ImGui::SameLine();
+
+        if (ImGui::Button("Save")) {
+            for (const auto& effect : fLoaded) {
+                SkFILEWStream fileStream(effect.fName.c_str());
+                if (fileStream.isValid()) {
+                    SkJSONWriter writer(&fileStream, SkJSONWriter::Mode::kPretty);
+                    SkToJsonVisitor toJson(writer);
+                    writer.beginObject();
+                    effect.fParams->visitFields(&toJson);
+                    writer.endObject();
+                    writer.flush();
+                    fileStream.flush();
+                } else {
+                    SkDebugf("Failed to open %s\n", effect.fName.c_str());
+                }
+            }
+        }
+
+        SkGuiVisitor gui;
+        for (int i = 0; i < fLoaded.count(); ++i) {
+            ImGui::PushID(i);
+            if (fAnimated && ImGui::Button("Play")) {
+                sk_sp<SkParticleEffect> effect(new SkParticleEffect(fLoaded[i].fParams, fRandom));
+                effect->start(fAnimationTime, looped);
+                fRunning.push_back({ fPlayPosition, fLoaded[i].fName, effect, false });
+                fRandom.nextU();
+            }
+            ImGui::SameLine();
+
+            ImGui::InputText("##Name", fLoaded[i].fName.writable_str(), fLoaded[i].fName.size() + 1,
+                             textFlags, InputTextCallback, &fLoaded[i].fName);
+
+            if (ImGui::TreeNode("##Details")) {
+                fLoaded[i].fParams->visitFields(&gui);
+                ImGui::TreePop();
+            }
+            ImGui::PopID();
+        }
+    }
+    ImGui::End();
+
+    // Another window to show all the running effects
+    if (ImGui::Begin("Running")) {
+        for (int i = 0; i < fRunning.count(); ++i) {
+            SkParticleEffect* effect = fRunning[i].fEffect.get();
+            ImGui::PushID(effect);
+
+            ImGui::Checkbox("##Track", &fRunning[i].fTrackMouse);
+            ImGui::SameLine();
+            bool remove = ImGui::Button("X") || !effect->isAlive();
+            ImGui::SameLine();
+            ImGui::Text("%4g, %4g %5d %s", fRunning[i].fPosition.fX, fRunning[i].fPosition.fY,
+                        effect->getCount(), fRunning[i].fName.c_str());
+            if (fRunning[i].fTrackMouse) {
+                effect->setPosition({ ImGui::GetMousePos().x, ImGui::GetMousePos().y });
+                fRunning[i].fPosition.set(0, 0);
+            }
+
+            auto uniformsGui = [](const SkSL::ByteCode* code, float* data, SkPoint spawnPos) {
+                if (!code || !data) {
+                    return;
+                }
+                for (int i = 0; i < code->getUniformCount(); ++i) {
+                    const auto& uni = code->getUniform(i);
+                    float* vals = data + uni.fSlot;
+
+                    // Skip over builtin uniforms, to reduce clutter
+                    if (uni.fName == "dt" || uni.fName.startsWith("effect.")) {
+                        continue;
+                    }
+
+                    // Special case for 'uniform float2 mouse_pos' - an example of likely app logic
+                    if (uni.fName == "mouse_pos" &&
+                        uni.fType == SkSL::TypeCategory::kFloat &&
+                        uni.fRows == 2 && uni.fColumns == 1) {
+                        ImVec2 mousePos = ImGui::GetMousePos();
+                        vals[0] = mousePos.x - spawnPos.fX;
+                        vals[1] = mousePos.y - spawnPos.fY;
+                        continue;
+                    }
+
+                    if (uni.fType == SkSL::TypeCategory::kBool) {
+                        for (int c = 0; c < uni.fColumns; ++c, vals += uni.fRows) {
+                            for (int r = 0; r < uni.fRows; ++r, ++vals) {
+                                ImGui::PushID(c*uni.fRows + r);
+                                if (r > 0) {
+                                    ImGui::SameLine();
+                                }
+                                ImGui::CheckboxFlags(r == uni.fRows - 1 ? uni.fName.c_str()
+                                                                        : "##Hidden",
+                                                     (unsigned int*)vals, ~0);
+                                ImGui::PopID();
+                            }
+                        }
+                        continue;
+                    }
+
+                    ImGuiDataType dataType = ImGuiDataType_COUNT;
+                    switch (uni.fType) {
+                        case SkSL::TypeCategory::kSigned:   dataType = ImGuiDataType_S32;   break;
+                        case SkSL::TypeCategory::kUnsigned: dataType = ImGuiDataType_U32;   break;
+                        case SkSL::TypeCategory::kFloat:    dataType = ImGuiDataType_Float; break;
+                        default:                                                            break;
+                    }
+                    SkASSERT(dataType != ImGuiDataType_COUNT);
+                    for (int c = 0; c < uni.fColumns; ++c, vals += uni.fRows) {
+                        ImGui::PushID(c);
+                        ImGui::DragScalarN(uni.fName.c_str(), dataType, vals, uni.fRows, 1.0f);
+                        ImGui::PopID();
+                    }
+                }
+            };
+            uniformsGui(effect->effectCode(), effect->effectUniforms(), fRunning[i].fPosition);
+            uniformsGui(effect->particleCode(), effect->particleUniforms(), fRunning[i].fPosition);
+            if (remove) {
+                fRunning.removeShuffle(i);
+            }
+            ImGui::PopID();
+        }
+    }
+    ImGui::End();
+
+    SkPaint dragPaint;
+    dragPaint.setColor(SK_ColorLTGRAY);
+    dragPaint.setAntiAlias(true);
+    SkPaint dragHighlight;
+    dragHighlight.setStyle(SkPaint::kStroke_Style);
+    dragHighlight.setColor(SK_ColorGREEN);
+    dragHighlight.setStrokeWidth(2);
+    dragHighlight.setAntiAlias(true);
+    for (int i = 0; i < gDragPoints.count(); ++i) {
+        canvas->drawCircle(*gDragPoints[i], kDragSize, dragPaint);
+        if (gDragIndex == i) {
+            canvas->drawCircle(*gDragPoints[i], kDragSize, dragHighlight);
+        }
+    }
+    for (const auto& effect : fRunning) {
+        canvas->save();
+        canvas->translate(effect.fPosition.fX, effect.fPosition.fY);
+        effect.fEffect->draw(canvas);
+        canvas->restore();
+    }
+}
+
+bool ParticlesSlide::animate(double nanos) {
+    fAnimated = true;
+    fAnimationTime = 1e-9 * nanos;
+    for (const auto& effect : fRunning) {
+        effect.fEffect->update(fAnimationTime);
+    }
+    return true;
+}
+
+bool ParticlesSlide::onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey modifiers) {
+    if (gDragIndex == -1) {
+        if (state == skui::InputState::kDown) {
+            float bestDistance = kDragSize;
+            SkPoint mousePt = { x, y };
+            for (int i = 0; i < gDragPoints.count(); ++i) {
+                float distance = SkPoint::Distance(*gDragPoints[i], mousePt);
+                if (distance < bestDistance) {
+                    gDragIndex = i;
+                    bestDistance = distance;
+                }
+            }
+            return gDragIndex != -1;
+        }
+    } else {
+        // Currently dragging
+        SkASSERT(gDragIndex < gDragPoints.count());
+        gDragPoints[gDragIndex]->set(x, y);
+        if (state == skui::InputState::kUp) {
+            gDragIndex = -1;
+        }
+        return true;
+    }
+    return false;
+}
diff --git a/src/third_party/skia/tools/viewer/ParticlesSlide.h b/src/third_party/skia/tools/viewer/ParticlesSlide.h
new file mode 100644
index 0000000..9d98d41
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/ParticlesSlide.h
@@ -0,0 +1,57 @@
+/*
+* Copyright 2019 Google LLC
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef ParticlesSlide_DEFINED
+#define ParticlesSlide_DEFINED
+
+#include "tools/viewer/Slide.h"
+
+#include "include/core/SkPath.h"
+#include "include/private/SkTArray.h"
+#include "include/utils/SkRandom.h"
+
+class SkParticleEffect;
+class SkParticleEffectParams;
+
+class ParticlesSlide : public Slide {
+public:
+    ParticlesSlide();
+
+    // TODO: We need a way for primarily interactive slides to always be as large as the window
+    SkISize getDimensions() const override { return SkISize::MakeEmpty(); }
+
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void draw(SkCanvas* canvas) override;
+    bool animate(double) override;
+
+    bool onMouse(SkScalar x, SkScalar y, skui::InputState state,
+                 skui::ModifierKey modifiers) override;
+
+private:
+    void loadEffects(const char* dirname);
+
+    SkRandom fRandom;
+    bool fAnimated = false;
+    double fAnimationTime = 0;
+    SkPoint fPlayPosition;
+
+    struct LoadedEffect {
+        SkString fName;
+        sk_sp<SkParticleEffectParams> fParams;
+    };
+    SkTArray<LoadedEffect> fLoaded;
+
+    struct RunningEffect {
+        SkPoint fPosition;
+        SkString fName;
+        sk_sp<SkParticleEffect> fEffect;
+        bool fTrackMouse;
+    };
+    SkTArray<RunningEffect> fRunning;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/SKPSlide.cpp b/src/third_party/skia/tools/viewer/SKPSlide.cpp
index e24e1fd..1c03a5e 100644
--- a/src/third_party/skia/tools/viewer/SKPSlide.cpp
+++ b/src/third_party/skia/tools/viewer/SKPSlide.cpp
@@ -5,12 +5,11 @@
 * found in the LICENSE file.
 */
 
-#include "SKPSlide.h"
+#include "tools/viewer/SKPSlide.h"
 
-#include "SkCanvas.h"
-#include "SkCommonFlags.h"
-#include "SkOSFile.h"
-#include "SkStream.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkStream.h"
+#include "src/core/SkOSFile.h"
 
 SKPSlide::SKPSlide(const SkString& name, const SkString& path) : fPath(path) {
     fName = name;
@@ -50,7 +49,9 @@
 
 void SKPSlide::load(SkScalar, SkScalar) {
     fPic = read_picture(fPath.c_str());
-    fCullRect = fPic->cullRect().roundOut();
+    if (fPic) {
+        fCullRect = fPic->cullRect().roundOut();
+    }
 }
 
 void SKPSlide::unload() {
diff --git a/src/third_party/skia/tools/viewer/SKPSlide.h b/src/third_party/skia/tools/viewer/SKPSlide.h
index ff92ed1..e202250 100644
--- a/src/third_party/skia/tools/viewer/SKPSlide.h
+++ b/src/third_party/skia/tools/viewer/SKPSlide.h
@@ -8,8 +8,8 @@
 #ifndef SKPSlide_DEFINED
 #define SKPSlide_DEFINED
 
-#include "Slide.h"
-#include "SkPicture.h"
+#include "include/core/SkPicture.h"
+#include "tools/viewer/Slide.h"
 
 class SKPSlide : public Slide {
 public:
diff --git a/src/third_party/skia/tools/viewer/SampleSlide.cpp b/src/third_party/skia/tools/viewer/SampleSlide.cpp
index 93a495e..662cb40 100644
--- a/src/third_party/skia/tools/viewer/SampleSlide.cpp
+++ b/src/third_party/skia/tools/viewer/SampleSlide.cpp
@@ -5,50 +5,45 @@
 * found in the LICENSE file.
 */
 
-#include "SampleSlide.h"
+#include "tools/viewer/SampleSlide.h"
 
-#include "SkCanvas.h"
-#include "SkCommonFlags.h"
-#include "SkOSFile.h"
-#include "SkStream.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkStream.h"
+#include "src/core/SkOSFile.h"
 
-SampleSlide::SampleSlide(const SkViewFactory* factory) : fViewFactory(factory) {
-    SkView* view = (*factory)();
-    SampleCode::RequestTitle(view, &fName);
-    view->unref();
+using namespace sk_app;
+
+SampleSlide::SampleSlide(const SampleFactory factory) : fSampleFactory(factory) {
+    std::unique_ptr<Sample> sample(factory());
+    fName = sample->name();
 }
 
 SampleSlide::~SampleSlide() {}
 
+SkISize SampleSlide::getDimensions() const  {
+    return SkISize::Make(SkScalarCeilToInt(fSample->width()), SkScalarCeilToInt(fSample->height()));
+}
+
+bool SampleSlide::animate(double nanos) { return fSample->animate(nanos); }
+
 void SampleSlide::draw(SkCanvas* canvas) {
-    SkASSERT(fView);
-    fView->draw(canvas);
+    SkASSERT(fSample);
+    fSample->draw(canvas);
 }
 
 void SampleSlide::load(SkScalar winWidth, SkScalar winHeight) {
-    fView.reset((*fViewFactory)());
-    fView->setVisibleP(true);
-    fView->setClipToBounds(false);
-    fView->setSize(winWidth, winHeight);
+    fSample.reset(fSampleFactory());
+    fSample->setSize(winWidth, winHeight);
 }
 
 void SampleSlide::unload() {
-    fView.reset();
+    fSample.reset();
 }
 
 bool SampleSlide::onChar(SkUnichar c) {
-    if (!fView) {
-        return false;
-    }
-    SkEvent evt(gCharEvtName);
-    evt.setFast32(c);
-    return fView->doQuery(&evt);
+    return fSample && fSample->onChar(c);
 }
 
-#if defined(SK_BUILD_FOR_ANDROID)
-// these are normally defined in SkOSWindow_unix, but we don't
-// want to include that
-void SkEvent::SignalNonEmptyQueue() {}
-
-void SkEvent::SignalQueueTimer(SkMSec delay) {}
-#endif
+bool SampleSlide::onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey modifierKeys) {
+    return fSample && fSample->mouse({x, y}, state, modifierKeys);
+}
diff --git a/src/third_party/skia/tools/viewer/SampleSlide.h b/src/third_party/skia/tools/viewer/SampleSlide.h
index 24325c9..fcb5542 100644
--- a/src/third_party/skia/tools/viewer/SampleSlide.h
+++ b/src/third_party/skia/tools/viewer/SampleSlide.h
@@ -8,29 +8,31 @@
 #ifndef SampleSlide_DEFINED
 #define SampleSlide_DEFINED
 
-#include "Slide.h"
-#include "SampleCode.h"
+#include "samplecode/Sample.h"
+#include "tools/viewer/Slide.h"
 
 class SampleSlide : public Slide {
 public:
-    SampleSlide(const SkViewFactory* factory);
+    SampleSlide(const SampleFactory factory);
     ~SampleSlide() override;
 
+    SkISize getDimensions() const override;
+
     void draw(SkCanvas* canvas) override;
     void load(SkScalar winWidth, SkScalar winHeight) override;
-    void unload() override;
-    bool animate(const SkAnimTimer& timer) override {
-        if (fView && SampleView::IsSampleView(fView.get())) {
-            return ((SampleView*)fView.get())->animate(timer);
-        }
-        return false;
+    void resize(SkScalar winWidth, SkScalar winHeight) override {
+        fSample->setSize(winWidth, winHeight);
     }
+    void unload() override;
+    bool animate(double) override;
 
     bool onChar(SkUnichar c) override;
+    bool onMouse(SkScalar x, SkScalar y, skui::InputState state,
+                 skui::ModifierKey modifiers) override;
 
 private:
-    const SkViewFactory*   fViewFactory;
-    sk_sp<SkView>          fView;
+    const SampleFactory fSampleFactory;
+    std::unique_ptr<Sample> fSample;
 };
 
 #endif
diff --git a/src/third_party/skia/tools/viewer/SkottieSlide.cpp b/src/third_party/skia/tools/viewer/SkottieSlide.cpp
new file mode 100644
index 0000000..65ec645
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SkottieSlide.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "tools/viewer/SkottieSlide.h"
+
+#if defined(SK_ENABLE_SKOTTIE)
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFont.h"
+#include "modules/skottie/include/Skottie.h"
+#include "modules/skottie/utils/SkottieUtils.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/timer/TimeUtils.h"
+
+#include <cmath>
+
+static void draw_stats_box(SkCanvas* canvas, const skottie::Animation::Builder::Stats& stats) {
+    static constexpr SkRect kR = { 10, 10, 280, 120 };
+    static constexpr SkScalar kTextSize = 20;
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    paint.setColor(0xffeeeeee);
+
+    SkFont font(nullptr, kTextSize);
+
+    canvas->drawRect(kR, paint);
+
+    paint.setColor(SK_ColorBLACK);
+
+    const auto json_size = SkStringPrintf("Json size: %lu bytes",
+                                          stats.fJsonSize);
+    canvas->drawString(json_size, kR.x() + 10, kR.y() + kTextSize * 1, font, paint);
+    const auto animator_count = SkStringPrintf("Animator count: %lu",
+                                               stats.fAnimatorCount);
+    canvas->drawString(animator_count, kR.x() + 10, kR.y() + kTextSize * 2, font, paint);
+    const auto json_parse_time = SkStringPrintf("Json parse time: %.3f ms",
+                                                stats.fJsonParseTimeMS);
+    canvas->drawString(json_parse_time, kR.x() + 10, kR.y() + kTextSize * 3, font, paint);
+    const auto scene_parse_time = SkStringPrintf("Scene build time: %.3f ms",
+                                                 stats.fSceneParseTimeMS);
+    canvas->drawString(scene_parse_time, kR.x() + 10, kR.y() + kTextSize * 4, font, paint);
+    const auto total_load_time = SkStringPrintf("Total load time: %.3f ms",
+                                                stats.fTotalLoadTimeMS);
+    canvas->drawString(total_load_time, kR.x() + 10, kR.y() + kTextSize * 5, font, paint);
+
+    paint.setStyle(SkPaint::kStroke_Style);
+    canvas->drawRect(kR, paint);
+}
+
+SkottieSlide::SkottieSlide(const SkString& name, const SkString& path)
+    : fPath(path) {
+    fName = name;
+}
+
+void SkottieSlide::load(SkScalar w, SkScalar h) {
+    class Logger final : public skottie::Logger {
+    public:
+        struct LogEntry {
+            SkString fMessage,
+                     fJSON;
+        };
+
+        void log(skottie::Logger::Level lvl, const char message[], const char json[]) override {
+            auto& log = lvl == skottie::Logger::Level::kError ? fErrors : fWarnings;
+            log.push_back({ SkString(message), json ? SkString(json) : SkString() });
+        }
+
+        void report() const {
+            SkDebugf("Animation loaded with %lu error%s, %lu warning%s.\n",
+                     fErrors.size(), fErrors.size() == 1 ? "" : "s",
+                     fWarnings.size(), fWarnings.size() == 1 ? "" : "s");
+
+            const auto& show = [](const LogEntry& log, const char prefix[]) {
+                SkDebugf("%s%s", prefix, log.fMessage.c_str());
+                if (!log.fJSON.isEmpty())
+                    SkDebugf(" : %s", log.fJSON.c_str());
+                SkDebugf("\n");
+            };
+
+            for (const auto& err : fErrors)   show(err, "  !! ");
+            for (const auto& wrn : fWarnings) show(wrn, "  ?? ");
+        }
+
+    private:
+        std::vector<LogEntry> fErrors,
+                              fWarnings;
+    };
+
+    auto logger = sk_make_sp<Logger>();
+    skottie::Animation::Builder builder;
+
+    fAnimation      = builder
+            .setLogger(logger)
+            .setResourceProvider(
+                skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
+            .makeFromFile(fPath.c_str());
+    fAnimationStats = builder.getStats();
+    fWinSize        = SkSize::Make(w, h);
+    fTimeBase       = 0; // force a time reset
+
+    if (fAnimation) {
+        SkDebugf("Loaded Bodymovin animation v: %s, size: [%f %f]\n",
+                 fAnimation->version().c_str(),
+                 fAnimation->size().width(),
+                 fAnimation->size().height());
+        logger->report();
+    } else {
+        SkDebugf("failed to load Bodymovin animation: %s\n", fPath.c_str());
+    }
+}
+
+void SkottieSlide::unload() {
+    fAnimation.reset();
+}
+
+SkISize SkottieSlide::getDimensions() const {
+    // We always scale to fill the window.
+    return fWinSize.toCeil();
+}
+
+void SkottieSlide::draw(SkCanvas* canvas) {
+    if (fAnimation) {
+        SkAutoCanvasRestore acr(canvas, true);
+        const auto dstR = SkRect::MakeSize(fWinSize);
+        fAnimation->render(canvas, &dstR);
+
+        if (fShowAnimationStats) {
+            draw_stats_box(canvas, fAnimationStats);
+        }
+        if (fShowAnimationInval) {
+            const auto t = SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()),
+                                                    dstR,
+                                                    SkMatrix::kCenter_ScaleToFit);
+            SkPaint fill, stroke;
+            fill.setAntiAlias(true);
+            fill.setColor(0x40ff0000);
+            stroke.setAntiAlias(true);
+            stroke.setColor(0xffff0000);
+            stroke.setStyle(SkPaint::kStroke_Style);
+
+            for (const auto& r : fInvalController) {
+                SkRect bounds;
+                t.mapRect(&bounds, r);
+                canvas->drawRect(bounds, fill);
+                canvas->drawRect(bounds, stroke);
+            }
+        }
+    }
+}
+
+bool SkottieSlide::animate(double nanos) {
+    SkMSec msec = TimeUtils::NanosToMSec(nanos);
+    if (fTimeBase == 0) {
+        // Reset the animation time.
+        fTimeBase = msec;
+    }
+
+    if (fAnimation) {
+        fInvalController.reset();
+        const auto t = msec - fTimeBase;
+        const auto d = fAnimation->duration() * 1000;
+        fAnimation->seek(std::fmod(t, d) / d, &fInvalController);
+    }
+    return true;
+}
+
+bool SkottieSlide::onChar(SkUnichar c) {
+    switch (c) {
+    case 'I':
+        fShowAnimationStats = !fShowAnimationStats;
+        break;
+    default:
+        break;
+    }
+
+    return INHERITED::onChar(c);
+}
+
+bool SkottieSlide::onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey) {
+    switch (state) {
+    case skui::InputState::kUp:
+        fShowAnimationInval = !fShowAnimationInval;
+        fShowAnimationStats = !fShowAnimationStats;
+        break;
+    default:
+        break;
+    }
+
+    return false;
+}
+
+#endif // SK_ENABLE_SKOTTIE
diff --git a/src/third_party/skia/tools/viewer/SkottieSlide.h b/src/third_party/skia/tools/viewer/SkottieSlide.h
new file mode 100644
index 0000000..843922b
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SkottieSlide.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkottieSlide_DEFINED
+#define SkottieSlide_DEFINED
+
+#include "tools/viewer/Slide.h"
+
+#if defined(SK_ENABLE_SKOTTIE)
+#include "modules/skottie/include/Skottie.h"
+#include "modules/sksg/include/SkSGInvalidationController.h"
+
+namespace sksg    { class Scene;     }
+
+class SkottieSlide : public Slide {
+public:
+    SkottieSlide(const SkString& name, const SkString& path);
+    ~SkottieSlide() override = default;
+
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+
+    SkISize getDimensions() const override;
+
+    void draw(SkCanvas*) override;
+    bool animate(double) override;
+
+    bool onChar(SkUnichar) override;
+    bool onMouse(SkScalar x, SkScalar y, skui::InputState, skui::ModifierKey modifiers) override;
+
+private:
+    SkString                           fPath;
+    sk_sp<skottie::Animation>          fAnimation;
+    skottie::Animation::Builder::Stats fAnimationStats;
+    sksg::InvalidationController       fInvalController;
+    SkSize                             fWinSize = SkSize::MakeEmpty();
+    SkMSec                             fTimeBase  = 0;
+    bool                               fShowAnimationInval = false,
+                                       fShowAnimationStats = false;
+
+    typedef Slide INHERITED;
+};
+
+#endif // SK_ENABLE_SKOTTIE
+
+#endif // SkottieSlide_DEFINED
diff --git a/src/third_party/skia/tools/viewer/Slide.h b/src/third_party/skia/tools/viewer/Slide.h
index 9ec7a3d..e81f860 100644
--- a/src/third_party/skia/tools/viewer/Slide.h
+++ b/src/third_party/skia/tools/viewer/Slide.h
@@ -8,30 +8,36 @@
 #ifndef Slide_DEFINED
 #define Slide_DEFINED
 
-#include "SkRefCnt.h"
-#include "SkSize.h"
-#include "SkString.h"
+#include "include/core/SkRefCnt.h"
+#include "include/core/SkSize.h"
+#include "include/core/SkString.h"
+#include "tools/sk_app/Window.h"
 
 class SkCanvas;
-class SkAnimTimer;
+class SkMetaData;
 
 class Slide : public SkRefCnt {
 public:
     virtual ~Slide() {}
 
-    virtual SkISize getDimensions() const {
-        return SkISize::Make(0, 0);
-    }
+    virtual SkISize getDimensions() const = 0;
 
     virtual void draw(SkCanvas* canvas) = 0;
-    virtual bool animate(const SkAnimTimer&) { return false;  }
+    virtual bool animate(double nanos) { return false; }
     virtual void load(SkScalar winWidth, SkScalar winHeight) {}
+    virtual void resize(SkScalar winWidth, SkScalar winHeight) {}
     virtual void unload() {}
 
     virtual bool onChar(SkUnichar c) { return false; }
+    virtual bool onMouse(SkScalar x, SkScalar y, skui::InputState state,
+                         skui::ModifierKey modifiers) { return false; }
+
+    virtual bool onGetControls(SkMetaData*) { return false; }
+    virtual void onSetControls(const SkMetaData&) {}
 
     SkString getName() { return fName; }
 
+
 protected:
     SkString    fName;
 };
diff --git a/src/third_party/skia/tools/viewer/SlideDir.cpp b/src/third_party/skia/tools/viewer/SlideDir.cpp
new file mode 100644
index 0000000..27eed20
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SlideDir.cpp
@@ -0,0 +1,428 @@
+/*
+ * 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 "tools/viewer/SlideDir.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkCubicMap.h"
+#include "include/core/SkTypeface.h"
+#include "modules/sksg/include/SkSGDraw.h"
+#include "modules/sksg/include/SkSGGroup.h"
+#include "modules/sksg/include/SkSGPaint.h"
+#include "modules/sksg/include/SkSGPlane.h"
+#include "modules/sksg/include/SkSGRect.h"
+#include "modules/sksg/include/SkSGRenderNode.h"
+#include "modules/sksg/include/SkSGScene.h"
+#include "modules/sksg/include/SkSGText.h"
+#include "modules/sksg/include/SkSGTransform.h"
+#include "src/core/SkMakeUnique.h"
+#include "tools/timer/TimeUtils.h"
+
+#include <cmath>
+#include <utility>
+
+namespace {
+
+static constexpr float  kAspectRatio   = 1.5f;
+static constexpr float  kLabelSize     = 12.0f;
+static constexpr SkSize kPadding       = { 12.0f , 24.0f };
+
+static constexpr float   kFocusDuration = 500;
+static constexpr SkSize  kFocusInset    = { 100.0f, 100.0f };
+static constexpr SkPoint kFocusCtrl0    = {   0.3f,   1.0f };
+static constexpr SkPoint kFocusCtrl1    = {   0.0f,   1.0f };
+static constexpr SkColor kFocusShade    = 0xa0000000;
+
+// TODO: better unfocus binding?
+static constexpr SkUnichar kUnfocusKey = ' ';
+
+class SlideAdapter final : public sksg::RenderNode {
+public:
+    explicit SlideAdapter(sk_sp<Slide> slide)
+        : fSlide(std::move(slide)) {
+        SkASSERT(fSlide);
+    }
+
+    sk_sp<sksg::Animator> makeForwardingAnimator() {
+        // Trivial sksg::Animator -> skottie::Animation tick adapter
+        class ForwardingAnimator final : public sksg::Animator {
+        public:
+            explicit ForwardingAnimator(sk_sp<SlideAdapter> adapter)
+                : fAdapter(std::move(adapter)) {}
+
+        protected:
+            void onTick(float t) override {
+                fAdapter->tick(SkScalarRoundToInt(t));
+            }
+
+        private:
+            sk_sp<SlideAdapter> fAdapter;
+        };
+
+        return sk_make_sp<ForwardingAnimator>(sk_ref_sp(this));
+    }
+
+protected:
+    SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
+        const auto isize = fSlide->getDimensions();
+        return SkRect::MakeIWH(isize.width(), isize.height());
+    }
+
+    void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
+        SkAutoCanvasRestore acr(canvas, true);
+        canvas->clipRect(SkRect::Make(fSlide->getDimensions()), true);
+
+        // TODO: commit the context?
+        fSlide->draw(canvas);
+    }
+
+    const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; }
+
+private:
+    void tick(SkMSec t) {
+        fSlide->animate(t * 1e6);
+        this->invalidate();
+    }
+
+    const sk_sp<Slide> fSlide;
+
+    using INHERITED = sksg::RenderNode;
+};
+
+SkMatrix SlideMatrix(const sk_sp<Slide>& slide, const SkRect& dst) {
+    const auto slideSize = slide->getDimensions();
+    return SkMatrix::MakeRectToRect(SkRect::MakeIWH(slideSize.width(), slideSize.height()),
+                                    dst,
+                                    SkMatrix::kCenter_ScaleToFit);
+}
+
+} // namespace
+
+struct SlideDir::Rec {
+    sk_sp<Slide>                  fSlide;
+    sk_sp<sksg::RenderNode>       fSlideRoot;
+    sk_sp<sksg::Matrix<SkMatrix>> fMatrix;
+    SkRect                        fRect;
+};
+
+class SlideDir::FocusController final : public sksg::Animator {
+public:
+    FocusController(const SlideDir* dir, const SkRect& focusRect)
+        : fDir(dir)
+        , fRect(focusRect)
+        , fTarget(nullptr)
+        , fMap(kFocusCtrl1, kFocusCtrl0)
+        , fState(State::kIdle) {
+        fShadePaint = sksg::Color::Make(kFocusShade);
+        fShade = sksg::Draw::Make(sksg::Plane::Make(), fShadePaint);
+    }
+
+    bool hasFocus() const { return fState == State::kFocused; }
+
+    void startFocus(const Rec* target) {
+        if (fState != State::kIdle)
+            return;
+
+        fTarget = target;
+
+        // Move the shade & slide to front.
+        fDir->fRoot->removeChild(fTarget->fSlideRoot);
+        fDir->fRoot->addChild(fShade);
+        fDir->fRoot->addChild(fTarget->fSlideRoot);
+
+        fM0 = SlideMatrix(fTarget->fSlide, fTarget->fRect);
+        fM1 = SlideMatrix(fTarget->fSlide, fRect);
+
+        fOpacity0 = 0;
+        fOpacity1 = 1;
+
+        fTimeBase = 0;
+        fState = State::kFocusing;
+
+        // Push initial state to the scene graph.
+        this->onTick(fTimeBase);
+    }
+
+    void startUnfocus() {
+        SkASSERT(fTarget);
+
+        using std::swap;
+        swap(fM0, fM1);
+        swap(fOpacity0, fOpacity1);
+
+        fTimeBase = 0;
+        fState = State::kUnfocusing;
+    }
+
+    bool onMouse(SkScalar x, SkScalar y, skui::InputState state, skui::ModifierKey modifiers) {
+        SkASSERT(fTarget);
+
+        if (!fRect.contains(x, y)) {
+            this->startUnfocus();
+            return true;
+        }
+
+        // Map coords to slide space.
+        const auto xform = SkMatrix::MakeRectToRect(fRect,
+                                                    SkRect::MakeSize(fDir->fWinSize),
+                                                    SkMatrix::kCenter_ScaleToFit);
+        const auto pt = xform.mapXY(x, y);
+
+        return fTarget->fSlide->onMouse(pt.x(), pt.y(), state, modifiers);
+    }
+
+    bool onChar(SkUnichar c) {
+        SkASSERT(fTarget);
+
+        return fTarget->fSlide->onChar(c);
+    }
+
+protected:
+    void onTick(float t) {
+        if (!this->isAnimating())
+            return;
+
+        if (!fTimeBase) {
+            fTimeBase = t;
+        }
+
+        const auto rel_t = (t - fTimeBase) / kFocusDuration,
+                   map_t = SkTPin(fMap.computeYFromX(rel_t), 0.0f, 1.0f);
+
+        SkMatrix m;
+        for (int i = 0; i < 9; ++i) {
+            m[i] = fM0[i] + map_t * (fM1[i] - fM0[i]);
+        }
+
+        SkASSERT(fTarget);
+        fTarget->fMatrix->setMatrix(m);
+
+        const auto shadeOpacity = fOpacity0 + map_t * (fOpacity1 - fOpacity0);
+        fShadePaint->setOpacity(shadeOpacity);
+
+        if (rel_t < 1)
+            return;
+
+        switch (fState) {
+        case State::kFocusing:
+            fState = State::kFocused;
+            break;
+        case State::kUnfocusing:
+            fState  = State::kIdle;
+            fDir->fRoot->removeChild(fShade);
+            break;
+
+        case State::kIdle:
+        case State::kFocused:
+            SkASSERT(false);
+            break;
+        }
+    }
+
+private:
+    enum class State {
+        kIdle,
+        kFocusing,
+        kUnfocusing,
+        kFocused,
+    };
+
+    bool isAnimating() const { return fState == State::kFocusing || fState == State::kUnfocusing; }
+
+    const SlideDir*         fDir;
+    const SkRect            fRect;
+    const Rec*              fTarget;
+
+    SkCubicMap              fMap;
+    sk_sp<sksg::RenderNode> fShade;
+    sk_sp<sksg::PaintNode>  fShadePaint;
+
+    SkMatrix        fM0       = SkMatrix::I(),
+                    fM1       = SkMatrix::I();
+    float           fOpacity0 = 0,
+                    fOpacity1 = 1,
+                    fTimeBase = 0;
+    State           fState    = State::kIdle;
+
+    using INHERITED = sksg::Animator;
+};
+
+SlideDir::SlideDir(const SkString& name, SkTArray<sk_sp<Slide>>&& slides, int columns)
+    : fSlides(std::move(slides))
+    , fColumns(columns) {
+    fName = name;
+}
+
+static sk_sp<sksg::RenderNode> MakeLabel(const SkString& txt,
+                                         const SkPoint& pos,
+                                         const SkMatrix& dstXform) {
+    const auto size = kLabelSize / std::sqrt(dstXform.getScaleX() * dstXform.getScaleY());
+    auto text = sksg::Text::Make(nullptr, txt);
+    text->setEdging(SkFont::Edging::kAntiAlias);
+    text->setSize(size);
+    text->setAlign(SkTextUtils::kCenter_Align);
+    text->setPosition(pos + SkPoint::Make(0, size));
+
+    return sksg::Draw::Make(std::move(text), sksg::Color::Make(SK_ColorBLACK));
+}
+
+void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
+    // Build a global scene using transformed animation fragments:
+    //
+    // [Group(root)]
+    //     [Transform]
+    //         [Group]
+    //             [AnimationWrapper]
+    //             [Draw]
+    //                 [Text]
+    //                 [Color]
+    //     [Transform]
+    //         [Group]
+    //             [AnimationWrapper]
+    //             [Draw]
+    //                 [Text]
+    //                 [Color]
+    //     ...
+    //
+
+    fWinSize = SkSize::Make(winWidth, winHeight);
+    const auto  cellWidth =  winWidth / fColumns;
+    fCellSize = SkSize::Make(cellWidth, cellWidth / kAspectRatio);
+
+    sksg::AnimatorList sceneAnimators;
+    fRoot = sksg::Group::Make();
+
+    for (int i = 0; i < fSlides.count(); ++i) {
+        const auto& slide     = fSlides[i];
+        slide->load(winWidth, winHeight);
+
+        const auto  slideSize = slide->getDimensions();
+        const auto  cell      = SkRect::MakeXYWH(fCellSize.width()  * (i % fColumns),
+                                                 fCellSize.height() * (i / fColumns),
+                                                 fCellSize.width(),
+                                                 fCellSize.height()),
+                    slideRect = cell.makeInset(kPadding.width(), kPadding.height());
+
+        auto slideMatrix = sksg::Matrix<SkMatrix>::Make(SlideMatrix(slide, slideRect));
+        auto adapter     = sk_make_sp<SlideAdapter>(slide);
+        auto slideGrp    = sksg::Group::Make();
+        slideGrp->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeIWH(slideSize.width(),
+                                                                             slideSize.height())),
+                                            sksg::Color::Make(0xfff0f0f0)));
+        slideGrp->addChild(adapter);
+        slideGrp->addChild(MakeLabel(slide->getName(),
+                                     SkPoint::Make(slideSize.width() / 2, slideSize.height()),
+                                     slideMatrix->getMatrix()));
+        auto slideRoot = sksg::TransformEffect::Make(std::move(slideGrp), slideMatrix);
+
+        sceneAnimators.push_back(adapter->makeForwardingAnimator());
+
+        fRoot->addChild(slideRoot);
+        fRecs.push_back({ slide, slideRoot, slideMatrix, slideRect });
+    }
+
+    fScene = sksg::Scene::Make(fRoot, std::move(sceneAnimators));
+
+    const auto focusRect = SkRect::MakeSize(fWinSize).makeInset(kFocusInset.width(),
+                                                                kFocusInset.height());
+    fFocusController = skstd::make_unique<FocusController>(this, focusRect);
+}
+
+void SlideDir::unload() {
+    for (const auto& slide : fSlides) {
+        slide->unload();
+    }
+
+    fRecs.reset();
+    fScene.reset();
+    fFocusController.reset();
+    fRoot.reset();
+    fTimeBase = 0;
+}
+
+SkISize SlideDir::getDimensions() const {
+    return SkSize::Make(fWinSize.width(),
+                        fCellSize.height() * (1 + (fSlides.count() - 1) / fColumns)).toCeil();
+}
+
+void SlideDir::draw(SkCanvas* canvas) {
+    fScene->render(canvas);
+}
+
+bool SlideDir::animate(double nanos) {
+    SkMSec msec = TimeUtils::NanosToMSec(nanos);
+    if (fTimeBase == 0) {
+        // Reset the animation time.
+        fTimeBase = msec;
+    }
+
+    const auto t = msec - fTimeBase;
+    fScene->animate(t);
+    fFocusController->tick(t);
+
+    return true;
+}
+
+bool SlideDir::onChar(SkUnichar c) {
+    if (fFocusController->hasFocus()) {
+        if (c == kUnfocusKey) {
+            fFocusController->startUnfocus();
+            return true;
+        }
+        return fFocusController->onChar(c);
+    }
+
+    return false;
+}
+
+bool SlideDir::onMouse(SkScalar x, SkScalar y, skui::InputState state,
+                       skui::ModifierKey modifiers) {
+    modifiers &= ~skui::ModifierKey::kFirstPress;
+    if (state == skui::InputState::kMove || skstd::Any(modifiers))
+        return false;
+
+    if (fFocusController->hasFocus()) {
+        return fFocusController->onMouse(x, y, state, modifiers);
+    }
+
+    const auto* cell = this->findCell(x, y);
+    if (!cell)
+        return false;
+
+    static constexpr SkScalar kClickMoveTolerance = 4;
+
+    switch (state) {
+    case skui::InputState::kDown:
+        fTrackingCell = cell;
+        fTrackingPos = SkPoint::Make(x, y);
+        break;
+    case skui::InputState::kUp:
+        if (cell == fTrackingCell &&
+            SkPoint::Distance(fTrackingPos, SkPoint::Make(x, y)) < kClickMoveTolerance) {
+            fFocusController->startFocus(cell);
+        }
+        break;
+    default:
+        break;
+    }
+
+    return false;
+}
+
+const SlideDir::Rec* SlideDir::findCell(float x, float y) const {
+    // TODO: use SG hit testing instead of layout info?
+    const auto size = this->getDimensions();
+    if (x < 0 || y < 0 || x >= size.width() || y >= size.height()) {
+        return nullptr;
+    }
+
+    const int col = static_cast<int>(x / fCellSize.width()),
+              row = static_cast<int>(y / fCellSize.height()),
+              idx = row * fColumns + col;
+
+    return idx < fRecs.count() ? &fRecs[idx] : nullptr;
+}
diff --git a/src/third_party/skia/tools/viewer/SlideDir.h b/src/third_party/skia/tools/viewer/SlideDir.h
new file mode 100644
index 0000000..3a57340
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SlideDir.h
@@ -0,0 +1,67 @@
+/*
+ * 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 SlideDir_DEFINED
+#define SlideDir_DEFINED
+
+#include "tools/viewer/Slide.h"
+
+#include "include/private/SkTArray.h"
+
+class SkString;
+
+namespace sksg {
+
+class Group;
+class Scene;
+
+}
+
+class SlideDir final : public Slide {
+public:
+    SlideDir(const SkString& name, SkTArray<sk_sp<Slide>>&&,
+             int columns = kDefaultColumnCount);
+
+protected:
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+
+    SkISize getDimensions() const override;
+
+    void draw(SkCanvas*) override;
+    bool animate(double) override;
+
+    bool onChar(SkUnichar) override;
+    bool onMouse(SkScalar x, SkScalar y, skui::InputState, skui::ModifierKey modifiers) override;
+
+private:
+    struct Rec;
+    class FocusController;
+
+    static constexpr int kDefaultColumnCount = 4;
+
+    const Rec* findCell(float x, float y) const;
+
+    const SkTArray<sk_sp<Slide>>       fSlides;
+    std::unique_ptr<FocusController>   fFocusController;
+    const int                          fColumns;
+
+    SkTArray<Rec, true>                fRecs;
+    std::unique_ptr<sksg::Scene>       fScene;
+    sk_sp<sksg::Group>                 fRoot;
+
+    SkSize                             fWinSize  = SkSize::MakeEmpty();
+    SkSize                             fCellSize = SkSize::MakeEmpty();
+    SkMSec                             fTimeBase = 0;
+
+    const Rec*                         fTrackingCell = nullptr;
+    SkPoint                            fTrackingPos  = SkPoint::Make(0, 0);
+
+    using INHERITED = Slide;
+};
+
+#endif // SlideDir_DEFINED
diff --git a/src/third_party/skia/tools/viewer/StatsLayer.cpp b/src/third_party/skia/tools/viewer/StatsLayer.cpp
new file mode 100644
index 0000000..a047b31
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/StatsLayer.cpp
@@ -0,0 +1,177 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "tools/viewer/StatsLayer.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkFont.h"
+#include "include/core/SkString.h"
+#include "include/core/SkSurface.h"
+#include "include/core/SkTime.h"
+
+StatsLayer::StatsLayer()
+    : fCurrentMeasurement(-1)
+    , fLastTotalBegin(0)
+    , fCumulativeMeasurementTime(0)
+    , fCumulativeMeasurementCount(0)
+    , fDisplayScale(1.0f) {
+    memset(fTotalTimes, 0, sizeof(fTotalTimes));
+}
+
+void StatsLayer::resetMeasurements() {
+    for (int i = 0; i < fTimers.count(); ++i) {
+        memset(fTimers[i].fTimes, 0, sizeof(fTimers[i].fTimes));
+    }
+    memset(fTotalTimes, 0, sizeof(fTotalTimes));
+    fCurrentMeasurement = -1;
+    fLastTotalBegin = 0;
+    fCumulativeMeasurementTime = 0;
+    fCumulativeMeasurementCount = 0;
+}
+
+StatsLayer::Timer StatsLayer::addTimer(const char* label, SkColor color, SkColor labelColor) {
+    Timer newTimer = fTimers.count();
+    TimerData& newData = fTimers.push_back();
+    memset(newData.fTimes, 0, sizeof(newData.fTimes));
+    newData.fLabel = label;
+    newData.fColor = color;
+    newData.fLabelColor = labelColor ? labelColor : color;
+    return newTimer;
+}
+
+void StatsLayer::beginTiming(Timer timer) {
+    if (fCurrentMeasurement >= 0) {
+        fTimers[timer].fTimes[fCurrentMeasurement] -= SkTime::GetMSecs();
+    }
+}
+
+void StatsLayer::endTiming(Timer timer) {
+    if (fCurrentMeasurement >= 0) {
+        fTimers[timer].fTimes[fCurrentMeasurement] += SkTime::GetMSecs();
+    }
+}
+
+void StatsLayer::onPrePaint() {
+    if (fCurrentMeasurement >= 0) {
+        fTotalTimes[fCurrentMeasurement] = SkTime::GetMSecs() - fLastTotalBegin;
+        fCumulativeMeasurementTime += fTotalTimes[fCurrentMeasurement];
+        fCumulativeMeasurementCount++;
+    }
+    fCurrentMeasurement = (fCurrentMeasurement + 1) & (kMeasurementCount - 1);
+    SkASSERT(fCurrentMeasurement >= 0 && fCurrentMeasurement < kMeasurementCount);
+    fLastTotalBegin = SkTime::GetMSecs();
+}
+
+void StatsLayer::onPaint(SkSurface* surface) {
+    int nextMeasurement = (fCurrentMeasurement + 1) & (kMeasurementCount - 1);
+    for (int i = 0; i < fTimers.count(); ++i) {
+        fTimers[i].fTimes[nextMeasurement] = 0;
+    }
+
+#ifdef SK_BUILD_FOR_ANDROID
+    // Scale up the stats overlay on Android devices
+    static constexpr SkScalar kScale = 1.5;
+#else
+    SkScalar kScale = fDisplayScale;
+#endif
+
+    // Now draw everything
+    static const float kPixelPerMS = 2.0f;
+    static const int kDisplayWidth = 192;
+    static const int kGraphHeight = 100;
+    static const int kTextHeight = 60;
+    static const int kDisplayHeight = kGraphHeight + kTextHeight;
+    static const int kDisplayPadding = 10;
+    static const int kGraphPadding = 3;
+    static const SkScalar kBaseMS = 1000.f / 60.f;  // ms/frame to hit 60 fps
+
+    auto canvas = surface->getCanvas();
+    SkISize canvasSize = canvas->getBaseLayerSize();
+    SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding),
+                                   SkIntToScalar(kDisplayPadding),
+                                   SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight));
+    SkPaint paint;
+    canvas->save();
+
+    // Scale the canvas while keeping the right edge in place.
+    canvas->concat(SkMatrix::MakeRectToRect(SkRect::Make(canvasSize),
+                                            SkRect::MakeXYWH(canvasSize.width()  * (1 - kScale),
+                                                             0,
+                                                             canvasSize.width()  * kScale,
+                                                             canvasSize.height() * kScale),
+                                            SkMatrix::kFill_ScaleToFit));
+
+    paint.setColor(SK_ColorBLACK);
+    canvas->drawRect(rect, paint);
+    // draw the 16ms line
+    paint.setColor(SK_ColorLTGRAY);
+    canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS,
+                     rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint);
+    paint.setColor(SK_ColorRED);
+    paint.setStyle(SkPaint::kStroke_Style);
+    canvas->drawRect(rect, paint);
+    paint.setStyle(SkPaint::kFill_Style);
+
+    int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding;
+    const int xStep = 3;
+    int i = nextMeasurement;
+    SkTDArray<double> sumTimes;
+    sumTimes.setCount(fTimers.count());
+    memset(sumTimes.begin(), 0, sumTimes.count() * sizeof(double));
+    int count = 0;
+    double totalTime = 0;
+    int totalCount = 0;
+    do {
+        int startY = SkScalarTruncToInt(rect.fBottom);
+        double inc = 0;
+        for (int timer = 0; timer < fTimers.count(); ++timer) {
+            int height = (int)(fTimers[timer].fTimes[i] * kPixelPerMS + 0.5);
+            int endY = SkTMax(startY - height, kDisplayPadding + kTextHeight);
+            paint.setColor(fTimers[timer].fColor);
+            canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
+                             SkIntToScalar(x), SkIntToScalar(endY), paint);
+            startY = endY;
+            inc += fTimers[timer].fTimes[i];
+            sumTimes[timer] += fTimers[timer].fTimes[i];
+        }
+
+        int height = (int)(fTotalTimes[i] * kPixelPerMS + 0.5);
+        height = SkTMax(0, height - (SkScalarTruncToInt(rect.fBottom) - startY));
+        int endY = SkTMax(startY - height, kDisplayPadding + kTextHeight);
+        paint.setColor(SK_ColorWHITE);
+        canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
+                         SkIntToScalar(x), SkIntToScalar(endY), paint);
+        totalTime += fTotalTimes[i];
+        if (fTotalTimes[i] > 0) {
+            ++totalCount;
+        }
+
+        if (inc > 0) {
+            ++count;
+        }
+
+        i++;
+        i &= (kMeasurementCount - 1);  // fast mod
+        x += xStep;
+    } while (i != nextMeasurement);
+
+    SkFont font(nullptr, 16);
+    paint.setColor(SK_ColorWHITE);
+    double time = totalTime / SkTMax(1, totalCount);
+    double measure = fCumulativeMeasurementTime / SkTMax(1, fCumulativeMeasurementCount);
+    canvas->drawString(SkStringPrintf("%4.3f ms -> %4.3f ms", time, measure),
+                       rect.fLeft + 3, rect.fTop + 14, font, paint);
+
+    for (int timer = 0; timer < fTimers.count(); ++timer) {
+        paint.setColor(fTimers[timer].fLabelColor);
+        canvas->drawString(SkStringPrintf("%s: %4.3f ms", fTimers[timer].fLabel.c_str(),
+                                          sumTimes[timer] / SkTMax(1, count)),
+                           rect.fLeft + 3, rect.fTop + 28 + (14 * timer), font, paint);
+    }
+
+    canvas->restore();
+}
diff --git a/src/third_party/skia/tools/viewer/StatsLayer.h b/src/third_party/skia/tools/viewer/StatsLayer.h
new file mode 100644
index 0000000..79f4a78
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/StatsLayer.h
@@ -0,0 +1,48 @@
+/*
+* Copyright 2017 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef StatsLayer_DEFINED
+#define StatsLayer_DEFINED
+
+#include "include/core/SkColor.h"
+#include "include/core/SkString.h"
+#include "tools/sk_app/Window.h"
+
+class StatsLayer : public sk_app::Window::Layer {
+public:
+    StatsLayer();
+    void resetMeasurements();
+
+    typedef int Timer;
+
+    Timer addTimer(const char* label, SkColor color, SkColor labelColor = 0);
+    void beginTiming(Timer);
+    void endTiming(Timer);
+
+    void onPrePaint() override;
+    void onPaint(SkSurface*) override;
+
+    void setDisplayScale(float scale) { fDisplayScale = scale; }
+
+private:
+    static const int kMeasurementCount = 1 << 6;  // should be power of 2 for fast mod
+    struct TimerData {
+        double fTimes[kMeasurementCount];
+        SkString fLabel;
+        SkColor fColor;
+        SkColor fLabelColor;
+    };
+    SkTArray<TimerData> fTimers;
+    double fTotalTimes[kMeasurementCount];
+    int fCurrentMeasurement;
+    double fLastTotalBegin;
+    double fCumulativeMeasurementTime;
+    int fCumulativeMeasurementCount;
+    float fDisplayScale;
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/SvgSlide.cpp b/src/third_party/skia/tools/viewer/SvgSlide.cpp
new file mode 100644
index 0000000..512546b
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SvgSlide.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "tools/viewer/SvgSlide.h"
+
+#if defined(SK_XML)
+
+#include "experimental/svg/model/SkSVGDOM.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkStream.h"
+
+SvgSlide::SvgSlide(const SkString& name, const SkString& path)
+    : fPath(path) {
+    fName = name;
+}
+
+void SvgSlide::load(SkScalar w, SkScalar h) {
+    fWinSize   = SkSize::Make(w, h);
+
+    if (const auto svgStream =  SkStream::MakeFromFile(fPath.c_str())) {
+        fDom = SkSVGDOM::MakeFromStream(*svgStream);
+        if (fDom) {
+            fDom->setContainerSize(fWinSize);
+        }
+    }
+}
+
+void SvgSlide::unload() {
+    fDom.reset();
+}
+
+SkISize SvgSlide::getDimensions() const {
+    // We always scale to fill the window.
+    return fWinSize.toCeil();
+}
+
+void SvgSlide::draw(SkCanvas* canvas) {
+    if (fDom) {
+        fDom->render(canvas);
+    }
+}
+
+#endif // SK_XML
diff --git a/src/third_party/skia/tools/viewer/SvgSlide.h b/src/third_party/skia/tools/viewer/SvgSlide.h
new file mode 100644
index 0000000..1744d74
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/SvgSlide.h
@@ -0,0 +1,34 @@
+/*
+ * 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 SvgSlide_DEFINED
+#define SvgSlide_DEFINED
+
+#include "tools/viewer/Slide.h"
+
+class SkSVGDOM;
+
+class SvgSlide final : public Slide {
+public:
+    SvgSlide(const SkString& name, const SkString& path);
+
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+
+    SkISize getDimensions() const override;
+
+    void draw(SkCanvas*) override;
+private:
+    const SkString  fPath;
+
+    SkSize          fWinSize = SkSize::MakeEmpty();
+    sk_sp<SkSVGDOM> fDom;
+
+    typedef Slide INHERITED;
+};
+
+#endif // SvgSlide_DEFINED
diff --git a/src/third_party/skia/tools/viewer/TouchGesture.cpp b/src/third_party/skia/tools/viewer/TouchGesture.cpp
new file mode 100644
index 0000000..4bef1f2
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/TouchGesture.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <algorithm>
+
+#include "include/core/SkMatrix.h"
+#include "include/core/SkTime.h"
+#include "tools/viewer/TouchGesture.h"
+
+#define DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER   true
+
+static const SkScalar MAX_FLING_SPEED = SkIntToScalar(1500);
+
+static SkScalar pin_max_fling(SkScalar speed) {
+    if (speed > MAX_FLING_SPEED) {
+        speed = MAX_FLING_SPEED;
+    }
+    return speed;
+}
+
+static double getseconds() {
+    return SkTime::GetMSecs() * 0.001;
+}
+
+// returns +1 or -1, depending on the sign of x
+// returns +1 if z is zero
+static SkScalar SkScalarSignNonZero(SkScalar x) {
+    SkScalar sign = SK_Scalar1;
+    if (x < 0) {
+        sign = -sign;
+    }
+    return sign;
+}
+
+static void unit_axis_align(SkVector* unit) {
+    const SkScalar TOLERANCE = SkDoubleToScalar(0.15);
+    if (SkScalarAbs(unit->fX) < TOLERANCE) {
+        unit->fX = 0;
+        unit->fY = SkScalarSignNonZero(unit->fY);
+    } else if (SkScalarAbs(unit->fY) < TOLERANCE) {
+        unit->fX = SkScalarSignNonZero(unit->fX);
+        unit->fY = 0;
+    }
+}
+
+void TouchGesture::FlingState::reset(float sx, float sy) {
+    fActive = true;
+    fDirection.set(sx, sy);
+    fSpeed0 = SkPoint::Normalize(&fDirection);
+    fSpeed0 = pin_max_fling(fSpeed0);
+    fTime0 = getseconds();
+
+    unit_axis_align(&fDirection);
+//    printf("---- speed %g dir %g %g\n", fSpeed0, fDirection.fX, fDirection.fY);
+}
+
+bool TouchGesture::FlingState::evaluateMatrix(SkMatrix* matrix) {
+    if (!fActive) {
+        return false;
+    }
+
+    const float t =  (float)(getseconds() - fTime0);
+    const float MIN_SPEED = 2;
+    const float K0 = 5;
+    const float K1 = 0.02f;
+    const float speed = fSpeed0 * (sk_float_exp(- K0 * t) - K1);
+    if (speed <= MIN_SPEED) {
+        fActive = false;
+        return false;
+    }
+    float dist = (fSpeed0 - speed) / K0;
+
+//    printf("---- time %g speed %g dist %g\n", t, speed, dist);
+    float tx = fDirection.fX * dist;
+    float ty = fDirection.fY * dist;
+    if (DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER) {
+        tx = (float)sk_float_round2int(tx);
+        ty = (float)sk_float_round2int(ty);
+    }
+    matrix->setTranslate(tx, ty);
+//    printf("---- evaluate (%g %g)\n", tx, ty);
+
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const SkMSec MAX_DBL_TAP_INTERVAL = 300;
+static const float MAX_DBL_TAP_DISTANCE = 100;
+static const float MAX_JITTER_RADIUS = 2;
+
+// if true, then ignore the touch-move, 'cause its probably just jitter
+static bool close_enough_for_jitter(float x0, float y0, float x1, float y1) {
+    return  sk_float_abs(x0 - x1) <= MAX_JITTER_RADIUS &&
+            sk_float_abs(y0 - y1) <= MAX_JITTER_RADIUS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+TouchGesture::TouchGesture() {
+    this->reset();
+}
+
+TouchGesture::~TouchGesture() {
+}
+
+void TouchGesture::resetTouchState() {
+    fIsTransLimited = false;
+    fTouches.reset();
+    fState = kEmpty_State;
+    fLocalM.reset();
+
+    fLastUpMillis = SkTime::GetMSecs() - 2*MAX_DBL_TAP_INTERVAL;
+    fLastUpP.set(0, 0);
+}
+
+void TouchGesture::reset() {
+    fGlobalM.reset();
+    this->resetTouchState();
+}
+
+void TouchGesture::flushLocalM() {
+    fGlobalM.postConcat(fLocalM);
+    fLocalM.reset();
+}
+
+const SkMatrix& TouchGesture::localM() {
+    if (fFlinger.isActive()) {
+        if (!fFlinger.evaluateMatrix(&fLocalM)) {
+            this->flushLocalM();
+        }
+    }
+    return fLocalM;
+}
+
+void TouchGesture::appendNewRec(void* owner, float x, float y) {
+    Rec* rec = fTouches.append();
+    rec->fOwner = owner;
+    rec->fStartX = rec->fPrevX = rec->fLastX = x;
+    rec->fStartY = rec->fPrevY = rec->fLastY = y;
+    rec->fLastT = rec->fPrevT = static_cast<float>(SkTime::GetSecs());
+}
+
+void TouchGesture::touchBegin(void* owner, float x, float y) {
+//    SkDebugf("--- %d touchBegin %p %g %g\n", fTouches.count(), owner, x, y);
+
+    int index = this->findRec(owner);
+    if (index >= 0) {
+        this->flushLocalM();
+        fTouches.removeShuffle(index);
+        SkDebugf("---- already exists, removing\n");
+    }
+
+    if (fTouches.count() == 2) {
+        return;
+    }
+
+    this->flushLocalM();
+    fFlinger.stop();
+
+    this->appendNewRec(owner, x, y);
+
+    switch (fTouches.count()) {
+        case 1:
+            fState = kTranslate_State;
+            break;
+        case 2:
+            this->startZoom();
+            break;
+        default:
+            break;
+    }
+}
+
+int TouchGesture::findRec(void* owner) const {
+    for (int i = 0; i < fTouches.count(); i++) {
+        if (owner == fTouches[i].fOwner) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static SkScalar center(float pos0, float pos1) {
+    return (pos0 + pos1) * 0.5f;
+}
+
+static const float MAX_ZOOM_SCALE = 4;
+static const float MIN_ZOOM_SCALE = 0.25f;
+
+float TouchGesture::limitTotalZoom(float scale) const {
+    // this query works 'cause we know that we're square-scale w/ no skew/rotation
+    const float curr = SkScalarToFloat(fGlobalM[0]);
+
+    if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) {
+        scale = MAX_ZOOM_SCALE / curr;
+    } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) {
+        scale = MIN_ZOOM_SCALE / curr;
+    }
+    return scale;
+}
+
+void TouchGesture::startZoom() {
+    fState = kZoom_State;
+}
+
+void TouchGesture::updateZoom(float scale, float startX, float startY, float lastX, float lastY) {
+    scale = this->limitTotalZoom(scale);
+
+    fLocalM.setTranslate(-startX, -startY);
+    fLocalM.postScale(scale, scale);
+    fLocalM.postTranslate(lastX, lastY);
+}
+
+void TouchGesture::endZoom() {
+    this->flushLocalM();
+    SkASSERT(kZoom_State == fState);
+    fState = kEmpty_State;
+}
+
+void TouchGesture::touchMoved(void* owner, float x, float y) {
+//    SkDebugf("--- %d touchMoved %p %g %g\n", fTouches.count(), owner, x, y);
+
+    if (kEmpty_State == fState) {
+        return;
+    }
+
+    int index = this->findRec(owner);
+    if (index < 0) {
+        SkDebugf("---- ignoring move without begin\n");
+        return;
+    }
+
+    Rec& rec = fTouches[index];
+
+    // not sure how valuable this is
+    if (fTouches.count() == 2) {
+        if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) {
+//            SkDebugf("--- drop touchMove, within jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y);
+            return;
+        }
+    }
+
+    rec.fPrevX = rec.fLastX; rec.fLastX = x;
+    rec.fPrevY = rec.fLastY; rec.fLastY = y;
+    rec.fPrevT = rec.fLastT;
+    rec.fLastT = static_cast<float>(SkTime::GetSecs());
+
+    switch (fTouches.count()) {
+        case 1: {
+            float dx = rec.fLastX - rec.fStartX;
+            float dy = rec.fLastY - rec.fStartY;
+            dx = (float)sk_float_round2int(dx);
+            dy = (float)sk_float_round2int(dy);
+            fLocalM.setTranslate(dx, dy);
+        } break;
+        case 2: {
+            SkASSERT(kZoom_State == fState);
+            const Rec& rec0 = fTouches[0];
+            const Rec& rec1 = fTouches[1];
+
+            float scale = this->computePinch(rec0, rec1);
+            this->updateZoom(scale,
+                             center(rec0.fStartX, rec1.fStartX),
+                             center(rec0.fStartY, rec1.fStartY),
+                             center(rec0.fLastX, rec1.fLastX),
+                             center(rec0.fLastY, rec1.fLastY));
+        } break;
+        default:
+            break;
+    }
+}
+
+void TouchGesture::touchEnd(void* owner) {
+//    SkDebugf("--- %d touchEnd   %p\n", fTouches.count(), owner);
+
+    int index = this->findRec(owner);
+    if (index < 0) {
+        SkDebugf("--- not found\n");
+        return;
+    }
+
+    const Rec& rec = fTouches[index];
+    if (this->handleDblTap(rec.fLastX, rec.fLastY)) {
+        return;
+    }
+
+    // count() reflects the number before we removed the owner
+    switch (fTouches.count()) {
+        case 1: {
+            this->flushLocalM();
+            float dx = rec.fLastX - rec.fPrevX;
+            float dy = rec.fLastY - rec.fPrevY;
+            float dur = rec.fLastT - rec.fPrevT;
+            if (dur > 0) {
+                fFlinger.reset(dx / dur, dy / dur);
+            }
+            fState = kEmpty_State;
+        } break;
+        case 2:
+            this->endZoom();
+            break;
+        default:
+            SkASSERT(kZoom_State == fState);
+            break;
+    }
+
+    fTouches.removeShuffle(index);
+
+    limitTrans();
+}
+
+bool TouchGesture::isFling(SkPoint* dir) {
+    if (fFlinger.isActive()) {
+        SkScalar speed;
+        fFlinger.get(dir, &speed);
+        if (speed > 1000) {
+            return true;
+        }
+    }
+    return false;
+}
+
+float TouchGesture::computePinch(const Rec& rec0, const Rec& rec1) {
+    double dx = rec0.fStartX - rec1.fStartX;
+    double dy = rec0.fStartY - rec1.fStartY;
+    double dist0 = sqrt(dx*dx + dy*dy);
+
+    dx = rec0.fLastX - rec1.fLastX;
+    dy = rec0.fLastY - rec1.fLastY;
+    double dist1 = sqrt(dx*dx + dy*dy);
+
+    double scale = dist1 / dist0;
+    return (float)scale;
+}
+
+bool TouchGesture::handleDblTap(float x, float y) {
+    bool found = false;
+    double now = SkTime::GetMSecs();
+    if (now - fLastUpMillis <= MAX_DBL_TAP_INTERVAL) {
+        if (SkPoint::Length(fLastUpP.fX - x,
+                            fLastUpP.fY - y) <= MAX_DBL_TAP_DISTANCE) {
+            fFlinger.stop();
+            fLocalM.reset();
+            fGlobalM.reset();
+            fTouches.reset();
+            fState = kEmpty_State;
+            found = true;
+        }
+    }
+
+    fLastUpMillis = now;
+    fLastUpP.set(x, y);
+    return found;
+}
+
+void TouchGesture::setTransLimit(const SkRect& contentRect, const SkRect& windowRect,
+                                   const SkMatrix& preTouchMatrix) {
+    fIsTransLimited = true;
+    fContentRect = contentRect;
+    fWindowRect = windowRect;
+    fPreTouchM = preTouchMatrix;
+}
+
+void TouchGesture::limitTrans() {
+    if (!fIsTransLimited) {
+        return;
+    }
+
+    SkRect scaledContent = fContentRect;
+    fPreTouchM.mapRect(&scaledContent);
+    fGlobalM.mapRect(&scaledContent);
+    const SkScalar ZERO = 0;
+
+    fGlobalM.postTranslate(ZERO, std::min(ZERO, fWindowRect.fBottom - scaledContent.fTop));
+    fGlobalM.postTranslate(ZERO, std::max(ZERO, fWindowRect.fTop - scaledContent.fBottom));
+    fGlobalM.postTranslate(std::min(ZERO, fWindowRect.fRight - scaledContent.fLeft), ZERO);
+    fGlobalM.postTranslate(std::max(ZERO, fWindowRect.fLeft - scaledContent.fRight), ZERO);
+}
diff --git a/src/third_party/skia/tools/viewer/TouchGesture.h b/src/third_party/skia/tools/viewer/TouchGesture.h
new file mode 100644
index 0000000..475b438
--- /dev/null
+++ b/src/third_party/skia/tools/viewer/TouchGesture.h
@@ -0,0 +1,96 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef TouchGesture_DEFINED
+#define TouchGesture_DEFINED
+
+#include "include/core/SkMatrix.h"
+#include "include/private/SkTDArray.h"
+
+class TouchGesture {
+public:
+    TouchGesture();
+    ~TouchGesture();
+
+    void touchBegin(void* owner, float x, float y);
+    void touchMoved(void* owner, float x, float y);
+    void touchEnd(void* owner);
+    void reset();
+    void resetTouchState();
+
+    bool isActive() { return fFlinger.isActive(); }
+    void stop() { fFlinger.stop(); }
+    bool isBeingTouched() { return kEmpty_State != fState; }
+    bool isFling(SkPoint* dir);
+
+    void startZoom();
+    void updateZoom(float scale, float startX, float startY, float lastX, float lastY);
+    void endZoom();
+
+    const SkMatrix& localM();
+    const SkMatrix& globalM() const { return fGlobalM; }
+
+    void setTransLimit(const SkRect& contentRect, const SkRect& windowRect,
+                       const SkMatrix& preTouchM);
+
+private:
+    enum State {
+        kEmpty_State,
+        kTranslate_State,
+        kZoom_State,
+    };
+
+    struct Rec {
+        void*   fOwner;
+        float   fStartX, fStartY;
+        float   fPrevX, fPrevY;
+        float   fLastX, fLastY;
+        float   fPrevT, fLastT;
+    };
+    SkTDArray<Rec> fTouches;
+
+    State           fState;
+    SkMatrix        fLocalM, fGlobalM, fPreTouchM;
+
+    struct FlingState {
+        FlingState() : fActive(false) {}
+
+        bool isActive() const { return fActive; }
+        void stop() { fActive = false; }
+
+        void reset(float sx, float sy);
+        bool evaluateMatrix(SkMatrix* matrix);
+
+        void get(SkPoint* dir, SkScalar* speed) {
+            *dir = fDirection;
+            *speed = fSpeed0;
+        }
+
+    private:
+        SkPoint     fDirection;
+        SkScalar    fSpeed0;
+        double      fTime0;
+        bool        fActive;
+    };
+    FlingState      fFlinger;
+    double          fLastUpMillis;
+    SkPoint         fLastUpP;
+
+    // The following rects are used to limit the translation so the content never leaves the window
+    SkRect          fContentRect, fWindowRect;
+    bool            fIsTransLimited = false;
+
+    void limitTrans(); // here we only limit the translation with respect to globalM
+    void flushLocalM();
+    int findRec(void* owner) const;
+    void appendNewRec(void* owner, float x, float y);
+    float computePinch(const Rec&, const Rec&);
+    float limitTotalZoom(float scale) const;
+    bool handleDblTap(float, float);
+};
+
+#endif
diff --git a/src/third_party/skia/tools/viewer/Viewer.cpp b/src/third_party/skia/tools/viewer/Viewer.cpp
index 6753b6b..f02f5b9 100644
--- a/src/third_party/skia/tools/viewer/Viewer.cpp
+++ b/src/third_party/skia/tools/viewer/Viewer.cpp
@@ -5,179 +5,169 @@
 * found in the LICENSE file.
 */
 
-#include "Viewer.h"
-
-#include "GMSlide.h"
-#include "ImageSlide.h"
-#include "Resources.h"
-#include "SampleSlide.h"
-#include "SKPSlide.h"
-
-#include "GrContext.h"
-#include "SkATrace.h"
-#include "SkCanvas.h"
-#include "SkColorSpace_Base.h"
-#include "SkColorSpaceXformCanvas.h"
-#include "SkCommandLineFlags.h"
-#include "SkCommonFlagsPathRenderer.h"
-#include "SkDashPathEffect.h"
-#include "SkGraphics.h"
-#include "SkImagePriv.h"
-#include "SkMetaData.h"
-#include "SkOnce.h"
-#include "SkOSFile.h"
-#include "SkOSPath.h"
-#include "SkRandom.h"
-#include "SkStream.h"
-#include "SkSurface.h"
-#include "SkSwizzle.h"
-#include "SkTaskGroup.h"
-#include "SkTime.h"
-#include "SkVertices.h"
-
-#include "imgui.h"
-
-#include "ccpr/GrCoverageCountingPathRenderer.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkData.h"
+#include "include/core/SkGraphics.h"
+#include "include/core/SkPictureRecorder.h"
+#include "include/core/SkStream.h"
+#include "include/core/SkSurface.h"
+#include "include/gpu/GrContext.h"
+#include "include/private/SkTo.h"
+#include "include/utils/SkPaintFilterCanvas.h"
+#include "src/core/SkColorSpacePriv.h"
+#include "src/core/SkImagePriv.h"
+#include "src/core/SkMD5.h"
+#include "src/core/SkMakeUnique.h"
+#include "src/core/SkOSFile.h"
+#include "src/core/SkScan.h"
+#include "src/core/SkTaskGroup.h"
+#include "src/gpu/GrContextPriv.h"
+#include "src/gpu/GrGpu.h"
+#include "src/gpu/GrPersistentCacheUtils.h"
+#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
+#include "src/utils/SkJSONWriter.h"
+#include "src/utils/SkOSPath.h"
+#include "tools/Resources.h"
+#include "tools/ToolUtils.h"
+#include "tools/flags/CommandLineFlags.h"
+#include "tools/flags/CommonFlags.h"
+#include "tools/trace/EventTracingPriv.h"
+#include "tools/viewer/BisectSlide.h"
+#include "tools/viewer/GMSlide.h"
+#include "tools/viewer/ImageSlide.h"
+#include "tools/viewer/ParticlesSlide.h"
+#include "tools/viewer/SKPSlide.h"
+#include "tools/viewer/SampleSlide.h"
+#include "tools/viewer/SlideDir.h"
+#include "tools/viewer/SvgSlide.h"
+#include "tools/viewer/Viewer.h"
 
 #include <stdlib.h>
 #include <map>
 
+#include "imgui.h"
+#include "misc/cpp/imgui_stdlib.h"  // For ImGui support of std::string
+
+#if defined(SK_ENABLE_SKOTTIE)
+    #include "tools/viewer/SkottieSlide.h"
+#endif
+
+class CapturingShaderErrorHandler : public GrContextOptions::ShaderErrorHandler {
+public:
+    void compileError(const char* shader, const char* errors) override {
+        fShaders.push_back(SkString(shader));
+        fErrors.push_back(SkString(errors));
+    }
+
+    void reset() {
+        fShaders.reset();
+        fErrors.reset();
+    }
+
+    SkTArray<SkString> fShaders;
+    SkTArray<SkString> fErrors;
+};
+
+static CapturingShaderErrorHandler gShaderErrorHandler;
+
 using namespace sk_app;
 
-using GpuPathRenderers = GrContextOptions::GpuPathRenderers;
 static std::map<GpuPathRenderers, std::string> gPathRendererNames;
 
 Application* Application::Create(int argc, char** argv, void* platformData) {
     return new Viewer(argc, argv, platformData);
 }
 
-static void on_backend_created_func(void* userData) {
-    Viewer* vv = reinterpret_cast<Viewer*>(userData);
+static DEFINE_string(slide, "", "Start on this sample.");
+static DEFINE_bool(list, false, "List samples?");
 
-    return vv->onBackendCreated();
-}
-
-static void on_paint_handler(SkCanvas* canvas, void* userData) {
-    Viewer* vv = reinterpret_cast<Viewer*>(userData);
-
-    return vv->onPaint(canvas);
-}
-
-static bool on_touch_handler(intptr_t owner, Window::InputState state, float x, float y, void* userData)
-{
-    Viewer* viewer = reinterpret_cast<Viewer*>(userData);
-
-    return viewer->onTouch(owner, state, x, y);
-}
-
-static void on_ui_state_changed_handler(const SkString& stateName, const SkString& stateValue, void* userData) {
-    Viewer* viewer = reinterpret_cast<Viewer*>(userData);
-
-    return viewer->onUIStateChanged(stateName, stateValue);
-}
-
-static bool on_mouse_handler(int x, int y, Window::InputState state, uint32_t modifiers,
-                             void* userData) {
-    ImGuiIO& io = ImGui::GetIO();
-    io.MousePos.x = static_cast<float>(x);
-    io.MousePos.y = static_cast<float>(y);
-    if (Window::kDown_InputState == state) {
-        io.MouseDown[0] = true;
-    } else if (Window::kUp_InputState == state) {
-        io.MouseDown[0] = false;
-    }
-    if (io.WantCaptureMouse) {
-        return true;
-    } else {
-        Viewer* viewer = reinterpret_cast<Viewer*>(userData);
-        return viewer->onMouse(x, y, state, modifiers);
-    }
-}
-
-static bool on_mouse_wheel_handler(float delta, uint32_t modifiers, void* userData) {
-    ImGuiIO& io = ImGui::GetIO();
-    io.MouseWheel += delta;
-    return true;
-}
-
-static bool on_key_handler(Window::Key key, Window::InputState state, uint32_t modifiers,
-                           void* userData) {
-    ImGuiIO& io = ImGui::GetIO();
-    io.KeysDown[static_cast<int>(key)] = (Window::kDown_InputState == state);
-
-    if (io.WantCaptureKeyboard) {
-        return true;
-    } else {
-        Viewer* viewer = reinterpret_cast<Viewer*>(userData);
-        return viewer->onKey(key, state, modifiers);
-    }
-}
-
-static bool on_char_handler(SkUnichar c, uint32_t modifiers, void* userData) {
-    ImGuiIO& io = ImGui::GetIO();
-    if (io.WantTextInput) {
-        if (c > 0 && c < 0x10000) {
-            io.AddInputCharacter(c);
-        }
-        return true;
-    } else {
-        Viewer* viewer = reinterpret_cast<Viewer*>(userData);
-        return viewer->onChar(c, modifiers);
-    }
-}
-
-static DEFINE_bool2(fullscreen, f, true, "Run fullscreen.");
-
-static DEFINE_string2(match, m, nullptr,
-               "[~][^]substring[$] [...] of bench name to run.\n"
-               "Multiple matches may be separated by spaces.\n"
-               "~ causes a matching bench to always be skipped\n"
-               "^ requires the start of the bench to match\n"
-               "$ requires the end of the bench to match\n"
-               "^ and $ requires an exact match\n"
-               "If a bench does not match any list entry,\n"
-               "it is skipped unless some list entry starts with ~");
-
-DEFINE_string(slide, "", "Start on this sample.");
-DEFINE_bool(list, false, "List samples?");
-
-#ifdef SK_VULKAN
+#if defined(SK_VULKAN)
 #    define BACKENDS_STR "\"sw\", \"gl\", and \"vk\""
+#elif defined(SK_METAL) && defined(SK_BUILD_FOR_MAC)
+#    define BACKENDS_STR "\"sw\", \"gl\", and \"mtl\""
+#elif defined(SK_DAWN)
+#    define BACKENDS_STR "\"sw\", \"gl\", and \"dawn\""
 #else
 #    define BACKENDS_STR "\"sw\" and \"gl\""
 #endif
 
-#ifdef SK_BUILD_FOR_ANDROID
-static DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
-static DEFINE_string(jpgs, "/data/local/tmp/resources", "Directory to read jpgs from.");
-#else
-static DEFINE_string(skps, "skps", "Directory to read skps from.");
-static DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
-#endif
-
 static DEFINE_string2(backend, b, "sw", "Backend to use. Allowed values are " BACKENDS_STR ".");
 
-static DEFINE_bool(atrace, false, "Enable support for using ATrace. ATrace is only supported on Android.");
+static DEFINE_int(msaa, 1, "Number of subpixel samples. 0 for no HW antialiasing.");
 
-DEFINE_int32(msaa, 0, "Number of subpixel samples. 0 for no HW antialiasing.");
-DEFINE_pathrenderer_flag;
+static DEFINE_int(internalSamples, 4,
+                  "Number of samples for internal draws that use MSAA or mixed samples.");
 
-DEFINE_bool(instancedRendering, false, "Enable instanced rendering on GPU backends.");
+static DEFINE_string(bisect, "", "Path to a .skp or .svg file to bisect.");
 
-const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
+static DEFINE_string2(file, f, "", "Open a single file for viewing.");
+
+static DEFINE_string2(match, m, nullptr,
+               "[~][^]substring[$] [...] of name to run.\n"
+               "Multiple matches may be separated by spaces.\n"
+               "~ causes a matching name to always be skipped\n"
+               "^ requires the start of the name to match\n"
+               "$ requires the end of the name to match\n"
+               "^ and $ requires an exact match\n"
+               "If a name does not match any list entry,\n"
+               "it is skipped unless some list entry starts with ~");
+
+#if defined(SK_BUILD_FOR_ANDROID)
+    static DEFINE_string(jpgs, "/data/local/tmp/resources", "Directory to read jpgs from.");
+    static DEFINE_string(skps, "/data/local/tmp/skps", "Directory to read skps from.");
+    static DEFINE_string(lotties, "/data/local/tmp/lotties",
+                         "Directory to read (Bodymovin) jsons from.");
+#else
+    static DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
+    static DEFINE_string(skps, "skps", "Directory to read skps from.");
+    static DEFINE_string(lotties, "lotties", "Directory to read (Bodymovin) jsons from.");
+#endif
+
+static DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file.");
+
+static DEFINE_int_2(threads, j, -1,
+               "Run threadsafe tests on a threadpool with this many extra threads, "
+               "defaulting to one extra thread per core.");
+
+
+const char* kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
     "OpenGL",
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+    "ANGLE",
+#endif
+#ifdef SK_DAWN
+    "Dawn",
+#endif
 #ifdef SK_VULKAN
     "Vulkan",
 #endif
+#ifdef SK_METAL
+    "Metal",
+#endif
     "Raster"
 };
 
 static sk_app::Window::BackendType get_backend_type(const char* str) {
+#ifdef SK_DAWN
+    if (0 == strcmp(str, "dawn")) {
+        return sk_app::Window::kDawn_BackendType;
+    } else
+#endif
 #ifdef SK_VULKAN
     if (0 == strcmp(str, "vk")) {
         return sk_app::Window::kVulkan_BackendType;
     } else
 #endif
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+    if (0 == strcmp(str, "angle")) {
+        return sk_app::Window::kANGLE_BackendType;
+    } else
+#endif
+#ifdef SK_METAL
+    if (0 == strcmp(str, "mtl")) {
+        return sk_app::Window::kMetal_BackendType;
+    } else
+#endif
     if (0 == strcmp(str, "gl")) {
         return sk_app::Window::kNativeGL_BackendType;
     } else if (0 == strcmp(str, "sw")) {
@@ -226,6 +216,22 @@
     return memcmp(&a, &b, sizeof(SkColorSpacePrimaries)) == 0;
 }
 
+static Window::BackendType backend_type_for_window(Window::BackendType backendType) {
+    // In raster mode, we still use GL for the window.
+    // This lets us render the GUI faster (and correct).
+    return Window::kRaster_BackendType == backendType ? Window::kNativeGL_BackendType : backendType;
+}
+
+class NullSlide : public Slide {
+    SkISize getDimensions() const override {
+        return SkISize::Make(640, 480);
+    }
+
+    void draw(SkCanvas* canvas) override {
+        canvas->clear(0xffff11ff);
+    }
+};
+
 const char* kName = "name";
 const char* kValue = "value";
 const char* kOptions = "options";
@@ -233,7 +239,6 @@
 const char* kBackendStateName = "Backend";
 const char* kMSAAStateName = "MSAA";
 const char* kPathRendererStateName = "Path renderer";
-const char* kInstancedRenderingStateName = "Instanced rendering";
 const char* kSoftkeyStateName = "Softkey";
 const char* kSoftkeyHint = "Please select a softkey";
 const char* kFpsStateName = "FPS";
@@ -242,37 +247,40 @@
 const char* kRefreshStateName = "Refresh";
 
 Viewer::Viewer(int argc, char** argv, void* platformData)
-    : fCurrentMeasurement(0)
-    , fDisplayStats(false)
+    : fCurrentSlide(-1)
     , fRefresh(false)
+    , fSaveToSKP(false)
+    , fShowSlideDimensions(false)
     , fShowImGuiDebugWindow(false)
+    , fShowSlidePicker(false)
     , fShowImGuiTestWindow(false)
     , fShowZoomWindow(false)
+    , fZoomWindowFixed(false)
+    , fZoomWindowLocation{0.0f, 0.0f}
     , fLastImage(nullptr)
+    , fZoomUI(false)
     , fBackendType(sk_app::Window::kNativeGL_BackendType)
     , fColorMode(ColorMode::kLegacy)
     , fColorSpacePrimaries(gSrgbPrimaries)
+    // Our UI can only tweak gamma (currently), so start out gamma-only
+    , fColorSpaceTransferFn(SkNamedTransferFn::k2Dot2)
     , fZoomLevel(0.0f)
+    , fRotation(0.0f)
+    , fOffset{0.5f, 0.5f}
     , fGestureDevice(GestureDevice::kNone)
+    , fTiled(false)
+    , fDrawTileBoundaries(false)
+    , fTileScale{0.25f, 0.25f}
+    , fPerspectiveMode(kPerspective_Off)
 {
-    static SkTaskGroup::Enabler kTaskGroupEnabler;
     SkGraphics::Init();
 
-    static SkOnce initPathRendererNames;
-    initPathRendererNames([]() {
-        gPathRendererNames[GpuPathRenderers::kAll] = "Default Ganesh Behavior (best path renderer)";
-        gPathRendererNames[GpuPathRenderers::kStencilAndCover] = "NV_path_rendering";
-        gPathRendererNames[GpuPathRenderers::kMSAA] = "Sample shading";
-        gPathRendererNames[GpuPathRenderers::kSmall] = "Small paths (cached sdf or alpha masks)";
-        gPathRendererNames[GpuPathRenderers::kCoverageCounting] = "Coverage counting";
-        gPathRendererNames[GpuPathRenderers::kTessellating] = "Tessellating";
-        gPathRendererNames[GpuPathRenderers::kDefault] = "Original Ganesh path renderer";
-        gPathRendererNames[GpuPathRenderers::kNone] = "Software masks";
-    });
-
-    memset(fPaintTimes, 0, sizeof(fPaintTimes));
-    memset(fFlushTimes, 0, sizeof(fFlushTimes));
-    memset(fAnimateTimes, 0, sizeof(fAnimateTimes));
+    gPathRendererNames[GpuPathRenderers::kAll] = "All Path Renderers";
+    gPathRendererNames[GpuPathRenderers::kStencilAndCover] = "NV_path_rendering";
+    gPathRendererNames[GpuPathRenderers::kSmall] = "Small paths (cached sdf or alpha masks)";
+    gPathRendererNames[GpuPathRenderers::kCoverageCounting] = "CCPR";
+    gPathRendererNames[GpuPathRenderers::kTessellating] = "Tessellating";
+    gPathRendererNames[GpuPathRenderers::kNone] = "Software masks";
 
     SkDebugf("Command line arguments: ");
     for (int i = 1; i < argc; ++i) {
@@ -280,40 +288,59 @@
     }
     SkDebugf("\n");
 
-    SkCommandLineFlags::Parse(argc, argv);
+    CommandLineFlags::Parse(argc, argv);
 #ifdef SK_BUILD_FOR_ANDROID
     SetResourcePath("/data/local/tmp/resources");
 #endif
 
-    if (FLAGS_atrace) {
-        SkAssertResult(SkEventTracer::SetInstance(new SkATrace()));
-    }
+    ToolUtils::SetDefaultFontMgr();
+
+    initializeEventTracingForTools();
+    static SkTaskGroup::Enabler kTaskGroupEnabler(FLAGS_threads);
 
     fBackendType = get_backend_type(FLAGS_backend[0]);
     fWindow = Window::CreateNativeWindow(platformData);
 
     DisplayParams displayParams;
     displayParams.fMSAASampleCount = FLAGS_msaa;
-    displayParams.fGrContextOptions.fEnableInstancedRendering = FLAGS_instancedRendering;
-    displayParams.fGrContextOptions.fGpuPathRenderers = CollectGpuPathRenderersFromFlags();
+    SetCtxOptionsFromCommonFlags(&displayParams.fGrContextOptions);
+    displayParams.fGrContextOptions.fPersistentCache = &fPersistentCache;
+    displayParams.fGrContextOptions.fShaderCacheStrategy =
+            GrContextOptions::ShaderCacheStrategy::kBackendSource;
+    displayParams.fGrContextOptions.fShaderErrorHandler = &gShaderErrorHandler;
+    displayParams.fGrContextOptions.fSuppressPrints = true;
+    displayParams.fGrContextOptions.fInternalMultisampleCount = FLAGS_internalSamples;
     fWindow->setRequestedDisplayParams(displayParams);
 
+    // Configure timers
+    fStatsLayer.setActive(false);
+    fAnimateTimer = fStatsLayer.addTimer("Animate", SK_ColorMAGENTA, 0xffff66ff);
+    fPaintTimer = fStatsLayer.addTimer("Paint", SK_ColorGREEN);
+    fFlushTimer = fStatsLayer.addTimer("Flush", SK_ColorRED, 0xffff6666);
+
     // register callbacks
     fCommands.attach(fWindow);
-    fWindow->registerBackendCreatedFunc(on_backend_created_func, this);
-    fWindow->registerPaintFunc(on_paint_handler, this);
-    fWindow->registerTouchFunc(on_touch_handler, this);
-    fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this);
-    fWindow->registerMouseFunc(on_mouse_handler, this);
-    fWindow->registerMouseWheelFunc(on_mouse_wheel_handler, this);
-    fWindow->registerKeyFunc(on_key_handler, this);
-    fWindow->registerCharFunc(on_char_handler, this);
+    fWindow->pushLayer(this);
+    fWindow->pushLayer(&fStatsLayer);
+    fWindow->pushLayer(&fImGuiLayer);
 
     // add key-bindings
     fCommands.addCommand(' ', "GUI", "Toggle Debug GUI", [this]() {
         this->fShowImGuiDebugWindow = !this->fShowImGuiDebugWindow;
         fWindow->inval();
     });
+    // Command to jump directly to the slide picker and give it focus
+    fCommands.addCommand('/', "GUI", "Jump to slide picker", [this]() {
+        this->fShowImGuiDebugWindow = true;
+        this->fShowSlidePicker = true;
+        fWindow->inval();
+    });
+    // Alias that to Backspace, to match SampleApp
+    fCommands.addCommand(skui::Key::kBack, "Backspace", "GUI", "Jump to slide picker", [this]() {
+        this->fShowImGuiDebugWindow = true;
+        this->fShowSlidePicker = true;
+        fWindow->inval();
+    });
     fCommands.addCommand('g', "GUI", "Toggle GUI Demo", [this]() {
         this->fShowImGuiTestWindow = !this->fShowImGuiTestWindow;
         fWindow->inval();
@@ -322,208 +349,405 @@
         this->fShowZoomWindow = !this->fShowZoomWindow;
         fWindow->inval();
     });
+    fCommands.addCommand('Z', "GUI", "Toggle zoom window state", [this]() {
+        this->fZoomWindowFixed = !this->fZoomWindowFixed;
+        fWindow->inval();
+    });
+    fCommands.addCommand('v', "VSync", "Toggle vsync on/off", [this]() {
+        DisplayParams params = fWindow->getRequestedDisplayParams();
+        params.fDisableVsync = !params.fDisableVsync;
+        fWindow->setRequestedDisplayParams(params);
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('r', "Redraw", "Toggle redraw", [this]() {
+        fRefresh = !fRefresh;
+        fWindow->inval();
+    });
     fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() {
-        this->fDisplayStats = !this->fDisplayStats;
+        fStatsLayer.setActive(!fStatsLayer.getActive());
+        fWindow->inval();
+    });
+    fCommands.addCommand('0', "Overlays", "Reset stats", [this]() {
+        fStatsLayer.resetMeasurements();
+        this->updateTitle();
         fWindow->inval();
     });
     fCommands.addCommand('c', "Modes", "Cycle color mode", [this]() {
         switch (fColorMode) {
             case ColorMode::kLegacy:
-                this->setColorMode(ColorMode::kColorManagedSRGB8888_NonLinearBlending);
+                this->setColorMode(ColorMode::kColorManaged8888);
                 break;
-            case ColorMode::kColorManagedSRGB8888_NonLinearBlending:
-                this->setColorMode(ColorMode::kColorManagedSRGB8888);
+            case ColorMode::kColorManaged8888:
+                this->setColorMode(ColorMode::kColorManagedF16);
                 break;
-            case ColorMode::kColorManagedSRGB8888:
-                this->setColorMode(ColorMode::kColorManagedLinearF16);
+            case ColorMode::kColorManagedF16:
+                this->setColorMode(ColorMode::kColorManagedF16Norm);
                 break;
-            case ColorMode::kColorManagedLinearF16:
+            case ColorMode::kColorManagedF16Norm:
                 this->setColorMode(ColorMode::kLegacy);
                 break;
         }
     });
-    fCommands.addCommand(Window::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
-        int previousSlide = fCurrentSlide;
-        fCurrentSlide++;
-        if (fCurrentSlide >= fSlides.count()) {
-            fCurrentSlide = 0;
-        }
-        this->setupCurrentSlide(previousSlide);
+    fCommands.addCommand(skui::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
+        this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ? fCurrentSlide + 1 : 0);
     });
-    fCommands.addCommand(Window::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
-        int previousSlide = fCurrentSlide;
-        fCurrentSlide--;
-        if (fCurrentSlide < 0) {
-            fCurrentSlide = fSlides.count() - 1;
-        }
-        this->setupCurrentSlide(previousSlide);
+    fCommands.addCommand(skui::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
+        this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.count() - 1);
     });
-    fCommands.addCommand(Window::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
+    fCommands.addCommand(skui::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
         this->changeZoomLevel(1.f / 32.f);
         fWindow->inval();
     });
-    fCommands.addCommand(Window::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
+    fCommands.addCommand(skui::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
         this->changeZoomLevel(-1.f / 32.f);
         fWindow->inval();
     });
     fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() {
-        sk_app::Window::BackendType newBackend = fBackendType;
-#if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
-        if (sk_app::Window::kRaster_BackendType == fBackendType) {
-            newBackend = sk_app::Window::kNativeGL_BackendType;
-#ifdef SK_VULKAN
-        } else if (sk_app::Window::kNativeGL_BackendType == fBackendType) {
-            newBackend = sk_app::Window::kVulkan_BackendType;
-#endif
-        } else {
-            newBackend = sk_app::Window::kRaster_BackendType;
-        }
-#elif defined(SK_BUILD_FOR_UNIX)
+        sk_app::Window::BackendType newBackend = (sk_app::Window::BackendType)(
+                (fBackendType + 1) % sk_app::Window::kBackendTypeCount);
         // Switching to and from Vulkan is problematic on Linux so disabled for now
-        if (sk_app::Window::kRaster_BackendType == fBackendType) {
-            newBackend = sk_app::Window::kNativeGL_BackendType;
-        } else if (sk_app::Window::kNativeGL_BackendType == fBackendType) {
-            newBackend = sk_app::Window::kRaster_BackendType;
+#if defined(SK_BUILD_FOR_UNIX) && defined(SK_VULKAN)
+        if (newBackend == sk_app::Window::kVulkan_BackendType) {
+            newBackend = (sk_app::Window::BackendType)((newBackend + 1) %
+                                                       sk_app::Window::kBackendTypeCount);
+        } else if (fBackendType == sk_app::Window::kVulkan_BackendType) {
+            newBackend = sk_app::Window::kVulkan_BackendType;
         }
 #endif
-
         this->setBackend(newBackend);
     });
+    fCommands.addCommand('K', "IO", "Save slide to SKP", [this]() {
+        fSaveToSKP = true;
+        fWindow->inval();
+    });
+    fCommands.addCommand('&', "Overlays", "Show slide dimensios", [this]() {
+        fShowSlideDimensions = !fShowSlideDimensions;
+        fWindow->inval();
+    });
+    fCommands.addCommand('G', "Modes", "Geometry", [this]() {
+        DisplayParams params = fWindow->getRequestedDisplayParams();
+        uint32_t flags = params.fSurfaceProps.flags();
+        if (!fPixelGeometryOverrides) {
+            fPixelGeometryOverrides = true;
+            params.fSurfaceProps = SkSurfaceProps(flags, kUnknown_SkPixelGeometry);
+        } else {
+            switch (params.fSurfaceProps.pixelGeometry()) {
+                case kUnknown_SkPixelGeometry:
+                    params.fSurfaceProps = SkSurfaceProps(flags, kRGB_H_SkPixelGeometry);
+                    break;
+                case kRGB_H_SkPixelGeometry:
+                    params.fSurfaceProps = SkSurfaceProps(flags, kBGR_H_SkPixelGeometry);
+                    break;
+                case kBGR_H_SkPixelGeometry:
+                    params.fSurfaceProps = SkSurfaceProps(flags, kRGB_V_SkPixelGeometry);
+                    break;
+                case kRGB_V_SkPixelGeometry:
+                    params.fSurfaceProps = SkSurfaceProps(flags, kBGR_V_SkPixelGeometry);
+                    break;
+                case kBGR_V_SkPixelGeometry:
+                    params.fSurfaceProps = SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+                    fPixelGeometryOverrides = false;
+                    break;
+            }
+        }
+        fWindow->setRequestedDisplayParams(params);
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('H', "Font", "Hinting mode", [this]() {
+        if (!fFontOverrides.fHinting) {
+            fFontOverrides.fHinting = true;
+            fFont.setHinting(SkFontHinting::kNone);
+        } else {
+            switch (fFont.getHinting()) {
+                case SkFontHinting::kNone:
+                    fFont.setHinting(SkFontHinting::kSlight);
+                    break;
+                case SkFontHinting::kSlight:
+                    fFont.setHinting(SkFontHinting::kNormal);
+                    break;
+                case SkFontHinting::kNormal:
+                    fFont.setHinting(SkFontHinting::kFull);
+                    break;
+                case SkFontHinting::kFull:
+                    fFont.setHinting(SkFontHinting::kNone);
+                    fFontOverrides.fHinting = false;
+                    break;
+            }
+        }
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('A', "Paint", "Antialias Mode", [this]() {
+        if (!fPaintOverrides.fAntiAlias) {
+            fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias;
+            fPaintOverrides.fAntiAlias = true;
+            fPaint.setAntiAlias(false);
+            gSkUseAnalyticAA = gSkForceAnalyticAA = false;
+        } else {
+            fPaint.setAntiAlias(true);
+            switch (fPaintOverrides.fAntiAliasState) {
+                case SkPaintFields::AntiAliasState::Alias:
+                    fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Normal;
+                    gSkUseAnalyticAA = gSkForceAnalyticAA = false;
+                    break;
+                case SkPaintFields::AntiAliasState::Normal:
+                    fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::AnalyticAAEnabled;
+                    gSkUseAnalyticAA = true;
+                    gSkForceAnalyticAA = false;
+                    break;
+                case SkPaintFields::AntiAliasState::AnalyticAAEnabled:
+                    fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::AnalyticAAForced;
+                    gSkUseAnalyticAA = gSkForceAnalyticAA = true;
+                    break;
+                case SkPaintFields::AntiAliasState::AnalyticAAForced:
+                    fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias;
+                    fPaintOverrides.fAntiAlias = false;
+                    gSkUseAnalyticAA = fPaintOverrides.fOriginalSkUseAnalyticAA;
+                    gSkForceAnalyticAA = fPaintOverrides.fOriginalSkForceAnalyticAA;
+                    break;
+            }
+        }
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('D', "Modes", "DFT", [this]() {
+        DisplayParams params = fWindow->getRequestedDisplayParams();
+        uint32_t flags = params.fSurfaceProps.flags();
+        flags ^= SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
+        params.fSurfaceProps = SkSurfaceProps(flags, params.fSurfaceProps.pixelGeometry());
+        fWindow->setRequestedDisplayParams(params);
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('L', "Font", "Subpixel Antialias Mode", [this]() {
+        if (!fFontOverrides.fEdging) {
+            fFontOverrides.fEdging = true;
+            fFont.setEdging(SkFont::Edging::kAlias);
+        } else {
+            switch (fFont.getEdging()) {
+                case SkFont::Edging::kAlias:
+                    fFont.setEdging(SkFont::Edging::kAntiAlias);
+                    break;
+                case SkFont::Edging::kAntiAlias:
+                    fFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);
+                    break;
+                case SkFont::Edging::kSubpixelAntiAlias:
+                    fFont.setEdging(SkFont::Edging::kAlias);
+                    fFontOverrides.fEdging = false;
+                    break;
+            }
+        }
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('S', "Font", "Subpixel Position Mode", [this]() {
+        if (!fFontOverrides.fSubpixel) {
+            fFontOverrides.fSubpixel = true;
+            fFont.setSubpixel(false);
+        } else {
+            if (!fFont.isSubpixel()) {
+                fFont.setSubpixel(true);
+            } else {
+                fFontOverrides.fSubpixel = false;
+            }
+        }
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('B', "Font", "Baseline Snapping", [this]() {
+        if (!fFontOverrides.fBaselineSnap) {
+            fFontOverrides.fBaselineSnap = true;
+            fFont.setBaselineSnap(false);
+        } else {
+            if (!fFont.isBaselineSnap()) {
+                fFont.setBaselineSnap(true);
+            } else {
+                fFontOverrides.fBaselineSnap = false;
+            }
+        }
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('p', "Transform", "Toggle Perspective Mode", [this]() {
+        fPerspectiveMode = (kPerspective_Real == fPerspectiveMode) ? kPerspective_Fake
+                                                                   : kPerspective_Real;
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('P', "Transform", "Toggle Perspective", [this]() {
+        fPerspectiveMode = (kPerspective_Off == fPerspectiveMode) ? kPerspective_Real
+                                                                  : kPerspective_Off;
+        this->updateTitle();
+        fWindow->inval();
+    });
+    fCommands.addCommand('a', "Transform", "Toggle Animation", [this]() {
+        fAnimTimer.togglePauseResume();
+    });
+    fCommands.addCommand('u', "GUI", "Zoom UI", [this]() {
+        fZoomUI = !fZoomUI;
+        fStatsLayer.setDisplayScale(fZoomUI ? 2.0f : 1.0f);
+        fWindow->inval();
+    });
 
     // set up slides
     this->initSlides();
-    this->setStartupSlide();
     if (FLAGS_list) {
         this->listNames();
     }
 
+    fPerspectivePoints[0].set(0, 0);
+    fPerspectivePoints[1].set(1, 0);
+    fPerspectivePoints[2].set(0, 1);
+    fPerspectivePoints[3].set(1, 1);
     fAnimTimer.run();
 
-    // ImGui initialization:
-    ImGuiIO& io = ImGui::GetIO();
-    io.DisplaySize.x = static_cast<float>(fWindow->width());
-    io.DisplaySize.y = static_cast<float>(fWindow->height());
-
-    // Keymap...
-    io.KeyMap[ImGuiKey_Tab] = (int)Window::Key::kTab;
-    io.KeyMap[ImGuiKey_LeftArrow] = (int)Window::Key::kLeft;
-    io.KeyMap[ImGuiKey_RightArrow] = (int)Window::Key::kRight;
-    io.KeyMap[ImGuiKey_UpArrow] = (int)Window::Key::kUp;
-    io.KeyMap[ImGuiKey_DownArrow] = (int)Window::Key::kDown;
-    io.KeyMap[ImGuiKey_PageUp] = (int)Window::Key::kPageUp;
-    io.KeyMap[ImGuiKey_PageDown] = (int)Window::Key::kPageDown;
-    io.KeyMap[ImGuiKey_Home] = (int)Window::Key::kHome;
-    io.KeyMap[ImGuiKey_End] = (int)Window::Key::kEnd;
-    io.KeyMap[ImGuiKey_Delete] = (int)Window::Key::kDelete;
-    io.KeyMap[ImGuiKey_Backspace] = (int)Window::Key::kBack;
-    io.KeyMap[ImGuiKey_Enter] = (int)Window::Key::kOK;
-    io.KeyMap[ImGuiKey_Escape] = (int)Window::Key::kEscape;
-    io.KeyMap[ImGuiKey_A] = (int)Window::Key::kA;
-    io.KeyMap[ImGuiKey_C] = (int)Window::Key::kC;
-    io.KeyMap[ImGuiKey_V] = (int)Window::Key::kV;
-    io.KeyMap[ImGuiKey_X] = (int)Window::Key::kX;
-    io.KeyMap[ImGuiKey_Y] = (int)Window::Key::kY;
-    io.KeyMap[ImGuiKey_Z] = (int)Window::Key::kZ;
-
-    int w, h;
-    unsigned char* pixels;
-    io.Fonts->GetTexDataAsAlpha8(&pixels, &w, &h);
-    SkImageInfo info = SkImageInfo::MakeA8(w, h);
-    SkPixmap pmap(info, pixels, info.minRowBytes());
-    SkMatrix localMatrix = SkMatrix::MakeScale(1.0f / w, 1.0f / h);
-    auto fontImage = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
-    auto fontShader = fontImage->makeShader(&localMatrix);
-    fImGuiFontPaint.setShader(fontShader);
-    fImGuiFontPaint.setColor(SK_ColorWHITE);
-    fImGuiFontPaint.setFilterQuality(kLow_SkFilterQuality);
-    io.Fonts->TexID = &fImGuiFontPaint;
-
-    auto gamutImage = GetResourceAsImage("gamut.png");
+    auto gamutImage = GetResourceAsImage("images/gamut.png");
     if (gamutImage) {
         fImGuiGamutPaint.setShader(gamutImage->makeShader());
     }
     fImGuiGamutPaint.setColor(SK_ColorWHITE);
     fImGuiGamutPaint.setFilterQuality(kLow_SkFilterQuality);
 
-    fWindow->attach(fBackendType);
+    fWindow->attach(backend_type_for_window(fBackendType));
+    this->setCurrentSlide(this->startupSlide());
 }
 
 void Viewer::initSlides() {
-    fAllSlideNames = Json::Value(Json::arrayValue);
+    using SlideFactory = sk_sp<Slide>(*)(const SkString& name, const SkString& path);
+    static const struct {
+        const char*                            fExtension;
+        const char*                            fDirName;
+        const CommandLineFlags::StringArray&   fFlags;
+        const SlideFactory                     fFactory;
+    } gExternalSlidesInfo[] = {
+        { ".skp", "skp-dir", FLAGS_skps,
+            [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+                return sk_make_sp<SKPSlide>(name, path);}
+        },
+        { ".jpg", "jpg-dir", FLAGS_jpgs,
+            [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+                return sk_make_sp<ImageSlide>(name, path);}
+        },
+#if defined(SK_ENABLE_SKOTTIE)
+        { ".json", "skottie-dir", FLAGS_lotties,
+            [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+                return sk_make_sp<SkottieSlide>(name, path);}
+        },
+#endif
+#if defined(SK_XML)
+        { ".svg", "svg-dir", FLAGS_svgs,
+            [](const SkString& name, const SkString& path) -> sk_sp<Slide> {
+                return sk_make_sp<SvgSlide>(name, path);}
+        },
+#endif
+    };
 
-    const skiagm::GMRegistry* gms(skiagm::GMRegistry::Head());
-    while (gms) {
-        std::unique_ptr<skiagm::GM> gm(gms->factory()(nullptr));
+    SkTArray<sk_sp<Slide>> dirSlides;
 
-        if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) {
-            sk_sp<Slide> slide(new GMSlide(gm.release()));
-            fSlides.push_back(slide);
+    const auto addSlide =
+            [&](const SkString& name, const SkString& path, const SlideFactory& fact) {
+                if (CommandLineFlags::ShouldSkip(FLAGS_match, name.c_str())) {
+                    return;
+                }
+
+                if (auto slide = fact(name, path)) {
+                    dirSlides.push_back(slide);
+                    fSlides.push_back(std::move(slide));
+                }
+            };
+
+    if (!FLAGS_file.isEmpty()) {
+        // single file mode
+        const SkString file(FLAGS_file[0]);
+
+        if (sk_exists(file.c_str(), kRead_SkFILE_Flag)) {
+            for (const auto& sinfo : gExternalSlidesInfo) {
+                if (file.endsWith(sinfo.fExtension)) {
+                    addSlide(SkOSPath::Basename(file.c_str()), file, sinfo.fFactory);
+                    return;
+                }
+            }
+
+            fprintf(stderr, "Unsupported file type \"%s\"\n", file.c_str());
+        } else {
+            fprintf(stderr, "Cannot read \"%s\"\n", file.c_str());
         }
 
-        gms = gms->next();
+        return;
     }
 
-    // reverse array
-    for (int i = 0; i < fSlides.count()/2; ++i) {
-        sk_sp<Slide> temp = fSlides[i];
-        fSlides[i] = fSlides[fSlides.count() - i - 1];
-        fSlides[fSlides.count() - i - 1] = temp;
+    // Bisect slide.
+    if (!FLAGS_bisect.isEmpty()) {
+        sk_sp<BisectSlide> bisect = BisectSlide::Create(FLAGS_bisect[0]);
+        if (bisect && !CommandLineFlags::ShouldSkip(FLAGS_match, bisect->getName().c_str())) {
+            if (FLAGS_bisect.count() >= 2) {
+                for (const char* ch = FLAGS_bisect[1]; *ch; ++ch) {
+                    bisect->onChar(*ch);
+                }
+            }
+            fSlides.push_back(std::move(bisect));
+        }
+    }
+
+    // GMs
+    int firstGM = fSlides.count();
+    for (skiagm::GMFactory gmFactory : skiagm::GMRegistry::Range()) {
+        std::unique_ptr<skiagm::GM> gm = gmFactory();
+        if (!CommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) {
+            sk_sp<Slide> slide(new GMSlide(std::move(gm)));
+            fSlides.push_back(std::move(slide));
+        }
+    }
+    // reverse gms
+    int numGMs = fSlides.count() - firstGM;
+    for (int i = 0; i < numGMs/2; ++i) {
+        std::swap(fSlides[firstGM + i], fSlides[fSlides.count() - i - 1]);
     }
 
     // samples
-    const SkViewRegister* reg = SkViewRegister::Head();
-    while (reg) {
-        sk_sp<Slide> slide(new SampleSlide(reg->factory()));
-        if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) {
+    for (const SampleFactory factory : SampleRegistry::Range()) {
+        sk_sp<Slide> slide(new SampleSlide(factory));
+        if (!CommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) {
             fSlides.push_back(slide);
         }
-        reg = reg->next();
     }
 
-    // SKPs
-    for (int i = 0; i < FLAGS_skps.count(); i++) {
-        if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
-            if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
-                continue;
-            }
+    // Particle demo
+    {
+        // TODO: Convert this to a sample
+        sk_sp<Slide> slide(new ParticlesSlide());
+        if (!CommandLineFlags::ShouldSkip(FLAGS_match, slide->getName().c_str())) {
+            fSlides.push_back(std::move(slide));
+        }
+    }
 
-            SkString path(FLAGS_skps[i]);
-            sk_sp<SKPSlide> slide(new SKPSlide(SkOSPath::Basename(path.c_str()), path));
-            if (slide) {
-                fSlides.push_back(slide);
+    for (const auto& info : gExternalSlidesInfo) {
+        for (const auto& flag : info.fFlags) {
+            if (SkStrEndsWith(flag.c_str(), info.fExtension)) {
+                // single file
+                addSlide(SkOSPath::Basename(flag.c_str()), flag, info.fFactory);
+            } else {
+                // directory
+                SkOSFile::Iter it(flag.c_str(), info.fExtension);
+                SkString name;
+                while (it.next(&name)) {
+                    addSlide(name, SkOSPath::Join(flag.c_str(), name.c_str()), info.fFactory);
+                }
             }
-        } else {
-            SkOSFile::Iter it(FLAGS_skps[i], ".skp");
-            SkString skpName;
-            while (it.next(&skpName)) {
-                if (SkCommandLineFlags::ShouldSkip(FLAGS_match, skpName.c_str())) {
-                    continue;
-                }
-
-                SkString path = SkOSPath::Join(FLAGS_skps[i], skpName.c_str());
-                sk_sp<SKPSlide> slide(new SKPSlide(skpName, path));
-                if (slide) {
-                    fSlides.push_back(slide);
-                }
+            if (!dirSlides.empty()) {
+                fSlides.push_back(
+                    sk_make_sp<SlideDir>(SkStringPrintf("%s[%s]", info.fDirName, flag.c_str()),
+                                         std::move(dirSlides)));
+                dirSlides.reset();  // NOLINT(bugprone-use-after-move)
             }
         }
     }
 
-    // JPGs
-    for (int i = 0; i < FLAGS_jpgs.count(); i++) {
-        SkOSFile::Iter it(FLAGS_jpgs[i], ".jpg");
-        SkString jpgName;
-        while (it.next(&jpgName)) {
-            if (SkCommandLineFlags::ShouldSkip(FLAGS_match, jpgName.c_str())) {
-                continue;
-            }
-
-            SkString path = SkOSPath::Join(FLAGS_jpgs[i], jpgName.c_str());
-            sk_sp<ImageSlide> slide(new ImageSlide(jpgName, path));
-            if (slide) {
-                fSlides.push_back(slide);
-            }
-        }
+    if (!fSlides.count()) {
+        sk_sp<Slide> slide(new NullSlide());
+        fSlides.push_back(std::move(slide));
     }
 }
 
@@ -533,30 +757,137 @@
     delete fWindow;
 }
 
+struct SkPaintTitleUpdater {
+    SkPaintTitleUpdater(SkString* title) : fTitle(title), fCount(0) {}
+    void append(const char* s) {
+        if (fCount == 0) {
+            fTitle->append(" {");
+        } else {
+            fTitle->append(", ");
+        }
+        fTitle->append(s);
+        ++fCount;
+    }
+    void done() {
+        if (fCount > 0) {
+            fTitle->append("}");
+        }
+    }
+    SkString* fTitle;
+    int fCount;
+};
+
 void Viewer::updateTitle() {
     if (!fWindow) {
         return;
     }
-    if (fWindow->sampleCount() < 0) {
+    if (fWindow->sampleCount() < 1) {
         return; // Surface hasn't been created yet.
     }
 
     SkString title("Viewer: ");
     title.append(fSlides[fCurrentSlide]->getName());
 
+    if (gSkUseAnalyticAA) {
+        if (gSkForceAnalyticAA) {
+            title.append(" <FAAA>");
+        } else {
+            title.append(" <AAA>");
+        }
+    }
+
+    SkPaintTitleUpdater paintTitle(&title);
+    auto paintFlag = [this, &paintTitle](bool SkPaintFields::* flag,
+                                         bool (SkPaint::* isFlag)() const,
+                                         const char* on, const char* off)
+    {
+        if (fPaintOverrides.*flag) {
+            paintTitle.append((fPaint.*isFlag)() ? on : off);
+        }
+    };
+
+    auto fontFlag = [this, &paintTitle](bool SkFontFields::* flag, bool (SkFont::* isFlag)() const,
+                                        const char* on, const char* off)
+    {
+        if (fFontOverrides.*flag) {
+            paintTitle.append((fFont.*isFlag)() ? on : off);
+        }
+    };
+
+    paintFlag(&SkPaintFields::fAntiAlias, &SkPaint::isAntiAlias, "Antialias", "Alias");
+    paintFlag(&SkPaintFields::fDither, &SkPaint::isDither, "DITHER", "No Dither");
+    if (fPaintOverrides.fFilterQuality) {
+        switch (fPaint.getFilterQuality()) {
+            case kNone_SkFilterQuality:
+                paintTitle.append("NoFilter");
+                break;
+            case kLow_SkFilterQuality:
+                paintTitle.append("LowFilter");
+                break;
+            case kMedium_SkFilterQuality:
+                paintTitle.append("MediumFilter");
+                break;
+            case kHigh_SkFilterQuality:
+                paintTitle.append("HighFilter");
+                break;
+        }
+    }
+
+    fontFlag(&SkFontFields::fForceAutoHinting, &SkFont::isForceAutoHinting,
+             "Force Autohint", "No Force Autohint");
+    fontFlag(&SkFontFields::fEmbolden, &SkFont::isEmbolden, "Fake Bold", "No Fake Bold");
+    fontFlag(&SkFontFields::fBaselineSnap, &SkFont::isBaselineSnap, "BaseSnap", "No BaseSnap");
+    fontFlag(&SkFontFields::fLinearMetrics, &SkFont::isLinearMetrics,
+             "Linear Metrics", "Non-Linear Metrics");
+    fontFlag(&SkFontFields::fEmbeddedBitmaps, &SkFont::isEmbeddedBitmaps,
+             "Bitmap Text", "No Bitmap Text");
+    fontFlag(&SkFontFields::fSubpixel, &SkFont::isSubpixel, "Subpixel Text", "Pixel Text");
+
+    if (fFontOverrides.fEdging) {
+        switch (fFont.getEdging()) {
+            case SkFont::Edging::kAlias:
+                paintTitle.append("Alias Text");
+                break;
+            case SkFont::Edging::kAntiAlias:
+                paintTitle.append("Antialias Text");
+                break;
+            case SkFont::Edging::kSubpixelAntiAlias:
+                paintTitle.append("Subpixel Antialias Text");
+                break;
+        }
+    }
+
+    if (fFontOverrides.fHinting) {
+        switch (fFont.getHinting()) {
+            case SkFontHinting::kNone:
+                paintTitle.append("No Hinting");
+                break;
+            case SkFontHinting::kSlight:
+                paintTitle.append("Slight Hinting");
+                break;
+            case SkFontHinting::kNormal:
+                paintTitle.append("Normal Hinting");
+                break;
+            case SkFontHinting::kFull:
+                paintTitle.append("Full Hinting");
+                break;
+        }
+    }
+    paintTitle.done();
+
     switch (fColorMode) {
         case ColorMode::kLegacy:
             title.append(" Legacy 8888");
             break;
-        case ColorMode::kColorManagedSRGB8888_NonLinearBlending:
-            title.append(" ColorManaged 8888 (Nonlinear blending)");
-            break;
-        case ColorMode::kColorManagedSRGB8888:
+        case ColorMode::kColorManaged8888:
             title.append(" ColorManaged 8888");
             break;
-        case ColorMode::kColorManagedLinearF16:
+        case ColorMode::kColorManagedF16:
             title.append(" ColorManaged F16");
             break;
+        case ColorMode::kColorManagedF16Norm:
+            title.append(" ColorManaged F16 Norm");
+            break;
     }
 
     if (ColorMode::kLegacy != fColorMode) {
@@ -567,12 +898,40 @@
                 break;
             }
         }
-        title.appendf(" %s", curPrimaries >= 0 ? gNamedPrimaries[curPrimaries].fName : "Custom");
+        title.appendf(" %s Gamma %f",
+                      curPrimaries >= 0 ? gNamedPrimaries[curPrimaries].fName : "Custom",
+                      fColorSpaceTransferFn.g);
+    }
+
+    const DisplayParams& params = fWindow->getRequestedDisplayParams();
+    if (fPixelGeometryOverrides) {
+        switch (params.fSurfaceProps.pixelGeometry()) {
+            case kUnknown_SkPixelGeometry:
+                title.append( " Flat");
+                break;
+            case kRGB_H_SkPixelGeometry:
+                title.append( " RGB");
+                break;
+            case kBGR_H_SkPixelGeometry:
+                title.append( " BGR");
+                break;
+            case kRGB_V_SkPixelGeometry:
+                title.append( " RGBV");
+                break;
+            case kBGR_V_SkPixelGeometry:
+                title.append( " BGRV");
+                break;
+        }
+    }
+
+    if (params.fSurfaceProps.isUseDeviceIndependentFonts()) {
+        title.append(" DFT");
     }
 
     title.append(" [");
     title.append(kBackendTypeStrings[fBackendType]);
-    if (int msaa = fWindow->sampleCount()) {
+    int msaa = fWindow->sampleCount();
+    if (msaa > 1) {
         title.appendf(" MSAA: %i", msaa);
     }
     title.append("]");
@@ -582,17 +941,22 @@
         title.appendf(" [Path renderer: %s]", gPathRendererNames[pr].c_str());
     }
 
+    if (kPerspective_Real == fPerspectiveMode) {
+        title.append(" Perpsective (Real)");
+    } else if (kPerspective_Fake == fPerspectiveMode) {
+        title.append(" Perspective (Fake)");
+    }
+
     fWindow->setTitle(title.c_str());
 }
 
-void Viewer::setStartupSlide() {
+int Viewer::startupSlide() const {
 
     if (!FLAGS_slide.isEmpty()) {
         int count = fSlides.count();
         for (int i = 0; i < count; i++) {
             if (fSlides[i]->getName().equals(FLAGS_slide[0])) {
-                fCurrentSlide = i;
-                return;
+                return i;
             }
         }
 
@@ -600,47 +964,60 @@
         this->listNames();
     }
 
-    fCurrentSlide = 0;
+    return 0;
 }
 
-void Viewer::listNames() {
-    int count = fSlides.count();
+void Viewer::listNames() const {
     SkDebugf("All Slides:\n");
-    for (int i = 0; i < count; i++) {
-        SkDebugf("    %s\n", fSlides[i]->getName().c_str());
+    for (const auto& slide : fSlides) {
+        SkDebugf("    %s\n", slide->getName().c_str());
     }
 }
 
-void Viewer::setupCurrentSlide(int previousSlide) {
-    if (fCurrentSlide == previousSlide) {
-        return; // no change; do nothing
+void Viewer::setCurrentSlide(int slide) {
+    SkASSERT(slide >= 0 && slide < fSlides.count());
+
+    if (slide == fCurrentSlide) {
+        return;
     }
-    // prepare dimensions for image slides
-    fSlides[fCurrentSlide]->load(SkIntToScalar(fWindow->width()), SkIntToScalar(fWindow->height()));
 
-    fGesture.reset();
-    fDefaultMatrix.reset();
+    if (fCurrentSlide >= 0) {
+        fSlides[fCurrentSlide]->unload();
+    }
 
-    const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
-    const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
-    const SkRect windowRect = SkRect::MakeIWH(fWindow->width(), fWindow->height());
+    fSlides[slide]->load(SkIntToScalar(fWindow->width()),
+                         SkIntToScalar(fWindow->height()));
+    fCurrentSlide = slide;
+    this->setupCurrentSlide();
+}
 
-    // Start with a matrix that scales the slide to the available screen space
-    if (fWindow->scaleContentToFit()) {
-        if (windowRect.width() > 0 && windowRect.height() > 0) {
-            fDefaultMatrix.setRectToRect(slideBounds, windowRect, SkMatrix::kStart_ScaleToFit);
+void Viewer::setupCurrentSlide() {
+    if (fCurrentSlide >= 0) {
+        // prepare dimensions for image slides
+        fGesture.resetTouchState();
+        fDefaultMatrix.reset();
+
+        const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
+        const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
+        const SkRect windowRect = SkRect::MakeIWH(fWindow->width(), fWindow->height());
+
+        // Start with a matrix that scales the slide to the available screen space
+        if (fWindow->scaleContentToFit()) {
+            if (windowRect.width() > 0 && windowRect.height() > 0) {
+                fDefaultMatrix.setRectToRect(slideBounds, windowRect, SkMatrix::kStart_ScaleToFit);
+            }
         }
-    }
 
-    // Prevent the user from dragging content so far outside the window they can't find it again
-    fGesture.setTransLimit(slideBounds, windowRect, fDefaultMatrix);
+        // Prevent the user from dragging content so far outside the window they can't find it again
+        fGesture.setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix());
 
-    this->updateTitle();
-    this->updateUIState();
-    if (previousSlide >= 0) {
-        fSlides[previousSlide]->unload();
+        this->updateTitle();
+        this->updateUIState();
+
+        fStatsLayer.resetMeasurements();
+
+        fWindow->inval();
     }
-    fWindow->inval();
 }
 
 #define MAX_ZOOM_LEVEL  8
@@ -649,362 +1026,577 @@
 void Viewer::changeZoomLevel(float delta) {
     fZoomLevel += delta;
     fZoomLevel = SkScalarPin(fZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
+    this->preTouchMatrixChanged();
 }
 
-SkMatrix Viewer::computeMatrix() {
-    SkMatrix m;
+void Viewer::preTouchMatrixChanged() {
+    // Update the trans limit as the transform changes.
+    const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
+    const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
+    const SkRect windowRect = SkRect::MakeIWH(fWindow->width(), fWindow->height());
+    fGesture.setTransLimit(slideBounds, windowRect, this->computePreTouchMatrix());
+}
 
-    SkScalar zoomScale = (fZoomLevel < 0) ? SK_Scalar1 / (SK_Scalar1 - fZoomLevel)
-                                          : SK_Scalar1 + fZoomLevel;
-    m = fGesture.localM();
-    m.preConcat(fGesture.globalM());
-    m.preConcat(fDefaultMatrix);
+SkMatrix Viewer::computePerspectiveMatrix() {
+    SkScalar w = fWindow->width(), h = fWindow->height();
+    SkPoint orthoPts[4] = { { 0, 0 }, { w, 0 }, { 0, h }, { w, h } };
+    SkPoint perspPts[4] = {
+        { fPerspectivePoints[0].fX * w, fPerspectivePoints[0].fY * h },
+        { fPerspectivePoints[1].fX * w, fPerspectivePoints[1].fY * h },
+        { fPerspectivePoints[2].fX * w, fPerspectivePoints[2].fY * h },
+        { fPerspectivePoints[3].fX * w, fPerspectivePoints[3].fY * h }
+    };
+    SkMatrix m;
+    m.setPolyToPoly(orthoPts, perspPts, 4);
+    return m;
+}
+
+SkMatrix Viewer::computePreTouchMatrix() {
+    SkMatrix m = fDefaultMatrix;
+
+    SkScalar zoomScale = exp(fZoomLevel);
+    m.preTranslate((fOffset.x() - 0.5f) * 2.0f, (fOffset.y() - 0.5f) * 2.0f);
     m.preScale(zoomScale, zoomScale);
 
+    const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
+    m.preRotate(fRotation, slideSize.width() * 0.5f, slideSize.height() * 0.5f);
+
+    if (kPerspective_Real == fPerspectiveMode) {
+        SkMatrix persp = this->computePerspectiveMatrix();
+        m.postConcat(persp);
+    }
+
     return m;
 }
 
+SkMatrix Viewer::computeMatrix() {
+    SkMatrix m = fGesture.localM();
+    m.preConcat(fGesture.globalM());
+    m.preConcat(this->computePreTouchMatrix());
+    return m;
+}
+
 void Viewer::setBackend(sk_app::Window::BackendType backendType) {
+    fPersistentCache.reset();
+    fCachedGLSL.reset();
     fBackendType = backendType;
 
     fWindow->detach();
 
-#if defined(SK_BUILD_FOR_WIN) && defined(SK_VULKAN)
-    // Switching from OpenGL to Vulkan (or vice-versa on some systems) in the same window is
-    // problematic at this point on Windows, so we just delete the window and recreate it.
-    if (sk_app::Window::kVulkan_BackendType == fBackendType ||
-            sk_app::Window::kNativeGL_BackendType == fBackendType) {
-        DisplayParams params = fWindow->getRequestedDisplayParams();
-        delete fWindow;
-        fWindow = Window::CreateNativeWindow(nullptr);
+#if defined(SK_BUILD_FOR_WIN)
+    // Switching between OpenGL, Vulkan, and ANGLE in the same window is problematic at this point
+    // on Windows, so we just delete the window and recreate it.
+    DisplayParams params = fWindow->getRequestedDisplayParams();
+    delete fWindow;
+    fWindow = Window::CreateNativeWindow(nullptr);
 
-        // re-register callbacks
-        fCommands.attach(fWindow);
-        fWindow->registerBackendCreatedFunc(on_backend_created_func, this);
-        fWindow->registerPaintFunc(on_paint_handler, this);
-        fWindow->registerTouchFunc(on_touch_handler, this);
-        fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this);
-        fWindow->registerMouseFunc(on_mouse_handler, this);
-        fWindow->registerMouseWheelFunc(on_mouse_wheel_handler, this);
-        fWindow->registerKeyFunc(on_key_handler, this);
-        fWindow->registerCharFunc(on_char_handler, this);
-        // Don't allow the window to re-attach. If we're in MSAA mode, the params we grabbed above
-        // will still include our correct sample count. But the re-created fWindow will lose that
-        // information. On Windows, we need to re-create the window when changing sample count,
-        // so we'll incorrectly detect that situation, then re-initialize the window in GL mode,
-        // rendering this tear-down step pointless (and causing the Vulkan window context to fail
-        // as if we had never changed windows at all).
-        fWindow->setRequestedDisplayParams(params, false);
-    }
+    // re-register callbacks
+    fCommands.attach(fWindow);
+    fWindow->pushLayer(this);
+    fWindow->pushLayer(&fStatsLayer);
+    fWindow->pushLayer(&fImGuiLayer);
+
+    // Don't allow the window to re-attach. If we're in MSAA mode, the params we grabbed above
+    // will still include our correct sample count. But the re-created fWindow will lose that
+    // information. On Windows, we need to re-create the window when changing sample count,
+    // so we'll incorrectly detect that situation, then re-initialize the window in GL mode,
+    // rendering this tear-down step pointless (and causing the Vulkan window context to fail
+    // as if we had never changed windows at all).
+    fWindow->setRequestedDisplayParams(params, false);
 #endif
 
-    fWindow->attach(fBackendType);
+    fWindow->attach(backend_type_for_window(fBackendType));
 }
 
 void Viewer::setColorMode(ColorMode colorMode) {
     fColorMode = colorMode;
-
-    // When we're in color managed mode, we tag our window surface as sRGB. If we've switched into
-    // or out of legacy/nonlinear mode, we need to update our window configuration.
-    DisplayParams params = fWindow->getRequestedDisplayParams();
-    bool wasInLegacy = !SkToBool(params.fColorSpace);
-    bool wantLegacy = (ColorMode::kLegacy == fColorMode) ||
-                      (ColorMode::kColorManagedSRGB8888_NonLinearBlending == fColorMode);
-    if (wasInLegacy != wantLegacy) {
-        params.fColorSpace = wantLegacy ? nullptr : SkColorSpace::MakeSRGB();
-        fWindow->setRequestedDisplayParams(params);
-    }
-
     this->updateTitle();
     fWindow->inval();
 }
 
-void Viewer::drawSlide(SkCanvas* canvas) {
-    SkAutoCanvasRestore autorestore(canvas, false);
+class OveridePaintFilterCanvas : public SkPaintFilterCanvas {
+public:
+    OveridePaintFilterCanvas(SkCanvas* canvas, SkPaint* paint, Viewer::SkPaintFields* pfields,
+            SkFont* font, Viewer::SkFontFields* ffields)
+        : SkPaintFilterCanvas(canvas), fPaint(paint), fPaintOverrides(pfields), fFont(font), fFontOverrides(ffields)
+    { }
+    const SkTextBlob* filterTextBlob(const SkPaint& paint, const SkTextBlob* blob,
+                                     sk_sp<SkTextBlob>* cache) {
+        bool blobWillChange = false;
+        for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
+            SkTCopyOnFirstWrite<SkFont> filteredFont(it.font());
+            bool shouldDraw = this->filterFont(&filteredFont);
+            if (it.font() != *filteredFont || !shouldDraw) {
+                blobWillChange = true;
+                break;
+            }
+        }
+        if (!blobWillChange) {
+            return blob;
+        }
+
+        SkTextBlobBuilder builder;
+        for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
+            SkTCopyOnFirstWrite<SkFont> filteredFont(it.font());
+            bool shouldDraw = this->filterFont(&filteredFont);
+            if (!shouldDraw) {
+                continue;
+            }
+
+            SkFont font = *filteredFont;
+
+            const SkTextBlobBuilder::RunBuffer& runBuffer
+                = it.positioning() == SkTextBlobRunIterator::kDefault_Positioning
+                    ? SkTextBlobBuilderPriv::AllocRunText(&builder, font,
+                        it.glyphCount(), it.offset().x(),it.offset().y(), it.textSize(), SkString())
+                : it.positioning() == SkTextBlobRunIterator::kHorizontal_Positioning
+                    ? SkTextBlobBuilderPriv::AllocRunTextPosH(&builder, font,
+                        it.glyphCount(), it.offset().y(), it.textSize(), SkString())
+                : it.positioning() == SkTextBlobRunIterator::kFull_Positioning
+                    ? SkTextBlobBuilderPriv::AllocRunTextPos(&builder, font,
+                        it.glyphCount(), it.textSize(), SkString())
+                : (SkASSERT_RELEASE(false), SkTextBlobBuilder::RunBuffer());
+            uint32_t glyphCount = it.glyphCount();
+            if (it.glyphs()) {
+                size_t glyphSize = sizeof(decltype(*it.glyphs()));
+                memcpy(runBuffer.glyphs, it.glyphs(), glyphCount * glyphSize);
+            }
+            if (it.pos()) {
+                size_t posSize = sizeof(decltype(*it.pos()));
+                uint8_t positioning = it.positioning();
+                memcpy(runBuffer.pos, it.pos(), glyphCount * positioning * posSize);
+            }
+            if (it.text()) {
+                size_t textSize = sizeof(decltype(*it.text()));
+                uint32_t textCount = it.textSize();
+                memcpy(runBuffer.utf8text, it.text(), textCount * textSize);
+            }
+            if (it.clusters()) {
+                size_t clusterSize = sizeof(decltype(*it.clusters()));
+                memcpy(runBuffer.clusters, it.clusters(), glyphCount * clusterSize);
+            }
+        }
+        *cache = builder.make();
+        return cache->get();
+    }
+    void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                        const SkPaint& paint) override {
+        sk_sp<SkTextBlob> cache;
+        this->SkPaintFilterCanvas::onDrawTextBlob(
+            this->filterTextBlob(paint, blob, &cache), x, y, paint);
+    }
+    bool filterFont(SkTCopyOnFirstWrite<SkFont>* font) const {
+        if (fFontOverrides->fSize) {
+            font->writable()->setSize(fFont->getSize());
+        }
+        if (fFontOverrides->fScaleX) {
+            font->writable()->setScaleX(fFont->getScaleX());
+        }
+        if (fFontOverrides->fSkewX) {
+            font->writable()->setSkewX(fFont->getSkewX());
+        }
+        if (fFontOverrides->fHinting) {
+            font->writable()->setHinting(fFont->getHinting());
+        }
+        if (fFontOverrides->fEdging) {
+            font->writable()->setEdging(fFont->getEdging());
+        }
+        if (fFontOverrides->fEmbolden) {
+            font->writable()->setEmbolden(fFont->isEmbolden());
+        }
+        if (fFontOverrides->fBaselineSnap) {
+            font->writable()->setBaselineSnap(fFont->isBaselineSnap());
+        }
+        if (fFontOverrides->fLinearMetrics) {
+            font->writable()->setLinearMetrics(fFont->isLinearMetrics());
+        }
+        if (fFontOverrides->fSubpixel) {
+            font->writable()->setSubpixel(fFont->isSubpixel());
+        }
+        if (fFontOverrides->fEmbeddedBitmaps) {
+            font->writable()->setEmbeddedBitmaps(fFont->isEmbeddedBitmaps());
+        }
+        if (fFontOverrides->fForceAutoHinting) {
+            font->writable()->setForceAutoHinting(fFont->isForceAutoHinting());
+        }
+
+        return true;
+    }
+    bool onFilter(SkPaint& paint) const override {
+        if (fPaintOverrides->fAntiAlias) {
+            paint.setAntiAlias(fPaint->isAntiAlias());
+        }
+        if (fPaintOverrides->fDither) {
+            paint.setDither(fPaint->isDither());
+        }
+        if (fPaintOverrides->fFilterQuality) {
+            paint.setFilterQuality(fPaint->getFilterQuality());
+        }
+        return true;
+    }
+    SkPaint* fPaint;
+    Viewer::SkPaintFields* fPaintOverrides;
+    SkFont* fFont;
+    Viewer::SkFontFields* fFontOverrides;
+};
+
+void Viewer::drawSlide(SkSurface* surface) {
+    if (fCurrentSlide < 0) {
+        return;
+    }
+
+    SkAutoCanvasRestore autorestore(surface->getCanvas(), false);
 
     // By default, we render directly into the window's surface/canvas
-    SkCanvas* slideCanvas = canvas;
+    SkSurface* slideSurface = surface;
+    SkCanvas* slideCanvas = surface->getCanvas();
     fLastImage.reset();
 
     // If we're in any of the color managed modes, construct the color space we're going to use
-    sk_sp<SkColorSpace> cs = nullptr;
+    sk_sp<SkColorSpace> colorSpace = nullptr;
     if (ColorMode::kLegacy != fColorMode) {
-        auto transferFn = (ColorMode::kColorManagedLinearF16 == fColorMode)
-            ? SkColorSpace::kLinear_RenderTargetGamma : SkColorSpace::kSRGB_RenderTargetGamma;
-        SkMatrix44 toXYZ;
+        skcms_Matrix3x3 toXYZ;
         SkAssertResult(fColorSpacePrimaries.toXYZD50(&toXYZ));
-        cs = SkColorSpace::MakeRGB(transferFn, toXYZ);
+        colorSpace = SkColorSpace::MakeRGB(fColorSpaceTransferFn, toXYZ);
     }
 
-    // If we're in F16, or we're zooming, or we're in color correct 8888 and the gamut isn't sRGB,
-    // we need to render offscreen
+    if (fSaveToSKP) {
+        SkPictureRecorder recorder;
+        SkCanvas* recorderCanvas = recorder.beginRecording(
+                SkRect::Make(fSlides[fCurrentSlide]->getDimensions()));
+        fSlides[fCurrentSlide]->draw(recorderCanvas);
+        sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
+        SkFILEWStream stream("sample_app.skp");
+        picture->serialize(&stream);
+        fSaveToSKP = false;
+    }
+
+    // Grab some things we'll need to make surfaces (for tiling or general offscreen rendering)
+    SkColorType colorType;
+    switch (fColorMode) {
+        case ColorMode::kLegacy:
+        case ColorMode::kColorManaged8888:
+            colorType = kN32_SkColorType;
+            break;
+        case ColorMode::kColorManagedF16:
+            colorType = kRGBA_F16_SkColorType;
+            break;
+        case ColorMode::kColorManagedF16Norm:
+            colorType = kRGBA_F16Norm_SkColorType;
+            break;
+    }
+
+    auto make_surface = [=](int w, int h) {
+        SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType);
+        slideCanvas->getProps(&props);
+
+        SkImageInfo info = SkImageInfo::Make(w, h, colorType, kPremul_SkAlphaType, colorSpace);
+        return Window::kRaster_BackendType == this->fBackendType
+                ? SkSurface::MakeRaster(info, &props)
+                : slideCanvas->makeSurface(info, &props);
+    };
+
+    // We need to render offscreen if we're...
+    // ... in fake perspective or zooming (so we have a snapped copy of the results)
+    // ... in any raster mode, because the window surface is actually GL
+    // ... in any color managed mode, because we always make the window surface with no color space
     sk_sp<SkSurface> offscreenSurface = nullptr;
-    if (ColorMode::kColorManagedLinearF16 == fColorMode ||
+    if (kPerspective_Fake == fPerspectiveMode ||
         fShowZoomWindow ||
-        (ColorMode::kColorManagedSRGB8888 == fColorMode &&
-         !primaries_equal(fColorSpacePrimaries, gSrgbPrimaries))) {
+        Window::kRaster_BackendType == fBackendType ||
+        colorSpace != nullptr) {
 
-        SkColorType colorType = (ColorMode::kColorManagedLinearF16 == fColorMode)
-            ? kRGBA_F16_SkColorType : kN32_SkColorType;
-        // In nonlinear blending mode, we actually use a legacy off-screen canvas, and wrap it
-        // with a special canvas (below) that has the color space attached
-        sk_sp<SkColorSpace> offscreenColorSpace =
-            (ColorMode::kColorManagedSRGB8888_NonLinearBlending == fColorMode) ? nullptr : cs;
-        SkImageInfo info = SkImageInfo::Make(fWindow->width(), fWindow->height(), colorType,
-                                             kPremul_SkAlphaType, std::move(offscreenColorSpace));
-        offscreenSurface = canvas->makeSurface(info);
+        offscreenSurface = make_surface(fWindow->width(), fWindow->height());
+        slideSurface = offscreenSurface.get();
         slideCanvas = offscreenSurface->getCanvas();
     }
 
-    std::unique_ptr<SkCanvas> xformCanvas = nullptr;
-    if (ColorMode::kColorManagedSRGB8888_NonLinearBlending == fColorMode) {
-        xformCanvas = SkCreateColorSpaceXformCanvas(slideCanvas, cs);
-        slideCanvas = xformCanvas.get();
-    }
-
     int count = slideCanvas->save();
     slideCanvas->clear(SK_ColorWHITE);
-    slideCanvas->concat(computeMatrix());
     // Time the painting logic of the slide
-    double startTime = SkTime::GetMSecs();
-    fSlides[fCurrentSlide]->draw(slideCanvas);
-    fPaintTimes[fCurrentMeasurement] = SkTime::GetMSecs() - startTime;
+    fStatsLayer.beginTiming(fPaintTimer);
+    if (fTiled) {
+        int tileW = SkScalarCeilToInt(fWindow->width() * fTileScale.width());
+        int tileH = SkScalarCeilToInt(fWindow->height() * fTileScale.height());
+        sk_sp<SkSurface> tileSurface = make_surface(tileW, tileH);
+        SkCanvas* tileCanvas = tileSurface->getCanvas();
+        SkMatrix m = this->computeMatrix();
+        for (int y = 0; y < fWindow->height(); y += tileH) {
+            for (int x = 0; x < fWindow->width(); x += tileW) {
+                SkAutoCanvasRestore acr(tileCanvas, true);
+                tileCanvas->translate(-x, -y);
+                tileCanvas->clear(SK_ColorTRANSPARENT);
+                tileCanvas->concat(m);
+                OveridePaintFilterCanvas filterCanvas(tileCanvas, &fPaint, &fPaintOverrides,
+                                                      &fFont, &fFontOverrides);
+                fSlides[fCurrentSlide]->draw(&filterCanvas);
+                tileSurface->draw(slideCanvas, x, y, nullptr);
+            }
+        }
+
+        // Draw borders between tiles
+        if (fDrawTileBoundaries) {
+            SkPaint border;
+            border.setColor(0x60FF00FF);
+            border.setStyle(SkPaint::kStroke_Style);
+            for (int y = 0; y < fWindow->height(); y += tileH) {
+                for (int x = 0; x < fWindow->width(); x += tileW) {
+                    slideCanvas->drawRect(SkRect::MakeXYWH(x, y, tileW, tileH), border);
+                }
+            }
+        }
+    } else {
+        slideCanvas->concat(this->computeMatrix());
+        if (kPerspective_Real == fPerspectiveMode) {
+            slideCanvas->clipRect(SkRect::MakeWH(fWindow->width(), fWindow->height()));
+        }
+        OveridePaintFilterCanvas filterCanvas(slideCanvas, &fPaint, &fPaintOverrides, &fFont, &fFontOverrides);
+        fSlides[fCurrentSlide]->draw(&filterCanvas);
+    }
+    fStatsLayer.endTiming(fPaintTimer);
     slideCanvas->restoreToCount(count);
 
     // Force a flush so we can time that, too
-    startTime = SkTime::GetMSecs();
-    slideCanvas->flush();
-    fFlushTimes[fCurrentMeasurement] = SkTime::GetMSecs() - startTime;
+    fStatsLayer.beginTiming(fFlushTimer);
+    slideSurface->flush();
+    fStatsLayer.endTiming(fFlushTimer);
 
     // If we rendered offscreen, snap an image and push the results to the window's canvas
     if (offscreenSurface) {
         fLastImage = offscreenSurface->makeImageSnapshot();
 
-        // Tag the image with the sRGB gamut, so no further color space conversion happens
-        sk_sp<SkColorSpace> srgb = (ColorMode::kColorManagedLinearF16 == fColorMode)
-            ? SkColorSpace::MakeSRGBLinear() : SkColorSpace::MakeSRGB();
-        auto retaggedImage = SkImageMakeRasterCopyAndAssignColorSpace(fLastImage.get(), srgb.get());
+        SkCanvas* canvas = surface->getCanvas();
         SkPaint paint;
         paint.setBlendMode(SkBlendMode::kSrc);
-        canvas->drawImage(retaggedImage, 0, 0, &paint);
+        int prePerspectiveCount = canvas->save();
+        if (kPerspective_Fake == fPerspectiveMode) {
+            paint.setFilterQuality(kHigh_SkFilterQuality);
+            canvas->clear(SK_ColorWHITE);
+            canvas->concat(this->computePerspectiveMatrix());
+        }
+        canvas->drawImage(fLastImage, 0, 0, &paint);
+        canvas->restoreToCount(prePerspectiveCount);
+    }
+
+    if (fShowSlideDimensions) {
+        SkRect r = SkRect::Make(fSlides[fCurrentSlide]->getDimensions());
+        SkPaint paint;
+        paint.setColor(0x40FFFF00);
+        surface->getCanvas()->drawRect(r, paint);
     }
 }
 
 void Viewer::onBackendCreated() {
-    this->updateTitle();
-    this->updateUIState();
-    this->setupCurrentSlide(-1);
+    this->setupCurrentSlide();
     fWindow->show();
-    fWindow->inval();
 }
 
-void Viewer::onPaint(SkCanvas* canvas) {
-    // Update ImGui input
-    ImGuiIO& io = ImGui::GetIO();
-    io.DeltaTime = 1.0f / 60.0f;
-    io.DisplaySize.x = static_cast<float>(fWindow->width());
-    io.DisplaySize.y = static_cast<float>(fWindow->height());
+void Viewer::onPaint(SkSurface* surface) {
+    this->drawSlide(surface);
 
-    io.KeyAlt = io.KeysDown[static_cast<int>(Window::Key::kOption)];
-    io.KeyCtrl = io.KeysDown[static_cast<int>(Window::Key::kCtrl)];
-    io.KeyShift = io.KeysDown[static_cast<int>(Window::Key::kShift)];
+    fCommands.drawHelp(surface->getCanvas());
 
-    ImGui::NewFrame();
+    this->drawImGui();
 
-    drawSlide(canvas);
-
-    // Advance our timing bookkeeping
-    fCurrentMeasurement = (fCurrentMeasurement + 1) & (kMeasurementCount - 1);
-    SkASSERT(fCurrentMeasurement < kMeasurementCount);
-
-    // Draw any overlays or UI that we don't want timed
-    if (fDisplayStats) {
-        drawStats(canvas);
+    if (GrContext* ctx = fWindow->getGrContext()) {
+        // Clean out cache items that haven't been used in more than 10 seconds.
+        ctx->performDeferredCleanup(std::chrono::seconds(10));
     }
-    fCommands.drawHelp(canvas);
-
-    drawImGui(canvas);
-
-    // Update the FPS
-    updateUIState();
 }
 
-bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y) {
+void Viewer::onResize(int width, int height) {
+    if (fCurrentSlide >= 0) {
+        fSlides[fCurrentSlide]->resize(width, height);
+    }
+}
+
+SkPoint Viewer::mapEvent(float x, float y) {
+    const auto m = this->computeMatrix();
+    SkMatrix inv;
+
+    SkAssertResult(m.invert(&inv));
+
+    return inv.mapXY(x, y);
+}
+
+bool Viewer::onTouch(intptr_t owner, skui::InputState state, float x, float y) {
     if (GestureDevice::kMouse == fGestureDevice) {
         return false;
     }
+
+    const auto slidePt = this->mapEvent(x, y);
+    if (fSlides[fCurrentSlide]->onMouse(slidePt.x(), slidePt.y(), state, skui::ModifierKey::kNone)) {
+        fWindow->inval();
+        return true;
+    }
+
     void* castedOwner = reinterpret_cast<void*>(owner);
     switch (state) {
-        case Window::kUp_InputState: {
+        case skui::InputState::kUp: {
             fGesture.touchEnd(castedOwner);
+#if defined(SK_BUILD_FOR_IOS)
+            // TODO: move IOS swipe detection higher up into the platform code
+            SkPoint dir;
+            if (fGesture.isFling(&dir)) {
+                // swiping left or right
+                if (SkTAbs(dir.fX) > SkTAbs(dir.fY)) {
+                    if (dir.fX < 0) {
+                        this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ?
+                                              fCurrentSlide + 1 : 0);
+                    } else {
+                        this->setCurrentSlide(fCurrentSlide > 0 ?
+                                              fCurrentSlide - 1 : fSlides.count() - 1);
+                    }
+                }
+                fGesture.reset();
+            }
+#endif
             break;
         }
-        case Window::kDown_InputState: {
+        case skui::InputState::kDown: {
             fGesture.touchBegin(castedOwner, x, y);
             break;
         }
-        case Window::kMove_InputState: {
+        case skui::InputState::kMove: {
             fGesture.touchMoved(castedOwner, x, y);
             break;
         }
+        default: {
+            // kLeft and kRight are only for swipes
+            SkASSERT(false);
+            break;
+        }
     }
     fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kTouch : GestureDevice::kNone;
     fWindow->inval();
     return true;
 }
 
-bool Viewer::onMouse(float x, float y, Window::InputState state, uint32_t modifiers) {
+bool Viewer::onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) {
     if (GestureDevice::kTouch == fGestureDevice) {
         return false;
     }
+
+    const auto slidePt = this->mapEvent(x, y);
+    if (fSlides[fCurrentSlide]->onMouse(slidePt.x(), slidePt.y(), state, modifiers)) {
+        fWindow->inval();
+        return true;
+    }
+
     switch (state) {
-        case Window::kUp_InputState: {
+        case skui::InputState::kUp: {
             fGesture.touchEnd(nullptr);
             break;
         }
-        case Window::kDown_InputState: {
+        case skui::InputState::kDown: {
             fGesture.touchBegin(nullptr, x, y);
             break;
         }
-        case Window::kMove_InputState: {
+        case skui::InputState::kMove: {
             fGesture.touchMoved(nullptr, x, y);
             break;
         }
+        default: {
+            SkASSERT(false); // shouldn't see kRight or kLeft here
+            break;
+        }
     }
     fGestureDevice = fGesture.isBeingTouched() ? GestureDevice::kMouse : GestureDevice::kNone;
-    fWindow->inval();
+
+    if (state != skui::InputState::kMove || fGesture.isBeingTouched()) {
+        fWindow->inval();
+    }
     return true;
 }
 
-void Viewer::drawStats(SkCanvas* canvas) {
-    static const float kPixelPerMS = 2.0f;
-    static const int kDisplayWidth = 130;
-    static const int kDisplayHeight = 100;
-    static const int kDisplayPadding = 10;
-    static const int kGraphPadding = 3;
-    static const SkScalar kBaseMS = 1000.f / 60.f;  // ms/frame to hit 60 fps
-
-    SkISize canvasSize = canvas->getBaseLayerSize();
-    SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding),
-                                   SkIntToScalar(kDisplayPadding),
-                                   SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight));
-    SkPaint paint;
-    canvas->save();
-
-    canvas->clipRect(rect);
-    paint.setColor(SK_ColorBLACK);
-    canvas->drawRect(rect, paint);
-    // draw the 16ms line
-    paint.setColor(SK_ColorLTGRAY);
-    canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS,
-                     rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint);
-    paint.setColor(SK_ColorRED);
-    paint.setStyle(SkPaint::kStroke_Style);
-    canvas->drawRect(rect, paint);
-
-    int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding;
-    const int xStep = 2;
-    int i = fCurrentMeasurement;
-    do {
-        // Round to nearest values
-        int animateHeight = (int)(fAnimateTimes[i] * kPixelPerMS + 0.5);
-        int paintHeight = (int)(fPaintTimes[i] * kPixelPerMS + 0.5);
-        int flushHeight = (int)(fFlushTimes[i] * kPixelPerMS + 0.5);
-        int startY = SkScalarTruncToInt(rect.fBottom);
-        int endY = startY - flushHeight;
-        paint.setColor(SK_ColorRED);
-        canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
-                         SkIntToScalar(x), SkIntToScalar(endY), paint);
-        startY = endY;
-        endY = startY - paintHeight;
-        paint.setColor(SK_ColorGREEN);
-        canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
-                         SkIntToScalar(x), SkIntToScalar(endY), paint);
-        startY = endY;
-        endY = startY - animateHeight;
-        paint.setColor(SK_ColorMAGENTA);
-        canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
-                         SkIntToScalar(x), SkIntToScalar(endY), paint);
-        i++;
-        i &= (kMeasurementCount - 1);  // fast mod
-        x += xStep;
-    } while (i != fCurrentMeasurement);
-
-    canvas->restore();
+bool Viewer::onFling(skui::InputState state) {
+    if (skui::InputState::kRight == state) {
+        this->setCurrentSlide(fCurrentSlide > 0 ? fCurrentSlide - 1 : fSlides.count() - 1);
+        return true;
+    } else if (skui::InputState::kLeft == state) {
+        this->setCurrentSlide(fCurrentSlide < fSlides.count() - 1 ? fCurrentSlide + 1 : 0);
+        return true;
+    }
+    return false;
 }
 
-static ImVec2 ImGui_DragPrimary(const char* label, float* x, float* y,
-                                const ImVec2& pos, const ImVec2& size) {
-    // Transform primaries ([0, 0] - [0.8, 0.9]) to screen coords (including Y-flip)
-    ImVec2 center(pos.x + (*x / 0.8f) * size.x, pos.y + (1.0f - (*y / 0.9f)) * size.y);
-
-    // Invisible 10x10 button
-    ImGui::SetCursorScreenPos(ImVec2(center.x - 5, center.y - 5));
-    ImGui::InvisibleButton(label, ImVec2(10, 10));
-
-    if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) {
-        ImGuiIO& io = ImGui::GetIO();
-        // Normalized mouse position, relative to our gamut box
-        ImVec2 mousePosXY((io.MousePos.x - pos.x) / size.x, (io.MousePos.y - pos.y) / size.y);
-        // Clamp to edge of box, convert back to primary scale
-        *x = SkTPin(mousePosXY.x, 0.0f, 1.0f) * 0.8f;
-        *y = SkTPin(1 - mousePosXY.y, 0.0f, 1.0f) * 0.9f;
+bool Viewer::onPinch(skui::InputState state, float scale, float x, float y) {
+    switch (state) {
+        case skui::InputState::kDown:
+            fGesture.startZoom();
+            return true;
+            break;
+        case skui::InputState::kMove:
+            fGesture.updateZoom(scale, x, y, x, y);
+            return true;
+            break;
+        case skui::InputState::kUp:
+            fGesture.endZoom();
+            return true;
+            break;
+        default:
+            SkASSERT(false);
+            break;
     }
 
-    if (ImGui::IsItemHovered()) {
-        ImGui::SetTooltip("x: %.3f\ny: %.3f", *x, *y);
-    }
-
-    // Return screen coordinates for the caller. We could just return center here, but we'd have
-    // one frame of lag during drag.
-    return ImVec2(pos.x + (*x / 0.8f) * size.x, pos.y + (1.0f - (*y / 0.9f)) * size.y);
+    return false;
 }
 
 static void ImGui_Primaries(SkColorSpacePrimaries* primaries, SkPaint* gamutPaint) {
-    ImDrawList* drawList = ImGui::GetWindowDrawList();
-
-    // The gamut image covers a (0.8 x 0.9) shaped region, so fit our image/canvas to the available
-    // width, and scale the height to maintain aspect ratio.
-    float canvasWidth = SkTMax(ImGui::GetContentRegionAvailWidth(), 50.0f);
-    ImVec2 size = ImVec2(canvasWidth, canvasWidth * (0.9f / 0.8f));
-    ImVec2 pos = ImGui::GetCursorScreenPos();
+    // The gamut image covers a (0.8 x 0.9) shaped region
+    ImGui::DragCanvas dc(primaries, { 0.0f, 0.9f }, { 0.8f, 0.0f });
 
     // Background image. Only draw a subset of the image, to avoid the regions less than zero.
     // Simplifes re-mapping math, clipping behavior, and increases resolution in the useful area.
     // Magic numbers are pixel locations of the origin and upper-right corner.
-    drawList->AddImage(gamutPaint, pos, ImVec2(pos.x + size.x, pos.y + size.y),
-                       ImVec2(242, 61), ImVec2(1897, 1922));
-    ImVec2 endPos = ImGui::GetCursorPos();
+    dc.fDrawList->AddImage(gamutPaint, dc.fPos,
+                           ImVec2(dc.fPos.x + dc.fSize.x, dc.fPos.y + dc.fSize.y),
+                           ImVec2(242, 61), ImVec2(1897, 1922));
 
-    // Primary markers
-    ImVec2 r = ImGui_DragPrimary("R", &primaries->fRX, &primaries->fRY, pos, size);
-    ImVec2 g = ImGui_DragPrimary("G", &primaries->fGX, &primaries->fGY, pos, size);
-    ImVec2 b = ImGui_DragPrimary("B", &primaries->fBX, &primaries->fBY, pos, size);
-    ImVec2 w = ImGui_DragPrimary("W", &primaries->fWX, &primaries->fWY, pos, size);
-
-    // Gamut triangle
-    drawList->AddCircle(r, 5.0f, 0xFF000040);
-    drawList->AddCircle(g, 5.0f, 0xFF004000);
-    drawList->AddCircle(b, 5.0f, 0xFF400000);
-    drawList->AddCircle(w, 5.0f, 0xFFFFFFFF);
-    drawList->AddTriangle(r, g, b, 0xFFFFFFFF);
-
-    // Re-position cursor immediate after the diagram for subsequent controls
-    ImGui::SetCursorPos(endPos);
+    dc.dragPoint((SkPoint*)(&primaries->fRX), true, 0xFF000040);
+    dc.dragPoint((SkPoint*)(&primaries->fGX), true, 0xFF004000);
+    dc.dragPoint((SkPoint*)(&primaries->fBX), true, 0xFF400000);
+    dc.dragPoint((SkPoint*)(&primaries->fWX), true);
+    dc.fDrawList->AddPolyline(dc.fScreenPoints.begin(), 3, 0xFFFFFFFF, true, 1.5f);
 }
 
-void Viewer::drawImGui(SkCanvas* canvas) {
+static bool ImGui_DragLocation(SkPoint* pt) {
+    ImGui::DragCanvas dc(pt);
+    dc.fillColor(IM_COL32(0, 0, 0, 128));
+    dc.dragPoint(pt);
+    return dc.fDragging;
+}
+
+static bool ImGui_DragQuad(SkPoint* pts) {
+    ImGui::DragCanvas dc(pts);
+    dc.fillColor(IM_COL32(0, 0, 0, 128));
+
+    for (int i = 0; i < 4; ++i) {
+        dc.dragPoint(pts + i);
+    }
+
+    dc.fDrawList->AddLine(dc.fScreenPoints[0], dc.fScreenPoints[1], 0xFFFFFFFF);
+    dc.fDrawList->AddLine(dc.fScreenPoints[1], dc.fScreenPoints[3], 0xFFFFFFFF);
+    dc.fDrawList->AddLine(dc.fScreenPoints[3], dc.fScreenPoints[2], 0xFFFFFFFF);
+    dc.fDrawList->AddLine(dc.fScreenPoints[2], dc.fScreenPoints[0], 0xFFFFFFFF);
+
+    return dc.fDragging;
+}
+
+void Viewer::drawImGui() {
     // Support drawing the ImGui demo window. Superfluous, but gives a good idea of what's possible
     if (fShowImGuiTestWindow) {
-        ImGui::ShowTestWindow(&fShowImGuiTestWindow);
+        ImGui::ShowDemoWindow(&fShowImGuiTestWindow);
     }
 
     if (fShowImGuiDebugWindow) {
         // We have some dynamic content that sizes to fill available size. If the scroll bar isn't
         // always visible, we can end up in a layout feedback loop.
-        ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiSetCond_FirstUseEver);
+        ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
         DisplayParams params = fWindow->getRequestedDisplayParams();
         bool paramsChanged = false;
+        const GrContext* ctx = fWindow->getGrContext();
+
         if (ImGui::Begin("Tools", &fShowImGuiDebugWindow,
                          ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
             if (ImGui::CollapsingHeader("Backend")) {
@@ -1012,21 +1604,28 @@
                 ImGui::RadioButton("Raster", &newBackend, sk_app::Window::kRaster_BackendType);
                 ImGui::SameLine();
                 ImGui::RadioButton("OpenGL", &newBackend, sk_app::Window::kNativeGL_BackendType);
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+                ImGui::SameLine();
+                ImGui::RadioButton("ANGLE", &newBackend, sk_app::Window::kANGLE_BackendType);
+#endif
+#if defined(SK_DAWN)
+                ImGui::SameLine();
+                ImGui::RadioButton("Dawn", &newBackend, sk_app::Window::kDawn_BackendType);
+#endif
 #if defined(SK_VULKAN)
                 ImGui::SameLine();
                 ImGui::RadioButton("Vulkan", &newBackend, sk_app::Window::kVulkan_BackendType);
 #endif
+#if defined(SK_METAL)
+                ImGui::SameLine();
+                ImGui::RadioButton("Metal", &newBackend, sk_app::Window::kMetal_BackendType);
+#endif
                 if (newBackend != fBackendType) {
                     fDeferredActions.push_back([=]() {
                         this->setBackend(static_cast<sk_app::Window::BackendType>(newBackend));
                     });
                 }
 
-                const GrContext* ctx = fWindow->getGrContext();
-                bool* inst = &params.fGrContextOptions.fEnableInstancedRendering;
-                if (ctx && ImGui::Checkbox("Instanced Rendering", inst)) {
-                    paramsChanged = true;
-                }
                 bool* wire = &params.fGrContextOptions.fWireframeMode;
                 if (ctx && ImGui::Checkbox("Wireframe Mode", wire)) {
                     paramsChanged = true;
@@ -1035,7 +1634,7 @@
                 if (ctx) {
                     int sampleCount = fWindow->sampleCount();
                     ImGui::Text("MSAA: "); ImGui::SameLine();
-                    ImGui::RadioButton("0", &sampleCount, 0); ImGui::SameLine();
+                    ImGui::RadioButton("1", &sampleCount, 1); ImGui::SameLine();
                     ImGui::RadioButton("4", &sampleCount, 4); ImGui::SameLine();
                     ImGui::RadioButton("8", &sampleCount, 8); ImGui::SameLine();
                     ImGui::RadioButton("16", &sampleCount, 16);
@@ -1046,6 +1645,38 @@
                     }
                 }
 
+                int pixelGeometryIdx = 0;
+                if (fPixelGeometryOverrides) {
+                    pixelGeometryIdx = params.fSurfaceProps.pixelGeometry() + 1;
+                }
+                if (ImGui::Combo("Pixel Geometry", &pixelGeometryIdx,
+                                 "Default\0Flat\0RGB\0BGR\0RGBV\0BGRV\0\0"))
+                {
+                    uint32_t flags = params.fSurfaceProps.flags();
+                    if (pixelGeometryIdx == 0) {
+                        fPixelGeometryOverrides = false;
+                        params.fSurfaceProps = SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+                    } else {
+                        fPixelGeometryOverrides = true;
+                        SkPixelGeometry pixelGeometry = SkTo<SkPixelGeometry>(pixelGeometryIdx - 1);
+                        params.fSurfaceProps = SkSurfaceProps(flags, pixelGeometry);
+                    }
+                    paramsChanged = true;
+                }
+
+                bool useDFT = params.fSurfaceProps.isUseDeviceIndependentFonts();
+                if (ImGui::Checkbox("DFT", &useDFT)) {
+                    uint32_t flags = params.fSurfaceProps.flags();
+                    if (useDFT) {
+                        flags |= SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
+                    } else {
+                        flags &= ~SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
+                    }
+                    SkPixelGeometry pixelGeometry = params.fSurfaceProps.pixelGeometry();
+                    params.fSurfaceProps = SkSurfaceProps(flags, pixelGeometry);
+                    paramsChanged = true;
+                }
+
                 if (ImGui::TreeNode("Path Renderers")) {
                     GpuPathRenderers prevPr = params.fGrContextOptions.fGpuPathRenderers;
                     auto prButton = [&](GpuPathRenderers x) {
@@ -1059,20 +1690,17 @@
 
                     if (!ctx) {
                         ImGui::RadioButton("Software", true);
-                    } else if (fWindow->sampleCount()) {
+                    } else if (fWindow->sampleCount() > 1) {
                         prButton(GpuPathRenderers::kAll);
-                        if (ctx->caps()->shaderCaps()->pathRenderingSupport()) {
+                        if (ctx->priv().caps()->shaderCaps()->pathRenderingSupport()) {
                             prButton(GpuPathRenderers::kStencilAndCover);
                         }
-                        if (ctx->caps()->sampleShadingSupport()) {
-                            prButton(GpuPathRenderers::kMSAA);
-                        }
                         prButton(GpuPathRenderers::kTessellating);
-                        prButton(GpuPathRenderers::kDefault);
                         prButton(GpuPathRenderers::kNone);
                     } else {
                         prButton(GpuPathRenderers::kAll);
-                        if (GrCoverageCountingPathRenderer::IsSupported(*ctx->caps())) {
+                        if (GrCoverageCountingPathRenderer::IsSupported(
+                                    *ctx->priv().caps())) {
                             prButton(GpuPathRenderers::kCoverageCounting);
                         }
                         prButton(GpuPathRenderers::kSmall);
@@ -1083,23 +1711,305 @@
                 }
             }
 
-            if (ImGui::CollapsingHeader("Slide")) {
-                static ImGuiTextFilter filter;
-                filter.Draw();
-                int previousSlide = fCurrentSlide;
-                fCurrentSlide = 0;
-                for (auto slide : fSlides) {
-                    if (filter.PassFilter(slide->getName().c_str())) {
-                        ImGui::BulletText("%s", slide->getName().c_str());
-                        if (ImGui::IsItemClicked()) {
-                            setupCurrentSlide(previousSlide);
-                            break;
+            if (ImGui::CollapsingHeader("Tiling")) {
+                ImGui::Checkbox("Enable", &fTiled);
+                ImGui::Checkbox("Draw Boundaries", &fDrawTileBoundaries);
+                ImGui::SliderFloat("Horizontal", &fTileScale.fWidth, 0.1f, 1.0f);
+                ImGui::SliderFloat("Vertical", &fTileScale.fHeight, 0.1f, 1.0f);
+            }
+
+            if (ImGui::CollapsingHeader("Transform")) {
+                float zoom = fZoomLevel;
+                if (ImGui::SliderFloat("Zoom", &zoom, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) {
+                    fZoomLevel = zoom;
+                    this->preTouchMatrixChanged();
+                    paramsChanged = true;
+                }
+                float deg = fRotation;
+                if (ImGui::SliderFloat("Rotate", &deg, -30, 360, "%.3f deg")) {
+                    fRotation = deg;
+                    this->preTouchMatrixChanged();
+                    paramsChanged = true;
+                }
+                if (ImGui::CollapsingHeader("Subpixel offset", ImGuiTreeNodeFlags_NoTreePushOnOpen)) {
+                    if (ImGui_DragLocation(&fOffset)) {
+                        this->preTouchMatrixChanged();
+                        paramsChanged = true;
+                    }
+                } else if (fOffset != SkVector{0.5f, 0.5f}) {
+                    this->preTouchMatrixChanged();
+                    paramsChanged = true;
+                    fOffset = {0.5f, 0.5f};
+                }
+                int perspectiveMode = static_cast<int>(fPerspectiveMode);
+                if (ImGui::Combo("Perspective", &perspectiveMode, "Off\0Real\0Fake\0\0")) {
+                    fPerspectiveMode = static_cast<PerspectiveMode>(perspectiveMode);
+                    this->preTouchMatrixChanged();
+                    paramsChanged = true;
+                }
+                if (perspectiveMode != kPerspective_Off && ImGui_DragQuad(fPerspectivePoints)) {
+                    this->preTouchMatrixChanged();
+                    paramsChanged = true;
+                }
+            }
+
+            if (ImGui::CollapsingHeader("Paint")) {
+                int aliasIdx = 0;
+                if (fPaintOverrides.fAntiAlias) {
+                    aliasIdx = SkTo<int>(fPaintOverrides.fAntiAliasState) + 1;
+                }
+                if (ImGui::Combo("Anti-Alias", &aliasIdx,
+                                 "Default\0Alias\0Normal\0AnalyticAAEnabled\0AnalyticAAForced\0\0"))
+                {
+                    gSkUseAnalyticAA = fPaintOverrides.fOriginalSkUseAnalyticAA;
+                    gSkForceAnalyticAA = fPaintOverrides.fOriginalSkForceAnalyticAA;
+                    if (aliasIdx == 0) {
+                        fPaintOverrides.fAntiAliasState = SkPaintFields::AntiAliasState::Alias;
+                        fPaintOverrides.fAntiAlias = false;
+                    } else {
+                        fPaintOverrides.fAntiAlias = true;
+                        fPaintOverrides.fAntiAliasState = SkTo<SkPaintFields::AntiAliasState>(aliasIdx-1);
+                        fPaint.setAntiAlias(aliasIdx > 1);
+                        switch (fPaintOverrides.fAntiAliasState) {
+                            case SkPaintFields::AntiAliasState::Alias:
+                                break;
+                            case SkPaintFields::AntiAliasState::Normal:
+                                break;
+                            case SkPaintFields::AntiAliasState::AnalyticAAEnabled:
+                                gSkUseAnalyticAA = true;
+                                gSkForceAnalyticAA = false;
+                                break;
+                            case SkPaintFields::AntiAliasState::AnalyticAAForced:
+                                gSkUseAnalyticAA = gSkForceAnalyticAA = true;
+                                break;
                         }
                     }
-                    ++fCurrentSlide;
+                    paramsChanged = true;
                 }
-                if (fCurrentSlide >= fSlides.count()) {
-                    fCurrentSlide = previousSlide;
+
+                auto paintFlag = [this, &paramsChanged](const char* label, const char* items,
+                                                        bool SkPaintFields::* flag,
+                                                        bool (SkPaint::* isFlag)() const,
+                                                        void (SkPaint::* setFlag)(bool) )
+                {
+                    int itemIndex = 0;
+                    if (fPaintOverrides.*flag) {
+                        itemIndex = (fPaint.*isFlag)() ? 2 : 1;
+                    }
+                    if (ImGui::Combo(label, &itemIndex, items)) {
+                        if (itemIndex == 0) {
+                            fPaintOverrides.*flag = false;
+                        } else {
+                            fPaintOverrides.*flag = true;
+                            (fPaint.*setFlag)(itemIndex == 2);
+                        }
+                        paramsChanged = true;
+                    }
+                };
+
+                paintFlag("Dither",
+                          "Default\0No Dither\0Dither\0\0",
+                          &SkPaintFields::fDither,
+                          &SkPaint::isDither, &SkPaint::setDither);
+
+                int filterQualityIdx = 0;
+                if (fPaintOverrides.fFilterQuality) {
+                    filterQualityIdx = SkTo<int>(fPaint.getFilterQuality()) + 1;
+                }
+                if (ImGui::Combo("Filter Quality", &filterQualityIdx,
+                                 "Default\0None\0Low\0Medium\0High\0\0"))
+                {
+                    if (filterQualityIdx == 0) {
+                        fPaintOverrides.fFilterQuality = false;
+                        fPaint.setFilterQuality(kNone_SkFilterQuality);
+                    } else {
+                        fPaint.setFilterQuality(SkTo<SkFilterQuality>(filterQualityIdx - 1));
+                        fPaintOverrides.fFilterQuality = true;
+                    }
+                    paramsChanged = true;
+                }
+            }
+
+            if (ImGui::CollapsingHeader("Font")) {
+                int hintingIdx = 0;
+                if (fFontOverrides.fHinting) {
+                    hintingIdx = SkTo<int>(fFont.getHinting()) + 1;
+                }
+                if (ImGui::Combo("Hinting", &hintingIdx,
+                                 "Default\0None\0Slight\0Normal\0Full\0\0"))
+                {
+                    if (hintingIdx == 0) {
+                        fFontOverrides.fHinting = false;
+                        fFont.setHinting(SkFontHinting::kNone);
+                    } else {
+                        fFont.setHinting(SkTo<SkFontHinting>(hintingIdx - 1));
+                        fFontOverrides.fHinting = true;
+                    }
+                    paramsChanged = true;
+                }
+
+                auto fontFlag = [this, &paramsChanged](const char* label, const char* items,
+                                                       bool SkFontFields::* flag,
+                                                       bool (SkFont::* isFlag)() const,
+                                                       void (SkFont::* setFlag)(bool) )
+                {
+                    int itemIndex = 0;
+                    if (fFontOverrides.*flag) {
+                        itemIndex = (fFont.*isFlag)() ? 2 : 1;
+                    }
+                    if (ImGui::Combo(label, &itemIndex, items)) {
+                        if (itemIndex == 0) {
+                            fFontOverrides.*flag = false;
+                        } else {
+                            fFontOverrides.*flag = true;
+                            (fFont.*setFlag)(itemIndex == 2);
+                        }
+                        paramsChanged = true;
+                    }
+                };
+
+                fontFlag("Fake Bold Glyphs",
+                         "Default\0No Fake Bold\0Fake Bold\0\0",
+                         &SkFontFields::fEmbolden,
+                         &SkFont::isEmbolden, &SkFont::setEmbolden);
+
+                fontFlag("Baseline Snapping",
+                         "Default\0No Baseline Snapping\0Baseline Snapping\0\0",
+                         &SkFontFields::fBaselineSnap,
+                         &SkFont::isBaselineSnap, &SkFont::setBaselineSnap);
+
+                fontFlag("Linear Text",
+                         "Default\0No Linear Text\0Linear Text\0\0",
+                         &SkFontFields::fLinearMetrics,
+                         &SkFont::isLinearMetrics, &SkFont::setLinearMetrics);
+
+                fontFlag("Subpixel Position Glyphs",
+                         "Default\0Pixel Text\0Subpixel Text\0\0",
+                         &SkFontFields::fSubpixel,
+                         &SkFont::isSubpixel, &SkFont::setSubpixel);
+
+                fontFlag("Embedded Bitmap Text",
+                         "Default\0No Embedded Bitmaps\0Embedded Bitmaps\0\0",
+                         &SkFontFields::fEmbeddedBitmaps,
+                         &SkFont::isEmbeddedBitmaps, &SkFont::setEmbeddedBitmaps);
+
+                fontFlag("Force Auto-Hinting",
+                         "Default\0No Force Auto-Hinting\0Force Auto-Hinting\0\0",
+                         &SkFontFields::fForceAutoHinting,
+                         &SkFont::isForceAutoHinting, &SkFont::setForceAutoHinting);
+
+                int edgingIdx = 0;
+                if (fFontOverrides.fEdging) {
+                    edgingIdx = SkTo<int>(fFont.getEdging()) + 1;
+                }
+                if (ImGui::Combo("Edging", &edgingIdx,
+                                 "Default\0Alias\0Antialias\0Subpixel Antialias\0\0"))
+                {
+                    if (edgingIdx == 0) {
+                        fFontOverrides.fEdging = false;
+                        fFont.setEdging(SkFont::Edging::kAlias);
+                    } else {
+                        fFont.setEdging(SkTo<SkFont::Edging>(edgingIdx-1));
+                        fFontOverrides.fEdging = true;
+                    }
+                    paramsChanged = true;
+                }
+
+                ImGui::Checkbox("Override Size", &fFontOverrides.fSize);
+                if (fFontOverrides.fSize) {
+                    ImGui::DragFloat2("TextRange", fFontOverrides.fSizeRange,
+                                      0.001f, -10.0f, 300.0f, "%.6f", 2.0f);
+                    float textSize = fFont.getSize();
+                    if (ImGui::DragFloat("TextSize", &textSize, 0.001f,
+                                         fFontOverrides.fSizeRange[0],
+                                         fFontOverrides.fSizeRange[1],
+                                         "%.6f", 2.0f))
+                    {
+                        fFont.setSize(textSize);
+                        paramsChanged = true;
+                    }
+                }
+
+                ImGui::Checkbox("Override ScaleX", &fFontOverrides.fScaleX);
+                if (fFontOverrides.fScaleX) {
+                    float scaleX = fFont.getScaleX();
+                    if (ImGui::SliderFloat("ScaleX", &scaleX, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) {
+                        fFont.setScaleX(scaleX);
+                        paramsChanged = true;
+                    }
+                }
+
+                ImGui::Checkbox("Override SkewX", &fFontOverrides.fSkewX);
+                if (fFontOverrides.fSkewX) {
+                    float skewX = fFont.getSkewX();
+                    if (ImGui::SliderFloat("SkewX", &skewX, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL)) {
+                        fFont.setSkewX(skewX);
+                        paramsChanged = true;
+                    }
+                }
+            }
+
+            {
+                SkMetaData controls;
+                if (fSlides[fCurrentSlide]->onGetControls(&controls)) {
+                    if (ImGui::CollapsingHeader("Current Slide")) {
+                        SkMetaData::Iter iter(controls);
+                        const char* name;
+                        SkMetaData::Type type;
+                        int count;
+                        while ((name = iter.next(&type, &count)) != nullptr) {
+                            if (type == SkMetaData::kScalar_Type) {
+                                float val[3];
+                                SkASSERT(count == 3);
+                                controls.findScalars(name, &count, val);
+                                if (ImGui::SliderFloat(name, &val[0], val[1], val[2])) {
+                                    controls.setScalars(name, 3, val);
+                                }
+                            } else if (type == SkMetaData::kBool_Type) {
+                                bool val;
+                                SkASSERT(count == 1);
+                                controls.findBool(name, &val);
+                                if (ImGui::Checkbox(name, &val)) {
+                                    controls.setBool(name, val);
+                                }
+                            }
+                        }
+                        fSlides[fCurrentSlide]->onSetControls(controls);
+                    }
+                }
+            }
+
+            if (fShowSlidePicker) {
+                ImGui::SetNextTreeNodeOpen(true);
+            }
+            if (ImGui::CollapsingHeader("Slide")) {
+                static ImGuiTextFilter filter;
+                static ImVector<const char*> filteredSlideNames;
+                static ImVector<int> filteredSlideIndices;
+
+                if (fShowSlidePicker) {
+                    ImGui::SetKeyboardFocusHere();
+                    fShowSlidePicker = false;
+                }
+
+                filter.Draw();
+                filteredSlideNames.clear();
+                filteredSlideIndices.clear();
+                int filteredIndex = 0;
+                for (int i = 0; i < fSlides.count(); ++i) {
+                    const char* slideName = fSlides[i]->getName().c_str();
+                    if (filter.PassFilter(slideName) || i == fCurrentSlide) {
+                        if (i == fCurrentSlide) {
+                            filteredIndex = filteredSlideIndices.size();
+                        }
+                        filteredSlideNames.push_back(slideName);
+                        filteredSlideIndices.push_back(i);
+                    }
+                }
+
+                if (ImGui::ListBox("", &filteredIndex, filteredSlideNames.begin(),
+                                   filteredSlideNames.size(), 20)) {
+                    this->setCurrentSlide(filteredSlideIndices[filteredIndex]);
                 }
             }
 
@@ -1112,17 +2022,12 @@
                 };
 
                 cmButton(ColorMode::kLegacy, "Legacy 8888");
-                cmButton(ColorMode::kColorManagedSRGB8888_NonLinearBlending,
-                         "Color Managed 8888 (Nonlinear blending)");
-                cmButton(ColorMode::kColorManagedSRGB8888, "Color Managed 8888");
-                cmButton(ColorMode::kColorManagedLinearF16, "Color Managed F16");
+                cmButton(ColorMode::kColorManaged8888, "Color Managed 8888");
+                cmButton(ColorMode::kColorManagedF16, "Color Managed F16");
+                cmButton(ColorMode::kColorManagedF16Norm, "Color Managed F16 Norm");
 
                 if (newMode != fColorMode) {
-                    // It isn't safe to switch color mode now (in the middle of painting). We might
-                    // tear down the back-end, etc... Defer this change until the next onIdle.
-                    fDeferredActions.push_back([=]() {
-                        this->setColorMode(newMode);
-                    });
+                    this->setColorMode(newMode);
                 }
 
                 // Pick from common gamuts:
@@ -1134,6 +2039,9 @@
                     }
                 }
 
+                // Let user adjust the gamma
+                ImGui::SliderFloat("Gamma", &fColorSpaceTransferFn.g, 0.5f, 3.5f);
+
                 if (ImGui::Combo("Primaries", &primariesIdx,
                                  "sRGB\0AdobeRGB\0P3\0Rec. 2020\0Custom\0\0")) {
                     if (primariesIdx >= 0 && primariesIdx <= 3) {
@@ -1144,6 +2052,142 @@
                 // Allow direct editing of gamut
                 ImGui_Primaries(&fColorSpacePrimaries, &fImGuiGamutPaint);
             }
+
+            if (ImGui::CollapsingHeader("Animation")) {
+                bool isPaused = AnimTimer::kPaused_State == fAnimTimer.state();
+                if (ImGui::Checkbox("Pause", &isPaused)) {
+                    fAnimTimer.togglePauseResume();
+                }
+
+                float speed = fAnimTimer.getSpeed();
+                if (ImGui::DragFloat("Speed", &speed, 0.1f)) {
+                    fAnimTimer.setSpeed(speed);
+                }
+            }
+
+            bool backendIsGL = Window::kNativeGL_BackendType == fBackendType
+#if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
+                            || Window::kANGLE_BackendType == fBackendType
+#endif
+                ;
+
+            // HACK: If we get here when SKSL caching isn't enabled, and we're on a backend other
+            // than GL, we need to force it on. Just do that on the first frame after the backend
+            // switch, then resume normal operation.
+            if (!backendIsGL &&
+                params.fGrContextOptions.fShaderCacheStrategy !=
+                        GrContextOptions::ShaderCacheStrategy::kSkSL) {
+                params.fGrContextOptions.fShaderCacheStrategy =
+                        GrContextOptions::ShaderCacheStrategy::kSkSL;
+                paramsChanged = true;
+                fPersistentCache.reset();
+            } else if (ImGui::CollapsingHeader("Shaders")) {
+                // To re-load shaders from the currently active programs, we flush all caches on one
+                // frame, then set a flag to poll the cache on the next frame.
+                static bool gLoadPending = false;
+                if (gLoadPending) {
+                    auto collectShaders = [this](sk_sp<const SkData> key, sk_sp<SkData> data,
+                                                 int hitCount) {
+                        CachedGLSL& entry(fCachedGLSL.push_back());
+                        entry.fKey = key;
+                        SkMD5 hash;
+                        hash.write(key->bytes(), key->size());
+                        SkMD5::Digest digest = hash.finish();
+                        for (int i = 0; i < 16; ++i) {
+                            entry.fKeyString.appendf("%02x", digest.data[i]);
+                        }
+
+                        SkReader32 reader(data->data(), data->size());
+                        entry.fShaderType = reader.readU32();
+                        GrPersistentCacheUtils::UnpackCachedShaders(&reader, entry.fShader,
+                                                                    entry.fInputs,
+                                                                    kGrShaderTypeCount);
+                    };
+                    fCachedGLSL.reset();
+                    fPersistentCache.foreach(collectShaders);
+                    gLoadPending = false;
+                }
+
+                // Defer actually doing the load/save logic so that we can trigger a save when we
+                // start or finish hovering on a tree node in the list below:
+                bool doLoad = ImGui::Button("Load"); ImGui::SameLine();
+                bool doSave = ImGui::Button("Save");
+                if (backendIsGL) {
+                    ImGui::SameLine();
+                    bool sksl = params.fGrContextOptions.fShaderCacheStrategy ==
+                                GrContextOptions::ShaderCacheStrategy::kSkSL;
+                    if (ImGui::Checkbox("SkSL", &sksl)) {
+                        params.fGrContextOptions.fShaderCacheStrategy = sksl
+                                ? GrContextOptions::ShaderCacheStrategy::kSkSL
+                                : GrContextOptions::ShaderCacheStrategy::kBackendSource;
+                        paramsChanged = true;
+                        doLoad = true;
+                        fDeferredActions.push_back([=]() { fPersistentCache.reset(); });
+                    }
+                }
+
+                ImGui::BeginChild("##ScrollingRegion");
+                for (auto& entry : fCachedGLSL) {
+                    bool inTreeNode = ImGui::TreeNode(entry.fKeyString.c_str());
+                    bool hovered = ImGui::IsItemHovered();
+                    if (hovered != entry.fHovered) {
+                        // Force a save to patch the highlight shader in/out
+                        entry.fHovered = hovered;
+                        doSave = true;
+                    }
+                    if (inTreeNode) {
+                        // Full width, and a reasonable amount of space for each shader.
+                        ImVec2 boxSize(-1.0f, ImGui::GetTextLineHeight() * 20.0f);
+                        ImGui::InputTextMultiline("##VP", &entry.fShader[kVertex_GrShaderType],
+                                                  boxSize);
+                        ImGui::InputTextMultiline("##FP", &entry.fShader[kFragment_GrShaderType],
+                                                  boxSize);
+                        ImGui::TreePop();
+                    }
+                }
+                ImGui::EndChild();
+
+                if (doLoad) {
+                    fPersistentCache.reset();
+                    fWindow->getGrContext()->priv().getGpu()->resetShaderCacheForTesting();
+                    gLoadPending = true;
+                }
+                if (doSave) {
+                    // The hovered item (if any) gets a special shader to make it identifiable
+                    auto shaderCaps = ctx->priv().caps()->shaderCaps();
+                    bool sksl = params.fGrContextOptions.fShaderCacheStrategy ==
+                                GrContextOptions::ShaderCacheStrategy::kSkSL;
+
+                    SkSL::String highlight;
+                    if (!sksl) {
+                        highlight = shaderCaps->versionDeclString();
+                        if (shaderCaps->usesPrecisionModifiers()) {
+                            highlight.append("precision mediump float;\n");
+                        }
+                    }
+                    const char* f4Type = sksl ? "half4" : "vec4";
+                    highlight.appendf("out %s sk_FragColor;\n"
+                                      "void main() { sk_FragColor = %s(1, 0, 1, 0.5); }",
+                                      f4Type, f4Type);
+
+                    fPersistentCache.reset();
+                    fWindow->getGrContext()->priv().getGpu()->resetShaderCacheForTesting();
+                    for (auto& entry : fCachedGLSL) {
+                        SkSL::String backup = entry.fShader[kFragment_GrShaderType];
+                        if (entry.fHovered) {
+                            entry.fShader[kFragment_GrShaderType] = highlight;
+                        }
+
+                        auto data = GrPersistentCacheUtils::PackCachedShaders(entry.fShaderType,
+                                                                              entry.fShader,
+                                                                              entry.fInputs,
+                                                                              kGrShaderTypeCount);
+                        fPersistentCache.store(*entry.fKey, *data);
+
+                        entry.fShader[kFragment_GrShaderType] = backup;
+                    }
+                }
+            }
         }
         if (paramsChanged) {
             fDeferredActions.push_back([=]() {
@@ -1155,80 +2199,65 @@
         ImGui::End();
     }
 
-    SkPaint zoomImagePaint;
+    if (gShaderErrorHandler.fErrors.count()) {
+        ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
+        ImGui::Begin("Shader Errors");
+        for (int i = 0; i < gShaderErrorHandler.fErrors.count(); ++i) {
+            ImGui::TextWrapped("%s", gShaderErrorHandler.fErrors[i].c_str());
+            ImGui::TextWrapped("%s", gShaderErrorHandler.fShaders[i].c_str());
+        }
+        ImGui::End();
+        gShaderErrorHandler.reset();
+    }
+
     if (fShowZoomWindow && fLastImage) {
-        if (ImGui::Begin("Zoom", &fShowZoomWindow, ImVec2(200, 200))) {
-            static int zoomFactor = 4;
-            ImGui::SliderInt("Scale", &zoomFactor, 1, 16);
+        ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiCond_FirstUseEver);
+        if (ImGui::Begin("Zoom", &fShowZoomWindow)) {
+            static int zoomFactor = 8;
+            if (ImGui::Button("<<")) {
+                zoomFactor = SkTMax(zoomFactor / 2, 4);
+            }
+            ImGui::SameLine(); ImGui::Text("%2d", zoomFactor); ImGui::SameLine();
+            if (ImGui::Button(">>")) {
+                zoomFactor = SkTMin(zoomFactor * 2, 32);
+            }
 
-            zoomImagePaint.setShader(fLastImage->makeShader());
-            zoomImagePaint.setColor(SK_ColorWHITE);
-
-            // Zoom by shrinking the corner UVs towards the mouse cursor
-            ImVec2 mousePos = ImGui::GetMousePos();
+            if (!fZoomWindowFixed) {
+                ImVec2 mousePos = ImGui::GetMousePos();
+                fZoomWindowLocation = SkPoint::Make(mousePos.x, mousePos.y);
+            }
+            SkScalar x = fZoomWindowLocation.x();
+            SkScalar y = fZoomWindowLocation.y();
+            int xInt = SkScalarRoundToInt(x);
+            int yInt = SkScalarRoundToInt(y);
             ImVec2 avail = ImGui::GetContentRegionAvail();
 
-            ImVec2 zoomHalfExtents = ImVec2((avail.x * 0.5f) / zoomFactor,
-                                            (avail.y * 0.5f) / zoomFactor);
-            ImGui::Image(&zoomImagePaint, avail,
-                         ImVec2(mousePos.x - zoomHalfExtents.x, mousePos.y - zoomHalfExtents.y),
-                         ImVec2(mousePos.x + zoomHalfExtents.x, mousePos.y + zoomHalfExtents.y));
+            uint32_t pixel = 0;
+            SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+            if (fLastImage->readPixels(info, &pixel, info.minRowBytes(), xInt, yInt)) {
+                ImGui::SameLine();
+                ImGui::Text("(X, Y): %d, %d RGBA: %X %X %X %X",
+                            xInt, yInt,
+                            SkGetPackedR32(pixel), SkGetPackedG32(pixel),
+                            SkGetPackedB32(pixel), SkGetPackedA32(pixel));
+            }
+
+            fImGuiLayer.skiaWidget(avail, [=](SkCanvas* c) {
+                // Translate so the region of the image that's under the mouse cursor is centered
+                // in the zoom canvas:
+                c->scale(zoomFactor, zoomFactor);
+                c->translate(avail.x * 0.5f / zoomFactor - x - 0.5f,
+                             avail.y * 0.5f / zoomFactor - y - 0.5f);
+                c->drawImage(this->fLastImage, 0, 0);
+
+                SkPaint outline;
+                outline.setStyle(SkPaint::kStroke_Style);
+                c->drawRect(SkRect::MakeXYWH(x, y, 1, 1), outline);
+            });
         }
 
         ImGui::End();
     }
-
-    // This causes ImGui to rebuild vertex/index data based on all immediate-mode commands
-    // (widgets, etc...) that have been issued
-    ImGui::Render();
-
-    // Then we fetch the most recent data, and convert it so we can render with Skia
-    const ImDrawData* drawData = ImGui::GetDrawData();
-    SkTDArray<SkPoint> pos;
-    SkTDArray<SkPoint> uv;
-    SkTDArray<SkColor> color;
-
-    for (int i = 0; i < drawData->CmdListsCount; ++i) {
-        const ImDrawList* drawList = drawData->CmdLists[i];
-
-        // De-interleave all vertex data (sigh), convert to Skia types
-        pos.rewind(); uv.rewind(); color.rewind();
-        for (int i = 0; i < drawList->VtxBuffer.size(); ++i) {
-            const ImDrawVert& vert = drawList->VtxBuffer[i];
-            pos.push(SkPoint::Make(vert.pos.x, vert.pos.y));
-            uv.push(SkPoint::Make(vert.uv.x, vert.uv.y));
-            color.push(vert.col);
-        }
-        // ImGui colors are RGBA
-        SkSwapRB(color.begin(), color.begin(), color.count());
-
-        int indexOffset = 0;
-
-        // Draw everything with canvas.drawVertices...
-        for (int j = 0; j < drawList->CmdBuffer.size(); ++j) {
-            const ImDrawCmd* drawCmd = &drawList->CmdBuffer[j];
-
-            // TODO: Find min/max index for each draw, so we know how many vertices (sigh)
-            if (drawCmd->UserCallback) {
-                drawCmd->UserCallback(drawList, drawCmd);
-            } else {
-                SkPaint* paint = static_cast<SkPaint*>(drawCmd->TextureId);
-                SkASSERT(paint);
-
-                canvas->save();
-                canvas->clipRect(SkRect::MakeLTRB(drawCmd->ClipRect.x, drawCmd->ClipRect.y,
-                                                  drawCmd->ClipRect.z, drawCmd->ClipRect.w));
-                canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode,
-                                                          drawList->VtxBuffer.size(), pos.begin(),
-                                                          uv.begin(), color.begin(),
-                                                          drawCmd->ElemCount,
-                                                          drawList->IdxBuffer.begin() + indexOffset),
-                                     SkBlendMode::kModulate, *paint);
-                indexOffset += drawCmd->ElemCount;
-                canvas->restore();
-            }
-        }
-    }
 }
 
 void Viewer::onIdle() {
@@ -1237,133 +2266,130 @@
     }
     fDeferredActions.reset();
 
-    double startTime = SkTime::GetMSecs();
+    fStatsLayer.beginTiming(fAnimateTimer);
     fAnimTimer.updateTime();
-    bool animateWantsInval = fSlides[fCurrentSlide]->animate(fAnimTimer);
-    fAnimateTimes[fCurrentMeasurement] = SkTime::GetMSecs() - startTime;
+    bool animateWantsInval = fSlides[fCurrentSlide]->animate(fAnimTimer.nanos());
+    fStatsLayer.endTiming(fAnimateTimer);
 
     ImGuiIO& io = ImGui::GetIO();
-    if (animateWantsInval || fDisplayStats || fRefresh || io.MetricsActiveWindows) {
+    // ImGui always has at least one "active" window, which is the default "Debug" window. It may
+    // not be visible, though. So we need to redraw if there is at least one visible window, or
+    // more than one active window. Newly created windows are active but not visible for one frame
+    // while they determine their layout and sizing.
+    if (animateWantsInval || fStatsLayer.getActive() || fRefresh ||
+        io.MetricsActiveWindows > 1 || io.MetricsRenderWindows > 0) {
         fWindow->inval();
     }
 }
 
+template <typename OptionsFunc>
+static void WriteStateObject(SkJSONWriter& writer, const char* name, const char* value,
+                             OptionsFunc&& optionsFunc) {
+    writer.beginObject();
+    {
+        writer.appendString(kName , name);
+        writer.appendString(kValue, value);
+
+        writer.beginArray(kOptions);
+        {
+            optionsFunc(writer);
+        }
+        writer.endArray();
+    }
+    writer.endObject();
+}
+
+
 void Viewer::updateUIState() {
     if (!fWindow) {
         return;
     }
-    if (fWindow->sampleCount() < 0) {
+    if (fWindow->sampleCount() < 1) {
         return; // Surface hasn't been created yet.
     }
 
+    SkDynamicMemoryWStream memStream;
+    SkJSONWriter writer(&memStream);
+    writer.beginArray();
+
     // Slide state
-    Json::Value slideState(Json::objectValue);
-    slideState[kName] = kSlideStateName;
-    slideState[kValue] = fSlides[fCurrentSlide]->getName().c_str();
-    if (fAllSlideNames.size() == 0) {
-        for(auto slide : fSlides) {
-            fAllSlideNames.append(Json::Value(slide->getName().c_str()));
-        }
-    }
-    slideState[kOptions] = fAllSlideNames;
+    WriteStateObject(writer, kSlideStateName, fSlides[fCurrentSlide]->getName().c_str(),
+        [this](SkJSONWriter& writer) {
+            for(const auto& slide : fSlides) {
+                writer.appendString(slide->getName().c_str());
+            }
+        });
 
     // Backend state
-    Json::Value backendState(Json::objectValue);
-    backendState[kName] = kBackendStateName;
-    backendState[kValue] = kBackendTypeStrings[fBackendType];
-    backendState[kOptions] = Json::Value(Json::arrayValue);
-    for (auto str : kBackendTypeStrings) {
-        backendState[kOptions].append(Json::Value(str));
-    }
+    WriteStateObject(writer, kBackendStateName, kBackendTypeStrings[fBackendType],
+        [](SkJSONWriter& writer) {
+            for (const auto& str : kBackendTypeStrings) {
+                writer.appendString(str);
+            }
+        });
 
     // MSAA state
-    Json::Value msaaState(Json::objectValue);
-    msaaState[kName] = kMSAAStateName;
-    msaaState[kValue] = fWindow->sampleCount();
-    msaaState[kOptions] = Json::Value(Json::arrayValue);
-    if (sk_app::Window::kRaster_BackendType == fBackendType) {
-        msaaState[kOptions].append(Json::Value(0));
-    } else {
-        for (int msaa : {0, 4, 8, 16}) {
-            msaaState[kOptions].append(Json::Value(msaa));
-        }
-    }
+    const auto countString = SkStringPrintf("%d", fWindow->sampleCount());
+    WriteStateObject(writer, kMSAAStateName, countString.c_str(),
+        [this](SkJSONWriter& writer) {
+            writer.appendS32(0);
+
+            if (sk_app::Window::kRaster_BackendType == fBackendType) {
+                return;
+            }
+
+            for (int msaa : {4, 8, 16}) {
+                writer.appendS32(msaa);
+            }
+        });
 
     // Path renderer state
     GpuPathRenderers pr = fWindow->getRequestedDisplayParams().fGrContextOptions.fGpuPathRenderers;
-    Json::Value prState(Json::objectValue);
-    prState[kName] = kPathRendererStateName;
-    prState[kValue] = gPathRendererNames[pr];
-    prState[kOptions] = Json::Value(Json::arrayValue);
-    const GrContext* ctx = fWindow->getGrContext();
-    if (!ctx) {
-        prState[kOptions].append("Software");
-    } else if (fWindow->sampleCount()) {
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kAll]);
-        if (ctx->caps()->shaderCaps()->pathRenderingSupport()) {
-            prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kStencilAndCover]);
-        }
-        if (ctx->caps()->sampleShadingSupport()) {
-            prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kMSAA]);
-        }
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kTessellating]);
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kDefault]);
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kNone]);
-    } else {
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kAll]);
-        if (GrCoverageCountingPathRenderer::IsSupported(*ctx->caps())) {
-            prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kCoverageCounting]);
-        }
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kSmall]);
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kTessellating]);
-        prState[kOptions].append(gPathRendererNames[GpuPathRenderers::kNone]);
-    }
+    WriteStateObject(writer, kPathRendererStateName, gPathRendererNames[pr].c_str(),
+        [this](SkJSONWriter& writer) {
+            const GrContext* ctx = fWindow->getGrContext();
+            if (!ctx) {
+                writer.appendString("Software");
+            } else {
+                const auto* caps = ctx->priv().caps();
 
-    // Instanced rendering state
-    Json::Value instState(Json::objectValue);
-    instState[kName] = kInstancedRenderingStateName;
-    if (ctx) {
-        if (fWindow->getRequestedDisplayParams().fGrContextOptions.fEnableInstancedRendering) {
-            instState[kValue] = kON;
-        } else {
-            instState[kValue] = kOFF;
-        }
-        instState[kOptions] = Json::Value(Json::arrayValue);
-        instState[kOptions].append(kOFF);
-        instState[kOptions].append(kON);
-    }
+                writer.appendString(gPathRendererNames[GpuPathRenderers::kAll].c_str());
+                if (fWindow->sampleCount() > 1) {
+                    if (caps->shaderCaps()->pathRenderingSupport()) {
+                        writer.appendString(
+                            gPathRendererNames[GpuPathRenderers::kStencilAndCover].c_str());
+                    }
+                } else {
+                    if(GrCoverageCountingPathRenderer::IsSupported(*caps)) {
+                        writer.appendString(
+                            gPathRendererNames[GpuPathRenderers::kCoverageCounting].c_str());
+                    }
+                    writer.appendString(gPathRendererNames[GpuPathRenderers::kSmall].c_str());
+                }
+                    writer.appendString(
+                        gPathRendererNames[GpuPathRenderers::kTessellating].c_str());
+                    writer.appendString(gPathRendererNames[GpuPathRenderers::kNone].c_str());
+            }
+        });
 
     // Softkey state
-    Json::Value softkeyState(Json::objectValue);
-    softkeyState[kName] = kSoftkeyStateName;
-    softkeyState[kValue] = kSoftkeyHint;
-    softkeyState[kOptions] = Json::Value(Json::arrayValue);
-    softkeyState[kOptions].append(kSoftkeyHint);
-    for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) {
-        softkeyState[kOptions].append(Json::Value(softkey.c_str()));
-    }
+    WriteStateObject(writer, kSoftkeyStateName, kSoftkeyHint,
+        [this](SkJSONWriter& writer) {
+            writer.appendString(kSoftkeyHint);
+            for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) {
+                writer.appendString(softkey.c_str());
+            }
+        });
 
-    // FPS state
-    Json::Value fpsState(Json::objectValue);
-    fpsState[kName] = kFpsStateName;
-    int idx = (fCurrentMeasurement + (kMeasurementCount - 1)) & (kMeasurementCount - 1);
-    fpsState[kValue] = SkStringPrintf("%8.3lf ms\n\nA %8.3lf\nP %8.3lf\nF%8.3lf",
-                                      fAnimateTimes[idx] + fPaintTimes[idx] + fFlushTimes[idx],
-                                      fAnimateTimes[idx],
-                                      fPaintTimes[idx],
-                                      fFlushTimes[idx]).c_str();
-    fpsState[kOptions] = Json::Value(Json::arrayValue);
+    writer.endArray();
+    writer.flush();
 
-    Json::Value state(Json::arrayValue);
-    state.append(slideState);
-    state.append(backendState);
-    state.append(msaaState);
-    state.append(prState);
-    state.append(instState);
-    state.append(softkeyState);
-    state.append(fpsState);
+    auto data = memStream.detachAsData();
 
-    fWindow->setUIState(state);
+    // TODO: would be cool to avoid this copy
+    const SkString cstring(static_cast<const char*>(data->data()), data->size());
+
+    fWindow->setUIState(cstring.c_str());
 }
 
 void Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateValue) {
@@ -1372,26 +2398,21 @@
     // For example, after slide change, updateUIState is called inside setupCurrentSlide;
     // after backend change, updateUIState is called in this function.
     if (stateName.equals(kSlideStateName)) {
-        int previousSlide = fCurrentSlide;
-        fCurrentSlide = 0;
-        for(auto slide : fSlides) {
-            if (slide->getName().equals(stateValue)) {
-                this->setupCurrentSlide(previousSlide);
-                break;
+        for (int i = 0; i < fSlides.count(); ++i) {
+            if (fSlides[i]->getName().equals(stateValue)) {
+                this->setCurrentSlide(i);
+                return;
             }
-            fCurrentSlide++;
         }
-        if (fCurrentSlide >= fSlides.count()) {
-            fCurrentSlide = previousSlide;
-            SkDebugf("Slide not found: %s", stateValue.c_str());
-        }
+
+        SkDebugf("Slide not found: %s", stateValue.c_str());
     } else if (stateName.equals(kBackendStateName)) {
         for (int i = 0; i < sk_app::Window::kBackendTypeCount; i++) {
             if (stateValue.equals(kBackendTypeStrings[i])) {
                 if (fBackendType != i) {
                     fBackendType = (sk_app::Window::BackendType)i;
                     fWindow->detach();
-                    fWindow->attach(fBackendType);
+                    fWindow->attach(backend_type_for_window(fBackendType));
                 }
                 break;
             }
@@ -1420,16 +2441,6 @@
                 break;
             }
         }
-    } else if (stateName.equals(kInstancedRenderingStateName)) {
-        DisplayParams params = fWindow->getRequestedDisplayParams();
-        bool value = !strcmp(stateValue.c_str(), kON);
-        if (params.fGrContextOptions.fEnableInstancedRendering != value) {
-            params.fGrContextOptions.fEnableInstancedRendering = value;
-            fWindow->setRequestedDisplayParams(params);
-            fWindow->inval();
-            this->updateTitle();
-            this->updateUIState();
-        }
     } else if (stateName.equals(kSoftkeyStateName)) {
         if (!stateValue.equals(kSoftkeyHint)) {
             fCommands.onSoftkey(stateValue);
@@ -1444,15 +2455,15 @@
     }
 }
 
-bool Viewer::onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers) {
+bool Viewer::onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) {
     return fCommands.onKey(key, state, modifiers);
 }
 
-bool Viewer::onChar(SkUnichar c, uint32_t modifiers) {
+bool Viewer::onChar(SkUnichar c, skui::ModifierKey modifiers) {
     if (fSlides[fCurrentSlide]->onChar(c)) {
         fWindow->inval();
         return true;
+    } else {
+        return fCommands.onChar(c, modifiers);
     }
-
-    return fCommands.onChar(c, modifiers);
 }
diff --git a/src/third_party/skia/tools/viewer/Viewer.h b/src/third_party/skia/tools/viewer/Viewer.h
index 1b68007..0549187 100644
--- a/src/third_party/skia/tools/viewer/Viewer.h
+++ b/src/third_party/skia/tools/viewer/Viewer.h
@@ -8,86 +8,155 @@
 #ifndef Viewer_DEFINED
 #define Viewer_DEFINED
 
-#include "sk_app/Application.h"
-#include "sk_app/CommandSet.h"
-#include "sk_app/Window.h"
-#include "gm.h"
-#include "SkAnimTimer.h"
-#include "SkTouchGesture.h"
-#include "Slide.h"
+#include "gm/gm.h"
+#include "include/core/SkExecutor.h"
+#include "include/core/SkFont.h"
+#include "src/core/SkScan.h"
+#include "src/sksl/SkSLString.h"
+#include "src/sksl/ir/SkSLProgram.h"
+#include "tools/gpu/MemoryCache.h"
+#include "tools/sk_app/Application.h"
+#include "tools/sk_app/CommandSet.h"
+#include "tools/sk_app/Window.h"
+#include "tools/viewer/AnimTimer.h"
+#include "tools/viewer/ImGuiLayer.h"
+#include "tools/viewer/Slide.h"
+#include "tools/viewer/StatsLayer.h"
+#include "tools/viewer/TouchGesture.h"
 
 class SkCanvas;
+class SkData;
 
-class Viewer : public sk_app::Application {
+class Viewer : public sk_app::Application, sk_app::Window::Layer {
 public:
     Viewer(int argc, char** argv, void* platformData);
     ~Viewer() override;
 
-    void onBackendCreated();
-    void onPaint(SkCanvas* canvas);
     void onIdle() override;
-    bool onTouch(intptr_t owner, sk_app::Window::InputState state, float x, float y);
-    bool onMouse(float x, float y, sk_app::Window::InputState state, uint32_t modifiers);
-    void onUIStateChanged(const SkString& stateName, const SkString& stateValue);
-    bool onKey(sk_app::Window::Key key, sk_app::Window::InputState state, uint32_t modifiers);
-    bool onChar(SkUnichar c, uint32_t modifiers);
 
+    void onBackendCreated() override;
+    void onPaint(SkSurface*) override;
+    void onResize(int width, int height) override;
+    bool onTouch(intptr_t owner, skui::InputState state, float x, float y) override;
+    bool onMouse(int x, int y, skui::InputState state, skui::ModifierKey modifiers) override;
+    void onUIStateChanged(const SkString& stateName, const SkString& stateValue) override;
+    bool onKey(skui::Key key, skui::InputState state, skui::ModifierKey modifiers) override;
+    bool onChar(SkUnichar c, skui::ModifierKey modifiers) override;
+    bool onPinch(skui::InputState state, float scale, float x, float y) override;
+    bool onFling(skui::InputState state) override;
+
+    struct SkFontFields {
+        bool fTypeface = false;
+        bool fSize = false;
+        SkScalar fSizeRange[2] = { 0, 20 };
+        bool fScaleX = false;
+        bool fSkewX = false;
+        bool fHinting = false;
+        bool fEdging = false;
+        bool fSubpixel = false;
+        bool fForceAutoHinting = false;
+        bool fEmbeddedBitmaps = false;
+        bool fLinearMetrics = false;
+        bool fEmbolden = false;
+        bool fBaselineSnap = false;
+    };
+    struct SkPaintFields {
+        bool fPathEffect = false;
+        bool fShader = false;
+        bool fMaskFilter = false;
+        bool fColorFilter = false;
+        bool fDrawLooper = false;
+        bool fImageFilter = false;
+
+        bool fColor = false;
+        bool fWidth = false;
+        bool fMiterLimit = false;
+        bool fBlendMode = false;
+
+        bool fAntiAlias = false;
+        bool fDither = false;
+        enum class AntiAliasState {
+            Alias,
+            Normal,
+            AnalyticAAEnabled,
+            AnalyticAAForced,
+        } fAntiAliasState = AntiAliasState::Alias;
+        const bool fOriginalSkUseAnalyticAA = gSkUseAnalyticAA;
+        const bool fOriginalSkForceAnalyticAA = gSkForceAnalyticAA;
+
+        bool fCapType = false;
+        bool fJoinType = false;
+        bool fStyle = false;
+        bool fFilterQuality = false;
+    };
 private:
     enum class ColorMode {
-        kLegacy,                                 // N32, no color management
-        kColorManagedSRGB8888_NonLinearBlending, // N32, sRGB transfer function, nonlinear blending
-        kColorManagedSRGB8888,                   // N32, sRGB transfer function, linear blending
-        kColorManagedLinearF16,                  // F16, linear transfer function, linear blending
+        kLegacy,                // 8888, no color management
+        kColorManaged8888,      // 8888 with color management
+        kColorManagedF16,       // F16 with color management
+        kColorManagedF16Norm,   // Normalized F16 with color management
     };
 
     void initSlides();
     void updateTitle();
     void setBackend(sk_app::Window::BackendType);
     void setColorMode(ColorMode);
-    void setStartupSlide();
-    void setupCurrentSlide(int previousSlide);
-    void listNames();
+    int startupSlide() const;
+    void setCurrentSlide(int);
+    void setupCurrentSlide();
+    void listNames() const;
 
     void updateUIState();
 
-    void drawSlide(SkCanvas* canvs);
-    void drawStats(SkCanvas* canvas);
-    void drawImGui(SkCanvas* canvas);
+    void drawSlide(SkSurface* surface);
+    void drawImGui();
 
     void changeZoomLevel(float delta);
+    void preTouchMatrixChanged();
+    SkMatrix computePreTouchMatrix();
+    SkMatrix computePerspectiveMatrix();
     SkMatrix computeMatrix();
+    SkPoint mapEvent(float x, float y);
 
     sk_app::Window*        fWindow;
 
-    static const int kMeasurementCount = 64;  // should be power of 2 for fast mod
-    double fPaintTimes[kMeasurementCount];
-    double fFlushTimes[kMeasurementCount];
-    double fAnimateTimes[kMeasurementCount];
-    int fCurrentMeasurement;
+    StatsLayer             fStatsLayer;
+    StatsLayer::Timer      fPaintTimer;
+    StatsLayer::Timer      fFlushTimer;
+    StatsLayer::Timer      fAnimateTimer;
 
-    SkAnimTimer            fAnimTimer;
+    AnimTimer              fAnimTimer;
     SkTArray<sk_sp<Slide>> fSlides;
     int                    fCurrentSlide;
 
-    bool                   fDisplayStats;
     bool                   fRefresh; // whether to continuously refresh for measuring render time
 
-    SkPaint                fImGuiFontPaint;
+    bool                   fSaveToSKP;
+    bool                   fShowSlideDimensions;
+
+    ImGuiLayer             fImGuiLayer;
     SkPaint                fImGuiGamutPaint;
     bool                   fShowImGuiDebugWindow;
+    bool                   fShowSlidePicker;
     bool                   fShowImGuiTestWindow;
 
     bool                   fShowZoomWindow;
+    bool                   fZoomWindowFixed;
+    SkPoint                fZoomWindowLocation;
     sk_sp<SkImage>         fLastImage;
+    bool                   fZoomUI;
 
     sk_app::Window::BackendType fBackendType;
 
     // Color properties for slide rendering
     ColorMode              fColorMode;
     SkColorSpacePrimaries  fColorSpacePrimaries;
+    skcms_TransferFunction fColorSpaceTransferFn;
 
     // transform data
     SkScalar               fZoomLevel;
+    SkScalar               fRotation;
+    SkVector               fOffset;
 
     sk_app::CommandSet     fCommands;
 
@@ -97,16 +166,45 @@
         kMouse,
     };
 
-    SkTouchGesture         fGesture;
+    TouchGesture           fGesture;
     GestureDevice          fGestureDevice;
 
     // identity unless the window initially scales the content to fit the screen.
     SkMatrix               fDefaultMatrix;
 
+    bool                   fTiled;
+    bool                   fDrawTileBoundaries;
+    SkSize                 fTileScale;
+
+    enum PerspectiveMode {
+        kPerspective_Off,
+        kPerspective_Real,
+        kPerspective_Fake,
+    };
+    PerspectiveMode        fPerspectiveMode;
+    SkPoint                fPerspectivePoints[4];
+
     SkTArray<std::function<void(void)>> fDeferredActions;
 
-    Json::Value            fAllSlideNames; // cache all slide names for fast updateUIState
-};
+    SkPaint fPaint;
+    SkPaintFields fPaintOverrides;
+    SkFont fFont;
+    SkFontFields fFontOverrides;
+    bool fPixelGeometryOverrides = false;
 
+    struct CachedGLSL {
+        bool                fHovered = false;
+
+        sk_sp<const SkData> fKey;
+        SkString            fKeyString;
+
+        SkFourByteTag         fShaderType;
+        SkSL::String          fShader[kGrShaderTypeCount];
+        SkSL::Program::Inputs fInputs[kGrShaderTypeCount];
+    };
+
+    sk_gpu_test::MemoryCache fPersistentCache;
+    SkTArray<CachedGLSL>     fCachedGLSL;
+};
 
 #endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/GLWindowContext.cpp b/src/third_party/skia/tools/viewer/sk_app/GLWindowContext.cpp
deleted file mode 100644
index 2f0d5dc..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/GLWindowContext.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBackendSurface.h"
-#include "GrContext.h"
-#include "GLWindowContext.h"
-
-#include "gl/GrGLDefines.h"
-#include "gl/GrGLUtil.h"
-
-#include "SkCanvas.h"
-#include "SkImage_Base.h"
-#include "SkMathPriv.h"
-#include "SkSurface.h"
-
-namespace sk_app {
-
-GLWindowContext::GLWindowContext(const DisplayParams& params)
-    : WindowContext(params)
-    , fBackendContext(nullptr)
-    , fSurface(nullptr) {
-    fDisplayParams.fMSAASampleCount = fDisplayParams.fMSAASampleCount ?
-                                      GrNextPow2(fDisplayParams.fMSAASampleCount) :
-                                      0;
-}
-
-void GLWindowContext::initializeContext() {
-    this->onInitializeContext();
-    SkASSERT(nullptr == fContext);
-
-    fBackendContext.reset(GrGLCreateNativeInterface());
-    fContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)fBackendContext.get(),
-                                 fDisplayParams.fGrContextOptions);
-    if (!fContext && fDisplayParams.fMSAASampleCount) {
-        fDisplayParams.fMSAASampleCount /= 2;
-        this->initializeContext();
-        return;
-    }
-
-    if (fContext) {
-        // We may not have real sRGB support (ANGLE, in particular), so check for
-        // that, and fall back to L32:
-        fPixelConfig = fContext->caps()->srgbSupport() && fDisplayParams.fColorSpace
-                       ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
-    } else {
-        fPixelConfig = kUnknown_GrPixelConfig;
-    }
-}
-
-void GLWindowContext::destroyContext() {
-    fSurface.reset(nullptr);
-
-    if (fContext) {
-        // in case we have outstanding refs to this guy (lua?)
-        fContext->abandonContext();
-        fContext->unref();
-        fContext = nullptr;
-    }
-
-    fBackendContext.reset(nullptr);
-
-    this->onDestroyContext();
-}
-
-sk_sp<SkSurface> GLWindowContext::getBackbufferSurface() {
-    if (nullptr == fSurface) {
-        if (fContext) {
-            GrGLFramebufferInfo fbInfo;
-            GrGLint buffer;
-            GR_GL_CALL(fBackendContext.get(), GetIntegerv(GR_GL_FRAMEBUFFER_BINDING,
-                                                          &buffer));
-            fbInfo.fFBOID = buffer;
-
-            GrBackendRenderTarget backendRT(fWidth,
-                                            fHeight,
-                                            fSampleCount,
-                                            fStencilBits,
-                                            fPixelConfig,
-                                            fbInfo);
-
-            fSurface = SkSurface::MakeFromBackendRenderTarget(fContext, backendRT,
-                                                              kBottomLeft_GrSurfaceOrigin,
-                                                              fDisplayParams.fColorSpace,
-                                                              &fSurfaceProps);
-        }
-    }
-
-    return fSurface;
-}
-
-void GLWindowContext::swapBuffers() {
-    this->onSwapBuffers();
-}
-
-void GLWindowContext::resize(int  w, int h) {
-    this->destroyContext();
-    this->initializeContext();
-}
-
-void GLWindowContext::setDisplayParams(const DisplayParams& params) {
-    this->destroyContext();
-    fDisplayParams = params;
-    this->initializeContext();
-}
-
-}   //namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.cpp b/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.cpp
deleted file mode 100644
index 261206c..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBackendSurface.h"
-#include "GrContext.h"
-#include "SkAutoMalloc.h"
-#include "SkSurface.h"
-#include "VulkanWindowContext.h"
-
-#include "vk/GrVkInterface.h"
-#include "vk/GrVkMemory.h"
-#include "vk/GrVkUtil.h"
-#include "vk/GrVkTypes.h"
-
-#ifdef VK_USE_PLATFORM_WIN32_KHR
-// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
-#undef CreateSemaphore
-#endif
-
-#define GET_PROC(F) f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
-#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
-
-namespace sk_app {
-
-VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
-                                         CreateVkSurfaceFn createVkSurface,
-                                         CanPresentFn canPresent)
-    : WindowContext(params)
-    , fCreateVkSurfaceFn(createVkSurface)
-    , fCanPresentFn(canPresent)
-    , fSurface(VK_NULL_HANDLE)
-    , fSwapchain(VK_NULL_HANDLE)
-    , fImages(nullptr)
-    , fImageLayouts(nullptr)
-    , fSurfaces(nullptr)
-    , fCommandPool(VK_NULL_HANDLE)
-    , fBackbuffers(nullptr) {
-    this->initializeContext();
-}
-
-void VulkanWindowContext::initializeContext() {
-    // any config code here (particularly for msaa)?
-    fBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
-                                                     &fPresentQueueIndex, fCanPresentFn));
-
-    if (!(fBackendContext->fExtensions & kKHR_surface_GrVkExtensionFlag) ||
-        !(fBackendContext->fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
-        fBackendContext.reset(nullptr);
-        return;
-    }
-
-    VkInstance instance = fBackendContext->fInstance;
-    VkDevice device = fBackendContext->fDevice;
-    GET_PROC(DestroySurfaceKHR);
-    GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
-    GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
-    GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
-    GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
-    GET_DEV_PROC(CreateSwapchainKHR);
-    GET_DEV_PROC(DestroySwapchainKHR);
-    GET_DEV_PROC(GetSwapchainImagesKHR);
-    GET_DEV_PROC(AcquireNextImageKHR);
-    GET_DEV_PROC(QueuePresentKHR);
-
-    fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext) fBackendContext.get(),
-                                 fDisplayParams.fGrContextOptions);
-
-    fSurface = fCreateVkSurfaceFn(instance);
-    if (VK_NULL_HANDLE == fSurface) {
-        fBackendContext.reset(nullptr);
-        return;
-    }
-
-    VkBool32 supported;
-    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice,
-                                                       fPresentQueueIndex, fSurface,
-                                                       &supported);
-    if (VK_SUCCESS != res) {
-        this->destroyContext();
-        return;
-    }
-
-    if (!this->createSwapchain(-1, -1, fDisplayParams)) {
-        this->destroyContext();
-        return;
-    }
-
-    // create presentQueue
-    vkGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue);
-}
-
-bool VulkanWindowContext::createSwapchain(int width, int height,
-                                          const DisplayParams& params) {
-    // check for capabilities
-    VkSurfaceCapabilitiesKHR caps;
-    VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
-                                                            fSurface, &caps);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    uint32_t surfaceFormatCount;
-    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
-                                              &surfaceFormatCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
-    VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
-    res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
-                                              &surfaceFormatCount, surfaceFormats);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    uint32_t presentModeCount;
-    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
-                                                   &presentModeCount, nullptr);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
-    VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
-    res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
-                                                   &presentModeCount, presentModes);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    VkExtent2D extent = caps.currentExtent;
-    // use the hints
-    if (extent.width == (uint32_t)-1) {
-        extent.width = width;
-        extent.height = height;
-    }
-
-    // clamp width; to protect us from broken hints
-    if (extent.width < caps.minImageExtent.width) {
-        extent.width = caps.minImageExtent.width;
-    } else if (extent.width > caps.maxImageExtent.width) {
-        extent.width = caps.maxImageExtent.width;
-    }
-    // clamp height
-    if (extent.height < caps.minImageExtent.height) {
-        extent.height = caps.minImageExtent.height;
-    } else if (extent.height > caps.maxImageExtent.height) {
-        extent.height = caps.maxImageExtent.height;
-    }
-
-    fWidth = (int)extent.width;
-    fHeight = (int)extent.height;
-
-    uint32_t imageCount = caps.minImageCount + 2;
-    if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
-        // Application must settle for fewer images than desired:
-        imageCount = caps.maxImageCount;
-    }
-
-    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                                   VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
-                                   VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-    SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-    SkASSERT(caps.supportedTransforms & caps.currentTransform);
-    SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
-                                             VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
-    VkCompositeAlphaFlagBitsKHR composite_alpha =
-        (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
-                                        VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
-                                        VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
-    // Pick our surface format. For now, just make sure it matches our sRGB request:
-    VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
-    VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
-    auto srgbColorSpace = SkColorSpace::MakeSRGB();
-    bool wantSRGB = srgbColorSpace == params.fColorSpace;
-    for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
-        GrPixelConfig config = GrVkFormatToPixelConfig(surfaceFormats[i].format);
-        if (kUnknown_GrPixelConfig != config &&
-            GrPixelConfigIsSRGB(config) == wantSRGB) {
-            surfaceFormat = surfaceFormats[i].format;
-            colorSpace = surfaceFormats[i].colorSpace;
-            break;
-        }
-    }
-    fDisplayParams = params;
-    fSampleCount = params.fMSAASampleCount;
-    fStencilBits = 8;
-
-    if (VK_FORMAT_UNDEFINED == surfaceFormat) {
-        return false;
-    }
-
-    // If mailbox mode is available, use it, as it is the lowest-latency non-
-    // tearing mode. If not, fall back to FIFO which is always available.
-    VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-    for (uint32_t i = 0; i < presentModeCount; ++i) {
-        // use mailbox
-        if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
-            mode = presentModes[i];
-            break;
-        }
-    }
-
-    VkSwapchainCreateInfoKHR swapchainCreateInfo;
-    memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
-    swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
-    swapchainCreateInfo.surface = fSurface;
-    swapchainCreateInfo.minImageCount = imageCount;
-    swapchainCreateInfo.imageFormat = surfaceFormat;
-    swapchainCreateInfo.imageColorSpace = colorSpace;
-    swapchainCreateInfo.imageExtent = extent;
-    swapchainCreateInfo.imageArrayLayers = 1;
-    swapchainCreateInfo.imageUsage = usageFlags;
-
-    uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex };
-    if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) {
-        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
-        swapchainCreateInfo.queueFamilyIndexCount = 2;
-        swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
-    } else {
-        swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
-        swapchainCreateInfo.queueFamilyIndexCount = 0;
-        swapchainCreateInfo.pQueueFamilyIndices = nullptr;
-    }
-
-    swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
-    swapchainCreateInfo.compositeAlpha = composite_alpha;
-    swapchainCreateInfo.presentMode = mode;
-    swapchainCreateInfo.clipped = true;
-    swapchainCreateInfo.oldSwapchain = fSwapchain;
-
-    res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
-    if (VK_SUCCESS != res) {
-        return false;
-    }
-
-    // destroy the old swapchain
-    if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
-        GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
-
-        this->destroyBuffers();
-
-        fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
-    }
-
-    this->createBuffers(swapchainCreateInfo.imageFormat);
-
-    return true;
-}
-
-void VulkanWindowContext::createBuffers(VkFormat format) {
-    fPixelConfig = GrVkFormatToPixelConfig(format);
-    SkASSERT(kUnknown_GrPixelConfig != fPixelConfig);
-
-    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr);
-    SkASSERT(fImageCount);
-    fImages = new VkImage[fImageCount];
-    fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages);
-
-    // set up initial image layouts and create surfaces
-    fImageLayouts = new VkImageLayout[fImageCount];
-    fSurfaces = new sk_sp<SkSurface>[fImageCount];
-    for (uint32_t i = 0; i < fImageCount; ++i) {
-        fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
-
-        GrVkImageInfo info;
-        info.fImage = fImages[i];
-        info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
-        info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-        info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-        info.fFormat = format;
-        info.fLevelCount = 1;
-
-        GrBackendTexture backendTex(fWidth, fHeight, info);
-
-        fSurfaces[i] = SkSurface::MakeFromBackendTextureAsRenderTarget(fContext, backendTex,
-                                                                       kTopLeft_GrSurfaceOrigin,
-                                                                       fSampleCount,
-                                                                       fDisplayParams.fColorSpace,
-                                                                       &fSurfaceProps);
-    }
-
-    // create the command pool for the command buffers
-    if (VK_NULL_HANDLE == fCommandPool) {
-        VkCommandPoolCreateInfo commandPoolInfo;
-        memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
-        commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
-        // this needs to be on the render queue
-        commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex;
-        commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
-                                              nullptr, &fCommandPool));
-    }
-
-    // set up the backbuffers
-    VkSemaphoreCreateInfo semaphoreInfo;
-    memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
-    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-    semaphoreInfo.pNext = nullptr;
-    semaphoreInfo.flags = 0;
-    VkCommandBufferAllocateInfo commandBuffersInfo;
-    memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
-    commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-    commandBuffersInfo.pNext = nullptr;
-    commandBuffersInfo.commandPool = fCommandPool;
-    commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-    commandBuffersInfo.commandBufferCount = 2;
-    VkFenceCreateInfo fenceInfo;
-    memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
-    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
-    fenceInfo.pNext = nullptr;
-    fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
-    // we create one additional backbuffer structure here, because we want to
-    // give the command buffers they contain a chance to finish before we cycle back
-    fBackbuffers = new BackbufferInfo[fImageCount + 1];
-    for (uint32_t i = 0; i < fImageCount + 1; ++i) {
-        fBackbuffers[i].fImageIndex = -1;
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
-                                            nullptr, &fBackbuffers[i].fAcquireSemaphore));
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
-                                            nullptr, &fBackbuffers[i].fRenderSemaphore));
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
-                                                   fBackbuffers[i].fTransitionCmdBuffers));
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
-                                        &fBackbuffers[i].fUsageFences[0]));
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
-                                        &fBackbuffers[i].fUsageFences[1]));
-    }
-    fCurrentBackbufferIndex = fImageCount;
-}
-
-void VulkanWindowContext::destroyBuffers() {
-
-    if (fBackbuffers) {
-        for (uint32_t i = 0; i < fImageCount + 1; ++i) {
-            GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                                WaitForFences(fBackendContext->fDevice, 2,
-                                              fBackbuffers[i].fUsageFences,
-                                              true, UINT64_MAX));
-            fBackbuffers[i].fImageIndex = -1;
-            GR_VK_CALL(fBackendContext->fInterface,
-                       DestroySemaphore(fBackendContext->fDevice,
-                                        fBackbuffers[i].fAcquireSemaphore,
-                                        nullptr));
-            GR_VK_CALL(fBackendContext->fInterface,
-                       DestroySemaphore(fBackendContext->fDevice,
-                                        fBackbuffers[i].fRenderSemaphore,
-                                        nullptr));
-            GR_VK_CALL(fBackendContext->fInterface,
-                       FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2,
-                                          fBackbuffers[i].fTransitionCmdBuffers));
-            GR_VK_CALL(fBackendContext->fInterface,
-                       DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0));
-            GR_VK_CALL(fBackendContext->fInterface,
-                       DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0));
-        }
-    }
-
-    delete[] fBackbuffers;
-    fBackbuffers = nullptr;
-
-    // Does this actually free the surfaces?
-    delete[] fSurfaces;
-    fSurfaces = nullptr;
-    delete[] fImageLayouts;
-    fImageLayouts = nullptr;
-    delete[] fImages;
-    fImages = nullptr;
-}
-
-VulkanWindowContext::~VulkanWindowContext() {
-    this->destroyContext();
-}
-
-void VulkanWindowContext::destroyContext() {
-    if (!fBackendContext.get()) {
-        return;
-    }
-
-    GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue));
-    GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
-
-    this->destroyBuffers();
-
-    if (VK_NULL_HANDLE != fCommandPool) {
-        GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice,
-                                                                   fCommandPool, nullptr));
-        fCommandPool = VK_NULL_HANDLE;
-    }
-
-    if (VK_NULL_HANDLE != fSwapchain) {
-        fDestroySwapchainKHR(fBackendContext->fDevice, fSwapchain, nullptr);
-        fSwapchain = VK_NULL_HANDLE;
-    }
-
-    if (VK_NULL_HANDLE != fSurface) {
-        fDestroySurfaceKHR(fBackendContext->fInstance, fSurface, nullptr);
-        fSurface = VK_NULL_HANDLE;
-    }
-
-    fContext->unref();
-
-    fBackendContext.reset(nullptr);
-}
-
-VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
-    SkASSERT(fBackbuffers);
-
-    ++fCurrentBackbufferIndex;
-    if (fCurrentBackbufferIndex > fImageCount) {
-        fCurrentBackbufferIndex = 0;
-    }
-
-    BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences,
-                                      true, UINT64_MAX));
-    return backbuffer;
-}
-
-sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
-    BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
-    SkASSERT(backbuffer);
-
-    // reset the fence
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
-    // semaphores should be in unsignaled state
-
-    // acquire the image
-    VkResult res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
-                                        backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
-                                        &backbuffer->fImageIndex);
-    if (VK_ERROR_SURFACE_LOST_KHR == res) {
-        // need to figure out how to create a new vkSurface without the platformData*
-        // maybe use attach somehow? but need a Window
-        return nullptr;
-    }
-    if (VK_ERROR_OUT_OF_DATE_KHR == res) {
-        // tear swapchain down and try again
-        if (!this->createSwapchain(-1, -1, fDisplayParams)) {
-            return nullptr;
-        }
-        backbuffer = this->getAvailableBackbuffer();
-        GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                            ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
-
-        // acquire the image
-        res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
-                                   backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
-                                   &backbuffer->fImageIndex);
-
-        if (VK_SUCCESS != res) {
-            return nullptr;
-        }
-    }
-
-    // set up layout transfer from initial to color attachment
-    VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
-    SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
-    VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
-                                        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
-                                        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
-                                  0 : VK_ACCESS_MEMORY_READ_BIT;
-    VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
-    VkImageMemoryBarrier imageMemoryBarrier = {
-        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // sType
-        NULL,                                     // pNext
-        srcAccessMask,                            // outputMask
-        dstAccessMask,                            // inputMask
-        layout,                                   // oldLayout
-        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
-        fPresentQueueIndex,                       // srcQueueFamilyIndex
-        fBackendContext->fGraphicsQueueIndex,     // dstQueueFamilyIndex
-        fImages[backbuffer->fImageIndex],         // image
-        { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
-    };
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
-    VkCommandBufferBeginInfo info;
-    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
-    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-    info.flags = 0;
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
-
-    GR_VK_CALL(fBackendContext->fInterface,
-               CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
-                                  srcStageMask, dstStageMask, 0,
-                                  0, nullptr,
-                                  0, nullptr,
-                                  1, &imageMemoryBarrier));
-
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
-
-    VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-    // insert the layout transfer into the queue and wait on the acquire
-    VkSubmitInfo submitInfo;
-    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-    submitInfo.waitSemaphoreCount = 1;
-    submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
-    submitInfo.pWaitDstStageMask = &waitDstStageFlags;
-    submitInfo.commandBufferCount = 1;
-    submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
-    submitInfo.signalSemaphoreCount = 0;
-
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
-                                    backbuffer->fUsageFences[0]));
-
-    GrVkImageInfo* imageInfo;
-    SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
-    surface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
-                                   SkSurface::kFlushRead_BackendHandleAccess);
-    imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
-    return sk_ref_sp(surface);
-}
-
-void VulkanWindowContext::swapBuffers() {
-
-    BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
-    GrVkImageInfo* imageInfo;
-    SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
-    surface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
-                                   SkSurface::kFlushRead_BackendHandleAccess);
-    // Check to make sure we never change the actually wrapped image
-    SkASSERT(imageInfo->fImage == fImages[backbuffer->fImageIndex]);
-
-    VkImageLayout layout = imageInfo->fImageLayout;
-    VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
-    VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-    VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
-    VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
-
-    VkImageMemoryBarrier imageMemoryBarrier = {
-        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // sType
-        NULL,                                     // pNext
-        srcAccessMask,                            // outputMask
-        dstAccessMask,                            // inputMask
-        layout,                                   // oldLayout
-        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,          // newLayout
-        fBackendContext->fGraphicsQueueIndex,     // srcQueueFamilyIndex
-        fPresentQueueIndex,                       // dstQueueFamilyIndex
-        fImages[backbuffer->fImageIndex],         // image
-        { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
-    };
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
-    VkCommandBufferBeginInfo info;
-    memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
-    info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-    info.flags = 0;
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
-    GR_VK_CALL(fBackendContext->fInterface,
-               CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
-                                  srcStageMask, dstStageMask, 0,
-                                  0, nullptr,
-                                  0, nullptr,
-                                  1, &imageMemoryBarrier));
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
-
-    fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
-    // insert the layout transfer into the queue and wait on the acquire
-    VkSubmitInfo submitInfo;
-    memset(&submitInfo, 0, sizeof(VkSubmitInfo));
-    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-    submitInfo.waitSemaphoreCount = 0;
-    submitInfo.pWaitDstStageMask = 0;
-    submitInfo.commandBufferCount = 1;
-    submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
-    submitInfo.signalSemaphoreCount = 1;
-    submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
-
-    GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
-                        QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
-                                    backbuffer->fUsageFences[1]));
-
-    // Submit present operation to present queue
-    const VkPresentInfoKHR presentInfo =
-    {
-        VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
-        NULL, // pNext
-        1, // waitSemaphoreCount
-        &backbuffer->fRenderSemaphore, // pWaitSemaphores
-        1, // swapchainCount
-        &fSwapchain, // pSwapchains
-        &backbuffer->fImageIndex, // pImageIndices
-        NULL // pResults
-    };
-
-    fQueuePresentKHR(fPresentQueue, &presentInfo);
-}
-
-}   //namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.h b/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.h
deleted file mode 100644
index 81e5f3d..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/VulkanWindowContext.h
+++ /dev/null
@@ -1,117 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef VulkanWindowContext_DEFINED
-#define VulkanWindowContext_DEFINED
-
-#include "SkTypes.h" // required to pull in any SkUserConfig defines
-
-#ifdef SK_VULKAN
-
-#include "vk/GrVkBackendContext.h"
-#include "WindowContext.h"
-
-class GrRenderTarget;
-
-namespace sk_app {
-
-class VulkanWindowContext : public WindowContext {
-public:
-    ~VulkanWindowContext() override;
-
-    sk_sp<SkSurface> getBackbufferSurface() override;
-    void swapBuffers() override;
-
-    bool isValid() override { return SkToBool(fBackendContext.get()); }
-
-    void resize(int w, int h) override {
-        this->createSwapchain(w, h, fDisplayParams);
-    }
-
-    void setDisplayParams(const DisplayParams& params) override {
-        this->destroyContext();
-        fDisplayParams = params;
-        this->initializeContext();
-    }
-
-    GrBackendContext getBackendContext() override {
-        return (GrBackendContext) fBackendContext.get();
-    }
-
-    /** Platform specific function that creates a VkSurfaceKHR for a window */
-    using CreateVkSurfaceFn = std::function<VkSurfaceKHR(VkInstance)>;
-    /** Platform specific function that determines whether presentation will succeed. */
-    using CanPresentFn = GrVkBackendContext::CanPresentFn;
-
-    VulkanWindowContext(const DisplayParams&, CreateVkSurfaceFn, CanPresentFn);
-
-private:
-    void initializeContext();
-    void destroyContext();
-
-    struct BackbufferInfo {
-        uint32_t        fImageIndex;          // image this is associated with
-        VkSemaphore     fAcquireSemaphore;    // we signal on this for acquisition of image
-        VkSemaphore     fRenderSemaphore;     // we wait on this for rendering to be done
-        VkCommandBuffer fTransitionCmdBuffers[2]; // to transition layout between present and render
-        VkFence         fUsageFences[2];      // used to ensure this data is no longer used on GPU
-    };
-
-    BackbufferInfo* getAvailableBackbuffer();
-    bool createSwapchain(int width, int height, const DisplayParams& params);
-    void createBuffers(VkFormat format);
-    void destroyBuffers();
-
-    sk_sp<const GrVkBackendContext> fBackendContext;
-
-    // simple wrapper class that exists only to initialize a pointer to NULL
-    template <typename FNPTR_TYPE> class VkPtr {
-    public:
-        VkPtr() : fPtr(NULL) {}
-        VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
-        operator FNPTR_TYPE() const { return fPtr; }
-    private:
-        FNPTR_TYPE fPtr;
-    };
-
-    // Create functions
-    CreateVkSurfaceFn fCreateVkSurfaceFn;
-    CanPresentFn      fCanPresentFn;
-
-    // WSI interface functions
-    VkPtr<PFN_vkDestroySurfaceKHR> fDestroySurfaceKHR;
-    VkPtr<PFN_vkGetPhysicalDeviceSurfaceSupportKHR> fGetPhysicalDeviceSurfaceSupportKHR;
-    VkPtr<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR> fGetPhysicalDeviceSurfaceCapabilitiesKHR;
-    VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> fGetPhysicalDeviceSurfaceFormatsKHR;
-    VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> fGetPhysicalDeviceSurfacePresentModesKHR;
-
-    VkPtr<PFN_vkCreateSwapchainKHR> fCreateSwapchainKHR;
-    VkPtr<PFN_vkDestroySwapchainKHR> fDestroySwapchainKHR;
-    VkPtr<PFN_vkGetSwapchainImagesKHR> fGetSwapchainImagesKHR;
-    VkPtr<PFN_vkAcquireNextImageKHR> fAcquireNextImageKHR;
-    VkPtr<PFN_vkQueuePresentKHR> fQueuePresentKHR;
-    VkPtr<PFN_vkCreateSharedSwapchainsKHR> fCreateSharedSwapchainsKHR;
-
-    VkSurfaceKHR      fSurface;
-    VkSwapchainKHR    fSwapchain;
-    uint32_t          fPresentQueueIndex;
-    VkQueue           fPresentQueue;
-
-    uint32_t               fImageCount;
-    VkImage*               fImages;         // images in the swapchain
-    VkImageLayout*         fImageLayouts;   // layouts of these images when not color attachment
-    sk_sp<SkSurface>*      fSurfaces;       // surfaces client renders to (may not be based on rts)
-    VkCommandPool          fCommandPool;
-    BackbufferInfo*        fBackbuffers;
-    uint32_t               fCurrentBackbufferIndex;
-};
-
-}   // namespace sk_app
-
-#endif // SK_VULKAN
-
-#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/Window.cpp b/src/third_party/skia/tools/viewer/sk_app/Window.cpp
deleted file mode 100644
index 9acea3f..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/Window.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#include "Window.h"
-
-#include "SkSurface.h"
-#include "SkCanvas.h"
-#include "WindowContext.h"
-
-namespace sk_app {
-
-static void default_backend_created_func(void* userData) {}
-
-static bool default_char_func(SkUnichar c, uint32_t modifiers, void* userData) {
-    return false;
-}
-
-static bool default_key_func(Window::Key key, Window::InputState state, uint32_t modifiers, 
-                             void* userData) {
-    return false;
-}
-
-static bool default_mouse_func(int x, int y, Window::InputState state, uint32_t modifiers, 
-                               void* userData) {
-    return false;
-}
-
-static bool default_mouse_wheel_func(float delta, uint32_t modifiers, void* userData) {
-    return false;
-}
-
-static bool default_touch_func(intptr_t owner, Window::InputState state, float x, float y,
-                               void* userData) {
-    return false;
-}
-
-static void default_ui_state_changed_func(
-        const SkString& stateName, const SkString& stateValue, void* userData) {}
-
-static void default_paint_func(SkCanvas*, void* userData) {}
-
-Window::Window() : fBackendCreatedFunc(default_backend_created_func)
-                 , fCharFunc(default_char_func)
-                 , fKeyFunc(default_key_func)
-                 , fMouseFunc(default_mouse_func)
-                 , fMouseWheelFunc(default_mouse_wheel_func)
-                 , fTouchFunc(default_touch_func)
-                 , fUIStateChangedFunc(default_ui_state_changed_func)
-                 , fPaintFunc(default_paint_func) {
-}
-
-void Window::detach() {
-    delete fWindowContext;
-    fWindowContext = nullptr;
-}
-
-void Window::onBackendCreated() {
-    fBackendCreatedFunc(fBackendCreatedUserData);
-}
-
-bool Window::onChar(SkUnichar c, uint32_t modifiers) {
-    return fCharFunc(c, modifiers, fCharUserData);
-}
-
-bool Window::onKey(Key key, InputState state, uint32_t modifiers) {
-    return fKeyFunc(key, state, modifiers, fKeyUserData);
-}
-
-bool Window::onMouse(int x, int y, InputState state, uint32_t modifiers) {
-    return fMouseFunc(x, y, state, modifiers, fMouseUserData);
-}
-
-bool Window::onMouseWheel(float delta, uint32_t modifiers) {
-    return fMouseWheelFunc(delta, modifiers, fMouseWheelUserData);
-}
-
-bool Window::onTouch(intptr_t owner, InputState state, float x, float y) {
-    return fTouchFunc(owner, state, x, y, fTouchUserData);
-}
-
-void Window::onUIStateChanged(const SkString& stateName, const SkString& stateValue) {
-    return fUIStateChangedFunc(stateName, stateValue, fUIStateChangedUserData);
-}
-
-void Window::onPaint() {
-    if (!fWindowContext) {
-        return;
-    }
-    markInvalProcessed();
-    sk_sp<SkSurface> backbuffer = fWindowContext->getBackbufferSurface();
-    if (backbuffer) {
-        // draw into the canvas of this surface
-        SkCanvas* canvas = backbuffer->getCanvas();
-
-        fPaintFunc(canvas, fPaintUserData);
-
-        canvas->flush();
-
-        fWindowContext->swapBuffers();
-    } else {
-        printf("no backbuffer!?\n");
-        // try recreating testcontext
-    }
-}
-
-void Window::onResize(int w, int h) {
-    if (!fWindowContext) {
-        return;
-    }
-    fWindowContext->resize(w, h);
-}
-
-int Window::width() {
-    if (!fWindowContext) {
-        return 0;
-    }
-    return fWindowContext->width();
-}
-
-int Window::height() {
-    if (!fWindowContext) {
-        return 0;
-    }
-    return fWindowContext->height();
-}
-
-void Window::setRequestedDisplayParams(const DisplayParams& params, bool /* allowReattach */) {
-    fRequestedDisplayParams = params;
-    if (fWindowContext) {
-        fWindowContext->setDisplayParams(fRequestedDisplayParams);
-    }
-}
-
-int Window::sampleCount() const {
-    if (!fWindowContext) {
-        return -1;
-    }
-    return fWindowContext->sampleCount();
-}
-
-int Window::stencilBits() const {
-    if (!fWindowContext) {
-        return -1;
-    }
-    return fWindowContext->stencilBits();
-}
-
-const GrContext* Window::getGrContext() const {
-    if (!fWindowContext) {
-        return nullptr;
-    }
-    return fWindowContext->getGrContext();
-}
-
-void Window::inval() {
-    if (!fWindowContext) {
-        return;
-    }
-    if (!fIsContentInvalidated) {
-        fIsContentInvalidated = true;
-        onInval();
-    }
-}
-
-void Window::markInvalProcessed() {
-    fIsContentInvalidated = false;
-}
-
-}   // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/Window.h b/src/third_party/skia/tools/viewer/sk_app/Window.h
deleted file mode 100644
index 7d0c097..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/Window.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#ifndef Window_DEFINED
-#define Window_DEFINED
-
-#include "DisplayParams.h"
-#include "SkRect.h"
-#include "SkTouchGesture.h"
-#include "SkTypes.h"
-#include "SkJSONCPP.h"
-
-class GrContext;
-class SkCanvas;
-class SkSurface;
-
-namespace sk_app {
-
-class WindowContext;
-
-class Window {
-public:
-    static Window* CreateNativeWindow(void* platformData);
-
-    virtual ~Window() { this->detach(); }
-
-    virtual void setTitle(const char*) = 0;
-    virtual void show() = 0;
-    virtual void setUIState(const Json::Value& state) {}  // do nothing in default
-
-    // Shedules an invalidation event for window if one is not currently pending.
-    // Make sure that either onPaint or markInvalReceived is called when the client window consumes
-    // the the inval event. They unset fIsContentInvalided which allow future onInval.
-    void inval();
-
-    virtual bool scaleContentToFit() const { return false; }
-
-    enum BackendType {
-        kNativeGL_BackendType,
-#ifdef SK_VULKAN
-        kVulkan_BackendType,
-#endif
-        kRaster_BackendType,
-
-        kLast_BackendType = kRaster_BackendType
-    };
-    enum {
-        kBackendTypeCount = kLast_BackendType + 1
-    };
-
-    virtual bool attach(BackendType) = 0;
-    void detach();
-
-    // input handling
-    enum class Key {
-        kNONE,    //corresponds to android's UNKNOWN
-
-        kLeftSoftKey,
-        kRightSoftKey,
-
-        kHome,    //!< the home key - added to match android
-        kBack,    //!< (CLR)
-        kSend,    //!< the green (talk) key
-        kEnd,     //!< the red key
-
-        k0,
-        k1,
-        k2,
-        k3,
-        k4,
-        k5,
-        k6,
-        k7,
-        k8,
-        k9,
-        kStar,    //!< the * key
-        kHash,    //!< the # key
-
-        kUp,
-        kDown,
-        kLeft,
-        kRight,
-
-        // Keys needed by ImGui
-        kTab,
-        kPageUp,
-        kPageDown,
-        kDelete,
-        kEscape,
-        kShift,
-        kCtrl,
-        kOption, // AKA Alt
-        kA,
-        kC,
-        kV,
-        kX,
-        kY,
-        kZ,
-
-        kOK,      //!< the center key
-
-        kVolUp,   //!< volume up    - match android
-        kVolDown, //!< volume down  - same
-        kPower,   //!< power button - same
-        kCamera,  //!< camera       - same
-
-        kLast = kCamera
-    };
-    static const int kKeyCount = static_cast<int>(Key::kLast) + 1;
-
-    enum ModifierKeys {
-        kShift_ModifierKey = 1 << 0,
-        kControl_ModifierKey = 1 << 1,
-        kOption_ModifierKey = 1 << 2,   // same as ALT
-        kCommand_ModifierKey = 1 << 3,
-        kFirstPress_ModifierKey = 1 << 4,
-    };
-
-    enum InputState {
-        kDown_InputState,
-        kUp_InputState,
-        kMove_InputState   // only valid for mouse
-    };
-
-    // return value of 'true' means 'I have handled this event'
-    typedef void(*OnBackendCreatedFunc)(void* userData);
-    typedef bool(*OnCharFunc)(SkUnichar c, uint32_t modifiers, void* userData);
-    typedef bool(*OnKeyFunc)(Key key, InputState state, uint32_t modifiers, void* userData);
-    typedef bool(*OnMouseFunc)(int x, int y, InputState state, uint32_t modifiers, void* userData);
-    typedef bool(*OnMouseWheelFunc)(float delta, uint32_t modifiers, void* userData);
-    typedef bool(*OnTouchFunc)(intptr_t owner, InputState state, float x, float y, void* userData);
-    typedef void(*OnUIStateChangedFunc)(
-            const SkString& stateName, const SkString& stateValue, void* userData);
-    typedef void(*OnPaintFunc)(SkCanvas*, void* userData);
-
-    void registerBackendCreatedFunc(OnBackendCreatedFunc func, void* userData) {
-        fBackendCreatedFunc = func;
-        fBackendCreatedUserData = userData;
-    }
-
-    void registerCharFunc(OnCharFunc func, void* userData) {
-        fCharFunc = func;
-        fCharUserData = userData;
-    }
-
-    void registerKeyFunc(OnKeyFunc func, void* userData) {
-        fKeyFunc = func;
-        fKeyUserData = userData;
-    }
-
-    void registerMouseFunc(OnMouseFunc func, void* userData) {
-        fMouseFunc = func;
-        fMouseUserData = userData;
-    }
-
-    void registerMouseWheelFunc(OnMouseWheelFunc func, void* userData) {
-        fMouseWheelFunc = func;
-        fMouseWheelUserData = userData;
-    }
-
-    void registerPaintFunc(OnPaintFunc func, void* userData) {
-        fPaintFunc = func;
-        fPaintUserData = userData;
-    }
-
-    void registerTouchFunc(OnTouchFunc func, void* userData) {
-        fTouchFunc = func;
-        fTouchUserData = userData;
-    }
-
-    void registerUIStateChangedFunc(OnUIStateChangedFunc func, void* userData) {
-        fUIStateChangedFunc = func;
-        fUIStateChangedUserData = userData;
-    }
-
-    void onBackendCreated();
-    bool onChar(SkUnichar c, uint32_t modifiers);
-    bool onKey(Key key, InputState state, uint32_t modifiers);
-    bool onMouse(int x, int y, InputState state, uint32_t modifiers);
-    bool onMouseWheel(float delta, uint32_t modifiers);
-    bool onTouch(intptr_t owner, InputState state, float x, float y);  // multi-owner = multi-touch
-    void onUIStateChanged(const SkString& stateName, const SkString& stateValue);
-    void onPaint();
-    void onResize(int width, int height);
-
-    int width();
-    int height();
-
-    virtual const DisplayParams& getRequestedDisplayParams() { return fRequestedDisplayParams; }
-    virtual void setRequestedDisplayParams(const DisplayParams&, bool allowReattach = true);
-
-    // Actual parameters in effect, obtained from the native window.
-    int sampleCount() const;
-    int stencilBits() const;
-
-    // Returns null if there is not a GPU backend or if the backend is not yet created.
-    const GrContext* getGrContext() const;
-
-protected:
-    Window();
-
-    OnBackendCreatedFunc   fBackendCreatedFunc;
-    void*                  fBackendCreatedUserData;
-    OnCharFunc             fCharFunc;
-    void*                  fCharUserData;
-    OnKeyFunc              fKeyFunc;
-    void*                  fKeyUserData;
-    OnMouseFunc            fMouseFunc;
-    void*                  fMouseUserData;
-    OnMouseWheelFunc       fMouseWheelFunc;
-    void*                  fMouseWheelUserData;
-    OnTouchFunc            fTouchFunc;
-    void*                  fTouchUserData;
-    OnUIStateChangedFunc   fUIStateChangedFunc;
-    void*                  fUIStateChangedUserData;
-    OnPaintFunc            fPaintFunc;
-    void*                  fPaintUserData;
-    DisplayParams          fRequestedDisplayParams;
-
-    WindowContext* fWindowContext = nullptr;
-
-    virtual void onInval() = 0;
-
-    // Uncheck fIsContentInvalided to allow future inval/onInval.
-    void markInvalProcessed();
-
-    bool fIsContentInvalidated = false;  // use this to avoid duplicate invalidate events
-};
-
-}   // namespace sk_app
-#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/android/VulkanWindowContext_android.cpp b/src/third_party/skia/tools/viewer/sk_app/android/VulkanWindowContext_android.cpp
deleted file mode 100644
index b50e152..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/android/VulkanWindowContext_android.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "WindowContextFactory_android.h"
-#include "../VulkanWindowContext.h"
-
-namespace sk_app {
-
-namespace window_context_factory {
-
-WindowContext* NewVulkanForAndroid(ANativeWindow* window, const DisplayParams& params) {
-    auto createVkSurface = [window] (VkInstance instance) -> VkSurfaceKHR {
-        PFN_vkCreateAndroidSurfaceKHR createAndroidSurfaceKHR =
-                (PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(instance,
-                                                                     "vkCreateAndroidSurfaceKHR");
-
-        if (!window) {
-            return VK_NULL_HANDLE;
-        }
-        VkSurfaceKHR surface;
-
-        VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
-        memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
-        surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
-        surfaceCreateInfo.pNext = nullptr;
-        surfaceCreateInfo.flags = 0;
-        surfaceCreateInfo.window = window;
-
-        VkResult res = createAndroidSurfaceKHR(instance, &surfaceCreateInfo,
-                                               nullptr, &surface);
-        return (VK_SUCCESS == res) ? surface : VK_NULL_HANDLE;
-    };
-
-    auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
-
-    WindowContext* ctx = new VulkanWindowContext(params, createVkSurface, canPresent);
-    if (!ctx->isValid()) {
-        delete ctx;
-        return nullptr;
-    }
-    return ctx;
-}
-
-}  // namespace window_context_factory
-}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/GLWindowContext_mac.cpp b/src/third_party/skia/tools/viewer/sk_app/mac/GLWindowContext_mac.cpp
deleted file mode 100644
index 5bdba64..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/GLWindowContext_mac.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "../GLWindowContext.h"
-#include "WindowContextFactory_mac.h"
-
-#include "SDL.h"
-
-#include <OpenGL/gl.h>
-
-using sk_app::DisplayParams;
-using sk_app::window_context_factory::MacWindowInfo;
-using sk_app::GLWindowContext;
-
-namespace {
-
-class GLWindowContext_mac : public GLWindowContext {
-public:
-    GLWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
-    
-    ~GLWindowContext_mac() override;
-    
-    void onSwapBuffers() override;
-    
-    void onInitializeContext() override;
-    void onDestroyContext() override;
-    
-private:
-    SDL_Window*   fWindow;
-    SDL_GLContext fGLContext;
-    
-    typedef GLWindowContext INHERITED;
-};
-
-GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params)
-    : INHERITED(params)
-    , fWindow(info.fWindow)
-    , fGLContext(nullptr) {
-
-    // any config code here (particularly for msaa)?
-
-    this->initializeContext();
-}
-
-GLWindowContext_mac::~GLWindowContext_mac() {
-    this->destroyContext();
-}
-
-void GLWindowContext_mac::onInitializeContext() {
-    SkASSERT(fWindow);
-
-    fGLContext = SDL_GL_CreateContext(fWindow);
-    if (!fGLContext) {
-        SkDebugf("%s\n", SDL_GetError());
-        return;
-    }
-
-    if (0 == SDL_GL_MakeCurrent(fWindow, fGLContext)) {
-        glClearStencil(0);
-        glClearColor(0, 0, 0, 0);
-        glStencilMask(0xffffffff);
-        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-
-        SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
-        SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
-
-        SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
-        glViewport(0, 0, fWidth, fHeight);
-    } else {
-        SkDebugf("MakeCurrent failed: %s\n", SDL_GetError());
-    }
-}
-
-void GLWindowContext_mac::onDestroyContext() {
-    if (!fWindow || !fGLContext) {
-        return;
-    }
-    SDL_GL_DeleteContext(fGLContext);
-    fGLContext = nullptr;
-}
-
-
-void GLWindowContext_mac::onSwapBuffers() {
-    if (fWindow && fGLContext) {
-        SDL_GL_SwapWindow(fWindow);
-    }
-}
-
-}  // anonymous namespace
-
-namespace sk_app {
-namespace window_context_factory {
-
-WindowContext* NewGLForMac(const MacWindowInfo& info, const DisplayParams& params) {
-    WindowContext* ctx = new GLWindowContext_mac(info, params);
-    if (!ctx->isValid()) {
-        delete ctx;
-        return nullptr;
-    }
-    return ctx;
-}
-
-}  // namespace window_context_factory
-}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp b/src/third_party/skia/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp
deleted file mode 100644
index a88ed13..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/RasterWindowContext_mac.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "../GLWindowContext.h"
-#include "SkCanvas.h"
-#include "SkColorFilter.h"
-#include "sk_tool_utils.h"
-#include "WindowContextFactory_mac.h"
-
-#include "SDL.h"
-
-#include <OpenGL/gl.h>
-
-using sk_app::DisplayParams;
-using sk_app::window_context_factory::MacWindowInfo;
-using sk_app::GLWindowContext;
-
-namespace {
-
-// We use SDL to support Mac windowing mainly for convenience's sake. However, it
-// does not allow us to support a purely raster backend because we have no hooks into
-// the NSWindow's drawRect: method. Hence we use GL to handle the update. Should we
-// want to avoid this, we will probably need to write our own windowing backend.
-
-class RasterWindowContext_mac : public GLWindowContext {
-public:
-    RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
-
-    ~RasterWindowContext_mac() override;
-
-    sk_sp<SkSurface> getBackbufferSurface() override;
-
-    void onSwapBuffers() override;
-
-    void onInitializeContext() override;
-    void onDestroyContext() override;
-
-private:
-    SDL_Window*   fWindow;
-    SDL_GLContext fGLContext;
-    sk_sp<SkSurface> fBackbufferSurface;
-
-    typedef GLWindowContext INHERITED;
-};
-
-RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
-                                                 const DisplayParams& params)
-    : INHERITED(params)
-    , fWindow(info.fWindow)
-    , fGLContext(nullptr) {
-
-    // any config code here (particularly for msaa)?
-
-    this->initializeContext();
-}
-
-RasterWindowContext_mac::~RasterWindowContext_mac() {
-    this->destroyContext();
-}
-
-void RasterWindowContext_mac::onInitializeContext() {
-    SkASSERT(fWindow);
-
-    fGLContext = SDL_GL_CreateContext(fWindow);
-    if (!fGLContext) {
-        SkDebugf("%s\n", SDL_GetError());
-        return;
-    }
-
-    if (0 == SDL_GL_MakeCurrent(fWindow, fGLContext)) {
-        glClearStencil(0);
-        glClearColor(0, 0, 0, 0);
-        glStencilMask(0xffffffff);
-        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-
-        SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
-        SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
-
-        SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
-        glViewport(0, 0, fWidth, fHeight);
-    } else {
-        SkDebugf("MakeCurrent failed: %s\n", SDL_GetError());
-    }
-
-    // make the offscreen image
-    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
-                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
-    fBackbufferSurface = SkSurface::MakeRaster(info);
-}
-
-void RasterWindowContext_mac::onDestroyContext() {
-    if (!fWindow || !fGLContext) {
-        return;
-    }
-    fBackbufferSurface.reset(nullptr);
-    SDL_GL_DeleteContext(fGLContext);
-    fGLContext = nullptr;
-}
-
-sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
-
-void RasterWindowContext_mac::onSwapBuffers() {
-    if (fWindow && fGLContext) {
-        // We made/have an off-screen surface. Get the contents as an SkImage:
-        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
-        
-        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
-        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
-        gpuCanvas->drawImage(snapshot, 0, 0);
-        gpuCanvas->flush();
-
-        SDL_GL_SwapWindow(fWindow);
-    }
-}
-
-}  // anonymous namespace
-
-namespace sk_app {
-namespace window_context_factory {
-
-WindowContext* NewRasterForMac(const MacWindowInfo& info, const DisplayParams& params) {
-    WindowContext* ctx = new RasterWindowContext_mac(info, params);
-    if (!ctx->isValid()) {
-        delete ctx;
-        return nullptr;
-    }
-    return ctx;
-}
-
-}  // namespace window_context_factory
-}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/WindowContextFactory_mac.h b/src/third_party/skia/tools/viewer/sk_app/mac/WindowContextFactory_mac.h
deleted file mode 100644
index 3adc68b..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/WindowContextFactory_mac.h
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef WindowContextFactory_mac_DEFINED
-#define WindowContextFactory_mac_DEFINED
-
-#include "SDL.h"
-
-namespace sk_app {
-
-class WindowContext;
-struct DisplayParams;
-
-namespace window_context_factory {
-
-struct MacWindowInfo {
-    SDL_Window*  fWindow;
-};
-
-inline WindowContext* NewVulkanForMac(const MacWindowInfo&, const DisplayParams&) {
-    // No Vulkan support on Mac.
-    return nullptr;
-}
-
-WindowContext* NewGLForMac(const MacWindowInfo&, const DisplayParams&);
-
-WindowContext* NewRasterForMac(const MacWindowInfo&, const DisplayParams&);
-
-}  // namespace window_context_factory
-
-}  // namespace sk_app
-
-#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.cpp b/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.cpp
deleted file mode 100644
index dff7ccb..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#include "SkUtils.h"
-#include "Timer.h"
-#include "WindowContextFactory_mac.h"
-#include "Window_mac.h"
-
-namespace sk_app {
-
-SkTDynamicHash<Window_mac, Uint32> Window_mac::gWindowMap;
-
-Window* Window::CreateNativeWindow(void*) {
-    Window_mac* window = new Window_mac();
-    if (!window->initWindow()) {
-        delete window;
-        return nullptr;
-    }
-
-    return window;
-}
-
-bool Window_mac::initWindow() {
-    if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
-        this->closeWindow();
-    }
-    // we already have a window
-    if (fWindow) {
-        return true;
-    } 
-
-    constexpr int initialWidth = 1280;
-    constexpr int initialHeight = 960;
-
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
-
-    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
-    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
-    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
-
-    SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
-
-    if (fRequestedDisplayParams.fMSAASampleCount > 0) {
-        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
-        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
-    } else {
-        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
-    }
-    // TODO: handle other display params
-
-    uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
-    fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-                               initialWidth, initialHeight, windowFlags);
-
-    if (!fWindow) {
-        return false;
-    }
-
-    fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount;
-
-    // add to hashtable of windows
-    fWindowID = SDL_GetWindowID(fWindow);
-    gWindowMap.add(this);
-
-    return true;
-}
-
-void Window_mac::closeWindow() {
-    if (fWindow) {
-        gWindowMap.remove(fWindowID);
-        SDL_DestroyWindow(fWindow);
-        fWindowID = 0;
-        fWindow = nullptr;
-    }
-}
-
-static Window::Key get_key(const SDL_Keysym& keysym) {
-    static const struct {
-        SDL_Keycode fSDLK;
-        Window::Key fKey;
-    } gPair[] = {
-        { SDLK_BACKSPACE, Window::Key::kBack },
-        { SDLK_CLEAR, Window::Key::kBack },
-        { SDLK_RETURN, Window::Key::kOK },
-        { SDLK_UP, Window::Key::kUp },
-        { SDLK_DOWN, Window::Key::kDown },
-        { SDLK_LEFT, Window::Key::kLeft },
-        { SDLK_RIGHT, Window::Key::kRight },
-        { SDLK_TAB, Window::Key::kTab },
-        { SDLK_PAGEUP, Window::Key::kPageUp },
-        { SDLK_PAGEDOWN, Window::Key::kPageDown },
-        { SDLK_HOME, Window::Key::kHome },
-        { SDLK_END, Window::Key::kEnd },
-        { SDLK_DELETE, Window::Key::kDelete },
-        { SDLK_ESCAPE, Window::Key::kEscape },
-        { SDLK_LSHIFT, Window::Key::kShift },
-        { SDLK_RSHIFT, Window::Key::kShift },
-        { SDLK_LCTRL, Window::Key::kCtrl },
-        { SDLK_RCTRL, Window::Key::kCtrl },
-        { SDLK_LALT, Window::Key::kOption },
-        { SDLK_LALT, Window::Key::kOption },
-        { 'A', Window::Key::kA },
-        { 'C', Window::Key::kC },
-        { 'V', Window::Key::kV },
-        { 'X', Window::Key::kX },
-        { 'Y', Window::Key::kY },
-        { 'Z', Window::Key::kZ },
-    };
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
-        if (gPair[i].fSDLK == keysym.sym) {
-            return gPair[i].fKey;
-        }
-    }
-    return Window::Key::kNONE;
-}
-
-static uint32_t get_modifiers(const SDL_Event& event) {
-    static const struct {
-        unsigned    fSDLMask;
-        unsigned    fSkMask;
-    } gModifiers[] = {
-        { KMOD_SHIFT, Window::kShift_ModifierKey },
-        { KMOD_CTRL,  Window::kControl_ModifierKey },
-        { KMOD_ALT,   Window::kOption_ModifierKey },
-    };
-
-    auto modifiers = 0;
-
-    switch (event.type) {
-        case SDL_KEYDOWN:
-            // fall through
-        case SDL_KEYUP: {
-            for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
-                if (event.key.keysym.mod & gModifiers[i].fSDLMask) {
-                    modifiers |= gModifiers[i].fSkMask;
-                }
-            }
-            if (0 == event.key.repeat) {
-                modifiers |= Window::kFirstPress_ModifierKey;
-            }
-            break;
-        }
-
-        default: {
-            SDL_Keymod mod = SDL_GetModState();
-            for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
-                if (mod & gModifiers[i].fSDLMask) {
-                    modifiers |= gModifiers[i].fSkMask;
-                }
-            }
-            break;
-        }
-    }
-    return modifiers;
-}
-
-bool Window_mac::HandleWindowEvent(const SDL_Event& event) {
-    Window_mac* win = gWindowMap.find(event.window.windowID);
-    if (win && win->handleEvent(event)) {
-        return true;
-    }
-
-    return false;
-}
-
-bool Window_mac::handleEvent(const SDL_Event& event) {
-    switch (event.type) {
-        case SDL_WINDOWEVENT:
-            if (SDL_WINDOWEVENT_EXPOSED == event.window.event) {
-                this->onPaint();
-            } else if (SDL_WINDOWEVENT_RESIZED == event.window.event) {
-                this->onResize(event.window.data1, event.window.data2);
-            }
-            break;
-
-        case SDL_MOUSEBUTTONDOWN:
-            if (event.button.button == SDL_BUTTON_LEFT) {
-                this->onMouse(event.button.x, event.button.y,
-                              Window::kDown_InputState, get_modifiers(event));
-            }
-            break;
-
-        case SDL_MOUSEBUTTONUP:
-            if (event.button.button == SDL_BUTTON_LEFT) {
-                this->onMouse(event.button.x, event.button.y,
-                              Window::kUp_InputState, get_modifiers(event));
-            }
-            break;
-
-        case SDL_MOUSEMOTION:
-            this->onMouse(event.motion.x, event.motion.y,
-                          Window::kMove_InputState, get_modifiers(event));
-            break;
-
-        case SDL_MOUSEWHEEL:
-            this->onMouseWheel(event.wheel.y, get_modifiers(event));
-            break;
-
-        case SDL_KEYDOWN: {
-            Window::Key key = get_key(event.key.keysym);
-            if (key != Window::Key::kNONE) {
-                if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
-                    if (event.key.keysym.sym == SDLK_ESCAPE) {
-                        return true;
-                    }
-                }
-            }
-        } break;
-
-        case SDL_KEYUP: {
-            Window::Key key = get_key(event.key.keysym);
-            if (key != Window::Key::kNONE) {
-                (void) this->onKey(key, Window::kUp_InputState,
-                                   get_modifiers(event));
-            }
-        } break;
-
-        case SDL_TEXTINPUT: {
-            const char* textIter = &event.text.text[0];
-            while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) {
-                (void) this->onChar(c, get_modifiers(event));
-            }
-        } break;
-
-        default:
-            break;
-    }
-
-    return false;
-}
-
-void Window_mac::setTitle(const char* title) {
-    SDL_SetWindowTitle(fWindow, title);
-}
-
-void Window_mac::show() {
-    SDL_ShowWindow(fWindow);
-}
-
-bool Window_mac::attach(BackendType attachType) {
-    this->initWindow();
-
-    window_context_factory::MacWindowInfo info;
-    info.fWindow = fWindow;
-    switch (attachType) {
-        case kRaster_BackendType:
-            fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
-            break;
-            
-        case kNativeGL_BackendType:
-        default:
-            fWindowContext = NewGLForMac(info, fRequestedDisplayParams);
-            break;
-    }
-    this->onBackendCreated();
-
-    return (SkToBool(fWindowContext));
-}
-
-void Window_mac::onInval() {
-    SDL_Event sdlevent;
-    sdlevent.type = SDL_WINDOWEVENT;
-    sdlevent.window.windowID = fWindowID;
-    sdlevent.window.event = SDL_WINDOWEVENT_EXPOSED;
-    SDL_PushEvent(&sdlevent);
-}
-
-}   // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.h b/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.h
deleted file mode 100644
index eb28ff4..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/Window_mac.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#ifndef Window_mac_DEFINED
-#define Window_mac_DEFINED
-
-#include "../Window.h"
-#include "SkChecksum.h"
-#include "SkTDynamicHash.h"
-
-#include "SDL.h"
-
-namespace sk_app {
-
-class Window_mac : public Window {
-public:
-    Window_mac()
-        : INHERITED()
-        , fWindow(nullptr)
-        , fWindowID(0)
-        , fMSAASampleCount(0) {}
-    ~Window_mac() override { this->closeWindow(); }
-
-    bool initWindow();
-
-    void setTitle(const char*) override;
-    void show() override;
-
-    bool attach(BackendType) override;
-
-    void onInval() override;
-
-    static bool HandleWindowEvent(const SDL_Event& event);
-
-    static const Uint32& GetKey(const Window_mac& w) {
-        return w.fWindowID;
-    }
-
-    static uint32_t Hash(const Uint32& winID) {
-        return winID;
-    }
-
-private:
-    bool handleEvent(const SDL_Event& event);
-
-    void closeWindow();
-
-    static SkTDynamicHash<Window_mac, Uint32> gWindowMap;
-
-    SDL_Window*  fWindow;
-    Uint32       fWindowID;
-    
-    int          fMSAASampleCount;
-    
-    typedef Window INHERITED;
-};
-
-}   // namespace sk_app
-
-#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/mac/main_mac.cpp b/src/third_party/skia/tools/viewer/sk_app/mac/main_mac.cpp
deleted file mode 100644
index b30a7ea..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/mac/main_mac.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#include "SkTypes.h"
-#include "SkTHash.h"
-#include "SDL.h"
-#include "Timer.h"
-#include "Window_mac.h"
-#include "../Application.h"
-
-using sk_app::Application;
-
-int main(int argc, char* argv[]) {
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
-        SkDebugf("Could not initialize SDL!\n");
-        return 1;
-    }
-
-    Application* app = Application::Create(argc, argv, nullptr);
-
-    SDL_Event event;
-    bool done = false;
-    while (!done) {
-        while (SDL_PollEvent(&event)) {
-            switch (event.type) {
-                // events handled by the windows
-                case SDL_WINDOWEVENT:
-                case SDL_MOUSEMOTION:
-                case SDL_MOUSEBUTTONDOWN:
-                case SDL_MOUSEBUTTONUP:
-                case SDL_MOUSEWHEEL:
-                case SDL_KEYDOWN:
-                case SDL_KEYUP:
-                case SDL_TEXTINPUT:
-                    done = sk_app::Window_mac::HandleWindowEvent(event);
-                    break;
-                    
-                case SDL_QUIT:
-                    done = true;
-                    break;
-                    
-                default:
-                    break;
-            }
-        }
-
-        app->onIdle();
-    }
-    delete app;
-
-    SDL_Quit();
-
-    return 0;
-}
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/GLWindowContext_unix.cpp b/src/third_party/skia/tools/viewer/sk_app/unix/GLWindowContext_unix.cpp
deleted file mode 100644
index ce2727e..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/unix/GLWindowContext_unix.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "../GLWindowContext.h"
-#include "WindowContextFactory_unix.h"
-
-#include <GL/gl.h>
-
-using sk_app::window_context_factory::XlibWindowInfo;
-using sk_app::DisplayParams;
-using sk_app::GLWindowContext;
-
-namespace {
-
-class GLWindowContext_xlib : public GLWindowContext {
-public:
-    GLWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
-    ~GLWindowContext_xlib() override;
-
-    void onSwapBuffers() override;
-
-    void onDestroyContext() override;
-
-protected:
-    void onInitializeContext() override;
-
-private:
-    GLWindowContext_xlib(void*, const DisplayParams&);
-
-    Display*     fDisplay;
-    XWindow      fWindow;
-    GLXFBConfig* fFBConfig;
-    XVisualInfo* fVisualInfo;
-    GLXContext   fGLContext;
-
-    typedef GLWindowContext INHERITED;
-};
-
-GLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo, const DisplayParams& params)
-        : INHERITED(params)
-        , fDisplay(winInfo.fDisplay)
-        , fWindow(winInfo.fWindow)
-        , fFBConfig(winInfo.fFBConfig)
-        , fVisualInfo(winInfo.fVisualInfo)
-        , fGLContext() {
-    fWidth = winInfo.fWidth;
-    fHeight = winInfo.fHeight;
-    this->initializeContext();
-}
-
-using CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
-
-void GLWindowContext_xlib::onInitializeContext() {
-    SkASSERT(fDisplay);
-    SkASSERT(!fGLContext);
-    // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
-    // created with this rather than glXCreateContext.
-    CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
-            (const GLubyte*)"glXCreateContextAttribsARB");
-    if (createContextAttribs && fFBConfig) {
-        // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
-        // have been removed).
-        for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
-            // Ganesh prefers a compatibility profile for possible NVPR support. However, RenderDoc
-            // requires a core profile. Edit this code to use RenderDoc.
-            for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
-                                GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
-                int attribs[] = {
-                        GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
-                        GLX_CONTEXT_PROFILE_MASK_ARB, profile,
-                        0
-                };
-                fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
-                if (fGLContext) {
-                    break;
-                }
-            }
-        }
-    }
-    if (!fGLContext) {
-        fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
-    }
-    if (!fGLContext) {
-        return;
-    }
-
-    if (glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
-        glClearStencil(0);
-        glClearColor(0, 0, 0, 0);
-        glStencilMask(0xffffffff);
-        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-
-        glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
-        glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
-
-        XWindow root;
-        int x, y;
-        unsigned int border_width, depth;
-        XGetGeometry(fDisplay, fWindow, &root, &x, &y,
-                     (unsigned int*)&fWidth, (unsigned int*)&fHeight, &border_width, &depth);
-        glViewport(0, 0, fWidth, fHeight);
-    }
-}
-
-GLWindowContext_xlib::~GLWindowContext_xlib() {
-    this->destroyContext();
-}
-
-void GLWindowContext_xlib::onDestroyContext() {
-    if (!fDisplay || !fGLContext) {
-        return;
-    }
-    glXMakeCurrent(fDisplay, None, nullptr);
-    glXDestroyContext(fDisplay, fGLContext);
-    fGLContext = nullptr;
-}
-
-void GLWindowContext_xlib::onSwapBuffers() {
-    if (fDisplay && fGLContext) {
-        glXSwapBuffers(fDisplay, fWindow);
-    }
-}
-
-}  // anonymous namespace
-
-namespace sk_app {
-
-namespace window_context_factory {
-
-WindowContext* NewGLForXlib(const XlibWindowInfo& winInfo, const DisplayParams& params) {
-    WindowContext* ctx = new GLWindowContext_xlib(winInfo, params);
-    if (!ctx->isValid()) {
-        delete ctx;
-        return nullptr;
-    }
-    return ctx;
-}
-
-}  // namespace window_context_factory
-
-}  // namespace sk_app
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/WindowContextFactory_unix.h b/src/third_party/skia/tools/viewer/sk_app/unix/WindowContextFactory_unix.h
deleted file mode 100644
index e6d033b..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/unix/WindowContextFactory_unix.h
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef WindowContextFactory_unix_DEFINED
-#define WindowContextFactory_unix_DEFINED
-
-#include <X11/Xlib.h>
-#include <GL/glx.h>
-typedef Window XWindow;
-
-namespace sk_app {
-
-class WindowContext;
-struct DisplayParams;
-
-namespace window_context_factory {
-
-struct XlibWindowInfo {
-    Display*     fDisplay;
-    XWindow      fWindow;
-    GLXFBConfig* fFBConfig;
-    XVisualInfo* fVisualInfo;
-    int          fWidth;
-    int          fHeight;
-};
-
-WindowContext* NewVulkanForXlib(const XlibWindowInfo&, const DisplayParams&);
-
-WindowContext* NewGLForXlib(const XlibWindowInfo&, const DisplayParams&);
-
-WindowContext* NewRasterForXlib(const XlibWindowInfo&, const DisplayParams&);
-
-}  // namespace window_context_factory
-
-}  // namespace sk_app
-
-#endif
diff --git a/src/third_party/skia/tools/viewer/sk_app/unix/main_unix.cpp b/src/third_party/skia/tools/viewer/sk_app/unix/main_unix.cpp
deleted file mode 100644
index beb3eda..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/unix/main_unix.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-
-* Copyright 2016 Google Inc.
-*
-* Use of this source code is governed by a BSD-style license that can be
-* found in the LICENSE file.
-*/
-
-#include "SkTypes.h"
-#include "SkTHash.h"
-#include "Timer.h"
-#include "Window_unix.h"
-#include "../Application.h"
-
-using sk_app::Application;
-
-void finishWindow(sk_app::Window_unix* win) {
-    win->finishResize();
-    win->finishPaint();
-}
-
-int main(int argc, char**argv) {
-
-    Display* display = XOpenDisplay(nullptr);
-
-    Application* app = Application::Create(argc, argv, (void*)display);
-
-    // Get the file descriptor for the X display
-    int x11_fd = ConnectionNumber(display);
-    int count = x11_fd + 1;
-
-    SkTHashSet<sk_app::Window_unix*> pendingWindows;
-    bool done = false;
-    while (!done) {
-        // Create a file description set containing x11_fd
-        fd_set in_fds;
-        FD_ZERO(&in_fds);
-        FD_SET(x11_fd, &in_fds);
-
-        // Set a sleep timer
-        struct timeval tv;
-        tv.tv_usec = 100;
-        tv.tv_sec = 0;
-
-        while (!XPending(display)) {
-            // Wait for an event on the file descriptor or for timer expiration
-            (void) select(count, &in_fds, NULL, NULL, &tv);
-        }
-
-        // Handle XEvents (if any) and flush the input
-        int count = XPending(display);
-        while (count-- && !done) {
-            XEvent event;
-            XNextEvent(display, &event);
-
-            sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window);
-            if (!win) {
-                continue;
-            }
-
-            // paint and resize events get collapsed
-            switch (event.type) {
-            case Expose:
-                win->markPendingPaint();
-                pendingWindows.add(win);
-                break;
-            case ConfigureNotify:
-                win->markPendingResize(event.xconfigurerequest.width,
-                                       event.xconfigurerequest.height);
-                pendingWindows.add(win);
-                break;
-            default:
-                if (win->handleEvent(event)) {
-                    done = true;
-                }
-                break;
-            } 
-        }
-        
-        pendingWindows.foreach(finishWindow);
-        if (pendingWindows.count() > 0) {
-            app->onIdle();
-        }
-        pendingWindows.reset();
-
-        XFlush(display);
-    }
-
-    delete app;
-
-    XCloseDisplay(display);
-
-    return 0;
-}
diff --git a/src/third_party/skia/tools/viewer/sk_app/win/WindowContextFactory_win.h b/src/third_party/skia/tools/viewer/sk_app/win/WindowContextFactory_win.h
deleted file mode 100644
index 4367492..0000000
--- a/src/third_party/skia/tools/viewer/sk_app/win/WindowContextFactory_win.h
+++ /dev/null
@@ -1,31 +0,0 @@
-
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef WindowContextFactory_win_DEFINED
-#define WindowContextFactory_win_DEFINED
-
-#include <Windows.h>
-
-namespace sk_app {
-
-class WindowContext;
-struct DisplayParams;
-
-namespace window_context_factory {
-
-WindowContext* NewVulkanForWin(HWND, const DisplayParams&);
-
-WindowContext* NewGLForWin(HWND, const DisplayParams&);
-
-WindowContext* NewRasterForWin(HWND, const DisplayParams&);
-
-}  // namespace window_context_factory
-
-}  // namespace sk_app
-
-#endif
diff --git a/src/third_party/skia/tools/whitelist_typefaces.cpp b/src/third_party/skia/tools/whitelist_typefaces.cpp
index 5cdfb6a..546dd96 100644
--- a/src/third_party/skia/tools/whitelist_typefaces.cpp
+++ b/src/third_party/skia/tools/whitelist_typefaces.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "SkGraphics.h"
+#include "include/core/SkGraphics.h"
 
 extern bool CheckChecksums();
 extern bool GenerateChecksums();
diff --git a/src/third_party/skia/tools/win_dbghelp.cpp b/src/third_party/skia/tools/win_dbghelp.cpp
index 7291f36..37e5f7f 100644
--- a/src/third_party/skia/tools/win_dbghelp.cpp
+++ b/src/third_party/skia/tools/win_dbghelp.cpp
@@ -5,8 +5,9 @@
  * found in the LICENSE file.
  */
 
-#include "windows.h"
-#include "win_dbghelp.h"
+#include <windows.h>
+#include "tools/win_dbghelp.h"
+
 #include <process.h>
 #include <string.h>
 #include <stdlib.h>
diff --git a/src/third_party/skia/tools/win_dbghelp.h b/src/third_party/skia/tools/win_dbghelp.h
index d334318..226249f 100644
--- a/src/third_party/skia/tools/win_dbghelp.h
+++ b/src/third_party/skia/tools/win_dbghelp.h
@@ -8,7 +8,7 @@
 #ifndef win_dbghelp_DEFINED
 #define win_dbghelp_DEFINED
 
-#ifdef SK_BUILD_FOR_WIN32
+#ifdef SK_BUILD_FOR_WIN
 
 #include <dbghelp.h>
 #include <shellapi.h>
@@ -30,6 +30,6 @@
 
 int GenerateDumpAndPrintCallstack(EXCEPTION_POINTERS* pExceptionPointers);
 
-#endif  // SK_BUILD_FOR_WIN32
+#endif  // SK_BUILD_FOR_WIN
 
 #endif  // win_dbghelp_DEFINED
diff --git a/src/third_party/skia/tools/win_lcid.cpp b/src/third_party/skia/tools/win_lcid.cpp
index 8cb7463..791f6bc 100644
--- a/src/third_party/skia/tools/win_lcid.cpp
+++ b/src/third_party/skia/tools/win_lcid.cpp
@@ -4,8 +4,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
-#include "windows.h"
-#include "stdio.h"
+#include <windows.h>
+#include <stdio.h>
 
 #define BUFFER_SIZE 512
 BOOL CALLBACK MyFuncLocaleEx(LPWSTR pStr, DWORD dwFlags, LPARAM lparam) {
diff --git a/src/third_party/skia/tools/xsan.blacklist b/src/third_party/skia/tools/xsan.blacklist
index a917e2d..df2b384 100644
--- a/src/third_party/skia/tools/xsan.blacklist
+++ b/src/third_party/skia/tools/xsan.blacklist
@@ -1,2 +1,15 @@
-# Suppress third_party/externals.  We mostly care about our own code.
-src:*third_party/externals*
+#if 0
+
+#  This file must be a no-op C #include header, and a valid *SAN blacklist file.
+#  Luckily, anything starting with # is a comment to *SAN blacklist files,
+#  and anything inside #if 0 is ignored by C.  Yippee!
+#
+#  If you want to type '*', type '.*' instead.  Don't make C comments!
+
+# libpng and zlib both dereference under-aligned pointers.
+# TODO: it'd be nice to tag these as [alignment] only but our Mac toolchain can't yet.
+# [alignment]
+src:.*third_party/externals/libpng/intel/filter_sse2_intrinsics.c
+src:.*third_party/externals/zlib/deflate.c
+
+#endif