blob: 075d510b8d0b6e53b65c99fbf305a4599cc74bc9 [file] [log] [blame]
// Copyright 2018 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 "components/autofill_assistant/browser/element_area.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/web_controller.h"
namespace autofill_assistant {
namespace {
// Waiting period between two checks.
static constexpr base::TimeDelta kCheckDelay =
base::TimeDelta::FromMilliseconds(100);
} // namespace
ElementArea::ElementArea(WebController* web_controller)
: web_controller_(web_controller),
scheduled_update_(false),
weak_ptr_factory_(this) {
DCHECK(web_controller_);
}
ElementArea::~ElementArea() = default;
void ElementArea::SetElements(const std::vector<Selector>& elements) {
element_positions_.clear();
for (const auto& selector : elements) {
element_positions_.emplace_back();
element_positions_.back().selector = selector;
}
ReportUpdate();
if (element_positions_.empty())
return;
if (!scheduled_update_) {
// Check once and schedule regular updates.
scheduled_update_ = true;
KeepUpdatingPositions();
} else {
// If regular updates are already scheduled, just force a check of position
// right away and keep running the scheduled updates.
UpdatePositions();
}
}
void ElementArea::UpdatePositions() {
if (element_positions_.empty())
return;
for (auto& position : element_positions_) {
web_controller_->GetElementPosition(
position.selector,
base::BindOnce(&ElementArea::OnGetElementPosition,
weak_ptr_factory_.GetWeakPtr(), position.selector));
}
}
bool ElementArea::IsEmpty() const {
for (const auto& position : element_positions_) {
if (!position.rect.empty()) {
return false;
}
}
return true;
}
ElementArea::ElementPosition::ElementPosition() = default;
ElementArea::ElementPosition::ElementPosition(const ElementPosition& orig) =
default;
ElementArea::ElementPosition::~ElementPosition() = default;
void ElementArea::KeepUpdatingPositions() {
if (element_positions_.empty()) {
scheduled_update_ = false;
return;
}
UpdatePositions();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ElementArea::KeepUpdatingPositions,
weak_ptr_factory_.GetWeakPtr()),
kCheckDelay);
}
void ElementArea::OnGetElementPosition(const Selector& selector,
bool found,
const RectF& rect) {
for (auto& position : element_positions_) {
if (position.selector == selector) {
// found == false, has all coordinates set to 0.0, which clears the area.
position.rect = rect;
ReportUpdate();
return;
}
}
// If the set of elements has changed, the given selector will not be found in
// element_positions_. This is fine.
}
bool ElementArea::Contains(float x, float y) const {
for (const auto& position : element_positions_) {
if (position.rect.Contains(x, y)) {
return true;
}
}
return false;
}
void ElementArea::ReportUpdate() {
if (!on_update_)
return;
std::vector<RectF> areas;
for (auto& position : element_positions_) {
if (!position.rect.empty()) {
areas.emplace_back(position.rect);
}
}
on_update_.Run(!element_positions_.empty(), areas);
}
} // namespace autofill_assistant