// Copyright (c) 2015 The Chromium 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 "cc/base/rtree.h" #include #include #include #include "base/logging.h" namespace cc { RTree::RTree() : num_data_elements_(0u) {} RTree::~RTree() {} RTree::Node* RTree::AllocateNodeAtLevel(int level) { nodes_.push_back(Node()); Node& node = nodes_.back(); node.num_children = 0; node.level = level; return &node; } RTree::Branch RTree::BuildRecursive(std::vector* branches, int level) { // Only one branch. It will be the root. if (branches->size() == 1) return (*branches)[0]; // TODO(vmpstr): Investigate if branches should be sorted in y. // The comment from Skia reads: // We might sort our branches here, but we expect Blink gives us a reasonable // x,y order. Skipping a call to sort (in Y) here resulted in a 17% win for // recording with negligible difference in playback speed. int num_branches = static_cast(branches->size() / MAX_CHILDREN); int remainder = static_cast(branches->size() % MAX_CHILDREN); if (remainder > 0) { ++num_branches; // If the remainder isn't enough to fill a node, we'll add fewer nodes to // other branches. if (remainder >= MIN_CHILDREN) remainder = 0; else remainder = MIN_CHILDREN - remainder; } int num_strips = static_cast(std::ceil(std::sqrt(num_branches))); int num_tiles = static_cast( std::ceil(num_branches / static_cast(num_strips))); size_t current_branch = 0; size_t new_branch_index = 0; for (int i = 0; i < num_strips; ++i) { // Might be worth sorting by X here too. for (int j = 0; j < num_tiles && current_branch < branches->size(); ++j) { int increment_by = MAX_CHILDREN; if (remainder != 0) { // if need be, omit some nodes to make up for remainder if (remainder <= MAX_CHILDREN - MIN_CHILDREN) { increment_by -= remainder; remainder = 0; } else { increment_by = MIN_CHILDREN; remainder -= MAX_CHILDREN - MIN_CHILDREN; } } Node* node = AllocateNodeAtLevel(level); node->num_children = 1; node->children[0] = (*branches)[current_branch]; Branch branch; branch.bounds = (*branches)[current_branch].bounds; branch.subtree = node; ++current_branch; for (int k = 1; k < increment_by && current_branch < branches->size(); ++k) { branch.bounds.Union((*branches)[current_branch].bounds); node->children[k] = (*branches)[current_branch]; ++node->num_children; ++current_branch; } DCHECK_LT(new_branch_index, current_branch); (*branches)[new_branch_index] = branch; ++new_branch_index; } } branches->resize(new_branch_index); return BuildRecursive(branches, level + 1); } void RTree::Search(const gfx::Rect& query, std::vector* results) const { if (num_data_elements_ > 0 && query.Intersects(root_.bounds)) SearchRecursive(root_.subtree, query, results); } void RTree::SearchRecursive(Node* node, const gfx::Rect& query, std::vector* results) const { for (uint16_t i = 0; i < node->num_children; ++i) { if (query.Intersects(node->children[i].bounds)) { if (node->level == 0) results->push_back(node->children[i].index); else SearchRecursive(node->children[i].subtree, query, results); } } } gfx::Rect RTree::GetBounds() const { return root_.bounds; } } // namespace cc