| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "rtree.h" | |
| #include "flutter/testing/testing.h" | |
| #include "third_party/skia/include/core/SkCanvas.h" | |
| #include "third_party/skia/include/core/SkPictureRecorder.h" | |
| namespace flutter { | |
| namespace testing { | |
| TEST(RTree, searchNonOverlappingDrawnRectsNoIntersection) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // If no rect is intersected with the query rect, then the result list is | |
| // empty. | |
| recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 40, 40), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(40, 40, 80, 80)); | |
| ASSERT_TRUE(hits.empty()); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsSingleRectIntersection) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Given a single rect A that intersects with the query rect, | |
| // the result list contains this rect. | |
| recording_canvas->drawRect(SkRect::MakeLTRB(120, 120, 160, 160), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(140, 140, 150, 150)); | |
| ASSERT_EQ(1UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 160, 160)); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsIgnoresNonDrawingRecords) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Creates two non drawing records. | |
| recording_canvas->translate(100, 100); | |
| // The result list should only contain the clipping rect. | |
| recording_canvas->clipRect(SkRect::MakeLTRB(40, 40, 50, 50), | |
| SkClipOp::kIntersect); | |
| recording_canvas->drawRect(SkRect::MakeLTRB(20, 20, 80, 80), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| // The rtree has a translate, a clip and a rect record. | |
| ASSERT_EQ(3, rtree_factory.getInstance()->getCount()); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(0, 0, 1000, 1000)); | |
| ASSERT_EQ(1UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(120, 120, 180, 180)); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsMultipleRectIntersection) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Given the A, B that intersect with the query rect, | |
| // there should be A and B in the result list since | |
| // they don't intersect with each other. | |
| // | |
| // +-----+ +-----+ | |
| // | A | | B | | |
| // +-----+ +-----+ | |
| // A | |
| recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); | |
| // B | |
| recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(0, 0, 1000, 1050)); | |
| ASSERT_EQ(2UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 200, 200)); | |
| ASSERT_EQ(*std::next(hits.begin(), 1), SkRect::MakeLTRB(300, 100, 400, 200)); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsJoinRectsWhenIntersectedCase1) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Given the A, and B rects, which intersect with the query rect, | |
| // the result list contains the rect resulting from the union of A and B. | |
| // | |
| // +-----+ | |
| // | A | | |
| // | +-----+ | |
| // | | C | | |
| // | +-----+ | |
| // | | | |
| // +-----+ | |
| // A | |
| recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 150, 150), rect_paint); | |
| // B | |
| recording_canvas->drawRect(SkRect::MakeLTRB(125, 125, 175, 175), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeXYWH(120, 120, 126, 126)); | |
| ASSERT_EQ(1UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(100, 100, 175, 175)); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsJoinRectsWhenIntersectedCase2) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Given the A, B, and C rects that intersect with the query rect, | |
| // there should be only C in the result list, | |
| // since A and B are contained in C. | |
| // | |
| // +---------------------+ | |
| // | C | | |
| // | +-----+ +-----+ | | |
| // | | A | | B | | | |
| // | +-----+ +-----+ | | |
| // +---------------------+ | |
| // +-----+ | |
| // | D | | |
| // +-----+ | |
| // A | |
| recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); | |
| // B | |
| recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); | |
| // C | |
| recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 500, 250), rect_paint); | |
| // D | |
| recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(30, 30, 550, 270)); | |
| ASSERT_EQ(1UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 500, 250)); | |
| } | |
| TEST(RTree, searchNonOverlappingDrawnRectsJoinRectsWhenIntersectedCase3) { | |
| auto rtree_factory = RTreeFactory(); | |
| auto recorder = std::make_unique<SkPictureRecorder>(); | |
| auto recording_canvas = | |
| recorder->beginRecording(SkRect::MakeIWH(1000, 1000), &rtree_factory); | |
| auto rect_paint = SkPaint(); | |
| rect_paint.setColor(SkColors::kCyan); | |
| rect_paint.setStyle(SkPaint::Style::kFill_Style); | |
| // Given the A, B, C and D rects that intersect with the query rect, | |
| // the result list contains a single rect, which is the union of | |
| // these four rects. | |
| // | |
| // +------------------------------+ | |
| // | D | | |
| // | +-----+ +-----+ +-----+ | | |
| // | | A | | B | | C | | | |
| // | +-----+ +-----+ | | | | |
| // +----------------------| |-+ | |
| // +-----+ | |
| // +-----+ | |
| // | E | | |
| // +-----+ | |
| // A | |
| recording_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), rect_paint); | |
| // B | |
| recording_canvas->drawRect(SkRect::MakeLTRB(300, 100, 400, 200), rect_paint); | |
| // C | |
| recording_canvas->drawRect(SkRect::MakeLTRB(500, 100, 600, 300), rect_paint); | |
| // D | |
| recording_canvas->drawRect(SkRect::MakeLTRB(50, 50, 620, 250), rect_paint); | |
| // E | |
| recording_canvas->drawRect(SkRect::MakeLTRB(280, 100, 280, 320), rect_paint); | |
| recorder->finishRecordingAsPicture(); | |
| auto hits = rtree_factory.getInstance()->searchNonOverlappingDrawnRects( | |
| SkRect::MakeLTRB(30, 30, 550, 270)); | |
| ASSERT_EQ(1UL, hits.size()); | |
| ASSERT_EQ(*hits.begin(), SkRect::MakeLTRB(50, 50, 620, 300)); | |
| } | |
| } // namespace testing | |
| } // namespace flutter |