Adding support for playback to L32/S32/F16 canvas.

Playback of my test GM works correctly on both raster and GPU, in all three modes.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1893393002

Review URL: https://codereview.chromium.org/1893393002
diff --git a/gyp/skiaserve.gyp b/gyp/skiaserve.gyp
index 32b73f7..658b4d1 100644
--- a/gyp/skiaserve.gyp
+++ b/gyp/skiaserve.gyp
@@ -40,6 +40,7 @@
         'microhttpd.gyp:microhttpd',
         'skia_lib.gyp:skia_lib',
         'tools.gyp:crash_handler',
+        'tools.gyp:picture_utils',
         'tools.gyp:proc_stats',
         'tools.gyp:resources',
         'tools.gyp:url_data_manager',
diff --git a/tools/skiaserve/Request.cpp b/tools/skiaserve/Request.cpp
index 7534b1d..58aca84 100644
--- a/tools/skiaserve/Request.cpp
+++ b/tools/skiaserve/Request.cpp
@@ -9,6 +9,7 @@
 
 #include "SkPictureRecorder.h"
 #include "SkPixelSerializer.h"
+#include "picture_utils.h"
 
 using namespace sk_gpu_test;
 
@@ -19,7 +20,8 @@
 Request::Request(SkString rootUrl)
     : fUploadContext(nullptr)
     , fUrlDataManager(rootUrl)
-    , fGPUEnabled(false) {
+    , fGPUEnabled(false)
+    , fColorMode(0) {
     // create surface
 #if SK_SUPPORT_GPU
     GrContextOptions grContextOpts;
@@ -39,10 +41,7 @@
 
 SkBitmap* Request::getBitmapFromCanvas(SkCanvas* canvas) {
     SkBitmap* bmp = new SkBitmap();
-    SkIRect bounds = this->getBounds();
-    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
-                                         kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
-    bmp->setInfo(info);
+    bmp->setInfo(canvas->imageInfo());
     if (!canvas->readPixels(bmp, 0, 0)) {
         fprintf(stderr, "Can't read pixels\n");
         return nullptr;
@@ -55,9 +54,14 @@
     SkAutoTDelete<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());
+
     // write to png
     SkDynamicMemoryWStream buffer;
-    SkDrawCommand::WritePNG((const png_bytep) bmp->getPixels(), bmp->width(), bmp->height(),
+    SkDrawCommand::WritePNG((const png_bytep) encodedBitmap->writable_data(),
+                            bmp->width(), bmp->height(),
                             buffer);
     return buffer.copyToData();
 }
@@ -138,25 +142,50 @@
     return bounds;
 }
 
+namespace {
+
+struct ColorAndProfile {
+    SkColorType fColorType;
+    SkColorProfileType fProfileType;
+    bool fGammaCorrect;
+};
+
+ColorAndProfile ColorModes[] = {
+    { kN32_SkColorType, kLinear_SkColorProfileType, false },
+    { kN32_SkColorType, kSRGB_SkColorProfileType, true },
+    { kRGBA_F16_SkColorType, kLinear_SkColorProfileType, true },
+};
+
+}
+
 SkSurface* Request::createCPUSurface() {
     SkIRect bounds = this->getBounds();
-    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), kN32_SkColorType,
-                                         kPremul_SkAlphaType);
-    return SkSurface::MakeRaster(info).release();
+    ColorAndProfile cap = ColorModes[fColorMode];
+    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
+                                         kPremul_SkAlphaType, cap.fProfileType);
+    uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
+    SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+    return SkSurface::MakeRaster(info, &props).release();
 }
 
 SkSurface* Request::createGPUSurface() {
     GrContext* context = this->getContext();
     SkIRect bounds = this->getBounds();
-    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(),
-                                         kN32_SkColorType, kPremul_SkAlphaType);
-    uint32_t flags = 0;
+    ColorAndProfile cap = ColorModes[fColorMode];
+    SkImageInfo info = SkImageInfo::Make(bounds.width(), bounds.height(), cap.fColorType,
+                                         kPremul_SkAlphaType, cap.fProfileType);
+    uint32_t flags = cap.fGammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0;
     SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
     SkSurface* surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0,
                                                      &props).release();
     return surface;
 }
 
+bool Request::setColorMode(int mode) {
+    fColorMode = mode;
+    return enableGPU(fGPUEnabled);
+}
+
 bool Request::enableGPU(bool enable) {
     if (enable) {
         SkSurface* surface = this->createGPUSurface();
@@ -167,8 +196,10 @@
             // When we switch to GPU, there seems to be some mystery draws in the canvas.  So we
             // draw once to flush the pipe
             // TODO understand what is actually happening here
-            fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
-            this->getCanvas()->flush();
+            if (fDebugCanvas) {
+                fDebugCanvas->drawTo(this->getCanvas(), this->getLastOp());
+                this->getCanvas()->flush();
+            }
 
             return true;
         }
@@ -206,6 +237,7 @@
     Json::Value root = fDebugCanvas->toJSON(fUrlDataManager, n, canvas);
     root["mode"] = Json::Value(fGPUEnabled ? "gpu" : "cpu");
     root["drawGpuBatchBounds"] = Json::Value(fDebugCanvas->getDrawGpuBatchBounds());
+    root["colorMode"] = Json::Value(fColorMode);
     SkDynamicMemoryWStream stream;
     stream.writeText(Json::FastWriter().write(root).c_str());
 
@@ -250,9 +282,12 @@
     canvas->flush();
     SkAutoTDelete<SkBitmap> bitmap(this->getBitmapFromCanvas(canvas));
     SkASSERT(bitmap);
-    bitmap->lockPixels();
-    uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * bitmap->width() + x) * 4;
+
+    // Convert to format suitable for inspection
+    sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(*bitmap);
+    SkASSERT(encodedBitmap.get());
+
+    const uint8_t* start = encodedBitmap->bytes() + ((y * bitmap->width() + x) * 4);
     SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
-    bitmap->unlockPixels();
     return result;
 }
diff --git a/tools/skiaserve/Request.h b/tools/skiaserve/Request.h
index d19c2ba..f3af6b7 100644
--- a/tools/skiaserve/Request.h
+++ b/tools/skiaserve/Request.h
@@ -41,6 +41,7 @@
     SkCanvas* getCanvas();
     SkBitmap* getBitmapFromCanvas(SkCanvas* canvas);
     bool enableGPU(bool enable);
+    bool setColorMode(int mode);
     bool hasPicture() const { return SkToBool(fPicture.get()); }
     int getLastOp() const { return fDebugCanvas->getSize() - 1; }
 
@@ -74,6 +75,7 @@
     sk_gpu_test::GrContextFactory* fContextFactory;
     SkAutoTUnref<SkSurface> fSurface;
     bool fGPUEnabled;
+    int fColorMode;
 };
 
 #endif
diff --git a/tools/skiaserve/skiaserve.cpp b/tools/skiaserve/skiaserve.cpp
index fd96251..e71be0f 100644
--- a/tools/skiaserve/skiaserve.cpp
+++ b/tools/skiaserve/skiaserve.cpp
@@ -39,6 +39,7 @@
         fHandlers.push_back(new BreakHandler);
         fHandlers.push_back(new BatchesHandler);
         fHandlers.push_back(new BatchBoundsHandler);
+        fHandlers.push_back(new ColorModeHandler);
     }
 
     ~UrlManager() {
diff --git a/tools/skiaserve/urlhandlers/ColorModeHandler.cpp b/tools/skiaserve/urlhandlers/ColorModeHandler.cpp
new file mode 100644
index 0000000..25cdf7d
--- /dev/null
+++ b/tools/skiaserve/urlhandlers/ColorModeHandler.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "UrlHandler.h"
+
+#include "microhttpd.h"
+#include "../Request.h"
+#include "../Response.h"
+
+using namespace Response;
+
+bool ColorModeHandler::canHandle(const char* method, const char* url) {
+    static const char* kBasePath = "/colorMode/";
+    return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
+           0 == strncmp(url, kBasePath, strlen(kBasePath));
+}
+
+int ColorModeHandler::handle(Request* request, MHD_Connection* connection,
+                             const char* url, const char* method,
+                             const char* upload_data, size_t* upload_data_size) {
+    SkTArray<SkString> commands;
+    SkStrSplit(url, "/", &commands);
+
+    if (commands.count() != 2) {
+        return MHD_NO;
+    }
+
+    int mode;
+    if (1 != sscanf(commands[1].c_str(), "%d", &mode)) {
+        return MHD_NO;
+    }
+
+    bool success = request->setColorMode(mode);
+    if (!success) {
+        return SendError(connection, "Unable to create requested surface");
+    }
+    return SendOK(connection);
+}
diff --git a/tools/skiaserve/urlhandlers/UrlHandler.h b/tools/skiaserve/urlhandlers/UrlHandler.h
index 02a07b0..adbdcb9 100644
--- a/tools/skiaserve/urlhandlers/UrlHandler.h
+++ b/tools/skiaserve/urlhandlers/UrlHandler.h
@@ -128,3 +128,16 @@
                const char* url, const char* method,
                const char* upload_data, size_t* upload_data_size) override;
 };
+
+/**
+ * Controls how rendering is performed (L32, S32, F16).
+ * Posting to /colorMode/0 turns on L32, /colorMode/1 turns on sRGB,
+ * /colorMode/2 turns on FP16.
+ */
+class ColorModeHandler : public UrlHandler {
+public:
+    bool canHandle(const char* method, const char* url) override;
+    int handle(Request* request, MHD_Connection* connection,
+               const char* url, const char* method,
+               const char* upload_data, size_t* upload_data_size) override;
+};