Tick off some TODOs:
- support fRecord in copy constructor - support SkDrawPictureCallback Moved SkDrawPictureCallback to its own header so SkRecordDraw can include it without pulling in all of SkPicture. Adding an SkAutoSaveRestore to SkRecordDraw was the easiest way to match the balance guarantees of the callback, and probably not a bad idea in general. Updated its tests. BUG=skia: R=robertphillips@google.com Review URL: https://codereview.chromium.org/349973008
This commit is contained in:
parent
5a940b5cbb
commit
c11530ea73
29
include/core/SkDrawPictureCallback.h
Normal file
29
include/core/SkDrawPictureCallback.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDrawPictureCallback_DEFINED
|
||||
#define SkDrawPictureCallback_DEFINED
|
||||
|
||||
/**
|
||||
* Subclasses of this can be passed to canvas.drawPicture(). During the drawing
|
||||
* of the picture, this callback will periodically be invoked. If its
|
||||
* abortDrawing() returns true, then picture playback will be interrupted.
|
||||
*
|
||||
* The resulting drawing is undefined, as there is no guarantee how often the
|
||||
* callback will be invoked. If the abort happens inside some level of nested
|
||||
* calls to save(), restore will automatically be called to return the state
|
||||
* to the same level it was before the drawPicture call was made.
|
||||
*/
|
||||
class SK_API SkDrawPictureCallback {
|
||||
public:
|
||||
SkDrawPictureCallback() {}
|
||||
virtual ~SkDrawPictureCallback() {}
|
||||
|
||||
virtual bool abortDrawing() = 0;
|
||||
};
|
||||
|
||||
#endif//SkDrawPictureCallback_DEFINED
|
@ -11,6 +11,7 @@
|
||||
#define SkPicture_DEFINED
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkDrawPictureCallback.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
@ -21,7 +22,6 @@ class GrContext;
|
||||
class SkBBHFactory;
|
||||
class SkBBoxHierarchy;
|
||||
class SkCanvas;
|
||||
class SkDrawPictureCallback;
|
||||
class SkData;
|
||||
class SkPicturePlayback;
|
||||
class SkPictureRecord;
|
||||
@ -314,22 +314,4 @@ private:
|
||||
SkAutoTDelete<SkRecord> fRecord;
|
||||
};
|
||||
|
||||
/**
|
||||
* Subclasses of this can be passed to canvas.drawPicture. During the drawing
|
||||
* of the picture, this callback will periodically be invoked. If its
|
||||
* abortDrawing() returns true, then picture playback will be interrupted.
|
||||
*
|
||||
* The resulting drawing is undefined, as there is no guarantee how often the
|
||||
* callback will be invoked. If the abort happens inside some level of nested
|
||||
* calls to save(), restore will automatically be called to return the state
|
||||
* to the same level it was before the drawPicture call was made.
|
||||
*/
|
||||
class SK_API SkDrawPictureCallback {
|
||||
public:
|
||||
SkDrawPictureCallback() {}
|
||||
virtual ~SkDrawPictureCallback() {}
|
||||
|
||||
virtual bool abortDrawing() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "SkBitmapDevice.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkChunkAlloc.h"
|
||||
#include "SkDrawPictureCallback.h"
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkRegion.h"
|
||||
@ -34,6 +35,7 @@
|
||||
|
||||
#include "SkRecord.h"
|
||||
#include "SkRecordDraw.h"
|
||||
#include "SkRecorder.h"
|
||||
|
||||
template <typename T> int SafeCount(const T* obj) {
|
||||
return obj ? obj->count() : 0;
|
||||
@ -146,29 +148,42 @@ SkPicture::SkPicture(int width, int height,
|
||||
fPlayback.reset(SkNEW_ARGS(SkPicturePlayback, (record, info, deepCopyOps)));
|
||||
}
|
||||
|
||||
// fRecord TODO
|
||||
// The simplest / safest way to copy an SkRecord is to replay it into a new one.
|
||||
static SkRecord* copy(const SkRecord& src, int width, int height) {
|
||||
SkRecord* dst = SkNEW(SkRecord);
|
||||
SkRecorder recorder(dst, width, height);
|
||||
SkRecordDraw(src, &recorder);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// fRecord OK
|
||||
SkPicture::SkPicture(const SkPicture& src) : INHERITED() {
|
||||
this->needsNewGenID();
|
||||
fWidth = src.fWidth;
|
||||
fHeight = src.fHeight;
|
||||
|
||||
if (src.fPlayback.get()) {
|
||||
if (NULL != src.fPlayback.get()) {
|
||||
fPlayback.reset(SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)));
|
||||
fUniqueID = src.uniqueID(); // need to call method to ensure != 0
|
||||
fUniqueID = src.uniqueID(); // need to call method to ensure != 0
|
||||
}
|
||||
|
||||
if (NULL != src.fRecord.get()) {
|
||||
fRecord.reset(copy(*src.fRecord, fWidth, fHeight));
|
||||
fUniqueID = src.uniqueID(); // need to call method to ensure != 0
|
||||
}
|
||||
}
|
||||
|
||||
// fRecord OK
|
||||
SkPicture::~SkPicture() {}
|
||||
|
||||
// fRecord TODO
|
||||
// fRecord TODO, fix by deleting this method
|
||||
SkPicture* SkPicture::clone() const {
|
||||
SkPicture* clonedPicture = SkNEW(SkPicture);
|
||||
this->clone(clonedPicture, 1);
|
||||
return clonedPicture;
|
||||
}
|
||||
|
||||
// fRecord TODO
|
||||
// fRecord TODO, fix by deleting this method
|
||||
void SkPicture::clone(SkPicture* pictures, int count) const {
|
||||
SkPictCopyInfo copyInfo;
|
||||
|
||||
@ -293,8 +308,7 @@ void SkPicture::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
|
||||
fPlayback->draw(*canvas, callback);
|
||||
}
|
||||
if (NULL != fRecord.get()) {
|
||||
// TODO: support SkDrawPictureCallback
|
||||
SkRecordDraw(*fRecord, canvas);
|
||||
SkRecordDraw(*fRecord, canvas, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,7 +509,7 @@ bool SkPicture::willPlayBackBitmaps() const {
|
||||
}
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
// fRecord TODO
|
||||
// fRecord TODO, fix by switching Android to SkDrawPictureCallback, then deleting this method
|
||||
void SkPicture::abortPlayback() {
|
||||
if (NULL == fPlayback.get()) {
|
||||
return;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#include <new>
|
||||
#include "SkBBoxHierarchy.h"
|
||||
#include "SkDrawPictureCallback.h"
|
||||
#include "SkPicturePlayback.h"
|
||||
#include "SkPictureRecord.h"
|
||||
#include "SkPictureStateTree.h"
|
||||
@ -1355,7 +1356,7 @@ bool SkPicturePlayback::suitableForGpuRasterization(GrContext* context, const ch
|
||||
&& 0 == sampleCount);
|
||||
|
||||
bool ret = suitableForDash &&
|
||||
(fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
|
||||
(fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
|
||||
< kNumAAConcavePaths;
|
||||
if (!ret && NULL != reason) {
|
||||
if (!suitableForDash) {
|
||||
@ -1364,7 +1365,7 @@ bool SkPicturePlayback::suitableForGpuRasterization(GrContext* context, const ch
|
||||
} else {
|
||||
*reason = "Too many non dashed path effects.";
|
||||
}
|
||||
} else if ((fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
|
||||
} else if ((fContentInfo.numAAConcavePaths() - fContentInfo.numAAHairlineConcavePaths())
|
||||
>= kNumAAConcavePaths)
|
||||
*reason = "Too many anti-aliased concave paths.";
|
||||
else
|
||||
|
@ -7,8 +7,12 @@
|
||||
|
||||
#include "SkRecordDraw.h"
|
||||
|
||||
void SkRecordDraw(const SkRecord& record, SkCanvas* canvas) {
|
||||
void SkRecordDraw(const SkRecord& record, SkCanvas* canvas, SkDrawPictureCallback* callback) {
|
||||
SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
|
||||
for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) {
|
||||
if (NULL != callback && callback->abortDrawing()) {
|
||||
return;
|
||||
}
|
||||
record.visit<void>(draw.index(), draw);
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,10 @@
|
||||
|
||||
#include "SkRecord.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDrawPictureCallback.h"
|
||||
|
||||
// Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::Draw.
|
||||
void SkRecordDraw(const SkRecord&, SkCanvas*);
|
||||
void SkRecordDraw(const SkRecord&, SkCanvas*, SkDrawPictureCallback* = NULL);
|
||||
|
||||
namespace SkRecords {
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "RecordTestUtils.h"
|
||||
|
||||
#include "SkDebugCanvas.h"
|
||||
#include "SkDrawPictureCallback.h"
|
||||
#include "SkRecord.h"
|
||||
#include "SkRecordOpts.h"
|
||||
#include "SkRecordDraw.h"
|
||||
@ -26,8 +27,51 @@ static void draw_pos_text_h(SkCanvas* canvas, const char* text, SkScalar y) {
|
||||
canvas->drawPosTextH(text, len, xpos, y, SkPaint());
|
||||
}
|
||||
|
||||
// Rerecord into another SkRecord using full SkCanvas semantics,
|
||||
// tracking clips and allowing SkRecordDraw's quickReject() calls to work.
|
||||
class JustOneDraw : public SkDrawPictureCallback {
|
||||
public:
|
||||
JustOneDraw() : fCalls(0) {}
|
||||
|
||||
virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; }
|
||||
private:
|
||||
int fCalls;
|
||||
};
|
||||
|
||||
DEF_TEST(RecordDraw_Abort, r) {
|
||||
// Record two commands.
|
||||
SkRecord record;
|
||||
SkRecorder recorder(&record, W, H);
|
||||
recorder.drawRect(SkRect::MakeWH(200, 300), SkPaint());
|
||||
recorder.clipRect(SkRect::MakeWH(100, 200));
|
||||
|
||||
SkRecord rerecord;
|
||||
SkRecorder canvas(&rerecord, W, H);
|
||||
|
||||
JustOneDraw callback;
|
||||
SkRecordDraw(record, &canvas, &callback);
|
||||
|
||||
REPORTER_ASSERT(r, 3 == rerecord.count());
|
||||
assert_type<SkRecords::Save> (r, rerecord, 0);
|
||||
assert_type<SkRecords::DrawRect>(r, rerecord, 1);
|
||||
assert_type<SkRecords::Restore> (r, rerecord, 2);
|
||||
}
|
||||
|
||||
DEF_TEST(RecordDraw_Unbalanced, r) {
|
||||
SkRecord record;
|
||||
SkRecorder recorder(&record, W, H);
|
||||
recorder.save(); // We won't balance this, but SkRecordDraw will for us.
|
||||
|
||||
SkRecord rerecord;
|
||||
SkRecorder canvas(&rerecord, W, H);
|
||||
SkRecordDraw(record, &canvas);
|
||||
|
||||
REPORTER_ASSERT(r, 4 == rerecord.count());
|
||||
assert_type<SkRecords::Save> (r, rerecord, 0);
|
||||
assert_type<SkRecords::Save> (r, rerecord, 1);
|
||||
assert_type<SkRecords::Restore> (r, rerecord, 2);
|
||||
assert_type<SkRecords::Restore> (r, rerecord, 3);
|
||||
}
|
||||
|
||||
// Rerecord into another SkRecord with a clip.
|
||||
static void record_clipped(const SkRecord& record, SkRect clip, SkRecord* clipped) {
|
||||
SkRecorder recorder(clipped, W, H);
|
||||
recorder.clipRect(clip);
|
||||
@ -46,8 +90,11 @@ DEF_TEST(RecordDraw_PosTextHQuickReject, r) {
|
||||
SkRecord clipped;
|
||||
record_clipped(record, SkRect::MakeLTRB(20, 20, 200, 200), &clipped);
|
||||
|
||||
// clipRect and the first drawPosTextH.
|
||||
REPORTER_ASSERT(r, 2 == clipped.count());
|
||||
REPORTER_ASSERT(r, 4 == clipped.count());
|
||||
assert_type<SkRecords::ClipRect> (r, clipped, 0);
|
||||
assert_type<SkRecords::Save> (r, clipped, 1);
|
||||
assert_type<SkRecords::DrawPosTextH>(r, clipped, 2);
|
||||
assert_type<SkRecords::Restore> (r, clipped, 3);
|
||||
}
|
||||
|
||||
DEF_TEST(RecordDraw_Culling, r) {
|
||||
@ -70,9 +117,15 @@ DEF_TEST(RecordDraw_Culling, r) {
|
||||
SkRecord clipped;
|
||||
record_clipped(record, SkRect::MakeLTRB(20, 20, 200, 200), &clipped);
|
||||
|
||||
// We'll keep the clipRect call from above, and the outer two drawRects, and the push/pop pair.
|
||||
// If culling weren't working, we'd see 8 commands recorded here.
|
||||
REPORTER_ASSERT(r, 5 == clipped.count());
|
||||
// If culling weren't working, we'd see 3 more commands recorded here.
|
||||
REPORTER_ASSERT(r, 7 == clipped.count());
|
||||
assert_type<SkRecords::ClipRect>(r, clipped, 0);
|
||||
assert_type<SkRecords::Save> (r, clipped, 1);
|
||||
assert_type<SkRecords::PushCull>(r, clipped, 2);
|
||||
assert_type<SkRecords::DrawRect>(r, clipped, 3);
|
||||
assert_type<SkRecords::DrawRect>(r, clipped, 4);
|
||||
assert_type<SkRecords::PopCull> (r, clipped, 5);
|
||||
assert_type<SkRecords::Restore> (r, clipped, 6);
|
||||
}
|
||||
|
||||
DEF_TEST(RecordDraw_SetMatrixClobber, r) {
|
||||
@ -91,6 +144,11 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
|
||||
translateCanvas.setMatrix(translate);
|
||||
|
||||
SkRecordDraw(scaleRecord, &translateCanvas);
|
||||
REPORTER_ASSERT(r, 4 == translateRecord.count());
|
||||
assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
|
||||
assert_type<SkRecords::Save> (r, translateRecord, 1);
|
||||
assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
|
||||
assert_type<SkRecords::Restore> (r, translateRecord, 3);
|
||||
|
||||
// When we look at translateRecord now, it should have its first +20,+20 translate,
|
||||
// then a 2x,3x scale that's been concatted with that +20,+20 translate.
|
||||
@ -98,7 +156,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) {
|
||||
setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
|
||||
REPORTER_ASSERT(r, setMatrix->matrix == translate);
|
||||
|
||||
setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 1);
|
||||
setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
|
||||
SkMatrix expected = scale;
|
||||
expected.postConcat(translate);
|
||||
REPORTER_ASSERT(r, setMatrix->matrix == expected);
|
||||
|
Loading…
Reference in New Issue
Block a user