// Copyright 2016 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/spiral_iterator.h" #include namespace cc { SpiralIterator::SpiralIterator() : around_index_rect_(-1, -1, -1, -1), consider_index_rect_(-1, -1, -1, -1), ignore_index_rect_(-1, -1, -1, -1), index_x_(-1), index_y_(-1) {} SpiralIterator::SpiralIterator(const IndexRect& around_index_rect, const IndexRect& consider_index_rect, const IndexRect& ignore_index_rect) : around_index_rect_(around_index_rect), consider_index_rect_(consider_index_rect), ignore_index_rect_(ignore_index_rect), index_x_(-1), index_y_(-1), direction_(RIGHT), delta_x_(1), delta_y_(0), current_step_(0), horizontal_step_count_(0), vertical_step_count_(0) { vertical_step_count_ = around_index_rect_.num_indices_y(); horizontal_step_count_ = around_index_rect_.num_indices_x(); current_step_ = horizontal_step_count_ - 1; index_x_ = around_index_rect_.right(); index_y_ = around_index_rect_.bottom(); // The current index is the bottom right of the around rect, which is also // ignored. So we have to advance. ++(*this); } SpiralIterator::operator bool() const { return index_x_ != -1 && index_y_ != -1; } SpiralIterator& SpiralIterator::operator++() { int cannot_hit_consider_count = 0; while (cannot_hit_consider_count < 4) { if (needs_direction_switch()) switch_direction(); index_x_ += delta_x_; index_y_ += delta_y_; ++current_step_; if (consider_index_rect_.Contains(index_x_, index_y_)) { cannot_hit_consider_count = 0; if (!ignore_index_rect_.Contains(index_x_, index_y_)) break; // Steps needed to reach the very edge of the ignore rect, while remaining // inside (so that the continue would take us outside). int steps_to_edge = 0; switch (direction_) { case UP: steps_to_edge = index_y_ - ignore_index_rect_.top(); break; case LEFT: steps_to_edge = index_x_ - ignore_index_rect_.left(); break; case DOWN: steps_to_edge = ignore_index_rect_.bottom() - index_y_; break; case RIGHT: steps_to_edge = ignore_index_rect_.right() - index_x_; break; } // We need to switch directions in |max_steps|. int max_steps = current_step_count() - current_step_; int steps_to_take = std::min(steps_to_edge, max_steps); DCHECK_GE(steps_to_take, 0); index_x_ += steps_to_take * delta_x_; index_y_ += steps_to_take * delta_y_; current_step_ += steps_to_take; } else { int max_steps = current_step_count() - current_step_; int steps_to_take = max_steps; bool can_hit_consider_rect = false; switch (direction_) { case UP: if (consider_index_rect_.valid_column(index_x_) && consider_index_rect_.bottom() < index_y_) steps_to_take = index_y_ - consider_index_rect_.bottom() - 1; can_hit_consider_rect |= consider_index_rect_.right() >= index_x_; break; case LEFT: if (consider_index_rect_.valid_row(index_y_) && consider_index_rect_.right() < index_x_) steps_to_take = index_x_ - consider_index_rect_.right() - 1; can_hit_consider_rect |= consider_index_rect_.top() <= index_y_; break; case DOWN: if (consider_index_rect_.valid_column(index_x_) && consider_index_rect_.top() > index_y_) steps_to_take = consider_index_rect_.top() - index_y_ - 1; can_hit_consider_rect |= consider_index_rect_.left() <= index_x_; break; case RIGHT: if (consider_index_rect_.valid_row(index_y_) && consider_index_rect_.left() > index_x_) steps_to_take = consider_index_rect_.left() - index_x_ - 1; can_hit_consider_rect |= consider_index_rect_.bottom() >= index_y_; break; } steps_to_take = std::min(steps_to_take, max_steps); DCHECK_GE(steps_to_take, 0); index_x_ += steps_to_take * delta_x_; index_y_ += steps_to_take * delta_y_; current_step_ += steps_to_take; if (can_hit_consider_rect) cannot_hit_consider_count = 0; else ++cannot_hit_consider_count; } } if (cannot_hit_consider_count >= 4) { index_x_ = -1; index_y_ = -1; } return *this; } bool SpiralIterator::needs_direction_switch() const { return current_step_ >= current_step_count(); } void SpiralIterator::switch_direction() { // Note that delta_x_ and delta_y_ always remain between -1 and 1. int new_delta_x = delta_y_; delta_y_ = -delta_x_; delta_x_ = new_delta_x; current_step_ = 0; direction_ = static_cast((direction_ + 1) % 4); if (direction_ == RIGHT || direction_ == LEFT) { ++vertical_step_count_; ++horizontal_step_count_; } } } // namespace cc