Commit message: None
CVE: CVE-2019-5828
CWE: CWE-416
Vulnerability description: Object lifecycle issue in ServiceWorker in Google Chrome prior to 75.0.3770.80 allowed a remote attacker to potentially perform out of bounds memory access via a crafted HTML page.

Project: Chrome

void PaymentHandlerWebFlowViewController::AbortPayment() {
  if (web_contents())
    web_contents()->Close();

  dialog()->ShowErrorMessage();
}

Project: Chrome

void PaymentHandlerWebFlowViewController::AddNewContents(
    content::WebContents* source,
    std::unique_ptr<content::WebContents> new_contents,
    WindowOpenDisposition disposition,
    const gfx::Rect& initial_rect,
    bool user_gesture,
    bool* was_blocked) {
  Browser* browser = chrome::FindLastActiveWithProfile(profile_);
  if (browser && user_gesture &&
      (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
       disposition == WindowOpenDisposition::NEW_POPUP)) {
    chrome::AddWebContents(browser, source, std::move(new_contents),
                           disposition, initial_rect);
  }
}

Project: Chrome

PaymentHandlerWebFlowViewController::CreateHeaderContentSeparatorView() {
  if (show_progress_bar_)
    return progress_bar_.get();
  return separator_.get();
}

Project: Chrome

PaymentHandlerWebFlowViewController::CreateHeaderContentView() {
  const GURL origin = web_contents()
                          ? web_contents()->GetVisibleURL().GetOrigin()
                          : target_.GetOrigin();
  std::unique_ptr<views::Background> background = GetHeaderBackground();
  return std::make_unique<ReadOnlyOriginView>(
      GetPaymentHandlerDialogTitle(web_contents(), https_prefix_), origin,
      state()->selected_instrument()->icon_image_skia(),
      background->get_color(), this);
}

Project: Chrome

void PaymentHandlerWebFlowViewController::DidAttachInterstitialPage() {
  log_.Error("Aborting payment handler window \"" + target_.spec() +
             "\" because of navigation to a page with invalid certificate "
             "state or malicious content.");
  AbortPayment();
}

Project: Chrome

void PaymentHandlerWebFlowViewController::DidStartNavigation(
    content::NavigationHandle* navigation_handle) {
  if (navigation_handle->IsSameDocument())
    return;

  UpdateHeaderView();
}

Project: Chrome

void PaymentHandlerWebFlowViewController::FillContentView(
    views::View* content_view) {
  content_view->SetLayoutManager(std::make_unique<views::FillLayout>());
  std::unique_ptr<views::WebView> web_view =
      std::make_unique<views::WebView>(profile_);
  Observe(web_view->GetWebContents());
  web_contents()->SetDelegate(this);
  web_view->LoadInitialURL(target_);

  dialog_manager_delegate_.SetWebContents(web_contents());
  web_modal::WebContentsModalDialogManager::CreateForWebContents(
      web_contents());
  web_modal::WebContentsModalDialogManager::FromWebContents(web_contents())
      ->SetDelegate(&dialog_manager_delegate_);

  web_view->SetPreferredSize(gfx::Size(0, kDialogHeight - 75));
  content_view->AddChildView(web_view.release());
}

Project: Chrome

PaymentHandlerWebFlowViewController::GetHeaderBackground() {
  auto default_header_background =
      PaymentRequestSheetController::GetHeaderBackground();
  if (web_contents()) {
    return views::CreateSolidBackground(color_utils::GetResultingPaintColor(
        web_contents()->GetThemeColor().value_or(SK_ColorTRANSPARENT),
        default_header_background->get_color()));
  }
  return default_header_background;
}

Project: Chrome

base::string16 GetPaymentHandlerDialogTitle(
    content::WebContents* web_contents,
    const base::string16& https_prefix) {
  return web_contents == nullptr ||
                 base::StartsWith(web_contents->GetTitle(), https_prefix,
                                  base::CompareCase::SENSITIVE)
             ? base::string16()
             : web_contents->GetTitle();
}

Project: Chrome

 base::string16 PaymentHandlerWebFlowViewController::GetSheetTitle() {
   return GetPaymentHandlerDialogTitle(web_contents(), https_prefix_);
}

Project: Chrome

void PaymentHandlerWebFlowViewController::LoadProgressChanged(
    content::WebContents* source,
    double progress) {
  DCHECK(source == web_contents());

  progress_bar_->SetValue(progress);

  if (progress == 1.0 && show_progress_bar_) {
    show_progress_bar_ = false;
    UpdateHeaderContentSeparatorView();
    return;
  }

  if (progress < 1.0 && !show_progress_bar_) {
    show_progress_bar_ = true;
    UpdateHeaderContentSeparatorView();
    return;
  }
}

Project: Chrome

PaymentHandlerWebFlowViewController::PaymentHandlerWebFlowViewController(
    PaymentRequestSpec* spec,
    PaymentRequestState* state,
    PaymentRequestDialogView* dialog,
    content::WebContents* payment_request_web_contents,
    Profile* profile,
    GURL target,
    PaymentHandlerOpenWindowCallback first_navigation_complete_callback)
    : PaymentRequestSheetController(spec, state, dialog),
      log_(payment_request_web_contents),
      profile_(profile),
      target_(target),
      show_progress_bar_(false),
      progress_bar_(
          std::make_unique<views::ProgressBar>(/*preferred_height=*/2)),
      separator_(std::make_unique<views::Separator>()),
      first_navigation_complete_callback_(
          std::move(first_navigation_complete_callback)),
      https_prefix_(base::UTF8ToUTF16(url::kHttpsScheme) +
                    base::UTF8ToUTF16(url::kStandardSchemeSeparator)),
      dialog_manager_delegate_(
          static_cast<web_modal::WebContentsModalDialogManagerDelegate*>(
              chrome::FindBrowserWithWebContents(payment_request_web_contents))
              ->GetWebContentsModalDialogHost()) {
  progress_bar_->set_owned_by_client();
  progress_bar_->set_foreground_color(gfx::kGoogleBlue500);
  progress_bar_->set_background_color(SK_ColorTRANSPARENT);
  separator_->set_owned_by_client();
  separator_->SetColor(separator_->GetNativeTheme()->GetSystemColor(
       ui::NativeTheme::kColorId_SeparatorColor));
 }

Project: Chrome

  ReadOnlyOriginView(const base::string16& page_title,
                     const GURL& origin,
                     gfx::ImageSkia icon_image_skia,
                     SkColor background_color,
                     views::ButtonListener* site_settings_listener) {
    std::unique_ptr<views::View> title_origin_container =
        std::make_unique<views::View>();
    SkColor foreground = color_utils::GetColorWithMaxContrast(background_color);
    views::GridLayout* title_origin_layout =
        title_origin_container->SetLayoutManager(
            std::make_unique<views::GridLayout>(title_origin_container.get()));

    views::ColumnSet* columns = title_origin_layout->AddColumnSet(0);
    columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1.0,
                       views::GridLayout::USE_PREF, 0, 0);

    bool title_is_valid = !page_title.empty();
    if (title_is_valid) {
      title_origin_layout->StartRow(views::GridLayout::kFixedSize, 0);
      std::unique_ptr<views::Label> title_label =
          std::make_unique<views::Label>(page_title,
                                         views::style::CONTEXT_DIALOG_TITLE);
      title_label->set_id(static_cast<int>(DialogViewID::SHEET_TITLE));
      title_label->SetFocusBehavior(
          views::View::FocusBehavior::ACCESSIBLE_ONLY);
      title_label->SetAutoColorReadabilityEnabled(false);
      title_label->SetEnabledColor(foreground);
      title_origin_layout->AddView(title_label.release());
    }

    title_origin_layout->StartRow(views::GridLayout::kFixedSize, 0);
    views::Label* origin_label =
        new views::Label(base::UTF8ToUTF16(origin.host()));
    origin_label->SetElideBehavior(gfx::ELIDE_HEAD);
    if (!title_is_valid) {
      origin_label->set_id(static_cast<int>(DialogViewID::SHEET_TITLE));

      constexpr int kVerticalPadding = 10;
      origin_label->SetBorder(
          views::CreateEmptyBorder(kVerticalPadding, 0, kVerticalPadding, 0));
    }
    origin_label->SetAutoColorReadabilityEnabled(false);
    origin_label->SetEnabledColor(foreground);

    origin_label->SetBackgroundColor(background_color);
    title_origin_layout->AddView(origin_label);

    views::GridLayout* top_level_layout =
        SetLayoutManager(std::make_unique<views::GridLayout>(this));
    views::ColumnSet* top_level_columns = top_level_layout->AddColumnSet(0);
    top_level_columns->AddColumn(views::GridLayout::LEADING,
                                 views::GridLayout::CENTER, 1.0,
                                 views::GridLayout::USE_PREF, 0, 0);
    const bool has_icon = icon_image_skia.width() && icon_image_skia.height();
    float adjusted_width = base::checked_cast<float>(icon_image_skia.width());
    if (has_icon) {
      adjusted_width =
          adjusted_width *
          IconSizeCalculator::kPaymentAppDeviceIndependentIdealIconHeight /
          icon_image_skia.height();
      top_level_columns->AddColumn(
          views::GridLayout::LEADING, views::GridLayout::FILL,
          views::GridLayout::kFixedSize, views::GridLayout::FIXED,
          adjusted_width,
          IconSizeCalculator::kPaymentAppDeviceIndependentIdealIconHeight);
      top_level_columns->AddPaddingColumn(views::GridLayout::kFixedSize, 8);
    }

    top_level_layout->StartRow(views::GridLayout::kFixedSize, 0);
    top_level_layout->AddView(title_origin_container.release());
    if (has_icon) {
      std::unique_ptr<views::ImageView> instrument_icon_view =
          CreateInstrumentIconView(/*icon_id=*/0, icon_image_skia,
                                   /*label=*/page_title);
      instrument_icon_view->SetImageSize(gfx::Size(
          adjusted_width,
          IconSizeCalculator::kPaymentAppDeviceIndependentIdealIconHeight));
      top_level_layout->AddView(instrument_icon_view.release());
    }
  }

Project: Chrome

bool PaymentHandlerWebFlowViewController::ShouldShowSecondaryButton() {
  return false;
}

Project: Chrome

void PaymentHandlerWebFlowViewController::TitleWasSet(
    content::NavigationEntry* entry) {
  UpdateHeaderView();
}

Project: Chrome

void PaymentHandlerWebFlowViewController::VisibleSecurityStateChanged(
    content::WebContents* source) {
  DCHECK(source == web_contents());
  if (!SslValidityChecker::IsSslCertificateValid(source) &&
      !net::IsLocalhost(source->GetLastCommittedURL())) {
    log_.Error("Aborting payment handler window \"" + target_.spec() +
               "\" because of insecure certificate state on \"" +
               source->GetVisibleURL().spec() + "\"");
    AbortPayment();
  }
}

Project: Chrome

PaymentHandlerWebFlowViewController::~PaymentHandlerWebFlowViewController() {}

Project: Chrome

void PaymentRequestState::AddAutofillContactProfile(
    bool selected,
    const autofill::AutofillProfile& profile) {
  profile_cache_.push_back(
      std::make_unique<autofill::AutofillProfile>(profile));
  autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
  contact_profiles_.push_back(new_cached_profile);

  if (selected)
    SetSelectedContactProfile(new_cached_profile);
}

Project: Chrome

void PaymentRequestState::AddAutofillPaymentInstrument(
    bool selected,
    const autofill::CreditCard& card) {
  std::string basic_card_network =
      autofill::data_util::GetPaymentRequestData(card.network())
          .basic_card_issuer_network;
  if (!spec_->supported_card_networks_set().count(basic_card_network) ||
      !spec_->supported_card_types_set().count(card.card_type())) {
    return;
  }

  constexpr size_t kTotalNumberOfCardTypes = 4U;

  bool matches_merchant_card_type_exactly =
      card.card_type() != autofill::CreditCard::CARD_TYPE_UNKNOWN ||
      spec_->supported_card_types_set().size() == kTotalNumberOfCardTypes;

  auto instrument = std::make_unique<AutofillPaymentInstrument>(
      basic_card_network, card, matches_merchant_card_type_exactly,
      shipping_profiles_, app_locale_, payment_request_delegate_);
  available_instruments_.push_back(std::move(instrument));

  if (selected)
    SetSelectedInstrument(available_instruments_.back().get());
}

Project: Chrome

void PaymentRequestState::AddAutofillShippingProfile(
    bool selected,
    const autofill::AutofillProfile& profile) {
  profile_cache_.push_back(
      std::make_unique<autofill::AutofillProfile>(profile));
  autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
  shipping_profiles_.push_back(new_cached_profile);

  if (selected)
    SetSelectedShippingProfile(new_cached_profile);
}

Project: Chrome

void PaymentRequestState::AddObserver(Observer* observer) {
  CHECK(observer);
  observers_.AddObserver(observer);
}

Project: Chrome

bool PaymentRequestState::ArePaymentDetailsSatisfied() {
  return selected_instrument_ != nullptr &&
         selected_instrument_->IsCompleteForPayment();
}

Project: Chrome

bool PaymentRequestState::ArePaymentOptionsSatisfied() {
  if (is_waiting_for_merchant_validation_)
    return false;

  if (!profile_comparator()->IsShippingComplete(selected_shipping_profile_))
    return false;

  if (spec_->request_shipping() && !spec_->selected_shipping_option())
    return false;

  return profile_comparator()->IsContactInfoComplete(selected_contact_profile_);
}

Project: Chrome

void PaymentRequestState::AreRequestedMethodsSupported(
    StatusCallback callback) {
  if (!get_all_instruments_finished_) {
    are_requested_methods_supported_callback_ = std::move(callback);
    return;
  }

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::BindOnce(&PaymentRequestState::CheckRequestedMethodsSupported,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

Project: Chrome

void PaymentRequestState::CanMakePayment(bool legacy_mode,
                                         StatusCallback callback) {
  if (!get_all_instruments_finished_) {
    DCHECK(!can_make_payment_callback_);
    can_make_payment_callback_ = std::move(callback);
    can_make_payment_legacy_mode_ = legacy_mode;
    return;
  }

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE, base::BindOnce(&PaymentRequestState::CheckCanMakePayment,
                                weak_ptr_factory_.GetWeakPtr(), legacy_mode,
                                std::move(callback)));
}

Project: Chrome

void PaymentRequestState::CheckCanMakePayment(bool legacy_mode,
                                              StatusCallback callback) {
  DCHECK(get_all_instruments_finished_);
  if (!legacy_mode) {
    std::move(callback).Run(are_requested_methods_supported_);
    return;
  }

  bool can_make_payment_value = false;
  for (const auto& instrument : available_instruments_) {
    if (instrument->IsValidForCanMakePayment()) {
      can_make_payment_value = true;
      break;
    }
  }
  std::move(callback).Run(can_make_payment_value);
}

Project: Chrome

void PaymentRequestState::CheckRequestedMethodsSupported(
    StatusCallback callback) {
  DCHECK(get_all_instruments_finished_);

  std::move(callback).Run(are_requested_methods_supported_);
}

Project: Chrome

void PaymentRequestState::FinishedGetAllSWPaymentInstruments() {
  PopulateProfileCache();
  SetDefaultProfileSelections();

  get_all_instruments_finished_ = true;
  are_requested_methods_supported_ |= !available_instruments_.empty();
  NotifyOnGetAllPaymentInstrumentsFinished();
  NotifyInitialized();

  if (can_make_payment_callback_) {
    CheckCanMakePayment(can_make_payment_legacy_mode_,
                        std::move(can_make_payment_callback_));
  }

  if (has_enrolled_instrument_callback_)
    CheckHasEnrolledInstrument(std::move(has_enrolled_instrument_callback_));

  if (are_requested_methods_supported_callback_)
    CheckRequestedMethodsSupported(
        std::move(are_requested_methods_supported_callback_));
}

Project: Chrome

void PaymentRequestState::GeneratePaymentResponse() {
  DCHECK(is_ready_to_pay());

  response_helper_ = std::make_unique<PaymentResponseHelper>(
      app_locale_, spec_, selected_instrument_, payment_request_delegate_,
       selected_shipping_profile_, selected_contact_profile_, this);
 }

Project: Chrome

autofill::AddressNormalizer* PaymentRequestState::GetAddressNormalizer() {
  return payment_request_delegate_->GetAddressNormalizer();
}

Project: Chrome

const std::string& PaymentRequestState::GetApplicationLocale() {
  return app_locale_;
}

Project: Chrome

std::string PaymentRequestState::GetAuthenticatedEmail() const {
  return payment_request_delegate_->GetAuthenticatedEmail();
}

Project: Chrome

autofill::PersonalDataManager* PaymentRequestState::GetPersonalDataManager() {
  return personal_data_manager_;
}

Project: Chrome

void PaymentRequestState::HasEnrolledInstrument(StatusCallback callback) {
  if (!get_all_instruments_finished_) {
    DCHECK(!has_enrolled_instrument_callback_);
    has_enrolled_instrument_callback_ = std::move(callback);
    return;
  }

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::BindOnce(&PaymentRequestState::CheckHasEnrolledInstrument,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

Project: Chrome

bool PaymentRequestState::IsInitialized() const {
  return get_all_instruments_finished_;
}

Project: Chrome

bool PaymentRequestState::IsPaymentAppInvoked() const {
  return !!response_helper_;
}

Project: Chrome

void PaymentRequestState::NotifyOnGetAllPaymentInstrumentsFinished() {
  for (auto& observer : observers_)
    observer.OnGetAllPaymentInstrumentsFinished();
}

Project: Chrome

void PaymentRequestState::NotifyOnSelectedInformationChanged() {
  for (auto& observer : observers_)
    observer.OnSelectedInformationChanged();
}

Project: Chrome

void PaymentRequestState::OnAddressNormalized(
    bool success,
    const autofill::AutofillProfile& normalized_profile) {
  delegate_->OnShippingAddressSelected(
      data_util::GetPaymentAddressFromAutofillProfile(normalized_profile,
                                                      app_locale_));
}

Project: Chrome

void PaymentRequestState::OnPaymentResponseReady(
    mojom::PaymentResponsePtr payment_response) {
  delegate_->OnPaymentResponseAvailable(std::move(payment_response));
}

Project: Chrome

void PaymentRequestState::OnSWPaymentInstrumentValidated(
    ServiceWorkerPaymentInstrument* instrument,
    bool result) {
  if (!result) {
    for (size_t i = 0; i < available_instruments_.size(); i++) {
      if (available_instruments_[i].get() == instrument) {
        available_instruments_.erase(available_instruments_.begin() + i);
        break;
      }
    }
  }

  if (--number_of_pending_sw_payment_instruments_ > 0)
    return;

  FinishedGetAllSWPaymentInstruments();
}

Project: Chrome

void PaymentRequestState::OnSpecUpdated() {
  autofill::AutofillProfile* selected_shipping_profile =
      selected_shipping_profile_;
  autofill::AutofillProfile* selected_contact_profile =
      selected_contact_profile_;

  if (spec_->current_update_reason() ==
      PaymentRequestSpec::UpdateReason::RETRY) {
    if (spec_->has_shipping_address_error() && selected_shipping_profile) {
      invalid_shipping_profile_ = selected_shipping_profile;
      selected_shipping_profile_ = nullptr;
    }

    if (spec_->has_payer_error() && selected_contact_profile) {
      invalid_contact_profile_ = selected_contact_profile;
      selected_contact_profile_ = nullptr;
    }
  }

  if (spec_->selected_shipping_option_error().empty()) {
    selected_shipping_option_error_profile_ = nullptr;
  } else {
    selected_shipping_option_error_profile_ = selected_shipping_profile;
    selected_shipping_profile_ = nullptr;
    if (spec_->has_shipping_address_error() && selected_shipping_profile) {
      invalid_shipping_profile_ = selected_shipping_profile;
    }
  }

  is_waiting_for_merchant_validation_ = false;
  UpdateIsReadyToPayAndNotifyObservers();
}

Project: Chrome

PaymentRequestState::PaymentRequestState(
    content::WebContents* web_contents,
    const GURL& top_level_origin,
    const GURL& frame_origin,
    PaymentRequestSpec* spec,
    Delegate* delegate,
    const std::string& app_locale,
    autofill::PersonalDataManager* personal_data_manager,
    ContentPaymentRequestDelegate* payment_request_delegate,
    JourneyLogger* journey_logger)
    : is_ready_to_pay_(false),
      get_all_instruments_finished_(true),
      is_waiting_for_merchant_validation_(false),
      app_locale_(app_locale),
      spec_(spec),
      delegate_(delegate),
      personal_data_manager_(personal_data_manager),
      journey_logger_(journey_logger),
      are_requested_methods_supported_(
          !spec_->supported_card_networks().empty()),
      selected_shipping_profile_(nullptr),
      selected_shipping_option_error_profile_(nullptr),
      selected_contact_profile_(nullptr),
      invalid_shipping_profile_(nullptr),
      invalid_contact_profile_(nullptr),
      selected_instrument_(nullptr),
      number_of_pending_sw_payment_instruments_(0),
      payment_request_delegate_(payment_request_delegate),
      profile_comparator_(app_locale, *spec),
      weak_ptr_factory_(this) {
  if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
    DCHECK(web_contents);
    get_all_instruments_finished_ = false;
    ServiceWorkerPaymentAppFactory::GetInstance()->GetAllPaymentApps(
        web_contents,
        payment_request_delegate_->GetPaymentManifestWebDataService(),
        spec_->method_data(),
        /*may_crawl_for_installable_payment_apps=*/
        !spec_->supports_basic_card(),
        base::BindOnce(&PaymentRequestState::GetAllPaymentAppsCallback,
                       weak_ptr_factory_.GetWeakPtr(), web_contents,
                       top_level_origin, frame_origin),
        base::BindOnce([]() {
          /* Nothing needs to be done after writing cache. This callback is used
           * only in tests. */
        }));
  } else {
    PopulateProfileCache();
    SetDefaultProfileSelections();
  }
  spec_->AddObserver(this);
}

Project: Chrome

void PaymentRequestState::PopulateProfileCache() {
  std::vector<autofill::AutofillProfile*> profiles =
      personal_data_manager_->GetProfilesToSuggest();

  std::vector<autofill::AutofillProfile*> raw_profiles_for_filtering;
  raw_profiles_for_filtering.reserve(profiles.size());

  for (size_t i = 0; i < profiles.size(); i++) {
    profile_cache_.push_back(
        std::make_unique<autofill::AutofillProfile>(*profiles[i]));
    raw_profiles_for_filtering.push_back(profile_cache_.back().get());
  }

  contact_profiles_ = profile_comparator()->FilterProfilesForContact(
      raw_profiles_for_filtering);
  shipping_profiles_ = profile_comparator()->FilterProfilesForShipping(
      raw_profiles_for_filtering);

  if (spec_->request_payer_name() || spec_->request_payer_phone() ||
      spec_->request_payer_email()) {
    bool has_complete_contact =
        contact_profiles_.empty()
            ? false
            : profile_comparator()->IsContactInfoComplete(contact_profiles_[0]);
    journey_logger_->SetNumberOfSuggestionsShown(
        JourneyLogger::Section::SECTION_CONTACT_INFO, contact_profiles_.size(),
        has_complete_contact);
  }
  if (spec_->request_shipping()) {
    bool has_complete_shipping =
        shipping_profiles_.empty()
            ? false
            : profile_comparator()->IsShippingComplete(shipping_profiles_[0]);
    journey_logger_->SetNumberOfSuggestionsShown(
        JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
        shipping_profiles_.size(), has_complete_shipping);
  }

  const std::vector<autofill::CreditCard*>& cards =
      personal_data_manager_->GetCreditCardsToSuggest(
          /*include_server_cards=*/base::FeatureList::IsEnabled(
              payments::features::kReturnGooglePayInBasicCard));
  for (autofill::CreditCard* card : cards)
    AddAutofillPaymentInstrument(/*selected=*/false, *card);
}

Project: Chrome

 void PaymentRequestState::RecordUseStats() {
   if (spec_->request_shipping()) {
     DCHECK(selected_shipping_profile_);
    personal_data_manager_->RecordUseOf(*selected_shipping_profile_);
  }

  if (spec_->request_payer_name() || spec_->request_payer_email() ||
      spec_->request_payer_phone()) {
    DCHECK(selected_contact_profile_);

    if (!spec_->request_shipping() || (selected_shipping_profile_->guid() !=
                                       selected_contact_profile_->guid())) {
      personal_data_manager_->RecordUseOf(*selected_contact_profile_);
    }
  }

  selected_instrument_->RecordUse();
}

Project: Chrome

void PaymentRequestState::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

Project: Chrome

void PaymentRequestState::SetDefaultProfileSelections() {
  if (!contact_profiles().empty() &&
      profile_comparator()->IsContactInfoComplete(contact_profiles_[0]))
    selected_contact_profile_ = contact_profiles()[0];

  const std::vector<std::unique_ptr<PaymentInstrument>>& instruments =
      available_instruments();
  auto first_complete_instrument =
      std::find_if(instruments.begin(), instruments.end(),
                   [](const std::unique_ptr<PaymentInstrument>& instrument) {
                     return instrument->IsCompleteForPayment() &&
                            instrument->IsExactlyMatchingMerchantRequest();
                   });
  selected_instrument_ = first_complete_instrument == instruments.end()
                             ? nullptr
                             : first_complete_instrument->get();

  SelectDefaultShippingAddressAndNotifyObservers();

  bool has_complete_instrument =
      available_instruments().empty()
          ? false
          : available_instruments()[0]->IsCompleteForPayment();

  journey_logger_->SetNumberOfSuggestionsShown(
      JourneyLogger::Section::SECTION_PAYMENT_METHOD,
      available_instruments().size(), has_complete_instrument);
}

Project: Chrome

void PaymentRequestState::SetSelectedContactProfile(
    autofill::AutofillProfile* profile) {
  selected_contact_profile_ = profile;

  invalid_contact_profile_ = nullptr;

  UpdateIsReadyToPayAndNotifyObservers();

  if (IsPaymentAppInvoked()) {
    delegate_->OnPayerInfoSelected(
        response_helper_->GeneratePayerDetail(profile));
  }
}

Project: Chrome

void PaymentRequestState::SetSelectedInstrument(PaymentInstrument* instrument) {
  selected_instrument_ = instrument;
  UpdateIsReadyToPayAndNotifyObservers();
}

Project: Chrome

void PaymentRequestState::SetSelectedShippingOption(
    const std::string& shipping_option_id) {
  spec_->StartWaitingForUpdateWith(
      PaymentRequestSpec::UpdateReason::SHIPPING_OPTION);
  delegate_->OnShippingOptionIdSelected(shipping_option_id);
}

Project: Chrome

void PaymentRequestState::SetSelectedShippingProfile(
    autofill::AutofillProfile* profile) {
  spec_->StartWaitingForUpdateWith(
      PaymentRequestSpec::UpdateReason::SHIPPING_ADDRESS);
  selected_shipping_profile_ = profile;

  invalid_shipping_profile_ = nullptr;

  is_waiting_for_merchant_validation_ = true;

  payment_request_delegate_->GetAddressNormalizer()->NormalizeAddressAsync(
      *selected_shipping_profile_, /*timeout_seconds=*/2,
      base::BindOnce(&PaymentRequestState::OnAddressNormalized,
                     weak_ptr_factory_.GetWeakPtr()));
}

Project: Chrome

void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
  is_ready_to_pay_ =
      ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
  NotifyOnSelectedInformationChanged();
}

Project: Chrome

PaymentRequestState::~PaymentRequestState() {}

Project: Chrome

ServiceWorkerPaymentInstrument::CreateCanMakePaymentEventData() {
  std::set<std::string> requested_url_methods;
  for (const auto& method : spec_->payment_method_identifiers_set()) {
    GURL url_method(method);
    if (url_method.is_valid()) {
      requested_url_methods.insert(method);
    }
  }
  std::set<std::string> supported_methods;
  supported_methods.insert(stored_payment_app_info_->enabled_methods.begin(),
                           stored_payment_app_info_->enabled_methods.end());
  std::set<std::string> supported_url_methods =
      base::STLSetIntersection<std::set<std::string>>(requested_url_methods,
                                                      supported_methods);
  if (supported_url_methods.empty())
    return nullptr;

  mojom::CanMakePaymentEventDataPtr event_data =
      mojom::CanMakePaymentEventData::New();

  event_data->top_origin = top_origin_;
  event_data->payment_request_origin = frame_origin_;

  DCHECK(spec_->details().modifiers);
  for (const auto& modifier : *spec_->details().modifiers) {
    if (base::ContainsKey(supported_url_methods,
                          modifier->method_data->supported_method)) {
      event_data->modifiers.emplace_back(modifier.Clone());
    }
  }

  for (const auto& data : spec_->method_data()) {
    if (base::ContainsKey(supported_url_methods, data->supported_method)) {
      event_data->method_data.push_back(data.Clone());
    }
  }

  return event_data;
}

Project: Chrome

base::string16 ServiceWorkerPaymentInstrument::GetLabel() const {
  return base::UTF8ToUTF16(needs_installation_
                               ? installable_web_app_info_->name
                               : stored_payment_app_info_->name);
}

Project: Chrome

base::string16 ServiceWorkerPaymentInstrument::GetMissingInfoLabel() const {
  NOTREACHED();
  return base::string16();
}

Project: Chrome

base::string16 ServiceWorkerPaymentInstrument::GetSublabel() const {
  if (needs_installation_) {
    DCHECK(GURL(installable_web_app_info_->sw_scope).is_valid());
    return base::UTF8ToUTF16(
        url::Origin::Create(GURL(installable_web_app_info_->sw_scope)).host());
  }
  return base::UTF8ToUTF16(
      url::Origin::Create(stored_payment_app_info_->scope).host());
}

Project: Chrome

void ServiceWorkerPaymentInstrument::InvokePaymentApp(Delegate* delegate) {
  delegate_ = delegate;

  if (needs_installation_) {
    content::PaymentAppProvider::GetInstance()->InstallAndInvokePaymentApp(
        web_contents_, CreatePaymentRequestEventData(),
        installable_web_app_info_->name,
        installable_web_app_info_->icon == nullptr
            ? SkBitmap()
            : *(installable_web_app_info_->icon),
        installable_web_app_info_->sw_js_url,
        installable_web_app_info_->sw_scope,
        installable_web_app_info_->sw_use_cache, installable_enabled_method_,
        base::BindOnce(&ServiceWorkerPaymentInstrument::OnPaymentAppInvoked,
                       weak_ptr_factory_.GetWeakPtr()));
  } else {
    content::PaymentAppProvider::GetInstance()->InvokePaymentApp(
        browser_context_, stored_payment_app_info_->registration_id,
        CreatePaymentRequestEventData(),
        base::BindOnce(&ServiceWorkerPaymentInstrument::OnPaymentAppInvoked,
                       weak_ptr_factory_.GetWeakPtr()));
  }

   payment_request_delegate_->ShowProcessingSpinner();
 }

Project: Chrome

bool ServiceWorkerPaymentInstrument::IsCompleteForPayment() const {
  return true;
}

Project: Chrome

bool ServiceWorkerPaymentInstrument::IsExactlyMatchingMerchantRequest() const {
  return true;
}

Project: Chrome

bool ServiceWorkerPaymentInstrument::IsValidForCanMakePayment() const {
  DCHECK(can_make_payment_result_);
  if (base::FeatureList::IsEnabled(
          ::features::kPaymentRequestHasEnrolledInstrument)) {
    return has_enrolled_instrument_result_;
  }
  return true;
}

Project: Chrome

bool ServiceWorkerPaymentInstrument::IsValidForModifier(
    const std::string& method,
    bool supported_networks_specified,
    const std::set<std::string>& supported_networks,
    bool supported_types_specified,
    const std::set<autofill::CreditCard::CardType>& supported_types) const {
  if (needs_installation_)
    return installable_enabled_method_ == method;

  if (!base::ContainsValue(stored_payment_app_info_->enabled_methods, method))
    return false;

  if (method != "basic-card")
    return true;

  if (!supported_networks_specified && !supported_types_specified)
    return true;

  if (stored_payment_app_info_->capabilities.empty())
    return false;

  uint32_t i = 0;
  for (; i < stored_payment_app_info_->capabilities.size(); i++) {
    if (supported_networks_specified) {
      std::set<std::string> app_supported_networks;
      for (const auto& network :
           stored_payment_app_info_->capabilities[i].supported_card_networks) {
        app_supported_networks.insert(GetBasicCardNetworkName(
            static_cast<mojom::BasicCardNetwork>(network)));
      }

      if (base::STLSetIntersection<std::set<std::string>>(
              app_supported_networks, supported_networks)
              .empty()) {
        continue;
      }
    }

    if (supported_types_specified) {
      std::set<autofill::CreditCard::CardType> app_supported_types;
      for (const auto& type :
           stored_payment_app_info_->capabilities[i].supported_card_types) {
        app_supported_types.insert(
            GetBasicCardType(static_cast<mojom::BasicCardType>(type)));
      }

      if (base::STLSetIntersection<std::set<autofill::CreditCard::CardType>>(
              app_supported_types, supported_types)
              .empty()) {
        continue;
      }
    }

    break;
  }

  return i < stored_payment_app_info_->capabilities.size();
}

Project: Chrome

void ServiceWorkerPaymentInstrument::OnCanMakePaymentEventResponded(
    ValidateCanMakePaymentCallback callback,
    bool result) {
  if (base::FeatureList::IsEnabled(
          ::features::kPaymentRequestHasEnrolledInstrument)) {
    can_make_payment_result_ = true;
    has_enrolled_instrument_result_ = result;
  } else {
    can_make_payment_result_ = result;
    has_enrolled_instrument_result_ = result;
  }
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), this, can_make_payment_result_));
}

Project: Chrome

void ServiceWorkerPaymentInstrument::RecordUse() {
  NOTIMPLEMENTED();
}

Project: Chrome

ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
    content::BrowserContext* browser_context,
    const GURL& top_origin,
    const GURL& frame_origin,
    const PaymentRequestSpec* spec,
    std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info,
    PaymentRequestDelegate* payment_request_delegate)
    : PaymentInstrument(0, PaymentInstrument::Type::SERVICE_WORKER_APP),
      browser_context_(browser_context),
      top_origin_(top_origin),
      frame_origin_(frame_origin),
      spec_(spec),
      stored_payment_app_info_(std::move(stored_payment_app_info)),
      delegate_(nullptr),
      payment_request_delegate_(payment_request_delegate),
      can_make_payment_result_(false),
      has_enrolled_instrument_result_(false),
      needs_installation_(false),
      weak_ptr_factory_(this) {
  DCHECK(browser_context_);
  DCHECK(top_origin_.is_valid());
  DCHECK(frame_origin_.is_valid());
  DCHECK(spec_);

  if (stored_payment_app_info_->icon) {
    icon_image_ =
        gfx::ImageSkia::CreateFrom1xBitmap(*(stored_payment_app_info_->icon))
            .DeepCopy();
  } else {
    icon_image_ = gfx::ImageSkia::CreateFrom1xBitmap(SkBitmap()).DeepCopy();
  }
}

Project: Chrome

ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
    content::WebContents* web_contents,
    const GURL& top_origin,
    const GURL& frame_origin,
    const PaymentRequestSpec* spec,
    std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info,
    const std::string& enabled_method,
    PaymentRequestDelegate* payment_request_delegate)
    : PaymentInstrument(0, PaymentInstrument::Type::SERVICE_WORKER_APP),
      top_origin_(top_origin),
      frame_origin_(frame_origin),
      spec_(spec),
      delegate_(nullptr),
      payment_request_delegate_(payment_request_delegate),
      can_make_payment_result_(false),
      has_enrolled_instrument_result_(false),
      needs_installation_(true),
      web_contents_(web_contents),
      installable_web_app_info_(std::move(installable_payment_app_info)),
      installable_enabled_method_(enabled_method),
      weak_ptr_factory_(this) {
  DCHECK(web_contents_);
  DCHECK(top_origin_.is_valid());
  DCHECK(frame_origin_.is_valid());
  DCHECK(spec_);

  if (installable_web_app_info_->icon) {
    icon_image_ =
        gfx::ImageSkia::CreateFrom1xBitmap(*(installable_web_app_info_->icon))
            .DeepCopy();
  } else {
    icon_image_ = gfx::ImageSkia::CreateFrom1xBitmap(SkBitmap()).DeepCopy();
  }
}

Project: Chrome

void ServiceWorkerPaymentInstrument::ValidateCanMakePayment(
    ValidateCanMakePaymentCallback callback) {
  if (needs_installation_) {
    OnCanMakePaymentEventSkipped(std::move(callback));
    return;
  }

  if (payment_request_delegate_->IsIncognito()) {
    OnCanMakePaymentEventSkipped(std::move(callback));
    return;
  }

  if (!stored_payment_app_info_->has_explicitly_verified_methods) {
    OnCanMakePaymentEventSkipped(std::move(callback));
    return;
  }

  mojom::CanMakePaymentEventDataPtr event_data =
      CreateCanMakePaymentEventData();
  if (event_data.is_null()) {
    OnCanMakePaymentEventSkipped(std::move(callback));
    return;
  }

  content::PaymentAppProvider::GetInstance()->CanMakePayment(
      browser_context_, stored_payment_app_info_->registration_id,
      std::move(event_data),
      base::BindOnce(
          &ServiceWorkerPaymentInstrument::OnCanMakePaymentEventResponded,
          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

Project: Chrome

gfx::ImageSkia ServiceWorkerPaymentInstrument::icon_image_skia() const {
  return icon_image_;
}

Project: Chrome

ServiceWorkerPaymentInstrument::~ServiceWorkerPaymentInstrument() {
  if (delegate_ && !needs_installation_) {
    content::PaymentAppProvider::GetInstance()->AbortPayment(
        browser_context_, stored_payment_app_info_->registration_id,
        base::DoNothing());
  }
}