Merge latest Skia into master (7 commits)

https://skia.googlesource.com/skia.git/+log/9c7dcac..70a309a

Test: Presubmit checks will test this change.
Change-Id: I41526baa3a78e1d2eb9af9088c7cb990eaf896c9
diff --git a/include/gpu/GrRenderTargetContext.h b/include/gpu/GrRenderTargetContext.h
index 3636d5c..e595a4f 100644
--- a/include/gpu/GrRenderTargetContext.h
+++ b/include/gpu/GrRenderTargetContext.h
@@ -316,34 +316,6 @@
      */
     void prepareForExternalIO();
 
-    /**
-     * Reads a rectangle of pixels from the render target context.
-     * @param dstInfo       image info for the destination
-     * @param dstBuffer     destination pixels for the read
-     * @param dstRowBytes   bytes in a row of 'dstBuffer'
-     * @param x             x offset w/in the render target context from which to read
-     * @param y             y offset w/in the render target context from which to read
-     *
-     * @return true if the read succeeded, false if not. The read can fail because of an
-     *              unsupported pixel config.
-     */
-    bool readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes, int x, int y);
-
-    /**
-     * Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the 
-     * renderTargetContext at the specified position.
-     * @param srcInfo       image info for the source pixels
-     * @param srcBuffer     source for the write
-     * @param srcRowBytes   bytes in a row of 'srcBuffer'
-     * @param x             x offset w/in the render target context at which to write
-     * @param y             y offset w/in the render target context at which to write
-     *
-     * @return true if the write succeeded, false if not. The write can fail because of an
-     *              unsupported pixel config.
-     */
-    bool writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, size_t srcRowBytes,
-                     int x, int y);
-
     bool isStencilBufferMultisampled() const {
         return fRenderTargetProxy->isStencilBufferMultisampled();
     }
@@ -356,10 +328,7 @@
     int height() const { return fRenderTargetProxy->height(); }
     GrPixelConfig config() const { return fRenderTargetProxy->config(); }
     int numColorSamples() const { return fRenderTargetProxy->numColorSamples(); }
-    bool isGammaCorrect() const { return SkToBool(fColorSpace.get()); }
     const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; }
-    SkColorSpace* getColorSpace() const { return fColorSpace.get(); }
-    sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; }
     GrColorSpaceXform* getColorXformFromSRGB() const { return fColorXformFromSRGB.get(); }
     GrSurfaceOrigin origin() const { return fRenderTargetProxy->origin(); }
 
@@ -396,7 +365,7 @@
 
 protected:
     GrRenderTargetContext(GrContext*, GrDrawingManager*, sk_sp<GrRenderTargetProxy>,
-                          sk_sp<SkColorSpace>, const SkSurfaceProps* surfaceProps, GrAuditTrail*,
+                          sk_sp<SkColorSpace>, const SkSurfaceProps*, GrAuditTrail*,
                           GrSingleOwner*);
 
     GrDrawingManager* drawingManager() { return fDrawingManager; }
@@ -469,6 +438,10 @@
             const GrClip&, GrPaint&&, GrAA, const SkMatrix&, const SkPath&, const GrStyle&);
 
     bool onCopy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
+    bool onReadPixels(const SkImageInfo& dstInfo, void* dstBuffer,
+                      size_t dstRowBytes, int x, int y) override;
+    bool onWritePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
+                       size_t srcRowBytes, int x, int y) override;
 
     // This entry point allows the GrTextContext-derived classes to add their ops to the GrOpList.
     void addDrawOp(const GrPipelineBuilder&, const GrClip&, std::unique_ptr<GrDrawOp>);
@@ -483,7 +456,6 @@
     GrRenderTargetOpList*             fOpList;
     GrInstancedPipelineInfo           fInstancedPipelineInfo;
 
-    sk_sp<SkColorSpace>               fColorSpace;
     sk_sp<GrColorSpaceXform>          fColorXformFromSRGB;
     SkSurfaceProps                    fSurfaceProps;
 
diff --git a/include/gpu/GrSurfaceContext.h b/include/gpu/GrSurfaceContext.h
index a772d19..6a40f2f 100644
--- a/include/gpu/GrSurfaceContext.h
+++ b/include/gpu/GrSurfaceContext.h
@@ -30,6 +30,10 @@
 public:
     ~GrSurfaceContext() override {}
 
+    SkColorSpace* getColorSpace() const { return fColorSpace.get(); }
+    sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; }
+    bool isGammaCorrect() const { return SkToBool(fColorSpace.get()); }
+
     /*
      * Copy 'src' into the proxy backing this context
      * @param src       src of pixels
@@ -52,6 +56,39 @@
                             SkIPoint::Make(0, 0));
     }
 
+    /**
+     * Reads a rectangle of pixels from the render target context.
+     * @param dstInfo       image info for the destination
+     * @param dstBuffer     destination pixels for the read
+     * @param dstRowBytes   bytes in a row of 'dstBuffer'
+     * @param x             x offset w/in the render target context from which to read
+     * @param y             y offset w/in the render target context from which to read
+     *
+     * @return true if the read succeeded, false if not. The read can fail because of an
+     *              unsupported pixel config.
+     */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes,
+                    int x, int y) {
+        return this->onReadPixels(dstInfo, dstBuffer, dstRowBytes, x, y);
+    }
+
+    /**
+     * Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the 
+     * renderTargetContext at the specified position.
+     * @param srcInfo       image info for the source pixels
+     * @param srcBuffer     source for the write
+     * @param srcRowBytes   bytes in a row of 'srcBuffer'
+     * @param x             x offset w/in the render target context at which to write
+     * @param y             y offset w/in the render target context at which to write
+     *
+     * @return true if the write succeeded, false if not. The write can fail because of an
+     *              unsupported pixel config.
+     */
+    bool writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, size_t srcRowBytes,
+                     int x, int y) {
+        return this->onWritePixels(srcInfo, srcBuffer, srcRowBytes, x, y);
+    }
+
     // TODO: this is virtual b.c. this object doesn't have a pointer to the wrapped GrSurfaceProxy?
     virtual GrSurfaceProxy* asDeferredSurface() = 0;
     virtual GrTextureProxy* asDeferredTexture() = 0;
@@ -66,11 +103,12 @@
 protected:
     friend class GrSurfaceContextPriv;
 
-    GrSurfaceContext(GrContext*, GrAuditTrail*, GrSingleOwner*);
+    GrSurfaceContext(GrContext*, sk_sp<SkColorSpace>, GrAuditTrail*, GrSingleOwner*);
 
     SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; })
 
     GrContext*            fContext;
+    sk_sp<SkColorSpace>   fColorSpace;
     GrAuditTrail*         fAuditTrail;
 
     // In debug builds we guard against improper thread handling
@@ -80,6 +118,10 @@
     virtual bool onCopy(GrSurfaceProxy* src,
                         const SkIRect& srcRect,
                         const SkIPoint& dstPoint) = 0;
+    virtual bool onReadPixels(const SkImageInfo& dstInfo, void* dstBuffer,
+                              size_t dstRowBytes, int x, int y) = 0;
+    virtual bool onWritePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
+                               size_t srcRowBytes, int x, int y) = 0;
 
     typedef SkRefCnt INHERITED;
 };
diff --git a/include/gpu/GrTextureContext.h b/include/gpu/GrTextureContext.h
index ef9613f..b49b272 100644
--- a/include/gpu/GrTextureContext.h
+++ b/include/gpu/GrTextureContext.h
@@ -32,8 +32,8 @@
     GrRenderTargetProxy* asDeferredRenderTarget() override;
 
 protected:
-    GrTextureContext(GrContext*, GrDrawingManager*, sk_sp<GrTextureProxy>, GrAuditTrail*,
-                     GrSingleOwner*);
+    GrTextureContext(GrContext*, GrDrawingManager*, sk_sp<GrTextureProxy>,
+                     sk_sp<SkColorSpace>, GrAuditTrail*, GrSingleOwner*);
 
     GrDrawingManager* drawingManager() { return fDrawingManager; }
 
@@ -43,6 +43,10 @@
     friend class GrDrawingManager; // for ctor
 
     bool onCopy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) override;
+    bool onReadPixels(const SkImageInfo& dstInfo, void* dstBuffer,
+                      size_t dstRowBytes, int x, int y) override;
+    bool onWritePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
+                       size_t srcRowBytes, int x, int y) override;
 
     GrTextureOpList* getOpList();
 
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_CPU_BENCH_10k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_CPU_BENCH_10k_SKPs.json
index e5ad308..6e268a7 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_CPU_BENCH_10k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_CPU_BENCH_10k_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-nanobench-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1411,7 +1411,7 @@
     ],
     "name": "ct-nanobench-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1540,7 +1540,7 @@
     ],
     "name": "ct-nanobench-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1669,7 +1669,7 @@
     ],
     "name": "ct-nanobench-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1798,7 +1798,7 @@
     ],
     "name": "ct-nanobench-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_100k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_100k_SKPs.json
index 349bbb9..6ad5b04 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_100k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_100k_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs.json
index cb34544..698899b 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs_Trybot.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs_Trybot.json
index c2fffd6..3718c73 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs_Trybot.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_10k_SKPs_Trybot.json
@@ -1288,7 +1288,7 @@
     ],
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1350,7 +1350,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1412,7 +1412,7 @@
     ],
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1474,7 +1474,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1536,7 +1536,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs.json
index 88c01d3..cc5efa0 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_2slaves_failure.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_2slaves_failure.json
index 1f2eefd..b20aa2a 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_2slaves_failure.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_2slaves_failure.json
@@ -1283,7 +1283,7 @@
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
       "step returned non-zero exit code: 1",
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1348,7 +1348,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1411,7 +1411,7 @@
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
       "step returned non-zero exit code: 1",
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1476,7 +1476,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1538,7 +1538,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_slave3_failure.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_slave3_failure.json
index 7d72042..0ea9f53 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_slave3_failure.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_DM_1m_SKPs_slave3_failure.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-dm-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-dm-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1407,7 +1407,7 @@
     "name": "ct-dm-3 on Ubuntu-14.04",
     "~followup_annotations": [
       "step returned non-zero exit code: 1",
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1472,7 +1472,7 @@
     ],
     "name": "ct-dm-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1534,7 +1534,7 @@
     ],
     "name": "ct-dm-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_10k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_10k_SKPs.json
index 1f9c825..11a298b 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_10k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_10k_SKPs.json
@@ -1297,7 +1297,7 @@
     ],
     "name": "ct-nanobench-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1426,7 +1426,7 @@
     ],
     "name": "ct-nanobench-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1555,7 +1555,7 @@
     ],
     "name": "ct-nanobench-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1684,7 +1684,7 @@
     ],
     "name": "ct-nanobench-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1813,7 +1813,7 @@
     ],
     "name": "ct-nanobench-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_1k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_1k_SKPs.json
index 8d34932..27b55e1 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_1k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_GPU_BENCH_1k_SKPs.json
@@ -1297,7 +1297,7 @@
     ],
     "name": "ct-nanobench-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1426,7 +1426,7 @@
     ],
     "name": "ct-nanobench-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1555,7 +1555,7 @@
     ],
     "name": "ct-nanobench-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1684,7 +1684,7 @@
     ],
     "name": "ct-nanobench-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1813,7 +1813,7 @@
     ],
     "name": "ct-nanobench-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_100k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_100k_SKPs.json
index 1f0bc93..c7a3e21 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_100k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_100k_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-get_images_from_skps-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-get_images_from_skps-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-get_images_from_skps-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-get_images_from_skps-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-get_images_from_skps-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs.json
index 729f4ac..3ad4ae4 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-get_images_from_skps-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-get_images_from_skps-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-get_images_from_skps-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-get_images_from_skps-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-get_images_from_skps-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs_Trybot.json b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs_Trybot.json
index f856037..76b7068 100644
--- a/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs_Trybot.json
+++ b/infra/bots/recipes/swarm_ct_skps.expected/CT_IMG_DECODE_10k_SKPs_Trybot.json
@@ -1282,7 +1282,7 @@
     ],
     "name": "ct-get_images_from_skps-1 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1344,7 +1344,7 @@
     ],
     "name": "ct-get_images_from_skps-2 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1406,7 +1406,7 @@
     ],
     "name": "ct-get_images_from_skps-3 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1468,7 +1468,7 @@
     ],
     "name": "ct-get_images_from_skps-4 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
@@ -1530,7 +1530,7 @@
     ],
     "name": "ct-get_images_from_skps-5 on Ubuntu-14.04",
     "~followup_annotations": [
-      "@@@STEP_TEXT@swarming pending 71s@@@",
+      "@@@STEP_TEXT@Run on OS: 'Ubuntu-14.04'<br>swarming pending 71s@@@",
       "@@@STEP_LOG_LINE@json.output@{@@@",
       "@@@STEP_LOG_LINE@json.output@  \"shards\": [@@@",
       "@@@STEP_LOG_LINE@json.output@    {@@@",
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 575a368..bf850ca 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -2,26 +2,26 @@
 project_id: "skia"
 recipes_path: "infra/bots"
 deps {
-  project_id: "skia-recipes"
-  url: "https://skia.googlesource.com/skia-recipes.git"
-  branch: "master"
-  revision: "38a221c163e04dc274872ffd63b6cef1d210d751"
-}
-deps {
   project_id: "build"
   url: "https://chromium.googlesource.com/chromium/tools/build.git"
   branch: "master"
-  revision: "396d0f5c499e0b9647026a0af93052148da28d22"
+  revision: "e818a6f8774aca64e723acc369d177feb15ba5b9"
 }
 deps {
   project_id: "depot_tools"
   url: "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
   branch: "master"
-  revision: "99790f42d633be44c16516aed08c9010aab15826"
+  revision: "54985b6b969e4428c79b5b5e8fb277d25d48c404"
 }
 deps {
   project_id: "recipe_engine"
   url: "https://chromium.googlesource.com/external/github.com/luci/recipes-py.git"
   branch: "master"
-  revision: "7c73d4ed7ea86551395704ec24c2bfdfc07acc48"
+  revision: "86fea566ec648a47fbe81cce049fa8ad8b7f5ce5"
+}
+deps {
+  project_id: "skia-recipes"
+  url: "https://skia.googlesource.com/skia-recipes.git"
+  branch: "master"
+  revision: "7ab5cc6255f6bae0ce71241a26c509f557e9983b"
 }
diff --git a/src/core/SkAnalyticEdge.cpp b/src/core/SkAnalyticEdge.cpp
index 199fc4e..213262f 100644
--- a/src/core/SkAnalyticEdge.cpp
+++ b/src/core/SkAnalyticEdge.cpp
@@ -39,7 +39,11 @@
     fY          = y0;
     fUpperY     = y0;
     fLowerY     = y1;
+#ifdef SK_SUPPORT_LEGACY_AAA
     fDY         = (absSlope | dx) == 0
+#else
+    fDY         = (dx == 0 || slope == 0)
+#endif
                   ? SK_MaxS32
                   : absSlope < kInverseTableSize
                     ? QuickFDot6Inverse::Lookup(absSlope)
@@ -113,7 +117,7 @@
 #ifndef SK_SUPPORT_LEGACY_AAA
             SkASSERT(slope == SK_MaxS32 ||
                     SkAbs32(fSnappedX + SkFixedMul(slope, newSnappedY - fSnappedY) - newSnappedX)
-                    < SK_FixedHalf);
+                    < SkFixedMul(SK_Fixed1 >> 4, SkTMax(SK_Fixed1, SkAbs32(slope))));
 #endif
             dx += fQEdge.fQDDx;
             dy += fQEdge.fQDDy;
diff --git a/src/core/SkAnalyticEdge.h b/src/core/SkAnalyticEdge.h
index 1ed25f3..c70772d 100644
--- a/src/core/SkAnalyticEdge.h
+++ b/src/core/SkAnalyticEdge.h
@@ -10,11 +10,6 @@
 
 #include "SkEdge.h"
 
-// Use this to check that we successfully guard the change against Chromium layout tests
-#ifndef  SK_SUPPORT_LEGACY_AAA
-# define SK_SUPPORT_LEGACY_AAA
-#endif
-
 struct SkAnalyticEdge {
     // Similar to SkEdge, the conic edges will be converted to quadratic edges
     enum Type {
@@ -166,7 +161,6 @@
     SkFDot6 dy = SkFixedToFDot6(y1 - y0);
     SkFDot6 dx = SkFixedToFDot6(x1 - x0);
     SkFixed slope = dy ? QuickSkFDot6Div(dx, dy) : SK_MaxS32;
-    SkASSERT(dx == 0 || slope != 0);
     SkFixed absSlope = SkAbs32(slope);
 #endif
 
@@ -179,9 +173,9 @@
 #ifdef SK_SUPPORT_LEGACY_AAA
     fDY         = x1 != x0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS32;
 #else
-    fDY         = dx == 0 ? SK_MaxS32 : absSlope < kInverseTableSize
-                                                 ? QuickFDot6Inverse::Lookup(absSlope)
-                                                 : SkAbs32(QuickSkFDot6Div(dy, dx));
+    fDY         = dx == 0 || slope == 0 ? SK_MaxS32 : absSlope < kInverseTableSize
+                                                    ? QuickFDot6Inverse::Lookup(absSlope)
+                                                    : SkAbs32(QuickSkFDot6Div(dy, dx));
 #endif
     fCurveCount = 0;
     fWinding    = SkToS8(winding);
diff --git a/src/core/SkImageInfoPriv.h b/src/core/SkImageInfoPriv.h
index 029aa93..72138ae 100644
--- a/src/core/SkImageInfoPriv.h
+++ b/src/core/SkImageInfoPriv.h
@@ -69,11 +69,9 @@
         return false;
     }
 
-    // FIXME (msarett): This is commented out until a fix to Chrome's gfx_unittest lands.
-    // In those tests, they write kPremul pixels to a kOpaque canvas.
-    //if (kOpaque_SkAlphaType == dst.alphaType() && kOpaque_SkAlphaType != src.alphaType()) {
-    //    return false;
-    //}
+    if (kOpaque_SkAlphaType == dst.alphaType() && kOpaque_SkAlphaType != src.alphaType()) {
+        return false;
+    }
 
     return true;
 }
diff --git a/src/core/SkScan.h b/src/core/SkScan.h
index d0c10fa..c995542 100644
--- a/src/core/SkScan.h
+++ b/src/core/SkScan.h
@@ -23,11 +23,6 @@
 */
 typedef SkIRect SkXRect;
 
-// Use this to check that we successfully guard the change against Chromium layout tests
-#ifndef  SK_SUPPORT_LEGACY_AAA
-# define SK_SUPPORT_LEGACY_AAA
-#endif
-
 extern std::atomic<bool> gSkUseAnalyticAA;
 extern std::atomic<bool> gSkForceAnalyticAA;
 
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp
index 1263228..af45f00 100644
--- a/src/core/SkScan_AAAPath.cpp
+++ b/src/core/SkScan_AAAPath.cpp
@@ -736,14 +736,14 @@
     int uL = SkFixedFloorToInt(ul);
     int lL = SkFixedCeilToInt(ll);
     if (uL + 2 == lL) { // We only need to compute two triangles, accelerate this special case
-        SkFixed first = (uL << 16) + SK_Fixed1 - ul;
+        SkFixed first = SkIntToFixed(uL) + SK_Fixed1 - ul;
         SkFixed second = ll - ul - first;
         SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, lDY);
         SkAlpha a2 = partialTriangleToAlpha(second, lDY);
         alphas[0] = alphas[0] > a1 ? alphas[0] - a1 : 0;
         alphas[1] = alphas[1] > a2 ? alphas[1] - a2 : 0;
     } else {
-        computeAlphaBelowLine(tempAlphas + uL - L, ul - (uL << 16), ll - (uL << 16),
+        computeAlphaBelowLine(tempAlphas + uL - L, ul - SkIntToFixed(uL), ll - SkIntToFixed(uL),
                 lDY, fullAlpha);
         for (int i = uL; i < lL; ++i) {
             if (alphas[i - L] > tempAlphas[i - L]) {
@@ -757,14 +757,14 @@
     int uR = SkFixedFloorToInt(ur);
     int lR = SkFixedCeilToInt(lr);
     if (uR + 2 == lR) { // We only need to compute two triangles, accelerate this special case
-        SkFixed first = (uR << 16) + SK_Fixed1 - ur;
+        SkFixed first = SkIntToFixed(uR) + SK_Fixed1 - ur;
         SkFixed second = lr - ur - first;
         SkAlpha a1 = partialTriangleToAlpha(first, rDY);
         SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, rDY);
         alphas[len-2] = alphas[len-2] > a1 ? alphas[len-2] - a1 : 0;
         alphas[len-1] = alphas[len-1] > a2 ? alphas[len-1] - a2 : 0;
     } else {
-        computeAlphaAboveLine(tempAlphas + uR - L, ur - (uR << 16), lr - (uR << 16),
+        computeAlphaAboveLine(tempAlphas + uR - L, ur - SkIntToFixed(uR), lr - SkIntToFixed(uR),
                 rDY, fullAlpha);
         for (int i = uR; i < lR; ++i) {
             if (alphas[i - L] > tempAlphas[i - L]) {
@@ -1605,7 +1605,9 @@
                         leftEnds, false, blitter, maskRow, isUsingMask, noRealBlitter,
                         leftClip, rightClip, yShift);
             } else {
-                blit_trapezoid_row(blitter, y >> 16, left, rightClip, leftE->fX, rightClip,
+                blit_trapezoid_row(blitter, y >> 16,
+                        SkTMax(leftClip, left), rightClip,
+                        SkTMax(leftClip, leftE->fX), rightClip,
                         leftDY, 0, fullAlpha, maskRow, isUsingMask,
                         noRealBlitter ||
                                 (fullAlpha == 0xFF && edges_too_close(leftE->fPrev, leftE, nextY)),
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 1256058..5543dff 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -593,14 +593,16 @@
                                                            surfaceProps);
 }
 
-sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy) {
+sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
+                                                                 sk_sp<SkColorSpace> colorSpace) {
     ASSERT_SINGLE_OWNER_PRIV
 
     if (proxy->asRenderTargetProxy()) {
-        return this->drawingManager()->makeRenderTargetContext(std::move(proxy), nullptr, nullptr);
+        return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
+                                                               std::move(colorSpace), nullptr);
     } else {
         SkASSERT(proxy->asTextureProxy());
-        return this->drawingManager()->makeTextureContext(std::move(proxy));
+        return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
     }
 }
 
@@ -609,7 +611,7 @@
 
     sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface)));
 
-    return this->makeWrappedSurfaceContext(std::move(proxy));
+    return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
 }
 
 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
@@ -619,7 +621,7 @@
     sk_sp<GrSurfaceProxy> proxy = GrSurfaceProxy::MakeDeferred(*fContext->caps(), dstDesc,
                                                                fit, isDstBudgeted);
 
-    return this->makeWrappedSurfaceContext(std::move(proxy));
+    return this->makeWrappedSurfaceContext(std::move(proxy), nullptr);
 }
 
 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index e24a588..3315c94 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -28,7 +28,8 @@
     // Create a surfaceContext that wraps an existing texture or renderTarget
     sk_sp<GrSurfaceContext> makeWrappedSurfaceContext(sk_sp<GrSurface> tex);
 
-    sk_sp<GrSurfaceContext> makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy);
+    sk_sp<GrSurfaceContext> makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
+                                                      sk_sp<SkColorSpace>);
 
     sk_sp<GrSurfaceContext> makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
                                                        SkBackingFit dstFit,
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index 515e26e..3a7110e 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -238,16 +238,16 @@
         return nullptr;
     }
 
-    sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy()));
-
     // SkSurface catches bad color space usage at creation. This check handles anything that slips
     // by, including internal usage. We allow a null color space here, for read/write pixels and
     // other special code paths. If a color space is provided, though, enforce all other rules.
-    if (colorSpace && !SkSurface_Gpu::Valid(fContext, rtp->config(), colorSpace.get())) {
+    if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
         SkDEBUGFAIL("Invalid config and colorspace combination");
         return nullptr;
     }
 
+    sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy()));
+
     bool useDIF = false;
     if (surfaceProps) {
         useDIF = surfaceProps->isUseDeviceIndependentFonts();
@@ -276,16 +276,27 @@
                                                                   fSingleOwner));
 }
 
-sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy) {
+sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy,
+                                                             sk_sp<SkColorSpace> colorSpace) {
     if (this->wasAbandoned() || !sProxy->asTextureProxy()) {
         return nullptr;
     }
 
+    // SkSurface catches bad color space usage at creation. This check handles anything that slips
+    // by, including internal usage. We allow a null color space here, for read/write pixels and
+    // other special code paths. If a color space is provided, though, enforce all other rules.
+    if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) {
+        SkDEBUGFAIL("Invalid config and colorspace combination");
+        return nullptr;
+    }
+
     // GrTextureRenderTargets should always be using GrRenderTargetContext
     SkASSERT(!sProxy->asRenderTargetProxy());
 
     sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy()));
 
     return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy),
-                                                        fContext->getAuditTrail(), fSingleOwner));
+                                                        std::move(colorSpace),
+                                                        fContext->getAuditTrail(),
+                                                        fSingleOwner));
 }
diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h
index 9a05215..061e878 100644
--- a/src/gpu/GrDrawingManager.h
+++ b/src/gpu/GrDrawingManager.h
@@ -39,7 +39,7 @@
     sk_sp<GrRenderTargetContext> makeRenderTargetContext(sk_sp<GrSurfaceProxy>,
                                                          sk_sp<SkColorSpace>,
                                                          const SkSurfaceProps*);
-    sk_sp<GrTextureContext> makeTextureContext(sk_sp<GrSurfaceProxy>);
+    sk_sp<GrTextureContext> makeTextureContext(sk_sp<GrSurfaceProxy>, sk_sp<SkColorSpace>);
 
     // The caller automatically gets a ref on the returned opList. It must
     // be balanced by an unref call.
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index b0d941b..39d5597 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -81,15 +81,13 @@
                                              const SkSurfaceProps* surfaceProps,
                                              GrAuditTrail* auditTrail,
                                              GrSingleOwner* singleOwner)
-    : GrSurfaceContext(context, auditTrail, singleOwner)
+    : GrSurfaceContext(context, std::move(colorSpace), auditTrail, singleOwner)
     , fDrawingManager(drawingMgr)
     , fRenderTargetProxy(std::move(rtp))
     , fOpList(SkSafeRef(fRenderTargetProxy->getLastRenderTargetOpList()))
     , fInstancedPipelineInfo(fRenderTargetProxy.get())
-    , fColorSpace(std::move(colorSpace))
     , fColorXformFromSRGB(nullptr)
-    , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
-{
+    , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) {
     if (fColorSpace) {
         // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
         auto srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
@@ -158,6 +156,56 @@
     return this->getOpList()->copySurface(rt.get(), src.get(), srcRect, dstPoint);
 }
 
+// TODO: move this (and GrTextureContext::onReadPixels) to GrSurfaceContext?
+bool GrRenderTargetContext::onReadPixels(const SkImageInfo& dstInfo, void* dstBuffer,
+                                         size_t dstRowBytes, int x, int y) {
+    // TODO: teach GrRenderTarget to take ImageInfo directly to specify the src pixels
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps());
+    if (kUnknown_GrPixelConfig == config) {
+        return false;
+    }
+
+    uint32_t flags = 0;
+    if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
+        flags = GrContext::kUnpremul_PixelOpsFlag;
+    }
+
+    // Deferral of the VRAM resources must end in this instance anyway
+    sk_sp<GrRenderTarget> rt(
+                        sk_ref_sp(fRenderTargetProxy->instantiate(fContext->textureProvider())));
+    if (!rt) {
+        return false;
+    }
+
+    return rt->readPixels(this->getColorSpace(), x, y, dstInfo.width(), dstInfo.height(),
+                          config, dstInfo.colorSpace(), dstBuffer, dstRowBytes, flags);
+}
+
+// TODO: move this (and GrTextureContext::onReadPixels) to GrSurfaceContext?
+bool GrRenderTargetContext::onWritePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
+                                          size_t srcRowBytes, int x, int y) {
+    // TODO: teach GrRenderTarget to take ImageInfo directly to specify the src pixels
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps());
+    if (kUnknown_GrPixelConfig == config) {
+        return false;
+    }
+    uint32_t flags = 0;
+    if (kUnpremul_SkAlphaType == srcInfo.alphaType()) {
+        flags = GrContext::kUnpremul_PixelOpsFlag;
+    }
+
+    // Deferral of the VRAM resources must end in this instance anyway
+    sk_sp<GrRenderTarget> rt(
+                        sk_ref_sp(fRenderTargetProxy->instantiate(fContext->textureProvider())));
+    if (!rt) {
+        return false;
+    }
+
+    return rt->writePixels(this->getColorSpace(), x, y, srcInfo.width(), srcInfo.height(),
+                           config, srcInfo.colorSpace(), srcBuffer, srcRowBytes, flags);
+}
+
+
 void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint,
                                      const SkMatrix& viewMatrix, const char text[],
                                      size_t byteLength, SkScalar x, SkScalar y,
@@ -1267,53 +1315,6 @@
     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, std::move(op));
 }
 
-bool GrRenderTargetContext::readPixels(const SkImageInfo& dstInfo, void* dstBuffer,
-                                       size_t dstRowBytes, int x, int y) {
-    // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
-    GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps());
-    if (kUnknown_GrPixelConfig == config) {
-        return false;
-    }
-
-    uint32_t flags = 0;
-    if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
-        flags = GrContext::kUnpremul_PixelOpsFlag;
-    }
-
-    // Deferral of the VRAM resources must end in this instance anyway
-    sk_sp<GrRenderTarget> rt(
-                        sk_ref_sp(fRenderTargetProxy->instantiate(fContext->textureProvider())));
-    if (!rt) {
-        return false;
-    }
-
-    return rt->readPixels(this->getColorSpace(), x, y, dstInfo.width(), dstInfo.height(),
-                          config, dstInfo.colorSpace(), dstBuffer, dstRowBytes, flags);
-}
-
-bool GrRenderTargetContext::writePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
-                                        size_t srcRowBytes, int x, int y) {
-    // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
-    GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps());
-    if (kUnknown_GrPixelConfig == config) {
-        return false;
-    }
-    uint32_t flags = 0;
-    if (kUnpremul_SkAlphaType == srcInfo.alphaType()) {
-        flags = GrContext::kUnpremul_PixelOpsFlag;
-    }
-
-    // Deferral of the VRAM resources must end in this instance anyway
-    sk_sp<GrRenderTarget> rt(
-                        sk_ref_sp(fRenderTargetProxy->instantiate(fContext->textureProvider())));
-    if (!rt) {
-        return false;
-    }
-
-    return rt->writePixels(this->getColorSpace(), x, y, srcInfo.width(), srcInfo.height(),
-                           config, srcInfo.colorSpace(), srcBuffer, srcRowBytes, flags);
-}
-
 // Can 'path' be drawn as a pair of filled nested rectangles?
 static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
 
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 682233b..f8c1cbc 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -15,9 +15,11 @@
 // stack. When this occurs with a closed GrOpList, a new one will be allocated
 // when the renderTargetContext attempts to use it (via getOpList).
 GrSurfaceContext::GrSurfaceContext(GrContext* context,
+                                   sk_sp<SkColorSpace> colorSpace,
                                    GrAuditTrail* auditTrail,
                                    GrSingleOwner* singleOwner)
     : fContext(context)
+    , fColorSpace(std::move(colorSpace))
     , fAuditTrail(auditTrail)
 #ifdef SK_DEBUG
     , fSingleOwner(singleOwner)
diff --git a/src/gpu/GrTextureContext.cpp b/src/gpu/GrTextureContext.cpp
index 9f61551..7ca1e54 100644
--- a/src/gpu/GrTextureContext.cpp
+++ b/src/gpu/GrTextureContext.cpp
@@ -19,9 +19,10 @@
 GrTextureContext::GrTextureContext(GrContext* context,
                                    GrDrawingManager* drawingMgr,
                                    sk_sp<GrTextureProxy> textureProxy,
+                                   sk_sp<SkColorSpace> colorSpace,
                                    GrAuditTrail* auditTrail,
                                    GrSingleOwner* singleOwner)
-    : GrSurfaceContext(context, auditTrail, singleOwner)
+    : GrSurfaceContext(context, std::move(colorSpace), auditTrail, singleOwner)
     , fDrawingManager(drawingMgr)
     , fTextureProxy(std::move(textureProxy))
     , fOpList(SkSafeRef(fTextureProxy->getLastTextureOpList())) {
@@ -75,11 +76,11 @@
     if (!src) {
         return false;
     }
-

-#ifndef ENABLE_MDB

-    // We can't yet fully defer copies to textures, so GrTextureContext::copySurface will

-    // execute the copy immediately. Ensure the data is ready.

-    src->flushWrites();

+
+#ifndef ENABLE_MDB
+    // We can't yet fully defer copies to textures, so GrTextureContext::copySurface will
+    // execute the copy immediately. Ensure the data is ready.
+    src->flushWrites();
 #endif
 
     // TODO: this needs to be fixed up since it ends the deferrable of the GrTexture
@@ -100,3 +101,50 @@
 
     return result;
 }
+
+// TODO: move this (and GrRenderTargetContext::onReadPixels) to GrSurfaceContext?
+bool GrTextureContext::onReadPixels(const SkImageInfo& dstInfo, void* dstBuffer,
+                                    size_t dstRowBytes, int x, int y) {
+    // TODO: teach GrTexture to take ImageInfo directly to specify the src pixels
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps());
+    if (kUnknown_GrPixelConfig == config) {
+        return false;
+    }
+
+    uint32_t flags = 0;
+    if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
+        flags = GrContext::kUnpremul_PixelOpsFlag;
+    }
+
+    // Deferral of the VRAM resources must end in this instance anyway
+    sk_sp<GrTexture> tex(sk_ref_sp(fTextureProxy->instantiate(fContext->textureProvider())));
+    if (!tex) {
+        return false;
+    }
+
+    return tex->readPixels(this->getColorSpace(), x, y, dstInfo.width(), dstInfo.height(),
+                           config, dstInfo.colorSpace(), dstBuffer, dstRowBytes, flags);
+}
+
+// TODO: move this (and GrRenderTargetContext::onReadPixels) to GrSurfaceContext?
+bool GrTextureContext::onWritePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
+                                     size_t srcRowBytes, int x, int y) {
+    // TODO: teach GrTexture to take ImageInfo directly to specify the src pixels
+    GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps());
+    if (kUnknown_GrPixelConfig == config) {
+        return false;
+    }
+    uint32_t flags = 0;
+    if (kUnpremul_SkAlphaType == srcInfo.alphaType()) {
+        flags = GrContext::kUnpremul_PixelOpsFlag;
+    }
+
+    // Deferral of the VRAM resources must end in this instance anyway
+    sk_sp<GrTexture> tex(sk_ref_sp(fTextureProxy->instantiate(fContext->textureProvider())));
+    if (!tex) {
+        return false;
+    }
+
+    return tex->writePixels(this->getColorSpace(), x, y, srcInfo.width(), srcInfo.height(),
+                            config, srcInfo.colorSpace(), srcBuffer, srcRowBytes, flags);
+}
diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp
index e51f6cc..5b71a07 100644
--- a/src/gpu/text/GrAtlasGlyphCache.cpp
+++ b/src/gpu/text/GrAtlasGlyphCache.cpp
@@ -125,7 +125,8 @@
     }
 
     sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
-                                                                            sk_ref_sp(sProxy)));
+                                                                            sk_ref_sp(sProxy),
+                                                                            nullptr));
     if (!sContext || !sContext->asDeferredTexture()) {
         return false;
     }
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index b56b1ba..02f53e7 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -91,6 +91,10 @@
     return true;
 }
 
+sk_sp<GrSurfaceProxy> SkImage_Gpu::refProxy() const {
+    return GrSurfaceProxy::MakeWrapped(fTexture);
+}
+
 GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrSamplerParams& params,
                                      SkColorSpace* dstColorSpace,
                                      sk_sp<SkColorSpace>* texColorSpace) const {
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 2098864..2d6f3bd 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -43,6 +43,7 @@
                             sk_sp<SkColorSpace>*) const override;
     sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
 
+    sk_sp<GrSurfaceProxy> refProxy() const;
     GrTexture* peekTexture() const override { return fTexture.get(); }
     sk_sp<GrTexture> refPinnedTexture(uint32_t* uniqueID) const override {
         *uniqueID = this->uniqueID();
@@ -51,6 +52,9 @@
     bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,
                       int srcX, int srcY, CachingHint) const override;
 
+    GrContext* context() { return fTexture->getContext(); }
+    sk_sp<SkColorSpace> refColorSpace() { return fColorSpace; }
+
 private:
     sk_sp<GrTexture>       fTexture;
     const SkAlphaType      fAlphaType;
diff --git a/tests/CopySurfaceTest.cpp b/tests/CopySurfaceTest.cpp
index 951d272..efb6b2d 100644
--- a/tests/CopySurfaceTest.cpp
+++ b/tests/CopySurfaceTest.cpp
@@ -91,7 +91,7 @@
                             }
 
                             sk_sp<GrSurfaceContext> sContext =
-                                            context->contextPriv().makeWrappedSurfaceContext(dst);
+                                   context->contextPriv().makeWrappedSurfaceContext(dst, nullptr);
 
                             bool result = sContext->copy(src.get(), srcRect, dstPoint);
 
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 1f04de5..29aee9c 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -20,6 +20,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
+#include "GrContextPriv.h"
 #include "GrRenderTargetContext.h"
 #include "GrGpu.h"
 #include "GrResourceProvider.h"
@@ -626,7 +627,7 @@
 }
 
 static void test_surface_clear(skiatest::Reporter* reporter, sk_sp<SkSurface> surface,
-                               std::function<GrSurface*(SkSurface*)> grSurfaceGetter,
+                               std::function<sk_sp<GrSurfaceContext>(SkSurface*)> grSurfaceGetter,
                                uint32_t expectedValue) {
     if (!surface) {
         ERRORF(reporter, "Could not create GPU SkSurface.");
@@ -637,13 +638,15 @@
     std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]);
     sk_memset32(pixels.get(), ~expectedValue, w * h);
 
-    sk_sp<GrSurface> grSurface(SkSafeRef(grSurfaceGetter(surface.get())));
-    if (!grSurface) {
+    sk_sp<GrSurfaceContext> grSurfaceContext(grSurfaceGetter(surface.get()));
+    if (!grSurfaceContext) {
         ERRORF(reporter, "Could access render target of GPU SkSurface.");
         return;
     }
     surface.reset();
-    grSurface->readPixels(0, 0, w, h, kRGBA_8888_GrPixelConfig, pixels.get());
+
+    SkImageInfo ii = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+    grSurfaceContext->readPixels(ii, pixels.get(), 0, 0, 0);
     for (int y = 0; y < h; ++y) {
         for (int x = 0; x < w; ++x) {
             uint32_t pixel = pixels.get()[y * w + x];
@@ -666,16 +669,21 @@
 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceClear_Gpu, reporter, ctxInfo) {
     GrContext* context = ctxInfo.grContext();
 
-    std::function<GrSurface*(SkSurface*)> grSurfaceGetters[] = {
+    std::function<sk_sp<GrSurfaceContext>(SkSurface*)> grSurfaceContextGetters[] = {
         [] (SkSurface* s){
-            GrRenderTargetContext* rtc =
-                s->getCanvas()->internal_private_accessTopLayerRenderTargetContext();
-            return rtc->accessRenderTarget(); },
-        [] (SkSurface* s){ sk_sp<SkImage> i(s->makeImageSnapshot());
-                           return as_IB(i)->peekTexture(); }
+            return sk_ref_sp(s->getCanvas()->internal_private_accessTopLayerRenderTargetContext());
+        },
+        [] (SkSurface* s){
+            sk_sp<SkImage> i(s->makeImageSnapshot());
+            SkImage_Gpu* gpuImage = (SkImage_Gpu *) as_IB(i);
+            sk_sp<GrSurfaceProxy> proxy = gpuImage->refProxy();
+            GrContext* context = gpuImage->context();
+            return context->contextPriv().makeWrappedSurfaceContext(std::move(proxy),
+                                                                    gpuImage->refColorSpace());
+        }
     };
 
-    for (auto grSurfaceGetter : grSurfaceGetters) {
+    for (auto grSurfaceGetter : grSurfaceContextGetters) {
         // Test that non-wrapped RTs are created clear.
         for (auto& surface_func : {&create_gpu_surface, &create_gpu_scratch_surface}) {
             auto surface = surface_func(context, kPremul_SkAlphaType, nullptr);