idea: add annotation to SkPaint
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 11 Jul 2012 19:57:55 +0000 (19:57 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 11 Jul 2012 19:57:55 +0000 (19:57 +0000)
Review URL: https://codereview.appspot.com/6355050

git-svn-id: http://skia.googlecode.com/svn/trunk@4555 2bbb7eff-a529-9590-31e7-b0007b416f81

gyp/core.gyp
gyp/tests.gyp
include/core/SkAnnotation.h [new file with mode: 0644]
include/core/SkPaint.h
src/core/SkAnnotation.cpp [new file with mode: 0644]
src/core/SkDevice.cpp
src/core/SkPaint.cpp
src/gpu/SkGpuDevice.cpp
tests/AnnotationTest.cpp [new file with mode: 0644]

index a109d7b..7b54024 100644 (file)
@@ -9,6 +9,7 @@
         '../src/core/ARGB32_Clamp_Bilinear_BitmapShader.h',
         '../src/core/Sk64.cpp',
         '../src/core/SkAAClip.cpp',
+        '../src/core/SkAnnotation.cpp',
         '../src/core/SkAdvancedTypefaceMetrics.cpp',
         '../src/core/SkAlphaRuns.cpp',
         '../src/core/SkAntiRun.h',
index cdf755b..c6e2786 100644 (file)
@@ -17,6 +17,7 @@
       ],
       'sources': [
         '../tests/AAClipTest.cpp',
+        '../tests/AnnotationTest.cpp',
         '../tests/BitmapCopyTest.cpp',
         '../tests/BitmapGetColorTest.cpp',
         '../tests/BitSetTest.cpp',
diff --git a/include/core/SkAnnotation.h b/include/core/SkAnnotation.h
new file mode 100644 (file)
index 0000000..d401588
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAnnotation_DEFINED
+#define SkAnnotation_DEFINED
+
+#include "SkFlattenable.h"
+
+class SkData;
+class SkDataSet;
+
+/**
+ *  Experimental class for annotating draws. Do not use directly yet.
+ *  Use helper functions at the bottom of this file for now.
+ */
+class SkAnnotation : public SkFlattenable {
+public:
+    enum Flags {
+        // If set, the associated drawing primitive should not be drawn
+        kNoDraw_Flag  = 1 << 0,
+    };
+
+    SkAnnotation(SkDataSet*, uint32_t flags);
+    virtual ~SkAnnotation();
+
+    uint32_t getFlags() const { return fFlags; }
+    SkDataSet* getDataSet() const { return fDataSet; }
+
+    bool isNoDraw() const { return SkToBool(fFlags & kNoDraw_Flag); }
+
+    /**
+     *  Helper for search the annotation's dataset.
+     */
+    SkData* find(const char name[]) const;
+
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAnnotation)
+
+protected:
+    SkAnnotation(SkFlattenableReadBuffer&);
+    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+
+private:
+    SkDataSet*  fDataSet;
+    uint32_t    fFlags;
+    
+    void writeToStream(SkWStream*) const;
+    void readFromStream(SkStream*);
+
+    typedef SkFlattenable 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();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// 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
+ *  safely ignored.
+ *
+ *  The caller is responsible for managing its ownership of the SkData.
+ */
+SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*);
+
+#endif
index 3d58527..684bc45 100644 (file)
@@ -15,6 +15,7 @@
 #include "SkDrawLooper.h"
 #include "SkXfermode.h"
 
+class SkAnnotation;
 class SkAutoGlyphCache;
 class SkColorFilter;
 class SkDescriptor;
@@ -581,6 +582,17 @@ public:
 
     SkImageFilter* getImageFilter() const { return fImageFilter; }
     SkImageFilter* setImageFilter(SkImageFilter*);
+    
+    SkAnnotation* getAnnotation() const { return fAnnotation; }
+    SkAnnotation* setAnnotation(SkAnnotation*);
+
+    /**
+     *  Returns true if there is an annotation installed on this paint, and
+     *  the annotation specifics no-drawing.
+     */
+    bool isNoDrawAnnotation() const {
+        return SkToBool(fPrivFlags & kNoDrawAnnotation_PrivFlag);
+    }
 
     /**
      *  Return the paint's SkDrawLooper (if any). Does not affect the looper's
@@ -903,17 +915,24 @@ private:
     SkRasterizer*   fRasterizer;
     SkDrawLooper*   fLooper;
     SkImageFilter*  fImageFilter;
+    SkAnnotation*   fAnnotation;
 
     SkColor         fColor;
     SkScalar        fWidth;
     SkScalar        fMiterLimit;
-    unsigned        fFlags : 15;
+    // all of these bitfields should add up to 32
+    unsigned        fFlags : 16;
     unsigned        fTextAlign : 2;
     unsigned        fCapType : 2;
     unsigned        fJoinType : 2;
     unsigned        fStyle : 2;
     unsigned        fTextEncoding : 2;  // 3 values
     unsigned        fHinting : 2;
+    unsigned        fPrivFlags : 4; // these are not flattened/unflattened
+
+    enum PrivFlags {
+        kNoDrawAnnotation_PrivFlag  = 1 << 0,
+    };
 
     SkDrawCacheProc    getDrawCacheProc() const;
     SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir,
diff --git a/src/core/SkAnnotation.cpp b/src/core/SkAnnotation.cpp
new file mode 100644 (file)
index 0000000..94ce6a0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAnnotation.h"
+#include "SkDataSet.h"
+#include "SkStream.h"
+
+SkAnnotation::SkAnnotation(SkDataSet* data, uint32_t flags) {
+    if (NULL == data) {
+        data = SkDataSet::NewEmpty();
+    } else {
+        data->ref();
+    }
+    fDataSet = data;
+    fFlags = flags;
+}
+
+SkAnnotation::~SkAnnotation() {
+    fDataSet->unref();
+}
+
+SkAnnotation::SkAnnotation(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+    fFlags = buffer.readU32();
+    fDataSet = SkNEW_ARGS(SkDataSet, (buffer));
+}
+
+void SkAnnotation::flatten(SkFlattenableWriteBuffer& buffer) const {
+    buffer.write32(fFlags);
+    fDataSet->flatten(buffer);
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkAnnotation)
+
+const char* SkAnnotationKeys::URL_Key() {
+    return "SkAnnotationKey_URL";
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkCanvas.h"
+
+void SkAnnotateRectWithURL(SkCanvas* canvas, const SkRect& rect, SkData* value) {
+    if (NULL == value) {
+        return;
+    }
+
+    const char* key = SkAnnotationKeys::URL_Key();
+    SkAutoTUnref<SkDataSet> dataset(SkNEW_ARGS(SkDataSet, (key, value)));
+    SkAnnotation* ann = SkNEW_ARGS(SkAnnotation, (dataset,
+                                                  SkAnnotation::kNoDraw_Flag));
+
+    SkPaint paint;
+    paint.setAnnotation(ann)->unref();
+    SkASSERT(paint.isNoDrawAnnotation());
+
+    canvas->drawRect(rect, paint);
+}
+
index c5dfc66..95664c8 100644 (file)
@@ -15,6 +15,11 @@ SK_DEFINE_INST_COUNT(SkDevice)
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#define CHECK_FOR_NODRAW_ANNOTATION(paint) \
+    do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
+
+///////////////////////////////////////////////////////////////////////////////
+
 SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
     fOrigin.setZero();
     fMetaData = NULL;
@@ -295,12 +300,14 @@ void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t c
 
 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r,
                             const SkPaint& paint) {
+    CHECK_FOR_NODRAW_ANNOTATION(paint);
     draw.drawRect(r, paint);
 }
 
 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
                         const SkPaint& paint, const SkMatrix* prePathMatrix,
                         bool pathIsMutable) {
+    CHECK_FOR_NODRAW_ANNOTATION(paint);
     draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
 }
 
index 08e642c..ea2d1f6 100644 (file)
@@ -6,8 +6,8 @@
  * found in the LICENSE file.
  */
 
-
 #include "SkPaint.h"
+#include "SkAnnotation.h"
 #include "SkColorFilter.h"
 #include "SkFontHost.h"
 #include "SkImageFilter.h"
@@ -55,6 +55,7 @@ SkPaint::SkPaint() {
     fRasterizer  = NULL;
     fLooper      = NULL;
     fImageFilter = NULL;
+    fAnnotation  = NULL;
     fWidth      = 0;
 #endif
 
@@ -69,6 +70,7 @@ SkPaint::SkPaint() {
     fStyle      = kFill_Style;
     fTextEncoding = kUTF8_TextEncoding;
     fHinting    = SkPaintDefaults_Hinting;
+    fPrivFlags  = 0;
 #ifdef SK_BUILD_FOR_ANDROID
     fGenerationID = 0;
 #endif
@@ -86,6 +88,7 @@ SkPaint::SkPaint(const SkPaint& src) {
     SkSafeRef(fRasterizer);
     SkSafeRef(fLooper);
     SkSafeRef(fImageFilter);
+    SkSafeRef(fAnnotation);
 }
 
 SkPaint::~SkPaint() {
@@ -98,6 +101,7 @@ SkPaint::~SkPaint() {
     SkSafeUnref(fRasterizer);
     SkSafeUnref(fLooper);
     SkSafeUnref(fImageFilter);
+    SkSafeUnref(fAnnotation);
 }
 
 SkPaint& SkPaint::operator=(const SkPaint& src) {
@@ -112,6 +116,7 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
     SkSafeRef(src.fRasterizer);
     SkSafeRef(src.fLooper);
     SkSafeRef(src.fImageFilter);
+    SkSafeRef(src.fAnnotation);
 
     SkSafeUnref(fTypeface);
     SkSafeUnref(fPathEffect);
@@ -122,6 +127,7 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
     SkSafeUnref(fRasterizer);
     SkSafeUnref(fLooper);
     SkSafeUnref(fImageFilter);
+    SkSafeUnref(fAnnotation);
 
 #ifdef SK_BUILD_FOR_ANDROID
     uint32_t oldGenerationID = fGenerationID;
@@ -371,6 +377,16 @@ SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
     return imageFilter;
 }
 
+SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
+    SkRefCnt_SafeAssign(fAnnotation, annotation);
+    GEN_ID_INC;
+
+    bool isNoDraw = annotation && annotation->isNoDraw();
+    fPrivFlags = SkSetClearMask(fPrivFlags, isNoDraw, kNoDrawAnnotation_PrivFlag);
+
+    return annotation;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "SkGlyphCache.h"
@@ -1809,7 +1825,7 @@ static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
 
 enum FlatFlags {
     kHasTypeface_FlatFlag   = 0x01,
-    kHasEffects_FlatFlag    = 0x02
+    kHasEffects_FlatFlag    = 0x02,
 };
 
 // The size of a flat paint's POD fields
@@ -1833,6 +1849,7 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
         asint(this->getColorFilter()) |
         asint(this->getRasterizer()) |
         asint(this->getLooper()) |
+        asint(this->getAnnotation()) |
         asint(this->getImageFilter())) {
         flatFlags |= kHasEffects_FlatFlag;
     }
@@ -1870,6 +1887,7 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
         buffer.writeFlattenable(this->getRasterizer());
         buffer.writeFlattenable(this->getLooper());
         buffer.writeFlattenable(this->getImageFilter());
+        buffer.writeFlattenable(this->getAnnotation());
     }
 }
 
@@ -1878,6 +1896,8 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
     const void* podData = buffer.skip(kPODPaintSize);
     const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
 
+    fPrivFlags = 0;
+
     // the order we read must match the order we wrote in flatten()
     this->setTextSize(read_scalar(pod));
     this->setTextScaleX(read_scalar(pod));
@@ -1920,6 +1940,7 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
         SkSafeUnref(this->setRasterizer((SkRasterizer*) buffer.readFlattenable()));
         SkSafeUnref(this->setLooper((SkDrawLooper*) buffer.readFlattenable()));
         SkSafeUnref(this->setImageFilter((SkImageFilter*) buffer.readFlattenable()));
+        SkSafeUnref(this->setAnnotation((SkAnnotation*) buffer.readFlattenable()));
     } else {
         this->setPathEffect(NULL);
         this->setShader(NULL);
@@ -2209,7 +2230,7 @@ bool SkImageFilter::asADilate(SkISize* radius) const {
     return false;
 }
 
-//////
+////////////////////
 
 SK_DEFINE_INST_COUNT(SkDrawLooper)
 
index c731999..fc77c47 100644 (file)
@@ -71,6 +71,12 @@ enum {
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#define CHECK_FOR_NODRAW_ANNOTATION(paint) \
+    do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
+
+///////////////////////////////////////////////////////////////////////////////
+
+
 class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable {
 public:
     SkAutoCachedTexture() { }    
@@ -662,6 +668,7 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
 
 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
                           const SkPaint& paint) {
+    CHECK_FOR_NODRAW_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
@@ -976,6 +983,7 @@ bool drawWithMaskFilter(GrContext* context, const SkPath& path,
 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
                            const SkPaint& paint, const SkMatrix* prePathMatrix,
                            bool pathIsMutable) {
+    CHECK_FOR_NODRAW_ANNOTATION(paint);
     CHECK_SHOULD_DRAW(draw);
 
     bool             doFill = true;
diff --git a/tests/AnnotationTest.cpp b/tests/AnnotationTest.cpp
new file mode 100644 (file)
index 0000000..fe2cd01
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkAnnotation.h"
+#include "SkData.h"
+#include "SkCanvas.h"
+
+static void test_nodraw(skiatest::Reporter* reporter) {
+    SkBitmap bm;
+    bm.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+    bm.allocPixels();
+    bm.eraseColor(0);
+
+    SkCanvas canvas(bm);
+    SkRect r = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
+
+    SkAutoDataUnref data(SkData::NewWithCString("http://www.gooogle.com"));
+
+    REPORTER_ASSERT(reporter, 0 == *bm.getAddr32(0, 0));
+    SkAnnotateRectWithURL(&canvas, r, data.get());
+    REPORTER_ASSERT(reporter, 0 == *bm.getAddr32(0, 0));
+}
+
+static void TestAnnotation(skiatest::Reporter* reporter) {
+    test_nodraw(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Annotation", AnnotationClass, TestAnnotation)