1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "FormAutofillNative.h"
10 #include "mozilla/ClearOnShutdown.h"
11 #include "mozilla/ComputedStyle.h"
12 #include "mozilla/dom/AutocompleteInfoBinding.h"
13 #include "mozilla/dom/Document.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/HTMLInputElement.h"
16 #include "mozilla/dom/HTMLLabelElement.h"
17 #include "mozilla/dom/HTMLOptionElement.h"
18 #include "mozilla/dom/HTMLSelectElement.h"
19 #include "mozilla/HashTable.h"
20 #include "mozilla/RustRegex.h"
21 #include "nsContentUtils.h"
23 #include "nsIFrameInlines.h"
24 #include "nsLayoutUtils.h"
25 #include "nsTStringHasher.h"
26 #include "mozilla/StaticPtr.h"
28 namespace mozilla::dom
{
30 static const char kWhitespace
[] = "\b\t\r\n ";
32 enum class RegexKey
: uint8_t {
46 CREDIT_CARD_NETWORK_EXACT_MATCH
,
47 CREDIT_CARD_NETWORK_LONG
,
48 TWO_OR_FOUR_DIGIT_YEAR
,
61 // We don't follow the coding style (naming start with capital letter) here and
62 // the following CCXXX enum class because we want to sync the rule naming with
63 // the JS implementation.
64 enum class CCNumberParams
: uint8_t {
65 idOrNameMatchNumberRegExp
,
66 labelsMatchNumberRegExp
,
67 closestLabelMatchesNumberRegExp
,
68 placeholderMatchesNumberRegExp
,
69 ariaLabelMatchesNumberRegExp
,
72 placeholderMatchesGift
,
74 idOrNameMatchSubscription
,
75 idOrNameMatchDwfrmAndBml
,
82 enum class CCNameParams
: uint8_t {
83 idOrNameMatchNameRegExp
,
84 labelsMatchNameRegExp
,
85 closestLabelMatchesNameRegExp
,
86 placeholderMatchesNameRegExp
,
87 ariaLabelMatchesNameRegExp
,
90 placeholderMatchesFirst
,
91 ariaLabelMatchesFirst
,
94 placeholderMatchesLast
,
96 idOrNameMatchFirstAndLast
,
97 idOrNameMatchSubscription
,
98 idOrNameMatchDwfrmAndBml
,
104 enum class CCTypeParams
: uint8_t {
105 idOrNameMatchTypeRegExp
,
106 labelsMatchTypeRegExp
,
107 closestLabelMatchesTypeRegExp
,
108 idOrNameMatchVisaCheckout
,
109 ariaLabelMatchesVisaCheckout
,
110 isSelectWithCreditCardOptions
,
111 isRadioWithCreditCardText
,
112 idOrNameMatchSubscription
,
113 idOrNameMatchDwfrmAndBml
,
119 enum class CCExpParams
: uint8_t {
120 labelsMatchExpRegExp
,
121 closestLabelMatchesExpRegExp
,
122 placeholderMatchesExpRegExp
,
123 labelsMatchExpWith2Or4DigitYear
,
124 placeholderMatchesExpWith2Or4DigitYear
,
126 placeholderMatchesMMYY
,
128 idOrNameMatchSubscription
,
129 idOrNameMatchDwfrmAndBml
,
131 isExpirationMonthLikely
,
132 isExpirationYearLikely
,
135 idOrNameMatchExpMonthRegExp
,
136 idOrNameMatchExpYearRegExp
,
137 idOrNameMatchValidation
,
141 enum class CCExpMonthParams
: uint8_t {
142 idOrNameMatchExpMonthRegExp
,
143 labelsMatchExpMonthRegExp
,
144 closestLabelMatchesExpMonthRegExp
,
145 placeholderMatchesExpMonthRegExp
,
146 ariaLabelMatchesExpMonthRegExp
,
149 placeholderMatchesMonth
,
150 ariaLabelMatchesMonth
,
151 nextFieldIdOrNameMatchExpYearRegExp
,
152 nextFieldLabelsMatchExpYearRegExp
,
153 nextFieldPlaceholderMatchExpYearRegExp
,
154 nextFieldAriaLabelMatchExpYearRegExp
,
155 nextFieldIdOrNameMatchYear
,
156 nextFieldLabelsMatchYear
,
157 nextFieldPlaceholderMatchesYear
,
158 nextFieldAriaLabelMatchesYear
,
159 nextFieldMatchesExpYearAutocomplete
,
160 isExpirationMonthLikely
,
161 nextFieldIsExpirationYearLikely
,
163 placeholderMatchesMM
,
165 idOrNameMatchSubscription
,
166 idOrNameMatchDwfrmAndBml
,
172 enum class CCExpYearParams
: uint8_t {
173 idOrNameMatchExpYearRegExp
,
174 labelsMatchExpYearRegExp
,
175 closestLabelMatchesExpYearRegExp
,
176 placeholderMatchesExpYearRegExp
,
177 ariaLabelMatchesExpYearRegExp
,
180 placeholderMatchesYear
,
181 ariaLabelMatchesYear
,
182 previousFieldIdOrNameMatchExpMonthRegExp
,
183 previousFieldLabelsMatchExpMonthRegExp
,
184 previousFieldPlaceholderMatchExpMonthRegExp
,
185 previousFieldAriaLabelMatchExpMonthRegExp
,
186 previousFieldIdOrNameMatchMonth
,
187 previousFieldLabelsMatchMonth
,
188 previousFieldPlaceholderMatchesMonth
,
189 previousFieldAriaLabelMatchesMonth
,
190 previousFieldMatchesExpMonthAutocomplete
,
191 isExpirationYearLikely
,
192 previousFieldIsExpirationMonthLikely
,
193 placeholderMatchesYYOrYYYY
,
195 idOrNameMatchSubscription
,
196 idOrNameMatchDwfrmAndBml
,
202 struct AutofillParams
{
203 EnumeratedArray
<CCNumberParams
, double, size_t(CCNumberParams::Count
)>
205 EnumeratedArray
<CCNameParams
, double, size_t(CCNameParams::Count
)>
207 EnumeratedArray
<CCTypeParams
, double, size_t(CCTypeParams::Count
)>
209 EnumeratedArray
<CCExpParams
, double, size_t(CCExpParams::Count
)> mCCExpParams
;
210 EnumeratedArray
<CCExpMonthParams
, double, size_t(CCExpMonthParams::Count
)>
212 EnumeratedArray
<CCExpYearParams
, double, size_t(CCExpYearParams::Count
)>
217 constexpr AutofillParams kCoefficents
{
219 /* idOrNameMatchNumberRegExp */ 7.679469585418701,
220 /* labelsMatchNumberRegExp */ 5.122580051422119,
221 /* closestLabelMatchesNumberRegExp */ 2.1256935596466064,
222 /* placeholderMatchesNumberRegExp */ 9.471800804138184,
223 /* ariaLabelMatchesNumberRegExp */ 6.067715644836426,
224 /* idOrNameMatchGift */ -22.946273803710938,
225 /* labelsMatchGift */ -7.852959632873535,
226 /* placeholderMatchesGift */ -2.355496406555176,
227 /* ariaLabelMatchesGift */ -2.940307855606079,
228 /* idOrNameMatchSubscription */ 0.11255314946174622,
229 /* idOrNameMatchDwfrmAndBml */ -0.0006645023822784424,
230 /* hasTemplatedValue */ -0.11370040476322174,
231 /* inputTypeNotNumbery */ -3.750155210494995
234 /* idOrNameMatchNameRegExp */ 7.496212959289551,
235 /* labelsMatchNameRegExp */ 6.081472873687744,
236 /* closestLabelMatchesNameRegExp */ 2.600574254989624,
237 /* placeholderMatchesNameRegExp */ 5.750874042510986,
238 /* ariaLabelMatchesNameRegExp */ 5.162227153778076,
239 /* idOrNameMatchFirst */ -6.742659091949463,
240 /* labelsMatchFirst */ -0.5234538912773132,
241 /* placeholderMatchesFirst */ -3.4615235328674316,
242 /* ariaLabelMatchesFirst */ -1.3145145177841187,
243 /* idOrNameMatchLast */ -12.561869621276855,
244 /* labelsMatchLast */ -0.27417105436325073,
245 /* placeholderMatchesLast */ -1.434966802597046,
246 /* ariaLabelMatchesLast */ -2.9319725036621094,
247 /* idOrNameMatchFirstAndLast */ 24.123435974121094,
248 /* idOrNameMatchSubscription */ 0.08349418640136719,
249 /* idOrNameMatchDwfrmAndBml */ 0.01882520318031311,
250 /* hasTemplatedValue */ 0.182317852973938
253 /* idOrNameMatchTypeRegExp */ 2.0581533908843994,
254 /* labelsMatchTypeRegExp */ 1.0784518718719482,
255 /* closestLabelMatchesTypeRegExp */ 0.6995877623558044,
256 /* idOrNameMatchVisaCheckout */ -3.320356845855713,
257 /* ariaLabelMatchesVisaCheckout */ -3.4196767807006836,
258 /* isSelectWithCreditCardOptions */ 10.337477684020996,
259 /* isRadioWithCreditCardText */ 4.530318737030029,
260 /* idOrNameMatchSubscription */ -3.7206356525421143,
261 /* idOrNameMatchDwfrmAndBml */ -0.08782318234443665,
262 /* hasTemplatedValue */ 0.1772511601448059
265 /* labelsMatchExpRegExp */ 7.588159561157227,
266 /* closestLabelMatchesExpRegExp */ 1.41484534740448,
267 /* placeholderMatchesExpRegExp */ 8.759064674377441,
268 /* labelsMatchExpWith2Or4DigitYear */ -3.876218795776367,
269 /* placeholderMatchesExpWith2Or4DigitYear */ 2.8364884853363037,
270 /* labelsMatchMMYY */ 8.836017608642578,
271 /* placeholderMatchesMMYY */ -0.5231751799583435,
272 /* maxLengthIs7 */ 1.3565447330474854,
273 /* idOrNameMatchSubscription */ 0.1779913753271103,
274 /* idOrNameMatchDwfrmAndBml */ 0.21037884056568146,
275 /* hasTemplatedValue */ 0.14900512993335724,
276 /* isExpirationMonthLikely */ -3.223409652709961,
277 /* isExpirationYearLikely */ -2.536919593811035,
278 /* idOrNameMatchMonth */ -3.6893014907836914,
279 /* idOrNameMatchYear */ -3.108184337615967,
280 /* idOrNameMatchExpMonthRegExp */ -2.264357089996338,
281 /* idOrNameMatchExpYearRegExp */ -2.7957723140716553,
282 /* idOrNameMatchValidation */ -2.29402756690979
284 .mCCExpMonthParams
= {
285 /* idOrNameMatchExpMonthRegExp */ 0.2787344455718994,
286 /* labelsMatchExpMonthRegExp */ 1.298413634300232,
287 /* closestLabelMatchesExpMonthRegExp */ -11.206244468688965,
288 /* placeholderMatchesExpMonthRegExp */ 1.2605619430541992,
289 /* ariaLabelMatchesExpMonthRegExp */ 1.1330018043518066,
290 /* idOrNameMatchMonth */ 6.1464314460754395,
291 /* labelsMatchMonth */ 0.7051732540130615,
292 /* placeholderMatchesMonth */ 0.7463492751121521,
293 /* ariaLabelMatchesMonth */ 1.8244760036468506,
294 /* nextFieldIdOrNameMatchExpYearRegExp */ 0.06347066164016724,
295 /* nextFieldLabelsMatchExpYearRegExp */ -0.1692247837781906,
296 /* nextFieldPlaceholderMatchExpYearRegExp */ 1.0434566736221313,
297 /* nextFieldAriaLabelMatchExpYearRegExp */ 1.751156210899353,
298 /* nextFieldIdOrNameMatchYear */ -0.532447338104248,
299 /* nextFieldLabelsMatchYear */ 1.3248541355133057,
300 /* nextFieldPlaceholderMatchesYear */ 0.604235827922821,
301 /* nextFieldAriaLabelMatchesYear */ 1.5364223718643188,
302 /* nextFieldMatchesExpYearAutocomplete */ 6.285938262939453,
303 /* isExpirationMonthLikely */ 13.117807388305664,
304 /* nextFieldIsExpirationYearLikely */ 7.182341575622559,
305 /* maxLengthIs2 */ 4.477289199829102,
306 /* placeholderMatchesMM */ 14.403288841247559,
307 /* roleIsMenu */ 5.770959854125977,
308 /* idOrNameMatchSubscription */ -0.043085768818855286,
309 /* idOrNameMatchDwfrmAndBml */ 0.02823038399219513,
310 /* hasTemplatedValue */ 0.07234494388103485
312 .mCCExpYearParams
= {
313 /* idOrNameMatchExpYearRegExp */ 5.426016807556152,
314 /* labelsMatchExpYearRegExp */ 1.3240209817886353,
315 /* closestLabelMatchesExpYearRegExp */ -8.702284812927246,
316 /* placeholderMatchesExpYearRegExp */ 0.9059725999832153,
317 /* ariaLabelMatchesExpYearRegExp */ 0.5550334453582764,
318 /* idOrNameMatchYear */ 5.362994194030762,
319 /* labelsMatchYear */ 2.7185044288635254,
320 /* placeholderMatchesYear */ 0.7883157134056091,
321 /* ariaLabelMatchesYear */ 0.311492383480072,
322 /* previousFieldIdOrNameMatchExpMonthRegExp */ 1.8155208826065063,
323 /* previousFieldLabelsMatchExpMonthRegExp */ -0.46133187413215637,
324 /* previousFieldPlaceholderMatchExpMonthRegExp */ 1.0374903678894043,
325 /* previousFieldAriaLabelMatchExpMonthRegExp */ -0.5901495814323425,
326 /* previousFieldIdOrNameMatchMonth */ -5.960310935974121,
327 /* previousFieldLabelsMatchMonth */ 0.6495584845542908,
328 /* previousFieldPlaceholderMatchesMonth */ 0.7198042273521423,
329 /* previousFieldAriaLabelMatchesMonth */ 3.4590985774993896,
330 /* previousFieldMatchesExpMonthAutocomplete */ 2.986003875732422,
331 /* isExpirationYearLikely */ 4.021566390991211,
332 /* previousFieldIsExpirationMonthLikely */ 9.298635482788086,
333 /* placeholderMatchesYYOrYYYY */ 10.457176208496094,
334 /* roleIsMenu */ 1.1051956415176392,
335 /* idOrNameMatchSubscription */ 0.000688597559928894,
336 /* idOrNameMatchDwfrmAndBml */ 0.15687309205532074,
337 /* hasTemplatedValue */ -0.19141331315040588
342 constexpr float kCCNumberBias
= -4.948795795440674;
343 constexpr float kCCNameBias
= -5.3578081130981445;
344 // Comment out code that are not used right now
346 constexpr float kCCTypeBias = -5.979659557342529;
347 constexpr float kCCExpBias = -5.849575996398926;
348 constexpr float kCCExpMonthBias = -8.844199180603027;
349 constexpr float kCCExpYearBias = -6.499860763549805;
357 const Rule kFirefoxRules
[] = {
358 {RegexKey::MM_MONTH
, "^mm$|\\(mm\\)"},
359 {RegexKey::YY_OR_YYYY
, "^(yy|yyyy)$|\\(yy\\)|\\(yyyy\\)"},
360 {RegexKey::MONTH
, "month"},
361 {RegexKey::YEAR
, "year"},
362 {RegexKey::MMYY
, "mm\\s*(/|\\\\)\\s*yy"},
363 {RegexKey::VISA_CHECKOUT
, "visa(-|\\s)checkout"},
364 // This should be a union of NETWORK_NAMES in CreditCard.sys.mjs
365 {RegexKey::CREDIT_CARD_NETWORK_LONG
,
366 "american express|master card|union pay"},
367 // Please also update CREDIT_CARD_NETWORK_EXACT_MATCH while updating
368 // CREDIT_CARD_NETWORK
369 {RegexKey::CREDIT_CARD_NETWORK
,
370 "amex|cartebancaire|diners|discover|jcb|mastercard|mir|unionpay|visa"},
371 {RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH
,
372 "^\\s*(?:amex|cartebancaire|diners|discover|jcb|mastercard|mir|unionpay|"
374 {RegexKey::TWO_OR_FOUR_DIGIT_YEAR
,
375 "(?:exp.*date[^y\\\\n\\\\r]*|mm\\\\s*[-/]?\\\\s*)yy(?:yy)?(?:[^y]|$)"},
376 {RegexKey::DWFRM
, "^dwfrm"},
377 {RegexKey::BML
, "BML"},
378 {RegexKey::TEMPLATED_VALUE
, "^\\{\\{.*\\}\\}$"},
379 {RegexKey::FIRST
, "first"},
380 {RegexKey::LAST
, "last"},
381 {RegexKey::GIFT
, "gift"},
382 {RegexKey::SUBSCRIPTION
, "subscription"},
383 {RegexKey::VALIDATION
, "validate|validation"},
386 // These are the rules used by Bitwarden [0], converted into RegExp form.
388 // https://github.com/bitwarden/browser/blob/c2b8802201fac5e292d55d5caf3f1f78088d823c/src/services/autofill.service.ts#L436
389 const Rule kCreditCardRules
[] = {
391 // Let us keep our consistent wrapping.
393 // Firefox-specific rules
394 "account.*holder.*name"
395 "|^(credit[-\\s]?card|card).*name"
397 "|^(kredit)?(karten|konto)inhaber"
400 "|nom.*(titulaire|détenteur)"
401 "|(titulaire|détenteur).*(carte)"
407 "|nombre.*(titular|tarjeta)"
410 // Rules from Bitwarden
415 // Rules are from Chromium source codes
416 "|card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card"
417 "|(?:card|cc).?name|cc.?full.?name"
418 "|(?:card|cc).?owner"
419 "|nom.*carte" // fr-FR
420 "|nome.*cart" // it-IT
423 "|信用卡开户名|开户名|持卡人姓名" // zh-CN
427 {RegexKey::CC_NUMBER
,
428 // Firefox-specific rules
431 "|(kredit)?(karten)(nummer|nr)"
435 "|(numero|número|numéro).*(carte)"
439 "|(número|numero).*tarjeta"
442 // Rules from Bitwarden
452 // Rules are from Chromium source codes
453 "|(add)?(?:card|cc|acct).?(?:number|#|no|num)"
455 "|Номер.*карты" // ru
456 "|信用卡号|信用卡号码" // zh-CN
461 // Firefox-specific rules
462 "mm\\s*(/|\\|-)\\s*(yy|jj|aa)"
463 "|(month|mois)\\s*(/|\\|-|et)\\s*(year|année)"
466 // Rules from Bitwarden
469 "|(^cc-?expiration$)"
470 "|(^card-?expiration$)"
483 "|payment-?card-?expiration"
484 "|(^payment-?cc-?date$)"
485 // Rules are from Chromium source codes
486 "|expir|exp.*date|^expfield$"
487 "|ablaufdatum|gueltig|gültig" // de-DE
489 "|date.*exp" // fr-FR
492 "|validade" // pt-BR, pt-PT
493 "|Срок действия карты"}, // ru
495 {RegexKey::CC_EXP_MONTH
,
496 // Firefox-specific rules
497 "(cc|kk)month" // de-DE
498 // Rules from Bitwarden
500 "|(^cc-?exp-?month$)"
508 "|(^card-?expiration-?month$)"
509 "|(^expiration-?month$)"
522 "|(^card-?expire-?month$)"
523 "|(^card-?expire-?mo$)"
524 "|(^card-?expiry-?month$)"
525 "|(^card-?expiry-?mo$)"
526 "|(^mois-?validite$)"
527 "|(^mois-?expiration$)"
530 "|(^expiry-?date-?field-?month$)"
531 "|(^expiration-?date-?month$)"
532 "|(^expiration-?date-?mm$)"
536 "|(^cb-?date-?mois$)"
538 // Rules are from Chromium source codes
539 "|exp.*mo|ccmonth|cardmonth|addmonth"
542 // "|date.*exp" // fr-FR
543 // "|scadenza" // it-IT
545 // "|validade" // pt-BR, pt-PT
546 // "|Срок действия карты" // ru
549 {RegexKey::CC_EXP_YEAR
,
550 // Firefox-specific rules
551 "(cc|kk)year" // de-DE
552 // Rules from Bitwarden
562 "|(^card-?expiration-?year$)"
563 "|(^expiration-?year$)"
574 "|(^card-?exp-?yyyy$)"
580 "|(^card-?expire-?year$)"
581 "|(^card-?expire-?yr$)"
582 "|(^card-?expiry-?year$)"
583 "|(^card-?expiry-?yr$)"
585 "|(^an-?expiration$)"
586 "|(^annee-?validite$)"
587 "|(^annee-?expiration$)"
588 "|(^expiry-?date-?field-?year$)"
589 "|(^expiration-?date-?year$)"
591 "|(^expiration-?date-?yy$)"
592 "|(^expiration-?date-?yyyy$)"
593 "|(^validity-?year$)"
594 "|(^exp-?date-?year$)"
596 // Rules are from Chromium source codes
600 // "|scadenza" // it-IT
602 // "|validade" // pt-BR, pt-PT
603 // "|Срок действия карты" // ru
607 // Firefox-specific rules
611 // Rules from Bitwarden
617 // Rules are from Chromium source codes
620 static double Sigmoid(double x
) { return 1.0 / (1.0 + exp(-x
)); }
622 class FormAutofillImpl
{
626 void GetFormAutofillConfidences(
627 GlobalObject
& aGlobal
, const Sequence
<OwningNonNull
<Element
>>& aElements
,
628 nsTArray
<FormAutofillConfidences
>& aResults
, ErrorResult
& aRv
);
631 const RustRegex
& GetRegex(RegexKey key
);
633 bool StringMatchesRegExp(const nsACString
& str
, RegexKey key
);
634 bool StringMatchesRegExp(const nsAString
& str
, RegexKey key
);
635 bool TextContentMatchesRegExp(Element
& element
, RegexKey key
);
636 size_t CountRegExpMatches(const nsACString
& str
, RegexKey key
);
637 size_t CountRegExpMatches(const nsAString
& str
, RegexKey key
);
638 bool IdOrNameMatchRegExp(Element
& element
, RegexKey key
);
639 bool NextFieldMatchesExpYearAutocomplete(Element
* aNextField
);
640 bool PreviousFieldMatchesExpMonthAutocomplete(Element
* aPrevField
);
641 bool LabelMatchesRegExp(Element
& element
, const nsTArray
<nsCString
>* labels
,
643 bool ClosestLabelMatchesRegExp(Element
& aElement
, RegexKey aKey
);
644 bool PlaceholderMatchesRegExp(Element
& element
, RegexKey key
);
645 bool AriaLabelMatchesRegExp(Element
& element
, RegexKey key
);
646 bool AutocompleteStringMatches(Element
& aElement
, const nsAString
& aKey
);
648 bool HasTemplatedValue(Element
& element
);
649 bool MaxLengthIs(Element
& aElement
, int32_t aValue
);
650 bool IsExpirationMonthLikely(Element
& element
);
651 bool IsExpirationYearLikely(Element
& element
);
652 bool InputTypeNotNumbery(Element
& element
);
653 bool IsSelectWithCreditCardOptions(Element
& element
);
654 bool IsRadioWithCreditCardText(Element
& element
,
655 const nsTArray
<nsCString
>* labels
,
657 bool MatchesExpYearAutocomplete(Element
& element
);
658 bool RoleIsMenu(Element
& element
);
660 Element
* FindRootForField(Element
* aElement
);
662 Element
* FindField(const Sequence
<OwningNonNull
<Element
>>& aElements
,
663 uint32_t aStartIndex
, int8_t aDirection
);
664 Element
* NextField(const Sequence
<OwningNonNull
<Element
>>& aElements
,
665 uint32_t aStartIndex
);
666 Element
* PrevField(const Sequence
<OwningNonNull
<Element
>>& aElements
,
667 uint32_t aStartIndex
);
669 // Array contains regular expressions to match the corresponding
670 // field. Ex, CC number, CC type, etc.
671 using RegexStringArray
=
672 EnumeratedArray
<RegexKey
, nsCString
, size_t(RegexKey::Count
)>;
673 RegexStringArray mRuleMap
;
675 // Array that holds RegexWrapper that created by regex::ffi::regex_new
676 using RegexWrapperArray
= EnumeratedArray
<RegexKey
, RustRegex
, size_t(RegexKey::Count
)>;
677 RegexWrapperArray mRegexes
;
680 FormAutofillImpl::FormAutofillImpl() {
681 const Rule
* rulesets
[] = {&kFirefoxRules
[0], &kCreditCardRules
[0]};
682 size_t rulesetLengths
[] = {std::size(kFirefoxRules
),
683 std::size(kCreditCardRules
)};
685 for (uint32_t i
= 0; i
< std::size(rulesetLengths
); ++i
) {
686 for (uint32_t j
= 0; j
< rulesetLengths
[i
]; ++j
) {
687 nsCString
& rule
= mRuleMap
[rulesets
[i
][j
].key
];
688 if (!rule
.IsEmpty()) {
691 rule
.Append(rulesets
[i
][j
].pattern
);
696 const RustRegex
& FormAutofillImpl::GetRegex(RegexKey aKey
) {
697 if (!mRegexes
[aKey
]) {
698 RustRegex
regex(mRuleMap
[aKey
], RustRegexOptions().CaseInsensitive(true));
699 MOZ_DIAGNOSTIC_ASSERT(regex
);
700 mRegexes
[aKey
] = std::move(regex
);
702 return mRegexes
[aKey
];
705 bool FormAutofillImpl::StringMatchesRegExp(const nsACString
& aStr
,
707 return GetRegex(aKey
).IsMatch(aStr
);
710 bool FormAutofillImpl::StringMatchesRegExp(const nsAString
& aStr
,
712 return StringMatchesRegExp(NS_ConvertUTF16toUTF8(aStr
), aKey
);
715 bool FormAutofillImpl::TextContentMatchesRegExp(Element
& element
,
719 element
.GetTextContent(text
, rv
);
724 return StringMatchesRegExp(text
, key
);
727 size_t FormAutofillImpl::CountRegExpMatches(const nsACString
& aStr
,
729 return GetRegex(aKey
).CountMatches(aStr
);
732 size_t FormAutofillImpl::CountRegExpMatches(const nsAString
& aStr
,
734 return CountRegExpMatches(NS_ConvertUTF16toUTF8(aStr
), aKey
);
737 bool FormAutofillImpl::NextFieldMatchesExpYearAutocomplete(
738 Element
* aNextField
) {
739 return AutocompleteStringMatches(*aNextField
, u
"cc-exp-year"_ns
);
742 bool FormAutofillImpl::PreviousFieldMatchesExpMonthAutocomplete(
743 Element
* aPrevField
) {
744 return AutocompleteStringMatches(*aPrevField
, u
"cc-exp-month"_ns
);
747 bool FormAutofillImpl::IdOrNameMatchRegExp(Element
& aElement
, RegexKey key
) {
750 if (StringMatchesRegExp(str
, key
)) {
753 aElement
.GetAttr(nsGkAtoms::name
, str
);
754 return StringMatchesRegExp(str
, key
);
757 bool FormAutofillImpl::LabelMatchesRegExp(
758 Element
& aElement
, const nsTArray
<nsCString
>* labelStrings
, RegexKey key
) {
760 for (const auto& str
: *labelStrings
) {
761 if (StringMatchesRegExp(str
, key
)) {
767 Element
* parent
= aElement
.GetParentElement();
773 if (parent
->IsHTMLElement(nsGkAtoms::td
)) {
774 Element
* pp
= parent
->GetParentElement();
776 return TextContentMatchesRegExp(*pp
, key
);
779 if (parent
->IsHTMLElement(nsGkAtoms::td
)) {
780 Element
* pes
= aElement
.GetPreviousElementSibling();
782 return TextContentMatchesRegExp(*pes
, key
);
788 bool FormAutofillImpl::ClosestLabelMatchesRegExp(Element
& aElement
,
791 Element
* pes
= aElement
.GetPreviousElementSibling();
792 if (pes
&& pes
->IsHTMLElement(nsGkAtoms::label
)) {
793 return TextContentMatchesRegExp(*pes
, aKey
);
796 Element
* nes
= aElement
.GetNextElementSibling();
797 if (nes
&& nes
->IsHTMLElement(nsGkAtoms::label
)) {
798 return TextContentMatchesRegExp(*nes
, aKey
);
804 bool FormAutofillImpl::PlaceholderMatchesRegExp(Element
& aElement
,
807 if (!aElement
.GetAttr(nsGkAtoms::placeholder
, str
)) {
810 return StringMatchesRegExp(str
, aKey
);
813 bool FormAutofillImpl::AriaLabelMatchesRegExp(Element
& aElement
,
816 if (!aElement
.GetAttr(nsGkAtoms::aria_label
, str
)) {
819 return StringMatchesRegExp(str
, aKey
);
822 bool FormAutofillImpl::AutocompleteStringMatches(Element
& aElement
,
823 const nsAString
& aKey
) {
824 Nullable
<AutocompleteInfo
> info
;
825 if (auto* input
= HTMLInputElement::FromNode(aElement
)) {
826 input
->GetAutocompleteInfo(info
);
828 AutocompleteInfo autoInfo
;
829 if (auto* select
= HTMLSelectElement::FromNode(aElement
)) {
830 select
->GetAutocompleteInfo(autoInfo
);
831 info
.SetValue(autoInfo
);
839 return info
.Value().mFieldName
.Equals(aKey
);
842 bool FormAutofillImpl::HasTemplatedValue(Element
& aElement
) {
844 if (!aElement
.GetAttr(nsGkAtoms::value
, str
)) {
847 return StringMatchesRegExp(str
, RegexKey::TEMPLATED_VALUE
);
850 bool FormAutofillImpl::RoleIsMenu(Element
& aElement
) {
851 return aElement
.AttrValueIs(kNameSpaceID_None
, nsGkAtoms::role
,
852 nsGkAtoms::menu
, eCaseMatters
);
855 bool FormAutofillImpl::InputTypeNotNumbery(Element
& aElement
) {
856 auto* input
= HTMLInputElement::FromNode(aElement
);
861 auto type
= input
->ControlType();
862 return type
!= FormControlType::InputText
&&
863 type
!= FormControlType::InputTel
&&
864 type
!= FormControlType::InputNumber
;
867 bool FormAutofillImpl::IsSelectWithCreditCardOptions(Element
& aElement
) {
868 auto* select
= HTMLSelectElement::FromNode(aElement
);
873 nsCOMPtr
<nsIHTMLCollection
> options
= select
->Options();
874 for (uint32_t i
= 0; i
< options
->Length(); ++i
) {
875 auto* item
= options
->Item(i
);
876 auto* option
= HTMLOptionElement::FromNode(item
);
880 // Bug 1756799, consider using getAttribute("value") instead of .value
882 option
->GetValue(str
);
883 if (StringMatchesRegExp(str
, RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH
) ||
884 StringMatchesRegExp(str
, RegexKey::CREDIT_CARD_NETWORK_LONG
)) {
888 option
->GetText(str
);
889 if (StringMatchesRegExp(str
, RegexKey::CREDIT_CARD_NETWORK_EXACT_MATCH
) ||
890 StringMatchesRegExp(str
, RegexKey::CREDIT_CARD_NETWORK_LONG
)) {
897 bool FormAutofillImpl::IsRadioWithCreditCardText(
898 Element
& aElement
, const nsTArray
<nsCString
>* aLabels
, ErrorResult
& aRv
) {
899 auto* input
= HTMLInputElement::FromNode(aElement
);
903 auto type
= input
->ControlType();
904 if (type
!= FormControlType::InputRadio
) {
909 input
->GetValue(str
, CallerType::System
);
910 if (CountRegExpMatches(str
, RegexKey::CREDIT_CARD_NETWORK
) == 1) {
915 size_t labelsMatched
= 0;
916 for (const auto& label
: *aLabels
) {
917 size_t labelMatches
=
918 CountRegExpMatches(label
, RegexKey::CREDIT_CARD_NETWORK
);
919 if (labelMatches
> 1) {
922 if (labelMatches
> 0) {
928 return labelsMatched
== 1;
932 // Bug 1756798 : Remove reading text content in a <input>
934 aElement
.GetTextContent(text
, aRv
);
938 return CountRegExpMatches(text
, RegexKey::CREDIT_CARD_NETWORK
) == 1;
941 bool FormAutofillImpl::MaxLengthIs(Element
& aElement
, int32_t aValue
) {
942 auto* input
= HTMLInputElement::FromNode(aElement
);
946 return input
->MaxLength() == aValue
;
949 static bool TestOptionElementForInteger(Element
* aElement
, int32_t aTestValue
) {
950 auto* option
= HTMLOptionElement::FromNodeOrNull(aElement
);
955 option
->GetValue(str
);
956 nsContentUtils::ParseHTMLIntegerResultFlags parseFlags
;
957 int32_t val
= nsContentUtils::ParseHTMLInteger(str
, &parseFlags
);
958 if (val
== aTestValue
) {
961 option
->GetRenderedLabel(str
);
962 val
= nsContentUtils::ParseHTMLInteger(str
, &parseFlags
);
963 return val
== aTestValue
;
966 static bool MatchOptionContiguousInteger(HTMLOptionsCollection
* aOptions
,
967 uint32_t aNumContiguous
,
969 uint32_t len
= aOptions
->Length();
970 if (aNumContiguous
> len
) {
974 for (uint32_t i
= 0; i
<= aOptions
->Length() - aNumContiguous
; i
++) {
976 for (uint32_t j
= 0; j
< aNumContiguous
; j
++) {
977 if (!TestOptionElementForInteger(aOptions
->GetElementAt(i
+ j
),
990 bool FormAutofillImpl::IsExpirationYearLikely(Element
& aElement
) {
991 auto* select
= HTMLSelectElement::FromNode(aElement
);
996 auto* options
= select
->Options();
1002 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters
, &tm
);
1003 uint16_t currentYear
= tm
.tm_year
;
1005 return MatchOptionContiguousInteger(options
, 3, currentYear
);
1008 bool FormAutofillImpl::IsExpirationMonthLikely(Element
& aElement
) {
1009 auto* select
= HTMLSelectElement::FromNode(aElement
);
1014 auto* options
= select
->Options();
1019 if (options
->Length() != 12 && options
->Length() != 13) {
1023 return MatchOptionContiguousInteger(options
, 12, 1);
1026 Element
* FormAutofillImpl::FindRootForField(Element
* aElement
) {
1027 if (const auto* control
=
1028 nsGenericHTMLFormControlElement::FromNode(aElement
)) {
1029 if (Element
* form
= control
->GetForm()) {
1034 return aElement
->OwnerDoc()->GetDocumentElement();
1037 Element
* FormAutofillImpl::FindField(
1038 const Sequence
<OwningNonNull
<Element
>>& aElements
, uint32_t aStartIndex
,
1039 int8_t aDirection
) {
1040 MOZ_ASSERT(aDirection
== 1 || aDirection
== -1);
1041 MOZ_ASSERT(aStartIndex
< aElements
.Length());
1043 Element
* curFieldRoot
= FindRootForField(aElements
[aStartIndex
]);
1044 bool isRootForm
= curFieldRoot
->IsHTMLElement(nsGkAtoms::form
);
1047 aDirection
== 1 ? aElements
.Length() - aStartIndex
- 1 : aStartIndex
;
1048 for (uint32_t i
= 0, searchIndex
= aStartIndex
; i
< num
; i
++) {
1049 searchIndex
+= aDirection
;
1050 const auto& element
= aElements
[searchIndex
];
1051 Element
* root
= FindRootForField(element
);
1054 // Only search fields that are within the same root element.
1055 if (curFieldRoot
!= root
) {
1059 // Exclude elements inside the rootElement that are already in a <form>.
1060 if (root
->IsHTMLElement(nsGkAtoms::form
)) {
1065 if (element
->IsAnyOfHTMLElements(nsGkAtoms::input
, nsGkAtoms::select
)) {
1066 return element
.get();
1073 Element
* FormAutofillImpl::NextField(
1074 const Sequence
<OwningNonNull
<Element
>>& aElements
, uint32_t aStartIndex
) {
1075 return FindField(aElements
, aStartIndex
, 1);
1078 Element
* FormAutofillImpl::PrevField(
1079 const Sequence
<OwningNonNull
<Element
>>& aElements
, uint32_t aStartIndex
) {
1080 return FindField(aElements
, aStartIndex
, -1);
1083 static void ExtractLabelStrings(nsINode
* aNode
, nsTArray
<nsCString
>& aStrings
,
1085 if (aNode
->IsAnyOfHTMLElements(nsGkAtoms::script
, nsGkAtoms::noscript
,
1086 nsGkAtoms::option
, nsGkAtoms::style
)) {
1090 if (aNode
->IsText() || !aNode
->HasChildren()) {
1092 aNode
->GetTextContent(text
, aRv
);
1097 text
.Trim(kWhitespace
);
1098 CopyUTF16toUTF8(text
, *aStrings
.AppendElement());
1102 for (nsINode
* child
= aNode
->GetFirstChild(); child
;
1103 child
= child
->GetNextSibling()) {
1104 if (child
->IsElement() || child
->IsText()) {
1105 ExtractLabelStrings(child
, aStrings
, aRv
);
1113 nsTArray
<nsCString
>* GetLabelStrings(
1115 const nsTHashMap
<void*, nsTArray
<nsCString
>>& aElementMap
,
1116 const nsTHashMap
<nsAtom
*, nsTArray
<nsCString
>>& aIdMap
) {
1121 if (nsAtom
* idAtom
= aElement
->GetID()) {
1122 return aIdMap
.Lookup(idAtom
).DataPtrOrNull();
1125 return aElementMap
.Lookup(aElement
).DataPtrOrNull();
1128 void FormAutofillImpl::GetFormAutofillConfidences(
1129 GlobalObject
& aGlobal
, const Sequence
<OwningNonNull
<Element
>>& aElements
,
1130 nsTArray
<FormAutofillConfidences
>& aResults
, ErrorResult
& aRv
) {
1131 if (aElements
.IsEmpty()) {
1136 auto* document
= aElements
[0]->OwnerDoc();
1138 for (uint32_t i
= 1; i
< aElements
.Length(); ++i
) {
1139 MOZ_ASSERT(document
== aElements
[i
]->OwnerDoc());
1143 RefPtr
<nsContentList
> labels
= document
->GetElementsByTagName(u
"label"_ns
);
1144 nsTHashMap
<void*, nsTArray
<nsCString
>> elementsToLabelStrings
;
1145 nsTHashMap
<nsAtom
*, nsTArray
<nsCString
>> elementsIdToLabelStrings
;
1147 for (uint32_t i
= 0; i
< labels
->Length(); ++i
) {
1148 auto* item
= labels
->Item(i
);
1149 auto* label
= HTMLLabelElement::FromNode(item
);
1150 if (NS_WARN_IF(!label
)) {
1153 auto* control
= label
->GetControl();
1157 nsTArray
<nsCString
> labelStrings
;
1158 ExtractLabelStrings(label
, labelStrings
, aRv
);
1163 // We need two maps here to keep track controls with id and without id.
1164 // We can't just use map without id to cover all cases because there
1165 // might be multiple elements with the same id.
1166 if (control
->GetID()) {
1167 elementsIdToLabelStrings
.LookupOrInsert(control
->GetID())
1168 .AppendElements(std::move(labelStrings
));
1170 elementsToLabelStrings
.LookupOrInsert(control
).AppendElements(
1171 std::move(labelStrings
));
1176 nsTArray
<AutofillParams
> paramSet
;
1177 paramSet
.SetLength(aElements
.Length());
1179 for (uint32_t i
= 0; i
< aElements
.Length(); ++i
) {
1180 auto& params
= paramSet
[i
];
1181 const auto& element
= aElements
[i
];
1183 const nsTArray
<nsCString
>* labelStrings
= GetLabelStrings(
1184 element
, elementsToLabelStrings
, elementsIdToLabelStrings
);
1186 bool idOrNameMatchDwfrmAndBml
=
1187 IdOrNameMatchRegExp(element
, RegexKey::DWFRM
) &&
1188 IdOrNameMatchRegExp(element
, RegexKey::BML
);
1189 bool hasTemplatedValue
= HasTemplatedValue(element
);
1190 bool inputTypeNotNumbery
= InputTypeNotNumbery(element
);
1191 bool idOrNameMatchSubscription
=
1192 IdOrNameMatchRegExp(element
, RegexKey::SUBSCRIPTION
);
1193 bool idOrNameMatchFirstAndLast
=
1194 IdOrNameMatchRegExp(element
, RegexKey::FIRST
) &&
1195 IdOrNameMatchRegExp(element
, RegexKey::LAST
);
1197 #define RULE_IMPL2(rule, type) params.m##type##Params[type##Params::rule]
1198 #define RULE_IMPL(rule, type) RULE_IMPL2(rule, type)
1199 #define RULE(rule) RULE_IMPL(rule, RULE_TYPE)
1202 #define RULE_TYPE CCNumber
1203 RULE(idOrNameMatchNumberRegExp
) =
1204 IdOrNameMatchRegExp(element
, RegexKey::CC_NUMBER
);
1205 RULE(labelsMatchNumberRegExp
) =
1206 LabelMatchesRegExp(element
, labelStrings
, RegexKey::CC_NUMBER
);
1207 RULE(closestLabelMatchesNumberRegExp
) =
1208 ClosestLabelMatchesRegExp(element
, RegexKey::CC_NUMBER
);
1209 RULE(placeholderMatchesNumberRegExp
) =
1210 PlaceholderMatchesRegExp(element
, RegexKey::CC_NUMBER
);
1211 RULE(ariaLabelMatchesNumberRegExp
) =
1212 AriaLabelMatchesRegExp(element
, RegexKey::CC_NUMBER
);
1213 RULE(idOrNameMatchGift
) = IdOrNameMatchRegExp(element
, RegexKey::GIFT
);
1214 RULE(labelsMatchGift
) =
1215 LabelMatchesRegExp(element
, labelStrings
, RegexKey::GIFT
);
1216 RULE(placeholderMatchesGift
) =
1217 PlaceholderMatchesRegExp(element
, RegexKey::GIFT
);
1218 RULE(ariaLabelMatchesGift
) =
1219 AriaLabelMatchesRegExp(element
, RegexKey::GIFT
);
1220 RULE(idOrNameMatchSubscription
) = idOrNameMatchSubscription
;
1221 RULE(idOrNameMatchDwfrmAndBml
) = idOrNameMatchDwfrmAndBml
;
1222 RULE(hasTemplatedValue
) = hasTemplatedValue
;
1223 RULE(inputTypeNotNumbery
) = inputTypeNotNumbery
;
1227 #define RULE_TYPE CCName
1228 RULE(idOrNameMatchNameRegExp
) =
1229 IdOrNameMatchRegExp(element
, RegexKey::CC_NAME
);
1230 RULE(labelsMatchNameRegExp
) =
1231 LabelMatchesRegExp(element
, labelStrings
, RegexKey::CC_NAME
);
1232 RULE(closestLabelMatchesNameRegExp
) =
1233 ClosestLabelMatchesRegExp(element
, RegexKey::CC_NAME
);
1234 RULE(placeholderMatchesNameRegExp
) =
1235 PlaceholderMatchesRegExp(element
, RegexKey::CC_NAME
);
1236 RULE(ariaLabelMatchesNameRegExp
) =
1237 AriaLabelMatchesRegExp(element
, RegexKey::CC_NAME
);
1238 RULE(idOrNameMatchFirst
) = IdOrNameMatchRegExp(element
, RegexKey::FIRST
);
1239 RULE(labelsMatchFirst
) =
1240 LabelMatchesRegExp(element
, labelStrings
, RegexKey::FIRST
);
1241 RULE(placeholderMatchesFirst
) =
1242 PlaceholderMatchesRegExp(element
, RegexKey::FIRST
);
1243 RULE(ariaLabelMatchesFirst
) =
1244 AriaLabelMatchesRegExp(element
, RegexKey::FIRST
);
1245 RULE(idOrNameMatchLast
) = IdOrNameMatchRegExp(element
, RegexKey::LAST
);
1246 RULE(labelsMatchLast
) =
1247 LabelMatchesRegExp(element
, labelStrings
, RegexKey::LAST
);
1248 RULE(placeholderMatchesLast
) =
1249 PlaceholderMatchesRegExp(element
, RegexKey::LAST
);
1250 RULE(ariaLabelMatchesLast
) =
1251 AriaLabelMatchesRegExp(element
, RegexKey::LAST
);
1252 RULE(idOrNameMatchSubscription
) = idOrNameMatchSubscription
;
1253 RULE(idOrNameMatchFirstAndLast
) = idOrNameMatchFirstAndLast
;
1254 RULE(idOrNameMatchDwfrmAndBml
) = idOrNameMatchDwfrmAndBml
;
1255 RULE(hasTemplatedValue
) = hasTemplatedValue
;
1258 // We only use Fathom to detect cc-number & cc-name fields for now.
1259 // Comment out code below instead of removing them to make it clear that
1260 // the current design is to support multiple rules.
1262 Element* nextFillableField = NextField(aElements, i);
1263 Element* prevFillableField = PrevField(aElements, i);
1265 const nsTArray<nsCString>* nextLabelStrings = GetLabelStrings(
1266 nextFillableField, elementsToLabelStrings, elementsIdToLabelStrings);
1267 const nsTArray<nsCString>* prevLabelStrings = GetLabelStrings(
1268 prevFillableField, elementsToLabelStrings, elementsIdToLabelStrings);
1269 bool roleIsMenu = RoleIsMenu(element);
1272 #define RULE_TYPE CCType
1273 RULE(idOrNameMatchTypeRegExp) =
1274 IdOrNameMatchRegExp(element, RegexKey::CC_TYPE);
1275 RULE(labelsMatchTypeRegExp) =
1276 LabelMatchesRegExp(element, labelStrings, RegexKey::CC_TYPE);
1277 RULE(closestLabelMatchesTypeRegExp) =
1278 ClosestLabelMatchesRegExp(element, RegexKey::CC_TYPE);
1279 RULE(idOrNameMatchVisaCheckout) =
1280 IdOrNameMatchRegExp(element, RegexKey::VISA_CHECKOUT);
1281 RULE(ariaLabelMatchesVisaCheckout) =
1282 AriaLabelMatchesRegExp(element, RegexKey::VISA_CHECKOUT);
1283 RULE(isSelectWithCreditCardOptions) =
1284 IsSelectWithCreditCardOptions(element);
1285 RULE(isRadioWithCreditCardText) =
1286 IsRadioWithCreditCardText(element, labelStrings, aRv);
1291 RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
1292 RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
1293 RULE(hasTemplatedValue) = hasTemplatedValue;
1297 #define RULE_TYPE CCExp
1298 RULE(labelsMatchExpRegExp) =
1299 LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP);
1300 RULE(closestLabelMatchesExpRegExp) =
1301 ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP);
1302 RULE(placeholderMatchesExpRegExp) =
1303 PlaceholderMatchesRegExp(element, RegexKey::CC_EXP);
1304 RULE(labelsMatchExpWith2Or4DigitYear) = LabelMatchesRegExp(
1305 element, labelStrings, RegexKey::TWO_OR_FOUR_DIGIT_YEAR);
1306 RULE(placeholderMatchesExpWith2Or4DigitYear) =
1307 PlaceholderMatchesRegExp(element, RegexKey::TWO_OR_FOUR_DIGIT_YEAR);
1308 RULE(labelsMatchMMYY) =
1309 LabelMatchesRegExp(element, labelStrings, RegexKey::MMYY);
1310 RULE(placeholderMatchesMMYY) =
1311 PlaceholderMatchesRegExp(element, RegexKey::MMYY);
1312 RULE(maxLengthIs7) = MaxLengthIs(element, 7);
1313 RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
1314 RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
1315 RULE(hasTemplatedValue) = hasTemplatedValue;
1316 RULE(isExpirationMonthLikely) = IsExpirationMonthLikely(element);
1317 RULE(isExpirationYearLikely) = IsExpirationYearLikely(element);
1318 RULE(idOrNameMatchMonth) = IdOrNameMatchRegExp(element, RegexKey::MONTH);
1319 RULE(idOrNameMatchYear) = IdOrNameMatchRegExp(element, RegexKey::YEAR);
1320 RULE(idOrNameMatchExpMonthRegExp) =
1321 IdOrNameMatchRegExp(element, RegexKey::CC_EXP_MONTH);
1322 RULE(idOrNameMatchExpYearRegExp) =
1323 IdOrNameMatchRegExp(element, RegexKey::CC_EXP_YEAR);
1324 RULE(idOrNameMatchValidation) =
1325 IdOrNameMatchRegExp(element, RegexKey::VALIDATION);
1329 #define RULE_TYPE CCExpMonth
1330 RULE(idOrNameMatchExpMonthRegExp) =
1331 IdOrNameMatchRegExp(element, RegexKey::CC_EXP_MONTH);
1332 RULE(labelsMatchExpMonthRegExp) =
1333 LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP_MONTH);
1334 RULE(closestLabelMatchesExpMonthRegExp) =
1335 ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
1336 RULE(placeholderMatchesExpMonthRegExp) =
1337 PlaceholderMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
1338 RULE(ariaLabelMatchesExpMonthRegExp) =
1339 AriaLabelMatchesRegExp(element, RegexKey::CC_EXP_MONTH);
1340 RULE(idOrNameMatchMonth) = IdOrNameMatchRegExp(element, RegexKey::MONTH);
1341 RULE(labelsMatchMonth) =
1342 LabelMatchesRegExp(element, labelStrings, RegexKey::MONTH);
1343 RULE(placeholderMatchesMonth) =
1344 PlaceholderMatchesRegExp(element, RegexKey::MONTH);
1345 RULE(ariaLabelMatchesMonth) =
1346 AriaLabelMatchesRegExp(element, RegexKey::MONTH);
1347 RULE(nextFieldIdOrNameMatchExpYearRegExp) =
1348 nextFillableField &&
1349 IdOrNameMatchRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
1350 RULE(nextFieldLabelsMatchExpYearRegExp) =
1351 nextFillableField &&
1352 LabelMatchesRegExp(element, nextLabelStrings, RegexKey::CC_EXP_YEAR);
1353 RULE(nextFieldPlaceholderMatchExpYearRegExp) =
1354 nextFillableField &&
1355 PlaceholderMatchesRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
1356 RULE(nextFieldAriaLabelMatchExpYearRegExp) =
1357 nextFillableField &&
1358 AriaLabelMatchesRegExp(*nextFillableField, RegexKey::CC_EXP_YEAR);
1359 RULE(nextFieldIdOrNameMatchYear) =
1360 nextFillableField &&
1361 IdOrNameMatchRegExp(*nextFillableField, RegexKey::YEAR);
1362 RULE(nextFieldLabelsMatchYear) =
1363 nextFillableField &&
1364 LabelMatchesRegExp(element, nextLabelStrings, RegexKey::YEAR);
1365 RULE(nextFieldPlaceholderMatchesYear) =
1366 nextFillableField &&
1367 PlaceholderMatchesRegExp(*nextFillableField, RegexKey::YEAR);
1368 RULE(nextFieldAriaLabelMatchesYear) =
1369 nextFillableField &&
1370 AriaLabelMatchesRegExp(*nextFillableField, RegexKey::YEAR);
1371 RULE(nextFieldMatchesExpYearAutocomplete) =
1372 nextFillableField &&
1373 NextFieldMatchesExpYearAutocomplete(nextFillableField);
1374 RULE(isExpirationMonthLikely) = IsExpirationMonthLikely(element);
1375 RULE(nextFieldIsExpirationYearLikely) =
1376 nextFillableField && IsExpirationYearLikely(*nextFillableField);
1377 RULE(maxLengthIs2) = MaxLengthIs(element, 2);
1378 RULE(placeholderMatchesMM) =
1379 PlaceholderMatchesRegExp(element, RegexKey::MM_MONTH);
1380 RULE(roleIsMenu) = roleIsMenu;
1381 RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
1382 RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
1383 RULE(hasTemplatedValue) = hasTemplatedValue;
1387 #define RULE_TYPE CCExpYear
1388 RULE(idOrNameMatchExpYearRegExp) =
1389 IdOrNameMatchRegExp(element, RegexKey::CC_EXP_YEAR);
1390 RULE(labelsMatchExpYearRegExp) =
1391 LabelMatchesRegExp(element, labelStrings, RegexKey::CC_EXP_YEAR);
1392 RULE(closestLabelMatchesExpYearRegExp) =
1393 ClosestLabelMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
1394 RULE(placeholderMatchesExpYearRegExp) =
1395 PlaceholderMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
1396 RULE(ariaLabelMatchesExpYearRegExp) =
1397 AriaLabelMatchesRegExp(element, RegexKey::CC_EXP_YEAR);
1398 RULE(idOrNameMatchYear) = IdOrNameMatchRegExp(element, RegexKey::YEAR);
1399 RULE(labelsMatchYear) =
1400 LabelMatchesRegExp(element, labelStrings, RegexKey::YEAR);
1401 RULE(placeholderMatchesYear) =
1402 PlaceholderMatchesRegExp(element, RegexKey::YEAR);
1403 RULE(ariaLabelMatchesYear) =
1404 AriaLabelMatchesRegExp(element, RegexKey::YEAR);
1405 RULE(previousFieldIdOrNameMatchExpMonthRegExp) =
1406 prevFillableField &&
1407 IdOrNameMatchRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
1408 RULE(previousFieldLabelsMatchExpMonthRegExp) =
1409 prevFillableField &&
1410 LabelMatchesRegExp(element, prevLabelStrings, RegexKey::CC_EXP_MONTH);
1411 RULE(previousFieldPlaceholderMatchExpMonthRegExp) =
1412 prevFillableField &&
1413 PlaceholderMatchesRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
1414 RULE(previousFieldAriaLabelMatchExpMonthRegExp) =
1415 prevFillableField &&
1416 AriaLabelMatchesRegExp(*prevFillableField, RegexKey::CC_EXP_MONTH);
1417 RULE(previousFieldIdOrNameMatchMonth) =
1418 prevFillableField &&
1419 IdOrNameMatchRegExp(*prevFillableField, RegexKey::MONTH);
1420 RULE(previousFieldLabelsMatchMonth) =
1421 prevFillableField &&
1422 LabelMatchesRegExp(element, prevLabelStrings, RegexKey::MONTH);
1423 RULE(previousFieldPlaceholderMatchesMonth) =
1424 prevFillableField &&
1425 PlaceholderMatchesRegExp(*prevFillableField, RegexKey::MONTH);
1426 RULE(previousFieldAriaLabelMatchesMonth) =
1427 prevFillableField &&
1428 AriaLabelMatchesRegExp(*prevFillableField, RegexKey::MONTH);
1429 RULE(previousFieldMatchesExpMonthAutocomplete) =
1430 prevFillableField &&
1431 PreviousFieldMatchesExpMonthAutocomplete(prevFillableField);
1432 RULE(isExpirationYearLikely) = IsExpirationYearLikely(element);
1433 RULE(previousFieldIsExpirationMonthLikely) =
1434 prevFillableField && IsExpirationMonthLikely(*prevFillableField);
1435 RULE(placeholderMatchesYYOrYYYY) =
1436 PlaceholderMatchesRegExp(element, RegexKey::YY_OR_YYYY);
1437 RULE(roleIsMenu) = roleIsMenu;
1438 RULE(idOrNameMatchSubscription) = idOrNameMatchSubscription;
1439 RULE(idOrNameMatchDwfrmAndBml) = idOrNameMatchDwfrmAndBml;
1440 RULE(hasTemplatedValue) = hasTemplatedValue;
1448 #define CALCULATE_SCORE(type, score) \
1449 for (auto i : MakeEnumeratedRange(type##Params::Count)) { \
1450 (score) += params.m##type##Params[i] * kCoefficents.m##type##Params[i]; \
1452 (score) = Sigmoid(score + k##type##Bias);
1454 // Calculating the final score of each rule
1455 FormAutofillConfidences score
;
1456 CALCULATE_SCORE(CCNumber
, score
.mCcNumber
)
1457 CALCULATE_SCORE(CCName
, score
.mCcName
)
1459 // Comment out code that are not used right now
1460 // CALCULATE_SCORE(CCType, score.mCcType)
1461 // CALCULATE_SCORE(CCExp, score.mCcExp)
1462 // CALCULATE_SCORE(CCExpMonth, score.mCcExpMonth)
1463 // CALCULATE_SCORE(CCExpYear, score.mCcExpYear)
1465 #undef CALCULATE_SCORE
1467 aResults
.AppendElement(score
);
1471 static StaticAutoPtr
<FormAutofillImpl
> sFormAutofillInstance
;
1473 static FormAutofillImpl
* GetFormAutofillImpl() {
1474 if (!sFormAutofillInstance
) {
1475 sFormAutofillInstance
= new FormAutofillImpl();
1476 ClearOnShutdown(&sFormAutofillInstance
);
1478 return sFormAutofillInstance
;
1482 void FormAutofillNative::GetFormAutofillConfidences(
1483 GlobalObject
& aGlobal
, const Sequence
<OwningNonNull
<Element
>>& aElements
,
1484 nsTArray
<FormAutofillConfidences
>& aResults
, ErrorResult
& aRv
) {
1485 GetFormAutofillImpl()->GetFormAutofillConfidences(aGlobal
, aElements
,
1489 } // namespace mozilla::dom