mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			1489 lines
		
	
	
	
		
			50 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1489 lines
		
	
	
	
		
			50 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "FormAutofillNative.h"
 | 
						|
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include "mozilla/ClearOnShutdown.h"
 | 
						|
#include "mozilla/ComputedStyle.h"
 | 
						|
#include "mozilla/dom/AutocompleteInfoBinding.h"
 | 
						|
#include "mozilla/dom/Document.h"
 | 
						|
#include "mozilla/dom/Element.h"
 | 
						|
#include "mozilla/dom/HTMLInputElement.h"
 | 
						|
#include "mozilla/dom/HTMLLabelElement.h"
 | 
						|
#include "mozilla/dom/HTMLOptionElement.h"
 | 
						|
#include "mozilla/dom/HTMLSelectElement.h"
 | 
						|
#include "mozilla/HashTable.h"
 | 
						|
#include "mozilla/RustRegex.h"
 | 
						|
#include "nsContentUtils.h"
 | 
						|
#include "nsIFrame.h"
 | 
						|
#include "nsIFrameInlines.h"
 | 
						|
#include "nsLayoutUtils.h"
 | 
						|
#include "nsTStringHasher.h"
 | 
						|
#include "mozilla/StaticPtr.h"
 | 
						|
 | 
						|
namespace mozilla::dom {
 | 
						|
 | 
						|
static const char kWhitespace[] = "\b\t\r\n ";
 | 
						|
 | 
						|
enum class RegexKey : uint8_t {
 | 
						|
  CC_NAME,
 | 
						|
  CC_NUMBER,
 | 
						|
  CC_EXP,
 | 
						|
  CC_EXP_MONTH,
 | 
						|
  CC_EXP_YEAR,
 | 
						|
  CC_TYPE,
 | 
						|
  MM_MONTH,
 | 
						|
  YY_OR_YYYY,
 | 
						|
  MONTH,
 | 
						|
  YEAR,
 | 
						|
  MMYY,
 | 
						|
  VISA_CHECKOUT,
 | 
						|
  CREDIT_CARD_NETWORK,
 | 
						|
  CREDIT_CARD_NETWORK_EXACT_MATCH,
 | 
						|
  CREDIT_CARD_NETWORK_LONG,
 | 
						|
  TWO_OR_FOUR_DIGIT_YEAR,
 | 
						|
  DWFRM,
 | 
						|
  BML,
 | 
						|
  TEMPLATED_VALUE,
 | 
						|
  FIRST,
 | 
						|
  LAST,
 | 
						|
  GIFT,
 | 
						|
  SUBSCRIPTION,
 | 
						|
  VALIDATION,
 | 
						|
 | 
						|
  Count
 | 
						|
};
 | 
						|
 | 
						|
// We don't follow the coding style (naming start with capital letter) here and
 | 
						|
// the following CCXXX enum class because we want to sync the rule naming with
 | 
						|
// the JS implementation.
 | 
						|
enum class CCNumberParams : uint8_t {
 | 
						|
  idOrNameMatchNumberRegExp,
 | 
						|
  labelsMatchNumberRegExp,
 | 
						|
  closestLabelMatchesNumberRegExp,
 | 
						|
  placeholderMatchesNumberRegExp,
 | 
						|
  ariaLabelMatchesNumberRegExp,
 | 
						|
  idOrNameMatchGift,
 | 
						|
  labelsMatchGift,
 | 
						|
  placeholderMatchesGift,
 | 
						|
  ariaLabelMatchesGift,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
  inputTypeNotNumbery,
 | 
						|
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
enum class CCNameParams : uint8_t {
 | 
						|
  idOrNameMatchNameRegExp,
 | 
						|
  labelsMatchNameRegExp,
 | 
						|
  closestLabelMatchesNameRegExp,
 | 
						|
  placeholderMatchesNameRegExp,
 | 
						|
  ariaLabelMatchesNameRegExp,
 | 
						|
  idOrNameMatchFirst,
 | 
						|
  labelsMatchFirst,
 | 
						|
  placeholderMatchesFirst,
 | 
						|
  ariaLabelMatchesFirst,
 | 
						|
  idOrNameMatchLast,
 | 
						|
  labelsMatchLast,
 | 
						|
  placeholderMatchesLast,
 | 
						|
  ariaLabelMatchesLast,
 | 
						|
  idOrNameMatchFirstAndLast,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
enum class CCTypeParams : uint8_t {
 | 
						|
  idOrNameMatchTypeRegExp,
 | 
						|
  labelsMatchTypeRegExp,
 | 
						|
  closestLabelMatchesTypeRegExp,
 | 
						|
  idOrNameMatchVisaCheckout,
 | 
						|
  ariaLabelMatchesVisaCheckout,
 | 
						|
  isSelectWithCreditCardOptions,
 | 
						|
  isRadioWithCreditCardText,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
enum class CCExpParams : uint8_t {
 | 
						|
  labelsMatchExpRegExp,
 | 
						|
  closestLabelMatchesExpRegExp,
 | 
						|
  placeholderMatchesExpRegExp,
 | 
						|
  labelsMatchExpWith2Or4DigitYear,
 | 
						|
  placeholderMatchesExpWith2Or4DigitYear,
 | 
						|
  labelsMatchMMYY,
 | 
						|
  placeholderMatchesMMYY,
 | 
						|
  maxLengthIs7,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
  isExpirationMonthLikely,
 | 
						|
  isExpirationYearLikely,
 | 
						|
  idOrNameMatchMonth,
 | 
						|
  idOrNameMatchYear,
 | 
						|
  idOrNameMatchExpMonthRegExp,
 | 
						|
  idOrNameMatchExpYearRegExp,
 | 
						|
  idOrNameMatchValidation,
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
enum class CCExpMonthParams : uint8_t {
 | 
						|
  idOrNameMatchExpMonthRegExp,
 | 
						|
  labelsMatchExpMonthRegExp,
 | 
						|
  closestLabelMatchesExpMonthRegExp,
 | 
						|
  placeholderMatchesExpMonthRegExp,
 | 
						|
  ariaLabelMatchesExpMonthRegExp,
 | 
						|
  idOrNameMatchMonth,
 | 
						|
  labelsMatchMonth,
 | 
						|
  placeholderMatchesMonth,
 | 
						|
  ariaLabelMatchesMonth,
 | 
						|
  nextFieldIdOrNameMatchExpYearRegExp,
 | 
						|
  nextFieldLabelsMatchExpYearRegExp,
 | 
						|
  nextFieldPlaceholderMatchExpYearRegExp,
 | 
						|
  nextFieldAriaLabelMatchExpYearRegExp,
 | 
						|
  nextFieldIdOrNameMatchYear,
 | 
						|
  nextFieldLabelsMatchYear,
 | 
						|
  nextFieldPlaceholderMatchesYear,
 | 
						|
  nextFieldAriaLabelMatchesYear,
 | 
						|
  nextFieldMatchesExpYearAutocomplete,
 | 
						|
  isExpirationMonthLikely,
 | 
						|
  nextFieldIsExpirationYearLikely,
 | 
						|
  maxLengthIs2,
 | 
						|
  placeholderMatchesMM,
 | 
						|
  roleIsMenu,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
enum class CCExpYearParams : uint8_t {
 | 
						|
  idOrNameMatchExpYearRegExp,
 | 
						|
  labelsMatchExpYearRegExp,
 | 
						|
  closestLabelMatchesExpYearRegExp,
 | 
						|
  placeholderMatchesExpYearRegExp,
 | 
						|
  ariaLabelMatchesExpYearRegExp,
 | 
						|
  idOrNameMatchYear,
 | 
						|
  labelsMatchYear,
 | 
						|
  placeholderMatchesYear,
 | 
						|
  ariaLabelMatchesYear,
 | 
						|
  previousFieldIdOrNameMatchExpMonthRegExp,
 | 
						|
  previousFieldLabelsMatchExpMonthRegExp,
 | 
						|
  previousFieldPlaceholderMatchExpMonthRegExp,
 | 
						|
  previousFieldAriaLabelMatchExpMonthRegExp,
 | 
						|
  previousFieldIdOrNameMatchMonth,
 | 
						|
  previousFieldLabelsMatchMonth,
 | 
						|
  previousFieldPlaceholderMatchesMonth,
 | 
						|
  previousFieldAriaLabelMatchesMonth,
 | 
						|
  previousFieldMatchesExpMonthAutocomplete,
 | 
						|
  isExpirationYearLikely,
 | 
						|
  previousFieldIsExpirationMonthLikely,
 | 
						|
  placeholderMatchesYYOrYYYY,
 | 
						|
  roleIsMenu,
 | 
						|
  idOrNameMatchSubscription,
 | 
						|
  idOrNameMatchDwfrmAndBml,
 | 
						|
  hasTemplatedValue,
 | 
						|
 | 
						|
  Count,
 | 
						|
};
 | 
						|
 | 
						|
struct AutofillParams {
 | 
						|
  EnumeratedArray<CCNumberParams, double, size_t(CCNumberParams::Count)>
 | 
						|
      mCCNumberParams;
 | 
						|
  EnumeratedArray<CCNameParams, double, size_t(CCNameParams::Count)>
 | 
						|
      mCCNameParams;
 | 
						|
  EnumeratedArray<CCTypeParams, double, size_t(CCTypeParams::Count)>
 | 
						|
      mCCTypeParams;
 | 
						|
  EnumeratedArray<CCExpParams, double, size_t(CCExpParams::Count)> mCCExpParams;
 | 
						|
  EnumeratedArray<CCExpMonthParams, double, size_t(CCExpMonthParams::Count)>
 | 
						|
      mCCExpMonthParams;
 | 
						|
  EnumeratedArray<CCExpYearParams, double, size_t(CCExpYearParams::Count)>
 | 
						|
      mCCExpYearParams;
 | 
						|
};
 | 
						|
 | 
						|
// clang-format off
 | 
						|
constexpr AutofillParams kCoefficents{
 | 
						|
    .mCCNumberParams = {
 | 
						|
      /* idOrNameMatchNumberRegExp */ 7.679469585418701,
 | 
						|
      /* labelsMatchNumberRegExp */ 5.122580051422119,
 | 
						|
      /* closestLabelMatchesNumberRegExp */ 2.1256935596466064,
 | 
						|
      /* placeholderMatchesNumberRegExp */ 9.471800804138184,
 | 
						|
      /* ariaLabelMatchesNumberRegExp */ 6.067715644836426,
 | 
						|
      /* idOrNameMatchGift */ -22.946273803710938,
 | 
						|
      /* labelsMatchGift */ -7.852959632873535,
 | 
						|
      /* placeholderMatchesGift */ -2.355496406555176,
 | 
						|
      /* ariaLabelMatchesGift */ -2.940307855606079,
 | 
						|
      /* idOrNameMatchSubscription */ 0.11255314946174622,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ -0.0006645023822784424,
 | 
						|
      /* hasTemplatedValue */ -0.11370040476322174,
 | 
						|
      /* inputTypeNotNumbery */ -3.750155210494995
 | 
						|
    },
 | 
						|
    .mCCNameParams = {
 | 
						|
      /* idOrNameMatchNameRegExp */ 7.496212959289551,
 | 
						|
      /* labelsMatchNameRegExp */ 6.081472873687744,
 | 
						|
      /* closestLabelMatchesNameRegExp */ 2.600574254989624,
 | 
						|
      /* placeholderMatchesNameRegExp */ 5.750874042510986,
 | 
						|
      /* ariaLabelMatchesNameRegExp */ 5.162227153778076,
 | 
						|
      /* idOrNameMatchFirst */ -6.742659091949463,
 | 
						|
      /* labelsMatchFirst */ -0.5234538912773132,
 | 
						|
      /* placeholderMatchesFirst */ -3.4615235328674316,
 | 
						|
      /* ariaLabelMatchesFirst */ -1.3145145177841187,
 | 
						|
      /* idOrNameMatchLast */ -12.561869621276855,
 | 
						|
      /* labelsMatchLast */ -0.27417105436325073,
 | 
						|
      /* placeholderMatchesLast */ -1.434966802597046,
 | 
						|
      /* ariaLabelMatchesLast */ -2.9319725036621094,
 | 
						|
      /* idOrNameMatchFirstAndLast */ 24.123435974121094,
 | 
						|
      /* idOrNameMatchSubscription */ 0.08349418640136719,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ 0.01882520318031311,
 | 
						|
      /* hasTemplatedValue */ 0.182317852973938
 | 
						|
    },
 | 
						|
    .mCCTypeParams = {
 | 
						|
      /* idOrNameMatchTypeRegExp */ 2.0581533908843994,
 | 
						|
      /* labelsMatchTypeRegExp */ 1.0784518718719482,
 | 
						|
      /* closestLabelMatchesTypeRegExp */ 0.6995877623558044,
 | 
						|
      /* idOrNameMatchVisaCheckout */ -3.320356845855713,
 | 
						|
      /* ariaLabelMatchesVisaCheckout */ -3.4196767807006836,
 | 
						|
      /* isSelectWithCreditCardOptions */ 10.337477684020996,
 | 
						|
      /* isRadioWithCreditCardText */ 4.530318737030029,
 | 
						|
      /* idOrNameMatchSubscription */ -3.7206356525421143,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ -0.08782318234443665,
 | 
						|
      /* hasTemplatedValue */ 0.1772511601448059
 | 
						|
    },
 | 
						|
    .mCCExpParams = {
 | 
						|
      /* labelsMatchExpRegExp */ 7.588159561157227,
 | 
						|
      /* closestLabelMatchesExpRegExp */ 1.41484534740448,
 | 
						|
      /* placeholderMatchesExpRegExp */ 8.759064674377441,
 | 
						|
      /* labelsMatchExpWith2Or4DigitYear */ -3.876218795776367,
 | 
						|
      /* placeholderMatchesExpWith2Or4DigitYear */ 2.8364884853363037,
 | 
						|
      /* labelsMatchMMYY */ 8.836017608642578,
 | 
						|
      /* placeholderMatchesMMYY */ -0.5231751799583435,
 | 
						|
      /* maxLengthIs7 */ 1.3565447330474854,
 | 
						|
      /* idOrNameMatchSubscription */ 0.1779913753271103,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ 0.21037884056568146,
 | 
						|
      /* hasTemplatedValue */ 0.14900512993335724,
 | 
						|
      /* isExpirationMonthLikely */ -3.223409652709961,
 | 
						|
      /* isExpirationYearLikely */ -2.536919593811035,
 | 
						|
      /* idOrNameMatchMonth */ -3.6893014907836914,
 | 
						|
      /* idOrNameMatchYear */ -3.108184337615967,
 | 
						|
      /* idOrNameMatchExpMonthRegExp */ -2.264357089996338,
 | 
						|
      /* idOrNameMatchExpYearRegExp */ -2.7957723140716553,
 | 
						|
      /* idOrNameMatchValidation */ -2.29402756690979
 | 
						|
    },
 | 
						|
    .mCCExpMonthParams = {
 | 
						|
      /* idOrNameMatchExpMonthRegExp */ 0.2787344455718994,
 | 
						|
      /* labelsMatchExpMonthRegExp */ 1.298413634300232,
 | 
						|
      /* closestLabelMatchesExpMonthRegExp */ -11.206244468688965,
 | 
						|
      /* placeholderMatchesExpMonthRegExp */ 1.2605619430541992,
 | 
						|
      /* ariaLabelMatchesExpMonthRegExp */ 1.1330018043518066,
 | 
						|
      /* idOrNameMatchMonth */ 6.1464314460754395,
 | 
						|
      /* labelsMatchMonth */ 0.7051732540130615,
 | 
						|
      /* placeholderMatchesMonth */ 0.7463492751121521,
 | 
						|
      /* ariaLabelMatchesMonth */ 1.8244760036468506,
 | 
						|
      /* nextFieldIdOrNameMatchExpYearRegExp */ 0.06347066164016724,
 | 
						|
      /* nextFieldLabelsMatchExpYearRegExp */ -0.1692247837781906,
 | 
						|
      /* nextFieldPlaceholderMatchExpYearRegExp */ 1.0434566736221313,
 | 
						|
      /* nextFieldAriaLabelMatchExpYearRegExp */ 1.751156210899353,
 | 
						|
      /* nextFieldIdOrNameMatchYear */ -0.532447338104248,
 | 
						|
      /* nextFieldLabelsMatchYear */ 1.3248541355133057,
 | 
						|
      /* nextFieldPlaceholderMatchesYear */ 0.604235827922821,
 | 
						|
      /* nextFieldAriaLabelMatchesYear */ 1.5364223718643188,
 | 
						|
      /* nextFieldMatchesExpYearAutocomplete */ 6.285938262939453,
 | 
						|
      /* isExpirationMonthLikely */ 13.117807388305664,
 | 
						|
      /* nextFieldIsExpirationYearLikely */ 7.182341575622559,
 | 
						|
      /* maxLengthIs2 */ 4.477289199829102,
 | 
						|
      /* placeholderMatchesMM */ 14.403288841247559,
 | 
						|
      /* roleIsMenu */ 5.770959854125977,
 | 
						|
      /* idOrNameMatchSubscription */ -0.043085768818855286,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ 0.02823038399219513,
 | 
						|
      /* hasTemplatedValue */ 0.07234494388103485
 | 
						|
    },
 | 
						|
    .mCCExpYearParams = {
 | 
						|
      /* idOrNameMatchExpYearRegExp */ 5.426016807556152,
 | 
						|
      /* labelsMatchExpYearRegExp */ 1.3240209817886353,
 | 
						|
      /* closestLabelMatchesExpYearRegExp */ -8.702284812927246,
 | 
						|
      /* placeholderMatchesExpYearRegExp */ 0.9059725999832153,
 | 
						|
      /* ariaLabelMatchesExpYearRegExp */ 0.5550334453582764,
 | 
						|
      /* idOrNameMatchYear */ 5.362994194030762,
 | 
						|
      /* labelsMatchYear */ 2.7185044288635254,
 | 
						|
      /* placeholderMatchesYear */ 0.7883157134056091,
 | 
						|
      /* ariaLabelMatchesYear */ 0.311492383480072,
 | 
						|
      /* previousFieldIdOrNameMatchExpMonthRegExp */ 1.8155208826065063,
 | 
						|
      /* previousFieldLabelsMatchExpMonthRegExp */ -0.46133187413215637,
 | 
						|
      /* previousFieldPlaceholderMatchExpMonthRegExp */ 1.0374903678894043,
 | 
						|
      /* previousFieldAriaLabelMatchExpMonthRegExp */ -0.5901495814323425,
 | 
						|
      /* previousFieldIdOrNameMatchMonth */ -5.960310935974121,
 | 
						|
      /* previousFieldLabelsMatchMonth */ 0.6495584845542908,
 | 
						|
      /* previousFieldPlaceholderMatchesMonth */ 0.7198042273521423,
 | 
						|
      /* previousFieldAriaLabelMatchesMonth */ 3.4590985774993896,
 | 
						|
      /* previousFieldMatchesExpMonthAutocomplete */ 2.986003875732422,
 | 
						|
      /* isExpirationYearLikely */ 4.021566390991211,
 | 
						|
      /* previousFieldIsExpirationMonthLikely */ 9.298635482788086,
 | 
						|
      /* placeholderMatchesYYOrYYYY */ 10.457176208496094,
 | 
						|
      /* roleIsMenu */ 1.1051956415176392,
 | 
						|
      /* idOrNameMatchSubscription */ 0.000688597559928894,
 | 
						|
      /* idOrNameMatchDwfrmAndBml */ 0.15687309205532074,
 | 
						|
      /* hasTemplatedValue */ -0.19141331315040588
 | 
						|
    }
 | 
						|
};
 | 
						|
// clang-format off
 | 
						|
 | 
						|
constexpr float kCCNumberBias = -4.948795795440674;
 | 
						|
constexpr float kCCNameBias = -5.3578081130981445;
 | 
						|
// Comment out code that are not used right now
 | 
						|
/*
 | 
						|
constexpr float kCCTypeBias = -5.979659557342529;
 | 
						|
constexpr float kCCExpBias = -5.849575996398926;
 | 
						|
constexpr float kCCExpMonthBias = -8.844199180603027;
 | 
						|
constexpr float kCCExpYearBias = -6.499860763549805;
 | 
						|
*/
 | 
						|
 | 
						|
struct Rule {
 | 
						|
  RegexKey key;
 | 
						|
  const char* pattern;
 | 
						|
};
 | 
						|
 | 
						|
const Rule kFirefoxRules[] = {
 | 
						|
    {RegexKey::MM_MONTH, "^mm$|\\(mm\\)"},
 | 
						|
    {RegexKey::YY_OR_YYYY, "^(yy|yyyy)$|\\(yy\\)|\\(yyyy\\)"},
 | 
						|
    {RegexKey::MONTH, "month"},
 | 
						|
    {RegexKey::YEAR, "year"},
 | 
						|
    {RegexKey::MMYY, "mm\\s*(/|\\\\)\\s*yy"},
 | 
						|
    {RegexKey::VISA_CHECKOUT, "visa(-|\\s)checkout"},
 | 
						|
    // This should be a union of NETWORK_NAMES in CreditCard.sys.mjs
 | 
						|
    {RegexKey::CREDIT_CARD_NETWORK_LONG,
 | 
						|
     "american express|master card|union pay"},
 | 
						|
    // Please also update CREDIT_CARD_NETWORK_EXACT_MATCH while updating
 | 
						|
    // CREDIT_CARD_NETWORK
 | 
						|
    {RegexKey::CREDIT_CARD_NETWORK,
 | 
						|
     "amex|cartebancaire|diners|discover|jcb|mastercard|mir|unionpay|visa"},
 | 
						|
    {RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH,
 | 
						|
     "^\\s*(?:amex|cartebancaire|diners|discover|jcb|mastercard|mir|unionpay|"
 | 
						|
     "visa)\\s*$"},
 | 
						|
    {RegexKey::TWO_OR_FOUR_DIGIT_YEAR,
 | 
						|
     "(?:exp.*date[^y\\\\n\\\\r]*|mm\\\\s*[-/]?\\\\s*)yy(?:yy)?(?:[^y]|$)"},
 | 
						|
    {RegexKey::DWFRM, "^dwfrm"},
 | 
						|
    {RegexKey::BML, "BML"},
 | 
						|
    {RegexKey::TEMPLATED_VALUE, "^\\{\\{.*\\}\\}$"},
 | 
						|
    {RegexKey::FIRST, "first"},
 | 
						|
    {RegexKey::LAST, "last"},
 | 
						|
    {RegexKey::GIFT, "gift"},
 | 
						|
    {RegexKey::SUBSCRIPTION, "subscription"},
 | 
						|
    {RegexKey::VALIDATION, "validate|validation"},
 | 
						|
};
 | 
						|
 | 
						|
// These are the rules used by Bitwarden [0], converted into RegExp form.
 | 
						|
// [0]
 | 
						|
// https://github.com/bitwarden/browser/blob/c2b8802201fac5e292d55d5caf3f1f78088d823c/src/services/autofill.service.ts#L436
 | 
						|
const Rule kCreditCardRules[] = {
 | 
						|
    /* eslint-disable */
 | 
						|
    // Let us keep our consistent wrapping.
 | 
						|
    {RegexKey::CC_NAME,
 | 
						|
     // Firefox-specific rules
 | 
						|
     "account.*holder.*name"
 | 
						|
     "|^(credit[-\\s]?card|card).*name"
 | 
						|
     // de-DE
 | 
						|
     "|^(kredit)?(karten|konto)inhaber"
 | 
						|
     "|^(name).*karte"
 | 
						|
     // fr-FR
 | 
						|
     "|nom.*(titulaire|détenteur)"
 | 
						|
     "|(titulaire|détenteur).*(carte)"
 | 
						|
     // it-IT
 | 
						|
     "|titolare.*carta"
 | 
						|
     // pl-PL
 | 
						|
     "|posiadacz.*karty"
 | 
						|
     // es-ES
 | 
						|
     "|nombre.*(titular|tarjeta)"
 | 
						|
     // nl-NL
 | 
						|
     "|naam.*op.*kaart"
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|cc-?name"
 | 
						|
     "|card-?name"
 | 
						|
     "|cardholder-?name"
 | 
						|
     "|(^nom$)"
 | 
						|
     // Rules are from Chromium source codes
 | 
						|
     "|card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card"
 | 
						|
     "|(?:card|cc).?name|cc.?full.?name"
 | 
						|
     "|(?:card|cc).?owner"
 | 
						|
     "|nom.*carte"                      // fr-FR
 | 
						|
     "|nome.*cart"                      // it-IT
 | 
						|
     "|名前"                            // ja-JP
 | 
						|
     "|Имя.*карты"                      // ru
 | 
						|
     "|信用卡开户名|开户名|持卡人姓名"  // zh-CN
 | 
						|
     "|持卡人姓名"},                    // zh-TW
 | 
						|
    /* eslint-enable */
 | 
						|
 | 
						|
    {RegexKey::CC_NUMBER,
 | 
						|
     // Firefox-specific rules
 | 
						|
     // de-DE
 | 
						|
     "(cc|kk)nr"
 | 
						|
     "|(kredit)?(karten)(nummer|nr)"
 | 
						|
     // it-IT
 | 
						|
     "|numero.*carta"
 | 
						|
     // fr-FR
 | 
						|
     "|(numero|número|numéro).*(carte)"
 | 
						|
     // pl-PL
 | 
						|
     "|numer.*karty"
 | 
						|
     // es-ES
 | 
						|
     "|(número|numero).*tarjeta"
 | 
						|
     // nl-NL
 | 
						|
     "|kaartnummer"
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|cc-?number"
 | 
						|
     "|cc-?num"
 | 
						|
     "|card-?number"
 | 
						|
     "|card-?num"
 | 
						|
     "|cc-?no"
 | 
						|
     "|card-?no"
 | 
						|
     "|numero-?carte"
 | 
						|
     "|num-?carte"
 | 
						|
     "|cb-?num"
 | 
						|
     // Rules are from Chromium source codes
 | 
						|
     "|(add)?(?:card|cc|acct).?(?:number|#|no|num)"
 | 
						|
     "|カード番号"           // ja-JP
 | 
						|
     "|Номер.*карты"         // ru
 | 
						|
     "|信用卡号|信用卡号码"  // zh-CN
 | 
						|
     "|信用卡卡號"           // zh-TW
 | 
						|
     "|카드"},               // ko-KR
 | 
						|
 | 
						|
    {RegexKey::CC_EXP,
 | 
						|
     // Firefox-specific rules
 | 
						|
     "mm\\s*(/|\\|-)\\s*(yy|jj|aa)"
 | 
						|
     "|(month|mois)\\s*(/|\\|-|et)\\s*(year|année)"
 | 
						|
     // de-DE
 | 
						|
     // fr-FR
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|(^cc-?exp$)"
 | 
						|
     "|(^card-?exp$)"
 | 
						|
     "|(^cc-?expiration$)"
 | 
						|
     "|(^card-?expiration$)"
 | 
						|
     "|(^cc-?ex$)"
 | 
						|
     "|(^card-?ex$)"
 | 
						|
     "|(^card-?expire$)"
 | 
						|
     "|(^card-?expiry$)"
 | 
						|
     "|(^validite$)"
 | 
						|
     "|(^expiration$)"
 | 
						|
     "|(^expiry$)"
 | 
						|
     "|mm-?yy"
 | 
						|
     "|mm-?yyyy"
 | 
						|
     "|yy-?mm"
 | 
						|
     "|yyyy-?mm"
 | 
						|
     "|expiration-?date"
 | 
						|
     "|payment-?card-?expiration"
 | 
						|
     "|(^payment-?cc-?date$)"
 | 
						|
     // Rules are from Chromium source codes
 | 
						|
     "|expir|exp.*date|^expfield$"
 | 
						|
     "|ablaufdatum|gueltig|gültig"  // de-DE
 | 
						|
     "|fecha"                       // es
 | 
						|
     "|date.*exp"                   // fr-FR
 | 
						|
     "|scadenza"                    // it-IT
 | 
						|
     "|有効期限"                    // ja-JP
 | 
						|
     "|validade"                    // pt-BR, pt-PT
 | 
						|
     "|Срок действия карты"},       // ru
 | 
						|
 | 
						|
    {RegexKey::CC_EXP_MONTH,
 | 
						|
     // Firefox-specific rules
 | 
						|
     "(cc|kk)month"  // de-DE
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|(^exp-?month$)"
 | 
						|
     "|(^cc-?exp-?month$)"
 | 
						|
     "|(^cc-?month$)"
 | 
						|
     "|(^card-?month$)"
 | 
						|
     "|(^cc-?mo$)"
 | 
						|
     "|(^card-?mo$)"
 | 
						|
     "|(^exp-?mo$)"
 | 
						|
     "|(^card-?exp-?mo$)"
 | 
						|
     "|(^cc-?exp-?mo$)"
 | 
						|
     "|(^card-?expiration-?month$)"
 | 
						|
     "|(^expiration-?month$)"
 | 
						|
     "|(^cc-?mm$)"
 | 
						|
     "|(^cc-?m$)"
 | 
						|
     "|(^card-?mm$)"
 | 
						|
     "|(^card-?m$)"
 | 
						|
     "|(^card-?exp-?mm$)"
 | 
						|
     "|(^cc-?exp-?mm$)"
 | 
						|
     "|(^exp-?mm$)"
 | 
						|
     "|(^exp-?m$)"
 | 
						|
     "|(^expire-?month$)"
 | 
						|
     "|(^expire-?mo$)"
 | 
						|
     "|(^expiry-?month$)"
 | 
						|
     "|(^expiry-?mo$)"
 | 
						|
     "|(^card-?expire-?month$)"
 | 
						|
     "|(^card-?expire-?mo$)"
 | 
						|
     "|(^card-?expiry-?month$)"
 | 
						|
     "|(^card-?expiry-?mo$)"
 | 
						|
     "|(^mois-?validite$)"
 | 
						|
     "|(^mois-?expiration$)"
 | 
						|
     "|(^m-?validite$)"
 | 
						|
     "|(^m-?expiration$)"
 | 
						|
     "|(^expiry-?date-?field-?month$)"
 | 
						|
     "|(^expiration-?date-?month$)"
 | 
						|
     "|(^expiration-?date-?mm$)"
 | 
						|
     "|(^exp-?mon$)"
 | 
						|
     "|(^validity-?mo$)"
 | 
						|
     "|(^exp-?date-?mo$)"
 | 
						|
     "|(^cb-?date-?mois$)"
 | 
						|
     "|(^date-?m$)"
 | 
						|
     // Rules are from Chromium source codes
 | 
						|
     "|exp.*mo|ccmonth|cardmonth|addmonth"
 | 
						|
     "|monat"  // de-DE
 | 
						|
     // "|fecha" // es
 | 
						|
     // "|date.*exp" // fr-FR
 | 
						|
     // "|scadenza" // it-IT
 | 
						|
     // "|有効期限" // ja-JP
 | 
						|
     // "|validade" // pt-BR, pt-PT
 | 
						|
     // "|Срок действия карты" // ru
 | 
						|
     "|月"},  // zh-CN
 | 
						|
 | 
						|
    {RegexKey::CC_EXP_YEAR,
 | 
						|
     // Firefox-specific rules
 | 
						|
     "(cc|kk)year"  // de-DE
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|(^exp-?year$)"
 | 
						|
     "|(^cc-?exp-?year$)"
 | 
						|
     "|(^cc-?year$)"
 | 
						|
     "|(^card-?year$)"
 | 
						|
     "|(^cc-?yr$)"
 | 
						|
     "|(^card-?yr$)"
 | 
						|
     "|(^exp-?yr$)"
 | 
						|
     "|(^card-?exp-?yr$)"
 | 
						|
     "|(^cc-?exp-?yr$)"
 | 
						|
     "|(^card-?expiration-?year$)"
 | 
						|
     "|(^expiration-?year$)"
 | 
						|
     "|(^cc-?yy$)"
 | 
						|
     "|(^cc-?y$)"
 | 
						|
     "|(^card-?yy$)"
 | 
						|
     "|(^card-?y$)"
 | 
						|
     "|(^card-?exp-?yy$)"
 | 
						|
     "|(^cc-?exp-?yy$)"
 | 
						|
     "|(^exp-?yy$)"
 | 
						|
     "|(^exp-?y$)"
 | 
						|
     "|(^cc-?yyyy$)"
 | 
						|
     "|(^card-?yyyy$)"
 | 
						|
     "|(^card-?exp-?yyyy$)"
 | 
						|
     "|(^cc-?exp-?yyyy$)"
 | 
						|
     "|(^expire-?year$)"
 | 
						|
     "|(^expire-?yr$)"
 | 
						|
     "|(^expiry-?year$)"
 | 
						|
     "|(^expiry-?yr$)"
 | 
						|
     "|(^card-?expire-?year$)"
 | 
						|
     "|(^card-?expire-?yr$)"
 | 
						|
     "|(^card-?expiry-?year$)"
 | 
						|
     "|(^card-?expiry-?yr$)"
 | 
						|
     "|(^an-?validite$)"
 | 
						|
     "|(^an-?expiration$)"
 | 
						|
     "|(^annee-?validite$)"
 | 
						|
     "|(^annee-?expiration$)"
 | 
						|
     "|(^expiry-?date-?field-?year$)"
 | 
						|
     "|(^expiration-?date-?year$)"
 | 
						|
     "|(^cb-?date-?ann$)"
 | 
						|
     "|(^expiration-?date-?yy$)"
 | 
						|
     "|(^expiration-?date-?yyyy$)"
 | 
						|
     "|(^validity-?year$)"
 | 
						|
     "|(^exp-?date-?year$)"
 | 
						|
     "|(^date-?y$)"
 | 
						|
     // Rules are from Chromium source codes
 | 
						|
     "|(add)?year"
 | 
						|
     "|jahr"  // de-DE
 | 
						|
     // "|fecha" // es
 | 
						|
     // "|scadenza" // it-IT
 | 
						|
     // "|有効期限" // ja-JP
 | 
						|
     // "|validade" // pt-BR, pt-PT
 | 
						|
     // "|Срок действия карты" // ru
 | 
						|
     "|年|有效期"},  // zh-CN
 | 
						|
 | 
						|
    {RegexKey::CC_TYPE,
 | 
						|
     // Firefox-specific rules
 | 
						|
     "type"
 | 
						|
     // de-DE
 | 
						|
     "|Kartenmarke"
 | 
						|
     // Rules from Bitwarden
 | 
						|
     "|(^cc-?type$)"
 | 
						|
     "|(^card-?type$)"
 | 
						|
     "|(^card-?brand$)"
 | 
						|
     "|(^cc-?brand$)"
 | 
						|
     "|(^cb-?type$)"},
 | 
						|
    // Rules are from Chromium source codes
 | 
						|
};
 | 
						|
 | 
						|
static double Sigmoid(double x) { return 1.0 / (1.0 + exp(-x)); }
 | 
						|
 | 
						|
class FormAutofillImpl {
 | 
						|
 public:
 | 
						|
  FormAutofillImpl();
 | 
						|
 | 
						|
  void GetFormAutofillConfidences(
 | 
						|
      GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
      nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv);
 | 
						|
 | 
						|
 private:
 | 
						|
  const RustRegex& GetRegex(RegexKey key);
 | 
						|
 | 
						|
  bool StringMatchesRegExp(const nsACString& str, RegexKey key);
 | 
						|
  bool StringMatchesRegExp(const nsAString& str, RegexKey key);
 | 
						|
  bool TextContentMatchesRegExp(Element& element, RegexKey key);
 | 
						|
  size_t CountRegExpMatches(const nsACString& str, RegexKey key);
 | 
						|
  size_t CountRegExpMatches(const nsAString& str, RegexKey key);
 | 
						|
  bool IdOrNameMatchRegExp(Element& element, RegexKey key);
 | 
						|
  bool NextFieldMatchesExpYearAutocomplete(Element* aNextField);
 | 
						|
  bool PreviousFieldMatchesExpMonthAutocomplete(Element* aPrevField);
 | 
						|
  bool LabelMatchesRegExp(Element& element, const nsTArray<nsCString>* labels,
 | 
						|
                          RegexKey key);
 | 
						|
  bool ClosestLabelMatchesRegExp(Element& aElement, RegexKey aKey);
 | 
						|
  bool PlaceholderMatchesRegExp(Element& element, RegexKey key);
 | 
						|
  bool AriaLabelMatchesRegExp(Element& element, RegexKey key);
 | 
						|
  bool AutocompleteStringMatches(Element& aElement, const nsAString& aKey);
 | 
						|
 | 
						|
  bool HasTemplatedValue(Element& element);
 | 
						|
  bool MaxLengthIs(Element& aElement, int32_t aValue);
 | 
						|
  bool IsExpirationMonthLikely(Element& element);
 | 
						|
  bool IsExpirationYearLikely(Element& element);
 | 
						|
  bool InputTypeNotNumbery(Element& element);
 | 
						|
  bool IsSelectWithCreditCardOptions(Element& element);
 | 
						|
  bool IsRadioWithCreditCardText(Element& element,
 | 
						|
                                 const nsTArray<nsCString>* labels,
 | 
						|
                                 ErrorResult& aRv);
 | 
						|
  bool MatchesExpYearAutocomplete(Element& element);
 | 
						|
  bool RoleIsMenu(Element& element);
 | 
						|
 | 
						|
  Element* FindRootForField(Element* aElement);
 | 
						|
 | 
						|
  Element* FindField(const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
                     uint32_t aStartIndex, int8_t aDirection);
 | 
						|
  Element* NextField(const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
                     uint32_t aStartIndex);
 | 
						|
  Element* PrevField(const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
                     uint32_t aStartIndex);
 | 
						|
 | 
						|
  // Array contains regular expressions to match the corresponding
 | 
						|
  // field. Ex, CC number, CC type, etc.
 | 
						|
  using RegexStringArray =
 | 
						|
      EnumeratedArray<RegexKey, nsCString, size_t(RegexKey::Count)>;
 | 
						|
  RegexStringArray mRuleMap;
 | 
						|
 | 
						|
  // Array that holds RegexWrapper that created by regex::ffi::regex_new
 | 
						|
  using RegexWrapperArray = EnumeratedArray<RegexKey, RustRegex, size_t(RegexKey::Count)>;
 | 
						|
  RegexWrapperArray mRegexes;
 | 
						|
};
 | 
						|
 | 
						|
FormAutofillImpl::FormAutofillImpl() {
 | 
						|
  const Rule* rulesets[] = {&kFirefoxRules[0], &kCreditCardRules[0]};
 | 
						|
  size_t rulesetLengths[] = {ArrayLength(kFirefoxRules),
 | 
						|
                             ArrayLength(kCreditCardRules)};
 | 
						|
 | 
						|
  for (uint32_t i = 0; i < ArrayLength(rulesetLengths); ++i) {
 | 
						|
    for (uint32_t j = 0; j < rulesetLengths[i]; ++j) {
 | 
						|
      nsCString& rule = mRuleMap[rulesets[i][j].key];
 | 
						|
      if (!rule.IsEmpty()) {
 | 
						|
        rule.Append("|");
 | 
						|
      }
 | 
						|
      rule.Append(rulesets[i][j].pattern);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
const RustRegex& FormAutofillImpl::GetRegex(RegexKey aKey) {
 | 
						|
  if (!mRegexes[aKey]) {
 | 
						|
    RustRegex regex(mRuleMap[aKey], RustRegexOptions().CaseInsensitive(true));
 | 
						|
    MOZ_DIAGNOSTIC_ASSERT(regex);
 | 
						|
    mRegexes[aKey] = std::move(regex);
 | 
						|
  }
 | 
						|
  return mRegexes[aKey];
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::StringMatchesRegExp(const nsACString& aStr,
 | 
						|
                                           RegexKey aKey) {
 | 
						|
  return GetRegex(aKey).IsMatch(aStr);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::StringMatchesRegExp(const nsAString& aStr,
 | 
						|
                                           RegexKey aKey) {
 | 
						|
  return StringMatchesRegExp(NS_ConvertUTF16toUTF8(aStr), aKey);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::TextContentMatchesRegExp(Element& element,
 | 
						|
                                                RegexKey key) {
 | 
						|
  ErrorResult rv;
 | 
						|
  nsAutoString text;
 | 
						|
  element.GetTextContent(text, rv);
 | 
						|
  if (rv.Failed()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return StringMatchesRegExp(text, key);
 | 
						|
}
 | 
						|
 | 
						|
size_t FormAutofillImpl::CountRegExpMatches(const nsACString& aStr,
 | 
						|
                                            RegexKey aKey) {
 | 
						|
  return GetRegex(aKey).CountMatches(aStr);
 | 
						|
}
 | 
						|
 | 
						|
size_t FormAutofillImpl::CountRegExpMatches(const nsAString& aStr,
 | 
						|
                                            RegexKey aKey) {
 | 
						|
  return CountRegExpMatches(NS_ConvertUTF16toUTF8(aStr), aKey);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::NextFieldMatchesExpYearAutocomplete(
 | 
						|
    Element* aNextField) {
 | 
						|
  return AutocompleteStringMatches(*aNextField, u"cc-exp-year"_ns);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::PreviousFieldMatchesExpMonthAutocomplete(
 | 
						|
    Element* aPrevField) {
 | 
						|
  return AutocompleteStringMatches(*aPrevField, u"cc-exp-month"_ns);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::IdOrNameMatchRegExp(Element& aElement, RegexKey key) {
 | 
						|
  nsAutoString str;
 | 
						|
  aElement.GetId(str);
 | 
						|
  if (StringMatchesRegExp(str, key)) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  aElement.GetAttr(nsGkAtoms::name, str);
 | 
						|
  return StringMatchesRegExp(str, key);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::LabelMatchesRegExp(
 | 
						|
    Element& aElement, const nsTArray<nsCString>* labelStrings, RegexKey key) {
 | 
						|
  if (labelStrings) {
 | 
						|
    for (const auto& str : *labelStrings) {
 | 
						|
      if (StringMatchesRegExp(str, key)) {
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Element* parent = aElement.GetParentElement();
 | 
						|
  if (!parent) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  ErrorResult aRv;
 | 
						|
  if (parent->IsHTMLElement(nsGkAtoms::td)) {
 | 
						|
    Element* pp = parent->GetParentElement();
 | 
						|
    if (pp) {
 | 
						|
      return TextContentMatchesRegExp(*pp, key);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (parent->IsHTMLElement(nsGkAtoms::td)) {
 | 
						|
    Element* pes = aElement.GetPreviousElementSibling();
 | 
						|
    if (pes) {
 | 
						|
      return TextContentMatchesRegExp(*pes, key);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::ClosestLabelMatchesRegExp(Element& aElement,
 | 
						|
                                                 RegexKey aKey) {
 | 
						|
  ErrorResult aRv;
 | 
						|
  Element* pes = aElement.GetPreviousElementSibling();
 | 
						|
  if (pes && pes->IsHTMLElement(nsGkAtoms::label)) {
 | 
						|
    return TextContentMatchesRegExp(*pes, aKey);
 | 
						|
  }
 | 
						|
 | 
						|
  Element* nes = aElement.GetNextElementSibling();
 | 
						|
  if (nes && nes->IsHTMLElement(nsGkAtoms::label)) {
 | 
						|
    return TextContentMatchesRegExp(*nes, aKey);
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::PlaceholderMatchesRegExp(Element& aElement,
 | 
						|
                                                RegexKey aKey) {
 | 
						|
  nsAutoString str;
 | 
						|
  if (!aElement.GetAttr(nsGkAtoms::placeholder, str)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return StringMatchesRegExp(str, aKey);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::AriaLabelMatchesRegExp(Element& aElement,
 | 
						|
                                              RegexKey aKey) {
 | 
						|
  nsAutoString str;
 | 
						|
  if (!aElement.GetAttr(nsGkAtoms::aria_label, str)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return StringMatchesRegExp(str, aKey);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::AutocompleteStringMatches(Element& aElement,
 | 
						|
                                                 const nsAString& aKey) {
 | 
						|
  Nullable<AutocompleteInfo> info;
 | 
						|
  if (auto* input = HTMLInputElement::FromNode(aElement)) {
 | 
						|
    input->GetAutocompleteInfo(info);
 | 
						|
  } else {
 | 
						|
    AutocompleteInfo autoInfo;
 | 
						|
    if (auto* select = HTMLSelectElement::FromNode(aElement)) {
 | 
						|
      select->GetAutocompleteInfo(autoInfo);
 | 
						|
      info.SetValue(autoInfo);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (info.IsNull()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return info.Value().mFieldName.Equals(aKey);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::HasTemplatedValue(Element& aElement) {
 | 
						|
  nsAutoString str;
 | 
						|
  if (!aElement.GetAttr(nsGkAtoms::value, str)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return StringMatchesRegExp(str, RegexKey::TEMPLATED_VALUE);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::RoleIsMenu(Element& aElement) {
 | 
						|
  return aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::role,
 | 
						|
                              nsGkAtoms::menu, eCaseMatters);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::InputTypeNotNumbery(Element& aElement) {
 | 
						|
  auto* input = HTMLInputElement::FromNode(aElement);
 | 
						|
  if (!input) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  auto type = input->ControlType();
 | 
						|
  return type != FormControlType::InputText &&
 | 
						|
         type != FormControlType::InputTel &&
 | 
						|
         type != FormControlType::InputNumber;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::IsSelectWithCreditCardOptions(Element& aElement) {
 | 
						|
  auto* select = HTMLSelectElement::FromNode(aElement);
 | 
						|
  if (!select) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIHTMLCollection> options = select->Options();
 | 
						|
  for (uint32_t i = 0; i < options->Length(); ++i) {
 | 
						|
    auto* item = options->Item(i);
 | 
						|
    auto* option = HTMLOptionElement::FromNode(item);
 | 
						|
    if (!option) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    // Bug 1756799, consider using getAttribute("value") instead of .value
 | 
						|
    nsAutoString str;
 | 
						|
    option->GetValue(str);
 | 
						|
    if (StringMatchesRegExp(str, RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH) ||
 | 
						|
        StringMatchesRegExp(str, RegexKey::CREDIT_CARD_NETWORK_LONG)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    option->GetText(str);
 | 
						|
    if (StringMatchesRegExp(str, RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH) ||
 | 
						|
        StringMatchesRegExp(str, RegexKey::CREDIT_CARD_NETWORK_LONG)) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::IsRadioWithCreditCardText(
 | 
						|
    Element& aElement, const nsTArray<nsCString>* aLabels, ErrorResult& aRv) {
 | 
						|
  auto* input = HTMLInputElement::FromNode(aElement);
 | 
						|
  if (!input) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  auto type = input->ControlType();
 | 
						|
  if (type != FormControlType::InputRadio) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  nsAutoString str;
 | 
						|
  input->GetValue(str, CallerType::System);
 | 
						|
  if (CountRegExpMatches(str, RegexKey::CREDIT_CARD_NETWORK) == 1) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aLabels) {
 | 
						|
    size_t labelsMatched = 0;
 | 
						|
    for (const auto& label : *aLabels) {
 | 
						|
      size_t labelMatches =
 | 
						|
          CountRegExpMatches(label, RegexKey::CREDIT_CARD_NETWORK);
 | 
						|
      if (labelMatches > 1) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      if (labelMatches > 0) {
 | 
						|
        labelsMatched++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (labelsMatched) {
 | 
						|
      return labelsMatched == 1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Bug 1756798 : Remove reading text content in a <input>
 | 
						|
  nsAutoString text;
 | 
						|
  aElement.GetTextContent(text, aRv);
 | 
						|
  if (aRv.Failed()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return CountRegExpMatches(text, RegexKey::CREDIT_CARD_NETWORK) == 1;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::MaxLengthIs(Element& aElement, int32_t aValue) {
 | 
						|
  auto* input = HTMLInputElement::FromNode(aElement);
 | 
						|
  if (!input) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return input->MaxLength() == aValue;
 | 
						|
}
 | 
						|
 | 
						|
static bool TestOptionElementForInteger(Element* aElement, int32_t aTestValue) {
 | 
						|
  auto* option = HTMLOptionElement::FromNodeOrNull(aElement);
 | 
						|
  if (!option) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  nsAutoString str;
 | 
						|
  option->GetValue(str);
 | 
						|
  nsContentUtils::ParseHTMLIntegerResultFlags parseFlags;
 | 
						|
  int32_t val = nsContentUtils::ParseHTMLInteger(str, &parseFlags);
 | 
						|
  if (val == aTestValue) {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  option->GetRenderedLabel(str);
 | 
						|
  val = nsContentUtils::ParseHTMLInteger(str, &parseFlags);
 | 
						|
  return val == aTestValue;
 | 
						|
}
 | 
						|
 | 
						|
static bool MatchOptionContiguousInteger(HTMLOptionsCollection* aOptions,
 | 
						|
                                         uint32_t aNumContiguous,
 | 
						|
                                         int32_t aInteger) {
 | 
						|
  uint32_t len = aOptions->Length();
 | 
						|
  if (aNumContiguous > len) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  for (uint32_t i = 0; i <= aOptions->Length() - aNumContiguous; i++) {
 | 
						|
    bool match = true;
 | 
						|
    for (uint32_t j = 0; j < aNumContiguous; j++) {
 | 
						|
      if (!TestOptionElementForInteger(aOptions->GetElementAt(i + j),
 | 
						|
                                       aInteger + j)) {
 | 
						|
        match = false;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (match) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::IsExpirationYearLikely(Element& aElement) {
 | 
						|
  auto* select = HTMLSelectElement::FromNode(aElement);
 | 
						|
  if (!select) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* options = select->Options();
 | 
						|
  if (!options) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  PRExplodedTime tm;
 | 
						|
  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tm);
 | 
						|
  uint16_t currentYear = tm.tm_year;
 | 
						|
 | 
						|
  return MatchOptionContiguousInteger(options, 3, currentYear);
 | 
						|
}
 | 
						|
 | 
						|
bool FormAutofillImpl::IsExpirationMonthLikely(Element& aElement) {
 | 
						|
  auto* select = HTMLSelectElement::FromNode(aElement);
 | 
						|
  if (!select) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  auto* options = select->Options();
 | 
						|
  if (!options) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  if (options->Length() != 12 && options->Length() != 13) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return MatchOptionContiguousInteger(options, 12, 1);
 | 
						|
}
 | 
						|
 | 
						|
Element* FormAutofillImpl::FindRootForField(Element* aElement) {
 | 
						|
  if (const auto* control =
 | 
						|
          nsGenericHTMLFormControlElement::FromNode(aElement)) {
 | 
						|
    if (Element* form = control->GetForm()) {
 | 
						|
      return form;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return aElement->OwnerDoc()->GetDocumentElement();
 | 
						|
}
 | 
						|
 | 
						|
Element* FormAutofillImpl::FindField(
 | 
						|
    const Sequence<OwningNonNull<Element>>& aElements, uint32_t aStartIndex,
 | 
						|
    int8_t aDirection) {
 | 
						|
  MOZ_ASSERT(aDirection == 1 || aDirection == -1);
 | 
						|
  MOZ_ASSERT(aStartIndex < aElements.Length());
 | 
						|
 | 
						|
  Element* curFieldRoot = FindRootForField(aElements[aStartIndex]);
 | 
						|
  bool isRootForm = curFieldRoot->IsHTMLElement(nsGkAtoms::form);
 | 
						|
 | 
						|
  uint32_t num =
 | 
						|
      aDirection == 1 ? aElements.Length() - aStartIndex - 1 : aStartIndex;
 | 
						|
  for (uint32_t i = 0, searchIndex = aStartIndex; i < num; i++) {
 | 
						|
    searchIndex += aDirection;
 | 
						|
    const auto& element = aElements[searchIndex];
 | 
						|
    Element* root = FindRootForField(element);
 | 
						|
 | 
						|
    if (isRootForm) {
 | 
						|
      // Only search fields that are within the same root element.
 | 
						|
      if (curFieldRoot != root) {
 | 
						|
        return nullptr;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      // Exclude elements inside the rootElement that are already in a <form>.
 | 
						|
      if (root->IsHTMLElement(nsGkAtoms::form)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (element->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::select)) {
 | 
						|
      return element.get();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
Element* FormAutofillImpl::NextField(
 | 
						|
    const Sequence<OwningNonNull<Element>>& aElements, uint32_t aStartIndex) {
 | 
						|
  return FindField(aElements, aStartIndex, 1);
 | 
						|
}
 | 
						|
 | 
						|
Element* FormAutofillImpl::PrevField(
 | 
						|
    const Sequence<OwningNonNull<Element>>& aElements, uint32_t aStartIndex) {
 | 
						|
  return FindField(aElements, aStartIndex, -1);
 | 
						|
}
 | 
						|
 | 
						|
static void ExtractLabelStrings(nsINode* aNode, nsTArray<nsCString>& aStrings,
 | 
						|
                                ErrorResult& aRv) {
 | 
						|
  if (aNode->IsAnyOfHTMLElements(nsGkAtoms::script, nsGkAtoms::noscript,
 | 
						|
                                 nsGkAtoms::option, nsGkAtoms::style)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (aNode->IsText() || !aNode->HasChildren()) {
 | 
						|
    nsAutoString text;
 | 
						|
    aNode->GetTextContent(text, aRv);
 | 
						|
    if (aRv.Failed()) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    text.Trim(kWhitespace);
 | 
						|
    CopyUTF16toUTF8(text, *aStrings.AppendElement());
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  for (nsINode* child = aNode->GetFirstChild(); child;
 | 
						|
       child = child->GetNextSibling()) {
 | 
						|
    if (child->IsElement() || child->IsText()) {
 | 
						|
      ExtractLabelStrings(child, aStrings, aRv);
 | 
						|
      if (aRv.Failed()) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
nsTArray<nsCString>* GetLabelStrings(
 | 
						|
    Element* aElement,
 | 
						|
    const nsTHashMap<void*, nsTArray<nsCString>>& aElementMap,
 | 
						|
    const nsTHashMap<nsAtom*, nsTArray<nsCString>>& aIdMap) {
 | 
						|
  if (!aElement) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  if (nsAtom* idAtom = aElement->GetID()) {
 | 
						|
    return aIdMap.Lookup(idAtom).DataPtrOrNull();
 | 
						|
  }
 | 
						|
 | 
						|
  return aElementMap.Lookup(aElement).DataPtrOrNull();
 | 
						|
}
 | 
						|
 | 
						|
void FormAutofillImpl::GetFormAutofillConfidences(
 | 
						|
    GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
    nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
 | 
						|
  if (aElements.IsEmpty()) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Create Labels
 | 
						|
  auto* document = aElements[0]->OwnerDoc();
 | 
						|
#ifdef DEBUG
 | 
						|
  for (uint32_t i = 1; i < aElements.Length(); ++i) {
 | 
						|
    MOZ_ASSERT(document == aElements[i]->OwnerDoc());
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  RefPtr<nsContentList> labels = document->GetElementsByTagName(u"label"_ns);
 | 
						|
  nsTHashMap<void*, nsTArray<nsCString>> elementsToLabelStrings;
 | 
						|
  nsTHashMap<nsAtom*, nsTArray<nsCString>> elementsIdToLabelStrings;
 | 
						|
  if (labels) {
 | 
						|
    for (uint32_t i = 0; i < labels->Length(); ++i) {
 | 
						|
      auto* item = labels->Item(i);
 | 
						|
      auto* label = HTMLLabelElement::FromNode(item);
 | 
						|
      if (NS_WARN_IF(!label)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      auto* control = label->GetControl();
 | 
						|
      if (!control) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      nsTArray<nsCString> labelStrings;
 | 
						|
      ExtractLabelStrings(label, labelStrings, aRv);
 | 
						|
      if (aRv.Failed()) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // We need two maps here to keep track controls with id and without id.
 | 
						|
      // We can't just use map without id to cover all cases  because there
 | 
						|
      // might be multiple elements with the same id.
 | 
						|
      if (control->GetID()) {
 | 
						|
        elementsIdToLabelStrings.LookupOrInsert(control->GetID())
 | 
						|
            .AppendElements(std::move(labelStrings));
 | 
						|
      } else {
 | 
						|
        elementsToLabelStrings.LookupOrInsert(control).AppendElements(
 | 
						|
            std::move(labelStrings));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  nsTArray<AutofillParams> paramSet;
 | 
						|
  paramSet.SetLength(aElements.Length());
 | 
						|
 | 
						|
  for (uint32_t i = 0; i < aElements.Length(); ++i) {
 | 
						|
    auto& params = paramSet[i];
 | 
						|
    const auto& element = aElements[i];
 | 
						|
 | 
						|
    const nsTArray<nsCString>* labelStrings = GetLabelStrings(
 | 
						|
        element, elementsToLabelStrings, elementsIdToLabelStrings);
 | 
						|
 | 
						|
    bool idOrNameMatchDwfrmAndBml =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::DWFRM) &&
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::BML);
 | 
						|
    bool hasTemplatedValue = HasTemplatedValue(element);
 | 
						|
    bool inputTypeNotNumbery = InputTypeNotNumbery(element);
 | 
						|
    bool idOrNameMatchSubscription =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::SUBSCRIPTION);
 | 
						|
    bool idOrNameMatchFirstAndLast =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::FIRST) &&
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::LAST);
 | 
						|
 | 
						|
#define RULE_IMPL2(rule, type) params.m##type##Params[type##Params::rule]
 | 
						|
#define RULE_IMPL(rule, type) RULE_IMPL2(rule, type)
 | 
						|
#define RULE(rule) RULE_IMPL(rule, RULE_TYPE)
 | 
						|
 | 
						|
    // cc-number
 | 
						|
#define RULE_TYPE CCNumber
 | 
						|
    RULE(idOrNameMatchNumberRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_NUMBER);
 | 
						|
    RULE(labelsMatchNumberRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_NUMBER);
 | 
						|
    RULE(closestLabelMatchesNumberRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_NUMBER);
 | 
						|
    RULE(placeholderMatchesNumberRegExp) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::CC_NUMBER);
 | 
						|
    RULE(ariaLabelMatchesNumberRegExp) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::CC_NUMBER);
 | 
						|
    RULE(idOrNameMatchGift) = IdOrNameMatchRegExp(element, RegexKey::GIFT);
 | 
						|
    RULE(labelsMatchGift) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::GIFT);
 | 
						|
    RULE(placeholderMatchesGift) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::GIFT);
 | 
						|
    RULE(ariaLabelMatchesGift) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::GIFT);
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
    RULE(inputTypeNotNumbery) = inputTypeNotNumbery;
 | 
						|
#undef RULE_TYPE
 | 
						|
 | 
						|
    // cc-name
 | 
						|
#define RULE_TYPE CCName
 | 
						|
    RULE(idOrNameMatchNameRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_NAME);
 | 
						|
    RULE(labelsMatchNameRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_NAME);
 | 
						|
    RULE(closestLabelMatchesNameRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_NAME);
 | 
						|
    RULE(placeholderMatchesNameRegExp) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::CC_NAME);
 | 
						|
    RULE(ariaLabelMatchesNameRegExp) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::CC_NAME);
 | 
						|
    RULE(idOrNameMatchFirst) = IdOrNameMatchRegExp(element, RegexKey::FIRST);
 | 
						|
    RULE(labelsMatchFirst) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::FIRST);
 | 
						|
    RULE(placeholderMatchesFirst) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::FIRST);
 | 
						|
    RULE(ariaLabelMatchesFirst) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::FIRST);
 | 
						|
    RULE(idOrNameMatchLast) = IdOrNameMatchRegExp(element, RegexKey::LAST);
 | 
						|
    RULE(labelsMatchLast) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::LAST);
 | 
						|
    RULE(placeholderMatchesLast) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::LAST);
 | 
						|
    RULE(ariaLabelMatchesLast) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::LAST);
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchFirstAndLast) = idOrNameMatchFirstAndLast;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
#undef RULE_TYPE
 | 
						|
 | 
						|
    // We only use Fathom to detect cc-number & cc-name fields for now.
 | 
						|
    // Comment out code below instead of removing them to make it clear that
 | 
						|
    // the current design is to support multiple rules.
 | 
						|
/*
 | 
						|
    Element* nextFillableField = NextField(aElements, i);
 | 
						|
    Element* prevFillableField = PrevField(aElements, i);
 | 
						|
 | 
						|
    const nsTArray<nsCString>* nextLabelStrings = GetLabelStrings(
 | 
						|
        nextFillableField, elementsToLabelStrings, elementsIdToLabelStrings);
 | 
						|
    const nsTArray<nsCString>* prevLabelStrings = GetLabelStrings(
 | 
						|
        prevFillableField, elementsToLabelStrings, elementsIdToLabelStrings);
 | 
						|
    bool roleIsMenu = RoleIsMenu(element);
 | 
						|
 | 
						|
    // cc-type
 | 
						|
#define RULE_TYPE CCType
 | 
						|
    RULE(idOrNameMatchTypeRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_TYPE);
 | 
						|
    RULE(labelsMatchTypeRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_TYPE);
 | 
						|
    RULE(closestLabelMatchesTypeRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_TYPE);
 | 
						|
    RULE(idOrNameMatchVisaCheckout) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::VISA_CHECKOUT);
 | 
						|
    RULE(ariaLabelMatchesVisaCheckout) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::VISA_CHECKOUT);
 | 
						|
    RULE(isSelectWithCreditCardOptions) =
 | 
						|
        IsSelectWithCreditCardOptions(element);
 | 
						|
    RULE(isRadioWithCreditCardText) =
 | 
						|
        IsRadioWithCreditCardText(element, labelStrings, aRv);
 | 
						|
    if (aRv.Failed()) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
#undef RULE_TYPE
 | 
						|
 | 
						|
    // cc-exp
 | 
						|
#define RULE_TYPE CCExp
 | 
						|
    RULE(labelsMatchExpRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP);
 | 
						|
    RULE(closestLabelMatchesExpRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP);
 | 
						|
    RULE(placeholderMatchesExpRegExp) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::CC_EXP);
 | 
						|
    RULE(labelsMatchExpWith2Or4DigitYear) = LabelMatchesRegExp(
 | 
						|
        element, labelStrings, RegexKey::TWO_OR_FOUR_DIGIT_YEAR);
 | 
						|
    RULE(placeholderMatchesExpWith2Or4DigitYear) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::TWO_OR_FOUR_DIGIT_YEAR);
 | 
						|
    RULE(labelsMatchMMYY) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::MMYY);
 | 
						|
    RULE(placeholderMatchesMMYY) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::MMYY);
 | 
						|
    RULE(maxLengthIs7) = MaxLengthIs(element, 7);
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
    RULE(isExpirationMonthLikely) = IsExpirationMonthLikely(element);
 | 
						|
    RULE(isExpirationYearLikely) = IsExpirationYearLikely(element);
 | 
						|
    RULE(idOrNameMatchMonth) = IdOrNameMatchRegExp(element, RegexKey::MONTH);
 | 
						|
    RULE(idOrNameMatchYear) = IdOrNameMatchRegExp(element, RegexKey::YEAR);
 | 
						|
    RULE(idOrNameMatchExpMonthRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(idOrNameMatchExpYearRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(idOrNameMatchValidation) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::VALIDATION);
 | 
						|
#undef RULE_TYPE
 | 
						|
 | 
						|
    // cc-exp-month
 | 
						|
#define RULE_TYPE CCExpMonth
 | 
						|
    RULE(idOrNameMatchExpMonthRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(labelsMatchExpMonthRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(closestLabelMatchesExpMonthRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(placeholderMatchesExpMonthRegExp) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(ariaLabelMatchesExpMonthRegExp) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(idOrNameMatchMonth) = IdOrNameMatchRegExp(element, RegexKey::MONTH);
 | 
						|
    RULE(labelsMatchMonth) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::MONTH);
 | 
						|
    RULE(placeholderMatchesMonth) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::MONTH);
 | 
						|
    RULE(ariaLabelMatchesMonth) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::MONTH);
 | 
						|
    RULE(nextFieldIdOrNameMatchExpYearRegExp) =
 | 
						|
        nextFillableField &&
 | 
						|
        IdOrNameMatchRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(nextFieldLabelsMatchExpYearRegExp) =
 | 
						|
        nextFillableField &&
 | 
						|
        LabelMatchesRegExp(element, nextLabelStrings, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(nextFieldPlaceholderMatchExpYearRegExp) =
 | 
						|
        nextFillableField &&
 | 
						|
        PlaceholderMatchesRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(nextFieldAriaLabelMatchExpYearRegExp) =
 | 
						|
        nextFillableField &&
 | 
						|
        AriaLabelMatchesRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(nextFieldIdOrNameMatchYear) =
 | 
						|
        nextFillableField &&
 | 
						|
        IdOrNameMatchRegExp(*nextFillableField, RegexKey::YEAR);
 | 
						|
    RULE(nextFieldLabelsMatchYear) =
 | 
						|
        nextFillableField &&
 | 
						|
        LabelMatchesRegExp(element, nextLabelStrings, RegexKey::YEAR);
 | 
						|
    RULE(nextFieldPlaceholderMatchesYear) =
 | 
						|
        nextFillableField &&
 | 
						|
        PlaceholderMatchesRegExp(*nextFillableField, RegexKey::YEAR);
 | 
						|
    RULE(nextFieldAriaLabelMatchesYear) =
 | 
						|
        nextFillableField &&
 | 
						|
        AriaLabelMatchesRegExp(*nextFillableField, RegexKey::YEAR);
 | 
						|
    RULE(nextFieldMatchesExpYearAutocomplete) =
 | 
						|
        nextFillableField &&
 | 
						|
        NextFieldMatchesExpYearAutocomplete(nextFillableField);
 | 
						|
    RULE(isExpirationMonthLikely) = IsExpirationMonthLikely(element);
 | 
						|
    RULE(nextFieldIsExpirationYearLikely) =
 | 
						|
        nextFillableField && IsExpirationYearLikely(*nextFillableField);
 | 
						|
    RULE(maxLengthIs2) = MaxLengthIs(element, 2);
 | 
						|
    RULE(placeholderMatchesMM) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::MM_MONTH);
 | 
						|
    RULE(roleIsMenu) = roleIsMenu;
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
#undef RULE_TYPE
 | 
						|
 | 
						|
    // cc-exp-year
 | 
						|
#define RULE_TYPE CCExpYear
 | 
						|
    RULE(idOrNameMatchExpYearRegExp) =
 | 
						|
        IdOrNameMatchRegExp(element, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(labelsMatchExpYearRegExp) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(closestLabelMatchesExpYearRegExp) =
 | 
						|
        ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(placeholderMatchesExpYearRegExp) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(ariaLabelMatchesExpYearRegExp) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
 | 
						|
    RULE(idOrNameMatchYear) = IdOrNameMatchRegExp(element, RegexKey::YEAR);
 | 
						|
    RULE(labelsMatchYear) =
 | 
						|
        LabelMatchesRegExp(element, labelStrings, RegexKey::YEAR);
 | 
						|
    RULE(placeholderMatchesYear) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::YEAR);
 | 
						|
    RULE(ariaLabelMatchesYear) =
 | 
						|
        AriaLabelMatchesRegExp(element, RegexKey::YEAR);
 | 
						|
    RULE(previousFieldIdOrNameMatchExpMonthRegExp) =
 | 
						|
        prevFillableField &&
 | 
						|
        IdOrNameMatchRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(previousFieldLabelsMatchExpMonthRegExp) =
 | 
						|
        prevFillableField &&
 | 
						|
        LabelMatchesRegExp(element, prevLabelStrings, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(previousFieldPlaceholderMatchExpMonthRegExp) =
 | 
						|
        prevFillableField &&
 | 
						|
        PlaceholderMatchesRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(previousFieldAriaLabelMatchExpMonthRegExp) =
 | 
						|
        prevFillableField &&
 | 
						|
        AriaLabelMatchesRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
 | 
						|
    RULE(previousFieldIdOrNameMatchMonth) =
 | 
						|
        prevFillableField &&
 | 
						|
        IdOrNameMatchRegExp(*prevFillableField, RegexKey::MONTH);
 | 
						|
    RULE(previousFieldLabelsMatchMonth) =
 | 
						|
        prevFillableField &&
 | 
						|
        LabelMatchesRegExp(element, prevLabelStrings, RegexKey::MONTH);
 | 
						|
    RULE(previousFieldPlaceholderMatchesMonth) =
 | 
						|
        prevFillableField &&
 | 
						|
        PlaceholderMatchesRegExp(*prevFillableField, RegexKey::MONTH);
 | 
						|
    RULE(previousFieldAriaLabelMatchesMonth) =
 | 
						|
        prevFillableField &&
 | 
						|
        AriaLabelMatchesRegExp(*prevFillableField, RegexKey::MONTH);
 | 
						|
    RULE(previousFieldMatchesExpMonthAutocomplete) =
 | 
						|
        prevFillableField &&
 | 
						|
        PreviousFieldMatchesExpMonthAutocomplete(prevFillableField);
 | 
						|
    RULE(isExpirationYearLikely) = IsExpirationYearLikely(element);
 | 
						|
    RULE(previousFieldIsExpirationMonthLikely) =
 | 
						|
        prevFillableField && IsExpirationMonthLikely(*prevFillableField);
 | 
						|
    RULE(placeholderMatchesYYOrYYYY) =
 | 
						|
        PlaceholderMatchesRegExp(element, RegexKey::YY_OR_YYYY);
 | 
						|
    RULE(roleIsMenu) = roleIsMenu;
 | 
						|
    RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
 | 
						|
    RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
 | 
						|
    RULE(hasTemplatedValue) = hasTemplatedValue;
 | 
						|
#undef RULE_TYPE
 | 
						|
*/
 | 
						|
 | 
						|
#undef RULE_IMPL2
 | 
						|
#undef RULE_IMPL
 | 
						|
#undef RULE
 | 
						|
 | 
						|
#define CALCULATE_SCORE(type, score)                                        \
 | 
						|
  for (auto i : MakeEnumeratedRange(type##Params::Count)) {                 \
 | 
						|
    (score) += params.m##type##Params[i] * kCoefficents.m##type##Params[i]; \
 | 
						|
  }                                                                         \
 | 
						|
  (score) = Sigmoid(score + k##type##Bias);
 | 
						|
 | 
						|
    // Calculating the final score of each rule
 | 
						|
    FormAutofillConfidences score;
 | 
						|
    CALCULATE_SCORE(CCNumber, score.mCcNumber)
 | 
						|
    CALCULATE_SCORE(CCName, score.mCcName)
 | 
						|
 | 
						|
    // Comment out code that are not used right now
 | 
						|
    // CALCULATE_SCORE(CCType, score.mCcType)
 | 
						|
    // CALCULATE_SCORE(CCExp, score.mCcExp)
 | 
						|
    // CALCULATE_SCORE(CCExpMonth, score.mCcExpMonth)
 | 
						|
    // CALCULATE_SCORE(CCExpYear, score.mCcExpYear)
 | 
						|
 | 
						|
#undef CALCULATE_SCORE
 | 
						|
 | 
						|
    aResults.AppendElement(score);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static StaticAutoPtr<FormAutofillImpl> sFormAutofillInstance;
 | 
						|
 | 
						|
static FormAutofillImpl* GetFormAutofillImpl() {
 | 
						|
  if (!sFormAutofillInstance) {
 | 
						|
    sFormAutofillInstance = new FormAutofillImpl();
 | 
						|
    ClearOnShutdown(&sFormAutofillInstance);
 | 
						|
  }
 | 
						|
  return sFormAutofillInstance;
 | 
						|
}
 | 
						|
 | 
						|
/* static */
 | 
						|
void FormAutofillNative::GetFormAutofillConfidences(
 | 
						|
    GlobalObject& aGlobal, const Sequence<OwningNonNull<Element>>& aElements,
 | 
						|
    nsTArray<FormAutofillConfidences>& aResults, ErrorResult& aRv) {
 | 
						|
  GetFormAutofillImpl()->GetFormAutofillConfidences(aGlobal, aElements,
 | 
						|
                                                    aResults, aRv);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla::dom
 |