skia2/tests/RecordDrawTest.cpp
Mike Klein c11530ea73 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
2014-06-24 11:29:06 -04:00

164 lines
5.4 KiB
C++

/*
* Copyright 2014 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 "RecordTestUtils.h"
#include "SkDebugCanvas.h"
#include "SkDrawPictureCallback.h"
#include "SkRecord.h"
#include "SkRecordOpts.h"
#include "SkRecordDraw.h"
#include "SkRecorder.h"
#include "SkRecords.h"
static const int W = 1920, H = 1080;
static void draw_pos_text_h(SkCanvas* canvas, const char* text, SkScalar y) {
const size_t len = strlen(text);
SkAutoTMalloc<SkScalar> xpos(len);
for (size_t i = 0; i < len; i++) {
xpos[i] = (SkScalar)i;
}
canvas->drawPosTextH(text, len, xpos, y, SkPaint());
}
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);
SkRecordDraw(record, &recorder);
}
DEF_TEST(RecordDraw_PosTextHQuickReject, r) {
SkRecord record;
SkRecorder recorder(&record, W, H);
draw_pos_text_h(&recorder, "This will draw.", 20);
draw_pos_text_h(&recorder, "This won't.", 5000);
SkRecordBoundDrawPosTextH(&record);
SkRecord clipped;
record_clipped(record, SkRect::MakeLTRB(20, 20, 200, 200), &clipped);
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) {
// Record these 7 drawing commands verbatim.
SkRecord record;
SkRecorder recorder(&record, W, H);
recorder.pushCull(SkRect::MakeWH(100, 100));
recorder.drawRect(SkRect::MakeWH(10, 10), SkPaint());
recorder.drawRect(SkRect::MakeWH(30, 30), SkPaint());
recorder.pushCull(SkRect::MakeWH(5, 5));
recorder.drawRect(SkRect::MakeWH(1, 1), SkPaint());
recorder.popCull();
recorder.popCull();
// Take a pass over to match up pushCulls and popCulls.
SkRecordAnnotateCullingPairs(&record);
// This clip intersects the outer cull, but allows us to quick reject the inner one.
SkRecord clipped;
record_clipped(record, SkRect::MakeLTRB(20, 20, 200, 200), &clipped);
// 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) {
// Set up an SkRecord that just scales by 2x,3x.
SkRecord scaleRecord;
SkRecorder scaleCanvas(&scaleRecord, W, H);
SkMatrix scale;
scale.setScale(2, 3);
scaleCanvas.setMatrix(scale);
// Set up an SkRecord with an initial +20, +20 translate.
SkRecord translateRecord;
SkRecorder translateCanvas(&translateRecord, W, H);
SkMatrix translate;
translate.setTranslate(20, 20);
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.
const SkRecords::SetMatrix* setMatrix;
setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
REPORTER_ASSERT(r, setMatrix->matrix == translate);
setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
SkMatrix expected = scale;
expected.postConcat(translate);
REPORTER_ASSERT(r, setMatrix->matrix == expected);
}