diff --git a/browser/extensions/formautofill/FormAutofillHandler.jsm b/browser/extensions/formautofill/FormAutofillHandler.jsm
index 4d78584799d9..cb36eeb4c3e8 100644
--- a/browser/extensions/formautofill/FormAutofillHandler.jsm
+++ b/browser/extensions/formautofill/FormAutofillHandler.jsm
@@ -61,36 +61,8 @@ FormAutofillHandler.prototype = {
* Set fieldDetails from the form about fields that can be autofilled.
*/
collectFormFields() {
- this.fieldDetails = [];
-
- for (let element of this.form.elements) {
- // Exclude elements to which no autocomplete field has been assigned.
- let info = FormAutofillHeuristics.getInfo(element);
- if (!info) {
- continue;
- }
-
- // Store the association between the field metadata and the element.
- if (this.fieldDetails.some(f => f.section == info.section &&
- f.addressType == info.addressType &&
- f.contactType == info.contactType &&
- f.fieldName == info.fieldName)) {
- // A field with the same identifier already exists.
- log.debug("Not collecting a field matching another with the same info:", info);
- continue;
- }
-
- let formatWithElement = {
- section: info.section,
- addressType: info.addressType,
- contactType: info.contactType,
- fieldName: info.fieldName,
- elementWeakRef: Cu.getWeakReference(element),
- };
-
- this.fieldDetails.push(formatWithElement);
- }
-
+ let fieldDetails = FormAutofillHeuristics.getFormInfo(this.form);
+ this.fieldDetails = fieldDetails ? fieldDetails : [];
log.debug("Collected details on", this.fieldDetails.length, "fields");
},
diff --git a/browser/extensions/formautofill/FormAutofillHeuristics.jsm b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
index b188f44119c8..0ce5138a7f03 100644
--- a/browser/extensions/formautofill/FormAutofillHeuristics.jsm
+++ b/browser/extensions/formautofill/FormAutofillHeuristics.jsm
@@ -12,6 +12,11 @@ this.EXPORTED_SYMBOLS = ["FormAutofillHeuristics"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+Cu.import("resource://formautofill/FormAutofillUtils.jsm");
+
+this.log = null;
+FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
+
/**
* Returns the autocomplete information of fields according to heuristics.
*/
@@ -34,6 +39,39 @@ this.FormAutofillHeuristics = {
"email",
],
+ getFormInfo(form) {
+ let fieldDetails = [];
+ for (let element of form.elements) {
+ // Exclude elements to which no autocomplete field has been assigned.
+ let info = this.getInfo(element);
+ if (!info) {
+ continue;
+ }
+
+ // Store the association between the field metadata and the element.
+ if (fieldDetails.some(f => f.section == info.section &&
+ f.addressType == info.addressType &&
+ f.contactType == info.contactType &&
+ f.fieldName == info.fieldName)) {
+ // A field with the same identifier already exists.
+ log.debug("Not collecting a field matching another with the same info:", info);
+ continue;
+ }
+
+ let formatWithElement = {
+ section: info.section,
+ addressType: info.addressType,
+ contactType: info.contactType,
+ fieldName: info.fieldName,
+ elementWeakRef: Cu.getWeakReference(element),
+ };
+
+ fieldDetails.push(formatWithElement);
+ }
+
+ return fieldDetails;
+ },
+
getInfo(element) {
if (!(element instanceof Ci.nsIDOMHTMLInputElement)) {
return null;
diff --git a/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html b/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
new file mode 100644
index 000000000000..bb74c9da920c
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/autocomplete_basic.html
@@ -0,0 +1,23 @@
+
+
+
+
+ Form Autofill Demo Page
+
+
+ Form Autofill Demo Page
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_Payment.html
new file mode 100644
index 000000000000..e987ef59cac1
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_Payment.html
@@ -0,0 +1,283 @@
+
+
+
+ Checkout – Best Buy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tomorrow
+
+ at a Best Buy store
+
+
+
+
+ Store pick ups are usually ready within one hour and held for up to 8 days
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ E-mail Address
+
+
+
+
+
+
+
+
+
+ Phone Number
+
+
+
+
+
+
+
+
+
+
+
+
+ Send me text notifications for my order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_ShippingAddress.html b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_ShippingAddress.html
new file mode 100644
index 000000000000..36760a26108e
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/Checkout_ShippingAddress.html
@@ -0,0 +1,326 @@
+
+
+
+ Checkout – Best Buy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tomorrow
+
+ at a Best Buy store
+
+
+
+
+ Store pick ups are usually ready within one hour and held for up to 8 days
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ E-mail Address
+
+
+
+
+
+
+
+
+
+ Phone Number
+
+
+
+
+
+
+
+
+
+
+
+
+ Send me text notifications for my order
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/SignIn.html
new file mode 100644
index 000000000000..8111d49c3725
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/BestBuy/SignIn.html
@@ -0,0 +1,21 @@
+
+
+
+ Sign In to BestBuy.com
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_BillingPaymentInfo.html b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_BillingPaymentInfo.html
new file mode 100644
index 000000000000..3258417b78cd
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_BillingPaymentInfo.html
@@ -0,0 +1,515 @@
+
+
+
+
+
+ Checkout
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_Logon.html b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_Logon.html
new file mode 100644
index 000000000000..6ee46c88731b
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_Logon.html
@@ -0,0 +1,118 @@
+
+
+
+
+
+ Logon Checkout
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_ShippingInfo.html b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_ShippingInfo.html
new file mode 100644
index 000000000000..d461a0050b86
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CDW/Checkout_ShippingInfo.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+ Checkout
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CostCo/Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/Payment.html
new file mode 100644
index 000000000000..e45176cabc26
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/Payment.html
@@ -0,0 +1,892 @@
+
+
+
+
+
+ Costco - Payment
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CostCo/ShippingAddress.html b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/ShippingAddress.html
new file mode 100644
index 000000000000..b9b72eb3385c
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/ShippingAddress.html
@@ -0,0 +1,527 @@
+
+
+
+
+
+
+ Shipping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/CostCo/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/SignIn.html
new file mode 100644
index 000000000000..afcd5fe6f09b
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/CostCo/SignIn.html
@@ -0,0 +1,374 @@
+
+
+
+
+
+ Sign In
+
+
+
+
+
+
+
+
+
+ Get Email Offers
+ Sign up for great offers from Costco.com!
+
+
+
+
+
+
+
+
+
+
+ ???LANGUAGE_REGION_MODAL_TITLE???
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/Checkout_ShippingPayment.html b/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/Checkout_ShippingPayment.html
new file mode 100644
index 000000000000..182535065101
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/Checkout_ShippingPayment.html
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+ The Home Depot - Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Email
+
+
+
+
+
+
+
+
+
+
+
+Create an account to track your order history and check out faster - all we need is a password.
+
+
Check out faster, access past orders, and organize products into lists.
+
+
+
+
+
+
+
+Password
+
+
+
+
+
+
+
+
+
+
+
+Confirm Password
+
+
+
+
+
+
+
+
+
+
+
Passwords are case sensitive and must be at least 8 characters.
+
+
Create a strong password by:
+
+ Including numbers or symbols
+ Mixing upper/lowercase
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phone
+
+
+
+
+
+
+
+
+
+
+
+Shipping Address
+
+
+
+
+
+
+
+
+
+
+
+
+Add an apartment, suite, building, etc.
+
+
+
+
+
+ZIP Code
+
+
+
+
+
+
+
+City, State
+
+
+MOUNTAIN VIEW, CA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Use as Billing Address
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Credit Card
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Expiration
+
+
+ Month
+ 01 - January
+ 02 - February
+ 03 - March
+ 04 - April
+ 05 - May
+ 06 - June
+ 07 - July
+ 08 - August
+ 09 - September
+ 10 - October
+ 11 - November
+ 12 - December
+
+
+
+
+
+
+
+
+ Year
+ 2017
+ 2018
+ 2019
+ 2020
+ 2021
+ 2022
+ 2023
+ 2024
+ 2025
+ 2026
+ 2027
+ 2028
+ 2029
+ 2030
+ 2031
+ 2032
+ 2033
+ 2034
+ 2035
+
+
+
+
+
+
+
+
+
+ CVV (on back)
+
+
+
+
+
+
+
+
+
+ Apply a Gift Card
+ |
+ Have a PO/Job Code for this order?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+myApron ID (Optional)
+
+
+
+
+
+
+
+
+
+
+
+
+
+Yes, I would like to receive emails about unadvertised & online only specials, new products and store promotions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Have a promo code?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/SignIn.html
new file mode 100644
index 000000000000..b741ce5f0c20
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/HomeDepot/SignIn.html
@@ -0,0 +1,83 @@
+
+
+
+
+ The Home Depot - SignIn
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_Payment.html
new file mode 100644
index 000000000000..4ec11c2b857f
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_Payment.html
@@ -0,0 +1,478 @@
+
+
+
+
+ Macy's Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_ShippingAddress.html b/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_ShippingAddress.html
new file mode 100644
index 000000000000..7ed68344fa90
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Macys/Checkout_ShippingAddress.html
@@ -0,0 +1,439 @@
+
+
+
+
+ Macy's Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Macys/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/Macys/SignIn.html
new file mode 100644
index 000000000000..51dff05d0464
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Macys/SignIn.html
@@ -0,0 +1,208 @@
+
+
+
+
+ Sign In - Macy's Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/BillingInfo.html b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/BillingInfo.html
new file mode 100644
index 000000000000..c614660e1093
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/BillingInfo.html
@@ -0,0 +1,1083 @@
+
+
+
+
+ Newegg.com - Billing Info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/Login.html b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/Login.html
new file mode 100644
index 000000000000..a5f149b68362
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/Login.html
@@ -0,0 +1,156 @@
+
+
+
+
+ Newegg.com - Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/ShippingInfo.html b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/ShippingInfo.html
new file mode 100644
index 000000000000..14bd9502afe4
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/NewEgg/ShippingInfo.html
@@ -0,0 +1,270 @@
+
+
+
+
+ Newegg.com - Shipping Info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set as default credit card
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/Payment.html
new file mode 100644
index 000000000000..06b9f8e7632b
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/Payment.html
@@ -0,0 +1,672 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Office Supplies, Furniture, Technology at Offic Depot
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/ShippingAddress.html b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/ShippingAddress.html
new file mode 100644
index 000000000000..849e3be49559
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/ShippingAddress.html
@@ -0,0 +1,347 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Office Supplies, Furniture, Technology at Office Depot
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Company Name:
+
+
+
+
+ * Address:
+
+
+
+ Address Line 2:
+ (optional)
+
+
+
+
+
+
+
+ * Postal Code:
+
+
+
+
+
+
+
+
+*
+City & State
+
+ MOUNTAIN VIEW, CA
+
+ Other City and State
+
+
+
+
+
+
+
+
+
+
+ * State:
+
+ Select a state
+
+ AK - Alaska
+
+ AL - Alabama
+
+ AR - Arkansas
+
+ AZ - Arizona
+
+ CA - California
+
+ CO - Colorado
+
+ CT - Connecticut
+
+ DC - District of Columbia
+
+ DE - Delaware
+
+ FL - Florida
+
+ GA - Georgia
+
+ HI - Hawaii
+
+ IA - Iowa
+
+ ID - Idaho
+
+ IL - Illinois
+
+ IN - Indiana
+
+ KS - Kansas
+
+ KY - Kentucky
+
+ LA - Louisiana
+
+ MA - Massachusetts
+
+ MD - Maryland
+
+ ME - Maine
+
+ MI - Michigan
+
+ MN - Minnesota
+
+ MO - Missouri
+
+ MS - Mississippi
+
+ MT - Montana
+
+ NC - North Carolina
+
+ ND - North Dakota
+
+ NE - Nebraska
+
+ NH - New Hampshire
+
+ NJ - New Jersey
+
+ NM - New Mexico
+
+ NV - Nevada
+
+ NY - New York
+
+ OH - Ohio
+
+ OK - Oklahoma
+
+ OR - Oregon
+
+ PA - Pennsylvania
+
+ PR - Puerto Rico
+
+ RI - Rhode Island
+
+ SC - South Carolina
+
+ SD - South Dakota
+
+ TN - Tennessee
+
+ TX - Texas
+
+ UT - Utah
+
+ VA - Virginia
+
+ VI - US Virgin Islands
+
+ VT - Vermont
+
+ WA - Washington
+
+ WI - Wisconsin
+
+ WV - West Virginia
+
+ WY - Wyoming
+
+
+
+
+
+
+
+
+
+
+ * Email Address:
+
+
+
+
+
+
+
+
+
+
+Send me exclusive coupons and special offers to my inbox.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/SignIn.html
new file mode 100644
index 000000000000..70b55fedddb3
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/OfficeDepot/SignIn.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Office Supplies, Furniture, Technology at Office Depot
+
+
+
+
+
+
+
+
+
+
+ Login name or email address
+ Logging in as a different user may cause pricing changes
+
+
+
+
+ Keep me logged in
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/QVC/PaymentMethod.html b/browser/extensions/formautofill/test/fixtures/third_party/QVC/PaymentMethod.html
new file mode 100644
index 000000000000..9d51db7c5d8c
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/QVC/PaymentMethod.html
@@ -0,0 +1,527 @@
+
+
+
+
+
+
+
+
+ Payment Method
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Total Purchase
+ (including tax and S&H) :
+
+
+
+
+
+
+
+
+
+ Continue Checkout
+
+
+ Continue Checkout
+
+
+
+
+ Edit Shopping cart
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/QVC/SignIn.html b/browser/extensions/formautofill/test/fixtures/third_party/QVC/SignIn.html
new file mode 100644
index 000000000000..a056ccfc5cc5
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/QVC/SignIn.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+ QVC.com Sign In
+
+
+
+
+
+
+
+ Search QVC:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Using your default shipping and payment information? Check the box to go directly to Order Summary.
+
+
+
+
+
+
+
+
+
+
+
+
+ Continue
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/QVC/YourInformation.html b/browser/extensions/formautofill/test/fixtures/third_party/QVC/YourInformation.html
new file mode 100644
index 000000000000..7af160e354cc
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/QVC/YourInformation.html
@@ -0,0 +1,522 @@
+
+
+
+
+
+
+
+
+ Payment Method
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Continue Checkout
+
+
+ Continue Checkout
+
+
+
+
+ Edit Shopping cart
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/README b/browser/extensions/formautofill/test/fixtures/third_party/README
new file mode 100644
index 000000000000..ca4750ec08cf
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/README
@@ -0,0 +1,4 @@
+This directory contains pages downloaded from the web for the purpose of testing
+Form Autofill against pages from the real world. These files are not made
+available under an open source license.
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Sears/PaymentOptions.html b/browser/extensions/formautofill/test/fixtures/third_party/Sears/PaymentOptions.html
new file mode 100644
index 000000000000..5f6ecd24d9d7
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Sears/PaymentOptions.html
@@ -0,0 +1,566 @@
+
+
+
+
+
+
+
+
+
+
+ Payment Options | Sears PartsDirect
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This is a Business Account
+
+
+
+ This is a Personal Account
+
+ First name*
+
+
+
+
+
+ Last name*
+
+
+
+
+ Bank routing number*
+
+
+
+
+ Checking account number*
+
+
+
+
+ Check number*
+
+
+
+
+
+ Driver's license or state identification #*
+
+
+
+
+ State issued*
+
+
+ ST *
+ AA
+ AE
+ AL
+ AK
+ AP
+ AZ
+ AR
+ CA
+ CO
+ CT
+ DE
+ DC
+ FL
+ GA
+ GU
+ HI
+ ID
+ IL
+ IN
+ IA
+ KS
+ KY
+ LA
+ ME
+ MD
+ MA
+ MI
+ MN
+ MS
+ MO
+ MT
+ NE
+ NV
+ NH
+ NJ
+ NM
+ NY
+ NC
+ ND
+ OH
+ OK
+ OR
+ PA
+ PR
+ RI
+ SC
+ SD
+ TN
+ TX
+ UT
+ VA
+ VI
+ VT
+ WA
+ WV
+ WI
+ WY
+
+
+
+ Date of birth*
+
+
+ Month
+ January
+ February
+ March
+ April
+ May
+ June
+ July
+ August
+ September
+ October
+ November
+ December
+
+
+ Date
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+
+
+ Year
+ 1999
+ 1998
+ 1997
+ 1996
+ 1995
+ 1994
+ 1993
+ 1992
+ 1991
+ 1990
+ 1989
+ 1988
+ 1987
+ 1986
+ 1985
+ 1984
+ 1983
+ 1982
+ 1981
+ 1980
+ 1979
+ 1978
+ 1977
+ 1976
+ 1975
+ 1974
+ 1973
+ 1972
+ 1971
+ 1970
+ 1969
+ 1968
+ 1967
+ 1966
+ 1965
+ 1964
+ 1963
+ 1962
+ 1961
+ 1960
+ 1959
+ 1958
+ 1957
+ 1956
+ 1955
+ 1954
+ 1953
+ 1952
+ 1951
+ 1950
+ 1949
+ 1948
+ 1947
+ 1946
+ 1945
+ 1944
+ 1943
+ 1942
+ 1941
+ 1940
+ 1939
+ 1938
+ 1937
+ 1936
+ 1935
+ 1934
+ 1933
+ 1932
+ 1931
+ 1930
+ 1929
+ 1928
+ 1927
+ 1926
+ 1925
+ 1924
+ 1923
+ 1922
+ 1921
+ 1920
+ 1919
+ 1918
+ 1917
+ 1916
+ 1915
+ 1914
+ 1913
+ 1912
+ 1911
+ 1910
+ 1909
+ 1908
+ 1907
+ 1906
+ 1905
+ 1904
+ 1903
+ 1902
+ 1901
+ 1900
+ 1899
+
+
+
+
+
+
+
+ enter email address
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Sears/ShippingAddress.html b/browser/extensions/formautofill/test/fixtures/third_party/Sears/ShippingAddress.html
new file mode 100644
index 000000000000..a9d1f5cd0f3f
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Sears/ShippingAddress.html
@@ -0,0 +1,447 @@
+
+
+
+
+
+
+
+
+
+
+ Shipping address | Sears PartsDirect
+
+
+
+
+
+
+
+
+ Email
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Same as shipping address
+
+
+
+
+
+
+ Send me promotions, discounts and other special information from Sears.com.
+
+
+
+
+
+
+
+
+
+
+ enter email address
+
+
+
+
+
+
+
+
+
+ Email Address
+ Required
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic.html b/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic.html
new file mode 100644
index 000000000000..cf9e892cb2b2
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic.html
@@ -0,0 +1,117 @@
+
+
+
+
+ It's easy to find the Office Supplies, Copy Paper,
+ Furniture, Ink, Toner, Cleaning Products, Electronics and the
+ Technology you need | Staples®
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+First Name
+ *
+
+
+
+
+
+
+
+
+Last
+ Name
+*
+
+
+
+
+
+
+
+
+
+ Shipping
+ Address*
+
+
+
+
+
+
+
+
+
+
+Email
+ Address
+*
+
+
+
+
+
+
+
+
+
+
+Company Name
+ (optional)
+
+
+
+
+
+
+
+
+ Email me exclusive offers & deals from
+ Staples
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic_ac_on.html b/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic_ac_on.html
new file mode 100644
index 000000000000..d3ba1116aabf
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Staples/Basic_ac_on.html
@@ -0,0 +1,117 @@
+
+
+
+
+ It's easy to find the Office Supplies, Copy Paper,
+ Furniture, Ink, Toner, Cleaning Products, Electronics and the
+ Technology you need | Staples®
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+First Name
+ *
+
+
+
+
+
+
+
+
+Last
+ Name
+*
+
+
+
+
+
+
+
+
+
+ Shipping
+ Address*
+
+
+
+
+
+
+
+
+
+
+Email
+ Address
+*
+
+
+
+
+
+
+
+
+
+
+Company Name
+ (optional)
+
+
+
+
+
+
+
+
+ Email me exclusive offers & deals from
+ Staples
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling.html b/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling.html
new file mode 100644
index 000000000000..37dadeb514a9
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling.html
@@ -0,0 +1,99 @@
+
+
+
+
+ It's easy to find the Office Supplies, Copy Paper,
+ Furniture, Ink, Toner, Cleaning Products, Electronics and the
+ Technology you need | Staples®
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Card
+ Number
+*
+
+
+
+
+
+
+
+
+Expiration
+ Date
+*
+
+
+
+
+
+
+
+
+Security
+ Code
+*
+
+
+
+
+
+
+
+
+
+
+
+
+ Billing address is the same as shipping
+ address
+
+
+
+
+
+
+
+
+
Purchase Order # (optional) Add
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling_ac_on.html b/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling_ac_on.html
new file mode 100644
index 000000000000..98c9fb85555b
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Staples/PaymentBilling_ac_on.html
@@ -0,0 +1,98 @@
+
+
+
+
+ It's easy to find the Office Supplies, Copy Paper,
+ Furniture, Ink, Toner, Cleaning Products, Electronics and the
+ Technology you need | Staples®
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Card
+ Number
+*
+
+
+
+
+
+
+
+
+Expiration
+ Date
+*
+
+
+
+
+
+
+
+
+Security
+ Code
+*
+
+
+
+
+
+
+
+
+
+
+
+
+ Billing address is the same as shipping
+ address
+
+
+
+
+
+
+
+
+
Purchase Order # (optional) Add
+
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Checkout.html b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Checkout.html
new file mode 100644
index 000000000000..0d59eec17280
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Checkout.html
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Enter new zip code:
+
+
+
+
+ZIP Code (required)
+
+
+
+
+
+
+
+Calculate
+
+
+Cancel
+
+
+
+
+
+
+Promo code
+ (optional)
+
+
+
+
+
+
+Apply
+
+
+
+
+
+
+Email address (required)
+
+
+
+
+
+
+
+
+Password (required)
+
+
+
+
+
+
+
+
+
+
+
+Show
+
+
+
+
+
+
+Password (required)
+
+
+
+
+
+
+
+
+
+
+
+Hide
+
+
+
+
+
+
+
+
+Sign In
+
+
+
+ *required field
+
+
+First name*
+
+
+
+
+
+Last name*
+
+
+
+
+
+Email address*
+
+
+
+
+
+
+
+
+
+
+
+Password*
+
+
+
+
+
+
+Your password
+ must be between 6 and 12 characters.
+
+
+
+
+
+Show
+
+
+
+
+
+
+Password*
+
+
+
+
+
+
+Your password
+ must be between 6 and 12 characters.
+
+
+
+
+
+Hide
+
+
+
+
+
+
+
+ Create Account
+
+
+
+
+Email me
+ about Rollbacks, special pricing, hot new items, gift ideas and
+ more.
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Payment.html b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Payment.html
new file mode 100644
index 000000000000..26936843291a
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Payment.html
@@ -0,0 +1,235 @@
+
+
+
+
+
+
+
+
+ Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Promo code
+ (optional)
+
+
+
+
+
+
+Apply
+
+
+
+
+
+
+
* required field
+
+
+First name on
+ card*
+
+
+
+
+
+Last name on
+ card*
+
+
+
+
+
+Card
+ number*
+
+
+
+
+
+
+
+Expiration date*
+
+
+
+
+
+
+
+
+
+
+ MM
+
+ 01
+ 02
+ 03
+ 04
+ 05
+ 06
+ 07
+ 08
+ 09
+ 10
+ 11
+ 12
+
+
+
+
+
/
+
+
+
+
+
+
+
+
+
+ YY
+
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Security code*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Phone number*
+Ex: (415)
+ 444 - 5555
+
+
+
+
+
+
+
+
+
+
+
+
+
+Same as shipping
+
+
+
+
+22F., No.55, Haiiu 1st Rd., Bafu Dist.,
+
+
+San Bruno
+,
+
+
+CA
+
+94066
+
+
+
+
+
+
+
+
+
+Review Your
+ Order
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Shipping.html b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Shipping.html
new file mode 100644
index 000000000000..908453b7f1e0
--- /dev/null
+++ b/browser/extensions/formautofill/test/fixtures/third_party/Walmart/Shipping.html
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+
+
+ Checkout
+
+
+
+
+
+
+
+
+
+
+
+
+ Enter new zip code:
+
+
+
+
+ZIP Code (required)
+
+
+
+
+
+
+
+Calculate
+
+
+Cancel
+
+
+
+
+
+
+Promo code
+ (optional)
+
+
+
+
+
+
+Apply
+
+
+
+
+
+
+
+
*required field
+
+
+
+First name*
+
+
+
+
+
+
+
+
+
+Last name*
+
+
+
+
+
+
+
+
+
+Phone number*
+
+
+
+
+
+
+
+
+
+
+
+Street address*
+
+
+
+
+
+
+
+
+
+Apt, suite, etc (optional)
+
+
+
+
+
+
+
+
+
+City*
+
+
+
+
+
+
+
+
+
+
+State*
+
+
+
+
+
+
+ Alabama
+ Alaska
+ Arizona
+ Arkansas
+ California
+ Colorado
+ Connecticut
+ District of Columbia
+ Delaware
+ Florida
+ Georgia
+ Hawaii
+ Idaho
+ Illinois
+ Indiana
+ Iowa
+ Kansas
+ Kentucky
+ Louisiana
+ Maine
+ Maryland
+ Massachusetts
+ Michigan
+ Minnesota
+ Mississippi
+ Missouri
+ Montana
+ Nebraska
+ Nevada
+ New Hampshire
+ New Jersey
+ New Mexico
+ New York
+ North Carolina
+ North Dakota
+ Ohio
+ Oklahoma
+ Oregon
+ Pennsylvania
+ Rhode Island
+ South Carolina
+ South Dakota
+ Tennessee
+ Texas
+ Utah
+ Vermont
+ Virginia
+ Washington
+ West Virginia
+ Wisconsin
+ Wyoming
+ Armed Forces Americas
+ Armed Forces Pacific
+ Armed Forces other
+ American Samoa
+ Guam
+ N. Mariana Islands
+ Palau
+ Puerto Rico
+ Virgin Islands
+
+
+
+
+
+
+
+
+
+ZIP
+ Code*
+
+
+
+
+
+
+
+
+
+
+
+
+Set as my preferred address
+
+
+
+
+
+
+
+
diff --git a/browser/extensions/formautofill/test/unit/head.js b/browser/extensions/formautofill/test/unit/head.js
index a49757a340ba..0bf3608ba4e4 100644
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -2,7 +2,7 @@
* Provides infrastructure for automated formautofill components tests.
*/
-/* exported loadFormAutofillContent, getTempFile, sinon */
+/* exported getTempFile, loadFormAutofillContent, runHeuristicsTest, sinon */
"use strict";
@@ -79,6 +79,45 @@ function getTempFile(leafName) {
return file;
}
+function runHeuristicsTest(patterns, fixturePathPrefix) {
+ Cu.import("resource://gre/modules/FormLikeFactory.jsm");
+ Cu.import("resource://formautofill/FormAutofillHeuristics.jsm");
+
+ // TODO: "select" and "textarea" will be included eventually.
+ const QUERY_STRING = ["input"];
+ patterns.forEach(testPattern => {
+ add_task(function* () {
+ do_print("Starting test fixture: " + testPattern.fixturePath);
+ let file = do_get_file(fixturePathPrefix + testPattern.fixturePath);
+ let doc = MockDocument.createTestDocumentFromFile("http://localhost:8080/test/", file);
+
+ let forms = [];
+
+ for (let query of QUERY_STRING) {
+ for (let field of doc.querySelectorAll(query)) {
+ let formLike = FormLikeFactory.createFromField(field);
+ if (!forms.some(form => form.rootElement === formLike.rootElement)) {
+ forms.push(formLike);
+ }
+ }
+ }
+
+ Assert.equal(forms.length, testPattern.expectedResult.length, "Expected form count.");
+
+ forms.forEach((form, formIndex) => {
+ let formInfo = FormAutofillHeuristics.getFormInfo(form);
+ // TODO: This line should be uncommented to make sure every field are verified.
+ // Assert.equal(formInfo.length, testPattern.expectedResult[formIndex].length, "Expected field count.");
+ formInfo.forEach((field, fieldIndex) => {
+ let expectedField = testPattern.expectedResult[formIndex][fieldIndex];
+ expectedField.elementWeakRef = field.elementWeakRef;
+ Assert.deepEqual(field, expectedField);
+ });
+ });
+ });
+ });
+}
+
add_task(function* head_initialize() {
Services.prefs.setBoolPref("browser.formautofill.experimental", true);
Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
diff --git a/browser/extensions/formautofill/test/unit/heuristics/test_basic.js b/browser/extensions/formautofill/test/unit/heuristics/test_basic.js
new file mode 100644
index 000000000000..5f3c7759c85e
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/test_basic.js
@@ -0,0 +1,22 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "autocomplete_basic.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "street-address"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "country"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../fixtures/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
new file mode 100644
index 000000000000..60df0f661a29
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_BestBuy.js
@@ -0,0 +1,56 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Checkout_ShippingAddress.html",
+ expectedResult: [
+ [], // Search form
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ [ // Sign up
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [ // unknown
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ ],
+ ],
+ }, {
+ fixturePath: "Checkout_Payment.html",
+ expectedResult: [
+ [], // Search form
+ [ // Sign up
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO:select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ [
+ // unknown
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ ],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [ // Sign in
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/BestBuy/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
new file mode 100644
index 000000000000..6c7a5fe0d2b8
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CDW.js
@@ -0,0 +1,55 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Checkout_ShippingInfo.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "Checkout_BillingPaymentInfo.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ [
+ /* TODO: Credit Card
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+*/
+ ],
+ ],
+ }, {
+ fixturePath: "Checkout_Logon.html",
+ expectedResult: [
+ [],
+ [],
+ [],
+ ],
+ },
+], "../../../fixtures/third_party/CDW/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
new file mode 100644
index 000000000000..f5e77d42fe77
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_CostCo.js
@@ -0,0 +1,124 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "ShippingAddress.html",
+ expectedResult: [
+ [],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"}, // TODO: fix the regexp
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select,country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"}, // TODO: fix the regexp
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select,state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "Payment.html",
+ expectedResult: [
+ [
+/* TODO: credit card
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // ac-off
+*/
+ ],
+ [],
+ [],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"}, // TODO: fix the regexp
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "additional-name"}, // middle-name initial
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"}, // TODO: fix the regexp
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ [ // Forgot password
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "password"},
+ ],
+ [ // Sign up
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ },
+], "../../../fixtures/third_party/CostCo/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
new file mode 100644
index 000000000000..77993b6c66a9
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_HomeDepot.js
@@ -0,0 +1,34 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Checkout_ShippingPayment.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+ ],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/HomeDepot/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
new file mode 100644
index 000000000000..6a957ae5e6ad
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Macys.js
@@ -0,0 +1,67 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Checkout_ShippingAddress.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ ],
+ [
+/*
+*/
+ ],
+ ],
+ }, {
+ fixturePath: "Checkout_Payment.html",
+ expectedResult: [
+ [
+ /*
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"}, // ac-off
+*/
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // select
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [ // Sign in
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "password"},
+ ],
+ [ // Forgot password
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ [],
+ [],
+ ],
+ },
+], "../../../fixtures/third_party/Macys/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
new file mode 100644
index 000000000000..d5479f364d52
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_NewEgg.js
@@ -0,0 +1,66 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "ShippingInfo.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "BillingInfo.html",
+ expectedResult: [
+ [
+/* TODO: Should match the following fields.
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+*/
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "country"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, country
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"}, // TODO
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"}, // TODO
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"}, // TODO
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"}, // TODO
+ ],
+ [],
+ [],
+ [],
+ ],
+ }, {
+ fixturePath: "Login.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/NewEgg/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
new file mode 100644
index 000000000000..c553615c765f
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_OfficeDepot.js
@@ -0,0 +1,64 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "ShippingAddress.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+
+ // TODO: telphone relative fields should be fixed:
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ }, {
+ fixturePath: "Payment.html",
+ expectedResult: [
+ [
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+
+ // TODO: telphone relative fields should be fixed:
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-area-code"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-prefix"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-local-suffix"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [ // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/OfficeDepot/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js
new file mode 100644
index 000000000000..d2b088ca9d49
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_QVC.js
@@ -0,0 +1,54 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "YourInformation.html",
+ expectedResult: [
+ [
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-year"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ }, {
+ fixturePath: "PaymentMethod.html",
+ expectedResult: [
+ [
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"}, // ac-off
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-month"}, // select
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-day"}, // select
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-year"}, // select
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-type"}, // select
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"}, // select
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ }, {
+ fixturePath: "SignIn.html",
+ expectedResult: [
+ [
+ // Unknown
+ ],
+ [ // Sign in
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [],
+ ],
+ },
+], "../../../fixtures/third_party/QVC/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
new file mode 100644
index 000000000000..60fe39e55ad2
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Sears.js
@@ -0,0 +1,87 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "ShippingAddress.html",
+ expectedResult: [
+ [],
+ [], // search form, ac-off
+ [ // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [ // check-out, ac-off
+/*
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+*/
+ ],
+ [ // ac-off
+/*
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "new-password"},
+*/
+ ],
+ [ // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ [ // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ }, {
+ fixturePath: "PaymentOptions.html",
+ expectedResult: [
+ [],
+ [], // search
+ [ // credit card
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+ ],
+ [ // Another billing address
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+ ],
+ [ // check out
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: Wrong. This is for Driver's license.
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-month"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-day"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "bday-year"},
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/Sears/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js
new file mode 100644
index 000000000000..240aa0fbbea3
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Staples.js
@@ -0,0 +1,48 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Basic.html",
+ expectedResult: [
+ [ // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ ],
+ ],
+ }, {
+ fixturePath: "Basic_ac_on.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "tel-extension"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "organization"},
+ ],
+ ],
+ }, {
+ fixturePath: "PaymentBilling.html",
+ expectedResult: [
+ [],
+ ],
+ }, {
+ fixturePath: "PaymentBilling_ac_on.html",
+ expectedResult: [
+ [
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/Staples/");
+
diff --git a/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
new file mode 100644
index 000000000000..4d8d67953a63
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/heuristics/third_party/test_Walmart.js
@@ -0,0 +1,62 @@
+/* global runHeuristicsTest */
+
+"use strict";
+
+runHeuristicsTest([
+ {
+ fixturePath: "Checkout.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ [
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "email"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "password"}, // ac-off
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "email"}, // ac-off
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "password"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "password"}, // ac-off
+ ],
+ ],
+ }, {
+ fixturePath: "Payment.html",
+ expectedResult: [
+ [
+ ],
+ [
+ {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "family-name"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-number"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-month"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-exp-year"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "cc-csc"},
+ {"section": "section-payment", "addressType": "", "contactType": "", "fieldName": "tel"},
+ ],
+ ],
+ }, {
+ fixturePath: "Shipping.html",
+ expectedResult: [
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ [
+ ],
+ [
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "given-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "family-name"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "tel"},
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line1"},
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-line2"}, // TODO: fix the regexp
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level2"}, // city
+// {"section": "", "addressType": "", "contactType": "", "fieldName": "address-level1"}, // TODO: select, state
+ {"section": "", "addressType": "", "contactType": "", "fieldName": "postal-code"},
+ ],
+ ],
+ },
+], "../../../fixtures/third_party/Walmart/");
+
diff --git a/browser/extensions/formautofill/test/unit/xpcshell.ini b/browser/extensions/formautofill/test/unit/xpcshell.ini
index 78c472186503..724e799c2e71 100644
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -2,7 +2,20 @@
firefox-appdir = browser
head = head.js
support-files =
+ ../fixtures/**
+[heuristics/test_basic.js]
+[heuristics/third_party/test_BestBuy.js]
+[heuristics/third_party/test_CDW.js]
+[heuristics/third_party/test_CostCo.js]
+[heuristics/third_party/test_HomeDepot.js]
+[heuristics/third_party/test_Macys.js]
+[heuristics/third_party/test_NewEgg.js]
+[heuristics/third_party/test_OfficeDepot.js]
+[heuristics/third_party/test_QVC.js]
+[heuristics/third_party/test_Sears.js]
+[heuristics/third_party/test_Staples.js]
+[heuristics/third_party/test_Walmart.js]
[test_autofillFormFields.js]
[test_collectFormFields.js]
[test_enabledStatus.js]
diff --git a/devtools/client/locales/en-US/netmonitor.properties b/devtools/client/locales/en-US/netmonitor.properties
index 75f0e0b62e57..e6f6b57dc43a 100644
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -219,6 +219,12 @@ networkMenu.sizeServiceWorker=service worker
# in the network menu specifying the time for a request to finish (in milliseconds).
networkMenu.totalMS=→ %S ms
+# This string is used to concatenate tooltips (netmonitor.waterfall.tooltip.*)
+# in the requests waterfall for total time (in milliseconds). \\u0020 represents
+# a whitespace. You can replace this with a different character, e.g. an hyphen
+# or a period, if a comma doesn't work for your language.
+netmonitor.waterfall.tooltip.separator=,\u0020
+
# LOCALIZATION NOTE (netmonitor.waterfall.tooltip.total): This is part of the tooltip
# displayed in the requests waterfall for total time (in milliseconds).
netmonitor.waterfall.tooltip.total=Total %S ms
diff --git a/devtools/client/netmonitor/src/components/request-list-column-waterfall.js b/devtools/client/netmonitor/src/components/request-list-column-waterfall.js
index a6277655c146..1fdf07b7eeb0 100644
--- a/devtools/client/netmonitor/src/components/request-list-column-waterfall.js
+++ b/devtools/client/netmonitor/src/components/request-list-column-waterfall.js
@@ -96,7 +96,10 @@ function timingBoxes(item) {
tooltip.push(L10N.getFormatStr("netmonitor.waterfall.tooltip.total", totalTime));
}
- return { boxes, tooltip: tooltip.join(", ") };
+ return {
+ boxes,
+ tooltip: tooltip.join(L10N.getStr("netmonitor.waterfall.tooltip.separator"))
+ };
}
module.exports = RequestListColumnWaterfall;
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index a35f546208d6..69d675ff80ac 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3094,12 +3094,7 @@ nsContentUtils::CheckQName(const nsAString& aQualifiedName,
return NS_OK;
}
- // MOZ_EXPAT_EMPTY_QNAME || MOZ_EXPAT_INVALID_CHARACTER
- if (result == (1 << 0) || result == (1 << 1)) {
- return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
- }
-
- return NS_ERROR_DOM_NAMESPACE_ERR;
+ return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
}
//static
diff --git a/dom/tests/mochitest/dom-level2-core/test_createAttributeNS01.html b/dom/tests/mochitest/dom-level2-core/test_createAttributeNS01.html
index aea5a3a6e0cf..727ee15f8caf 100644
--- a/dom/tests/mochitest/dom-level2-core/test_createAttributeNS01.html
+++ b/dom/tests/mochitest/dom-level2-core/test_createAttributeNS01.html
@@ -108,9 +108,9 @@ function createAttributeNS01() {
newAttr = doc.createAttributeNS(namespaceURI,malformedName);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
- assertTrue("throw_NAMESPACE_ERR",success);
+ assertTrue("throw INVALID_CHARACTER_ERR",success);
}
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_createDocument01.html b/dom/tests/mochitest/dom-level2-core/test_createDocument01.html
index ffc032082893..173c2bdb824b 100644
--- a/dom/tests/mochitest/dom-level2-core/test_createDocument01.html
+++ b/dom/tests/mochitest/dom-level2-core/test_createDocument01.html
@@ -114,9 +114,9 @@ function createDocument01() {
aNewDoc = domImpl.createDocument(namespaceURI,malformedName,docType);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
- assertTrue("throw_NAMESPACE_ERR",success);
+ assertTrue("throw INVALID_CHARACTER_ERR",success);
}
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_createDocumentType01.html b/dom/tests/mochitest/dom-level2-core/test_createDocumentType01.html
index d52ce64e1c44..d6d460d00969 100644
--- a/dom/tests/mochitest/dom-level2-core/test_createDocumentType01.html
+++ b/dom/tests/mochitest/dom-level2-core/test_createDocumentType01.html
@@ -112,9 +112,9 @@ function createDocumentType01() {
newType = domImpl.createDocumentType(malformedName,publicId,systemId);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
- assertTrue("throw_NAMESPACE_ERR",success);
+ assertTrue("throw INVALID_CHARACTER_ERR", success);
}
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_createElementNS01.html b/dom/tests/mochitest/dom-level2-core/test_createElementNS01.html
index e15464d3b42a..e592d096fbd6 100644
--- a/dom/tests/mochitest/dom-level2-core/test_createElementNS01.html
+++ b/dom/tests/mochitest/dom-level2-core/test_createElementNS01.html
@@ -108,9 +108,9 @@ function createElementNS01() {
newElement = doc.createElementNS(namespaceURI,malformedName);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
- assertTrue("throw_NAMESPACE_ERR",success);
+ assertTrue("throw INVALID_CHARACTER_ERR", success);
}
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_documentcreateattributeNS04.html b/dom/tests/mochitest/dom-level2-core/test_documentcreateattributeNS04.html
index 89e34b874d30..1485f75a07bf 100644
--- a/dom/tests/mochitest/dom-level2-core/test_documentcreateattributeNS04.html
+++ b/dom/tests/mochitest/dom-level2-core/test_documentcreateattributeNS04.html
@@ -113,7 +113,7 @@ function documentcreateattributeNS04() {
attribute = doc.createAttributeNS(namespaceURI,qualifiedName);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
assertTrue("documentcreateattributeNS04",success);
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_domimplementationcreatedocument07.html b/dom/tests/mochitest/dom-level2-core/test_domimplementationcreatedocument07.html
index b87b2150cb87..056fa2d256ec 100644
--- a/dom/tests/mochitest/dom-level2-core/test_domimplementationcreatedocument07.html
+++ b/dom/tests/mochitest/dom-level2-core/test_domimplementationcreatedocument07.html
@@ -106,7 +106,7 @@ function domimplementationcreatedocument07() {
newDoc = domImpl.createDocument(namespaceURI,":",docType);
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
assertTrue("domimplementationcreatedocument07",success);
}
diff --git a/dom/tests/mochitest/dom-level2-core/test_setAttributeNS02.html b/dom/tests/mochitest/dom-level2-core/test_setAttributeNS02.html
index 6f58738f6cf6..de73321e66b9 100644
--- a/dom/tests/mochitest/dom-level2-core/test_setAttributeNS02.html
+++ b/dom/tests/mochitest/dom-level2-core/test_setAttributeNS02.html
@@ -109,9 +109,9 @@ function setAttributeNS02() {
testAddr.setAttributeNS(namespaceURI,qualifiedName,"newValue");
}
catch(ex) {
- success = (typeof(ex.code) != 'undefined' && ex.code == 14);
+ success = ex.code === DOMException.INVALID_CHARACTER_ERR;
}
- assertTrue("throw_NAMESPACE_ERR",success);
+ assertTrue("throw INVALID_CHARACTER_ERR",success);
}
}
diff --git a/layout/reftests/css-break/reftest.list b/layout/reftests/css-break/reftest.list
index c85d4238cbd0..28f60935b9c0 100644
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -6,7 +6,7 @@ fuzzy(16,460) fuzzy-if(Android,10,3673) fuzzy-if(skiaContent,32,254) == box-deco
random-if(!gtkWidget) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
== box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
== box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
-fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) fails-if(stylo) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
+fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
== box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
== box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html
== box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md
index 67f2f2bfca9e..01cf0e8f81a6 100644
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -128,7 +128,7 @@ to mochitest command.
* test_initial_storage.html `-moz-force-broken-image-icon` [4]
* test_value_storage.html `-moz-force-broken-image-icon` [4]
* -moz-transform: need different parsing rules servo/servo#16003
- * test_value_storage.html `-moz-transform`: need different parsing rules bug 1357906 [72]
+ * test_value_storage.html `-moz-transform`: need different parsing rules bug 1357906 [70]
* test_variables.html `var(--var6)`: -x-system-font [1]
* Unimplemented CSS properties:
* place-{content,items,self} shorthands servo/servo#16391
diff --git a/servo/components/gfx/display_list/mod.rs b/servo/components/gfx/display_list/mod.rs
index 205b4071589c..77a64553c29f 100644
--- a/servo/components/gfx/display_list/mod.rs
+++ b/servo/components/gfx/display_list/mod.rs
@@ -528,6 +528,7 @@ pub enum DisplayItem {
WebGL(Box),
Border(Box),
Gradient(Box),
+ RadialGradient(Box),
Line(Box),
BoxShadow(Box),
Iframe(Box),
@@ -889,6 +890,9 @@ pub struct Gradient {
/// A list of color stops.
pub stops: Vec,
+
+ /// True if gradient repeats infinitly.
+ pub repeating: bool,
}
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
@@ -900,6 +904,31 @@ pub struct GradientDisplayItem {
pub gradient: Gradient,
}
+/// Paints a radial gradient.
+#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
+pub struct RadialGradient {
+ /// The center point of the gradient.
+ pub center: Point2D,
+
+ /// The radius of the gradient with an x and an y component.
+ pub radius: Size2D,
+
+ /// A list of color stops.
+ pub stops: Vec,
+
+ /// True if gradient repeats infinitly.
+ pub repeating: bool,
+}
+
+#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
+pub struct RadialGradientDisplayItem {
+ /// Fields common to all display item.
+ pub base: BaseDisplayItem,
+
+ /// Contains all gradient data.
+ pub gradient: RadialGradient,
+}
+
/// A normal border, supporting CSS border styles.
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
pub struct NormalBorder {
@@ -1124,6 +1153,7 @@ impl DisplayItem {
DisplayItem::WebGL(ref webgl_item) => &webgl_item.base,
DisplayItem::Border(ref border) => &border.base,
DisplayItem::Gradient(ref gradient) => &gradient.base,
+ DisplayItem::RadialGradient(ref gradient) => &gradient.base,
DisplayItem::Line(ref line) => &line.base,
DisplayItem::BoxShadow(ref box_shadow) => &box_shadow.base,
DisplayItem::Iframe(ref iframe) => &iframe.base,
@@ -1241,6 +1271,7 @@ impl fmt::Debug for DisplayItem {
DisplayItem::WebGL(_) => "WebGL".to_owned(),
DisplayItem::Border(_) => "Border".to_owned(),
DisplayItem::Gradient(_) => "Gradient".to_owned(),
+ DisplayItem::RadialGradient(_) => "RadialGradient".to_owned(),
DisplayItem::Line(_) => "Line".to_owned(),
DisplayItem::BoxShadow(_) => "BoxShadow".to_owned(),
DisplayItem::Iframe(_) => "Iframe".to_owned(),
diff --git a/servo/components/layout/display_list_builder.rs b/servo/components/layout/display_list_builder.rs
index 2e065572615d..a2453067e1f5 100644
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -25,7 +25,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDetails};
use gfx::display_list::{BorderDisplayItem, ImageBorder, NormalBorder};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayItemMetadata, DisplayList, DisplayListSection};
-use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageDisplayItem};
+use gfx::display_list::{GradientDisplayItem, RadialGradientDisplayItem, IframeDisplayItem, ImageDisplayItem};
use gfx::display_list::{LineDisplayItem, OpaqueNode};
use gfx::display_list::{SolidColorDisplayItem, ScrollRoot, StackingContext, StackingContextType};
use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo};
@@ -33,7 +33,7 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc;
use list_item::ListItemFlow;
-use model::{self, MaybeAuto};
+use model::{self, MaybeAuto, specified};
use msg::constellation_msg::PipelineId;
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::UsePlaceholder;
@@ -58,8 +58,10 @@ use style::properties::longhands::border_image_repeat::computed_value::RepeatKey
use style::properties::style_structs;
use style::servo::restyle_damage::REPAINT;
use style::values::{Either, RGBA, computed};
-use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind};
-use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, NumberOrPercentage};
+use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind, LengthOrPercentage};
+use style::values::computed::{LengthOrPercentageOrAuto, LengthOrKeyword, LengthOrPercentageOrKeyword};
+use style::values::computed::{NumberOrPercentage, Position};
+use style::values::computed::image::{EndingShape, SizeKeyword};
use style::values::specified::{HorizontalDirection, VerticalDirection};
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;
@@ -385,11 +387,22 @@ pub trait FragmentDisplayListBuilding {
image_url: &ServoUrl,
background_index: usize);
- fn convert_gradient(&self,
- absolute_bounds: &Rect,
- gradient: &Gradient,
- style: &ServoComputedValues)
- -> Option;
+ fn convert_linear_gradient(&self,
+ bounds: &Rect,
+ stops: &[GradientItem],
+ angle_or_corner: &AngleOrCorner,
+ repeating: bool,
+ style: &ServoComputedValues)
+ -> display_list::Gradient;
+
+ fn convert_radial_gradient(&self,
+ bounds: &Rect,
+ stops: &[GradientItem],
+ shape: &EndingShape,
+ center: &Position,
+ repeating: bool,
+ style: &ServoComputedValues)
+ -> display_list::RadialGradient;
/// Adds the display items necessary to paint the background linear gradient of this fragment
/// to the appropriate section of the display list.
@@ -397,6 +410,7 @@ pub trait FragmentDisplayListBuilding {
state: &mut DisplayListBuildState,
display_list_section: DisplayListSection,
absolute_bounds: &Rect,
+ clip_bounds: &Rect,
clip: &ClippingRegion,
gradient: &Gradient,
style: &ServoComputedValues);
@@ -588,6 +602,152 @@ fn build_border_radius_for_inner_rect(outer_rect: &Rect,
radii
}
+fn convert_gradient_stops(gradient_items: &[GradientItem],
+ length: Au,
+ style: &ServoComputedValues) -> Vec {
+ // Determine the position of each stop per CSS-IMAGES § 3.4.
+ //
+ // FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops.
+ let stop_items = gradient_items.iter().filter_map(|item| {
+ match *item {
+ GradientItem::ColorStop(ref stop) => Some(stop),
+ _ => None,
+ }
+ }).collect::>();
+ let mut stops = Vec::with_capacity(stop_items.len());
+ let mut stop_run = None;
+ for (i, stop) in stop_items.iter().enumerate() {
+ let offset = match stop.position {
+ None => {
+ if stop_run.is_none() {
+ // Initialize a new stop run.
+ let start_offset = if i == 0 {
+ 0.0
+ } else {
+ // `unwrap()` here should never fail because this is the beginning of
+ // a stop run, which is always bounded by a length or percentage.
+ position_to_offset(stop_items[i - 1].position.unwrap(), length)
+ };
+ let (end_index, end_offset) =
+ match stop_items[i..]
+ .iter()
+ .enumerate()
+ .find(|&(_, ref stop)| stop.position.is_some()) {
+ None => (stop_items.len() - 1, 1.0),
+ Some((end_index, end_stop)) => {
+ // `unwrap()` here should never fail because this is the end of
+ // a stop run, which is always bounded by a length or
+ // percentage.
+ (end_index,
+ position_to_offset(end_stop.position.unwrap(), length))
+ }
+ };
+ stop_run = Some(StopRun {
+ start_offset: start_offset,
+ end_offset: end_offset,
+ start_index: i,
+ stop_count: end_index - i,
+ })
+ }
+
+ let stop_run = stop_run.unwrap();
+ let stop_run_length = stop_run.end_offset - stop_run.start_offset;
+ if stop_run.stop_count == 0 {
+ stop_run.end_offset
+ } else {
+ stop_run.start_offset +
+ stop_run_length * (i - stop_run.start_index) as f32 /
+ (stop_run.stop_count as f32)
+ }
+ }
+ Some(position) => {
+ stop_run = None;
+ position_to_offset(position, length)
+ }
+ };
+ stops.push(GradientStop {
+ offset: offset,
+ color: style.resolve_color(stop.color).to_gfx_color()
+ })
+ }
+ stops
+}
+
+/// Returns the the distance to the nearest or farthest corner depending on the comperator.
+fn get_distance_to_corner(size: &Size2D, center: &Point2D, cmp: F) -> Au
+ where F: Fn(Au, Au) -> Au
+{
+ let dist = get_distance_to_sides(size, center, cmp);
+ Au::from_f32_px(dist.width.to_f32_px().hypot(dist.height.to_f32_px()))
+}
+
+/// Returns the distance to the nearest or farthest sides depending on the comparator.
+///
+/// The first return value is horizontal distance the second vertical distance.
+fn get_distance_to_sides(size: &Size2D, center: &Point2D, cmp: F) -> Size2D
+ where F: Fn(Au, Au) -> Au
+{
+ let top_side = center.y;
+ let right_side = size.width - center.x;
+ let bottom_side = size.height - center.y;
+ let left_side = center.x;
+ Size2D::new(cmp(left_side, right_side), cmp(top_side, bottom_side))
+}
+
+/// Returns the radius for an ellipse with the same ratio as if it was matched to the sides.
+fn get_ellipse_radius(size: &Size2D, center: &Point2D, cmp: F) -> Size2D
+ where F: Fn(Au, Au) -> Au
+{
+ let dist = get_distance_to_sides(size, center, cmp);
+ Size2D::new(dist.width.scale_by(::std::f32::consts::FRAC_1_SQRT_2 * 2.0),
+ dist.height.scale_by(::std::f32::consts::FRAC_1_SQRT_2 * 2.0))
+}
+
+/// Determines the radius of a circle if it was not explictly provided.
+/// https://drafts.csswg.org/css-images-3/#typedef-size
+fn convert_circle_size_keyword(keyword: SizeKeyword,
+ size: &Size2D,
+ center: &Point2D) -> Size2D {
+ use style::values::computed::image::SizeKeyword::*;
+ let radius = match keyword {
+ ClosestSide => {
+ let dist = get_distance_to_sides(size, center, ::std::cmp::min);
+ ::std::cmp::min(dist.width, dist.height)
+ }
+ FarthestSide => {
+ let dist = get_distance_to_sides(size, center, ::std::cmp::max);
+ ::std::cmp::max(dist.width, dist.height)
+ }
+ ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min),
+ FarthestCorner => get_distance_to_corner(size, center, ::std::cmp::max),
+ _ => {
+ // TODO(#16542)
+ println!("TODO: implement size keyword {:?} for circles", keyword);
+ Au::new(0)
+ }
+ };
+ Size2D::new(radius, radius)
+}
+
+/// Determines the radius of an ellipse if it was not explictly provided.
+/// https://drafts.csswg.org/css-images-3/#typedef-size
+fn convert_ellipse_size_keyword(keyword: SizeKeyword,
+ size: &Size2D,
+ center: &Point2D) -> Size2D {
+ use style::values::computed::image::SizeKeyword::*;
+ match keyword {
+ ClosestSide => get_distance_to_sides(size, center, ::std::cmp::min),
+ FarthestSide => get_distance_to_sides(size, center, ::std::cmp::max),
+ ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min),
+ FarthestCorner => get_ellipse_radius(size, center, ::std::cmp::max),
+ _ => {
+ // TODO(#16542)
+ println!("TODO: implement size keyword {:?} for ellipses", keyword);
+ Size2D::new(Au::new(0), Au::new(0))
+ }
+ }
+}
+
impl FragmentDisplayListBuilding for Fragment {
fn build_display_list_for_background_if_applicable(&self,
state: &mut DisplayListBuildState,
@@ -653,15 +813,13 @@ impl FragmentDisplayListBuilding for Fragment {
match background_image.0 {
None => {}
Some(computed::Image::Gradient(ref gradient)) => {
- // FIXME: Radial gradients aren't implemented yet.
- if let GradientKind::Linear(_) = gradient.gradient_kind {
- self.build_display_list_for_background_gradient(state,
- display_list_section,
- &bounds,
- &clip,
- gradient,
- style);
- }
+ self.build_display_list_for_background_gradient(state,
+ display_list_section,
+ &absolute_bounds,
+ &bounds,
+ &clip,
+ gradient,
+ style);
}
Some(computed::Image::Url(ref image_url)) => {
if let Some(url) = image_url.url() {
@@ -893,46 +1051,40 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
- fn convert_gradient(&self,
- absolute_bounds: &Rect,
- gradient: &Gradient,
- style: &ServoComputedValues) -> Option {
- // FIXME: Repeating gradients aren't implemented yet.
- if gradient.repeating {
- return None;
- }
- let angle = if let GradientKind::Linear(angle_or_corner) = gradient.gradient_kind {
- match angle_or_corner {
- AngleOrCorner::Angle(angle) => angle.radians(),
- AngleOrCorner::Corner(horizontal, vertical) => {
- // This the angle for one of the diagonals of the box. Our angle
- // will either be this one, this one + PI, or one of the other
- // two perpendicular angles.
- let atan = (absolute_bounds.size.height.to_f32_px() /
- absolute_bounds.size.width.to_f32_px()).atan();
- match (horizontal, vertical) {
- (HorizontalDirection::Right, VerticalDirection::Bottom)
- => f32::consts::PI - atan,
- (HorizontalDirection::Left, VerticalDirection::Bottom)
- => f32::consts::PI + atan,
- (HorizontalDirection::Right, VerticalDirection::Top)
- => atan,
- (HorizontalDirection::Left, VerticalDirection::Top)
- => -atan,
- }
+ fn convert_linear_gradient(&self,
+ bounds: &Rect,
+ stops: &[GradientItem],
+ angle_or_corner: &AngleOrCorner,
+ repeating: bool,
+ style: &ServoComputedValues)
+ -> display_list::Gradient {
+ let angle = match *angle_or_corner {
+ AngleOrCorner::Angle(angle) => angle.radians(),
+ AngleOrCorner::Corner(horizontal, vertical) => {
+ // This the angle for one of the diagonals of the box. Our angle
+ // will either be this one, this one + PI, or one of the other
+ // two perpendicular angles.
+ let atan = (bounds.size.height.to_f32_px() /
+ bounds.size.width.to_f32_px()).atan();
+ match (horizontal, vertical) {
+ (HorizontalDirection::Right, VerticalDirection::Bottom)
+ => f32::consts::PI - atan,
+ (HorizontalDirection::Left, VerticalDirection::Bottom)
+ => f32::consts::PI + atan,
+ (HorizontalDirection::Right, VerticalDirection::Top)
+ => atan,
+ (HorizontalDirection::Left, VerticalDirection::Top)
+ => -atan,
}
}
- } else {
- // FIXME: Radial gradients aren't implemented yet.
- return None;
};
// Get correct gradient line length, based on:
// https://drafts.csswg.org/css-images-3/#linear-gradients
let dir = Point2D::new(angle.sin(), -angle.cos());
- let line_length = (dir.x * absolute_bounds.size.width.to_f32_px()).abs() +
- (dir.y * absolute_bounds.size.height.to_f32_px()).abs();
+ let line_length = (dir.x * bounds.size.width.to_f32_px()).abs() +
+ (dir.y * bounds.size.height.to_f32_px()).abs();
let inv_dir_length = 1.0 / (dir.x * dir.x + dir.y * dir.y).sqrt();
@@ -945,108 +1097,100 @@ impl FragmentDisplayListBuilding for Fragment {
let length = Au::from_f32_px(
(delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
- // Determine the position of each stop per CSS-IMAGES § 3.4.
- //
- // FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops.
- let stop_items = gradient.items.iter().filter_map(|item| {
- match *item {
- GradientItem::ColorStop(ref stop) => Some(stop),
- _ => None,
- }
- }).collect::>();
- let mut stops = Vec::with_capacity(stop_items.len());
- let mut stop_run = None;
- for (i, stop) in stop_items.iter().enumerate() {
- let offset = match stop.position {
- None => {
- if stop_run.is_none() {
- // Initialize a new stop run.
- let start_offset = if i == 0 {
- 0.0
- } else {
- // `unwrap()` here should never fail because this is the beginning of
- // a stop run, which is always bounded by a length or percentage.
- position_to_offset(stop_items[i - 1].position.unwrap(), length)
- };
- let (end_index, end_offset) =
- match stop_items[i..]
- .iter()
- .enumerate()
- .find(|&(_, ref stop)| stop.position.is_some()) {
- None => (stop_items.len() - 1, 1.0),
- Some((end_index, end_stop)) => {
- // `unwrap()` here should never fail because this is the end of
- // a stop run, which is always bounded by a length or
- // percentage.
- (end_index,
- position_to_offset(end_stop.position.unwrap(), length))
- }
- };
- stop_run = Some(StopRun {
- start_offset: start_offset,
- end_offset: end_offset,
- start_index: i,
- stop_count: end_index - i,
- })
- }
+ let stops = convert_gradient_stops(stops, length, style);
- let stop_run = stop_run.unwrap();
- let stop_run_length = stop_run.end_offset - stop_run.start_offset;
- if stop_run.stop_count == 0 {
- stop_run.end_offset
- } else {
- stop_run.start_offset +
- stop_run_length * (i - stop_run.start_index) as f32 /
- (stop_run.stop_count as f32)
- }
- }
- Some(position) => {
- stop_run = None;
- position_to_offset(position, length)
- }
- };
- stops.push(GradientStop {
- offset: offset,
- color: style.resolve_color(stop.color).to_gfx_color()
- })
- }
+ let center = Point2D::new(bounds.size.width / 2, bounds.size.height / 2);
- let center = Point2D::new(absolute_bounds.size.width / 2,
- absolute_bounds.size.height / 2);
-
- Some(display_list::Gradient {
+ display_list::Gradient {
start_point: center - delta,
end_point: center + delta,
stops: stops,
- })
+ repeating: repeating,
+ }
+ }
+
+ fn convert_radial_gradient(&self,
+ bounds: &Rect,
+ stops: &[GradientItem],
+ shape: &EndingShape,
+ center: &Position,
+ repeating: bool,
+ style: &ServoComputedValues)
+ -> display_list::RadialGradient {
+ let center = Point2D::new(specified(center.horizontal.0, bounds.size.width),
+ specified(center.vertical.0, bounds.size.height));
+ let radius = match *shape {
+ EndingShape::Circle(LengthOrKeyword::Length(length))
+ => Size2D::new(length, length),
+ EndingShape::Circle(LengthOrKeyword::Keyword(word))
+ => convert_circle_size_keyword(word, &bounds.size, ¢er),
+ EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal,
+ vertical))
+ => Size2D::new(specified(horizontal, bounds.size.width),
+ specified(vertical, bounds.size.height)),
+ EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word))
+ => convert_ellipse_size_keyword(word, &bounds.size, ¢er),
+ };
+ let length = Au::from_f32_px(radius.width.to_f32_px().hypot(radius.height.to_f32_px()));
+ let stops = convert_gradient_stops(stops, length, style);
+ display_list::RadialGradient {
+ center: center,
+ radius: radius,
+ stops: stops,
+ repeating: repeating,
+ }
}
fn build_display_list_for_background_gradient(&self,
state: &mut DisplayListBuildState,
display_list_section: DisplayListSection,
absolute_bounds: &Rect,
+ clip_bounds: &Rect,
clip: &ClippingRegion,
gradient: &Gradient,
style: &ServoComputedValues) {
let mut clip = clip.clone();
- clip.intersect_rect(absolute_bounds);
+ clip.intersect_rect(clip_bounds);
- let grad = self.convert_gradient(absolute_bounds, gradient, style);
+ let border_padding = self.border_padding.to_physical(style.writing_mode);
+ let mut bounds = *absolute_bounds;
+ bounds.origin.x = bounds.origin.x + border_padding.left;
+ bounds.origin.y = bounds.origin.y + border_padding.top;
+ bounds.size.width = bounds.size.width - border_padding.horizontal();
+ bounds.size.height = bounds.size.height - border_padding.vertical();
- if let Some(x) = grad {
- let base = state.create_base_display_item(absolute_bounds,
- &clip,
- self.node,
- style.get_cursor(Cursor::Default),
- display_list_section);
+ let base = state.create_base_display_item(&bounds,
+ &clip,
+ self.node,
+ style.get_cursor(Cursor::Default),
+ display_list_section);
- let gradient_display_item = DisplayItem::Gradient(box GradientDisplayItem {
- base: base,
- gradient: x,
- });
-
- state.add_display_item(gradient_display_item);
- }
+ let display_item = match gradient.gradient_kind {
+ GradientKind::Linear(ref angle_or_corner) => {
+ let gradient = self.convert_linear_gradient(&bounds,
+ &gradient.items[..],
+ angle_or_corner,
+ gradient.repeating,
+ style);
+ DisplayItem::Gradient(box GradientDisplayItem {
+ base: base,
+ gradient: gradient,
+ })
+ }
+ GradientKind::Radial(ref shape, ref center) => {
+ let gradient = self.convert_radial_gradient(&bounds,
+ &gradient.items[..],
+ shape,
+ center,
+ gradient.repeating,
+ style);
+ DisplayItem::RadialGradient(box RadialGradientDisplayItem {
+ base: base,
+ gradient: gradient,
+ })
+ }
+ };
+ state.add_display_item(display_item);
}
fn build_display_list_for_box_shadow_if_applicable(&self,
@@ -1159,24 +1303,26 @@ impl FragmentDisplayListBuilding for Fragment {
}
Some(computed::Image::Gradient(ref gradient)) => {
match gradient.gradient_kind {
- GradientKind::Linear(_) => {
- let grad = self.convert_gradient(&bounds, gradient, style);
+ GradientKind::Linear(angle_or_corner) => {
+ let grad = self.convert_linear_gradient(&bounds,
+ &gradient.items[..],
+ &angle_or_corner,
+ gradient.repeating,
+ style);
- if let Some(x) = grad {
- state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
- base: base,
- border_widths: border.to_physical(style.writing_mode),
- details: BorderDetails::Gradient(display_list::GradientBorder {
- gradient: x,
+ state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
+ base: base,
+ border_widths: border.to_physical(style.writing_mode),
+ details: BorderDetails::Gradient(display_list::GradientBorder {
+ gradient: grad,
- // TODO(gw): Support border-image-outset
- outset: SideOffsets2D::zero(),
- }),
- }));
- }
+ // TODO(gw): Support border-image-outset
+ outset: SideOffsets2D::zero(),
+ }),
+ }));
}
GradientKind::Radial(_, _) => {
- // TODO(gw): Handle border-image with radial gradient.
+ // TODO(#16638): Handle border-image with radial gradient.
}
}
}
diff --git a/servo/components/layout/webrender_helpers.rs b/servo/components/layout/webrender_helpers.rs
index 723e33287024..70479d438379 100644
--- a/servo/components/layout/webrender_helpers.rs
+++ b/servo/components/layout/webrender_helpers.rs
@@ -370,16 +370,41 @@ impl WebRenderDisplayItemConverter for DisplayItem {
let start_point = item.gradient.start_point.to_pointf();
let end_point = item.gradient.end_point.to_pointf();
let clip = item.base.clip.to_clip_region(builder);
+ let extend_mode = if item.gradient.repeating {
+ ExtendMode::Repeat
+ } else {
+ ExtendMode::Clamp
+ };
let gradient = builder.create_gradient(start_point,
end_point,
item.gradient.stops.clone(),
- ExtendMode::Clamp);
+ extend_mode);
builder.push_gradient(rect,
clip,
gradient,
rect.size,
webrender_traits::LayoutSize::zero());
}
+ DisplayItem::RadialGradient(ref item) => {
+ let rect = item.base.bounds.to_rectf();
+ let center = item.gradient.center.to_pointf();
+ let radius = item.gradient.radius.to_sizef();
+ let clip = item.base.clip.to_clip_region(builder);
+ let extend_mode = if item.gradient.repeating {
+ ExtendMode::Repeat
+ } else {
+ ExtendMode::Clamp
+ };
+ let gradient = builder.create_radial_gradient(center,
+ radius,
+ item.gradient.stops.clone(),
+ extend_mode);
+ builder.push_radial_gradient(rect,
+ clip,
+ gradient,
+ rect.size,
+ webrender_traits::LayoutSize::zero());
+ }
DisplayItem::Line(..) => {
println!("TODO DisplayItem::Line");
}
diff --git a/servo/components/script/dom/canvasrenderingcontext2d.rs b/servo/components/script/dom/canvasrenderingcontext2d.rs
index 432dbe800aa8..a5ec8d233b65 100644
--- a/servo/components/script/dom/canvasrenderingcontext2d.rs
+++ b/servo/components/script/dom/canvasrenderingcontext2d.rs
@@ -350,7 +350,7 @@ impl CanvasRenderingContext2D {
dh);
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
- return Err(Error::IndexSize);
+ return Ok(());
}
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
@@ -407,7 +407,7 @@ impl CanvasRenderingContext2D {
dh);
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
- return Err(Error::IndexSize);
+ return Ok(());
}
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
diff --git a/servo/components/selectors/parser.rs b/servo/components/selectors/parser.rs
index f53380c2b220..66867000fda0 100644
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -1457,7 +1457,7 @@ pub mod tests {
where V: SelectorVisitor { true }
}
- #[derive(PartialEq, Debug)]
+ #[derive(Clone, PartialEq, Debug)]
pub struct DummySelectorImpl;
#[derive(Default)]
diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs
index b468a76009d1..b8f4d4ed5418 100644
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -3784,8 +3784,8 @@ clip-path
for (mut gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v.0.into_iter()) {
match servo {
- Either::First(lop) => gecko.set(lop),
- Either::Second(number) => gecko.set_value(CoordDataValue::Factor(number)),
+ Either::First(number) => gecko.set_value(CoordDataValue::Factor(number)),
+ Either::Second(lop) => gecko.set(lop),
}
}
}
diff --git a/servo/components/style/properties/longhand/box.mako.rs b/servo/components/style/properties/longhand/box.mako.rs
index 85350c76ddf3..bd53e8c716db 100644
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -2008,8 +2008,8 @@ ${helpers.predefined_type("scroll-snap-coordinate",
m32: Number::from_computed_value(&computed.m32),
m33: Number::from_computed_value(&computed.m33),
m34: Number::from_computed_value(&computed.m34),
- m41: Either::First(LengthOrPercentage::from_computed_value(&computed.m41)),
- m42: Either::First(LengthOrPercentage::from_computed_value(&computed.m42)),
+ m41: Either::Second(LengthOrPercentage::from_computed_value(&computed.m41)),
+ m42: Either::Second(LengthOrPercentage::from_computed_value(&computed.m42)),
m43: LengthOrNumber::from_computed_value(&Either::First(computed.m43)),
m44: Number::from_computed_value(&computed.m44),
});
@@ -2056,8 +2056,8 @@ ${helpers.predefined_type("scroll-snap-coordinate",
// LengthOrPercentage. Number maps into Length
fn lopon_to_lop(value: &ComputedLoPoNumber) -> ComputedLoP {
match *value {
- Either::First(length_or_percentage) => length_or_percentage,
- Either::Second(number) => ComputedLoP::Length(Au::from_f32_px(number)),
+ Either::First(number) => ComputedLoP::Length(Au::from_f32_px(number)),
+ Either::Second(length_or_percentage) => length_or_percentage,
}
}
diff --git a/servo/components/style/properties/longhand/inherited_svg.mako.rs b/servo/components/style/properties/longhand/inherited_svg.mako.rs
index 480f4a7adfb1..068c3d127f61 100644
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -92,7 +92,7 @@ ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
${helpers.predefined_type("stroke-dasharray",
"LengthOrPercentageOrNumber",
- "Either::Second(0.0)",
+ "Either::First(0.0)",
"parse_non_negative",
vector="True",
allow_empty="True",
diff --git a/servo/components/style/restyle_hints.rs b/servo/components/style/restyle_hints.rs
index 9d3d8814ac76..193b7e82a9da 100644
--- a/servo/components/style/restyle_hints.rs
+++ b/servo/components/style/restyle_hints.rs
@@ -18,7 +18,7 @@ use selectors::{Element, MatchAttr};
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::matching::matches_selector;
use selectors::parser::{AttrSelector, Combinator, Component, Selector};
-use selectors::parser::{SelectorInner, SelectorIter, SelectorMethods};
+use selectors::parser::{SelectorInner, SelectorMethods};
use selectors::visitor::SelectorVisitor;
use std::clone::Clone;
@@ -482,27 +482,13 @@ struct Dependency {
/// of them is sensitive to attribute or state changes.
struct SensitivitiesVisitor {
sensitivities: Sensitivities,
- hint: RestyleHint,
}
impl SelectorVisitor for SensitivitiesVisitor {
type Impl = SelectorImpl;
-
- fn visit_complex_selector(&mut self,
- _: SelectorIter,
- combinator: Option) -> bool {
- self.hint |= combinator_to_restyle_hint(combinator);
-
- true
- }
-
fn visit_simple_selector(&mut self, s: &Component) -> bool {
self.sensitivities.states.insert(selector_to_state(s));
-
- if !self.sensitivities.attrs {
- self.sensitivities.attrs = is_attr_selector(s);
- }
-
+ self.sensitivities.attrs |= is_attr_selector(s);
true
}
}
@@ -539,56 +525,63 @@ impl DependencySet {
/// Adds a selector to this `DependencySet`.
pub fn note_selector(&mut self, selector: &Selector) {
- let mut is_pseudo_element = selector.pseudo_element.is_some();
-
- let mut next = Some(selector.inner.complex.clone());
let mut combinator = None;
+ let mut iter = selector.inner.complex.iter();
+ let mut index = 0;
- while let Some(current) = next.take() {
- // Set up our visitor.
+ loop {
+ let sequence_start = index;
let mut visitor = SensitivitiesVisitor {
- sensitivities: Sensitivities::new(),
- hint: combinator_to_restyle_hint(combinator),
+ sensitivities: Sensitivities::new()
};
- if is_pseudo_element {
- // TODO(emilio): use more fancy restyle hints to avoid restyling
- // the whole subtree when pseudos change.
- //
- // We currently need is_pseudo_element to handle eager pseudos
- // (so the style the parent stores doesn't become stale), and
- // restyle_descendants to handle all of them (::before and
- // ::after, because we find them in the subtree, and other lazy
- // pseudos for the same reason).
- visitor.hint |= RESTYLE_SELF | RESTYLE_DESCENDANTS;
- is_pseudo_element = false;
+ // Visit all the simple selectors in this sequence.
+ //
+ // Note that this works because we can't have combinators nested
+ // inside simple selectors (i.e. in :not() or :-moz-any()). If we
+ // ever support that we'll need to visit complex selectors as well.
+ for ss in &mut iter {
+ ss.visit(&mut visitor);
+ index += 1; // Account for the simple selector.
}
- {
- // Visit all the simple selectors.
- let mut iter = current.iter();
- let mut index = 0usize;
- for ss in &mut iter {
- ss.visit(&mut visitor);
- index += 1;
- }
-
- // Prepare the next sequence of simple selectors.
- if let Some(next_combinator) = iter.next_sequence() {
- next = Some(current.slice_from(index + 1));
- combinator = Some(next_combinator);
- }
- }
-
- // Note what we found.
+ // If we found a sensitivity, add an entry in the dependency set.
if !visitor.sensitivities.is_empty() {
+ let mut hint = combinator_to_restyle_hint(combinator);
+ let dep_selector;
+ if sequence_start == 0 {
+ if selector.pseudo_element.is_some() {
+ // TODO(emilio): use more fancy restyle hints to avoid
+ // restyling the whole subtree when pseudos change.
+ //
+ // We currently need is_pseudo_element to handle eager
+ // pseudos (so the style the parent stores doesn't
+ // become stale), and restyle_descendants to handle all
+ // of them (::before and ::after, because we find them
+ // in the subtree, and other lazy pseudos for the same
+ // reason).
+ hint |= RESTYLE_SELF | RESTYLE_DESCENDANTS;
+ }
+
+ // Reuse the bloom hashes if this is the base selector.
+ dep_selector = selector.inner.clone();
+ } else {
+ dep_selector = SelectorInner::new(selector.inner.complex.slice_from(sequence_start));
+ }
+
self.add_dependency(Dependency {
sensitivities: visitor.sensitivities,
- hint: visitor.hint,
- selector: SelectorInner::new(current),
- })
+ hint: hint,
+ selector: dep_selector,
+ });
}
+ combinator = iter.next_sequence();
+ if combinator.is_none() {
+ break;
+ }
+
+ index += 1; // Account for the combinator.
}
}
diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs
index cde51a8f3fbe..65d04630fd35 100644
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -313,38 +313,13 @@ impl Stylist {
CssRule::Style(ref locked) => {
let style_rule = locked.read_with(&guard);
self.num_declarations += style_rule.block.read_with(&guard).len();
-
for selector in &style_rule.selectors.0 {
self.num_selectors += 1;
- let map = if let Some(ref pseudo) = selector.pseudo_element {
- self.pseudos_map
- .entry(pseudo.clone())
- .or_insert_with(PerPseudoElementSelectorMap::new)
- .borrow_for_origin(&stylesheet.origin)
- } else {
- self.element_map.borrow_for_origin(&stylesheet.origin)
- };
-
- map.insert(Rule::new(guard,
- selector.inner.clone(),
- locked.clone(),
- self.rules_source_order,
- selector.specificity));
+ self.add_rule_to_map(guard, selector, locked, stylesheet);
+ self.dependencies.note_selector(selector);
+ self.note_for_revalidation(selector);
}
self.rules_source_order += 1;
-
- for selector in &style_rule.selectors.0 {
- self.dependencies.note_selector(selector);
-
- if needs_revalidation(selector) {
- // For revalidation, we can skip everything left of
- // the first ancestor combinator.
- let revalidation_sel =
- selector.inner.slice_to_first_ancestor_combinator();
-
- self.selectors_for_cache_revalidation.push(revalidation_sel);
- }
- }
}
CssRule::Import(ref import) => {
let import = import.read_with(guard);
@@ -374,6 +349,38 @@ impl Stylist {
});
}
+ #[inline]
+ fn add_rule_to_map(&mut self,
+ guard: &SharedRwLockReadGuard,
+ selector: &Selector,
+ rule: &Arc>,
+ stylesheet: &Stylesheet)
+ {
+ let map = if let Some(ref pseudo) = selector.pseudo_element {
+ self.pseudos_map
+ .entry(pseudo.clone())
+ .or_insert_with(PerPseudoElementSelectorMap::new)
+ .borrow_for_origin(&stylesheet.origin)
+ } else {
+ self.element_map.borrow_for_origin(&stylesheet.origin)
+ };
+
+ map.insert(Rule::new(guard,
+ selector.inner.clone(),
+ rule.clone(),
+ self.rules_source_order,
+ selector.specificity));
+ }
+
+ #[inline]
+ fn note_for_revalidation(&mut self, selector: &Selector) {
+ if needs_revalidation(selector) {
+ // For revalidation, we can skip everything left of the first ancestor
+ // combinator.
+ let revalidation_sel = selector.inner.slice_to_first_ancestor_combinator();
+ self.selectors_for_cache_revalidation.push(revalidation_sel);
+ }
+ }
/// Computes the style for a given "precomputed" pseudo-element, taking the
/// universal rules and applying them.
@@ -1043,9 +1050,6 @@ pub struct SelectorMap {
pub class_hash: FnvHashMap>,
/// A hash from local name to rules which contain that local name selector.
pub local_name_hash: FnvHashMap>,
- /// Same as local_name_hash, but keys are lower-cased.
- /// For HTML elements in HTML documents.
- pub lower_local_name_hash: FnvHashMap>,
/// Rules that don't have ID, class, or element selectors.
pub other_rules: Vec,
/// Whether this hash is empty.
@@ -1064,7 +1068,6 @@ impl SelectorMap {
id_hash: HashMap::default(),
class_hash: HashMap::default(),
local_name_hash: HashMap::default(),
- lower_local_name_hash: HashMap::default(),
other_rules: Vec::new(),
empty: true,
}
@@ -1113,14 +1116,9 @@ impl SelectorMap {
cascade_level);
});
- let local_name_hash = if element.is_html_element_in_html_document() {
- &self.lower_local_name_hash
- } else {
- &self.local_name_hash
- };
SelectorMap::get_matching_rules_from_hash(element,
parent_bf,
- local_name_hash,
+ &self.local_name_hash,
element.get_local_name(),
matching_rules_list,
relations,
@@ -1253,8 +1251,22 @@ impl SelectorMap {
}
if let Some(LocalNameSelector { name, lower_name }) = SelectorMap::get_local_name(&rule) {
- find_push(&mut self.local_name_hash, name, rule.clone());
- find_push(&mut self.lower_local_name_hash, lower_name, rule);
+ // If the local name in the selector isn't lowercase, insert it into
+ // the rule hash twice. This means that, during lookup, we can always
+ // find the rules based on the local name of the element, regardless
+ // of whether it's an html element in an html document (in which case
+ // we match against lower_name) or not (in which case we match against
+ // name).
+ //
+ // In the case of a non-html-element-in-html-document with a
+ // lowercase localname and a non-lowercase selector, the rulehash
+ // lookup may produce superfluous selectors, but the subsequent
+ // selector matching work will filter them out.
+ if name != lower_name {
+ find_push(&mut self.local_name_hash, lower_name, rule.clone());
+ }
+ find_push(&mut self.local_name_hash, name, rule);
+
return;
}
diff --git a/servo/components/style/values/computed/image.rs b/servo/components/style/values/computed/image.rs
index 4ccce1e1f8f9..607cc8f20257 100644
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -14,10 +14,11 @@ use std::fmt;
use style_traits::ToCss;
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
use values::computed::position::Position;
-use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection};
+use values::specified::{self, HorizontalDirection, VerticalDirection};
use values::specified::image::CompatMode;
use values::specified::url::SpecifiedUrl;
+pub use values::specified::SizeKeyword;
impl ToComputedValue for specified::Image {
type ComputedValue = Image;
diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs
index 9f7396608779..7cfdfa777163 100644
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -468,7 +468,7 @@ impl ToCss for SVGPaint {
}
/// | |
-pub type LengthOrPercentageOrNumber = Either;
+pub type LengthOrPercentageOrNumber = Either;
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs
index c51027b864ae..84c25c81119b 100644
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -1191,7 +1191,7 @@ impl ToComputedValue for SVGPaintKind {
}
/// | |
-pub type LengthOrPercentageOrNumber = Either;
+pub type LengthOrPercentageOrNumber = Either;
impl LengthOrPercentageOrNumber {
/// parse a | enforcing that the contents aren't negative
@@ -1199,10 +1199,10 @@ impl LengthOrPercentageOrNumber {
// NB: Parse numbers before Lengths so we are consistent about how to
// recognize and serialize "0".
if let Ok(num) = input.try(|i| Number::parse_non_negative(context, i)) {
- return Ok(Either::Second(num))
+ return Ok(Either::First(num))
}
- LengthOrPercentage::parse_non_negative(context, input).map(Either::First)
+ LengthOrPercentage::parse_non_negative(context, input).map(Either::Second)
}
}
diff --git a/servo/tests/unit/style/parsing/length.rs b/servo/tests/unit/style/parsing/length.rs
index b6d9a30b42c5..6b2464849349 100644
--- a/servo/tests/unit/style/parsing/length.rs
+++ b/servo/tests/unit/style/parsing/length.rs
@@ -8,6 +8,8 @@ use parsing::parse;
use style::context::QuirksMode;
use style::parser::{LengthParsingMode, Parse, ParserContext};
use style::stylesheets::{CssRuleType, Origin};
+use style::values::Either;
+use style::values::specified::{LengthOrPercentageOrNumber, Number};
use style::values::specified::length::{AbsoluteLength, Length, NoCalcLength};
use style_traits::ToCss;
@@ -46,3 +48,8 @@ fn test_length_parsing_modes() {
assert!(result.is_ok());
assert_eq!(result.unwrap(), Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(1.))));
}
+
+#[test]
+fn test_zero_percentage_length_or_number() {
+ assert_eq!(parse(LengthOrPercentageOrNumber::parse, "0"), Ok(Either::First(Number::new(0.))));
+}
diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html
index ac79ddd7340a..f7e6e18b8442 100644
--- a/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html
+++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html
@@ -80,9 +80,9 @@ test(function() {
["(", "", "", "INVALID_CHARACTER_ERR"],
[")", "", "", "INVALID_CHARACTER_ERR"],
["f:oo", "", "", null],
- [":foo", "", "", "NAMESPACE_ERR"],
- ["foo:", "", "", "NAMESPACE_ERR"],
- ["prefix::local", "", "", "NAMESPACE_ERR"],
+ [":foo", "", "", "INVALID_CHARACTER_ERR"],
+ ["foo:", "", "", "INVALID_CHARACTER_ERR"],
+ ["prefix::local", "", "", "INVALID_CHARACTER_ERR"],
["foo", "foo", "", null],
["foo", "", "foo", null],
["foo", "f'oo", "", null],
diff --git a/testing/web-platform/tests/dom/nodes/Document-createElementNS.js b/testing/web-platform/tests/dom/nodes/Document-createElementNS.js
index 1abd3330183c..bf5e12cf9518 100644
--- a/testing/web-platform/tests/dom/nodes/Document-createElementNS.js
+++ b/testing/web-platform/tests/dom/nodes/Document-createElementNS.js
@@ -25,11 +25,11 @@ var createElementNS_tests = [
[null, "fo o", "INVALID_CHARACTER_ERR"],
[null, "-foo", "INVALID_CHARACTER_ERR"],
[null, ".foo", "INVALID_CHARACTER_ERR"],
- [null, ":foo", "NAMESPACE_ERR"],
+ [null, ":foo", "INVALID_CHARACTER_ERR"],
[null, "f:oo", "NAMESPACE_ERR"],
- [null, "foo:", "NAMESPACE_ERR"],
- [null, "f:o:o", "NAMESPACE_ERR"],
- [null, ":", "NAMESPACE_ERR"],
+ [null, "foo:", "INVALID_CHARACTER_ERR"],
+ [null, "f:o:o", "INVALID_CHARACTER_ERR"],
+ [null, ":", "INVALID_CHARACTER_ERR"],
[null, "xml", null],
[null, "xmlns", "NAMESPACE_ERR"],
[null, "xmlfoo", null],
@@ -38,19 +38,19 @@ var createElementNS_tests = [
[null, "xmlfoo:bar", "NAMESPACE_ERR"],
[null, "null:xml", "NAMESPACE_ERR"],
["", null, null],
- ["", ":foo", "NAMESPACE_ERR"],
+ ["", ":foo", "INVALID_CHARACTER_ERR"],
["", "f:oo", "NAMESPACE_ERR"],
- ["", "foo:", "NAMESPACE_ERR"],
+ ["", "foo:", "INVALID_CHARACTER_ERR"],
[undefined, null, null],
[undefined, undefined, null],
[undefined, "foo", null],
[undefined, "1foo", "INVALID_CHARACTER_ERR"],
[undefined, "f1oo", null],
[undefined, "foo1", null],
- [undefined, ":foo", "NAMESPACE_ERR"],
+ [undefined, ":foo", "INVALID_CHARACTER_ERR"],
[undefined, "f:oo", "NAMESPACE_ERR"],
- [undefined, "foo:", "NAMESPACE_ERR"],
- [undefined, "f::oo", "NAMESPACE_ERR"],
+ [undefined, "foo:", "INVALID_CHARACTER_ERR"],
+ [undefined, "f::oo", "INVALID_CHARACTER_ERR"],
[undefined, "xml", null],
[undefined, "xmlns", "NAMESPACE_ERR"],
[undefined, "xmlfoo", null],
@@ -65,15 +65,15 @@ var createElementNS_tests = [
["http://example.com/", ".foo", "INVALID_CHARACTER_ERR"],
["http://example.com/", "f1oo", null],
["http://example.com/", "foo1", null],
- ["http://example.com/", ":foo", "NAMESPACE_ERR"],
+ ["http://example.com/", ":foo", "INVALID_CHARACTER_ERR"],
["http://example.com/", "f:oo", null],
- ["http://example.com/", "f:o:o", "NAMESPACE_ERR"],
- ["http://example.com/", "foo:", "NAMESPACE_ERR"],
- ["http://example.com/", "f::oo", "NAMESPACE_ERR"],
- ["http://example.com/", "a:0", "NAMESPACE_ERR"],
+ ["http://example.com/", "f:o:o", "INVALID_CHARACTER_ERR"],
+ ["http://example.com/", "foo:", "INVALID_CHARACTER_ERR"],
+ ["http://example.com/", "f::oo", "INVALID_CHARACTER_ERR"],
+ ["http://example.com/", "a:0", "INVALID_CHARACTER_ERR"],
["http://example.com/", "0:a", "INVALID_CHARACTER_ERR"],
["http://example.com/", "a:_", null],
- ["http://example.com/", "a:\u0BC6", "NAMESPACE_ERR"],
+ ["http://example.com/", "a:\u0BC6", "INVALID_CHARACTER_ERR"],
["http://example.com/", "\u0BC6:a", "INVALID_CHARACTER_ERR"],
["http://example.com/", "a:a\u0BC6", null],
["http://example.com/", "a\u0BC6:a", null],
@@ -98,7 +98,7 @@ var createElementNS_tests = [
["http://example.com/", "xmlns:foo", "NAMESPACE_ERR"],
["http://example.com/", "XMLNS:foo", null],
["http://example.com/", "xmlfoo:bar", null],
- ["http://example.com/", "prefix::local", "NAMESPACE_ERR"],
+ ["http://example.com/", "prefix::local", "INVALID_CHARACTER_ERR"],
["http://example.com/", "namespaceURI:{", "INVALID_CHARACTER_ERR"],
["http://example.com/", "namespaceURI:}", "INVALID_CHARACTER_ERR"],
["http://example.com/", "namespaceURI:~", "INVALID_CHARACTER_ERR"],
@@ -130,9 +130,9 @@ var createElementNS_tests = [
["/", "1foo", "INVALID_CHARACTER_ERR"],
["/", "f1oo", null],
["/", "foo1", null],
- ["/", ":foo", "NAMESPACE_ERR"],
+ ["/", ":foo", "INVALID_CHARACTER_ERR"],
["/", "f:oo", null],
- ["/", "foo:", "NAMESPACE_ERR"],
+ ["/", "foo:", "INVALID_CHARACTER_ERR"],
["/", "xml", null],
["/", "xmlns", "NAMESPACE_ERR"],
["/", "xmlfoo", null],
@@ -143,9 +143,9 @@ var createElementNS_tests = [
["http://www.w3.org/XML/1998/namespace", "1foo", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/XML/1998/namespace", "f1oo", null],
["http://www.w3.org/XML/1998/namespace", "foo1", null],
- ["http://www.w3.org/XML/1998/namespace", ":foo", "NAMESPACE_ERR"],
+ ["http://www.w3.org/XML/1998/namespace", ":foo", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/XML/1998/namespace", "f:oo", null],
- ["http://www.w3.org/XML/1998/namespace", "foo:", "NAMESPACE_ERR"],
+ ["http://www.w3.org/XML/1998/namespace", "foo:", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/XML/1998/namespace", "xml", null],
["http://www.w3.org/XML/1998/namespace", "xmlns", "NAMESPACE_ERR"],
["http://www.w3.org/XML/1998/namespace", "xmlfoo", null],
@@ -158,9 +158,9 @@ var createElementNS_tests = [
["http://www.w3.org/2000/xmlns/", "1foo", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/2000/xmlns/", "f1oo", "NAMESPACE_ERR"],
["http://www.w3.org/2000/xmlns/", "foo1", "NAMESPACE_ERR"],
- ["http://www.w3.org/2000/xmlns/", ":foo", "NAMESPACE_ERR"],
+ ["http://www.w3.org/2000/xmlns/", ":foo", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/2000/xmlns/", "f:oo", "NAMESPACE_ERR"],
- ["http://www.w3.org/2000/xmlns/", "foo:", "NAMESPACE_ERR"],
+ ["http://www.w3.org/2000/xmlns/", "foo:", "INVALID_CHARACTER_ERR"],
["http://www.w3.org/2000/xmlns/", "xml", "NAMESPACE_ERR"],
["http://www.w3.org/2000/xmlns/", "xmlns", null],
["http://www.w3.org/2000/xmlns/", "xmlfoo", "NAMESPACE_ERR"],
@@ -172,9 +172,9 @@ var createElementNS_tests = [
["foo:", "1foo", "INVALID_CHARACTER_ERR"],
["foo:", "f1oo", null],
["foo:", "foo1", null],
- ["foo:", ":foo", "NAMESPACE_ERR"],
+ ["foo:", ":foo", "INVALID_CHARACTER_ERR"],
["foo:", "f:oo", null],
- ["foo:", "foo:", "NAMESPACE_ERR"],
+ ["foo:", "foo:", "INVALID_CHARACTER_ERR"],
["foo:", "xml", null],
["foo:", "xmlns", "NAMESPACE_ERR"],
["foo:", "xmlfoo", null],
diff --git a/testing/web-platform/tests/dom/nodes/attributes.html b/testing/web-platform/tests/dom/nodes/attributes.html
index 8d983350df9d..d1f2aeea571f 100644
--- a/testing/web-platform/tests/dom/nodes/attributes.html
+++ b/testing/web-platform/tests/dom/nodes/attributes.html
@@ -130,12 +130,12 @@ test(function() {
test(function() {
var el = document.createElement("foo")
for (var i = 0, il = invalid_qnames.length; i < il; ++i) {
- assert_throws("NAMESPACE_ERR",
+ assert_throws("INVALID_CHARACTER_ERR",
function() { el.setAttributeNS("a", invalid_qnames[i], "fail") },
"Expected exception for " + invalid_qnames[i] + ".")
}
}, "When qualifiedName does not match the QName production, an " +
- "NAMESPACE_ERR exception is to be thrown.")
+ "INVALID_CHARACTER_ERR exception is to be thrown.")
// Step 3
test(function() {
diff --git a/toolkit/modules/tests/modules/MockDocument.jsm b/toolkit/modules/tests/modules/MockDocument.jsm
index 3cae9bb910e0..a4048dac9a01 100644
--- a/toolkit/modules/tests/modules/MockDocument.jsm
+++ b/toolkit/modules/tests/modules/MockDocument.jsm
@@ -10,6 +10,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.importGlobalProperties(["URL"]);
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+
const MockDocument = {
/**
* Create a document for the given URL containing the given HTML with the ownerDocument of all s having a mocked location.
@@ -46,5 +48,15 @@ const MockDocument = {
});
},
+ createTestDocumentFromFile(aDocumentURL, aFile) {
+ let fileStream = Cc["@mozilla.org/network/file-input-stream;1"].
+ createInstance(Ci.nsIFileInputStream);
+ fileStream.init(aFile, -1, -1, 0);
+
+ let data = NetUtil.readInputStreamToString(fileStream, fileStream.available());
+
+ return this.createTestDocument(aDocumentURL, data);
+ },
+
};
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
index 8cf76085728d..c27bb34be9cc 100644
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -587,7 +587,7 @@ option('--enable-stylo', env='STYLO_ENABLED', nargs=0,
# configure options. The Windows installer of LLVM/Clang doesn't provide
# llvm-config, so we need both methods to support all of our tier-1
# platforms.
-llvm_config = check_prog('LLVM_CONFIG', ('llvm-config-3.9', 'llvm-config',),
+llvm_config = check_prog('LLVM_CONFIG', ('llvm-config-3.9', 'llvm-config39', 'llvm-config',),
what='llvm-config', allow_missing=True)
option('--disable-stylo-build-bindgen',