integrated SkDebugCanvas JSON support with UrlDataManager
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1686143004

Review URL: https://codereview.chromium.org/1686143004
diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp
index 20ac994..f23c41a 100644
--- a/tools/debugger/SkDrawCommand.cpp
+++ b/tools/debugger/SkDrawCommand.cpp
@@ -24,8 +24,6 @@
 #include "SkValidatingReadBuffer.h"
 #include "SkWriteBuffer.h"
 
-#define SKDEBUGCANVAS_SEND_BINARIES               false
-
 #define SKDEBUGCANVAS_ATTRIBUTE_COMMAND           "command"
 #define SKDEBUGCANVAS_ATTRIBUTE_MATRIX            "matrix"
 #define SKDEBUGCANVAS_ATTRIBUTE_COORDS            "coords"
@@ -63,7 +61,7 @@
 #define SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE          "fillType"
 #define SKDEBUGCANVAS_ATTRIBUTE_VERBS             "verbs"
 #define SKDEBUGCANVAS_ATTRIBUTE_NAME              "name"
-#define SKDEBUGCANVAS_ATTRIBUTE_BYTES             "bytes"
+#define SKDEBUGCANVAS_ATTRIBUTE_DATA              "data"
 #define SKDEBUGCANVAS_ATTRIBUTE_SHADER            "shader"
 #define SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT        "pathEffect"
 #define SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER        "maskFilter"
@@ -155,7 +153,7 @@
 #define SKDEBUGCANVAS_FILTERQUALITY_MEDIUM        "medium"
 #define SKDEBUGCANVAS_FILTERQUALITY_HIGH          "high"
 
-typedef SkDrawCommand* (*FROM_JSON)(Json::Value);
+typedef SkDrawCommand* (*FROM_JSON)(Json::Value&, UrlDataManager&);
 
 // TODO(chudy): Refactor into non subclass model.
 
@@ -214,7 +212,7 @@
     return SkString(GetCommandString(fOpType));
 }
 
-Json::Value SkDrawCommand::toJSON() const {
+Json::Value SkDrawCommand::toJSON(UrlDataManager& urlDataManager) const {
     Json::Value result;
     result[SKDEBUGCANVAS_ATTRIBUTE_COMMAND] = this->GetCommandString(fOpType);
     return result;
@@ -222,7 +220,7 @@
 
 #define INSTALL_FACTORY(name) factories.set(SkString(GetCommandString(k ## name ##_OpType)), \
                                             (FROM_JSON) Sk ## name ## Command::fromJSON)
-SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command) {
+SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
     static SkTHashMap<SkString, FROM_JSON> factories;
     static bool initialized = false;
     if (!initialized) {
@@ -261,7 +259,7 @@
         SkDebugf("no JSON factory for '%s'\n", name.c_str());
         return nullptr;
     }
-    return (*factory)(command);
+    return (*factory)(command, urlDataManager);
 }
 
 namespace {
@@ -582,64 +580,55 @@
     }
 }
 
-static void encode_data(const void* data, size_t count, Json::Value* target) {
-    // just use a brain-dead JSON array for now, switch to base64 or something else smarter down the
-    // road
-    for (size_t i = 0; i < count; i++) {
-        target->append(((const uint8_t*)data)[i]);
-    }
+static void encode_data(const void* bytes, size_t count, const char* contentType, 
+                        UrlDataManager& urlDataManager, Json::Value* target) {
+    SkAutoTUnref<SkData> data(SkData::NewWithCopy(bytes, count));
+    SkString url = urlDataManager.addData(data, contentType);
+    *target = Json::Value(url.c_str());
 }
 
-static void flatten(const SkFlattenable* flattenable, Json::Value* target, bool sendBinaries) {
-    if (sendBinaries) {
-        SkWriteBuffer buffer;
-        flattenable->flatten(buffer);
-        void* data = sk_malloc_throw(buffer.bytesWritten());
-        buffer.writeToMemory(data);
-        Json::Value bytes;
-        encode_data(data, buffer.bytesWritten(), &bytes);
-        Json::Value jsonFlattenable;
-        jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName());
-        jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_BYTES] = bytes;
-        (*target) = jsonFlattenable;
-        sk_free(data);
-    } else {
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(flattenable->getTypeName());
-    }
+static void flatten(const SkFlattenable* flattenable, Json::Value* target, 
+                    UrlDataManager& urlDataManager) {
+    SkWriteBuffer 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;
+    (*target) = jsonFlattenable;
+    sk_free(data);
 }
 
 static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target, 
-                                          bool sendBinaries) {
-    if (sendBinaries) {
-        SkData* encoded = image.encode(SkImageEncoder::kPNG_Type, 100);
-        if (encoded == nullptr) {
-            // PNG encode doesn't necessarily support all color formats, convert to a different
-            // format
-            size_t rowBytes = 4 * image.width();
-            void* buffer = sk_malloc_throw(rowBytes * image.height());
-            SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(), 
-                                                    kN32_SkColorType, kPremul_SkAlphaType);
-            if (!image.readPixels(dstInfo, buffer, rowBytes, 0, 0)) {
-                SkDebugf("readPixels failed\n");
-                return false;
-            }
-            SkImage* converted = SkImage::NewRasterCopy(dstInfo, buffer, rowBytes);
-            encoded = converted->encode(SkImageEncoder::kPNG_Type, 100);
-            if (encoded == nullptr) {
-                SkDebugf("image encode failed\n");
-                return false;
-            }
-            sk_free(converted);
-            sk_free(buffer);
+                                          UrlDataManager& urlDataManager) {
+    SkData* encoded = image.encode(SkImageEncoder::kPNG_Type, 100);
+    if (encoded == nullptr) {
+        // PNG encode doesn't necessarily support all color formats, convert to a different
+        // format
+        size_t rowBytes = 4 * image.width();
+        void* buffer = sk_malloc_throw(rowBytes * image.height());
+        SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(), 
+                                                kN32_SkColorType, kPremul_SkAlphaType);
+        if (!image.readPixels(dstInfo, buffer, rowBytes, 0, 0)) {
+            SkDebugf("readPixels failed\n");
+            return false;
         }
-        Json::Value bytes;
-        encode_data(encoded->data(), encoded->size(), &bytes);
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_BYTES] = bytes;
-        encoded->unref();
-    } else {
-        SkString description = SkStringPrintf("%dx%d pixel image", image.width(), image.height());
-        (*target)[SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(description.c_str());
+        SkImage* converted = SkImage::NewRasterCopy(dstInfo, buffer, rowBytes);
+        encoded = converted->encode(SkImageEncoder::kPNG_Type, 100);
+        if (encoded == nullptr) {
+            SkDebugf("image encode failed\n");
+            return false;
+        }
+        sk_free(converted);
+        sk_free(buffer);
     }
+    Json::Value jsonData;
+    encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager, &jsonData);
+    (*target)[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
+    encoded->unref();
     return true;
 }
 
@@ -679,17 +668,21 @@
     }
 }
 
-// note that the caller is responsible for freeing the pointer
-static Json::ArrayIndex decode_data(Json::Value bytes, void** target) {
-    Json::ArrayIndex size = bytes.size();
-    *target = sk_malloc_throw(size);
-    for (Json::ArrayIndex i = 0; i < size; i++) {
-        ((uint8_t*) *target)[i] = bytes[i].asInt();
+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;
     }
-    return size;
+    *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) {
+static SkFlattenable* load_flattenable(Json::Value jsonFlattenable, 
+                                       UrlDataManager& urlDataManager) {
     if (!jsonFlattenable.isMember(SKDEBUGCANVAS_ATTRIBUTE_NAME)) {
         return nullptr;
     }
@@ -699,11 +692,10 @@
         SkDebugf("no factory for loading '%s'\n", name);
         return nullptr;
     }
-    void* data;
-    int size = decode_data(jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_BYTES], &data);
+    const void* data;
+    int size = decode_data(jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
     SkValidatingReadBuffer buffer(data, size);
     SkFlattenable* result = factory(buffer);
-    sk_free(data);
     if (!buffer.isValid()) {
         SkDebugf("invalid buffer loading flattenable\n");
         return nullptr;
@@ -752,13 +744,13 @@
 }
 
 // caller is responsible for freeing return value
-static SkBitmap* load_bitmap(const Json::Value& jsonBitmap) {
-    if (!jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_BYTES)) {
+static SkBitmap* load_bitmap(const Json::Value& jsonBitmap, UrlDataManager& urlDataManager) {
+    if (!jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_DATA)) {
         SkDebugf("invalid bitmap\n");
         return nullptr;
     }
-    void* data;
-    int size = decode_data(jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_BYTES], &data);
+    const void* data;
+    int size = decode_data(jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
     SkMemoryStream stream(data, size);
     SkImageDecoder* decoder = SkImageDecoder::Factory(&stream);
     SkBitmap* bitmap = new SkBitmap();
@@ -766,7 +758,6 @@
                                                     SkImageDecoder::kDecodePixels_Mode);
     sk_free(decoder);
     if (result != SkImageDecoder::kFailure) {
-        sk_free(data);
         if (jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) {
             const char* ctName = jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_COLOR].asCString();
             SkColorType ct = colortype_from_name(ctName);
@@ -777,12 +768,11 @@
         return bitmap;
     }
     SkDebugf("image decode failed\n");
-    sk_free(data);
     return nullptr;
 }
 
-static SkImage* load_image(const Json::Value& jsonImage) {
-    SkBitmap* bitmap = load_bitmap(jsonImage);
+static SkImage* load_image(const Json::Value& jsonImage, UrlDataManager& urlDataManager) {
+    SkBitmap* bitmap = load_bitmap(jsonImage, urlDataManager);
     if (bitmap == nullptr) {
         return nullptr;
     }
@@ -792,13 +782,13 @@
 }
 
 static bool SK_WARN_UNUSED_RESULT flatten(const SkBitmap& bitmap, Json::Value* target, 
-                                          bool sendBinaries) {
+                                          UrlDataManager& urlDataManager) {
     bitmap.lockPixels();
     SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
     bitmap.unlockPixels();
     (*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, sendBinaries);
+    bool success = flatten(*image, target, urlDataManager);
     return success;
 }
 
@@ -892,7 +882,8 @@
     }
 }
 
-static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, 
+                                   UrlDataManager& urlDataManager) {
     SkMaskFilter* maskFilter = paint.getMaskFilter();
     if (maskFilter != nullptr) {
         SkMaskFilter::BlurRec blurRec;
@@ -934,13 +925,14 @@
             (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLUR] = blur;
         } else {
             Json::Value jsonMaskFilter;
-            flatten(maskFilter, &jsonMaskFilter, sendBinaries);
+            flatten(maskFilter, &jsonMaskFilter, urlDataManager);
             (*target)[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter;
         }
     }
 }
 
-static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, 
+                                   UrlDataManager& urlDataManager) {
     SkPathEffect* pathEffect = paint.getPathEffect();
     if (pathEffect != nullptr) {
         SkPathEffect::DashInfo dashInfo;
@@ -959,7 +951,7 @@
             (*target)[SKDEBUGCANVAS_ATTRIBUTE_DASHING] = dashing;
         } else {
             Json::Value jsonPathEffect;
-            flatten(pathEffect, &jsonPathEffect, sendBinaries);
+            flatten(pathEffect, &jsonPathEffect, urlDataManager);
             (*target)[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect;
         }
     }
@@ -983,70 +975,74 @@
 }
 
 static void apply_paint_typeface(const SkPaint& paint, Json::Value* target, 
-                                 bool sendBinaries) {
+                                 UrlDataManager& urlDataManager) {
     SkTypeface* typeface = paint.getTypeface();
     if (typeface != nullptr) {
-        if (sendBinaries) {
-            Json::Value jsonTypeface;
-            SkDynamicMemoryWStream buffer;
-            typeface->serialize(&buffer);
-            void* data = sk_malloc_throw(buffer.bytesWritten());
-            buffer.copyTo(data);
-            Json::Value bytes;
-            encode_data(data, buffer.bytesWritten(), &bytes);
-            jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_BYTES] = bytes;
-            sk_free(data);
-            (*target)[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE] = jsonTypeface;
-        }
+        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, bool sendBinaries) {
+static void apply_paint_shader(const SkPaint& paint, Json::Value* target, 
+                               UrlDataManager& urlDataManager) {
     SkFlattenable* shader = paint.getShader();
     if (shader != nullptr) {
         Json::Value jsonShader;
-        flatten(shader, &jsonShader, sendBinaries);
+        flatten(shader, &jsonShader, urlDataManager);
         (*target)[SKDEBUGCANVAS_ATTRIBUTE_SHADER] = jsonShader;
     }
 }
 
-static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, 
+                                 UrlDataManager& urlDataManager) {
     SkFlattenable* xfermode = paint.getXfermode();
     if (xfermode != nullptr) {
         Json::Value jsonXfermode;
-        flatten(xfermode, &jsonXfermode, sendBinaries);
+        flatten(xfermode, &jsonXfermode, urlDataManager);
         (*target)[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode;
     }
 }
 
-static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target,
+                                    UrlDataManager& urlDataManager) {
     SkFlattenable* imageFilter = paint.getImageFilter();
     if (imageFilter != nullptr) {
         Json::Value jsonImageFilter;
-        flatten(imageFilter, &jsonImageFilter, sendBinaries);
+        flatten(imageFilter, &jsonImageFilter, urlDataManager);
         (*target)[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter;
     }
 }
 
-static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target, 
+                                    UrlDataManager& urlDataManager) {
     SkFlattenable* colorFilter = paint.getColorFilter();
     if (colorFilter != nullptr) {
         Json::Value jsonColorFilter;
-        flatten(colorFilter, &jsonColorFilter, sendBinaries);
+        flatten(colorFilter, &jsonColorFilter, urlDataManager);
         (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER] = jsonColorFilter;
     }
 }
 
-static void apply_paint_looper(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
+static void apply_paint_looper(const SkPaint& paint, Json::Value* target, 
+                               UrlDataManager& urlDataManager) {
     SkFlattenable* looper = paint.getLooper();
     if (looper != nullptr) {
         Json::Value jsonLooper;
-        flatten(looper, &jsonLooper, sendBinaries);
+        flatten(looper, &jsonLooper, urlDataManager);
         (*target)[SKDEBUGCANVAS_ATTRIBUTE_LOOPER] = jsonLooper;
     }
 }
 
-Json::Value make_json_paint(const SkPaint& paint, bool sendBinaries) {
+Json::Value make_json_paint(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(), 
@@ -1063,14 +1059,14 @@
     apply_paint_join(paint, &result);
     apply_paint_filterquality(paint, &result);
     apply_paint_textalign(paint, &result);
-    apply_paint_patheffect(paint, &result, sendBinaries);
-    apply_paint_maskfilter(paint, &result, sendBinaries);
-    apply_paint_shader(paint, &result, sendBinaries);
-    apply_paint_xfermode(paint, &result, sendBinaries);
-    apply_paint_looper(paint, &result, sendBinaries);
-    apply_paint_imagefilter(paint, &result, sendBinaries);
-    apply_paint_colorfilter(paint, &result, sendBinaries);
-    apply_paint_typeface(paint, &result, sendBinaries);
+    apply_paint_patheffect(paint, &result, urlDataManager);
+    apply_paint_maskfilter(paint, &result, urlDataManager);
+    apply_paint_shader(paint, &result, urlDataManager);
+    apply_paint_xfermode(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;
 }
 
@@ -1088,10 +1084,11 @@
     }
 }
 
-static void extract_json_paint_shader(Json::Value& jsonPaint, SkPaint* target) {
+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);
+        SkShader* shader = (SkShader*) load_flattenable(jsonShader, urlDataManager);
         if (shader != nullptr) {
             target->setShader(shader);
             shader->unref();
@@ -1099,10 +1096,11 @@
     }
 }
 
-static void extract_json_paint_patheffect(Json::Value& jsonPaint, SkPaint* target) {
+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];
-        SkPathEffect* pathEffect = (SkPathEffect*) load_flattenable(jsonPathEffect);
+        SkPathEffect* pathEffect = (SkPathEffect*) load_flattenable(jsonPathEffect, urlDataManager);
         if (pathEffect != nullptr) {
             target->setPathEffect(pathEffect);
             pathEffect->unref();
@@ -1110,10 +1108,11 @@
     }
 }
 
-static void extract_json_paint_maskfilter(Json::Value& jsonPaint, SkPaint* target) {
+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];
-        SkMaskFilter* maskFilter = (SkMaskFilter*) load_flattenable(jsonMaskFilter);
+        SkMaskFilter* maskFilter = (SkMaskFilter*) load_flattenable(jsonMaskFilter, urlDataManager);
         if (maskFilter != nullptr) {
             target->setMaskFilter(maskFilter);
             maskFilter->unref();
@@ -1121,10 +1120,12 @@
     }
 }
 
-static void extract_json_paint_colorfilter(Json::Value& jsonPaint, SkPaint* target) {
+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];
-        SkColorFilter* colorFilter = (SkColorFilter*) load_flattenable(jsonColorFilter);
+        SkColorFilter* colorFilter = (SkColorFilter*) load_flattenable(jsonColorFilter, 
+                                                                       urlDataManager);
         if (colorFilter != nullptr) {
             target->setColorFilter(colorFilter);
             colorFilter->unref();
@@ -1132,10 +1133,11 @@
     }
 }
 
-static void extract_json_paint_xfermode(Json::Value& jsonPaint, SkPaint* target) {
+static void extract_json_paint_xfermode(Json::Value& jsonPaint, UrlDataManager& urlDataManager, 
+                                        SkPaint* target) {
     if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_XFERMODE)) {
         Json::Value jsonXfermode = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE];
-        SkXfermode* xfermode = (SkXfermode*) load_flattenable(jsonXfermode);
+        SkXfermode* xfermode = (SkXfermode*) load_flattenable(jsonXfermode, urlDataManager);
         if (xfermode != nullptr) {
             target->setXfermode(xfermode);
             xfermode->unref();
@@ -1143,10 +1145,11 @@
     }
 }
 
-static void extract_json_paint_looper(Json::Value& jsonPaint, SkPaint* target) {
+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];
-        SkDrawLooper* looper = (SkDrawLooper*) load_flattenable(jsonLooper);
+        SkDrawLooper* looper = (SkDrawLooper*) load_flattenable(jsonLooper, urlDataManager);
         if (looper != nullptr) {
             target->setLooper(looper);
             looper->unref();
@@ -1154,10 +1157,12 @@
     }
 }
 
-static void extract_json_paint_imagefilter(Json::Value& jsonPaint, SkPaint* target) {
+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];
-        SkImageFilter* imageFilter = (SkImageFilter*) load_flattenable(jsonImageFilter);
+        SkImageFilter* imageFilter = (SkImageFilter*) load_flattenable(jsonImageFilter, 
+                                                                       urlDataManager);
         if (imageFilter != nullptr) {
             target->setImageFilter(imageFilter);
             imageFilter->unref();
@@ -1165,6 +1170,19 @@
     }
 }
 
+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);
+        SkTypeface* typeface = SkTypeface::Deserialize(&buffer);
+        target->setTypeface(typeface);
+    }
+}
+
 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();
@@ -1352,28 +1370,17 @@
     }
 }
 
-static void extract_json_paint_typeface(Json::Value& jsonPaint, SkPaint* target) {
-    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE)) {
-        Json::Value jsonTypeface = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE];
-        Json::Value bytes = jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_BYTES];
-        void* data;
-        Json::ArrayIndex length = decode_data(bytes, &data);
-        SkMemoryStream buffer(data, length);
-        SkTypeface* typeface = SkTypeface::Deserialize(&buffer);
-        sk_free(data);
-        target->setTypeface(typeface);
-    }
-}
-
-static void extract_json_paint(Json::Value& paint, SkPaint* result) {
+static void extract_json_paint(Json::Value& paint, UrlDataManager& urlDataManager, 
+                               SkPaint* result) {
     extract_json_paint_color(paint, result);
-    extract_json_paint_shader(paint, result);
-    extract_json_paint_patheffect(paint, result);
-    extract_json_paint_maskfilter(paint, result);
-    extract_json_paint_colorfilter(paint, result);
-    extract_json_paint_xfermode(paint, result);
-    extract_json_paint_looper(paint, result);
-    extract_json_paint_imagefilter(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_xfermode(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_strokewidth(paint, result);
     extract_json_paint_strokemiter(paint, result);
@@ -1388,7 +1395,6 @@
     extract_json_paint_textsize(paint, result);
     extract_json_paint_textscalex(paint, result);
     extract_json_paint_textskewx(paint, result);
-    extract_json_paint_typeface(paint, result);
 }
 
 static void extract_json_rect(Json::Value& rect, SkRect* result) {
@@ -1507,13 +1513,13 @@
     canvas->clear(fColor);
 }
 
-Json::Value SkClearCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkClearCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = make_json_color(fColor);
     return result;
 }
 
- SkClearCommand* SkClearCommand::fromJSON(Json::Value& command) {
+ SkClearCommand* SkClearCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
     Json::Value color = command[SKDEBUGCANVAS_ATTRIBUTE_COLOR];
     return new SkClearCommand(get_json_color(color));
 }
@@ -1538,15 +1544,16 @@
     return true;
 }
 
-Json::Value SkClipPathCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkClipPathCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = make_json_path(fPath);
     result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
     result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = fDoAA;
     return result;
 }
 
-SkClipPathCommand* SkClipPathCommand::fromJSON(Json::Value& command) {
+SkClipPathCommand* SkClipPathCommand::fromJSON(Json::Value& command, 
+                                               UrlDataManager& urlDataManager) {
     SkPath path;
     extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
     return new SkClipPathCommand(path, get_json_regionop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]), 
@@ -1566,14 +1573,15 @@
     canvas->clipRegion(fRegion, fOp);
 }
 
-Json::Value SkClipRegionCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkClipRegionCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_REGION] = make_json_region(fRegion);
     result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
     return result;
 }
 
-SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command) {
+SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command, 
+                                                   UrlDataManager& urlDataManager) {
     SkASSERT(false);
     return nullptr;
 }
@@ -1593,15 +1601,16 @@
     canvas->clipRect(fRect, fOp, fDoAA);
 }
 
-Json::Value SkClipRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkClipRectCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fRect);
     result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
     result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA);
     return result;
 }
 
-SkClipRectCommand* SkClipRectCommand::fromJSON(Json::Value& command) {
+SkClipRectCommand* SkClipRectCommand::fromJSON(Json::Value& command, 
+                                               UrlDataManager& urlDataManager) {
     SkRect rect;
     extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect);
     return new SkClipRectCommand(rect, get_json_regionop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]), 
@@ -1628,15 +1637,16 @@
     return true;
 }
 
-Json::Value SkClipRRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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) {
+SkClipRRectCommand* SkClipRRectCommand::fromJSON(Json::Value& command, 
+                                                 UrlDataManager& urlDataManager) {
     SkRRect rrect;
     extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rrect);
     return new SkClipRRectCommand(rrect, 
@@ -1655,13 +1665,13 @@
     canvas->concat(fMatrix);
 }
 
-Json::Value SkConcatCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkConcatCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = make_json_matrix(fMatrix);
     return result;
 }
 
-SkConcatCommand* SkConcatCommand::fromJSON(Json::Value& command) {
+SkConcatCommand* SkConcatCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
     SkMatrix matrix;
     extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
     return new SkConcatCommand(matrix);
@@ -1697,23 +1707,23 @@
     return true;
 }
 
-Json::Value SkDrawBitmapCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawBitmapCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
-    if (flatten(fBitmap, &encoded, SKDEBUGCANVAS_SEND_BINARIES)) {
+    if (flatten(fBitmap, &encoded, urlDataManager)) {
         Json::Value command(Json::objectValue);
         result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
         result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(fLeft, fTop);
         if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, 
-                                                                    SKDEBUGCANVAS_SEND_BINARIES);
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager);
         }
     }
     return result;
 }
 
-SkDrawBitmapCommand* SkDrawBitmapCommand::fromJSON(Json::Value& command) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP]);
+SkDrawBitmapCommand* SkDrawBitmapCommand::fromJSON(Json::Value& command, 
+                                                   UrlDataManager& urlDataManager) {
+    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
     if (bitmap == nullptr) {
         return nullptr;
     }
@@ -1721,7 +1731,7 @@
     SkPaint* paintPtr;
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
         paintPtr = &paint;
     }
     else {
@@ -1764,23 +1774,23 @@
     return true;
 }
 
-Json::Value SkDrawBitmapNineCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawBitmapNineCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
-    if (flatten(fBitmap, &encoded, SKDEBUGCANVAS_SEND_BINARIES)) {
+    if (flatten(fBitmap, &encoded, urlDataManager)) {
         result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
         result[SKDEBUGCANVAS_ATTRIBUTE_CENTER] = make_json_irect(fCenter);
         result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst);
         if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr,
-                                                                    SKDEBUGCANVAS_SEND_BINARIES);
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager);
         }
     }
     return result;
 }
 
-SkDrawBitmapNineCommand* SkDrawBitmapNineCommand::fromJSON(Json::Value& command) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP]);
+SkDrawBitmapNineCommand* SkDrawBitmapNineCommand::fromJSON(Json::Value& command, 
+                                                           UrlDataManager& urlDataManager) {
+    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
     if (bitmap == nullptr) {
         return nullptr;
     }
@@ -1791,7 +1801,7 @@
     SkPaint* paintPtr;
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
         paintPtr = &paint;
     }
     else {
@@ -1842,18 +1852,17 @@
     return true;
 }
 
-Json::Value SkDrawBitmapRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawBitmapRectCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
-    if (flatten(fBitmap, &encoded, SKDEBUGCANVAS_SEND_BINARIES)) {
+    if (flatten(fBitmap, &encoded, urlDataManager)) {
         result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
         if (!fSrc.isEmpty()) {
             result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = make_json_rect(fSrc);
         }
         result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst);
         if (fPaintPtr != nullptr) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr,
-                                                                    SKDEBUGCANVAS_SEND_BINARIES);
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager);
         }
         if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
             result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
@@ -1862,8 +1871,9 @@
     return result;
 }
 
-SkDrawBitmapRectCommand* SkDrawBitmapRectCommand::fromJSON(Json::Value& command) {
-    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP]);
+SkDrawBitmapRectCommand* SkDrawBitmapRectCommand::fromJSON(Json::Value& command, 
+                                                           UrlDataManager& urlDataManager) {
+    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
     if (bitmap == nullptr) {
         return nullptr;
     }
@@ -1872,7 +1882,7 @@
     SkPaint* paintPtr;
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
         paintPtr = &paint;
     }
     else {
@@ -1933,22 +1943,22 @@
     return true;
 }
 
-Json::Value SkDrawImageCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawImageCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
-    if (flatten(*fImage, &encoded, SKDEBUGCANVAS_SEND_BINARIES)) {
+    if (flatten(*fImage, &encoded, urlDataManager)) {
         result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
         result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(fLeft, fTop);
         if (fPaint.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(),
-                                                                    SKDEBUGCANVAS_SEND_BINARIES);
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(), urlDataManager);
         }
     }
     return result;
 }
 
-SkDrawImageCommand* SkDrawImageCommand::fromJSON(Json::Value& command) {
-    SkImage* image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE]);
+SkDrawImageCommand* SkDrawImageCommand::fromJSON(Json::Value& command, 
+                                                 UrlDataManager& urlDataManager) {
+    SkImage* image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
     if (image == nullptr) {
         return nullptr;
     }
@@ -1956,7 +1966,7 @@
     SkPaint* paintPtr;
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
         paintPtr = &paint;
     }
     else {
@@ -2010,18 +2020,17 @@
     return true;
 }
 
-Json::Value SkDrawImageRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
-    if (flatten(*fImage.get(), &encoded, SKDEBUGCANVAS_SEND_BINARIES)) {
+    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
         result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
         if (fSrc.isValid()) {
             result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = make_json_rect(*fSrc.get());
         }
         result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst);
         if (fPaint.isValid()) {
-            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(),
-                                                                    SKDEBUGCANVAS_SEND_BINARIES);
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(), urlDataManager);
         }
         if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
             result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
@@ -2030,8 +2039,9 @@
     return result;
 }
 
-SkDrawImageRectCommand* SkDrawImageRectCommand::fromJSON(Json::Value& command) {
-    SkImage* image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE]);
+SkDrawImageRectCommand* SkDrawImageRectCommand::fromJSON(Json::Value& command, 
+                                                         UrlDataManager& urlDataManager) {
+    SkImage* image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
     if (image == nullptr) {
         return nullptr;
     }
@@ -2040,7 +2050,7 @@
     SkPaint* paintPtr;
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
         paintPtr = &paint;
     }
     else {
@@ -2098,18 +2108,19 @@
     return true;
 }
 
-Json::Value SkDrawOvalCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawOvalCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fOval);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawOvalCommand* SkDrawOvalCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawOvalCommand(coords, paint);
 }
 
@@ -2130,15 +2141,16 @@
     return true;
 }
 
-Json::Value SkDrawPaintCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+Json::Value SkDrawPaintCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawPaintCommand* SkDrawPaintCommand::fromJSON(Json::Value& command) {
+SkDrawPaintCommand* SkDrawPaintCommand::fromJSON(Json::Value& command, 
+                                                 UrlDataManager& urlDataManager) {
     SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawPaintCommand(paint);
 }
 
@@ -2160,18 +2172,19 @@
     return true;
 }
 
-Json::Value SkDrawPathCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawPathCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = make_json_path(fPath);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawPathCommand* SkDrawPathCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawPathCommand(path, paint);
 }
 
@@ -2281,19 +2294,20 @@
     return true;
 }
 
-Json::Value SkDrawPointsCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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(make_json_point(fPts[i]));
     }
     result[SKDEBUGCANVAS_ATTRIBUTE_POINTS] = points;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawPointsCommand* SkDrawPointsCommand::fromJSON(Json::Value& command) {
+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)) {
@@ -2316,7 +2330,7 @@
         points[i] = SkPoint::Make(jsonPoints[i][0].asFloat(), jsonPoints[i][1].asFloat());
     }
     SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     SkDrawPointsCommand* result = new SkDrawPointsCommand(mode, count, points, paint);
     sk_free(points);
     return result;
@@ -2346,8 +2360,8 @@
     canvas->drawPosText(fText, fByteLength, fPos, fPaint);
 }
 
-Json::Value SkDrawPosTextCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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);
@@ -2355,14 +2369,15 @@
         coords.append(make_json_point(fPos[i]));
     }
     result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = coords;
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawPosTextCommand* SkDrawPosTextCommand::fromJSON(Json::Value& command) {
+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], &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));
@@ -2461,8 +2476,8 @@
     return true;
 }
 
-Json::Value SkDrawTextBlobCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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()) {
@@ -2491,7 +2506,7 @@
         run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS] = jsonGlyphs;
         SkPaint fontPaint;
         iter.applyFontToPaint(&fontPaint);
-        run[SKDEBUGCANVAS_ATTRIBUTE_FONT] = make_json_paint(fontPaint, SKDEBUGCANVAS_SEND_BINARIES);
+        run[SKDEBUGCANVAS_ATTRIBUTE_FONT] = make_json_paint(fontPaint, urlDataManager);
         run[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(iter.offset());
         runs.append(run);
         iter.next();
@@ -2499,18 +2514,19 @@
     result[SKDEBUGCANVAS_ATTRIBUTE_RUNS] = runs;
     result[SKDEBUGCANVAS_ATTRIBUTE_X] = Json::Value(fXPos);
     result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fYPos);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawTextBlobCommand* SkDrawTextBlobCommand::fromJSON(Json::Value& command) {
+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], &font);
+        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];
@@ -2544,7 +2560,7 @@
     SkScalar x = command[SKDEBUGCANVAS_ATTRIBUTE_X].asFloat();
     SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat();
     SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawTextBlobCommand(builder.build(), x, y, paint);
 }
 
@@ -2577,8 +2593,8 @@
     canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fXfermode, fPaint);
 }
 
-Json::Value SkDrawPatchCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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(make_json_point(fCubics[i]));
@@ -2600,13 +2616,14 @@
     }
     if (fXfermode.get() != nullptr) {
         Json::Value jsonXfermode;
-        flatten(fXfermode, &jsonXfermode, SKDEBUGCANVAS_SEND_BINARIES);
+        flatten(fXfermode, &jsonXfermode, urlDataManager);
         result[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode;
     }
     return result;
 }
 
-SkDrawPatchCommand* SkDrawPatchCommand::fromJSON(Json::Value& command) {
+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++) {
@@ -2639,10 +2656,10 @@
     SkAutoTUnref<SkXfermode> xfermode;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_XFERMODE)) {
         Json::Value jsonXfermode = command[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE];
-        xfermode.reset((SkXfermode*) load_flattenable(jsonXfermode));
+        xfermode.reset((SkXfermode*) load_flattenable(jsonXfermode, urlDataManager));
     }
     SkPaint paint;
-    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawPatchCommand(cubics, colorsPtr, texCoordsPtr, xfermode, paint);
 }
 
@@ -2659,18 +2676,19 @@
     canvas->drawRect(fRect, fPaint);
 }
 
-Json::Value SkDrawRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkDrawRectCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fRect);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawRectCommand* SkDrawRectCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawRectCommand(coords, paint);
 }
 
@@ -2692,18 +2710,19 @@
     return true;
 }
 
-Json::Value SkDrawRRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawRRectCommand* SkDrawRRectCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawRRectCommand(coords, paint);
 }
 
@@ -2729,21 +2748,22 @@
     return true;
 }
 
-Json::Value SkDrawDRRectCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawDRRectCommand* SkDrawDRRectCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     return new SkDrawDRRectCommand(outer, inner, paint);
 }
 
@@ -2767,20 +2787,21 @@
     canvas->drawText(fText, fByteLength, fX, fY, fPaint);
 }
 
-Json::Value SkDrawTextCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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] = make_json_point(fX, fY);
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawTextCommand* SkDrawTextCommand::fromJSON(Json::Value& command) {
+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], &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);
@@ -2815,8 +2836,8 @@
                            fPaint);
 }
 
-Json::Value SkDrawTextOnPathCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+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);
@@ -2824,14 +2845,15 @@
     if (!fMatrix.isIdentity()) {
         result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = make_json_matrix(fMatrix);
     }
-    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, SKDEBUGCANVAS_SEND_BINARIES);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager);
     return result;
 }
 
-SkDrawTextOnPathCommand* SkDrawTextOnPathCommand::fromJSON(Json::Value& command) {
+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], &paint);
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
     SkPath path;
     extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
     SkMatrix* matrixPtr;
@@ -2916,7 +2938,7 @@
     canvas->restore();
 }
 
-SkRestoreCommand* SkRestoreCommand::fromJSON(Json::Value& command) {
+SkRestoreCommand* SkRestoreCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
     return new SkRestoreCommand();
 }
 
@@ -2928,7 +2950,7 @@
     canvas->save();
 }
 
-SkSaveCommand* SkSaveCommand::fromJSON(Json::Value& command) {
+SkSaveCommand* SkSaveCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
     return new SkSaveCommand();
 }
 
@@ -2980,18 +3002,18 @@
     canvas->save();
 }
 
-Json::Value SkSaveLayerCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkSaveLayerCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     if (!fBounds.isEmpty()) {
         result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = make_json_rect(fBounds);
     }
     if (fPaintPtr != nullptr) {
         result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, 
-                                                                SKDEBUGCANVAS_SEND_BINARIES);
+                                                                urlDataManager);
     }
     if (fBackdrop != nullptr) {
         Json::Value jsonBackdrop;
-        flatten(fBackdrop, &jsonBackdrop, SKDEBUGCANVAS_SEND_BINARIES);
+        flatten(fBackdrop, &jsonBackdrop, urlDataManager);
         result[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP] = jsonBackdrop;
     }
     if (fSaveLayerFlags != 0) {
@@ -3001,7 +3023,8 @@
     return result;
 }
 
-SkSaveLayerCommand* SkSaveLayerCommand::fromJSON(Json::Value& command) {
+SkSaveLayerCommand* SkSaveLayerCommand::fromJSON(Json::Value& command, 
+                                                 UrlDataManager& urlDataManager) {
     SkCanvas::SaveLayerRec rec;
     SkRect bounds;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS)) {
@@ -3010,12 +3033,12 @@
     }
     SkPaint paint;
     if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
-        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], &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);
+        rec.fBackdrop = (SkImageFilter*) load_flattenable(backdrop, urlDataManager);
     }
     SkSaveLayerCommand* result = new SkSaveLayerCommand(rec);
     if (rec.fBackdrop != nullptr) {
@@ -3040,13 +3063,14 @@
     canvas->setMatrix(temp);
 }
 
-Json::Value SkSetMatrixCommand::toJSON() const {
-    Json::Value result = INHERITED::toJSON();
+Json::Value SkSetMatrixCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
     result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = make_json_matrix(fMatrix);
     return result;
 }
 
-SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command) {
+SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command, 
+                                                 UrlDataManager& urlDataManager) {
     SkMatrix matrix;
     extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
     return new SkSetMatrixCommand(matrix);