Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ FILE: ../../../flutter/display_list/display_list_paint_unittests.cc
FILE: ../../../flutter/display_list/display_list_path_effect.cc
FILE: ../../../flutter/display_list/display_list_path_effect.h
FILE: ../../../flutter/display_list/display_list_path_effect_unittests.cc
FILE: ../../../flutter/display_list/display_list_rtree.cc
FILE: ../../../flutter/display_list/display_list_rtree.h
FILE: ../../../flutter/display_list/display_list_sampling_options.h
FILE: ../../../flutter/display_list/display_list_test_utils.cc
FILE: ../../../flutter/display_list/display_list_test_utils.h
Expand Down
2 changes: 2 additions & 0 deletions display_list/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ source_set("display_list") {
"display_list_paint.h",
"display_list_path_effect.cc",
"display_list_path_effect.h",
"display_list_rtree.cc",
"display_list_rtree.h",
"display_list_sampling_options.h",
"display_list_tile_mode.h",
"display_list_utils.cc",
Expand Down
18 changes: 16 additions & 2 deletions display_list/display_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,23 @@ DisplayList::~DisplayList() {
}

void DisplayList::ComputeBounds() {
DisplayListBoundsCalculator calculator(&bounds_cull_);
RectBoundsAccumulator accumulator;
DisplayListBoundsCalculator calculator(accumulator, &bounds_cull_);
Dispatch(calculator);
bounds_ = calculator.bounds();
if (calculator.is_unbounded()) {
FML_LOG(INFO) << "returning partial bounds for unbounded DisplayList";
}
bounds_ = accumulator.bounds();
}

void DisplayList::ComputeRTree() {
RTreeBoundsAccumulator accumulator;
DisplayListBoundsCalculator calculator(accumulator, &bounds_cull_);
Dispatch(calculator);
if (calculator.is_unbounded()) {
FML_LOG(INFO) << "returning partial rtree for unbounded DisplayList";
}
rtree_ = accumulator.rtree();
}

void DisplayList::Dispatch(Dispatcher& dispatcher,
Expand Down
11 changes: 11 additions & 0 deletions display_list/display_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_H_

#include <memory>
#include <optional>

#include "flutter/display_list/display_list_rtree.h"
#include "flutter/display_list/display_list_sampling_options.h"
#include "flutter/display_list/types.h"
#include "flutter/fml/logging.h"
Expand Down Expand Up @@ -254,6 +256,13 @@ class DisplayList : public SkRefCnt {
return bounds_;
}

sk_sp<const DlRTree> rtree() {
if (!rtree_) {
ComputeRTree();
}
return rtree_;
}

bool Equals(const DisplayList* other) const;
bool Equals(const DisplayList& other) const { return Equals(&other); }
bool Equals(sk_sp<const DisplayList> other) const {
Expand Down Expand Up @@ -282,13 +291,15 @@ class DisplayList : public SkRefCnt {

uint32_t unique_id_;
SkRect bounds_;
sk_sp<const DlRTree> rtree_;

// Only used for drawPaint() and drawColor()
SkRect bounds_cull_;

bool can_apply_group_opacity_;

void ComputeBounds();
void ComputeRTree();
void Dispatch(Dispatcher& ctx, uint8_t* ptr, uint8_t* end) const;

friend class DisplayListBuilder;
Expand Down
97 changes: 97 additions & 0 deletions display_list/display_list_rtree.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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 "flutter/display_list/display_list_rtree.h"

#include "flutter/fml/logging.h"

namespace flutter {

DlRTree::DlRTree() : bbh_{SkRTreeFactory{}()}, all_ops_count_(0) {}

void DlRTree::insert(const SkRect boundsArray[],
const SkBBoxHierarchy::Metadata metadata[],
int N) {
FML_DCHECK(0 == all_ops_count_);
bbh_->insert(boundsArray, metadata, N);
for (int i = 0; i < N; i++) {
if (metadata == nullptr || metadata[i].isDraw) {
draw_op_[i] = boundsArray[i];
}
}
all_ops_count_ = N;
}

void DlRTree::insert(const SkRect boundsArray[], int N) {
insert(boundsArray, nullptr, N);
}

void DlRTree::search(const SkRect& query, std::vector<int>* results) const {
bbh_->search(query, results);
}

std::list<SkRect> DlRTree::searchNonOverlappingDrawnRects(
const SkRect& query) const {
// Get the indexes for the operations that intersect with the query rect.
std::vector<int> intermediary_results;
search(query, &intermediary_results);

std::list<SkRect> final_results;
for (int index : intermediary_results) {
auto draw_op = draw_op_.find(index);
// Ignore records that don't draw anything.
if (draw_op == draw_op_.end()) {
continue;
}
auto current_record_rect = draw_op->second;
auto replaced_existing_rect = false;
// // If the current record rect intersects with any of the rects in the
// // result list, then join them, and update the rect in final_results.
std::list<SkRect>::iterator curr_rect_itr = final_results.begin();
std::list<SkRect>::iterator first_intersecting_rect_itr;
while (!replaced_existing_rect && curr_rect_itr != final_results.end()) {
if (SkRect::Intersects(*curr_rect_itr, current_record_rect)) {
replaced_existing_rect = true;
first_intersecting_rect_itr = curr_rect_itr;
curr_rect_itr->join(current_record_rect);
}
curr_rect_itr++;
}
// It's possible that the result contains duplicated rects at this point.
// For example, consider a result list that contains rects A, B. If a
// new rect C is a superset of A and B, then A and B are the same set after
// the merge. As a result, find such cases and remove them from the result
// list.
while (replaced_existing_rect && curr_rect_itr != final_results.end()) {
if (SkRect::Intersects(*curr_rect_itr, *first_intersecting_rect_itr)) {
first_intersecting_rect_itr->join(*curr_rect_itr);
curr_rect_itr = final_results.erase(curr_rect_itr);
} else {
curr_rect_itr++;
}
}
if (!replaced_existing_rect) {
final_results.push_back(current_record_rect);
}
}
return final_results;
}

size_t DlRTree::bytesUsed() const {
return bbh_->bytesUsed();
}

DlRTreeFactory::DlRTreeFactory() {
r_tree_ = sk_make_sp<DlRTree>();
}

sk_sp<DlRTree> DlRTreeFactory::getInstance() {
return r_tree_;
}

sk_sp<SkBBoxHierarchy> DlRTreeFactory::operator()() const {
return r_tree_;
}

} // namespace flutter
68 changes: 68 additions & 0 deletions display_list/display_list_rtree.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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.

#ifndef FLUTTER_DISPLAY_LIST_RTREE_H_
#define FLUTTER_DISPLAY_LIST_RTREE_H_

#include <list>
#include <map>

#include "third_party/skia/include/core/SkBBHFactory.h"
#include "third_party/skia/include/core/SkRect.h"

namespace flutter {

/**
* An R-Tree implementation that forwards calls to an SkRTree. This is just
* a copy of flow/rtree.h/cc until we can figure out where these utilities
* can live with appropriate linking visibility.
*
* This implementation provides a searchNonOverlappingDrawnRects method,
* which can be used to query the rects for the operations recorded in the tree.
*/
class DlRTree : public SkBBoxHierarchy {
public:
DlRTree();

void insert(const SkRect[],
const SkBBoxHierarchy::Metadata[],
int N) override;
void insert(const SkRect[], int N) override;
void search(const SkRect& query, std::vector<int>* results) const override;
size_t bytesUsed() const override;

// Finds the rects in the tree that represent drawing operations and intersect
// with the query rect.
//
// When two rects intersect with each other, they are joined into a single
// rect which also intersects with the query rect. In other words, the bounds
// of each rect in the result list are mutually exclusive.
std::list<SkRect> searchNonOverlappingDrawnRects(const SkRect& query) const;

// Insertion count (not overall node count, which may be greater).
int getCount() const { return all_ops_count_; }

private:
// A map containing the draw operation rects keyed off the operation index
// in the insert call.
std::map<int, SkRect> draw_op_;
sk_sp<SkBBoxHierarchy> bbh_;
int all_ops_count_;
};

class DlRTreeFactory : public SkBBHFactory {
public:
DlRTreeFactory();

// Gets the instance to the R-tree.
sk_sp<DlRTree> getInstance();
sk_sp<SkBBoxHierarchy> operator()() const override;

private:
sk_sp<DlRTree> r_tree_;
};

} // namespace flutter

#endif // FLUTTER_DISPLAY_LIST_RTREE_H_
Loading