Add link annotation support to SkSVGDevice.

This CL implements |SkSVGDevice::drawAnnotation|, overridden from
|SKBaseDevice|.  |drawAnnotation| supports annotating rectangular areas
of a Skia device.  Previous to this change, annotations are being used
in |SkPDFDevice| to include hyperlinked rectangular areas in .pdf
documents.  This CL implements the SVG equivalent of this PDF feature.

BUG=skia:7581

Docs-Preview: https://skia.org/?cl=104680
Change-Id: I92ae01ceb7ae10cd2010bebab2a58dcfe48ef253
Reviewed-on: https://skia-review.googlesource.com/104680
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/AUTHORS b/AUTHORS
index 6ebbda8..ab93081 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@
 # Please keep the list sorted alphabetically.
 
 ACCESS CO., LTD. <*@access-company.com>
+Amazon, Inc <*@amazon.com>
 Anthony Catel <paraboul@gmail.com>
 ARM <*@arm.com>
 Ehsan Akhgari <ehsan.akhgari@gmail.com>
diff --git a/site/user/index.md b/site/user/index.md
index 5fb51e8..c27bd61 100644
--- a/site/user/index.md
+++ b/site/user/index.md
@@ -16,5 +16,6 @@
   * OpenGL
   * PDF
   * XPS
+  * SVG
   * Picture (for recording and then playing back into another Canvas)
 
diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp
index 4a1f2b7..6bb971d 100644
--- a/src/svg/SkSVGDevice.cpp
+++ b/src/svg/SkSVGDevice.cpp
@@ -7,9 +7,11 @@
 
 #include "SkSVGDevice.h"
 
+#include "SkAnnotationKeys.h"
 #include "SkBase64.h"
 #include "SkBitmap.h"
 #include "SkChecksum.h"
+#include "SkClipOpPriv.h"
 #include "SkClipStack.h"
 #include "SkData.h"
 #include "SkDraw.h"
@@ -22,7 +24,6 @@
 #include "SkTypeface.h"
 #include "SkUtils.h"
 #include "SkXMLWriter.h"
-#include "SkClipOpPriv.h"
 
 namespace {
 
@@ -621,6 +622,32 @@
                                           SkIntToScalar(this->height())));
 }
 
+void SkSVGDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
+    if (!value) {
+        return;
+    }
+
+    if (!strcmp(SkAnnotationKeys::URL_Key(), key) ||
+        !strcmp(SkAnnotationKeys::Link_Named_Dest_Key(), key)) {
+        this->cs().save();
+        this->cs().clipRect(rect, this->ctm(), kIntersect_SkClipOp, true);
+        SkRect transformedRect = this->cs().bounds(this->getGlobalBounds());
+        this->cs().restore();
+        if (transformedRect.isEmpty()) {
+            return;
+        }
+
+        SkString url(static_cast<const char*>(value->data()), value->size() - 1);
+        AutoElement a("a", fWriter);
+        a.addAttribute("xlink:href", url.c_str());
+        {
+            AutoElement r("rect", fWriter);
+            r.addAttribute("fill-opacity", "0.0");
+            r.addRectAttributes(transformedRect);
+        }
+    }
+}
+
 void SkSVGDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
                              const SkPoint pts[], const SkPaint& paint) {
     SkPath path;
diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h
index 0e22910..222e55d 100644
--- a/src/svg/SkSVGDevice.h
+++ b/src/svg/SkSVGDevice.h
@@ -19,6 +19,7 @@
 
 protected:
     void drawPaint(const SkPaint& paint) override;
+    void drawAnnotation(const SkRect& rect, const char key[], SkData* value) override;
     void drawPoints(SkCanvas::PointMode mode, size_t count,
                     const SkPoint[], const SkPaint& paint) override;
     void drawRect(const SkRect& r, const SkPaint& paint) override;
diff --git a/tests/AnnotationTest.cpp b/tests/AnnotationTest.cpp
index cc2fd1f..b49b80d 100644
--- a/tests/AnnotationTest.cpp
+++ b/tests/AnnotationTest.cpp
@@ -8,7 +8,9 @@
 #include "SkCanvas.h"
 #include "SkData.h"
 #include "SkDocument.h"
+#include "SkSVGCanvas.h"
 #include "SkStream.h"
+#include "SkXMLWriter.h"
 #include "Test.h"
 
 /** Returns true if data (may contain null characters) contains needle (null
@@ -57,8 +59,8 @@
     REPORTER_ASSERT(reporter, ContainsString(rawOutput, out->size(), "/Annots "));
 }
 
-DEF_TEST(Annotation_NamedDestination, reporter) {
-    REQUIRE_PDF_DOCUMENT(Annotation_NamedDestination, reporter);
+DEF_TEST(Annotation_PdfDefineNamedDestination, reporter) {
+    REQUIRE_PDF_DOCUMENT(Annotation_PdfNamedDestination, reporter);
     SkDynamicMemoryWStream outStream;
     sk_sp<SkDocument> doc(SkDocument::MakePDF(&outStream));
     SkCanvas* canvas = doc->beginPage(612.0f, 792.0f);
@@ -75,3 +77,42 @@
     REPORTER_ASSERT(reporter,
         ContainsString(rawOutput, out->size(), "/example "));
 }
+
+DEF_TEST(Annotation_SvgLink, reporter) {
+    SkDynamicMemoryWStream outStream;
+    std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(&outStream));
+    SkRect bounds = SkRect::MakeIWH(400, 400);
+    std::unique_ptr<SkCanvas> canvas = SkSVGCanvas::Make(bounds, xmlWriter.get());
+
+    SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72), SkIntToScalar(288),
+                                SkIntToScalar(72));
+    sk_sp<SkData> data(SkData::MakeWithCString("http://www.gooogle.com"));
+    SkAnnotateRectWithURL(canvas.get(), r, data.get());
+
+    canvas->flush();
+    sk_sp<SkData> out = outStream.detachAsData();
+    const char* rawOutput = (const char*)out->data();
+
+    REPORTER_ASSERT(reporter,
+        ContainsString(rawOutput, out->size(), "a xlink:href=\"http://www.gooogle.com\""));
+}
+
+DEF_TEST(Annotation_SvgLinkNamedDestination, reporter) {
+    SkDynamicMemoryWStream outStream;
+    std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(&outStream));
+    SkRect bounds = SkRect::MakeIWH(400, 400);
+    std::unique_ptr<SkCanvas> canvas = SkSVGCanvas::Make(bounds, xmlWriter.get());
+
+    SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72), SkIntToScalar(288),
+                                SkIntToScalar(72));
+    sk_sp<SkData> data(SkData::MakeWithCString("http://www.gooogle.com/#NamedDestination"));
+    SkAnnotateLinkToDestination(canvas.get(), r, data.get());
+
+    canvas->flush();
+    sk_sp<SkData> out = outStream.detachAsData();
+    const char* rawOutput = (const char*)out->data();
+
+    REPORTER_ASSERT(reporter,
+                    ContainsString(rawOutput, out->size(),
+                                   "a xlink:href=\"http://www.gooogle.com/#NamedDestination\""));
+}