blob: 0b389f427fe8e74b65242d29db1e2dbca0f009f7 [file] [log] [blame]
// 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 <stddef.h>
#include <stdint.h>
#include <cmath>
#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<Branch>* 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<int>(branches->size() / MAX_CHILDREN);
int remainder = static_cast<int>(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<int>(std::ceil(std::sqrt(num_branches)));
int num_tiles = static_cast<int>(
std::ceil(num_branches / static_cast<float>(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<size_t>* 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<size_t>* 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