chromium/components/autofill/ios/browser/autofill_driver_ios_factory.mm

// 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 "components/autofill/ios/browser/autofill_driver_ios.h"
#import "components/autofill/ios/browser/autofill_java_script_feature.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(
    web::WebState* web_state,
    AutofillClient* client,
    id<AutofillDriverIOSBridge> bridge,
    const std::string& app_locale)
    : app_locale_(app_locale),
      client_(client),
      web_state_(web_state),
      bridge_(bridge) {
  web_state_->AddObserver(this);
  GetWebFramesManager().AddObserver(this);
}

AutofillDriverIOSFactory::~AutofillDriverIOSFactory() {
  TearDown();
}

void AutofillDriverIOSFactory::TearDown() {
  if (web_state_) {
    for (const auto& [frame_id, driver] : driver_map_) {
      if (driver) {
        SetLifecycleStateAndNotifyObservers(*driver,
                                            LifecycleState::kPendingDeletion);
      }
    }
    driver_map_.clear();
    for (auto& observer : AutofillDriverFactory::observers()) {
      observer.OnAutofillDriverFactoryDestroyed(*this);
    }
    GetWebFramesManager().RemoveObserver(this);
    web_state_->RemoveObserver(this);
    web_state_ = nullptr;
  }
}

void AutofillDriverIOSFactory::WebStateDestroyed(web::WebState* web_state) {
  TearDown();
}

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.
  base::EraseIf(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_) {
    // WebStateDestroyed() has already been fired.
    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_, app_locale_,
        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);
  }
  // `driver` may be null if WebFrameBecameUnavailable() has been called for its
  // `web_frame` already.
  return driver.get();
}

WEB_STATE_USER_DATA_KEY_IMPL(AutofillDriverIOSFactory)

}  //  namespace autofill