|  | /* | 
|  | * 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})); | 
|  | } | 
|  | } |