/*
* 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 "SkBitmap.h"
#include "SkCanvas.h"
#include "SkBBoxHierarchy.h"
#include "SkPaint.h"
#include "SkPicture.h"
#include "SkPictureRecorder.h"
#include "SkRectPriv.h"
#include "Test.h"
class PictureBBHTestBase {
public:
PictureBBHTestBase(int playbackWidth, int playbackHeight,
int recordWidth, int recordHeight) {
fResultBitmap.allocN32Pixels(playbackWidth, playbackHeight);
fPictureWidth = recordWidth;
fPictureHeight = recordHeight;
}
virtual ~PictureBBHTestBase() { }
virtual void doTest(SkCanvas& playbackCanvas, SkCanvas& recordingCanvas) = 0;
void run(skiatest::Reporter* reporter) {
// No BBH
this->run(nullptr, reporter);
// With an R-Tree
SkRTreeFactory RTreeFactory;
this->run(&RTreeFactory, reporter);
}
private:
void run(SkBBHFactory* factory, skiatest::Reporter* reporter) {
SkCanvas playbackCanvas(fResultBitmap);
playbackCanvas.clear(SK_ColorGREEN);
SkPictureRecorder recorder;
SkCanvas* recordCanvas = recorder.beginRecording(SkIntToScalar(fPictureWidth),
SkIntToScalar(fPictureHeight),
factory);
this->doTest(playbackCanvas, *recordCanvas);
sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
playbackCanvas.drawPicture(picture);
REPORTER_ASSERT(reporter, SK_ColorGREEN == fResultBitmap.getColor(0, 0));
}
SkBitmap fResultBitmap;
int fPictureWidth, fPictureHeight;
};
// Test to verify the playback of an empty picture
//
class DrawEmptyPictureBBHTest : public PictureBBHTestBase {
public:
DrawEmptyPictureBBHTest()
: PictureBBHTestBase(2, 2, 1, 1) {}
~DrawEmptyPictureBBHTest() override {}
void doTest(SkCanvas&, SkCanvas&) override {}
};
// Test to verify the playback of a picture into a canvas that has
// an empty clip.
//
class EmptyClipPictureBBHTest : public PictureBBHTestBase {
public:
EmptyClipPictureBBHTest()
: PictureBBHTestBase(2, 2, 3, 3) {}
void doTest(SkCanvas& playbackCanvas, SkCanvas& recordingCanvas) override {
// intersect with out of bounds rect -> empty clip.
playbackCanvas.clipRect(SkRect::MakeXYWH(10, 10, 1, 1));
SkPaint paint;
recordingCanvas.drawRect(SkRect::MakeWH(3, 3), paint);
}
~EmptyClipPictureBBHTest() override {}
};
DEF_TEST(PictureBBH, reporter) {
DrawEmptyPictureBBHTest emptyPictureTest;
emptyPictureTest.run(reporter);
EmptyClipPictureBBHTest emptyClipPictureTest;
emptyClipPictureTest.run(reporter);
}
DEF_TEST(RTreeMakeLargest, r) {
// A call to insert() with 2 or more rects and a bounds of SkRect::MakeLargest()
// used to fall into an infinite loop.
SkRTreeFactory factory;
std::unique_ptr<SkBBoxHierarchy> bbh{ factory(SkRectPriv::MakeLargest()) };
SkRect rects[] = { {0,0, 10,10}, {5,5,15,15} };
bbh->insert(rects, SK_ARRAY_COUNT(rects));
REPORTER_ASSERT(r, bbh->getRootBound() == SkRect::MakeWH(15,15));
}
DEF_TEST(PictureNegativeSpace, r) {
SkRTreeFactory factory;
SkPictureRecorder recorder;
SkRect cull = {-200,-200,+200,+200};
{
auto canvas = recorder.beginRecording(cull, &factory);
canvas->save();
canvas->clipRect(cull);
canvas->drawRect({-20,-20,-10,-10}, SkPaint{});
canvas->drawRect({-20,-20,-10,-10}, SkPaint{});
canvas->restore();
auto pic = recorder.finishRecordingAsPicture();
REPORTER_ASSERT(r, pic->approximateOpCount() == 5);
REPORTER_ASSERT(r, pic->cullRect() == (SkRect{-20,-20,-10,-10}));
}
{
auto canvas = recorder.beginRecording(cull, &factory);
canvas->clipRect(cull);
canvas->drawRect({-20,-20,-10,-10}, SkPaint{});
canvas->drawRect({-20,-20,-10,-10}, SkPaint{});
auto pic = recorder.finishRecordingAsPicture();
REPORTER_ASSERT(r, pic->approximateOpCount() == 3);
REPORTER_ASSERT(r, pic->cullRect() == (SkRect{-20,-20,-10,-10}));
}
}