Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  FormAutofillNative.cpp   Sprache: 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[] = {std::size(kFirefoxRules),
                             std::size(kCreditCardRules)};

  for (uint32_t i = 0; i < std::size(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

Messung V0.5
C=86 H=93 G=89

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge