move annotations to canvas virtual

In an effort to do it all at once, this change assumes that its ok to ignore annotations that were previously stored on paints in old SKP files (since this feature is only interesting to PDF printing).

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

Review URL: https://codereview.chromium.org/1744103002
This commit is contained in:
reed 2016-03-03 08:13:54 -08:00 committed by Commit bot
parent c6663dc36b
commit 0eda2587cc
34 changed files with 329 additions and 253 deletions

View File

@ -8,83 +8,18 @@
#ifndef SkAnnotation_DEFINED
#define SkAnnotation_DEFINED
#include "SkRefCnt.h"
#include "SkString.h"
#include "SkTypes.h"
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 +27,6 @@ class SkCanvas;
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 +37,6 @@ SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*);
SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*);
/**
* Experimental!
*
* Annotate the canvas by making the specified rectangle link to a named
* destination.
*
@ -116,5 +47,4 @@ SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*);
*/
SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*);
#endif

View File

@ -22,6 +22,7 @@ class GrRenderTarget;
class SkBaseDevice;
class SkCanvasClipVisitor;
class SkClipStack;
class SkData;
class SkDraw;
class SkDrawable;
class SkDrawFilter;
@ -1072,6 +1073,18 @@ public:
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 @@ protected:
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,

View File

@ -252,6 +252,8 @@ protected:
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.
*/

View File

@ -13,7 +13,6 @@
#include "SkMatrix.h"
#include "SkXfermode.h"
class SkAnnotation;
class SkAutoDescriptor;
class SkAutoGlyphCache;
class SkColorFilter;
@ -625,9 +624,6 @@ public:
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 @@ private:
SkRasterizer* fRasterizer;
SkDrawLooper* fLooper;
SkImageFilter* fImageFilter;
SkAnnotation* fAnnotation;
SkScalar fTextSize;
SkScalar fTextScaleX;

View File

@ -192,10 +192,11 @@ private:
// 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 @@ private:
static_assert(MIN_PICTURE_VERSION <= 43,
"Remove SkBitmapSourceDeserializer.");
static bool IsValidPictInfo(const SkPictInfo& info);
static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);

View File

@ -206,6 +206,18 @@ public:
*/
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().

View File

@ -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 @@ namespace SkRecords {
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 @@ RECORD(DrawVertices, kDraw_Tag,
RefBox<SkXfermode> xmode;
PODArray<uint16_t> indices;
int indexCount);
RECORD(DrawAnnotation, 0,
SkRect rect;
SkString key;
RefBox<SkData> value);
#undef RECORD
} // namespace SkRecords

View File

@ -48,6 +48,7 @@ public:
kDrawVertices_Verb,
kDrawPatch_Verb,
kDrawData_Verb, // obsolete
kDrawAnnotation_Verb,
kCull_Verb
};
@ -120,6 +121,7 @@ protected:
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);

View File

@ -79,6 +79,7 @@ protected:
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;

View File

@ -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 @@ static SkPaint make_paint() {
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());

View File

@ -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 @@ const char* SkAnnotationKeys::Link_Named_Dest_Key() {
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);
}

View File

@ -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

View File

@ -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::drawPaint(const SkDraw& draw, const SkPaint& paint) {
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::drawOval(const SkDraw& draw, const SkRect& oval, const SkPa
}
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::drawRRect(const SkDraw& draw, const SkRRect& rrect, const S
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);
}

View File

@ -1973,6 +1973,12 @@ void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const Sk
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 @@ void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const
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.

View File

@ -6,7 +6,6 @@
*/
#include "SkPaint.h"
#include "SkAnnotation.h"
#include "SkAutoKern.h"
#include "SkChecksum.h"
#include "SkColorFilter.h"
@ -54,7 +53,6 @@ SkPaint::SkPaint() {
fRasterizer = nullptr;
fLooper = nullptr;
fImageFilter = nullptr;
fAnnotation = nullptr;
fTextSize = SkPaintDefaults_TextSize;
fTextScaleX = SK_Scalar1;
@ -87,7 +85,6 @@ SkPaint::SkPaint(const SkPaint& src) {
REF_COPY(fRasterizer);
REF_COPY(fLooper);
REF_COPY(fImageFilter);
REF_COPY(fAnnotation);
COPY(fTextSize);
COPY(fTextScaleX);
@ -114,7 +111,6 @@ SkPaint::SkPaint(SkPaint&& src) {
REF_MOVE(fRasterizer);
REF_MOVE(fLooper);
REF_MOVE(fImageFilter);
REF_MOVE(fAnnotation);
MOVE(fTextSize);
MOVE(fTextScaleX);
@ -138,7 +134,6 @@ SkPaint::~SkPaint() {
SkSafeUnref(fRasterizer);
SkSafeUnref(fLooper);
SkSafeUnref(fImageFilter);
SkSafeUnref(fAnnotation);
}
SkPaint& SkPaint::operator=(const SkPaint& src) {
@ -158,7 +153,6 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
REF_COPY(fRasterizer);
REF_COPY(fLooper);
REF_COPY(fImageFilter);
REF_COPY(fAnnotation);
COPY(fTextSize);
COPY(fTextScaleX);
@ -191,7 +185,6 @@ SkPaint& SkPaint::operator=(SkPaint&& src) {
REF_MOVE(fRasterizer);
REF_MOVE(fLooper);
REF_MOVE(fImageFilter);
REF_MOVE(fAnnotation);
MOVE(fTextSize);
MOVE(fTextScaleX);
@ -218,7 +211,6 @@ bool operator==(const SkPaint& a, const SkPaint& b) {
&& EQUAL(fRasterizer)
&& EQUAL(fLooper)
&& EQUAL(fImageFilter)
&& EQUAL(fAnnotation)
&& EQUAL(fTextSize)
&& EQUAL(fTextScaleX)
&& EQUAL(fTextSkewX)
@ -420,11 +412,6 @@ SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
return imageFilter;
}
SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
SkRefCnt_SafeAssign(fAnnotation, annotation);
return annotation;
}
///////////////////////////////////////////////////////////////////////////////
static SkScalar mag2(SkScalar x, SkScalar y) {
@ -1897,7 +1884,6 @@ void SkPaint::flatten(SkWriteBuffer& buffer) const {
asint(this->getColorFilter()) |
asint(this->getRasterizer()) |
asint(this->getLooper()) |
asint(this->getAnnotation()) |
asint(this->getImageFilter())) {
flatFlags |= kHasEffects_FlatFlag;
}
@ -1931,13 +1917,6 @@ void SkPaint::flatten(SkWriteBuffer& buffer) const {
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 @@ void SkPaint::unflatten(SkReadBuffer& buffer) {
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 @@ void SkPaint::toString(SkString* str) const {
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 @@ bool SkPaint::nothingToDraw() const {
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));

View File

@ -78,7 +78,9 @@ enum DrawType {
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*

View File

@ -175,6 +175,12 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
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);

View File

@ -777,6 +777,18 @@ void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[],
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&) {

View File

@ -204,6 +204,7 @@ protected:
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

View File

@ -60,6 +60,7 @@ public:
kBitmapSourceFilterQuality_Version = 41,
kPictureShaderHasPictureBool_Version = 42,
kHasDrawImageOpCodes_Version = 43,
kAnnotationsMovedToCanvas_Version = 44,
};
/**

View File

@ -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 @@ public:
*/
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());

View File

@ -117,6 +117,7 @@ DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.p
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 @@ private:
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;

View File

@ -332,6 +332,10 @@ void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], cons
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);
}

View File

@ -120,6 +120,7 @@ public:
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; }

View File

@ -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 @@ namespace SkRemote {
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 @@ namespace SkRemote {
fEncoder->undefine(fIDs.rasterizer);
fEncoder->undefine(fIDs.looper);
fEncoder->undefine(fIDs.imagefilter);
fEncoder->undefine(fIDs.annotation);
}
}
@ -461,7 +458,6 @@ namespace SkRemote {
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 @@ namespace SkRemote {
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 @@ namespace SkRemote {
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 @@ namespace SkRemote {
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 @@ namespace SkRemote {
fRasterizer .foreach(undef);
fDrawLooper .foreach(undef);
fImageFilter.foreach(undef);
fAnnotation .foreach(undef);
}
template <typename Map, typename T>
@ -679,7 +671,6 @@ namespace SkRemote {
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 @@ namespace SkRemote {
RefKeyMap<SkRasterizer , Type::kRasterizer > fRasterizer;
RefKeyMap<SkDrawLooper , Type::kDrawLooper > fDrawLooper;
RefKeyMap<SkImageFilter , Type::kImageFilter> fImageFilter;
RefKeyMap<SkAnnotation , Type::kAnnotation > fAnnotation;
Encoder* fWrapped;
};

View File

@ -79,14 +79,13 @@ namespace SkRemote {
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;

View File

@ -28,7 +28,6 @@ namespace SkRemote {
kRasterizer,
kDrawLooper,
kImageFilter,
kAnnotation,
};
} // namespace SkRemote

View File

@ -68,11 +68,6 @@ enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
///////////////////////////////////////////////////////////////////////////////
#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 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
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::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
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 @@ void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
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 @@ void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
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::drawDRRect(const SkDraw& draw, const SkRRect& outer,
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 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
}
}
CHECK_FOR_ANNOTATION(paint);
CHECK_SHOULD_DRAW(draw);
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext);
@ -1472,7 +1461,6 @@ void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* produc
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() ||

View File

@ -7,7 +7,7 @@
#include "SkPDFDevice.h"
#include "SkAnnotation.h"
#include "SkAnnotationKeys.h"
#include "SkColor.h"
#include "SkColorFilter.h"
#include "SkClipStack.h"
@ -757,6 +757,17 @@ void SkPDFDevice::cleanUp(bool clearFontUsage) {
}
}
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);
@ -796,12 +807,6 @@ void SkPDFDevice::drawPoints(const SkDraw& d,
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.
@ -939,14 +944,6 @@ void SkPDFDevice::drawRect(const SkDraw& d,
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;
@ -1025,12 +1022,6 @@ void SkPDFDevice::drawPath(const SkDraw& d,
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;
@ -1684,26 +1675,26 @@ bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
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.push(new NamedDestination(nameData, transformedPoint));
}
return true;
const char key[], SkData* value) {
if (!value) {
return;
}
if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) {
SkPoint transformedPoint;
matrix.mapXY(point.x(), point.y(), &transformedPoint);
fNamedDestinations.push(new NamedDestination(value, transformedPoint));
}
return false;
}
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);
@ -1712,24 +1703,15 @@ bool SkPDFDevice::handlePathAnnotation(const SkPath& path,
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.push(new RectWithData(transformedRect, urlData));
fLinkToURLs.push(new RectWithData(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.push(new RectWithData(transformedRect, linkToDestination));
fLinkToDestinations.push(new RectWithData(transformedRect, value));
}
return true;
}
return false;
}
void SkPDFDevice::appendAnnotations(SkPDFArray* array) const {

View File

@ -198,6 +198,8 @@ protected:
SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps&) override;
void drawAnnotation(const SkDraw&, const SkRect&, const char key[], SkData* value) override;
private:
// TODO(vandebo): push most of SkPDFDevice's state into a core object in
// order to get the right access levels without using friend.
@ -303,10 +305,8 @@ private:
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;

View File

@ -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 @@ void SkDumpCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4]
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);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -292,6 +292,13 @@ void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4]
}
}
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);

View File

@ -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 @@ DEF_TEST(Serialization, reporter) {
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);
}

View File

@ -278,3 +278,44 @@ DEF_TEST(Writer32_misc, reporter) {
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());
}