From fd5a5081d53d16facd315cb0b5d4b9622ba22d9d Mon Sep 17 00:00:00 2001 From: Bryce Thomas Date: Tue, 6 Feb 2018 14:53:05 -0800 Subject: 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 Reviewed-by: Florin Malita --- AUTHORS | 1 + site/user/index.md | 1 + src/svg/SkSVGDevice.cpp | 29 ++++++++++++++++++++++++++++- src/svg/SkSVGDevice.h | 1 + tests/AnnotationTest.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6ebbda8e1a..ab930810d8 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 ARM <*@arm.com> Ehsan Akhgari diff --git a/site/user/index.md b/site/user/index.md index 5fb51e8898..c27bd61102 100644 --- a/site/user/index.md +++ b/site/user/index.md @@ -16,5 +16,6 @@ Device backends for Skia currently include: * 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 4a1f2b750a..6bb971d764 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 @@ void SkSVGDevice::drawPaint(const SkPaint& paint) { 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(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 0e22910412..222e55d83c 100644 --- a/src/svg/SkSVGDevice.h +++ b/src/svg/SkSVGDevice.h @@ -19,6 +19,7 @@ public: 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 cc2fd1f912..b49b80d545 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 @@ DEF_TEST(Annotation_PdfLink, reporter) { 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 doc(SkDocument::MakePDF(&outStream)); SkCanvas* canvas = doc->beginPage(612.0f, 792.0f); @@ -75,3 +77,42 @@ DEF_TEST(Annotation_NamedDestination, reporter) { REPORTER_ASSERT(reporter, ContainsString(rawOutput, out->size(), "/example ")); } + +DEF_TEST(Annotation_SvgLink, reporter) { + SkDynamicMemoryWStream outStream; + std::unique_ptr xmlWriter(new SkXMLStreamWriter(&outStream)); + SkRect bounds = SkRect::MakeIWH(400, 400); + std::unique_ptr canvas = SkSVGCanvas::Make(bounds, xmlWriter.get()); + + SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72), SkIntToScalar(288), + SkIntToScalar(72)); + sk_sp data(SkData::MakeWithCString("http://www.gooogle.com")); + SkAnnotateRectWithURL(canvas.get(), r, data.get()); + + canvas->flush(); + sk_sp 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 xmlWriter(new SkXMLStreamWriter(&outStream)); + SkRect bounds = SkRect::MakeIWH(400, 400); + std::unique_ptr canvas = SkSVGCanvas::Make(bounds, xmlWriter.get()); + + SkRect r = SkRect::MakeXYWH(SkIntToScalar(72), SkIntToScalar(72), SkIntToScalar(288), + SkIntToScalar(72)); + sk_sp data(SkData::MakeWithCString("http://www.gooogle.com/#NamedDestination")); + SkAnnotateLinkToDestination(canvas.get(), r, data.get()); + + canvas->flush(); + sk_sp 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\"")); +} -- cgit v1.2.3