Move annotations to canvas virtual (patchset #8 id:140001 of https://codereview.chromium.org/1744103002/ )"

Need to land chrome change first https://codereview.chromium.org/1766723003/

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

TBR=

Review URL: https://codereview.chromium.org/1758023003
diff --git a/include/core/SkAnnotation.h b/include/core/SkAnnotation.h
index 80503c7..2ea66d3 100644
--- a/include/core/SkAnnotation.h
+++ b/include/core/SkAnnotation.h
@@ -1,3 +1,4 @@
+
 /*
  * Copyright 2012 Google Inc.
  *
@@ -8,83 +9,21 @@
 #ifndef SkAnnotation_DEFINED
 #define SkAnnotation_DEFINED
 
-#include "SkRefCnt.h"
-#include "SkString.h"
 #include "SkTypes.h"
 
+// for chrome in PrintContextTest.cpp
+#define SK_SUPPORT_NEW_ANNOTATION_CANVAS_VIRTUAL
+
 class SkData;
-class SkReadBuffer;
-class SkWriteBuffer;
 struct SkPoint;
-
-/**
- *  Experimental class for annotating draws. Do not use directly yet.
- *  Use helper functions at the bottom of this file for now.
- */
-class SkAnnotation : public SkRefCnt {
-public:
-    virtual ~SkAnnotation();
-
-    static SkAnnotation* Create(const char key[], SkData* value) {
-        return new SkAnnotation(key, value);
-    }
-
-    static SkAnnotation* Create(SkReadBuffer& buffer) { return new SkAnnotation(buffer); }
-
-    /**
-     *  Return the data for the specified key, or NULL.
-     */
-    SkData* find(const char key[]) const;
-
-    void writeToBuffer(SkWriteBuffer&) const;
-
-private:
-    SkAnnotation(const char key[], SkData* value);
-    SkAnnotation(SkReadBuffer&);
-
-    SkString    fKey;
-    SkData*     fData;
-
-    typedef SkRefCnt INHERITED;
-};
-
-/**
- *  Experimental collection of predefined Keys into the Annotation dictionary
- */
-class SkAnnotationKeys {
-public:
-    /**
-     *  Returns the canonical key whose payload is a URL
-     */
-    static const char* URL_Key();
-
-    /**
-     *  Returns the canonical key whose payload is the name of a destination to
-     *  be defined.
-     */
-    static const char* Define_Named_Dest_Key();
-
-    /**
-     *  Returns the canonical key whose payload is the name of a destination to
-     *  be linked to.
-     */
-    static const char* Link_Named_Dest_Key();
-};
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// Experimental helper functions to use Annotations
-//
-
 struct SkRect;
 class SkCanvas;
 
 /**
- *  Experimental!
- *
  *  Annotate the canvas by associating the specified URL with the
- *  specified rectangle (in local coordinates, just like drawRect). If the
- *  backend of this canvas does not support annotations, this call is
+ *  specified rectangle (in local coordinates, just like drawRect).
+ *
+ *  If the backend of this canvas does not support annotations, this call is
  *  safely ignored.
  *
  *  The caller is responsible for managing its ownership of the SkData.
@@ -92,8 +31,6 @@
 SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*);
 
 /**
- *  Experimental!
- *
  *  Annotate the canvas by associating a name with the specified point.
  *
  *  If the backend of this canvas does not support annotations, this call is
@@ -104,8 +41,6 @@
 SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*);
 
 /**
- *  Experimental!
- *
  *  Annotate the canvas by making the specified rectangle link to a named
  *  destination.
  *
@@ -116,5 +51,4 @@
  */
 SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*);
 
-
 #endif
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index c23d748..1b4571a 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -22,6 +22,7 @@
 class SkBaseDevice;
 class SkCanvasClipVisitor;
 class SkClipStack;
+class SkData;
 class SkDraw;
 class SkDrawable;
 class SkDrawFilter;
@@ -1072,6 +1073,18 @@
     void drawDrawable(SkDrawable* drawable, const SkMatrix* = NULL);
     void drawDrawable(SkDrawable*, SkScalar x, SkScalar y);
 
+    /**
+     *  Send an "annotation" to the canvas. The annotation is a key/value pair, where the key is
+     *  a null-terminated utf8 string, and the value is a blob of data stored in an SkData
+     *  (which may be null). The annotation is associated with the specified rectangle.
+     *
+     *  The caller still retains its ownership of the data (if any).
+     *
+     *  Note: on may canvas types, this information is ignored, but some canvases (e.g. recording
+     *  a picture or drawing to a PDF document) will pass on this information.
+     */
+    void drawAnnotation(const SkRect&, const char key[], SkData* value);
+
     //////////////////////////////////////////////////////////////////////////
 #ifdef SK_INTERNAL
 #ifndef SK_SUPPORT_LEGACY_DRAWFILTER
@@ -1221,6 +1234,7 @@
     virtual void didConcat(const SkMatrix&) {}
     virtual void didSetMatrix(const SkMatrix&) {}
 
+    virtual void onDrawAnnotation(const SkRect&, const char key[], SkData* value);
     virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&);
 
     virtual void onDrawText(const void* text, size_t byteLength, SkScalar x,
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 65ec56f..cd13d54 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -252,6 +252,8 @@
     virtual void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
                            const SkColor[], int count, SkXfermode::Mode, const SkPaint&);
 
+    virtual void drawAnnotation(const SkDraw&, const SkRect&, const char[], SkData*) {}
+
     /** The SkDevice passed will be an SkDevice which was returned by a call to
         onCreateDevice on this device with kNeverTile_TileExpectation.
      */
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index b58a3f3..7090f3e 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -13,7 +13,6 @@
 #include "SkMatrix.h"
 #include "SkXfermode.h"
 
-class SkAnnotation;
 class SkAutoDescriptor;
 class SkAutoGlyphCache;
 class SkColorFilter;
@@ -625,9 +624,6 @@
     SkImageFilter* getImageFilter() const { return fImageFilter; }
     SkImageFilter* setImageFilter(SkImageFilter*);
 
-    SkAnnotation* getAnnotation() const { return fAnnotation; }
-    SkAnnotation* setAnnotation(SkAnnotation*);
-
     /**
      *  Return the paint's SkDrawLooper (if any). Does not affect the looper's
      *  reference count.
@@ -1039,7 +1035,6 @@
     SkRasterizer*   fRasterizer;
     SkDrawLooper*   fLooper;
     SkImageFilter*  fImageFilter;
-    SkAnnotation*   fAnnotation;
 
     SkScalar        fTextSize;
     SkScalar        fTextScaleX;
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 7c8c187..36f5310 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -192,10 +192,11 @@
     // V41: Added serialization of SkBitmapSource's filterQuality parameter
     // V42: Added a bool to SkPictureShader serialization to indicate did-we-serialize-a-picture?
     // V43: Added DRAW_IMAGE and DRAW_IMAGE_RECT opt codes to serialized data
+    // V44: Move annotations from paint to drawAnnotation
 
     // Only SKPs within the min/current picture version range (inclusive) can be read.
     static const uint32_t     MIN_PICTURE_VERSION = 35;     // Produced by Chrome M39.
-    static const uint32_t CURRENT_PICTURE_VERSION = 43;
+    static const uint32_t CURRENT_PICTURE_VERSION = 44;
 
     static_assert(MIN_PICTURE_VERSION <= 41,
                   "Remove kFontFileName and related code from SkFontDescriptor.cpp.");
@@ -205,7 +206,7 @@
 
     static_assert(MIN_PICTURE_VERSION <= 43,
                   "Remove SkBitmapSourceDeserializer.");
-
+    
     static bool IsValidPictInfo(const SkPictInfo& info);
     static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);
 
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index 1e7ec6d..a2c6f5d 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -206,6 +206,18 @@
      */
     static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
 
+    void writeData(const SkData* data) {
+        uint32_t len = data ? SkToU32(data->size()) : 0;
+        this->write32(len);
+        if (data) {
+            this->writePad(data->data(), len);
+        }
+    }
+
+    static size_t WriteDataSize(const SkData* data) {
+        return 4 + SkAlign4(data ? data->size() : 0);
+    }
+
     /**
      *  Move the cursor back to offset bytes from the beginning.
      *  offset must be a multiple of 4 no greater than size().
diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h
index ecd73a1..1e274e9 100644
--- a/include/private/SkRecords.h
+++ b/include/private/SkRecords.h
@@ -8,6 +8,7 @@
 #ifndef SkRecords_DEFINED
 #define SkRecords_DEFINED
 
+#include "SkData.h"
 #include "SkCanvas.h"
 #include "SkDrawable.h"
 #include "SkImageFilter.h"
@@ -17,6 +18,7 @@
 #include "SkRect.h"
 #include "SkRRect.h"
 #include "SkRSXform.h"
+#include "SkString.h"
 #include "SkTextBlob.h"
 
 namespace SkRecords {
@@ -66,7 +68,8 @@
     M(DrawRect)                                                     \
     M(DrawTextBlob)                                                 \
     M(DrawAtlas)                                                    \
-    M(DrawVertices)
+    M(DrawVertices)                                                 \
+    M(DrawAnnotation)
 
 // Defines SkRecords::Type, an enum of all record types.
 #define ENUM(T) T##_Type,
@@ -358,7 +361,10 @@
         RefBox<SkXfermode> xmode;
         PODArray<uint16_t> indices;
         int indexCount);
-
+RECORD(DrawAnnotation, 0,
+       SkRect rect;
+       SkString key;
+       RefBox<SkData> value);
 #undef RECORD
 
 }  // namespace SkRecords
diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index d4c6dbf..1c16bf3 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -48,6 +48,7 @@
         kDrawVertices_Verb,
         kDrawPatch_Verb,
         kDrawData_Verb, // obsolete
+        kDrawAnnotation_Verb,
 
         kCull_Verb
     };
@@ -120,6 +121,7 @@
     void onClipRegion(const SkRegion&, SkRegion::Op) override;
 
     void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+    void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override;
 
     static const char* EdgeStyleToAAString(ClipEdgeStyle edgeStyle);
 
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index 175701e..f2a99db 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -79,6 +79,7 @@
     void onClipRegion(const SkRegion&, SkRegion::Op) override;
 
     void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
 
     class Iter;
 
diff --git a/samplecode/SampleFilterFuzz.cpp b/samplecode/SampleFilterFuzz.cpp
index 687921a..28155f1 100644
--- a/samplecode/SampleFilterFuzz.cpp
+++ b/samplecode/SampleFilterFuzz.cpp
@@ -9,7 +9,6 @@
 #include "Sk2DPathEffect.h"
 #include "SkAlphaThresholdFilter.h"
 #include "SkArcToPathEffect.h"
-#include "SkAnnotation.h"
 #include "SkBlurImageFilter.h"
 #include "SkBlurMaskFilter.h"
 #include "SkCanvas.h"
@@ -545,9 +544,6 @@
     paint.setRasterizer(rasterizer);
     paint.setImageFilter(make_image_filter());
     SkAutoDataUnref data(make_3Dlut(nullptr, make_bool(), make_bool(), make_bool()));
-    SkAutoTUnref<SkAnnotation> annotation(
-        SkAnnotation::Create(make_string().c_str(), data));
-    paint.setAnnotation(annotation);
     paint.setTextAlign(make_paint_align());
     paint.setTextSize(make_scalar());
     paint.setTextScaleX(make_scalar());
diff --git a/src/core/SkAnnotation.cpp b/src/core/SkAnnotation.cpp
index 84d41fc..09a6296 100644
--- a/src/core/SkAnnotation.cpp
+++ b/src/core/SkAnnotation.cpp
@@ -6,38 +6,10 @@
  */
 
 #include "SkAnnotation.h"
-#include "SkData.h"
-#include "SkPaint.h"
+#include "SkAnnotationKeys.h"
+#include "SkCanvas.h"
 #include "SkPoint.h"
-#include "SkReadBuffer.h"
-#include "SkWriteBuffer.h"
-
-SkAnnotation::SkAnnotation(const char key[], SkData* value) : fKey(key) {
-    if (nullptr == value) {
-        value = SkData::NewEmpty();
-    } else {
-        value->ref();
-    }
-    fData = value;
-}
-
-SkAnnotation::~SkAnnotation() {
-    fData->unref();
-}
-
-SkData* SkAnnotation::find(const char key[]) const {
-    return fKey.equals(key) ? fData : nullptr;
-}
-
-SkAnnotation::SkAnnotation(SkReadBuffer& buffer) {
-    buffer.readString(&fKey);
-    fData = buffer.readByteArrayAsData();
-}
-
-void SkAnnotation::writeToBuffer(SkWriteBuffer& buffer) const {
-    buffer.writeString(fKey.c_str());
-    buffer.writeDataAsByteArray(fData);
-}
+#include "SkRect.h"
 
 const char* SkAnnotationKeys::URL_Key() {
     return "SkAnnotationKey_URL";
@@ -51,37 +23,26 @@
     return "SkAnnotationKey_Link_Named_Dest";
 };
 
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkCanvas.h"
-
-static void annotate_paint(SkPaint& paint, const char* key, SkData* value) {
-    paint.setAnnotation(SkAnnotation::Create(key, value))->unref();
-}
+//////////////////////////////////////////////////////////////////////////////////////////////////
 
 void SkAnnotateRectWithURL(SkCanvas* canvas, const SkRect& rect, SkData* value) {
     if (nullptr == value) {
         return;
     }
-    SkPaint paint;
-    annotate_paint(paint, SkAnnotationKeys::URL_Key(), value);
-    canvas->drawRect(rect, paint);
+    canvas->drawAnnotation(rect, SkAnnotationKeys::URL_Key(), value);
 }
 
 void SkAnnotateNamedDestination(SkCanvas* canvas, const SkPoint& point, SkData* name) {
     if (nullptr == name) {
         return;
     }
-    SkPaint paint;
-    annotate_paint(paint, SkAnnotationKeys::Define_Named_Dest_Key(), name);
-    canvas->drawPoint(point.x(), point.y(), paint);
+    const SkRect rect = SkRect::MakeXYWH(point.x(), point.y(), 0, 0);
+    canvas->drawAnnotation(rect, SkAnnotationKeys::Define_Named_Dest_Key(), name);
 }
 
 void SkAnnotateLinkToDestination(SkCanvas* canvas, const SkRect& rect, SkData* name) {
     if (nullptr == name) {
         return;
     }
-    SkPaint paint;
-    annotate_paint(paint, SkAnnotationKeys::Link_Named_Dest_Key(), name);
-    canvas->drawRect(rect, paint);
+    canvas->drawAnnotation(rect, SkAnnotationKeys::Link_Named_Dest_Key(), name);
 }
diff --git a/src/core/SkAnnotationKeys.h b/src/core/SkAnnotationKeys.h
new file mode 100644
index 0000000..dff9338
--- /dev/null
+++ b/src/core/SkAnnotationKeys.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAnnotationKeys_DEFINED
+#define SkAnnotationKeys_DEFINED
+
+#include "SkTypes.h"
+
+class SkAnnotationKeys {
+public:
+    /**
+     *  Returns the canonical key whose payload is a URL
+     */
+    static const char* URL_Key();
+
+    /**
+     *  Returns the canonical key whose payload is the name of a destination to
+     *  be defined.
+     */
+    static const char* Define_Named_Dest_Key();
+
+    /**
+     *  Returns the canonical key whose payload is the name of a destination to
+     *  be linked to.
+     */
+    static const char* Link_Named_Dest_Key();
+};
+
+#endif
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 8c3c562..d5dfcc1 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -20,9 +20,6 @@
 
 class SkColorTable;
 
-#define CHECK_FOR_ANNOTATION(paint) \
-    do { if (paint.getAnnotation()) { return; } } while (0)
-
 static bool valid_for_bitmap_device(const SkImageInfo& info,
                                     SkAlphaType* newAlphaType) {
     if (info.width() < 0 || info.height() < 0) {
@@ -204,18 +201,14 @@
 
 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
                                 const SkPoint pts[], const SkPaint& paint) {
-    CHECK_FOR_ANNOTATION(paint);
     draw.drawPoints(mode, count, pts, paint);
 }
 
 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
-    CHECK_FOR_ANNOTATION(paint);
     draw.drawRect(r, paint);
 }
 
 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
-    CHECK_FOR_ANNOTATION(paint);
-
     SkPath path;
     path.addOval(oval);
     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
@@ -224,8 +217,6 @@
 }
 
 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
-    CHECK_FOR_ANNOTATION(paint);
-
 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
     SkPath  path;
 
@@ -241,7 +232,6 @@
 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path,
                               const SkPaint& paint, const SkMatrix* prePathMatrix,
                               bool pathIsMutable) {
-    CHECK_FOR_ANNOTATION(paint);
     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
 }
 
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a628105..f3f3838 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1973,6 +1973,12 @@
     this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
 }
 
+void SkCanvas::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    if (key) {
+        this->onDrawAnnotation(rect, key, value);
+    }
+}
+
 void SkCanvas::legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
                                     const SkPaint* paint, SrcRectConstraint constraint) {
     if (src) {
@@ -2725,6 +2731,17 @@
     LOOPER_END
 }
 
+void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    SkASSERT(key);
+
+    SkPaint paint;
+    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, nullptr)
+    while (iter.next()) {
+        iter.fDevice->drawAnnotation(iter, rect, key, value);
+    }
+    LOOPER_END
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // These methods are NOT virtual, and therefore must call back into virtual
 // methods, rather than actually drawing themselves.
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 017662f..cdfb110 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -6,7 +6,6 @@
  */
 
 #include "SkPaint.h"
-#include "SkAnnotation.h"
 #include "SkAutoKern.h"
 #include "SkChecksum.h"
 #include "SkColorFilter.h"
@@ -54,7 +53,6 @@
     fRasterizer  = nullptr;
     fLooper      = nullptr;
     fImageFilter = nullptr;
-    fAnnotation  = nullptr;
 
     fTextSize   = SkPaintDefaults_TextSize;
     fTextScaleX = SK_Scalar1;
@@ -87,7 +85,6 @@
     REF_COPY(fRasterizer);
     REF_COPY(fLooper);
     REF_COPY(fImageFilter);
-    REF_COPY(fAnnotation);
 
     COPY(fTextSize);
     COPY(fTextScaleX);
@@ -114,7 +111,6 @@
     REF_MOVE(fRasterizer);
     REF_MOVE(fLooper);
     REF_MOVE(fImageFilter);
-    REF_MOVE(fAnnotation);
 
     MOVE(fTextSize);
     MOVE(fTextScaleX);
@@ -138,7 +134,6 @@
     SkSafeUnref(fRasterizer);
     SkSafeUnref(fLooper);
     SkSafeUnref(fImageFilter);
-    SkSafeUnref(fAnnotation);
 }
 
 SkPaint& SkPaint::operator=(const SkPaint& src) {
@@ -158,7 +153,6 @@
     REF_COPY(fRasterizer);
     REF_COPY(fLooper);
     REF_COPY(fImageFilter);
-    REF_COPY(fAnnotation);
 
     COPY(fTextSize);
     COPY(fTextScaleX);
@@ -191,7 +185,6 @@
     REF_MOVE(fRasterizer);
     REF_MOVE(fLooper);
     REF_MOVE(fImageFilter);
-    REF_MOVE(fAnnotation);
 
     MOVE(fTextSize);
     MOVE(fTextScaleX);
@@ -218,7 +211,6 @@
         && EQUAL(fRasterizer)
         && EQUAL(fLooper)
         && EQUAL(fImageFilter)
-        && EQUAL(fAnnotation)
         && EQUAL(fTextSize)
         && EQUAL(fTextScaleX)
         && EQUAL(fTextSkewX)
@@ -420,11 +412,6 @@
     return imageFilter;
 }
 
-SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
-    SkRefCnt_SafeAssign(fAnnotation, annotation);
-    return annotation;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static SkScalar mag2(SkScalar x, SkScalar y) {
@@ -1897,7 +1884,6 @@
         asint(this->getColorFilter()) |
         asint(this->getRasterizer()) |
         asint(this->getLooper()) |
-        asint(this->getAnnotation()) |
         asint(this->getImageFilter())) {
         flatFlags |= kHasEffects_FlatFlag;
     }
@@ -1931,13 +1917,6 @@
         buffer.writeFlattenable(this->getRasterizer());
         buffer.writeFlattenable(this->getLooper());
         buffer.writeFlattenable(this->getImageFilter());
-
-        if (fAnnotation) {
-            buffer.writeBool(true);
-            fAnnotation->writeToBuffer(buffer);
-        } else {
-            buffer.writeBool(false);
-        }
     }
 }
 
@@ -1981,8 +1960,14 @@
         SkSafeUnref(this->setLooper(buffer.readDrawLooper()));
         SkSafeUnref(this->setImageFilter(buffer.readImageFilter()));
 
-        if (buffer.readBool()) {
-            this->setAnnotation(SkAnnotation::Create(buffer))->unref();
+        if (buffer.isVersionLT(SkReadBuffer::kAnnotationsMovedToCanvas_Version)) {
+            // We used to store annotations here (string+skdata) if this bool was true
+            if (buffer.readBool()) {
+                // Annotations have moved to drawAnnotation, so we just drop this one on the floor.
+                SkString key;
+                buffer.readString(&key);
+                SkSafeUnref(buffer.readByteArrayAsData());
+            }
         }
     } else {
         this->setPathEffect(nullptr);
@@ -2205,12 +2190,6 @@
         str->append("</dd>");
     }
 
-    SkAnnotation* annotation = this->getAnnotation();
-    if (annotation) {
-        str->append("<dt>Annotation:</dt><dd>");
-        str->append("</dd>");
-    }
-
     str->append("<dt>Color:</dt><dd>0x");
     SkColor color = this->getColor();
     str->appendHex(color);
@@ -2437,7 +2416,7 @@
 uint32_t SkPaint::getHash() const {
     // We're going to hash 10 pointers and 7 32-bit values, finishing up with fBitfields,
     // so fBitfields should be 10 pointers and 6 32-bit values from the start.
-    static_assert(offsetof(SkPaint, fBitfields) == 10 * sizeof(void*) + 6 * sizeof(uint32_t),
+    static_assert(offsetof(SkPaint, fBitfields) == 9 * sizeof(void*) + 6 * sizeof(uint32_t),
                   "SkPaint_notPackedTightly");
     return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(this),
                                offsetof(SkPaint, fBitfields) + sizeof(fBitfields));
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 4eee04f..00b7c2b 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -78,7 +78,9 @@
     SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016,
     SAVE_LAYER_SAVELAYERREC,
 
-    LAST_DRAWTYPE_ENUM = SAVE_LAYER_SAVELAYERREC,
+    DRAW_ANNOTATION,
+
+    LAST_DRAWTYPE_ENUM = DRAW_ANNOTATION,
 };
 
 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index a5dd814..e8497da 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -175,6 +175,12 @@
             canvas->concat(matrix);
             break;
         }
+        case DRAW_ANNOTATION: {
+            const SkRect& rect = reader->skipT<SkRect>();
+            const char* key = reader->readString();
+            SkAutoTUnref<SkData> value(reader->readData());
+            canvas->drawAnnotation(rect, key, value);
+        } break;
         case DRAW_ATLAS: {
             const SkPaint* paint = fPictureData->getPaint(reader);
             const SkImage* atlas = fPictureData->getImage(reader);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 2822a1a..2718ee9 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -777,6 +777,18 @@
     this->validate(initialOffset, size);
 }
 
+void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    size_t keyLen = fWriter.WriteStringSize(key);
+    size_t valueLen = fWriter.WriteDataSize(value);
+    size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
+
+    size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
+    this->addRect(rect);
+    fWriter.writeString(key);
+    fWriter.writeData(value);
+    this->validate(initialOffset, size);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 2e1e62a..607f6f1 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -204,6 +204,7 @@
     void onClipRegion(const SkRegion&, SkRegion::Op) override;
 
     void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
 
     int addPathToHeap(const SkPath& path);  // does not write to ops stream
 
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 3d6dd36..b9b3094 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -60,6 +60,7 @@
         kBitmapSourceFilterQuality_Version = 41,
         kPictureShaderHasPictureBool_Version = 42,
         kHasDrawImageOpCodes_Version       = 43,
+        kAnnotationsMovedToCanvas_Version  = 44,
     };
 
     /**
diff --git a/src/core/SkReader32.h b/src/core/SkReader32.h
index 68dda23..645d64c 100644
--- a/src/core/SkReader32.h
+++ b/src/core/SkReader32.h
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2008 The Android Open Source Project
  *
@@ -10,6 +9,7 @@
 #ifndef SkReader32_DEFINED
 #define SkReader32_DEFINED
 
+#include "SkData.h"
 #include "SkMatrix.h"
 #include "SkPath.h"
 #include "SkRegion.h"
@@ -135,6 +135,14 @@
      */
     size_t readIntoString(SkString* copy);
 
+    SkData* readData() {
+        uint32_t byteLength = this->readU32();
+        if (0 == byteLength) {
+            return SkData::NewEmpty();
+        }
+        return SkData::NewWithCopy(this->skip(byteLength), byteLength);
+    }
+
 private:
     template <typename T> bool readObjectFromMemory(T* obj) {
         size_t size = obj->readFromMemory(this->peek(), this->available());
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 5ca9517..0e4b5af 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -117,6 +117,7 @@
 DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
 DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
                                 r.xmode, r.indices, r.indexCount, r.paint));
+DRAW(DrawAnnotation, drawAnnotation(r.rect, r.key.c_str(), r.value));
 #undef DRAW
 
 template <> void Draw::draw(const DrawDrawable& r) {
@@ -517,6 +518,10 @@
         return this->adjustAndMap(op.worstCaseBounds, nullptr);
     }
 
+    Bounds bounds(const DrawAnnotation& op) const {
+        return this->adjustAndMap(op.rect, nullptr);
+    }
+    
     static void AdjustTextForFontMetrics(SkRect* rect, const SkPaint& paint) {
 #ifdef SK_DEBUG
         SkRect correct = *rect;
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 01c28df..f9fd8bb 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -332,6 +332,10 @@
            this->copy(cull));
 }
 
+void SkRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    APPEND(DrawAnnotation, rect, SkString(key), value);
+}
+
 void SkRecorder::willSave() {
     APPEND(Save);
 }
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index cd5bc8a..7372e54 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -120,6 +120,7 @@
     void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override;
 
     void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+    void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
 
     SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override { return nullptr; }
 
diff --git a/src/core/SkRemote.cpp b/src/core/SkRemote.cpp
index 22185cd..9b0383d 100644
--- a/src/core/SkRemote.cpp
+++ b/src/core/SkRemote.cpp
@@ -5,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-#include "SkAnnotation.h"
 #include "SkCanvas.h"
 #include "SkColorFilter.h"
 #include "SkDrawLooper.h"
@@ -127,7 +126,6 @@
                 fIDs.rasterizer  = fEncoder->define(paint.getRasterizer());
                 fIDs.looper      = fEncoder->define(paint.getLooper());
                 fIDs.imagefilter = fEncoder->define(paint.getImageFilter());
-                fIDs.annotation  = fEncoder->define(paint.getAnnotation());
             }
             ~AutoCommonIDs() {
                 if (fEncoder) {
@@ -140,7 +138,6 @@
                     fEncoder->undefine(fIDs.rasterizer);
                     fEncoder->undefine(fIDs.looper);
                     fEncoder->undefine(fIDs.imagefilter);
-                    fEncoder->undefine(fIDs.annotation);
                 }
             }
 
@@ -461,7 +458,6 @@
         ID define(SkRasterizer*     v)O{return this->define(Type::kRasterizer,  &fRasterizer,  v);}
         ID define(SkDrawLooper*     v)O{return this->define(Type::kDrawLooper,  &fDrawLooper,  v);}
         ID define(SkImageFilter*    v)O{return this->define(Type::kImageFilter, &fImageFilter, v);}
-        ID define(SkAnnotation*     v)O{return this->define(Type::kAnnotation,  &fAnnotation,  v);}
     #undef O
 
 
@@ -480,7 +476,6 @@
                 case Type::kRasterizer:  return fRasterizer .remove(id);
                 case Type::kDrawLooper:  return fDrawLooper .remove(id);
                 case Type::kImageFilter: return fImageFilter.remove(id);
-                case Type::kAnnotation:  return fAnnotation .remove(id);
             };
         }
 
@@ -494,7 +489,6 @@
             paint->setRasterizer (fRasterizer .find(common.rasterizer));
             paint->setLooper     (fDrawLooper .find(common.looper));
             paint->setImageFilter(fImageFilter.find(common.imagefilter));
-            paint->setAnnotation (fAnnotation .find(common.annotation));
         }
 
         void    save() override { fCanvas->save(); }
@@ -617,7 +611,6 @@
         ReffedIDMap<SkRasterizer    , Type::kRasterizer > fRasterizer;
         ReffedIDMap<SkDrawLooper    , Type::kDrawLooper > fDrawLooper;
         ReffedIDMap<SkImageFilter   , Type::kImageFilter> fImageFilter;
-        ReffedIDMap<SkAnnotation    , Type::kAnnotation > fAnnotation;
 
         SkCanvas* fCanvas;
         uint64_t fNextID = 0;
@@ -653,7 +646,6 @@
             fRasterizer .foreach(undef);
             fDrawLooper .foreach(undef);
             fImageFilter.foreach(undef);
-            fAnnotation .foreach(undef);
         }
 
         template <typename Map, typename T>
@@ -679,7 +671,6 @@
         ID define(SkRasterizer*     v) override { return this->define(&fRasterizer , v); }
         ID define(SkDrawLooper*     v) override { return this->define(&fDrawLooper , v); }
         ID define(SkImageFilter*    v) override { return this->define(&fImageFilter, v); }
-        ID define(SkAnnotation*     v) override { return this->define(&fAnnotation , v); }
 
         void undefine(ID) override {}
 
@@ -749,7 +740,6 @@
         RefKeyMap<SkRasterizer    , Type::kRasterizer > fRasterizer;
         RefKeyMap<SkDrawLooper    , Type::kDrawLooper > fDrawLooper;
         RefKeyMap<SkImageFilter   , Type::kImageFilter> fImageFilter;
-        RefKeyMap<SkAnnotation    , Type::kAnnotation > fAnnotation;
 
         Encoder* fWrapped;
     };
diff --git a/src/core/SkRemote.h b/src/core/SkRemote.h
index a1b1405..a8126d6 100644
--- a/src/core/SkRemote.h
+++ b/src/core/SkRemote.h
@@ -79,14 +79,13 @@
         virtual ID define(SkRasterizer*)     = 0;
         virtual ID define(SkDrawLooper*)     = 0;
         virtual ID define(SkImageFilter*)    = 0;
-        virtual ID define(SkAnnotation*)     = 0;
 
         virtual void undefine(ID) = 0;
 
         // TODO: do these all belong here in CommonIDs?
         struct CommonIDs {
             ID misc, patheffect, shader, xfermode, maskfilter,
-               colorfilter, rasterizer, looper, imagefilter, annotation;
+               colorfilter, rasterizer, looper, imagefilter;
         };
 
         virtual void    save() = 0;
diff --git a/src/core/SkRemote_protocol.h b/src/core/SkRemote_protocol.h
index 19bdc33..825a1c2 100644
--- a/src/core/SkRemote_protocol.h
+++ b/src/core/SkRemote_protocol.h
@@ -28,7 +28,6 @@
         kRasterizer,
         kDrawLooper,
         kImageFilter,
-        kAnnotation,
     };
 
 }  // namespace SkRemote
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 04bc14e..a7bf82e 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -68,11 +68,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#define CHECK_FOR_ANNOTATION(paint) \
-    do { if (paint.getAnnotation()) { return; } } while (0)
-
-///////////////////////////////////////////////////////////////////////////////
-
 // Helper for turning a bitmap into a texture. If the bitmap is GrTexture backed this
 // just accesses the backing GrTexture. Otherwise, it creates a cached texture
 // representation and releases it in the destructor.
@@ -401,7 +396,6 @@
                              size_t count, const SkPoint pts[], const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext);
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     SkScalar width = paint.getStrokeWidth();
@@ -453,7 +447,6 @@
 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext);
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
@@ -500,7 +493,6 @@
                             const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext);
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     GrPaint grPaint;
@@ -565,7 +557,6 @@
                              const SkRRect& inner, const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext);
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     if (outer.isEmpty()) {
@@ -606,7 +597,6 @@
 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext);
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     // Presumably the path effect warps this to something other than an oval
@@ -661,7 +651,6 @@
         }
     }
 
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext);
 
@@ -1472,7 +1461,6 @@
                                    const SkIRect& center, const SkRect& dst, const SkPaint& paint) {
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext);
 
-    CHECK_FOR_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index d102f0e..239b738 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -7,7 +7,7 @@
 
 #include "SkPDFDevice.h"
 
-#include "SkAnnotation.h"
+#include "SkAnnotationKeys.h"
 #include "SkColor.h"
 #include "SkColorFilter.h"
 #include "SkClipStack.h"
@@ -753,6 +753,17 @@
     }
 }
 
+void SkPDFDevice::drawAnnotation(const SkDraw& d, const SkRect& rect, const char key[],
+                                 SkData* value) {
+    if (0 == rect.width() && 0 == rect.height()) {
+        handlePointAnnotation({ rect.x(), rect.y() }, *d.fMatrix, key, value);
+    } else {
+        SkPath path;
+        path.addRect(rect);
+        handlePathAnnotation(path, d, key, value);
+    }
+}
+
 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
     SkPaint newPaint = paint;
     replace_srcmode_on_opaque_paint(&newPaint);
@@ -792,12 +803,6 @@
         return;
     }
 
-    if (SkAnnotation* annotation = passedPaint.getAnnotation()) {
-        if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) {
-            return;
-        }
-    }
-
     // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
     // We only use this when there's a path effect because of the overhead
     // of multiple calls to setUpContentEntry it causes.
@@ -935,14 +940,6 @@
         return;
     }
 
-    if (SkAnnotation* annotation = paint.getAnnotation()) {
-        SkPath path;
-        path.addRect(rect);
-        if (handlePathAnnotation(path, d, annotation)) {
-            return;
-        }
-    }
-
     ScopedContentEntry content(this, d, paint);
     if (!content.entry()) {
         return;
@@ -1021,12 +1018,6 @@
         return;
     }
 
-    if (SkAnnotation* annotation = paint.getAnnotation()) {
-        if (handlePathAnnotation(*pathPtr, d, annotation)) {
-            return;
-        }
-    }
-
     ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
     if (!content.entry()) {
         return;
@@ -1664,26 +1655,26 @@
     return true;
 }
 
-bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count,
+void SkPDFDevice::handlePointAnnotation(const SkPoint& point,
                                         const SkMatrix& matrix,
-                                        SkAnnotation* annotationInfo) {
-    SkData* nameData = annotationInfo->find(
-            SkAnnotationKeys::Define_Named_Dest_Key());
-    if (nameData) {
-        for (size_t i = 0; i < count; i++) {
-            SkPoint transformedPoint;
-            matrix.mapXY(points[i].x(), points[i].y(), &transformedPoint);
-            fNamedDestinations.emplace_back(nameData, transformedPoint);
-        }
-        return true;
+                                        const char key[], SkData* value) {
+    if (!value) {
+        return;
     }
-    return false;
+
+    if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) {
+        SkPoint transformedPoint;
+        matrix.mapXY(point.x(), point.y(), &transformedPoint);
+        fNamedDestinations.emplace_back(value, transformedPoint);
+    }
 }
 
-bool SkPDFDevice::handlePathAnnotation(const SkPath& path,
+void SkPDFDevice::handlePathAnnotation(const SkPath& path,
                                        const SkDraw& d,
-                                       SkAnnotation* annotation) {
-    SkASSERT(annotation);
+                                       const char key[], SkData* value) {
+    if (!value) {
+        return;
+    }
 
     SkPath transformedPath = path;
     transformedPath.transform(*d.fMatrix);
@@ -1692,24 +1683,15 @@
             false);
     SkRect transformedRect = SkRect::Make(clip.getBounds());
 
-    SkData* urlData = annotation->find(SkAnnotationKeys::URL_Key());
-    if (urlData) {
+    if (!strcmp(SkAnnotationKeys::URL_Key(), key)) {
         if (!transformedRect.isEmpty()) {
-            fLinkToURLs.emplace_back(transformedRect, urlData);
+            fLinkToURLs.emplace_back(transformedRect, value);
         }
-        return true;
-    }
-
-    SkData* linkToDestination =
-            annotation->find(SkAnnotationKeys::Link_Named_Dest_Key());
-    if (linkToDestination) {
+    } else if (!strcmp(SkAnnotationKeys::Link_Named_Dest_Key(), key)) {
         if (!transformedRect.isEmpty()) {
-            fLinkToDestinations.emplace_back(transformedRect, linkToDestination);
+            fLinkToDestinations.emplace_back(transformedRect, value);
         }
-        return true;
     }
-
-    return false;
 }
 
 void SkPDFDevice::appendAnnotations(SkPDFArray* array) const {
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index cceb123..d38f282 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -197,6 +197,8 @@
 
     SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
 
+    void drawAnnotation(const SkDraw&, const SkRect&, const char key[], SkData* value) override;
+
 private:
     struct RectWithData {
         SkRect rect;
@@ -318,10 +320,8 @@
     bool handleInversePath(const SkDraw& d, const SkPath& origPath,
                            const SkPaint& paint, bool pathIsMutable,
                            const SkMatrix* prePathMatrix = nullptr);
-    bool handlePointAnnotation(const SkPoint* points, size_t count,
-                               const SkMatrix& matrix, SkAnnotation* annot);
-    bool handlePathAnnotation(const SkPath& path, const SkDraw& d,
-                              SkAnnotation* annot);
+    void handlePointAnnotation(const SkPoint&, const SkMatrix&, const char key[], SkData* value);
+    void handlePathAnnotation(const SkPath&, const SkDraw& d, const char key[], SkData* value);
 
     typedef SkBaseDevice INHERITED;
 
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 916c32a..75fa836 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -9,6 +9,7 @@
 #include "SkDumpCanvas.h"
 
 #ifdef SK_DEVELOPER
+#include "SkData.h"
 #include "SkPatchUtils.h"
 #include "SkPicture.h"
 #include "SkPixelRef.h"
@@ -482,6 +483,13 @@
               texCoords[2].x(), texCoords[2].y(), texCoords[3].x(), texCoords[3].y());
 }
 
+void SkDumpCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    SkString str;
+    toString(rect, &str);
+    this->dump(kDrawAnnotation_Verb, nullptr, "drawAnnotation(%s \"%s\" (%zu))",
+               str.c_str(), key, value ? value->size() : 0);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index e3b1e01..fd5fa82 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -292,6 +292,13 @@
     }
 }
 
+void SkNWayCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* data) {
+    Iter iter(fList);
+    while (iter.next()) {
+        iter->drawAnnotation(rect, key, data);
+    }
+}
+
 #ifdef SK_SUPPORT_LEGACY_DRAWFILTER
 SkDrawFilter* SkNWayCanvas::setDrawFilter(SkDrawFilter* filter) {
     Iter iter(fList);
diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp
index a4e40c5..eb84b3c 100644
--- a/tests/SerializationTest.cpp
+++ b/tests/SerializationTest.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkAnnotationKeys.h"
 #include "Resources.h"
 #include "SkCanvas.h"
 #include "SkFixed.h"
@@ -546,3 +547,85 @@
 
     TestPictureTypefaceSerialization(reporter);
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkAnnotation.h"
+
+static SkPicture* copy_picture_via_serialization(SkPicture* src) {
+    SkDynamicMemoryWStream wstream;
+    src->serialize(&wstream);
+    SkAutoTDelete<SkStreamAsset> rstream(wstream.detachAsStream());
+    return SkPicture::CreateFromStream(rstream);
+}
+
+struct AnnotationRec {
+    const SkRect    fRect;
+    const char*     fKey;
+    SkData*         fValue;
+};
+
+class TestAnnotationCanvas : public SkCanvas {
+    skiatest::Reporter*     fReporter;
+    const AnnotationRec*    fRec;
+    int                     fCount;
+    int                     fCurrIndex;
+
+public:
+    TestAnnotationCanvas(skiatest::Reporter* reporter, const AnnotationRec rec[], int count)
+        : SkCanvas(100, 100)
+        , fReporter(reporter)
+        , fRec(rec)
+        , fCount(count)
+        , fCurrIndex(0)
+    {}
+
+    ~TestAnnotationCanvas() {
+        REPORTER_ASSERT(fReporter, fCount == fCurrIndex);
+    }
+
+protected:
+    void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+        REPORTER_ASSERT(fReporter, fCurrIndex < fCount);
+        REPORTER_ASSERT(fReporter, rect == fRec[fCurrIndex].fRect);
+        REPORTER_ASSERT(fReporter, !strcmp(key, fRec[fCurrIndex].fKey));
+        REPORTER_ASSERT(fReporter, value->equals(fRec[fCurrIndex].fValue));
+        fCurrIndex += 1;
+    }
+};
+
+/*
+ *  Test the 3 annotation types by recording them into a picture, serializing, and then playing
+ *  them back into another canvas.
+ */
+DEF_TEST(Annotations, reporter) {
+    SkPictureRecorder recorder;
+    SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(100, 100));
+    
+    const char* str0 = "rect-with-url";
+    const SkRect r0 = SkRect::MakeWH(10, 10);
+    SkAutoTUnref<SkData> d0(SkData::NewWithCString(str0));
+    SkAnnotateRectWithURL(recordingCanvas, r0, d0);
+    
+    const char* str1 = "named-destination";
+    const SkRect r1 = SkRect::MakeXYWH(5, 5, 0, 0); // collapsed to a point
+    SkAutoTUnref<SkData> d1(SkData::NewWithCString(str1));
+    SkAnnotateNamedDestination(recordingCanvas, {r1.x(), r1.y()}, d1);
+    
+    const char* str2 = "link-to-destination";
+    const SkRect r2 = SkRect::MakeXYWH(20, 20, 5, 6);
+    SkAutoTUnref<SkData> d2(SkData::NewWithCString(str2));
+    SkAnnotateLinkToDestination(recordingCanvas, r2, d2);
+
+    const AnnotationRec recs[] = {
+        { r0, SkAnnotationKeys::URL_Key(),                  d0 },
+        { r1, SkAnnotationKeys::Define_Named_Dest_Key(),    d1 },
+        { r2, SkAnnotationKeys::Link_Named_Dest_Key(),      d2 },
+    };
+
+    SkAutoTUnref<SkPicture> pict0(recorder.endRecording());
+    SkAutoTUnref<SkPicture> pict1(copy_picture_via_serialization(pict0));
+
+    TestAnnotationCanvas canvas(reporter, recs, SK_ARRAY_COUNT(recs));
+    canvas.drawPicture(pict1);
+}
+
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
index 39ae79c..e03a916 100644
--- a/tests/Writer32Test.cpp
+++ b/tests/Writer32Test.cpp
@@ -278,3 +278,44 @@
     test_rewind(reporter);
 }
 
+DEF_TEST(Writer32_data, reporter) {
+    const char* str = "0123456789";
+    SkAutoTUnref<SkData> data0(SkData::NewWithCString(str));
+    SkAutoTUnref<SkData> data1(SkData::NewEmpty());
+
+    const size_t sizes[] = {
+        SkWriter32::WriteDataSize(nullptr),
+        SkWriter32::WriteDataSize(data0),
+        SkWriter32::WriteDataSize(data1),
+    };
+    
+    SkSWriter32<1000> writer;
+    size_t sizeWritten = 0;
+
+    writer.writeData(nullptr);
+    sizeWritten += sizes[0];
+    REPORTER_ASSERT(reporter, sizeWritten == writer.bytesWritten());
+    
+    writer.writeData(data0);
+    sizeWritten += sizes[1];
+    REPORTER_ASSERT(reporter, sizeWritten == writer.bytesWritten());
+
+    writer.writeData(data1);
+    sizeWritten += sizes[2];
+    REPORTER_ASSERT(reporter, sizeWritten == writer.bytesWritten());
+
+    SkAutoTUnref<SkData> result(writer.snapshotAsData());
+
+    SkReader32 reader(result->data(), result->size());
+    SkAutoTUnref<SkData> d0(reader.readData()),
+                         d1(reader.readData()),
+                         d2(reader.readData());
+
+    REPORTER_ASSERT(reporter, 0 == d0->size());
+    REPORTER_ASSERT(reporter, strlen(str)+1 == d1->size());
+    REPORTER_ASSERT(reporter, !memcmp(str, d1->data(), strlen(str)+1));
+    REPORTER_ASSERT(reporter, 0 == d2->size());
+    
+    REPORTER_ASSERT(reporter, reader.offset() == sizeWritten);
+    REPORTER_ASSERT(reporter, reader.eof());
+}