blob: 247a78f57c3781d3f571181790ffd295f1e603ce [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "components/autofill/ios/browser/autofill_driver_ios_factory.h"
#import <memory>
#import <ranges>
#import "base/check.h"
#import "base/check_deref.h"
#import "base/metrics/histogram_functions.h"
#import "components/autofill/ios/browser/autofill_client_ios.h"
#import "components/autofill/ios/browser/autofill_driver_ios.h"
#import "components/autofill/ios/browser/autofill_java_script_feature.h"
#import "ios/web/public/web_state.h"
namespace autofill {
void AutofillDriverIOSFactory::Observer::OnAutofillDriverFactoryDestroyed(
AutofillDriverFactory& factory) {
OnAutofillDriverIOSFactoryDestroyed(
static_cast<AutofillDriverIOSFactory&>(factory));
}
void AutofillDriverIOSFactory::Observer::OnAutofillDriverCreated(
AutofillDriverFactory& factory,
AutofillDriver& driver) {
OnAutofillDriverIOSCreated(static_cast<AutofillDriverIOSFactory&>(factory),
static_cast<AutofillDriverIOS&>(driver));
}
void AutofillDriverIOSFactory::Observer::OnAutofillDriverStateChanged(
AutofillDriverFactory& factory,
AutofillDriver& driver,
LifecycleState old_state,
LifecycleState new_state) {
OnAutofillDriverIOSStateChanged(
static_cast<AutofillDriverIOSFactory&>(factory),
static_cast<AutofillDriverIOS&>(driver), old_state, new_state);
}
AutofillDriverIOSFactory::AutofillDriverIOSFactory(
AutofillClientIOS* client,
id<AutofillDriverIOSBridge> bridge)
: client_(CHECK_DEREF(client)), bridge_(bridge) {
web_state()->AddObserver(this);
GetWebFramesManager().AddObserver(this);
}
AutofillDriverIOSFactory::~AutofillDriverIOSFactory() {
CHECK(web_state_destroyed_);
for (auto& observer : AutofillDriverFactory::observers()) {
observer.OnAutofillDriverFactoryDestroyed(*this);
}
if (web_state() && web_state()->IsRealized()) {
// Only count the max number of drivers for realized web states because
// unrealized web states do not have loaded frames which can heavily skew
// the data towards 0 frames.
base::UmaHistogramCounts1000("Autofill.NumberOfDriversPerFactory",
max_drivers_);
}
}
// The AutofillClientIOS contract guarantees that WebStateDestroyed() is called
// and that `client_` is still alive.
void AutofillDriverIOSFactory::WebStateDestroyed(
web::WebState* destroyed_web_state) {
CHECK(web_state());
if (web_state()) {
for (const auto& [frame_id, driver] : driver_map_) {
if (driver) {
SetLifecycleStateAndNotifyObservers(*driver,
LifecycleState::kPendingDeletion);
}
}
driver_map_.clear();
GetWebFramesManager().RemoveObserver(this);
web_state()->RemoveObserver(this);
}
web_state_destroyed_ = true;
}
web::WebState* AutofillDriverIOSFactory::web_state() {
return client_->web_state();
}
web::WebFramesManager& AutofillDriverIOSFactory::GetWebFramesManager() {
CHECK(web_state());
auto* web_frames_manager =
AutofillJavaScriptFeature::GetInstance()->GetWebFramesManager(
web_state());
CHECK(web_frames_manager) << "Tests must set the WebFramesManager before "
"instantiating AutofillDriverIOSFactory";
return *web_frames_manager;
}
void AutofillDriverIOSFactory::WebFrameBecameAvailable(
web::WebFramesManager* web_frames_manager,
web::WebFrame* web_frame) {
// Remove the null driver for `web_frame` to unblock DriverForFrame() from
// creating a driver for the available frame.
// Also clean up the null drivers for deleted WebFrames.
std::erase_if(driver_map_, [&](const auto& p) {
const std::string& frame_id = p.first;
const AutofillDriverIOS* driver = p.second.get();
return driver == nullptr &&
(web_frames_manager->GetFrameWithId(frame_id) == nullptr ||
frame_id == web_frame->GetFrameId());
});
}
void AutofillDriverIOSFactory::WebFrameBecameUnavailable(
web::WebFramesManager* web_frames_manager,
const std::string& frame_id) {
// Keep a null driver for `frame_id` in the map to block DriverForFrame() from
// creating a driver for the unavailable frame.
std::unique_ptr<AutofillDriverIOS>& driver = driver_map_[frame_id];
if (driver) {
SetLifecycleStateAndNotifyObservers(*driver,
LifecycleState::kPendingDeletion);
}
driver = nullptr;
DCHECK_EQ(&driver_map_[frame_id], &driver);
}
AutofillDriverIOS* AutofillDriverIOSFactory::DriverForFrame(
web::WebFrame* web_frame) {
if (web_state_destroyed_) {
return nullptr;
}
std::string web_frame_id = web_frame->GetFrameId();
auto [iter, insertion_happened] = driver_map_.emplace(web_frame_id, nullptr);
std::unique_ptr<AutofillDriverIOS>& driver = iter->second;
if (insertion_happened) {
driver = std::make_unique<AutofillDriverIOS>(
web_state(), web_frame, &*client_, &router_, bridge_,
base::PassKey<AutofillDriverIOSFactory>());
for (auto& observer : observers()) {
observer.OnAutofillDriverCreated(*this, *driver);
}
DCHECK(driver->IsActive());
SetLifecycleStateAndNotifyObservers(*driver, LifecycleState::kActive);
DCHECK_EQ(&driver_map_[web_frame_id], &driver);
}
max_drivers_ = std::max(max_drivers_, driver_map_.size());
// `driver` may be null if WebFrameBecameUnavailable() has been called for its
// `web_frame` already.
return driver.get();
}
std::vector<AutofillDriver*> AutofillDriverIOSFactory::GetExistingDrivers() {
std::vector<AutofillDriver*> drivers;
drivers.reserve(driver_map_.size());
for (const auto& [frame_id, driver] : driver_map_) {
if (driver) {
drivers.push_back(driver.get());
}
}
return drivers;
}
} // namespace autofill