add replay entry point to SkPictureRecorder for Android
This CL adds an Android-only entry point to address the Java Picture(Picture) and serialize use cases. Note that (in its current form) it doesn't preserve the old API's handling of unbalanced saves/saveLayers (this CL always balances them). R=reed@google.com, scroggo@google.com, djsollen@google.com, mtklein@google.com Author: robertphillips@google.com Review URL: https://codereview.chromium.org/252873005 git-svn-id: http://skia.googlecode.com/svn/trunk@14911 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
293a4b367a
commit
6d3eaeabdd
@ -99,6 +99,15 @@ private:
|
|||||||
SkAutoTUnref<SkPictureFactory> fFactory;
|
SkAutoTUnref<SkPictureFactory> fFactory;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
/** Replay the current (partially recorded) operation stream into
|
||||||
|
canvas. This call doesn't close the current recording.
|
||||||
|
*/
|
||||||
|
friend class AndroidPicture;
|
||||||
|
friend class SkPictureRecorderReplayTester; // for unit testing
|
||||||
|
void partialReplay(SkCanvas* canvas);
|
||||||
|
#endif
|
||||||
|
|
||||||
SkAutoTUnref<SkPicture> fPicture;
|
SkAutoTUnref<SkPicture> fPicture;
|
||||||
|
|
||||||
typedef SkNoncopyable INHERITED;
|
typedef SkNoncopyable INHERITED;
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
#include "SkPicturePlayback.h"
|
||||||
|
#endif
|
||||||
#include "SkPictureRecorder.h"
|
#include "SkPictureRecorder.h"
|
||||||
|
|
||||||
SkCanvas* SkPictureRecorder::beginRecording(int width, int height,
|
SkCanvas* SkPictureRecorder::beginRecording(int width, int height,
|
||||||
@ -13,3 +16,19 @@ SkCanvas* SkPictureRecorder::beginRecording(int width, int height,
|
|||||||
fPicture.reset(SkNEW(SkPicture));
|
fPicture.reset(SkNEW(SkPicture));
|
||||||
return fPicture->beginRecording(width, height, bbhFactory, recordFlags);
|
return fPicture->beginRecording(width, height, bbhFactory, recordFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
void SkPictureRecorder::partialReplay(SkCanvas* canvas) {
|
||||||
|
if (NULL == fPicture.get() || NULL == canvas) {
|
||||||
|
// Not recording or nothing to replay into
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkASSERT(NULL != fPicture->fRecord);
|
||||||
|
|
||||||
|
SkAutoTDelete<SkPicturePlayback> playback(SkPicture::FakeEndRecording(fPicture,
|
||||||
|
*fPicture->fRecord,
|
||||||
|
false));
|
||||||
|
playback->draw(*canvas, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -916,6 +916,131 @@ static void set_canvas_to_save_count_4(SkCanvas* canvas) {
|
|||||||
canvas->save();
|
canvas->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
/**
|
||||||
|
* A canvas that records the number of saves, saveLayers and restores.
|
||||||
|
*/
|
||||||
|
class SaveCountingCanvas : public SkCanvas {
|
||||||
|
public:
|
||||||
|
SaveCountingCanvas(int width, int height)
|
||||||
|
: INHERITED(width, height)
|
||||||
|
, fSaveCount(0)
|
||||||
|
, fSaveLayerCount(0)
|
||||||
|
, fRestoreCount(0){
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||||
|
SaveFlags flags) SK_OVERRIDE {
|
||||||
|
++fSaveLayerCount;
|
||||||
|
return this->INHERITED::willSaveLayer(bounds, paint, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void willSave(SaveFlags flags) SK_OVERRIDE {
|
||||||
|
++fSaveCount;
|
||||||
|
this->INHERITED::willSave(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void willRestore() SK_OVERRIDE {
|
||||||
|
++fRestoreCount;
|
||||||
|
this->INHERITED::willRestore();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int getSaveCount() const { return fSaveCount; }
|
||||||
|
unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
|
||||||
|
unsigned int getRestoreCount() const { return fRestoreCount; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int fSaveCount;
|
||||||
|
unsigned int fSaveLayerCount;
|
||||||
|
unsigned int fRestoreCount;
|
||||||
|
|
||||||
|
typedef SkCanvas INHERITED;
|
||||||
|
};
|
||||||
|
|
||||||
|
void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
|
||||||
|
unsigned int numSaves, unsigned int numSaveLayers,
|
||||||
|
unsigned int numRestores) {
|
||||||
|
SaveCountingCanvas canvas(picture->width(), picture->height());
|
||||||
|
|
||||||
|
picture->draw(&canvas);
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, numSaves == canvas.getSaveCount());
|
||||||
|
REPORTER_ASSERT(reporter, numSaveLayers == canvas.getSaveLayerCount());
|
||||||
|
REPORTER_ASSERT(reporter, numRestores == canvas.getRestoreCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class exists so SkPicture can friend it and give it access to
|
||||||
|
// the 'partialReplay' method.
|
||||||
|
class SkPictureRecorderReplayTester {
|
||||||
|
public:
|
||||||
|
static SkPicture* Copy(SkPictureRecorder* recorder) {
|
||||||
|
SkPictureRecorder recorder2;
|
||||||
|
|
||||||
|
SkCanvas* canvas = recorder2.beginRecording(10, 10, NULL, 0);
|
||||||
|
|
||||||
|
recorder->partialReplay(canvas);
|
||||||
|
|
||||||
|
return recorder2.endRecording();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test out SkPictureRecorder::partialReplay
|
||||||
|
DEF_TEST(PictureRecorder_replay, reporter) {
|
||||||
|
// check save/saveLayer state
|
||||||
|
{
|
||||||
|
SkPictureRecorder recorder;
|
||||||
|
|
||||||
|
SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
|
||||||
|
|
||||||
|
canvas->saveLayer(NULL, NULL);
|
||||||
|
|
||||||
|
SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
|
||||||
|
|
||||||
|
// The extra save and restore comes from the Copy process.
|
||||||
|
check_save_state(reporter, copy, 2, 1, 3);
|
||||||
|
|
||||||
|
canvas->saveLayer(NULL, NULL);
|
||||||
|
|
||||||
|
SkAutoTUnref<SkPicture> final(recorder.endRecording());
|
||||||
|
|
||||||
|
check_save_state(reporter, final, 1, 2, 3);
|
||||||
|
|
||||||
|
// The copy shouldn't pick up any operations added after it was made
|
||||||
|
check_save_state(reporter, copy, 2, 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (partially) check leakage of draw ops
|
||||||
|
{
|
||||||
|
SkPictureRecorder recorder;
|
||||||
|
|
||||||
|
SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
|
||||||
|
|
||||||
|
SkRect r = SkRect::MakeWH(5, 5);
|
||||||
|
SkPaint p;
|
||||||
|
|
||||||
|
canvas->drawRect(r, p);
|
||||||
|
|
||||||
|
SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
|
||||||
|
|
||||||
|
SkBitmap bm;
|
||||||
|
make_bm(&bm, 10, 10, SK_ColorRED, true);
|
||||||
|
|
||||||
|
r.offset(5.0f, 5.0f);
|
||||||
|
canvas->drawBitmapRectToRect(bm, NULL, r);
|
||||||
|
|
||||||
|
SkAutoTUnref<SkPicture> final(recorder.endRecording());
|
||||||
|
REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
|
||||||
|
|
||||||
|
REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
|
||||||
|
|
||||||
|
// The snapshot shouldn't pick up any operations added after it was made
|
||||||
|
REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
|
static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
|
||||||
SkCanvas testCanvas(100, 100);
|
SkCanvas testCanvas(100, 100);
|
||||||
set_canvas_to_save_count_4(&testCanvas);
|
set_canvas_to_save_count_4(&testCanvas);
|
||||||
@ -994,20 +1119,21 @@ static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
|
|||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
canvas->drawRect(r, paint);
|
canvas->drawRect(r, paint);
|
||||||
|
|
||||||
// Copying a mid-recording picture could result in unbalanced saves/restores
|
// Check that copying a mid-recording picture does not result in unbalanced saves/restores
|
||||||
SkPicture p2(p);
|
SkPicture p2(p);
|
||||||
|
|
||||||
testCanvas.drawPicture(p2);
|
testCanvas.drawPicture(p2);
|
||||||
REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
|
REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
|
||||||
set_canvas_to_save_count_4(&testCanvas);
|
set_canvas_to_save_count_4(&testCanvas);
|
||||||
|
|
||||||
// Cloning a mid-recording picture could result in unbalanced saves/restores
|
// Check that cloning a mid-recording picture does not result in unbalanced saves/restores
|
||||||
SkAutoTUnref<SkPicture> p3(p.clone());
|
SkAutoTUnref<SkPicture> p3(p.clone());
|
||||||
testCanvas.drawPicture(*p3);
|
testCanvas.drawPicture(*p3);
|
||||||
REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
|
REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
|
||||||
set_canvas_to_save_count_4(&testCanvas);
|
set_canvas_to_save_count_4(&testCanvas);
|
||||||
|
|
||||||
// Serializing a mid-recording picture could result in unbalanced saves/restores
|
// Check that serializing a mid-recording picture doesn't result in unbalanced
|
||||||
|
// saves/restores
|
||||||
SkDynamicMemoryWStream wStream;
|
SkDynamicMemoryWStream wStream;
|
||||||
p.serialize(&wStream);
|
p.serialize(&wStream);
|
||||||
SkAutoDataUnref data(wStream.copyToData());
|
SkAutoDataUnref data(wStream.copyToData());
|
||||||
@ -1299,7 +1425,7 @@ static void test_clip_bound_opt(skiatest::Reporter* reporter) {
|
|||||||
*/
|
*/
|
||||||
class ClipCountingCanvas : public SkCanvas {
|
class ClipCountingCanvas : public SkCanvas {
|
||||||
public:
|
public:
|
||||||
explicit ClipCountingCanvas(int width, int height)
|
ClipCountingCanvas(int width, int height)
|
||||||
: INHERITED(width, height)
|
: INHERITED(width, height)
|
||||||
, fClipCount(0){
|
, fClipCount(0){
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user