Skip to content

Commit d884e27

Browse files
author
Emmanuel Garcia
authored
Add RTree to flow (flutter#16923)
1 parent 5294bd3 commit d884e27

File tree

5 files changed

+406
-0
lines changed

5 files changed

+406
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ FILE: ../../../flutter/flow/raster_cache.h
9292
FILE: ../../../flutter/flow/raster_cache_key.cc
9393
FILE: ../../../flutter/flow/raster_cache_key.h
9494
FILE: ../../../flutter/flow/raster_cache_unittests.cc
95+
FILE: ../../../flutter/flow/rtree.cc
96+
FILE: ../../../flutter/flow/rtree.h
97+
FILE: ../../../flutter/flow/rtree_unittests.cc
9598
FILE: ../../../flutter/flow/scene_update_context.cc
9699
FILE: ../../../flutter/flow/scene_update_context.h
97100
FILE: ../../../flutter/flow/skia_gpu_object.cc

flow/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ source_set("flow") {
5858
"raster_cache.h",
5959
"raster_cache_key.cc",
6060
"raster_cache_key.h",
61+
"rtree.cc",
62+
"rtree.h",
6163
"skia_gpu_object.cc",
6264
"skia_gpu_object.h",
6365
"texture.cc",
@@ -150,6 +152,7 @@ executable("flow_unittests") {
150152
"matrix_decomposition_unittests.cc",
151153
"mutators_stack_unittests.cc",
152154
"raster_cache_unittests.cc",
155+
"rtree_unittests.cc",
153156
"skia_gpu_object_unittests.cc",
154157
"testing/mock_layer_unittests.cc",
155158
"testing/mock_texture_unittests.cc",

flow/rtree.cc

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "rtree.h"
6+
7+
#include <list>
8+
9+
#include "flutter/fml/logging.h"
10+
#include "third_party/skia/include/core/SkBBHFactory.h"
11+
12+
namespace flutter {
13+
14+
RTree::RTree() : bbh_{SkRTreeFactory{}()}, all_ops_count_(0) {}
15+
16+
void RTree::insert(const SkRect boundsArray[],
17+
const SkBBoxHierarchy::Metadata metadata[],
18+
int N) {
19+
FML_DCHECK(0 == all_ops_count_);
20+
bbh_->insert(boundsArray, metadata, N);
21+
for (int i = 0; i < N; i++) {
22+
if (metadata != nullptr && metadata[i].isDraw) {
23+
draw_op_[i] = boundsArray[i];
24+
}
25+
}
26+
all_ops_count_ = N;
27+
}
28+
29+
void RTree::insert(const SkRect boundsArray[], int N) {
30+
insert(boundsArray, nullptr, N);
31+
}
32+
33+
void RTree::search(const SkRect& query, std::vector<int>* results) const {
34+
bbh_->search(query, results);
35+
}
36+
37+
std::list<SkRect> RTree::searchNonOverlappingDrawnRects(
38+
const SkRect& query) const {
39+
// Get the indexes for the operations that intersect with the query rect.
40+
std::vector<int> intermediary_results;
41+
search(query, &intermediary_results);
42+
43+
std::list<SkRect> final_results;
44+
for (int index : intermediary_results) {
45+
auto draw_op = draw_op_.find(index);
46+
// Ignore records that don't draw anything.
47+
if (draw_op == draw_op_.end()) {
48+
continue;
49+
}
50+
auto current_record_rect = draw_op->second;
51+
auto replaced_existing_rect = false;
52+
// // If the current record rect intersects with any of the rects in the
53+
// // result list, then join them, and update the rect in final_results.
54+
std::list<SkRect>::iterator curr_rect_itr = final_results.begin();
55+
std::list<SkRect>::iterator first_intersecting_rect_itr;
56+
while (!replaced_existing_rect && curr_rect_itr != final_results.end()) {
57+
if (SkRect::Intersects(*curr_rect_itr, current_record_rect)) {
58+
replaced_existing_rect = true;
59+
first_intersecting_rect_itr = curr_rect_itr;
60+
curr_rect_itr->join(current_record_rect);
61+
}
62+
curr_rect_itr++;
63+
}
64+
// It's possible that the result contains duplicated rects at this point.
65+
// For example, consider a result list that contains rects A, B. If a
66+
// new rect C is a superset of A and B, then A and B are the same set after
67+
// the merge. As a result, find such cases and remove them from the result
68+
// list.
69+
while (replaced_existing_rect && curr_rect_itr != final_results.end()) {
70+
if (SkRect::Intersects(*curr_rect_itr, *first_intersecting_rect_itr)) {
71+
first_intersecting_rect_itr->join(*curr_rect_itr);
72+
curr_rect_itr = final_results.erase(curr_rect_itr);
73+
} else {
74+
curr_rect_itr++;
75+
}
76+
}
77+
if (!replaced_existing_rect) {
78+
final_results.push_back(current_record_rect);
79+
}
80+
}
81+
return final_results;
82+
}
83+
84+
size_t RTree::bytesUsed() const {
85+
return bbh_->bytesUsed();
86+
}
87+
88+
RTreeFactory::RTreeFactory() {
89+
r_tree_ = sk_make_sp<RTree>();
90+
}
91+
92+
sk_sp<RTree> RTreeFactory::getInstance() {
93+
return r_tree_;
94+
}
95+
96+
sk_sp<SkBBoxHierarchy> RTreeFactory::operator()() const {
97+
return r_tree_;
98+
}
99+
100+
} // namespace flutter

flow/rtree.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FLOW_RTREE_H_
6+
#define FLUTTER_FLOW_RTREE_H_
7+
8+
#include <list>
9+
#include <map>
10+
11+
#include "third_party/skia/include/core/SkBBHFactory.h"
12+
#include "third_party/skia/include/core/SkTypes.h"
13+
14+
namespace flutter {
15+
/**
16+
* An R-Tree implementation that forwards calls to an SkRTree.
17+
*
18+
* This implementation provides a searchNonOverlappingDrawnRects method,
19+
* which can be used to query the rects for the operations recorded in the tree.
20+
*/
21+
class RTree : public SkBBoxHierarchy {
22+
public:
23+
RTree();
24+
25+
void insert(const SkRect[],
26+
const SkBBoxHierarchy::Metadata[],
27+
int N) override;
28+
void insert(const SkRect[], int N) override;
29+
void search(const SkRect& query, std::vector<int>* results) const override;
30+
size_t bytesUsed() const override;
31+
32+
// Finds the rects in the tree that represent drawing operations and intersect
33+
// with the query rect.
34+
//
35+
// When two rects intersect with each other, they are joined into a single
36+
// rect which also intersects with the query rect. In other words, the bounds
37+
// of each rect in the result list are mutually exclusive.
38+
std::list<SkRect> searchNonOverlappingDrawnRects(const SkRect& query) const;
39+
40+
// Insertion count (not overall node count, which may be greater).
41+
int getCount() const { return all_ops_count_; }
42+
43+
private:
44+
// A map containing the draw operation rects keyed off the operation index
45+
// in the insert call.
46+
std::map<int, SkRect> draw_op_;
47+
sk_sp<SkBBoxHierarchy> bbh_;
48+
int all_ops_count_;
49+
};
50+
51+
class RTreeFactory : public SkBBHFactory {
52+
public:
53+
RTreeFactory();
54+
55+
// Gets the instance to the R-tree.
56+
sk_sp<RTree> getInstance();
57+
sk_sp<SkBBoxHierarchy> operator()() const override;
58+
59+
private:
60+
sk_sp<RTree> r_tree_;
61+
};
62+
63+
} // namespace flutter
64+
65+
#endif // FLUTTER_FLOW_RTREE_H_

0 commit comments

Comments
 (0)