Commit message: None
CVE: CVE-2016-1690
Vulnerability description: The Autofill implementation in Google Chrome before 51.0.2704.63 mishandles the interaction between field updates and JavaScript code that triggers a frame deletion, which allows remote attackers to cause a denial of service (use-after-free) or possibly have unspecified other impact via a crafted web site, a different vulnerability than CVE-2016-1701.

Project: Chrome

void PasswordAutofillAgent::AJAXSucceeded() {
  OnSamePageNavigationCompleted();
}

Project: Chrome

bool CanShowSuggestion(const PasswordFormFillData& fill_data,
                       const base::string16& current_username,
                       bool show_all) {
  base::string16 current_username_lower = base::i18n::ToLower(current_username);
  for (const auto& usernames : fill_data.other_possible_usernames) {
    for (size_t i = 0; i < usernames.second.size(); ++i) {
      if (show_all ||
          base::StartsWith(
              base::i18n::ToLower(base::string16(usernames.second[i])),
              current_username_lower, base::CompareCase::SENSITIVE)) {
        return true;
      }
    }
  }

  if (show_all ||
      base::StartsWith(base::i18n::ToLower(fill_data.username_field.value),
                       current_username_lower, base::CompareCase::SENSITIVE)) {
    return true;
  }

  for (const auto& login : fill_data.additional_logins) {
    if (show_all ||
        base::StartsWith(base::i18n::ToLower(login.first),
                         current_username_lower,
                         base::CompareCase::SENSITIVE)) {
      return true;
    }
  }

  return false;
}

Project: Chrome

void PasswordAutofillAgent::ClearPreview(
    blink::WebInputElement* username,
    blink::WebInputElement* password) {
  if (!username->isNull() && !username->suggestedValue().isEmpty()) {
    username->setSuggestedValue(blink::WebString());
    username->setAutofilled(was_username_autofilled_);
    username->setSelectionRange(username_query_prefix_.length(),
                                username->value().length());
  }
  if (!password->suggestedValue().isEmpty()) {
      password->setSuggestedValue(blink::WebString());
      password->setAutofilled(was_password_autofilled_);
  }
}

Project: Chrome

bool ContainsNonNullEntryForNonNullKey(
    const std::map<Key*, linked_ptr<Value>>& map,
    Key* key) {
  if (!key)
    return false;
  auto it = map.find(key);
  return it != map.end() && it->second.get();
}

Project: Chrome

bool PasswordAutofillAgent::DidClearAutofillSelection(
    const blink::WebFormControlElement& control_element) {
  const blink::WebInputElement* element = toWebInputElement(&control_element);
  if (!element)
    return false;

  blink::WebInputElement username_element;
  blink::WebInputElement password_element;
  PasswordInfo* password_info;

  if (!FindPasswordInfoForElement(*element, &username_element,
                                  &password_element, &password_info))
    return false;

  ClearPreview(&username_element, &password_element);
  return true;
}

Project: Chrome

void PasswordAutofillAgent::DidStartProvisionalLoad() {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_) {
    logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
    logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD);
  }

  const blink::WebLocalFrame* navigated_frame = render_frame()->GetWebFrame();
  if (navigated_frame->parent()) {
    if (logger)
      logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME);
    return;
  }

  content::DocumentState* document_state =
      content::DocumentState::FromDataSource(
          navigated_frame->provisionalDataSource());
  content::NavigationState* navigation_state =
      document_state->navigation_state();
  ui::PageTransition type = navigation_state->GetTransitionType();
  if (ui::PageTransitionIsWebTriggerable(type) &&
      ui::PageTransitionIsNewNavigation(type) &&
      !blink::WebUserGestureIndicator::isProcessingUserGesture()) {
    if (provisionally_saved_form_) {
      if (logger) {
        logger->LogPasswordForm(
            Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
            *provisionally_saved_form_);
      }
      Send(new AutofillHostMsg_PasswordFormSubmitted(
          routing_id(), *provisionally_saved_form_));
      provisionally_saved_form_.reset();
    } else {
      ScopedVector<PasswordForm> possible_submitted_forms;
      blink::WebVector<blink::WebFormElement> forms;
      render_frame()->GetWebFrame()->document().forms(forms);

      bool password_forms_found = false;
      for (size_t i = 0; i < forms.size(); ++i) {
        blink::WebFormElement form_element = forms[i];
        if (logger) {
          LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE,
                      form_element);
        }
        possible_submitted_forms.push_back(CreatePasswordFormFromWebForm(
            form_element, &nonscript_modified_values_, &form_predictions_));
      }

      possible_submitted_forms.push_back(
          CreatePasswordFormFromUnownedInputElements(
              *render_frame()->GetWebFrame(),
              &nonscript_modified_values_,
              &form_predictions_));

      for (const PasswordForm* password_form : possible_submitted_forms) {
        if (password_form && !password_form->username_value.empty() &&
            FormContainsNonDefaultPasswordValue(*password_form)) {
          password_forms_found = true;
          if (logger) {
            logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE,
                                    *password_form);
          }
          Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
                                                         *password_form));
          break;
        }
      }

      if (!password_forms_found && logger)
        logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE);
    }
  }

  gatekeeper_.Reset();
}

Project: Chrome

bool DoUsernamesMatch(const base::string16& username1,
                      const base::string16& username2,
                      bool exact_match) {
  if (exact_match)
    return username1 == username2;
  return FieldIsSuggestionSubstringStartingOnTokenBoundary(username1, username2,
                                                           true);
}

Project: Chrome

base::string16 FieldName(const FormFieldData& field,
                         bool ambiguous_or_empty_names) {
  return ambiguous_or_empty_names
             ? IsPasswordField(field) ? base::ASCIIToUTF16(kDummyPasswordField)
                                      : base::ASCIIToUTF16(kDummyUsernameField)
             : field.name;
}

Project: Chrome

bool FillDataContainsFillableUsername(const PasswordFormFillData& fill_data) {
  return !fill_data.username_field.name.empty() &&
         (!fill_data.additional_logins.empty() ||
          !fill_data.username_field.value.empty());
}

Project: Chrome

bool FillFormOnPasswordReceived(
    const PasswordFormFillData& fill_data,
    blink::WebInputElement username_element,
    blink::WebInputElement password_element,
    std::map<const blink::WebInputElement, blink::WebString>*
        nonscript_modified_values,
    base::Callback<void(blink::WebInputElement*)> registration_callback,
    RendererSavePasswordProgressLogger* logger) {
  blink::WebFrame* cur_frame = password_element.document().frame();
  blink::WebString bottom_frame_origin =
      cur_frame->getSecurityOrigin().toString();

  DCHECK(cur_frame);

  while (cur_frame->parent()) {
    cur_frame = cur_frame->parent();
    if (!bottom_frame_origin.equals(cur_frame->getSecurityOrigin().toString()))
      return false;
  }

  if (!IsElementAutocompletable(password_element))
    return false;

  bool form_contains_fillable_username_field =
      FillDataContainsFillableUsername(fill_data);
  bool ambiguous_or_empty_names =
      DoesFormContainAmbiguousOrEmptyNames(fill_data);
  base::string16 username_field_name;
  if (form_contains_fillable_username_field)
    username_field_name =
        FieldName(fill_data.username_field, ambiguous_or_empty_names);

  bool form_has_fillable_username = !username_field_name.empty() &&
                                    IsElementAutocompletable(username_element);

  if (ShouldFillOnAccountSelect()) {
    if (!ShouldHighlightFields()) {
      return false;
    }

    if (form_has_fillable_username) {
      username_element.setAutofilled(true);
    } else if (username_element.isNull() ||
               HasExactMatchSuggestion(fill_data, username_element.value())) {
      password_element.setAutofilled(true);
    }
    return false;
  }

  if (form_has_fillable_username && username_element.value().isEmpty()) {
    username_element.setValue(fill_data.username_field.value, true);
  }

  return FillUserNameAndPassword(
      &username_element, &password_element, fill_data,
      true /* exact_username_match */, false /* set_selection */,
      nonscript_modified_values, registration_callback, logger);
}

Project: Chrome

bool PasswordAutofillAgent::FillSuggestion(
    const blink::WebFormControlElement& control_element,
    const blink::WebString& username,
    const blink::WebString& password) {
  const blink::WebInputElement* element = toWebInputElement(&control_element);
  if (!element)
    return false;

  blink::WebInputElement username_element;
  blink::WebInputElement password_element;
  PasswordInfo* password_info;

  if (!FindPasswordInfoForElement(*element, &username_element,
                                  &password_element, &password_info) ||
      (!username_element.isNull() &&
       !IsElementAutocompletable(username_element)) ||
      !IsElementAutocompletable(password_element)) {
    return false;
  }

  password_info->password_was_edited_last = false;
  if (element->isPasswordField()) {
    password_info->password_field_suggestion_was_accepted = true;
    password_info->password_field = password_element;
  } else if (!username_element.isNull()) {
    username_element.setValue(username, true);
    username_element.setAutofilled(true);
    nonscript_modified_values_[username_element] = username;
  }

  password_element.setValue(password, true);
  password_element.setAutofilled(true);
  nonscript_modified_values_[password_element] = password;

  blink::WebInputElement mutable_filled_element = *element;
  mutable_filled_element.setSelectionRange(element->value().length(),
                                           element->value().length());

  return true;
}

Project: Chrome

bool FillUserNameAndPassword(
    blink::WebInputElement* username_element,
    blink::WebInputElement* password_element,
    const PasswordFormFillData& fill_data,
    bool exact_username_match,
    bool set_selection,
    std::map<const blink::WebInputElement, blink::WebString>*
        nonscript_modified_values,
    base::Callback<void(blink::WebInputElement*)> registration_callback,
    RendererSavePasswordProgressLogger* logger) {
  if (logger)
    logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD);

  if (!IsElementAutocompletable(*password_element))
    return false;

  base::string16 current_username;
  if (!username_element->isNull()) {
    current_username = username_element->value();
  }

  base::string16 username;
  base::string16 password;

  if (DoUsernamesMatch(fill_data.username_field.value, current_username,
                       exact_username_match)) {
    username = fill_data.username_field.value;
    password = fill_data.password_field.value;
    if (logger)
      logger->LogMessage(Logger::STRING_USERNAMES_MATCH);
  } else {
    for (const auto& it : fill_data.additional_logins) {
      if (DoUsernamesMatch(it.first, current_username, exact_username_match)) {
        username = it.first;
        password = it.second.password;
        break;
      }
    }
    if (logger) {
      logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL,
                         !(username.empty() && password.empty()));
    }

    if (username.empty() && password.empty()) {
      for (const auto& it : fill_data.other_possible_usernames) {
        for (size_t i = 0; i < it.second.size(); ++i) {
          if (DoUsernamesMatch(
                  it.second[i], current_username, exact_username_match)) {
            username = it.second[i];
            password = it.first.password;
            break;
          }
        }
        if (!username.empty() && !password.empty())
          break;
      }
    }
  }
  if (password.empty())
    return false;


  if (!username_element->isNull() &&
      IsElementAutocompletable(*username_element)) {
    username_element->setValue(username, true);
    (*nonscript_modified_values)[*username_element] = username;
    username_element->setAutofilled(true);
    if (logger)
      logger->LogElementName(Logger::STRING_USERNAME_FILLED, *username_element);
    if (set_selection) {
      form_util::PreviewSuggestion(username, current_username,
                                   username_element);
    }
  } else if (current_username != username) {
    return false;
  }

  password_element->setSuggestedValue(password);
  (*nonscript_modified_values)[*password_element] = password;
  registration_callback.Run(password_element);

  password_element->setAutofilled(true);
  if (logger)
    logger->LogElementName(Logger::STRING_PASSWORD_FILLED, *password_element);
  return true;
}

Project: Chrome

void FindFormElements(content::RenderFrame* render_frame,
                      const PasswordFormFillData& data,
                      bool ambiguous_or_empty_names,
                      FormElementsList* results) {
  DCHECK(results);

  blink::WebDocument doc = render_frame->GetWebFrame()->document();
  if (!doc.isHTMLDocument())
    return;

  if (data.origin != form_util::GetCanonicalOriginForDocument(doc))
    return;

  blink::WebVector<blink::WebFormElement> forms;
  doc.forms(forms);

  for (size_t i = 0; i < forms.size(); ++i) {
    blink::WebFormElement fe = forms[i];

    if (data.action != form_util::GetCanonicalActionForForm(fe))
      continue;

    std::vector<blink::WebFormControlElement> control_elements =
        form_util::ExtractAutofillableElementsInForm(fe);
    FormInputElementMap cur_map;
    if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names,
                              &cur_map))
      results->push_back(cur_map);
  }
  if (data.action != data.origin)
    return;

  std::vector<blink::WebFormControlElement> control_elements =
      form_util::GetUnownedAutofillableFormFieldElements(doc.all(), nullptr);
  FormInputElementMap unowned_elements_map;
  if (FindFormInputElements(control_elements, data, ambiguous_or_empty_names,
                            &unowned_elements_map))
    results->push_back(unowned_elements_map);
}

Project: Chrome

bool FindFormInputElement(
    const std::vector<blink::WebFormControlElement>& control_elements,
    const FormFieldData& field,
    bool ambiguous_or_empty_names,
    FormInputElementMap* result) {
  bool found_input = false;
  bool is_password_field = IsPasswordField(field);
  bool does_password_field_has_ambigous_or_empty_name =
      ambiguous_or_empty_names && is_password_field;
  bool ambiguous_and_multiple_password_fields_with_autocomplete =
      does_password_field_has_ambigous_or_empty_name &&
      HasPasswordWithAutocompleteAttribute(control_elements);
  base::string16 field_name = FieldName(field, ambiguous_or_empty_names);
  for (const blink::WebFormControlElement& control_element : control_elements) {
    if (!ambiguous_or_empty_names &&
        control_element.nameForAutofill() != field_name) {
      continue;
    }

    if (!control_element.hasHTMLTagName("input"))
      continue;

    const blink::WebInputElement input_element =
        control_element.toConst<blink::WebInputElement>();
    if (input_element.isPasswordField() != is_password_field)
      continue;

    if (ambiguous_and_multiple_password_fields_with_autocomplete &&
        !HasAutocompleteAttributeValue(input_element, "current-password")) {
      continue;
    }

    if (found_input) {
      if (does_password_field_has_ambigous_or_empty_name) {
        if (!form_util::IsWebNodeVisible((*result)[field_name])) {
          (*result)[field_name] = input_element;
        }
        continue;
      }

      found_input = false;
      break;
    }

    (*result)[field_name] = input_element;
    found_input = true;
  }

  if (!found_input) {
    result->clear();
    return false;
  }

  return true;
}

Project: Chrome

bool FindFormInputElements(
    const std::vector<blink::WebFormControlElement>& control_elements,
    const PasswordFormFillData& data,
    bool ambiguous_or_empty_names,
    FormInputElementMap* result) {
  return FindFormInputElement(control_elements, data.password_field,
                              ambiguous_or_empty_names, result) &&
         (!FillDataContainsFillableUsername(data) ||
          FindFormInputElement(control_elements, data.username_field,
                               ambiguous_or_empty_names, result));
}

Project: Chrome

bool PasswordAutofillAgent::FindPasswordInfoForElement(
    const blink::WebInputElement& element,
    blink::WebInputElement* username_element,
    blink::WebInputElement* password_element,
    PasswordInfo** password_info) {
  DCHECK(username_element && password_element && password_info);
  username_element->reset();
  password_element->reset();
  if (!element.isPasswordField()) {
    *username_element = element;
  } else {
    WebInputToPasswordInfoMap::iterator iter =
        web_input_to_password_info_.find(element);
    if (iter != web_input_to_password_info_.end()) {
      *password_element = element;
      *password_info = &iter->second;
      return true;
    }
    PasswordToLoginMap::const_iterator password_iter =
        password_to_username_.find(element);
    if (password_iter == password_to_username_.end()) {
      if (web_input_to_password_info_.empty())
        return false;

      *password_element = element;
      *password_info = &web_input_to_password_info_.begin()->second;
      return true;
    }
    *username_element = password_iter->second;
    *password_element = element;
  }

  WebInputToPasswordInfoMap::iterator iter =
      web_input_to_password_info_.find(*username_element);

  if (iter == web_input_to_password_info_.end())
    return false;

  *password_info = &iter->second;
  if (password_element->isNull())
    *password_element = (*password_info)->password_field;

  return true;
}

Project: Chrome

void PasswordAutofillAgent::FirstUserGestureObserved() {
  gatekeeper_.OnUserGesture();
}

Project: Chrome

bool FormContainsNonDefaultPasswordValue(const PasswordForm& password_form) {
  return (!password_form.password_value.empty() &&
          !password_form.password_value_is_default) ||
      (!password_form.new_password_value.empty() &&
       !password_form.new_password_value_is_default);
}

Project: Chrome

void PasswordAutofillAgent::FrameClosing() {
  for (auto const& iter : web_input_to_password_info_) {
    password_to_username_.erase(iter.second.password_field);
  }
  web_input_to_password_info_.clear();
  provisionally_saved_form_.reset();
  nonscript_modified_values_.clear();
}

Project: Chrome

void PasswordAutofillAgent::FrameWillClose() {
  FrameClosing();
}

Project: Chrome

bool HasExactMatchSuggestion(const PasswordFormFillData& fill_data,
                             const base::string16& current_username) {
  if (fill_data.username_field.value == current_username)
    return true;

  for (const auto& usernames : fill_data.other_possible_usernames) {
    for (const auto& username_string : usernames.second) {
      if (username_string == current_username)
        return true;
    }
  }

  for (const auto& login : fill_data.additional_logins) {
    if (login.first == current_username)
      return true;
  }

  return false;
}

Project: Chrome

bool HasPasswordWithAutocompleteAttribute(
    const std::vector<blink::WebFormControlElement>& control_elements) {
  for (const blink::WebFormControlElement& control_element : control_elements) {
    if (!control_element.hasHTMLTagName("input"))
      continue;

    const blink::WebInputElement input_element =
        control_element.toConst<blink::WebInputElement>();
    if (input_element.isPasswordField() &&
        (HasAutocompleteAttributeValue(input_element, "current-password") ||
         HasAutocompleteAttributeValue(input_element, "new-password")))
      return true;
  }

  return false;
}

Project: Chrome

bool IsElementAutocompletable(const blink::WebInputElement& element) {
  return IsElementEditable(element);
}

Project: Chrome

bool IsElementEditable(const blink::WebInputElement& element) {
  return element.isEnabled() && !element.isReadOnly();
}

Project: Chrome

void LogHTMLForm(SavePasswordProgressLogger* logger,
                 SavePasswordProgressLogger::StringID message_id,
                 const blink::WebFormElement& form) {
  logger->LogHTMLForm(message_id,
                      form.name().utf8(),
                      GURL(form.action().utf8()));
}

Project: Chrome

void PasswordAutofillAgent::OnAutofillUsernameAndPasswordDataReceived(
    const FormsPredictionsMap& predictions) {
  form_predictions_.insert(predictions.begin(), predictions.end());
}

Project: Chrome

void PasswordAutofillAgent::OnFillPasswordForm(
    int key,
    const PasswordFormFillData& form_data) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_) {
    logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
    logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD);
  }

  bool ambiguous_or_empty_names =
      DoesFormContainAmbiguousOrEmptyNames(form_data);
  FormElementsList forms;
  FindFormElements(render_frame(), form_data, ambiguous_or_empty_names, &forms);
  if (logger) {
    logger->LogBoolean(Logger::STRING_AMBIGUOUS_OR_EMPTY_NAMES,
                       ambiguous_or_empty_names);
    logger->LogNumber(Logger::STRING_NUMBER_OF_POTENTIAL_FORMS_TO_FILL,
                      forms.size());
    logger->LogBoolean(Logger::STRING_FORM_DATA_WAIT,
                       form_data.wait_for_username);
  }
  for (const auto& form : forms) {
    base::string16 username_field_name;
    base::string16 password_field_name =
        FieldName(form_data.password_field, ambiguous_or_empty_names);
    bool form_contains_fillable_username_field =
        FillDataContainsFillableUsername(form_data);
    if (form_contains_fillable_username_field) {
      username_field_name =
          FieldName(form_data.username_field, ambiguous_or_empty_names);
    }
    if (logger) {
      logger->LogBoolean(Logger::STRING_CONTAINS_FILLABLE_USERNAME_FIELD,
                         form_contains_fillable_username_field);
      logger->LogBoolean(Logger::STRING_USERNAME_FIELD_NAME_EMPTY,
                         username_field_name.empty());
      logger->LogBoolean(Logger::STRING_PASSWORD_FIELD_NAME_EMPTY,
                         password_field_name.empty());
    }

    blink::WebInputElement username_element;
    blink::WebInputElement password_element;

    if (!username_field_name.empty()) {
      const auto it = form.find(username_field_name);
      DCHECK(it != form.end());
      username_element = it->second;
    }

    if (password_field_name.empty())
      break;

    {
      const auto it = form.find(password_field_name);
      DCHECK(it != form.end());
      password_element = it->second;
    }

    blink::WebInputElement main_element =
        username_element.isNull() ? password_element : username_element;

    if (web_input_to_password_info_.find(main_element) !=
        web_input_to_password_info_.end())
      continue;

    if (!form_data.wait_for_username) {
      FillFormOnPasswordReceived(
          form_data, username_element, password_element,
          &nonscript_modified_values_,
          base::Bind(&PasswordValueGatekeeper::RegisterElement,
                     base::Unretained(&gatekeeper_)),
          logger.get());
    }

    PasswordInfo password_info;
    password_info.fill_data = form_data;
    password_info.key = key;
    password_info.password_field = password_element;
    web_input_to_password_info_[main_element] = password_info;
    if (!main_element.isPasswordField())
      password_to_username_[password_element] = username_element;
  }
}

Project: Chrome

void PasswordAutofillAgent::OnFindFocusedPasswordForm() {
  std::unique_ptr<PasswordForm> password_form;

  blink::WebElement element = render_frame()->GetFocusedElement();
  if (!element.isNull() && element.hasHTMLTagName("input")) {
    blink::WebInputElement input = element.to<blink::WebInputElement>();
    if (input.isPasswordField() && !input.form().isNull()) {
      if (!input.form().isNull()) {
        password_form = CreatePasswordFormFromWebForm(
            input.form(), &nonscript_modified_values_, &form_predictions_);
      } else {
        password_form = CreatePasswordFormFromUnownedInputElements(
            *render_frame()->GetWebFrame(),
            &nonscript_modified_values_, &form_predictions_);
        if (password_form->password_element != input.nameForAutofill() &&
            password_form->new_password_element != input.nameForAutofill())
          password_form.reset();
      }
    }
  }

  if (!password_form)
    password_form.reset(new PasswordForm());

  Send(new AutofillHostMsg_FocusedPasswordFormFound(
      routing_id(), *password_form));
}

Project: Chrome

bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message)
    IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm)
    IPC_MESSAGE_HANDLER(AutofillMsg_SetLoggingState, OnSetLoggingState)
    IPC_MESSAGE_HANDLER(AutofillMsg_AutofillUsernameAndPasswordDataReceived,
                        OnAutofillUsernameAndPasswordDataReceived)
    IPC_MESSAGE_HANDLER(AutofillMsg_FindFocusedPasswordForm,
                        OnFindFocusedPasswordForm)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

Project: Chrome

void PasswordAutofillAgent::OnSamePageNavigationCompleted() {
  if (!ProvisionallySavedPasswordIsValid())
    return;

  blink::WebFrame* frame = render_frame()->GetWebFrame();
  if (form_util::IsFormVisible(frame, provisionally_saved_form_->action,
                               provisionally_saved_form_->origin,
                               provisionally_saved_form_->form_data) ||
      IsUnownedPasswordFormVisible(frame, provisionally_saved_form_->action,
                                   provisionally_saved_form_->origin,
                                   provisionally_saved_form_->form_data,
                                   form_predictions_)) {
    return;
  }

  Send(new AutofillHostMsg_InPageNavigation(routing_id(),
                                            *provisionally_saved_form_));
  provisionally_saved_form_.reset();
}

Project: Chrome

void PasswordAutofillAgent::OnSetLoggingState(bool active) {
  logging_state_active_ = active;
}

Project: Chrome

void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() {
  was_user_gesture_seen_ = true;

  for (blink::WebInputElement& element : elements_)
    ShowValue(&element);

  elements_.clear();
}

Project: Chrome

bool PasswordAutofillAgent::PreviewSuggestion(
    const blink::WebFormControlElement& control_element,
    const blink::WebString& username,
    const blink::WebString& password) {
  const blink::WebInputElement* element = toWebInputElement(&control_element);
  if (!element)
    return false;

  blink::WebInputElement username_element;
  blink::WebInputElement password_element;
  PasswordInfo* password_info;

  if (!FindPasswordInfoForElement(*element, &username_element,
                                  &password_element, &password_info) ||
      (!username_element.isNull() &&
       !IsElementAutocompletable(username_element)) ||
      !IsElementAutocompletable(password_element)) {
    return false;
  }

  if (!element->isPasswordField() && !username_element.isNull()) {
    if (username_query_prefix_.empty())
      username_query_prefix_ = username_element.value();

    was_username_autofilled_ = username_element.isAutofilled();
    username_element.setSuggestedValue(username);
    username_element.setAutofilled(true);
    form_util::PreviewSuggestion(username_element.suggestedValue(),
                                 username_query_prefix_, &username_element);
  }
  was_password_autofilled_ = password_element.isAutofilled();
  password_element.setSuggestedValue(password);
  password_element.setAutofilled(true);

  return true;
}

Project: Chrome

bool PasswordAutofillAgent::ProvisionallySavedPasswordIsValid() {
  return provisionally_saved_form_ &&
         !provisionally_saved_form_->username_value.empty() &&
         !(provisionally_saved_form_->password_value.empty() &&
         provisionally_saved_form_->new_password_value.empty());
}

Project: Chrome

bool ShouldHighlightFields() {
  std::string group_name =
      base::FieldTrialList::FindFullName(kFillOnAccountSelectFieldTrialName);
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableFillOnAccountSelect) ||
      base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableFillOnAccountSelect)) {
    return true;
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableFillOnAccountSelectNoHighlighting)) {
    return false;
  }

  return group_name !=
         kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup;
}

Project: Chrome

bool PasswordAutofillAgent::ShowSuggestions(
    const blink::WebInputElement& element,
    bool show_all,
    bool generation_popup_showing) {
  blink::WebInputElement username_element;
  blink::WebInputElement password_element;
  PasswordInfo* password_info;
  if (!FindPasswordInfoForElement(element, &username_element, &password_element,
                                  &password_info))
    return false;

  if (!element.isTextField() || !IsElementAutocompletable(element) ||
      !IsElementAutocompletable(password_element))
    return true;

  if (element.nameForAutofill().isEmpty() &&
      !DoesFormContainAmbiguousOrEmptyNames(password_info->fill_data)) {
    return false;  // If the field has no name, then we won't have values.
  }

  if (element.value().length() > kMaximumTextSizeForAutocomplete)
    return false;

  if (element.isPasswordField() &&
      (password_info->password_field_suggestion_was_accepted &&
       element != password_info->password_field))
    return true;

  UMA_HISTOGRAM_BOOLEAN(
      "PasswordManager.AutocompletePopupSuppressedByGeneration",
      generation_popup_showing);

  if (generation_popup_showing)
    return false;

  return ShowSuggestionPopup(*password_info, element,
                             show_all && !element.isPasswordField(),
                             element.isPasswordField());
}

Project: Chrome

void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
    blink::WebInputElement* element) {
  if (!element->isNull() && !element->suggestedValue().isEmpty())
    element->setValue(element->suggestedValue(), true);
}

Project: Chrome

bool PasswordAutofillAgent::TextFieldDidEndEditing(
    const blink::WebInputElement& element) {
  WebInputToPasswordInfoMap::const_iterator iter =
      web_input_to_password_info_.find(element);
  if (iter == web_input_to_password_info_.end())
    return false;

  const PasswordInfo& password_info = iter->second;
  if (password_info.password_was_edited_last)
    return false;

  const PasswordFormFillData& fill_data = password_info.fill_data;

  if (!fill_data.wait_for_username)
    return false;

  blink::WebInputElement password = password_info.password_field;
  if (!IsElementEditable(password))
    return false;

  blink::WebInputElement username = element;  // We need a non-const.

  FillUserNameAndPassword(&username, &password, fill_data, true, false,
                          &nonscript_modified_values_,
                          base::Bind(&PasswordValueGatekeeper::RegisterElement,
                                     base::Unretained(&gatekeeper_)),
                          nullptr);
  return true;
}

Project: Chrome

void PasswordAutofillAgent::WillSendSubmitEvent(
    const blink::WebFormElement& form) {
  std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm(
      form, &nonscript_modified_values_, &form_predictions_);
  ProvisionallySavePassword(std::move(password_form),
                            RESTRICTION_NON_EMPTY_PASSWORD);
}

Project: Chrome

void PasswordAutofillAgent::WillSubmitForm(const blink::WebFormElement& form) {
  std::unique_ptr<RendererSavePasswordProgressLogger> logger;
  if (logging_state_active_) {
    logger.reset(new RendererSavePasswordProgressLogger(this, routing_id()));
    logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD);
    LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form);
  }

  std::unique_ptr<PasswordForm> submitted_form = CreatePasswordFormFromWebForm(
      form, &nonscript_modified_values_, &form_predictions_);

  if (submitted_form) {
    if (logger) {
      logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM,
                              *submitted_form);
    }
    if (provisionally_saved_form_ &&
        submitted_form->action == provisionally_saved_form_->action) {
      if (logger)
        logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED);
      submitted_form->password_value =
          provisionally_saved_form_->password_value;
      submitted_form->new_password_value =
          provisionally_saved_form_->new_password_value;
      submitted_form->username_value =
          provisionally_saved_form_->username_value;
    }

    Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
                                                   *submitted_form));
    provisionally_saved_form_.reset();
  } else if (logger) {
    logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD);
  }
}

Project: Chrome

PasswordAutofillAgent::~PasswordAutofillAgent() {
}